Windows2003-3790/inetsrv/iis/svcs/smtp/server/shash.cxx
2020-09-30 16:53:55 +02:00

511 lines
12 KiB
C++

/*++
Copyright (c) 1996 Microsoft Corporation
Module Name :
shash.cxx
Abstract:
This file contains type definitions hash table support
Author:
Revision History:
Rohan Phillips (RohanP) MARCH-08-1997 - modified for SMTP
--*/
#define INCL_INETSRV_INCS
#include "smtpinc.h"
#include "shash.hxx"
CSMTP_HASH_TABLE::~CSMTP_HASH_TABLE()
{
TraceFunctEnterEx((LPARAM)this, "CSMTP_HASH_TABLE::~CSMTP_HASH_TABLE");
RemoveAllEntries();
TraceFunctLeaveEx((LPARAM)this);
}
void CSMTP_HASH_TABLE::RemoveThisEntry(CHASH_ENTRY * pHashEntry, DWORD BucketNum)
{
TraceFunctEnterEx((LPARAM)this, "CSMTP_HASH_TABLE::RemoveThisEntry");
DebugTrace((LPARAM)this, "removing %s from hash table", pHashEntry->GetData());
m_HashTable[BucketNum].m_Lock.ExclusiveLock();
RemoveEntryList(&pHashEntry->QueryListEntry());
m_HashTable[BucketNum].m_Lock.ExclusiveUnlock();
TraceFunctLeaveEx((LPARAM)this);
}
void CSMTP_HASH_TABLE::RemoveAllEntries(void)
{
DWORD LoopVar = 0;
PLIST_ENTRY HeadOfList = NULL;
PLIST_ENTRY pEntry = NULL;
CHASH_ENTRY * pHashEntry = NULL;
TraceFunctEnterEx((LPARAM)this, "CSMTP_HASH_TABLE::RemoveAllEntries");
//say we don't have any wildcard entries anymore
m_fWildCard = FALSE;
for (LoopVar = 0; LoopVar < TABLE_SIZE; LoopVar++)
{
m_HashTable[LoopVar].m_Lock.ExclusiveLock();
HeadOfList = &m_HashTable[LoopVar].m_ListHead;
while (!IsListEmpty(HeadOfList))
{
//remove the entries from the list
pEntry = RemoveHeadList (HeadOfList);
pHashEntry = CONTAINING_RECORD(pEntry, CHASH_ENTRY, m_ListEntry);
//clear inlist flag
pHashEntry->ClearInList();
DebugTrace((LPARAM)this, "removing %s from hash table. RefCnt = %d", pHashEntry->GetData(), pHashEntry->QueryRefCount());
//decrement the ref count. If it hits 0, then the
//entry will be deleted. Else, it means some other
//thread has a refernce to it and that thread will
//delete the object when the ref count hits 0.
pHashEntry->DecRefCount();
//decrement entry counts
m_HashTable[LoopVar].m_NumEntries--;
InterlockedIncrement(&(m_HashTable[LoopVar].m_RefNum));
InterlockedDecrement(&m_TotalEntries);
}
m_HashTable[LoopVar].m_Lock.ExclusiveUnlock();
}
TraceFunctLeaveEx((LPARAM)this);
}
void CSMTP_HASH_TABLE::PrintAllEntries(void)
{
DWORD LoopVar = 0;
PLIST_ENTRY HeadOfList = NULL;
PLIST_ENTRY pEntry = NULL;
PLIST_ENTRY pentryNext = NULL;
CHASH_ENTRY * pHashEntry = NULL;
for (LoopVar = 0; LoopVar < TABLE_SIZE; LoopVar++)
{
m_HashTable[LoopVar].m_Lock.ExclusiveLock();
HeadOfList = &m_HashTable[LoopVar].m_ListHead;
pEntry = m_HashTable[LoopVar].m_ListHead.Flink;
for(; pEntry != HeadOfList; pEntry = pentryNext)
{
pentryNext = pEntry->Flink;
pHashEntry = CONTAINING_RECORD(pEntry, CHASH_ENTRY, m_ListEntry);
printf("%s i n bucket %d\n", pHashEntry->GetData(), LoopVar);
}
m_HashTable[LoopVar].m_Lock.ExclusiveUnlock();
}
}
BOOL CSMTP_HASH_TABLE::InsertIntoTable(CHASH_ENTRY * pHashEntry)
{
unsigned int HashValue = 0;
char * NewData = NULL;
char * ExistingData = NULL;
PLIST_ENTRY HeadOfList = NULL;
PLIST_ENTRY ListEntry =NULL;
CHASH_ENTRY * pExistingEntry = NULL;
int Result = 0;
TraceFunctEnterEx((LPARAM)this, "CSMTP_HASH_TABLE::InsertIntoTable");
_ASSERT(pHashEntry != NULL);
if(pHashEntry == NULL)
{
TraceFunctLeaveEx((LPARAM)this);
return FALSE;
}
//get the new data
NewData = pHashEntry->GetData();
_ASSERT(NewData != NULL);
if(NewData == NULL)
{
TraceFunctLeaveEx((LPARAM)this);
return FALSE;
}
//get the hash value
HashValue = HashFunction (NewData);
//lock the list exclusively
m_HashTable[HashValue].m_Lock.ExclusiveLock();
//insert the head of the list for this bucket
//duplicates are not allowed
HeadOfList = &m_HashTable[HashValue].m_ListHead;
for (ListEntry = HeadOfList->Flink; ListEntry != HeadOfList;
ListEntry = ListEntry->Flink)
{
pExistingEntry = CONTAINING_RECORD(ListEntry, CHASH_ENTRY, m_ListEntry);
ExistingData = pExistingEntry->GetData();
Result = lstrcmpi(NewData, ExistingData);
if(Result < 0)
{
break;
}
else if(Result == 0)
{
ErrorTrace((LPARAM)this, "%s is already in hash table - returning FALSE", pHashEntry->GetData());
if(!m_fDupesAllowed)
{
//duplicates are not allowed
m_HashTable[HashValue].m_Lock.ExclusiveUnlock();
SetLastError(ERROR_DUP_NAME);
TraceFunctLeaveEx((LPARAM)this);
return FALSE;
}
else
{
//duplicates are allowed
break;
}
}
}
// Ok, insert here.
//inc the ref count
pHashEntry->IncRefCount();
// QFE 123862 MarkH: insert before this item
InsertTailList(ListEntry, &pHashEntry->QueryListEntry());
//set inlist flag
pHashEntry->SetInList();
//update total entries in this bucket
m_HashTable[HashValue].m_NumEntries++;
DebugTrace((LPARAM)this, "inserted %s into hash table. RefCnt = %d", pHashEntry->GetData(), pHashEntry->QueryRefCount());
//update numentries in this bucket
InterlockedIncrement(&m_TotalEntries);
//unlock this bucket
m_HashTable[HashValue].m_Lock.ExclusiveUnlock();
TraceFunctLeaveEx((LPARAM)this);
return TRUE;
}
BOOL CSMTP_HASH_TABLE::InsertIntoTableEx(CHASH_ENTRY * pHashEntry, char * szDefaultDomain)
{
return(CSMTP_HASH_TABLE::InsertIntoTable(pHashEntry));
}
BOOL CSMTP_HASH_TABLE::RemoveFromTable(const char * SearchData)
{
unsigned int HashValue;
char * ExistingData = NULL;
PLIST_ENTRY HeadOfList;
PLIST_ENTRY ListEntry;
CHASH_ENTRY * pExistingEntry;
int Result = 0;
TraceFunctEnterEx((LPARAM)this, "CSMTP_HASH_TABLE::RemoveFromTable");
_ASSERT(SearchData != NULL);
if(SearchData == NULL)
{
return FALSE;
}
CharLowerBuff((char *)SearchData, lstrlen(SearchData));
//get the hash value
HashValue = HashFunction (SearchData);
m_HashTable[HashValue].m_Lock.ExclusiveLock();
HeadOfList = &m_HashTable[HashValue].m_ListHead;
for (ListEntry = HeadOfList->Flink; ListEntry != HeadOfList;
ListEntry = ListEntry->Flink)
{
pExistingEntry = CONTAINING_RECORD(ListEntry, CHASH_ENTRY, m_ListEntry);
ExistingData = pExistingEntry->GetData();
Result = lstrcmpi(ExistingData, SearchData);
if(Result == 0)
{
DebugTrace((LPARAM)this, "Removing %s from hash table", ExistingData);
//found it
RemoveEntryList(ListEntry);
m_HashTable[HashValue].m_NumEntries--;
InterlockedIncrement(&(m_HashTable[HashValue].m_RefNum));
//clear inlist flag
pExistingEntry->ClearInList();
pExistingEntry->DecRefCount();
InterlockedDecrement(&m_TotalEntries);
m_HashTable[HashValue].m_Lock.ExclusiveUnlock();
TraceFunctLeaveEx((LPARAM)this);
return TRUE;
}
}
//duplicates are not allowed
SetLastError(ERROR_PATH_NOT_FOUND);
m_HashTable[HashValue].m_Lock.ExclusiveUnlock();
TraceFunctLeaveEx((LPARAM)this);
return FALSE;
}
BOOL CSMTP_HASH_TABLE::RemoveFromTableNoDecRef(const char * SearchData)
{
unsigned int HashValue;
char * ExistingData = NULL;
PLIST_ENTRY HeadOfList;
PLIST_ENTRY ListEntry;
CHASH_ENTRY * pExistingEntry;
int Result = 0;
TraceFunctEnterEx((LPARAM)this, "CSMTP_HASH_TABLE::RemoveFromTableNoDecRef");
_ASSERT(SearchData != NULL);
if(SearchData == NULL)
{
return FALSE;
}
CharLowerBuff((char *)SearchData, lstrlen(SearchData));
//get the hash value
HashValue = HashFunction (SearchData);
m_HashTable[HashValue].m_Lock.ExclusiveLock();
HeadOfList = &m_HashTable[HashValue].m_ListHead;
for (ListEntry = HeadOfList->Flink; ListEntry != HeadOfList;
ListEntry = ListEntry->Flink)
{
pExistingEntry = CONTAINING_RECORD(ListEntry, CHASH_ENTRY, m_ListEntry);
ExistingData = pExistingEntry->GetData();
Result = lstrcmpi(ExistingData, SearchData);
if(Result == 0)
{
DebugTrace((LPARAM)this, "Removing %s from hash table", ExistingData);
//found it
RemoveEntryList(ListEntry);
m_HashTable[HashValue].m_NumEntries--;
InterlockedIncrement(&(m_HashTable[HashValue].m_RefNum));
m_HashTable[HashValue].m_Lock.ExclusiveUnlock();
InterlockedDecrement(&m_TotalEntries);
TraceFunctLeaveEx((LPARAM)this);
return TRUE;
}
}
//duplicates are not allowed
SetLastError(ERROR_PATH_NOT_FOUND);
m_HashTable[HashValue].m_Lock.ExclusiveUnlock();
TraceFunctLeaveEx((LPARAM)this);
return FALSE;
}
CHASH_ENTRY * CSMTP_HASH_TABLE::FindHashData(const char * SearchData, BOOL fUseShareLock, MULTISZ* pmsz)
{
unsigned int HashValue;
char * ExistingData = NULL;
PLIST_ENTRY HeadOfList;
PLIST_ENTRY ListEntry;
CHASH_ENTRY * pExistingEntry;
int Result = 0;
TraceFunctEnterEx((LPARAM)this, "CSMTP_HASH_TABLE::FindHashData");
CharLowerBuff((char *)SearchData, lstrlen(SearchData));
//get the hash value
HashValue = HashFunction (SearchData);
if(fUseShareLock)
m_HashTable[HashValue].m_Lock.ShareLock();
else
m_HashTable[HashValue].m_Lock.ExclusiveLock();
//start search at the head of the list for this bucket
HeadOfList = &m_HashTable[HashValue].m_ListHead;
for (ListEntry = HeadOfList->Flink; ListEntry != HeadOfList;
ListEntry = ListEntry->Flink)
{
pExistingEntry = CONTAINING_RECORD(ListEntry, CHASH_ENTRY, m_ListEntry);
ExistingData = pExistingEntry->GetData();
Result = lstrcmpi(SearchData, ExistingData);
// QFE 123862 MarkH: List is ascending
if(Result < 0)
{
break;
}
else if(Result == 0)
{
//found it
pExistingEntry->IncRefCount();
InterlockedIncrement((LPLONG)&m_CacheHits);
DebugTrace((LPARAM)this, "found %s in hash table", SearchData);
if(!pmsz)
{
if(fUseShareLock)
m_HashTable[HashValue].m_Lock.ShareUnlock();
else
m_HashTable[HashValue].m_Lock.ExclusiveUnlock();
TraceFunctLeaveEx((LPARAM)this);
return pExistingEntry;
}
else
{
MultiszFunction(pExistingEntry, pmsz);
pExistingEntry->DecRefCount();
continue;
}
}
}
DebugTrace((LPARAM)this, "%s was not found in hash table", SearchData);
if(fUseShareLock)
m_HashTable[HashValue].m_Lock.ShareUnlock();
else
m_HashTable[HashValue].m_Lock.ExclusiveUnlock();
InterlockedIncrement((LPLONG)&m_CacheMisses);
SetLastError(ERROR_PATH_NOT_FOUND);
TraceFunctLeaveEx((LPARAM)this);
return NULL;
}
CHASH_ENTRY * CSMTP_HASH_TABLE::UnSafeFindHashData(const char * SearchData)
{
unsigned int HashValue;
char * ExistingData = NULL;
PLIST_ENTRY HeadOfList;
PLIST_ENTRY ListEntry;
CHASH_ENTRY * pExistingEntry;
int Result = 0;
//get the hash value
HashValue = HashFunction (SearchData);
//insert the head of the list for this bucket
//duplicates are not allowed
HeadOfList = &m_HashTable[HashValue].m_ListHead;
for (ListEntry = HeadOfList->Flink; ListEntry != HeadOfList;
ListEntry = ListEntry->Flink)
{
pExistingEntry = CONTAINING_RECORD(ListEntry, CHASH_ENTRY, m_ListEntry);
ExistingData = pExistingEntry->GetData();
Result = lstrcmpi(SearchData, ExistingData);
if(Result < 0)
{
break;
}
else if(Result == 0)
{
//found it
m_HashTable[HashValue].m_Lock.ShareUnlock();
return pExistingEntry;
}
}
//duplicates are not allowed
SetLastError(ERROR_PATH_NOT_FOUND);
return NULL;
}
CHASH_ENTRY * CSMTP_HASH_TABLE::WildCardFindHashData(const char * DomainName)
{
CHASH_ENTRY * pHashEntry = NULL;
char * SearchPtr = NULL;
TraceFunctEnterEx((LPARAM)this, "CSMTP_HASH_TABLE::WildCardFindHashData");
//perform the first level hash
pHashEntry = FindHashData(DomainName, TRUE);
if(pHashEntry != NULL)
{
TraceFunctLeaveEx((LPARAM)this);
return pHashEntry;
}
else if(!m_fWildCard)
{
//if no wildcards are in the table,
//just return NULL. Else, perform
//the multilevel hash
TraceFunctLeaveEx((LPARAM)this);
return NULL;
}
//try to find all sub-domains
SearchPtr = strchr(DomainName, '.');
while(SearchPtr)
{
//skip past '.'
SearchPtr += 1;
//hash this portion of the domain name
pHashEntry = FindHashData(SearchPtr);
if((pHashEntry != NULL) && (pHashEntry->IsWildCard()))
{
TraceFunctLeaveEx((LPARAM)this);
return pHashEntry;
}
else if(pHashEntry)
{
pHashEntry->DecRefCount();
}
SearchPtr = strchr(SearchPtr, '.');
}
//didn't find it.
TraceFunctLeaveEx((LPARAM)this);
return NULL;
}