Source code of Windows XP (NT5)
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.

510 lines
12 KiB

  1. /*++
  2. Copyright (c) 1996 Microsoft Corporation
  3. Module Name :
  4. shash.cxx
  5. Abstract:
  6. This file contains type definitions hash table support
  7. Author:
  8. Revision History:
  9. Rohan Phillips (RohanP) MARCH-08-1997 - modified for SMTP
  10. --*/
  11. #define INCL_INETSRV_INCS
  12. #include "smtpinc.h"
  13. #include "shash.hxx"
  14. CSMTP_HASH_TABLE::~CSMTP_HASH_TABLE()
  15. {
  16. TraceFunctEnterEx((LPARAM)this, "CSMTP_HASH_TABLE::~CSMTP_HASH_TABLE");
  17. RemoveAllEntries();
  18. TraceFunctLeaveEx((LPARAM)this);
  19. }
  20. void CSMTP_HASH_TABLE::RemoveThisEntry(CHASH_ENTRY * pHashEntry, DWORD BucketNum)
  21. {
  22. TraceFunctEnterEx((LPARAM)this, "CSMTP_HASH_TABLE::RemoveThisEntry");
  23. DebugTrace((LPARAM)this, "removing %s from hash table", pHashEntry->GetData());
  24. m_HashTable[BucketNum].m_Lock.ExclusiveLock();
  25. RemoveEntryList(&pHashEntry->QueryListEntry());
  26. m_HashTable[BucketNum].m_Lock.ExclusiveUnlock();
  27. TraceFunctLeaveEx((LPARAM)this);
  28. }
  29. void CSMTP_HASH_TABLE::RemoveAllEntries(void)
  30. {
  31. DWORD LoopVar = 0;
  32. PLIST_ENTRY HeadOfList = NULL;
  33. PLIST_ENTRY pEntry = NULL;
  34. CHASH_ENTRY * pHashEntry = NULL;
  35. TraceFunctEnterEx((LPARAM)this, "CSMTP_HASH_TABLE::RemoveAllEntries");
  36. //say we don't have any wildcard entries anymore
  37. m_fWildCard = FALSE;
  38. for (LoopVar = 0; LoopVar < TABLE_SIZE; LoopVar++)
  39. {
  40. m_HashTable[LoopVar].m_Lock.ExclusiveLock();
  41. HeadOfList = &m_HashTable[LoopVar].m_ListHead;
  42. while (!IsListEmpty(HeadOfList))
  43. {
  44. //remove the entries from the list
  45. pEntry = RemoveHeadList (HeadOfList);
  46. pHashEntry = CONTAINING_RECORD(pEntry, CHASH_ENTRY, m_ListEntry);
  47. //clear inlist flag
  48. pHashEntry->ClearInList();
  49. DebugTrace((LPARAM)this, "removing %s from hash table. RefCnt = %d", pHashEntry->GetData(), pHashEntry->QueryRefCount());
  50. //decrement the ref count. If it hits 0, then the
  51. //entry will be deleted. Else, it means some other
  52. //thread has a refernce to it and that thread will
  53. //delete the object when the ref count hits 0.
  54. pHashEntry->DecRefCount();
  55. //decrement entry counts
  56. m_HashTable[LoopVar].m_NumEntries--;
  57. InterlockedIncrement(&(m_HashTable[LoopVar].m_RefNum));
  58. InterlockedDecrement(&m_TotalEntries);
  59. }
  60. m_HashTable[LoopVar].m_Lock.ExclusiveUnlock();
  61. }
  62. TraceFunctLeaveEx((LPARAM)this);
  63. }
  64. void CSMTP_HASH_TABLE::PrintAllEntries(void)
  65. {
  66. DWORD LoopVar = 0;
  67. PLIST_ENTRY HeadOfList = NULL;
  68. PLIST_ENTRY pEntry = NULL;
  69. PLIST_ENTRY pentryNext = NULL;
  70. CHASH_ENTRY * pHashEntry = NULL;
  71. for (LoopVar = 0; LoopVar < TABLE_SIZE; LoopVar++)
  72. {
  73. m_HashTable[LoopVar].m_Lock.ExclusiveLock();
  74. HeadOfList = &m_HashTable[LoopVar].m_ListHead;
  75. pEntry = m_HashTable[LoopVar].m_ListHead.Flink;
  76. for(; pEntry != HeadOfList; pEntry = pentryNext)
  77. {
  78. pentryNext = pEntry->Flink;
  79. pHashEntry = CONTAINING_RECORD(pEntry, CHASH_ENTRY, m_ListEntry);
  80. printf("%s i n bucket %d\n", pHashEntry->GetData(), LoopVar);
  81. }
  82. m_HashTable[LoopVar].m_Lock.ExclusiveUnlock();
  83. }
  84. }
  85. BOOL CSMTP_HASH_TABLE::InsertIntoTable(CHASH_ENTRY * pHashEntry)
  86. {
  87. unsigned int HashValue = 0;
  88. char * NewData = NULL;
  89. char * ExistingData = NULL;
  90. PLIST_ENTRY HeadOfList = NULL;
  91. PLIST_ENTRY ListEntry =NULL;
  92. CHASH_ENTRY * pExistingEntry = NULL;
  93. int Result = 0;
  94. TraceFunctEnterEx((LPARAM)this, "CSMTP_HASH_TABLE::InsertIntoTable");
  95. _ASSERT(pHashEntry != NULL);
  96. if(pHashEntry == NULL)
  97. {
  98. TraceFunctLeaveEx((LPARAM)this);
  99. return FALSE;
  100. }
  101. //get the new data
  102. NewData = pHashEntry->GetData();
  103. _ASSERT(NewData != NULL);
  104. if(NewData == NULL)
  105. {
  106. TraceFunctLeaveEx((LPARAM)this);
  107. return FALSE;
  108. }
  109. //get the hash value
  110. HashValue = HashFunction (NewData);
  111. //lock the list exclusively
  112. m_HashTable[HashValue].m_Lock.ExclusiveLock();
  113. //insert the head of the list for this bucket
  114. //duplicates are not allowed
  115. HeadOfList = &m_HashTable[HashValue].m_ListHead;
  116. for (ListEntry = HeadOfList->Flink; ListEntry != HeadOfList;
  117. ListEntry = ListEntry->Flink)
  118. {
  119. pExistingEntry = CONTAINING_RECORD(ListEntry, CHASH_ENTRY, m_ListEntry);
  120. ExistingData = pExistingEntry->GetData();
  121. Result = lstrcmpi(NewData, ExistingData);
  122. if(Result < 0)
  123. {
  124. break;
  125. }
  126. else if(Result == 0)
  127. {
  128. ErrorTrace((LPARAM)this, "%s is already in hash table - returning FALSE", pHashEntry->GetData());
  129. if(!m_fDupesAllowed)
  130. {
  131. //duplicates are not allowed
  132. m_HashTable[HashValue].m_Lock.ExclusiveUnlock();
  133. SetLastError(ERROR_DUP_NAME);
  134. TraceFunctLeaveEx((LPARAM)this);
  135. return FALSE;
  136. }
  137. else
  138. {
  139. //duplicates are allowed
  140. break;
  141. }
  142. }
  143. }
  144. // Ok, insert here.
  145. //inc the ref count
  146. pHashEntry->IncRefCount();
  147. // QFE 123862 MarkH: insert before this item
  148. InsertTailList(ListEntry, &pHashEntry->QueryListEntry());
  149. //set inlist flag
  150. pHashEntry->SetInList();
  151. //update total entries in this bucket
  152. m_HashTable[HashValue].m_NumEntries++;
  153. DebugTrace((LPARAM)this, "inserted %s into hash table. RefCnt = %d", pHashEntry->GetData(), pHashEntry->QueryRefCount());
  154. //update numentries in this bucket
  155. InterlockedIncrement(&m_TotalEntries);
  156. //unlock this bucket
  157. m_HashTable[HashValue].m_Lock.ExclusiveUnlock();
  158. TraceFunctLeaveEx((LPARAM)this);
  159. return TRUE;
  160. }
  161. BOOL CSMTP_HASH_TABLE::InsertIntoTableEx(CHASH_ENTRY * pHashEntry, char * szDefaultDomain)
  162. {
  163. return(CSMTP_HASH_TABLE::InsertIntoTable(pHashEntry));
  164. }
  165. BOOL CSMTP_HASH_TABLE::RemoveFromTable(const char * SearchData)
  166. {
  167. unsigned int HashValue;
  168. char * ExistingData = NULL;
  169. PLIST_ENTRY HeadOfList;
  170. PLIST_ENTRY ListEntry;
  171. CHASH_ENTRY * pExistingEntry;
  172. int Result = 0;
  173. TraceFunctEnterEx((LPARAM)this, "CSMTP_HASH_TABLE::RemoveFromTable");
  174. _ASSERT(SearchData != NULL);
  175. if(SearchData == NULL)
  176. {
  177. return FALSE;
  178. }
  179. CharLowerBuff((char *)SearchData, lstrlen(SearchData));
  180. //get the hash value
  181. HashValue = HashFunction (SearchData);
  182. m_HashTable[HashValue].m_Lock.ExclusiveLock();
  183. HeadOfList = &m_HashTable[HashValue].m_ListHead;
  184. for (ListEntry = HeadOfList->Flink; ListEntry != HeadOfList;
  185. ListEntry = ListEntry->Flink)
  186. {
  187. pExistingEntry = CONTAINING_RECORD(ListEntry, CHASH_ENTRY, m_ListEntry);
  188. ExistingData = pExistingEntry->GetData();
  189. Result = lstrcmpi(ExistingData, SearchData);
  190. if(Result == 0)
  191. {
  192. DebugTrace((LPARAM)this, "Removing %s from hash table", ExistingData);
  193. //found it
  194. RemoveEntryList(ListEntry);
  195. m_HashTable[HashValue].m_NumEntries--;
  196. InterlockedIncrement(&(m_HashTable[HashValue].m_RefNum));
  197. //clear inlist flag
  198. pExistingEntry->ClearInList();
  199. pExistingEntry->DecRefCount();
  200. InterlockedDecrement(&m_TotalEntries);
  201. m_HashTable[HashValue].m_Lock.ExclusiveUnlock();
  202. TraceFunctLeaveEx((LPARAM)this);
  203. return TRUE;
  204. }
  205. }
  206. //duplicates are not allowed
  207. SetLastError(ERROR_PATH_NOT_FOUND);
  208. m_HashTable[HashValue].m_Lock.ExclusiveUnlock();
  209. TraceFunctLeaveEx((LPARAM)this);
  210. return FALSE;
  211. }
  212. BOOL CSMTP_HASH_TABLE::RemoveFromTableNoDecRef(const char * SearchData)
  213. {
  214. unsigned int HashValue;
  215. char * ExistingData = NULL;
  216. PLIST_ENTRY HeadOfList;
  217. PLIST_ENTRY ListEntry;
  218. CHASH_ENTRY * pExistingEntry;
  219. int Result = 0;
  220. TraceFunctEnterEx((LPARAM)this, "CSMTP_HASH_TABLE::RemoveFromTableNoDecRef");
  221. _ASSERT(SearchData != NULL);
  222. if(SearchData == NULL)
  223. {
  224. return FALSE;
  225. }
  226. CharLowerBuff((char *)SearchData, lstrlen(SearchData));
  227. //get the hash value
  228. HashValue = HashFunction (SearchData);
  229. m_HashTable[HashValue].m_Lock.ExclusiveLock();
  230. HeadOfList = &m_HashTable[HashValue].m_ListHead;
  231. for (ListEntry = HeadOfList->Flink; ListEntry != HeadOfList;
  232. ListEntry = ListEntry->Flink)
  233. {
  234. pExistingEntry = CONTAINING_RECORD(ListEntry, CHASH_ENTRY, m_ListEntry);
  235. ExistingData = pExistingEntry->GetData();
  236. Result = lstrcmpi(ExistingData, SearchData);
  237. if(Result == 0)
  238. {
  239. DebugTrace((LPARAM)this, "Removing %s from hash table", ExistingData);
  240. //found it
  241. RemoveEntryList(ListEntry);
  242. m_HashTable[HashValue].m_NumEntries--;
  243. InterlockedIncrement(&(m_HashTable[HashValue].m_RefNum));
  244. m_HashTable[HashValue].m_Lock.ExclusiveUnlock();
  245. InterlockedDecrement(&m_TotalEntries);
  246. TraceFunctLeaveEx((LPARAM)this);
  247. return TRUE;
  248. }
  249. }
  250. //duplicates are not allowed
  251. SetLastError(ERROR_PATH_NOT_FOUND);
  252. m_HashTable[HashValue].m_Lock.ExclusiveUnlock();
  253. TraceFunctLeaveEx((LPARAM)this);
  254. return FALSE;
  255. }
  256. CHASH_ENTRY * CSMTP_HASH_TABLE::FindHashData(const char * SearchData, BOOL fUseShareLock, MULTISZ* pmsz)
  257. {
  258. unsigned int HashValue;
  259. char * ExistingData = NULL;
  260. PLIST_ENTRY HeadOfList;
  261. PLIST_ENTRY ListEntry;
  262. CHASH_ENTRY * pExistingEntry;
  263. int Result = 0;
  264. TraceFunctEnterEx((LPARAM)this, "CSMTP_HASH_TABLE::FindHashData");
  265. CharLowerBuff((char *)SearchData, lstrlen(SearchData));
  266. //get the hash value
  267. HashValue = HashFunction (SearchData);
  268. if(fUseShareLock)
  269. m_HashTable[HashValue].m_Lock.ShareLock();
  270. else
  271. m_HashTable[HashValue].m_Lock.ExclusiveLock();
  272. //start search at the head of the list for this bucket
  273. HeadOfList = &m_HashTable[HashValue].m_ListHead;
  274. for (ListEntry = HeadOfList->Flink; ListEntry != HeadOfList;
  275. ListEntry = ListEntry->Flink)
  276. {
  277. pExistingEntry = CONTAINING_RECORD(ListEntry, CHASH_ENTRY, m_ListEntry);
  278. ExistingData = pExistingEntry->GetData();
  279. Result = lstrcmpi(SearchData, ExistingData);
  280. // QFE 123862 MarkH: List is ascending
  281. if(Result < 0)
  282. {
  283. break;
  284. }
  285. else if(Result == 0)
  286. {
  287. //found it
  288. pExistingEntry->IncRefCount();
  289. InterlockedIncrement((LPLONG)&m_CacheHits);
  290. DebugTrace((LPARAM)this, "found %s in hash table", SearchData);
  291. if(!pmsz)
  292. {
  293. if(fUseShareLock)
  294. m_HashTable[HashValue].m_Lock.ShareUnlock();
  295. else
  296. m_HashTable[HashValue].m_Lock.ExclusiveUnlock();
  297. TraceFunctLeaveEx((LPARAM)this);
  298. return pExistingEntry;
  299. }
  300. else
  301. {
  302. MultiszFunction(pExistingEntry, pmsz);
  303. pExistingEntry->DecRefCount();
  304. continue;
  305. }
  306. }
  307. }
  308. DebugTrace((LPARAM)this, "%s was not found in hash table", SearchData);
  309. if(fUseShareLock)
  310. m_HashTable[HashValue].m_Lock.ShareUnlock();
  311. else
  312. m_HashTable[HashValue].m_Lock.ExclusiveUnlock();
  313. InterlockedIncrement((LPLONG)&m_CacheMisses);
  314. SetLastError(ERROR_PATH_NOT_FOUND);
  315. TraceFunctLeaveEx((LPARAM)this);
  316. return NULL;
  317. }
  318. CHASH_ENTRY * CSMTP_HASH_TABLE::UnSafeFindHashData(const char * SearchData)
  319. {
  320. unsigned int HashValue;
  321. char * ExistingData = NULL;
  322. PLIST_ENTRY HeadOfList;
  323. PLIST_ENTRY ListEntry;
  324. CHASH_ENTRY * pExistingEntry;
  325. int Result = 0;
  326. //get the hash value
  327. HashValue = HashFunction (SearchData);
  328. //insert the head of the list for this bucket
  329. //duplicates are not allowed
  330. HeadOfList = &m_HashTable[HashValue].m_ListHead;
  331. for (ListEntry = HeadOfList->Flink; ListEntry != HeadOfList;
  332. ListEntry = ListEntry->Flink)
  333. {
  334. pExistingEntry = CONTAINING_RECORD(ListEntry, CHASH_ENTRY, m_ListEntry);
  335. ExistingData = pExistingEntry->GetData();
  336. Result = lstrcmpi(SearchData, ExistingData);
  337. if(Result < 0)
  338. {
  339. break;
  340. }
  341. else if(Result == 0)
  342. {
  343. //found it
  344. m_HashTable[HashValue].m_Lock.ShareUnlock();
  345. return pExistingEntry;
  346. }
  347. }
  348. //duplicates are not allowed
  349. SetLastError(ERROR_PATH_NOT_FOUND);
  350. return NULL;
  351. }
  352. CHASH_ENTRY * CSMTP_HASH_TABLE::WildCardFindHashData(const char * DomainName)
  353. {
  354. CHASH_ENTRY * pHashEntry = NULL;
  355. char * SearchPtr = NULL;
  356. TraceFunctEnterEx((LPARAM)this, "CSMTP_HASH_TABLE::WildCardFindHashData");
  357. //perform the first level hash
  358. pHashEntry = FindHashData(DomainName, TRUE);
  359. if(pHashEntry != NULL)
  360. {
  361. TraceFunctLeaveEx((LPARAM)this);
  362. return pHashEntry;
  363. }
  364. else if(!m_fWildCard)
  365. {
  366. //if no wildcards are in the table,
  367. //just return NULL. Else, perform
  368. //the multilevel hash
  369. TraceFunctLeaveEx((LPARAM)this);
  370. return NULL;
  371. }
  372. //try to find all sub-domains
  373. SearchPtr = strchr(DomainName, '.');
  374. while(SearchPtr)
  375. {
  376. //skip past '.'
  377. SearchPtr += 1;
  378. //hash this portion of the domain name
  379. pHashEntry = FindHashData(SearchPtr);
  380. if((pHashEntry != NULL) && (pHashEntry->IsWildCard()))
  381. {
  382. TraceFunctLeaveEx((LPARAM)this);
  383. return pHashEntry;
  384. }
  385. else if(pHashEntry)
  386. {
  387. pHashEntry->DecRefCount();
  388. }
  389. SearchPtr = strchr(SearchPtr, '.');
  390. }
  391. //didn't find it.
  392. TraceFunctLeaveEx((LPARAM)this);
  393. return NULL;
  394. }