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.

498 lines
11 KiB

  1. /*++
  2. Copyright (c) 1997 Microsoft Corporation
  3. Module Name:
  4. caddrlst.hxx
  5. Abstract:
  6. Contains CAddressList class definition
  7. Contents:
  8. Author:
  9. Richard L Firth (rfirth) 21-Apr-1997
  10. Revision History:
  11. 21-Apr-1997 rfirth
  12. Created
  13. --*/
  14. //
  15. // manifests
  16. //
  17. #define CSADDR_BUFFER_LENGTH (sizeof(CSADDR_INFO) + 128)
  18. //
  19. // types
  20. //
  21. //
  22. // RESOLVED_ADDRESS - a CSADDR_INFO with additional IsBad field which is set
  23. // when we fail to connect to the address
  24. //
  25. typedef struct {
  26. CSADDR_INFO AddrInfo;
  27. BOOL IsValid;
  28. } RESOLVED_ADDRESS, * LPRESOLVED_ADDRESS;
  29. //
  30. // forward references
  31. //
  32. class CFsm_ResolveHost;
  33. //
  34. // classes
  35. //
  36. class CListItem
  37. {
  38. protected:
  39. CListItem* pNext;
  40. CListItem()
  41. {
  42. pNext=NULL;
  43. }
  44. public:
  45. void SetNext(CListItem* _pNext)
  46. {
  47. pNext = _pNext;
  48. }
  49. CListItem* GetNext()
  50. {
  51. return pNext;
  52. }
  53. virtual ~CListItem()
  54. {}
  55. };
  56. //This list maintains a list of threads that have not yet exited from GHBN for the session handle.
  57. // We periodically check ( based on trimsize ), for threads that have exited and remove them from the list.
  58. class CList
  59. {
  60. protected:
  61. CCritSec _cs;
  62. ULONG _nItems;
  63. CListItem* _pHead;
  64. CListItem* _pTail;
  65. public:
  66. CList(CListItem* pHead)
  67. {
  68. _cs.Init();
  69. if (pHead)
  70. _nItems = 1;
  71. else
  72. _nItems = 0;
  73. _pHead = pHead;
  74. _pTail = pHead;
  75. }
  76. ULONG GetCount()
  77. {
  78. return _nItems;
  79. }
  80. void AddAtHead(CListItem* pItem)
  81. {
  82. if (_pHead)
  83. {
  84. pItem->SetNext(_pHead);
  85. }
  86. else
  87. {
  88. _pTail = pItem;
  89. }
  90. _pHead = pItem;
  91. ++_nItems;
  92. }
  93. void AddToTail(CListItem* pItem)
  94. {
  95. if (_pTail)
  96. {
  97. _pTail->SetNext(pItem);
  98. }
  99. else
  100. {
  101. _pHead = pItem;
  102. }
  103. _pTail = pItem;
  104. ++_nItems;
  105. }
  106. CListItem* GetHead()
  107. {
  108. return _pHead;
  109. }
  110. void SetHead(CListItem* pItem)
  111. {
  112. _pHead = pItem;
  113. }
  114. void SetTail(CListItem* pItem)
  115. {
  116. _pTail = pItem;
  117. }
  118. void ReduceCount()
  119. {
  120. --_nItems;
  121. }
  122. BOOL LockList()
  123. {
  124. if (_cs.IsInitialized())
  125. return _cs.Lock();
  126. else
  127. // try initializing again
  128. return (_cs.Init() && _cs.Lock());
  129. }
  130. void UnlockList()
  131. {
  132. _cs.Unlock();
  133. }
  134. BOOL IsInitialized()
  135. {
  136. return _cs.IsInitialized();
  137. }
  138. ~CList()
  139. {
  140. INET_ASSERT(_nItems == 0);
  141. }
  142. };
  143. class CGetHostItem;
  144. class CResolverCache
  145. {
  146. private:
  147. SERIALIZED_LIST _ResolverCache;
  148. CList* _pHandlesList;
  149. public:
  150. CResolverCache(DWORD* pdwStatus)
  151. {
  152. if (!InitializeSerializedList(&_ResolverCache))
  153. {
  154. _pHandlesList = NULL;
  155. *pdwStatus = ERROR_NOT_ENOUGH_MEMORY;
  156. }
  157. else
  158. {
  159. _pHandlesList = New CList(NULL);
  160. if (!_pHandlesList || !_pHandlesList->IsInitialized())
  161. *pdwStatus = ERROR_NOT_ENOUGH_MEMORY;
  162. }
  163. }
  164. ~CResolverCache();
  165. SERIALIZED_LIST* GetResolverCacheList()
  166. {
  167. return &_ResolverCache;
  168. }
  169. #if 0
  170. //Use to force all GHBN threads to terminate
  171. void ForceEmptyAndDeleteHandlesList();
  172. #endif
  173. //Use to force graceful termination of GHBN threads
  174. void EmptyHandlesList();
  175. //Used to trim size of GHBN thread list periodically. default for trim size =1
  176. void TrimHandlesListSize(ULONG nTrimSize=1);
  177. //Used to add not-cleaned-up resources to handles list.
  178. BOOL AddToHandlesList(HANDLE hThread, CGetHostItem* pGetHostItem);
  179. };
  180. //This class exists for the following reasons:
  181. // 1. to transmit the resolver cache and hostname to the GHBN thread.
  182. // 2. to save information regarding above and the thread handle in case we time out in ResolveHost:
  183. // in which case, we need to clean up all these resources.
  184. // We don't clean up resources in the GHBN thread itself, because we may have to kill off the thread
  185. // in case we are unloaded by client without proper cleanup of session handle.
  186. //
  187. // This could also be used on a completion-port servicing thread, in which case _hThread, _fDelete &&
  188. // _dwAllocSize are not used. In this case, _pAlloc is overloaded to point to the pFsm member.
  189. class CGetHostItem: public CListItem
  190. {
  191. private:
  192. //Used in all cases.
  193. LPSTR _lpszHostName; //copy of host name to free
  194. CResolverCache* _pResolverCache; //resolver cache wrapper
  195. INTERNET_HANDLE_OBJECT* _pSession; //session handle to addref so the resolver cache lives.
  196. //Used only on a new thread
  197. HANDLE _hThread; //GHBN thread handle to wait on
  198. BOOL _fDelete; //delete this memory in the destructor?
  199. //Optimization/workaround to not allocate resources on a new thread - not used on worker thread.
  200. DWORD _dwAllocSize;
  201. //server as an alloc pointer on new thread, and as an fsm pointer on worker thread.
  202. VOID* _pAlloc; //preallocated memory to get around Rockall allocation issue.
  203. HMODULE _hMod;
  204. public:
  205. CGetHostItem(LPSTR lpszHostName, CResolverCache* pResolverCache, INTERNET_HANDLE_OBJECT* pSession,
  206. VOID* pAlloc, DWORD dwAllocSize):
  207. _hThread(NULL),_lpszHostName(lpszHostName),_pResolverCache(pResolverCache),_pSession(pSession),
  208. _pAlloc(pAlloc),_dwAllocSize(dwAllocSize),_fDelete(FALSE)
  209. {
  210. _hMod = NULL;
  211. }
  212. HMODULE GetModuleHandle() const { return _hMod; }
  213. VOID SetModuleHandle(HMODULE hMod) { _hMod = hMod; }
  214. VOID* GetAllocPointer()
  215. {
  216. return _pAlloc;
  217. }
  218. INTERNET_HANDLE_OBJECT* GetRoot()
  219. {
  220. return _pSession;
  221. }
  222. DWORD GetAllocSize()
  223. {
  224. return _dwAllocSize;
  225. }
  226. VOID SetDelete()
  227. {
  228. _fDelete = TRUE;
  229. }
  230. LPSTR GetHostName()
  231. {
  232. return _lpszHostName;
  233. }
  234. CResolverCache* GetResolverCache()
  235. {
  236. return _pResolverCache;
  237. }
  238. BOOL CanBeDeleted()
  239. {
  240. DWORD dwExitCode;
  241. if (GetExitCodeThread(_hThread, &dwExitCode) && (dwExitCode != STILL_ACTIVE))
  242. return TRUE;
  243. else
  244. return FALSE;
  245. }
  246. void SetThreadHandle(HANDLE hThread)
  247. {
  248. _hThread = hThread;
  249. }
  250. #if 0
  251. void ForceDelete()
  252. {
  253. DWORD dwExitCode;
  254. if (GetExitCodeThread(_hThread, &dwExitCode) && (dwExitCode != STILL_ACTIVE))
  255. return;
  256. else
  257. TerminateThread(_hThread, 0);
  258. }
  259. #endif
  260. void WaitDelete()
  261. {
  262. WaitForSingleObject(_hThread, INFINITE);
  263. }
  264. //lpszHostname and pResolverCache will always be non-NULL ( because we check for them
  265. // before creating this in ResolveHost_Fsm )
  266. // But hThread may be NULL, in which case the destructor is called immdly.
  267. ~CGetHostItem();
  268. };
  269. //
  270. // CAddressList - maintains list of resolved addresses for a host name/port
  271. // combination
  272. //
  273. class CAddressList {
  274. private:
  275. CCritSec m_CritSec; // grab this before updating
  276. DWORD m_ResolutionId; // determines when OK to resolve
  277. INT m_CurrentAddress; // index of current (good) address
  278. INT m_AddressCount; // number of addresses in list
  279. INT m_BadAddressCount; // number addresses already tried & failed
  280. LPRESOLVED_ADDRESS m_Addresses; // list of resolved addresses
  281. DWORD
  282. AddrInfoToAddressList(
  283. IN struct addrinfo FAR *lpAddrInfo
  284. );
  285. public:
  286. CAddressList() {
  287. m_CritSec.Init();
  288. m_ResolutionId = 0;
  289. m_CurrentAddress = 0;
  290. m_AddressCount = 0;
  291. m_BadAddressCount = 0;
  292. m_Addresses = NULL;
  293. }
  294. ~CAddressList() {
  295. FreeList();
  296. }
  297. BOOL Acquire(VOID) {
  298. return m_CritSec.Lock();
  299. }
  300. VOID Release(VOID) {
  301. m_CritSec.Unlock();
  302. }
  303. VOID
  304. FreeList(
  305. VOID
  306. );
  307. DWORD
  308. SetList(
  309. IN struct addrinfo *lpAddrInfo
  310. );
  311. BOOL
  312. GetNextAddress(
  313. IN OUT LPDWORD lpdwResolutionId,
  314. IN OUT LPDWORD lpdwIndex,
  315. IN INTERNET_PORT nPort,
  316. OUT LPCSADDR_INFO lpResolvedAddress
  317. );
  318. VOID
  319. InvalidateAddress(
  320. IN DWORD dwResolutionId,
  321. IN DWORD dwAddressIndex
  322. );
  323. DWORD
  324. ResolveHost(
  325. IN LPSTR lpszHostName,
  326. IN OUT LPDWORD lpdwResolutionId,
  327. IN DWORD dwFlags
  328. );
  329. DWORD
  330. ResolveHost_Fsm(
  331. IN CFsm_ResolveHost * Fsm
  332. );
  333. DWORD
  334. ResolveHost_Continue(
  335. IN CFsm_ResolveHost * Fsm
  336. );
  337. VOID NextAddress(VOID) {
  338. ++m_CurrentAddress;
  339. if (m_CurrentAddress == m_AddressCount) {
  340. m_CurrentAddress = 0;
  341. }
  342. }
  343. LPCSADDR_INFO CurrentAddress(VOID) {
  344. return &m_Addresses[m_CurrentAddress].AddrInfo;
  345. }
  346. LPSOCKADDR LocalSockaddr() {
  347. return CurrentAddress()->LocalAddr.lpSockaddr;
  348. }
  349. INT LocalSockaddrLength() {
  350. return CurrentAddress()->LocalAddr.iSockaddrLength;
  351. }
  352. INT LocalFamily(VOID) {
  353. return (INT)LocalSockaddr()->sa_family;
  354. }
  355. INT LocalPort() {
  356. //
  357. // The port number field is in the same location in both a
  358. // sockaddr_in and a sockaddr_in6, so it is safe to cast the
  359. // sockaddr to sockaddr_in here - this works for IPv4 or IPv6.
  360. //
  361. INET_ASSERT(offsetof(SOCKADDR_IN, sin_port) ==
  362. offsetof(SOCKADDR_IN6, sin6_port));
  363. return ((LPSOCKADDR_IN)LocalSockaddr())->sin_port;
  364. }
  365. VOID SetLocalPort(INTERNET_PORT Port) {
  366. //
  367. // The port number field is in the same location in both a
  368. // sockaddr_in and a sockaddr_in6, so it is safe to cast the
  369. // sockaddr to sockaddr_in here - this works for IPv4 or IPv6.
  370. //
  371. INET_ASSERT(offsetof(SOCKADDR_IN, sin_port) ==
  372. offsetof(SOCKADDR_IN6, sin6_port));
  373. ((LPSOCKADDR_IN)LocalSockaddr())->sin_port = Port;
  374. }
  375. LPSOCKADDR RemoteSockaddr() {
  376. return CurrentAddress()->RemoteAddr.lpSockaddr;
  377. }
  378. INT RemoteSockaddrLength() {
  379. return CurrentAddress()->RemoteAddr.iSockaddrLength;
  380. }
  381. INT RemoteFamily(VOID) {
  382. return (INT)RemoteSockaddr()->sa_family;
  383. }
  384. INT RemotePort() {
  385. //
  386. // The port number field is in the same location in both a
  387. // sockaddr_in and a sockaddr_in6, so it is safe to cast the
  388. // sockaddr to sockaddr_in here - this works for IPv4 or IPv6.
  389. //
  390. INET_ASSERT(offsetof(SOCKADDR_IN, sin_port) ==
  391. offsetof(SOCKADDR_IN6, sin6_port));
  392. return ((LPSOCKADDR_IN)RemoteSockaddr())->sin_port;
  393. }
  394. INT SocketType(VOID) {
  395. return CurrentAddress()->iSocketType;
  396. }
  397. INT Protocol(VOID) {
  398. return CurrentAddress()->iProtocol;
  399. }
  400. BOOL IsCurrentAddressValid(VOID) {
  401. return m_Addresses[m_CurrentAddress].IsValid;
  402. }
  403. };