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.
 
 
 
 
 
 

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;
}
};