/*++ Copyright (c) 1997 Microsoft Corporation Module Name: caddrlst.hxx Abstract: Contains CAddressList class definition Contents: Author: Richard L Firth (rfirth) 21-Apr-1997 Revision History: 21-Apr-1997 rfirth Created --*/ // // manifests // #define CSADDR_BUFFER_LENGTH (sizeof(CSADDR_INFO) + 128) // // types // // // RESOLVED_ADDRESS - a CSADDR_INFO with additional IsBad field which is set // when we fail to connect to the address // typedef struct { CSADDR_INFO AddrInfo; BOOL IsValid; } RESOLVED_ADDRESS, * LPRESOLVED_ADDRESS; // // forward references // class CFsm_ResolveHost; // // classes // class CListItem { protected: CListItem* pNext; CListItem() { pNext=NULL; } public: void SetNext(CListItem* _pNext) { pNext = _pNext; } CListItem* GetNext() { return pNext; } }; //This list maintains a list of threads that have not yet exited from GHBN for the session handle. // We periodically check ( based on trimsize ), for threads that have exited and remove them from the list. class CList { protected: CCritSec _cs; ULONG _nItems; CListItem* _pHead; CListItem* _pTail; public: CList(CListItem* pHead) { _cs.Init(); if (pHead) _nItems = 1; else _nItems = 0; _pHead = pHead; _pTail = pHead; } ULONG GetCount() { return _nItems; } void AddAtHead(CListItem* pItem) { if (_pHead) { pItem->SetNext(_pHead); } else { _pTail = pItem; } _pHead = pItem; ++_nItems; } void AddToTail(CListItem* pItem) { if (_pTail) { _pTail->SetNext(pItem); } else { _pHead = pItem; } _pTail = pItem; ++_nItems; } CListItem* GetHead() { return _pHead; } void SetHead(CListItem* pItem) { _pHead = pItem; } void SetTail(CListItem* pItem) { _pTail = pItem; } void ReduceCount() { --_nItems; } BOOL LockList() { if (_cs.IsInitialized()) return _cs.Lock(); else // try initializing again return (_cs.Init() && _cs.Lock()); } void UnlockList() { _cs.Unlock(); } BOOL IsInitialized() { return _cs.IsInitialized(); } ~CList() { INET_ASSERT(_nItems == 0); } }; class CGetHostItem; class CResolverCache { private: SERIALIZED_LIST _ResolverCache; CList* _pHandlesList; public: CResolverCache(DWORD* pdwStatus) { if (!InitializeSerializedList(&_ResolverCache)) { _pHandlesList = NULL; *pdwStatus = ERROR_NOT_ENOUGH_MEMORY; } else { _pHandlesList = New CList(NULL); if (!_pHandlesList || !_pHandlesList->IsInitialized()) *pdwStatus = ERROR_NOT_ENOUGH_MEMORY; } } ~CResolverCache(); SERIALIZED_LIST* GetResolverCacheList() { return &_ResolverCache; } //Use to force all GHBN threads to terminate void ForceEmptyAndDeleteHandlesList(); //Use to force graceful termination of GHBN threads void EmptyHandlesList(); //Used to trim size of GHBN thread list periodically. default for trim size =1 void TrimHandlesListSize(ULONG nTrimSize=1); //Used to add not-cleaned-up resources to handles list. BOOL AddToHandlesList(HANDLE hThread, CGetHostItem* pGetHostItem); }; //This class exists for the following reasons: // 1. to transmit the resolver cache and hostname to the GHBN thread. // 2. to save information regarding above and the thread handle in case we time out in ResolveHost: // in which case, we need to clean up all these resources. // We don't clean up resources in the GHBN thread itself, because we may have to kill off the thread // in case we are unloaded by client without proper cleanup of session handle. class CGetHostItem: public CListItem { private: HANDLE _hThread; //GHBN thread handle to wait on LPSTR _lpszHostName; //copy of host name to free CResolverCache* _pResolverCache; //resolver cache wrapper VOID* _pAlloc; //preallocated memory to get around Rockall allocation issue. DWORD _dwAllocSize; BOOL _fDelete; //delete this memory in the destructor? public: CGetHostItem(LPSTR lpszHostName, CResolverCache* pResolverCache, VOID* pAlloc, DWORD dwAllocSize): _hThread(NULL),_lpszHostName(lpszHostName),_pResolverCache(pResolverCache), _pAlloc(pAlloc),_dwAllocSize(dwAllocSize),_fDelete(FALSE) { } VOID* GetAllocPointer() { return _pAlloc; } DWORD GetAllocSize() { return _dwAllocSize; } VOID SetDelete() { _fDelete = TRUE; } LPSTR GetHostName() { return _lpszHostName; } CResolverCache* GetResolverCache() { return _pResolverCache; } BOOL CanBeDeleted() { DWORD dwExitCode; if (GetExitCodeThread(_hThread, &dwExitCode) && (dwExitCode != STILL_ACTIVE)) return TRUE; else return FALSE; } void SetThreadHandle(HANDLE hThread) { _hThread = hThread; } void ForceDelete() { DWORD dwExitCode; if (GetExitCodeThread(_hThread, &dwExitCode) && (dwExitCode != STILL_ACTIVE)) return; else TerminateThread(_hThread, 0); } void WaitDelete() { WaitForSingleObject(_hThread, INFINITE); } //lpszHostname and pResolverCache will always be non-NULL ( because we check for them // before creating this in ResolveHost_Fsm ) // But hThread may be NULL, in which case the destructor is called immdly. ~CGetHostItem() { FREE_FIXED_MEMORY(_lpszHostName); if (_hThread) CloseHandle(_hThread); if (_fDelete && _pAlloc) FREE_FIXED_MEMORY(_pAlloc); } }; // // CAddressList - maintains list of resolved addresses for a host name/port // combination // class CAddressList { private: CCritSec m_CritSec; // grab this before updating DWORD m_ResolutionId; // determines when OK to resolve INT m_CurrentAddress; // index of current (good) address INT m_AddressCount; // number of addresses in list INT m_BadAddressCount; // number addresses already tried & failed LPRESOLVED_ADDRESS m_Addresses; // list of resolved addresses DWORD IPAddressToAddressList( IN DWORD ipAddr ); DWORD HostentToAddressList( IN LPHOSTENT lpHostent ); public: CAddressList() { m_CritSec.Init(); m_ResolutionId = 0; m_CurrentAddress = 0; m_AddressCount = 0; m_BadAddressCount = 0; m_Addresses = NULL; } ~CAddressList() { FreeList(); } BOOL Acquire(VOID) { return m_CritSec.Lock(); } VOID Release(VOID) { m_CritSec.Unlock(); } VOID FreeList( VOID ); DWORD SetList( IN DWORD dwIpAddress ); DWORD SetList( IN LPHOSTENT lpHostent ); BOOL GetNextAddress( IN OUT LPDWORD lpdwResolutionId, IN OUT LPDWORD lpdwIndex, IN INTERNET_PORT nPort, OUT LPCSADDR_INFO lpResolvedAddress ); VOID InvalidateAddress( IN DWORD dwResolutionId, IN DWORD dwAddressIndex ); DWORD ResolveHost( IN LPSTR lpszHostName, IN OUT LPDWORD lpdwResolutionId, IN DWORD dwFlags ); DWORD ResolveHost_Fsm( IN CFsm_ResolveHost * Fsm ); VOID NextAddress(VOID) { ++m_CurrentAddress; if (m_CurrentAddress == m_AddressCount) { m_CurrentAddress = 0; } } LPCSADDR_INFO CurrentAddress(VOID) { return &m_Addresses[m_CurrentAddress].AddrInfo; } LPSOCKADDR LocalSockaddr() { return CurrentAddress()->LocalAddr.lpSockaddr; } INT LocalSockaddrLength() { return CurrentAddress()->LocalAddr.iSockaddrLength; } INT LocalFamily(VOID) { return (INT)LocalSockaddr()->sa_family; } INT LocalPort() { return ((LPSOCKADDR_IN)LocalSockaddr())->sin_port; } VOID SetLocalPort(INTERNET_PORT Port) { ((LPSOCKADDR_IN)LocalSockaddr())->sin_port = Port; } LPSOCKADDR RemoteSockaddr() { return CurrentAddress()->RemoteAddr.lpSockaddr; } INT RemoteSockaddrLength() { return CurrentAddress()->RemoteAddr.iSockaddrLength; } INT RemoteFamily(VOID) { return (INT)RemoteSockaddr()->sa_family; } INT RemotePort() { return ((LPSOCKADDR_IN)RemoteSockaddr())->sin_port; } INT SocketType(VOID) { return CurrentAddress()->iSocketType; } INT Protocol(VOID) { return CurrentAddress()->iProtocol; } BOOL IsCurrentAddressValid(VOID) { return m_Addresses[m_CurrentAddress].IsValid; } };