Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

775 lines
18 KiB

  1. /*++
  2. Copyright (c) 1996 Microsoft Corporation
  3. Module Name:
  4. servinfo.hxx
  5. Abstract:
  6. Contains the CServerInfo class declaration
  7. Author:
  8. Richard L Firth (rfirth) 02-Oct-1996
  9. Notes:
  10. In this implementation, we maintain a single host name per server
  11. Revision History:
  12. 02-Oct-1996 rfirth
  13. Created
  14. --*/
  15. //
  16. // manifests
  17. //
  18. #define SERVER_INFO_SIGNATURE 'fIvS'
  19. //
  20. // values for PurgeKeepAlives dwForce parameter, method & function
  21. //
  22. #define PKA_NO_FORCE 0
  23. #define PKA_NOW 1
  24. #define PKA_AUTH_FAILED 2
  25. //
  26. // data (forward references)
  27. //
  28. extern const DWORD GlobalServerInfoTimeout;
  29. //
  30. // forward references
  31. //
  32. class CFsm_GetConnection;
  33. class HTTP_REQUEST_HANDLE_OBJECT;
  34. //
  35. // classes
  36. //
  37. //
  38. // CServerInfo - we maintain an aged list of CServerInfo's. These are used as a
  39. // database of all useful information about a server
  40. //
  41. class CServerInfo {
  42. private:
  43. //
  44. // m_ServerInfoList, m_List - CServerInfo's are kept in a list
  45. //
  46. LIST_ENTRY m_List;
  47. SERIALIZED_LIST * m_ServerInfoList;
  48. //
  49. // m_Expires - system tick count at which this entry will expire
  50. //
  51. LONG m_Expires;
  52. LONG m_Wrap;
  53. //
  54. // m_ReferenceCount - number of other structures referencing this
  55. //
  56. LONG m_ReferenceCount;
  57. //
  58. // m_HostName - primary host name of the server. Stored as LOWER CASE so
  59. // that we don't have to perform case insensitive string comparisons each
  60. // time
  61. //
  62. ICSTRING m_HostName;
  63. //
  64. // m_Hash - hash value of m_HostName. Check this value first
  65. //
  66. DWORD m_Hash;
  67. //
  68. // m_ProxyLink - if this is an origin server, we link to the proxy
  69. // that may carry
  70. //
  71. CServerInfo * m_ProxyLink;
  72. //
  73. // m_dwProxyVersion - a copy of the Global Proxy Version Count,
  74. // the proxy link goes bad if version count changes
  75. //
  76. DWORD m_dwProxyVersion;
  77. //
  78. // m_HostScheme - Not used for direct connections,
  79. // only used for matching proxy info with cached information
  80. //
  81. INTERNET_SCHEME m_HostScheme;
  82. //
  83. // m_HostPort - can also be, proxy port for cached proxy server
  84. //
  85. INTERNET_PORT m_HostPort;
  86. INTERNET_HANDLE_OBJECT * m_pInternet;
  87. private:
  88. //
  89. // m_Services - bitmap of services supported by the server
  90. //
  91. union {
  92. struct {
  93. unsigned HTTP : 1; // HTTP server running at host
  94. unsigned FTP : 1; // FTP " " " "
  95. unsigned Gopher : 1; // gopher " " " "
  96. unsigned GopherPlus : 1; // gopher+ " " " "
  97. unsigned NNTP : 1; // news " " " " (future)
  98. unsigned SMTP : 1; // mail " " " " (future)
  99. unsigned CERN_Proxy : 1; // server is running CERN proxy
  100. unsigned FTP_Proxy : 1; // server is running (TIS) FTP proxy/gateway
  101. unsigned Socks_Proxy: 1; // server is a Socks Gateway
  102. } Bits;
  103. unsigned Word;
  104. } m_Services;
  105. //
  106. // m_HttpSupport - bitmap of HTTP properties supported by the server, such
  107. // as HTTP version, keep-alive, SSL/PCT, etc.
  108. //
  109. union {
  110. struct {
  111. unsigned KeepAlive : 1; // HTTP server supports keep-alive
  112. unsigned Http1_0 : 1; // " " IS HTTP/1.0
  113. unsigned Http1_1 : 1; // " " " HTTP/1.1
  114. unsigned SSL : 1; // HTTP server supports SSL
  115. unsigned PCT : 1; // HTTP server supports PCT
  116. unsigned IIS : 1; // HTTP server is MS IIS (could be running others?)
  117. unsigned BadNS : 1; // HTTP server is BAD NS Enterprise server
  118. } Bits;
  119. unsigned Word;
  120. } m_HttpSupport;
  121. //
  122. // m_Flags - collection of boolean flags
  123. //
  124. union {
  125. struct {
  126. unsigned KA_Init : 1; // KeepAliveListInitialized
  127. unsigned Unreachable: 1; // host (currently) unreachable
  128. unsigned ProxyByPassSet: 1; // has the next bit been set.
  129. unsigned ProxyByPassed: 1; // did we bypass the proxy talking to this server.
  130. unsigned ProxyScriptCached: 1; // did/are we using this entry to cache the result of JS proxy resolution
  131. unsigned InGlobalPool: 1; // Does this ServerInfo live in the global pool?
  132. } Bits;
  133. unsigned Word;
  134. } m_Flags;
  135. //
  136. // m_KeepAliveList - if the server supports keep-alive, a list of the
  137. // keep-alive connections
  138. //
  139. SERIALIZED_LIST m_KeepAliveList;
  140. //
  141. // m_Waiters - list of sync/async waiters for connections
  142. //
  143. CPriorityList m_Waiters;
  144. //
  145. // CConnectionWaiter - private class identifying waiters in m_Waiters list
  146. //
  147. class CConnectionWaiter : public CPriorityListEntry {
  148. private:
  149. DWORD m_Sync : 1;
  150. DWORD m_KeepAlive : 1;
  151. DWORD_PTR m_dwId;
  152. HANDLE m_hEvent;
  153. public:
  154. CConnectionWaiter(
  155. IN CPriorityList *pList,
  156. IN BOOL bSync,
  157. IN BOOL bKeepAlive,
  158. IN DWORD_PTR dwId,
  159. IN HANDLE hEvent,
  160. IN LONG lPriority,
  161. OUT LPDWORD lpdwStatus) : CPriorityListEntry(lPriority) {
  162. m_Sync = bSync ? 1 : 0;
  163. m_KeepAlive = bKeepAlive ? 1 : 0;
  164. m_dwId = dwId;
  165. m_hEvent = hEvent;
  166. *lpdwStatus = pList->Insert(this);
  167. }
  168. ~CConnectionWaiter() {
  169. }
  170. BOOL IsSync(VOID) {
  171. return (m_Sync == 1) ? TRUE : FALSE;
  172. }
  173. BOOL IsKeepAlive(VOID) {
  174. return (m_KeepAlive == 1) ? TRUE : FALSE;
  175. }
  176. DWORD_PTR Id(VOID) {
  177. return m_dwId;
  178. }
  179. VOID Signal(VOID) {
  180. SetEvent(m_hEvent);
  181. }
  182. };
  183. //
  184. // m_ConnectionLimit - number of simultaneous connections allowed to this
  185. // server
  186. //
  187. LONG m_ConnectionLimit;
  188. //
  189. // m_NewLimit - set when we need to change limit
  190. //
  191. LONG m_NewLimit;
  192. //
  193. // m_ConnectionsAvailable - number of connections available to this server.
  194. // If <= 0 (and not unlimited connections) then we have to wait until a
  195. // connection is freed
  196. //
  197. LONG m_ConnectionsAvailable;
  198. //
  199. // m_ActiveConnections - number of connections that are active. An active
  200. // connection is connected and sending or receiving data. This value can be
  201. // greater than m_ConnectionLimit if we are in the situation of being run
  202. // out of connections
  203. //
  204. //LONG m_ActiveConnections;
  205. //
  206. // m_LastActiveTime - timestamp (tick count) of last operation was made on
  207. // any connection to this server
  208. //
  209. DWORD m_LastActiveTime;
  210. //
  211. // m_ConnectTime - the average time to connect in milliseconds
  212. //
  213. DWORD m_ConnectTime;
  214. //
  215. // m_RTT - average Round Trip Time
  216. //
  217. DWORD m_RTT;
  218. //
  219. // m_AddressList - list of resolved addresses for this server
  220. //
  221. CAddressList m_AddressList;
  222. //
  223. // m_dwError - error code (mainly for constructor)
  224. //
  225. DWORD m_dwError;
  226. #if INET_DEBUG
  227. DWORD m_Signature;
  228. #define INIT_SERVER_INFO() m_Signature = SERVER_INFO_SIGNATURE
  229. #define CHECK_SERVER_INFO() INET_ASSERT(m_Signature == SERVER_INFO_SIGNATURE)
  230. #else
  231. #define INIT_SERVER_INFO() /* NOTHING */
  232. #define CHECK_SERVER_INFO() /* NOTHING */
  233. #endif
  234. //
  235. // private methods
  236. //
  237. ICSocket *
  238. FindKeepAliveConnection(
  239. IN DWORD dwSocketFlags,
  240. IN INTERNET_PORT nPort,
  241. IN LPSTR pszTunnelServer,
  242. IN DWORD dwSecureProtocols,
  243. IN DWORD dwSecureFlags
  244. );
  245. BOOL
  246. KeepAliveWaiters(
  247. VOID
  248. );
  249. VOID
  250. UpdateConnectionLimit(
  251. VOID
  252. );
  253. public:
  254. CServerInfo(
  255. IN SERIALIZED_LIST * ServerInfoList,
  256. IN LPSTR lpszHostName,
  257. OUT DWORD* pdwError,
  258. IN DWORD dwService = INTERNET_SERVICE_HTTP,
  259. IN DWORD dwMaxConnections = WINHTTP_CONNS_PER_SERVER_UNLIMITED
  260. );
  261. ~CServerInfo();
  262. CServerInfo * Next(VOID) {
  263. return (CServerInfo *)m_List.Flink;
  264. }
  265. CServerInfo * Prev(VOID) {
  266. return (CServerInfo *)m_List.Blink;
  267. }
  268. // This code needs to handle system time roll over.
  269. // SetExpiryTime is passed the duration, and we calculate the ultimate time
  270. // However, this may result in a rollover -- e.g. if the current time is
  271. // 0xffffff00, the ultimate time could be 0x000000fd
  272. // Expired is passed the current tick count, however, and in the past
  273. // would return TRUE immediately.
  274. // Thus we set a flag is we need to wait for system time rollover to happen,
  275. VOID SetExpiryTime(DWORD dwMilliseconds = GlobalServerInfoTimeout) {
  276. DWORD dw = GetTickCountWrap();
  277. m_Expires = dw + dwMilliseconds;
  278. m_Wrap = (dw > (DWORD)m_Expires);
  279. }
  280. VOID ResetExpiryTime(VOID) {
  281. m_Expires = 0;
  282. m_Wrap = 0;
  283. }
  284. BOOL Expired(LONG dwTime = (LONG)GetTickCountWrap()) {
  285. if (m_Wrap)
  286. {
  287. m_Wrap = ((LONG)dwTime < 0);
  288. }
  289. return (!m_Wrap && (dwTime > m_Expires)) ? TRUE : FALSE;
  290. }
  291. VOID
  292. Reference(
  293. VOID
  294. );
  295. BOOL
  296. Dereference(
  297. VOID
  298. );
  299. LONG ReferenceCount(VOID) const {
  300. return m_ReferenceCount;
  301. }
  302. LPSTR GetHostName(VOID) const {
  303. return m_HostName.StringAddress();
  304. }
  305. DWORD
  306. SetCachedProxyServerInfo(
  307. IN CServerInfo * pProxyServer,
  308. IN DWORD dwProxyVersion,
  309. IN BOOL fUseProxy,
  310. IN INTERNET_SCHEME HostScheme,
  311. IN INTERNET_PORT HostPort,
  312. IN INTERNET_SCHEME ProxyScheme,
  313. IN INTERNET_PORT ProxyPort
  314. );
  315. CServerInfo *
  316. GetCachedProxyServerInfo(
  317. IN INTERNET_SCHEME HostScheme,
  318. IN INTERNET_PORT HostPort,
  319. OUT BOOL *pfCachedEntry
  320. );
  321. BOOL
  322. CopyCachedProxyInfoToProxyMsg(
  323. IN OUT AUTO_PROXY_ASYNC_MSG *pQueryForProxyInfo
  324. );
  325. BOOL Match(IN DWORD dwHash, IN LPSTR lpszHostName) {
  326. return (dwHash == m_Hash) ? m_HostName.Strcmp(lpszHostName) : FALSE;
  327. }
  328. VOID SetHTTP(VOID) {
  329. m_Services.Bits.HTTP = 1;
  330. }
  331. BOOL IsHTTP(VOID) {
  332. return m_Services.Bits.HTTP ? TRUE : FALSE;
  333. }
  334. VOID SetFTP(VOID) {
  335. m_Services.Bits.FTP = 1;
  336. }
  337. BOOL IsFTP(VOID) {
  338. return m_Services.Bits.FTP ? TRUE : FALSE;
  339. }
  340. VOID SetGopher(VOID) {
  341. m_Services.Bits.Gopher = 1;
  342. }
  343. BOOL IsGopher(VOID) {
  344. return m_Services.Bits.Gopher ? TRUE : FALSE;
  345. }
  346. VOID SetSocksGateway(VOID) {
  347. m_Services.Bits.Socks_Proxy = 1;
  348. }
  349. BOOL IsSocksGateway(VOID) {
  350. return m_Services.Bits.Socks_Proxy ? TRUE : FALSE;
  351. }
  352. VOID SetCernProxy(VOID) {
  353. m_Services.Bits.CERN_Proxy = 1;
  354. }
  355. VOID SetFTPProxy(VOID) {
  356. m_Services.Bits.FTP_Proxy = 1;
  357. }
  358. BOOL IsCernProxy(VOID) {
  359. return m_Services.Bits.CERN_Proxy ? TRUE : FALSE;
  360. }
  361. VOID SetHttp1_1(VOID) {
  362. m_HttpSupport.Bits.Http1_1 = 1;
  363. }
  364. BOOL IsHttp1_1(VOID) {
  365. return m_HttpSupport.Bits.Http1_1 ? TRUE : FALSE;
  366. }
  367. VOID SetHttp1_0(VOID) {
  368. m_HttpSupport.Bits.Http1_0 = 1;
  369. }
  370. VOID SetBadNSServer(VOID) {
  371. m_HttpSupport.Bits.BadNS = 1;
  372. }
  373. BOOL IsBadNSServer(VOID) {
  374. return m_HttpSupport.Bits.BadNS ? TRUE : FALSE;
  375. }
  376. BOOL IsHttp1_0(VOID) {
  377. return m_HttpSupport.Bits.Http1_0 ? TRUE : FALSE;
  378. }
  379. VOID SetKeepAlive(VOID) {
  380. m_HttpSupport.Bits.KeepAlive = 1;
  381. }
  382. BOOL IsKeepAlive(VOID) {
  383. return m_HttpSupport.Bits.KeepAlive ? TRUE : FALSE;
  384. }
  385. VOID SetProxyScriptCached(BOOL fSetCached) {
  386. m_Flags.Bits.ProxyScriptCached = (fSetCached) ? 1 : 0;
  387. }
  388. BOOL IsProxyScriptCached(VOID) {
  389. return m_Flags.Bits.ProxyScriptCached ? TRUE : FALSE;
  390. }
  391. VOID SetKeepAliveListInitialized(VOID) {
  392. m_Flags.Bits.KA_Init = 1;
  393. }
  394. BOOL IsKeepAliveListInitialized(VOID) {
  395. return m_Flags.Bits.KA_Init ? TRUE : FALSE;
  396. }
  397. VOID SetUnreachable(VOID) {
  398. m_Flags.Bits.Unreachable = 1;
  399. }
  400. VOID SetReachable(VOID) {
  401. m_Flags.Bits.Unreachable = 0;
  402. }
  403. BOOL IsUnreachable(VOID) {
  404. return m_Flags.Bits.Unreachable ? TRUE : FALSE;
  405. }
  406. VOID SetProxyByPassed(BOOL fProxyByPassed) {
  407. m_Flags.Bits.ProxyByPassed = fProxyByPassed ? TRUE: FALSE;
  408. m_Flags.Bits.ProxyByPassSet = TRUE;
  409. }
  410. BOOL IsProxyByPassSet(VOID)
  411. {
  412. return m_Flags.Bits.ProxyByPassSet ? TRUE : FALSE;
  413. }
  414. BOOL WasProxyByPassed(VOID) {
  415. return m_Flags.Bits.ProxyByPassed ? TRUE : FALSE;
  416. }
  417. VOID SetInGlobalServerInfoPool()
  418. {
  419. m_Flags.Bits.InGlobalPool = TRUE;
  420. }
  421. BOOL InGlobalServerInfoPool() const
  422. {
  423. return m_Flags.Bits.InGlobalPool ? TRUE : FALSE;
  424. }
  425. LONG ConnectionLimit(VOID) const {
  426. return m_ConnectionLimit;
  427. }
  428. VOID SetConnectionLimit(LONG Limit) {
  429. m_ConnectionLimit = Limit;
  430. }
  431. BOOL UnlimitedConnections(VOID) {
  432. return (ConnectionLimit() == WINHTTP_CONNS_PER_SERVER_UNLIMITED) ? TRUE : FALSE;
  433. }
  434. LONG KeepAliveConnections(VOID) {
  435. return ElementsOnSerializedList(&m_KeepAliveList);
  436. }
  437. LONG AvailableConnections(VOID) const {
  438. return m_ConnectionsAvailable;
  439. }
  440. LONG TotalAvailableConnections(VOID) {
  441. return KeepAliveConnections() + AvailableConnections();
  442. }
  443. LONG GetNewLimit(VOID) const {
  444. return m_NewLimit;
  445. }
  446. VOID SetNewLimit(LONG Limit) {
  447. m_NewLimit = Limit;
  448. }
  449. BOOL IsNewLimit(VOID) {
  450. return (m_ConnectionLimit != m_NewLimit) ? TRUE : FALSE;
  451. }
  452. VOID
  453. UpdateConnectTime(
  454. IN DWORD dwConnectTime
  455. );
  456. DWORD GetConnectTime(VOID) const {
  457. return (m_ConnectTime == (DWORD)-1) ? 0 : m_ConnectTime;
  458. }
  459. VOID
  460. UpdateRTT(
  461. IN DWORD dwTime
  462. );
  463. DWORD GetRTT(VOID) const {
  464. return m_RTT;
  465. }
  466. DWORD
  467. GetConnection_Fsm(
  468. IN CFsm_GetConnection * Fsm
  469. );
  470. DWORD
  471. ReleaseConnection(
  472. IN ICSocket * lpSocket OPTIONAL
  473. );
  474. VOID
  475. RemoveWaiter(
  476. IN DWORD_PTR dwId
  477. );
  478. VOID
  479. PurgeKeepAlives(
  480. IN DWORD dwForce = PKA_NO_FORCE
  481. );
  482. BOOL
  483. GetNextAddress(
  484. IN OUT LPDWORD lpdwResolutionId,
  485. IN OUT LPDWORD lpdwIndex,
  486. IN INTERNET_PORT nPort,
  487. OUT LPCSADDR_INFO lpAddress
  488. ) {
  489. return m_AddressList.GetNextAddress(lpdwResolutionId,
  490. lpdwIndex,
  491. nPort,
  492. lpAddress
  493. );
  494. }
  495. VOID
  496. InvalidateAddress(
  497. IN DWORD dwResolutionId,
  498. IN DWORD dwAddressIndex
  499. ) {
  500. m_AddressList.InvalidateAddress(dwResolutionId, dwAddressIndex);
  501. }
  502. DWORD
  503. ResolveHost(
  504. IN OUT LPDWORD lpdwResolutionId,
  505. IN DWORD dwFlags
  506. ) {
  507. return m_AddressList.ResolveHost(GetHostName(),
  508. lpdwResolutionId,
  509. dwFlags
  510. );
  511. }
  512. DWORD GetError(VOID) const {
  513. return m_dwError;
  514. }
  515. VOID SetError(DWORD dwError = GetLastError()) {
  516. m_dwError = dwError;
  517. }
  518. //
  519. // connection activity methods
  520. //
  521. VOID SetLastActiveTime(VOID) {
  522. m_LastActiveTime = GetTickCountWrap();
  523. }
  524. VOID ResetLastActiveTime(VOID) {
  525. m_LastActiveTime = 0;
  526. }
  527. DWORD GetLastActiveTime(VOID) const {
  528. return m_LastActiveTime;
  529. }
  530. BOOL ConnectionActivity(VOID) {
  531. DWORD lastActiveTime = GetLastActiveTime();
  532. return (lastActiveTime != 0)
  533. ? (((GetTickCountWrap() - lastActiveTime)
  534. <= GlobalConnectionInactiveTimeout) ? TRUE : FALSE)
  535. : FALSE;
  536. }
  537. BOOL AllConnectionsInactive(VOID) {
  538. //return ((ActiveConnectionCount() >= ConnectionLimit())
  539. // && !ConnectionActivity())
  540. // ? TRUE
  541. // : FALSE;
  542. return !ConnectionActivity();
  543. }
  544. //
  545. // friend functions
  546. //
  547. friend
  548. CServerInfo *
  549. ContainingServerInfo(
  550. IN LPVOID lpAddress
  551. );
  552. };
  553. class CGlobalServerInfoPool
  554. {
  555. SERIALIZED_LIST _GlobalServerInfoList;
  556. DWORD _PreviousScavengeTime;
  557. DWORD _NextScavengeTime;
  558. BOOL _bWrap;
  559. HANDLE _hGCThread;
  560. BOOL _fIsGCRunning;
  561. public:
  562. BOOL Initialize();
  563. void Terminate();
  564. CServerInfo * FindServerInfo(LPSTR lpszHostName);
  565. CServerInfo * GetServerInfo(LPSTR lpszHostName);
  566. BOOL TimeToScavenge(DWORD CurrentTime) const;
  567. void SetNextScavengeTime();
  568. BOOL ScavengeList();
  569. void StartGarbageCollectorIfNotRunning();
  570. void SetGarbageCollectorRunning(BOOL fGCRunning) { _fIsGCRunning = fGCRunning; }
  571. BOOL IsGarbageCollectorRunning() { return _fIsGCRunning; }
  572. private:
  573. static DWORD WINAPI GarbageCollectorThread(LPVOID lpParameter);
  574. };
  575. extern CGlobalServerInfoPool * g_pGlobalServerInfoPool;
  576. //
  577. // prototypes
  578. //
  579. VOID
  580. ReleaseServerInfo(
  581. IN CServerInfo * lpServerInfo
  582. );
  583. CServerInfo *
  584. ContainingServerInfo(
  585. IN LPVOID lpAddress
  586. );