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.

754 lines
15 KiB

  1. /*++
  2. Copyright (c) 1997 Microsoft Corporation
  3. Module Name:
  4. iisassoc.cxx
  5. Abstract:
  6. This module implements the IIS_ASSOCIATION class.
  7. Author:
  8. Keith Moore (keithmo) 16-Jan-1997
  9. Revision History:
  10. --*/
  11. #include "tcpdllp.hxx"
  12. #pragma hdrstop
  13. #include <iisassoc.hxx>
  14. //
  15. // Private constants.
  16. //
  17. #define HASH_FROM_CONTEXT(ctx) \
  18. ( \
  19. (m_HashIpAddress ? ctx->IpAddressHash : 0) + \
  20. (m_HashHostName ? ctx->HostNameHash : 0) \
  21. )
  22. //
  23. // Private types.
  24. //
  25. typedef struct _HASH_ENTRY {
  26. LIST_ENTRY HashBucketListEntry;
  27. DWORD IpAddress;
  28. DWORD Hash;
  29. LPVOID Context;
  30. CHAR HostName[1]; // Expands as needed. MUST BE LAST FIELD IN STRUCTURE!
  31. } HASH_ENTRY, *PHASH_ENTRY;
  32. //
  33. // Private globals.
  34. //
  35. //
  36. // Private prototypes.
  37. //
  38. //
  39. // Public functions.
  40. //
  41. IIS_ASSOCIATION::IIS_ASSOCIATION(
  42. IN BOOL HashIpAddress,
  43. IN BOOL HashHostName,
  44. IN INT NumHashBuckets
  45. ) :
  46. m_HashIpAddress( HashIpAddress ),
  47. m_HashHostName( HashHostName ),
  48. m_NumHashBuckets( NumHashBuckets ),
  49. m_HashBuckets( NULL )
  50. /*++
  51. Routine Description:
  52. IIS_ASSOCIATION constructor.
  53. Arguments:
  54. HashIpAddress - TRUE if this association should hash the IP address.
  55. HashHostName - TRUE if this association should hash the host name.
  56. NumHashBuckets - The number of hash buckets to create for this
  57. association.
  58. Return Value:
  59. None.
  60. --*/
  61. {
  62. //
  63. // Sanity check.
  64. //
  65. DBG_ASSERT( HashIpAddress || HashHostName );
  66. DBG_ASSERT( NumHashBuckets > 0 );
  67. //
  68. // Initialize the hash buckets.
  69. //
  70. m_HashBuckets = new LIST_ENTRY[m_NumHashBuckets];
  71. if( m_HashBuckets == NULL ) {
  72. SetLastError( ERROR_NOT_ENOUGH_MEMORY );
  73. } else {
  74. for( INT i = 0 ; i < m_NumHashBuckets ; i++ ) {
  75. InitializeListHead( &m_HashBuckets[i] );
  76. }
  77. }
  78. } // IIS_ASSOCIATION::IIS_ASSOCIATION
  79. IIS_ASSOCIATION::~IIS_ASSOCIATION()
  80. /*++
  81. Routine Description:
  82. IIS_ASSOCIATION destructor.
  83. Arguments:
  84. None.
  85. Return Value:
  86. None.
  87. --*/
  88. {
  89. INT i;
  90. PLIST_ENTRY hashBucket;
  91. PLIST_ENTRY listEntry;
  92. PHASH_ENTRY hashEntry;
  93. //
  94. // Purge the hash bucket entries.
  95. //
  96. for( i = 0, hashBucket = m_HashBuckets ;
  97. i < m_NumHashBuckets ;
  98. i++, hashBucket++ ) {
  99. while( !IsListEmpty( hashBucket ) ) {
  100. listEntry = RemoveHeadList( hashBucket );
  101. hashEntry = CONTAINING_RECORD(
  102. listEntry,
  103. HASH_ENTRY,
  104. HashBucketListEntry
  105. );
  106. delete hashEntry;
  107. }
  108. }
  109. //
  110. // Delete the hash bucket array.
  111. //
  112. delete m_HashBuckets;
  113. } // IIS_ASSOCIATION::~IIS_ASSOCIATION
  114. DWORD
  115. IIS_ASSOCIATION::AddDescriptor(
  116. IN DWORD IpAddress,
  117. IN const CHAR * HostName,
  118. IN LPVOID Context,
  119. IN OUT PHASH_CONTEXT HashContext OPTIONAL
  120. )
  121. /*++
  122. Routine Description:
  123. Adds a new descriptor to the association.
  124. Arguments:
  125. IpAddress - The descriptor IP address. Ignored if the association
  126. was not created with HashIpAddress == TRUE.
  127. HostName - The descriptor host name. Ignored if the association was
  128. not created with HashHostName == TRUE.
  129. Context - A context to associate with the descriptor.
  130. HashContext - An optional hash context from a previous call to one
  131. of the association functions. This is used to avoid redundant
  132. hash calculations. If NULL, then a temporary hash context is
  133. created and used.
  134. Return Value:
  135. DWORD - Completion status. 0 if successful, !0 otherwise.
  136. --*/
  137. {
  138. HASH_CONTEXT localContext;
  139. PHASH_ENTRY hashEntry;
  140. //
  141. // If a hash context was specified, use it. Otherwise, initialize a
  142. // local context and use it instead.
  143. //
  144. if( HashContext == NULL ) {
  145. HashContext = &localContext;
  146. InitializeHashContext( &localContext );
  147. }
  148. //
  149. // Get the hash.
  150. //
  151. CalculateHash(
  152. IpAddress,
  153. HostName,
  154. HashContext
  155. );
  156. //
  157. // Try to find the descriptor in the hash table. If it's there, then
  158. // fail the request. Otherwise, create a new hash entry and stick it
  159. // in the table.
  160. //
  161. hashEntry = FindDescriptor(
  162. IpAddress,
  163. HostName,
  164. HashContext
  165. );
  166. if( hashEntry == NULL ) {
  167. hashEntry = CreateHashEntry(
  168. IpAddress,
  169. HostName,
  170. HashContext
  171. );
  172. if( hashEntry != NULL ) {
  173. InsertHeadList(
  174. &m_HashBuckets[hashEntry->Hash % m_NumHashBuckets],
  175. &hashEntry->HashBucketListEntry
  176. );
  177. hashEntry->Context = Context;
  178. return NO_ERROR;
  179. }
  180. return ERROR_NOT_ENOUGH_MEMORY;
  181. }
  182. return ERROR_DUP_NAME;
  183. } // IIS_ASSOCIATION::AddDescriptor
  184. DWORD
  185. IIS_ASSOCIATION::LookupDescriptor(
  186. IN DWORD IpAddress,
  187. IN const CHAR * HostName OPTIONAL,
  188. OUT LPVOID *Context,
  189. IN OUT PHASH_CONTEXT HashContext
  190. )
  191. /*++
  192. Routine Description:
  193. Searches the association for the specified descriptor.
  194. Arguments:
  195. IpAddress - The descriptor IP address. Ignored if the association
  196. was not created with HashIpAddress == TRUE.
  197. HostName - The descriptor host name. Ignored if the association was
  198. not created with HashHostName == TRUE.
  199. Context - Recieves the context associated with the descriptor if
  200. successful.
  201. HashContext - An optional hash context from a previous call to one
  202. of the association functions. This is used to avoid redundant
  203. hash calculations. If NULL, then a temporary hash context is
  204. created and used.
  205. Return Value:
  206. DWORD - Completion status. 0 if successful, !0 otherwise.
  207. --*/
  208. {
  209. HASH_CONTEXT localContext;
  210. PHASH_ENTRY hashEntry;
  211. //
  212. // If a hash context was specified, use it. Otherwise, initialize a
  213. // local context and use it instead.
  214. //
  215. if( HashContext == NULL ) {
  216. HashContext = &localContext;
  217. InitializeHashContext( &localContext );
  218. }
  219. //
  220. // Get the hash.
  221. //
  222. CalculateHash(
  223. IpAddress,
  224. HostName,
  225. HashContext
  226. );
  227. //
  228. // Try to find the descriptor in the hash table. If it's there, then
  229. // return the context to the caller. Otherwise, fail the request.
  230. //
  231. hashEntry = FindDescriptor(
  232. IpAddress,
  233. HostName,
  234. HashContext
  235. );
  236. if( hashEntry != NULL ) {
  237. *Context = hashEntry->Context;
  238. return NO_ERROR;
  239. }
  240. return ERROR_INVALID_PARAMETER;
  241. } // IIS_ASSOCIATION::LookupDescriptor
  242. DWORD
  243. IIS_ASSOCIATION::RemoveDescriptor(
  244. IN DWORD IpAddress,
  245. IN const CHAR * HostName OPTIONAL,
  246. OUT LPVOID *Context,
  247. IN OUT PHASH_CONTEXT HashContext
  248. )
  249. /*++
  250. Routine Description:
  251. Removes a descriptor from the association.
  252. Arguments:
  253. IpAddress - The descriptor IP address. Ignored if the association
  254. was not created with HashIpAddress == TRUE.
  255. HostName - The descriptor host name. Ignored if the association was
  256. not created with HashHostName == TRUE.
  257. Context - Receives the context associated with the descriptor if
  258. successful.
  259. HashContext - An optional hash context from a previous call to one
  260. of the association functions. This is used to avoid redundant
  261. hash calculations. If NULL, then a temporary hash context is
  262. created and used.
  263. Return Value:
  264. DWORD - Completion status. 0 if successful, !0 otherwise.
  265. --*/
  266. {
  267. HASH_CONTEXT localContext;
  268. PHASH_ENTRY hashEntry;
  269. //
  270. // If a hash context was specified, use it. Otherwise, initialize a
  271. // local context and use it instead.
  272. //
  273. if( HashContext == NULL ) {
  274. HashContext = &localContext;
  275. InitializeHashContext( &localContext );
  276. }
  277. //
  278. // Get the hash.
  279. //
  280. CalculateHash(
  281. IpAddress,
  282. HostName,
  283. HashContext
  284. );
  285. //
  286. // Try to find the descriptor in the hash table. If it's there, then
  287. // remove it from the hash table and return the context to the caller.
  288. // Otherwise, fail the request.
  289. //
  290. hashEntry = FindDescriptor(
  291. IpAddress,
  292. HostName,
  293. HashContext
  294. );
  295. if( hashEntry != NULL ) {
  296. *Context = hashEntry->Context;
  297. RemoveEntryList(
  298. &hashEntry->HashBucketListEntry
  299. );
  300. delete hashEntry;
  301. return NO_ERROR;
  302. }
  303. return ERROR_INVALID_PARAMETER;
  304. } // IIS_ASSOCIATION::RemoveDescriptor
  305. VOID
  306. IIS_ASSOCIATION::EnumDescriptors(
  307. IN LPFN_ASSOCIATION_CALLBACK Callback,
  308. IN LPVOID CallbackContext
  309. )
  310. /*++
  311. Routine Description:
  312. Enumerates the descriptors in the association.
  313. Arguments:
  314. Callback - A function to call for every descriptor.
  315. CallbackContext - A context to pass back to the callback.
  316. Return Value:
  317. None.
  318. --*/
  319. {
  320. INT i;
  321. PLIST_ENTRY listEntry;
  322. PLIST_ENTRY hashBuckets;
  323. PHASH_ENTRY hashEntry;
  324. DBG_ASSERT( Callback != NULL );
  325. for( i = 0, hashBuckets = m_HashBuckets ;
  326. i < m_NumHashBuckets ;
  327. i++, hashBuckets++ ) {
  328. listEntry = hashBuckets->Flink;
  329. while( listEntry != hashBuckets ) {
  330. hashEntry = CONTAINING_RECORD(
  331. listEntry,
  332. HASH_ENTRY,
  333. HashBucketListEntry
  334. );
  335. listEntry = listEntry->Flink;
  336. if( !(Callback)(
  337. CallbackContext,
  338. hashEntry->Context,
  339. hashEntry->IpAddress,
  340. hashEntry->HostName
  341. ) ) {
  342. break;
  343. }
  344. }
  345. }
  346. } // IIS_ASSOCIATION::EnumDescriptors
  347. //
  348. // Private functions.
  349. //
  350. VOID
  351. IIS_ASSOCIATION::CalculateHash(
  352. IN DWORD IpAddress,
  353. IN const CHAR * HostName OPTIONAL,
  354. OUT PHASH_CONTEXT HashContext
  355. )
  356. /*++
  357. Routine Description:
  358. Calculates the hash of the IP address (if HashIpAddress == TRUE) and/or
  359. the host name (if HashHostName == TRUE).
  360. Arguments:
  361. IpAddress - The descriptor IP address. Ignored if the association
  362. was not created with HashIpAddress == TRUE.
  363. HostName - The descriptor host name. Ignored if the association was
  364. not created with HashHostName == TRUE.
  365. HashContext - Will receive the updated hash.
  366. Return Value:
  367. None.
  368. --*/
  369. {
  370. //
  371. // Calculate the IP address hash if needed and not already calculated.
  372. //
  373. if( HashContext->IpAddressHash == 0 && m_HashIpAddress ) {
  374. HashContext->IpAddressHash = IpAddress;
  375. if( HashContext->IpAddressHash == 0 ) {
  376. HashContext->IpAddressHash++;
  377. }
  378. }
  379. //
  380. // Calculate the host name hash if needed and not already calculated.
  381. //
  382. if( HashContext->HostNameHash == 0 && m_HashHostName ) {
  383. DWORD hash = 0;
  384. DBG_ASSERT( HostName != NULL );
  385. while( *HostName ) {
  386. CHAR ch;
  387. ch = *HostName++;
  388. //
  389. // This is basically toupper() for 7-bit ASCII. This is
  390. // OK for DNS names.
  391. //
  392. if( ch >= 'a' && ch <= 'z' ) {
  393. ch -= ( 'a' - 'A' );
  394. }
  395. hash = ( hash * 5 ) + (DWORD)ch;
  396. }
  397. if( hash == 0 ) {
  398. hash++;
  399. }
  400. HashContext->HostNameHash = hash;
  401. }
  402. } // IIS_ASSOCIATION::CalculateHash
  403. PHASH_ENTRY
  404. IIS_ASSOCIATION::FindDescriptor(
  405. IN DWORD IpAddress,
  406. IN const CHAR * HostName OPTIONAL,
  407. IN PHASH_CONTEXT HashContext
  408. )
  409. /*++
  410. Routine Description:
  411. Finds a descriptor in the association.
  412. Arguments:
  413. IpAddress - The descriptor IP address. Ignored if the association
  414. was not created with HashIpAddress == TRUE.
  415. HostName - The descriptor host name. Ignored if the association was
  416. not created with HashHostName == TRUE.
  417. HashContext - The current hash value.
  418. Return Value:
  419. PHASH_ENTRY - Pointer to the hash entry if successful, NULL otherwise.
  420. --*/
  421. {
  422. DWORD hash;
  423. PLIST_ENTRY bucket;
  424. PLIST_ENTRY scan;
  425. PHASH_ENTRY entry;
  426. //
  427. // Get the correct bucket based on the hash value.
  428. //
  429. hash = HASH_FROM_CONTEXT(HashContext);
  430. bucket = &m_HashBuckets[hash % m_NumHashBuckets];
  431. //
  432. // Scan the bucket, looking for a match.
  433. //
  434. for( scan = bucket->Flink ; scan != bucket ; scan = scan->Flink ) {
  435. entry = CONTAINING_RECORD(
  436. scan,
  437. HASH_ENTRY,
  438. HashBucketListEntry
  439. );
  440. if( entry->Hash != hash ) {
  441. continue;
  442. }
  443. if( m_HashIpAddress &&
  444. entry->IpAddress != IpAddress ) {
  445. continue;
  446. }
  447. if( m_HashHostName ) {
  448. DBG_ASSERT( HostName != NULL );
  449. if( _stricmp(
  450. entry->HostName,
  451. HostName
  452. ) ) {
  453. continue;
  454. }
  455. }
  456. //
  457. // Success!
  458. //
  459. return entry;
  460. }
  461. //
  462. // If we made it this far, then the item is not in the hash table.
  463. //
  464. return NULL;
  465. } // IIS_ASSOCIATION::FindDescriptor
  466. PHASH_ENTRY
  467. IIS_ASSOCIATION::CreateHashEntry(
  468. IN DWORD IpAddress,
  469. IN const CHAR * HostName OPTIONAL,
  470. IN PHASH_CONTEXT HashContext
  471. )
  472. /*++
  473. Routine Description:
  474. Creats a new hash entry.
  475. Arguments:
  476. IpAddress - The descriptor IP address. Ignored if the association
  477. was not created with HashIpAddress == TRUE.
  478. HostName - The descriptor host name. Ignored if the association was
  479. not created with HashHostName == TRUE.
  480. HashContext - The current hash value.
  481. Return Value:
  482. PHASH_ENTRY - Pointer to the newly created hash entry if successful,
  483. NULL otherwise.
  484. --*/
  485. {
  486. PHASH_ENTRY entry;
  487. entry = (PHASH_ENTRY)( new BYTE[sizeof(*entry) + strlen(HostName)] );
  488. if( entry != NULL ) {
  489. entry->IpAddress = IpAddress;
  490. entry->Hash = HASH_FROM_CONTEXT(HashContext);
  491. strcpy( entry->HostName, HostName );
  492. }
  493. return entry;
  494. } // IIS_ASSOCIATION::CreateHashEntry