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.

394 lines
11 KiB

  1. //--------------------------------------------------------------------
  2. // Copyright (C) Microsoft Corporation, 1997 - 2000
  3. //
  4. // ecblist.c
  5. //
  6. // Simple hash table support for keeping a list of active ECBs.
  7. //
  8. // History:
  9. //
  10. // Edward Reus 12-08-97 Initial Version.
  11. // Edward Reus 03-01-2000 Convert to hash table.
  12. //--------------------------------------------------------------------
  13. #include <sysinc.h>
  14. #include <rpc.h>
  15. #include <winsock2.h>
  16. #include <httpfilt.h>
  17. #include <httpext.h>
  18. #include "ecblist.h"
  19. #include "filter.h"
  20. //--------------------------------------------------------------------
  21. // InitializeECBList()
  22. //
  23. // Create an empty ECB list. If the list is successfully created,
  24. // the return a pointer to it, else return NULL.
  25. //
  26. // This will fail (return FALSE) if either the memory allocation
  27. // for the list failed, or if the initialization of a critical
  28. // section for the list failed.
  29. //--------------------------------------------------------------------
  30. ACTIVE_ECB_LIST *InitializeECBList()
  31. {
  32. int i;
  33. DWORD dwStatus;
  34. DWORD dwSpinCount = 0x80000008; // Preallocate event, spincount is 4096.
  35. ACTIVE_ECB_LIST *pECBList;
  36. pECBList = MemAllocate(sizeof(ACTIVE_ECB_LIST));
  37. if (!pECBList)
  38. {
  39. return NULL;
  40. }
  41. memset(pECBList,0,sizeof(ACTIVE_ECB_LIST));
  42. dwStatus = RtlInitializeCriticalSectionAndSpinCount(&pECBList->cs,dwSpinCount);
  43. if (dwStatus != 0)
  44. {
  45. MemFree(pECBList);
  46. return NULL;
  47. }
  48. for (i=0; i<HASH_SIZE; i++)
  49. {
  50. InitializeListHead( &(pECBList->HashTable[i]) );
  51. }
  52. return pECBList;
  53. }
  54. //--------------------------------------------------------------------
  55. // EmptyECBList()
  56. //
  57. // Return true iff the ECB list holds at least one active ECB.
  58. //--------------------------------------------------------------------
  59. BOOL EmptyECBList( IN ACTIVE_ECB_LIST *pECBList )
  60. {
  61. ASSERT(pECBList);
  62. return (pECBList->dwNumEntries > 0);
  63. }
  64. //--------------------------------------------------------------------
  65. // InternalLookup()
  66. //
  67. // Do a non-protected lookup for the specified ECB. If its found, then
  68. // return a pointer to its ECB_ENTRY, else return NULL.
  69. //--------------------------------------------------------------------
  70. ECB_ENTRY *InternalLookup( IN ACTIVE_ECB_LIST *pECBList,
  71. IN EXTENSION_CONTROL_BLOCK *pECB )
  72. {
  73. DWORD dwHash;
  74. LIST_ENTRY *pHead;
  75. LIST_ENTRY *pListEntry;
  76. ECB_ENTRY *pECBEntry;
  77. dwHash = ECB_HASH(pECB);
  78. pHead = &(pECBList->HashTable[dwHash]);
  79. pListEntry = pHead->Flink;
  80. while (pListEntry != pHead)
  81. {
  82. pECBEntry = CONTAINING_RECORD(pListEntry,ECB_ENTRY,ListEntry);
  83. if (pECB == pECBEntry->pECB)
  84. {
  85. return pECBEntry;
  86. }
  87. pListEntry = pListEntry->Flink;
  88. }
  89. return NULL;
  90. }
  91. //--------------------------------------------------------------------
  92. // LookupInECBList()
  93. //
  94. // Look for the specified extension control block (pECB) on the
  95. // list of active ECBs. If its found, then return a pointer to it.
  96. // If its not found then return NULL.
  97. //--------------------------------------------------------------------
  98. EXTENSION_CONTROL_BLOCK *LookupInECBList(
  99. IN ACTIVE_ECB_LIST *pECBList,
  100. IN EXTENSION_CONTROL_BLOCK *pECB )
  101. {
  102. DWORD dwStatus;
  103. ECB_ENTRY *pECBEntry;
  104. EXTENSION_CONTROL_BLOCK *pRet = NULL;
  105. ASSERT(pECBList);
  106. ASSERT(pECB);
  107. if (pECBList->dwNumEntries == 0)
  108. {
  109. return NULL;
  110. }
  111. dwStatus = RtlEnterCriticalSection(&pECBList->cs);
  112. ASSERT(dwStatus == 0);
  113. pECBEntry = InternalLookup(pECBList,pECB);
  114. if (pECBEntry)
  115. {
  116. pRet = pECB;
  117. }
  118. dwStatus = RtlLeaveCriticalSection(&pECBList->cs);
  119. ASSERT(dwStatus == 0);
  120. return pRet;
  121. }
  122. //--------------------------------------------------------------------
  123. // AddToECBList()
  124. //
  125. // Add the specified extension control block (pECB) to the list
  126. // of active ECBs. If the ECB is already in the list of active ECBs
  127. // then return success (already added).
  128. //
  129. // Return TRUE on success, FALSE on failure.
  130. //--------------------------------------------------------------------
  131. BOOL AddToECBList( IN ACTIVE_ECB_LIST *pECBList,
  132. IN EXTENSION_CONTROL_BLOCK *pECB )
  133. {
  134. DWORD dwStatus;
  135. DWORD dwHash;
  136. ECB_ENTRY *pECBEntry;
  137. ASSERT(pECBList);
  138. ASSERT(pECB);
  139. dwStatus = RtlEnterCriticalSection(&pECBList->cs);
  140. ASSERT(dwStatus == 0);
  141. //
  142. // Check to see if the ECB is alreay on the list...
  143. //
  144. pECBEntry = InternalLookup(pECBList,pECB);
  145. if (pECBEntry)
  146. {
  147. #ifdef DBG_ERROR
  148. DbgPrint("RpcProxy: AddToECBList(): pECB (0x%p) already in list\n",pECB);
  149. #endif
  150. dwStatus = RtlLeaveCriticalSection(&pECBList->cs);
  151. ASSERT(dwStatus == 0);
  152. return TRUE;
  153. }
  154. //
  155. // Make up a new ECB entry:
  156. //
  157. pECBEntry = MemAllocate(sizeof(ECB_ENTRY));
  158. if (!pECBEntry)
  159. {
  160. dwStatus = RtlLeaveCriticalSection(&pECBList->cs);
  161. ASSERT(dwStatus == 0);
  162. return FALSE;
  163. }
  164. pECBEntry->lRefCount = 1; // Take the first reference...
  165. pECBEntry->dwTickCount = 0; // Set when connection is closed.
  166. pECBEntry->pECB = pECB; // Cache the Extension Control Block.
  167. dwHash = ECB_HASH(pECB);
  168. InsertHeadList( &(pECBList->HashTable[dwHash]),
  169. &(pECBEntry->ListEntry) );
  170. pECBList->dwNumEntries++;
  171. dwStatus = RtlLeaveCriticalSection(&pECBList->cs);
  172. ASSERT(dwStatus == 0);
  173. return TRUE;
  174. }
  175. //--------------------------------------------------------------------
  176. // IncrementECBRefCount()
  177. //
  178. // Find the specified ECB in the list and increment its refcount.
  179. // Return TRUE if its found, FALSE if it isn't on the list.
  180. //
  181. // Note: That the RefCount shouldn't go over 2 (or less than 0).
  182. //--------------------------------------------------------------------
  183. BOOL IncrementECBRefCount( IN ACTIVE_ECB_LIST *pECBList,
  184. IN EXTENSION_CONTROL_BLOCK *pECB )
  185. {
  186. DWORD dwStatus;
  187. DWORD dwHash;
  188. ECB_ENTRY *pECBEntry;
  189. ASSERT(pECBList);
  190. ASSERT(pECB);
  191. dwStatus = RtlEnterCriticalSection(&pECBList->cs);
  192. ASSERT(dwStatus == 0);
  193. //
  194. // Look for the ECB:
  195. //
  196. pECBEntry = InternalLookup(pECBList,pECB);
  197. if (pECBEntry)
  198. {
  199. pECBEntry->lRefCount++;
  200. }
  201. dwStatus = RtlLeaveCriticalSection(&pECBList->cs);
  202. ASSERT(dwStatus == 0);
  203. return (pECBEntry != NULL);
  204. }
  205. //--------------------------------------------------------------------
  206. // DecrementECBRefCount()
  207. //
  208. // Look for the specified ECB in the list and if found, decrement its
  209. // refcount. If the RefCount falls to zero, then remove it from the
  210. // list and return it. If the refcount is greater than zero (or the
  211. // ECB wasn't on the lsit) then return NULL.
  212. //--------------------------------------------------------------------
  213. EXTENSION_CONTROL_BLOCK *DecrementECBRefCount(
  214. IN ACTIVE_ECB_LIST *pECBList,
  215. IN EXTENSION_CONTROL_BLOCK *pECB )
  216. {
  217. DWORD dwStatus;
  218. ECB_ENTRY *pECBEntry;
  219. EXTENSION_CONTROL_BLOCK *pRet = NULL;
  220. ASSERT(pECBList);
  221. ASSERT(pECB);
  222. dwStatus = RtlEnterCriticalSection(&pECBList->cs);
  223. ASSERT(dwStatus == 0);
  224. //
  225. // Look for the ECB:
  226. //
  227. pECBEntry = InternalLookup(pECBList,pECB);
  228. if (pECBEntry)
  229. {
  230. pECBEntry->lRefCount--;
  231. ASSERT(pECBEntry->lRefCount >= 0);
  232. if (pECBEntry->lRefCount <= 0)
  233. {
  234. RemoveEntryList( &(pECBEntry->ListEntry) );
  235. pRet = pECBEntry->pECB;
  236. MemFree(pECBEntry);
  237. pECBList->dwNumEntries--;
  238. }
  239. }
  240. dwStatus = RtlLeaveCriticalSection(&pECBList->cs);
  241. ASSERT(dwStatus == 0);
  242. return pRet;
  243. }
  244. //--------------------------------------------------------------------
  245. // LookupRemoveFromECBList()
  246. //
  247. // Look for the specified extension control block (pECB) on the
  248. // list of active ECBs. If its found, then remove it from the active
  249. // list and return a pointer to it. If its not found then return
  250. // NULL.
  251. //--------------------------------------------------------------------
  252. EXTENSION_CONTROL_BLOCK *LookupRemoveFromECBList(
  253. IN ACTIVE_ECB_LIST *pECBList,
  254. IN EXTENSION_CONTROL_BLOCK *pECB )
  255. {
  256. DWORD dwStatus;
  257. ECB_ENTRY *pECBEntry;
  258. EXTENSION_CONTROL_BLOCK *pRet = NULL;
  259. ASSERT(pECBList);
  260. ASSERT(pECB);
  261. dwStatus = RtlEnterCriticalSection(&pECBList->cs);
  262. ASSERT(dwStatus == 0);
  263. //
  264. // Look for the ECB:
  265. //
  266. pECBEntry = InternalLookup(pECBList,pECB);
  267. if (pECBEntry)
  268. {
  269. RemoveEntryList( &(pECBEntry->ListEntry) );
  270. MemFree(pECBEntry);
  271. pECBList->dwNumEntries--;
  272. pRet = pECB;
  273. }
  274. dwStatus = RtlLeaveCriticalSection(&pECBList->cs);
  275. ASSERT(dwStatus == 0);
  276. return pRet;
  277. }
  278. #ifdef DBG
  279. //--------------------------------------------------------------------
  280. // CountBucket()
  281. //
  282. // Helper used by CheckECBHashBalance() to count the number of entries
  283. // in a hast table bucket.
  284. //--------------------------------------------------------------------
  285. int CountBucket( IN LIST_ENTRY *pBucket )
  286. {
  287. int iCount = 0;
  288. LIST_ENTRY *p = pBucket->Flink;
  289. while (p != pBucket)
  290. {
  291. iCount++;
  292. p = p->Flink;
  293. }
  294. return iCount;
  295. }
  296. //--------------------------------------------------------------------
  297. // CheckECBHashBalance()
  298. //
  299. // DBG code to walk through the hash table and inspect the hash buckets
  300. // for collisions. A will balanced hash table will have a nice uniform
  301. // distribution of entries spread throughout the hash buckets in the
  302. // hash table.
  303. //--------------------------------------------------------------------
  304. void CheckECBHashBalance( IN ACTIVE_ECB_LIST *pECBList )
  305. {
  306. #define ICOUNTS 7
  307. #define ILAST (ICOUNTS-1)
  308. #define TOO_MANY_COLLISIONS_POINT 3
  309. int i;
  310. int iCount;
  311. int iHashCounts[ICOUNTS];
  312. BOOL fAssert = FALSE;
  313. memset(iHashCounts,0,sizeof(iHashCounts));
  314. for (i=0; i<HASH_SIZE; i++)
  315. {
  316. iCount = CountBucket( &(pECBList->HashTable[i]) );
  317. if (iCount < ILAST)
  318. {
  319. iHashCounts[iCount]++;
  320. }
  321. else
  322. {
  323. iHashCounts[ILAST]++;
  324. }
  325. }
  326. DbgPrint("CheckECBHashBalance():\n");
  327. for (i=0; i<ICOUNTS; i++)
  328. {
  329. DbgPrint(" Buckets with %d entries: %d\n",i,iHashCounts[i]);
  330. if ((i>=TOO_MANY_COLLISIONS_POINT)&&(iHashCounts[i] > 0))
  331. {
  332. fAssert = TRUE;
  333. }
  334. }
  335. ASSERT(fAssert == FALSE);
  336. }
  337. #endif