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.
461 lines
9.6 KiB
461 lines
9.6 KiB
/*++
|
|
|
|
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;
|
|
}
|
|
};
|