/*++ 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; }