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.

397 lines
16 KiB

  1. //+-------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1992 - 1992, 1998.
  5. //
  6. // File: domhash.h
  7. //
  8. // Contents: Definition and public include for domain lookup table.
  9. //
  10. // History: SethuR -- Implemented
  11. // MikeSwa - Modified for Domain Name lookup 2/98
  12. //
  13. // Notes: The DFS prefix table data structure consists of three
  14. // entities and methods to manipulate them. They are the
  15. // DOMAIN_NAME_TABLE_ENTRY,DOMAIN_NAME_TABLE_BUCKET and the
  16. // DOMAIN_NAME_TABLE.
  17. //
  18. // The DOMAIN_NAME_TABLE is a hash table of DOMAIN_NAME_TABLE_ENTRY's
  19. // wherein collisions are resolved through linear chaining. The
  20. // hash table is organized as an array of collision lists
  21. // (DOMAIN_NAME_TABLE_BUCKET). A brief description with each of
  22. // these entities is attached to the declaration.
  23. //
  24. // There are certain characterstics that distinguish this
  25. // hash table from other hash tables. These are the extensions
  26. // provided to accomodate the special operations.
  27. //
  28. // 2/98 The major difference between the DFS version and the domain
  29. // name lookup is the size of the table, the ability for
  30. // wildcard lookups (*.foo.com), and the reverse order of the
  31. // lookup (com hashes first in foo.com). To make the code more
  32. // readable given its new purpose, the files, structures, and
  33. // functions have been given non DFS-centric names. A quick
  34. // mapping of the major files is (for those familiar with the
  35. // DFS code):
  36. // domhash.h (prefix.h) - Public include file
  37. // _domhash.h (prefixp.h) - Private inlcude file
  38. // domhash.cpp (prefix.c) - Implementation of API
  39. // _domhash.cpp (prefixp.c) - Private helper functions.
  40. //
  41. // Many functions defined an C macros have been converted to C++
  42. // style inline functions to make debugging easier.
  43. //
  44. // The public API has moved to be public member functions of
  45. // the DOMAIN_NAME_TABLE *class*.
  46. //--------------------------------------------------------------------------
  47. #ifndef __DOMHASH_H__
  48. #define __DOMHASH_H__
  49. #include <windows.h>
  50. //#include <ole2.h>
  51. //#include <mapicode.h>
  52. #include <stdio.h>
  53. //#include <string.h>
  54. // Transport specific headers - every component should use these
  55. #include "transmem.h"
  56. //#include "baseobj.h"
  57. #include <dbgtrace.h>
  58. //#include <rwnew.h>
  59. #include <tchar.h>
  60. #include <stdlib.h>
  61. //Macro to ensure uniformity of domain strings
  62. #define INIT_DOMAIN_STRING(str, cbDomain, szDomain) \
  63. { \
  64. _ASSERT(_tcslen(szDomain)*sizeof(TCHAR) == cbDomain); \
  65. str.Length = (USHORT) (cbDomain); \
  66. str.MaximumLength = str.Length; \
  67. str.Buffer = (szDomain); \
  68. }
  69. //Macro to init global or stack declared domain strings with
  70. //constant string values
  71. #define INIT_DOMAIN_STRING_AT_COMPILE(String) \
  72. { \
  73. (sizeof(String)-sizeof(TCHAR)), /*Length*/ \
  74. (sizeof(String)-sizeof(TCHAR)), /*Maximum*/ \
  75. String /*String buffer*/ \
  76. }
  77. //Define internal HRESULTs
  78. #define DOMHASH_E_DOMAIN_EXISTS HRESULT_FROM_WIN32(ERROR_DOMAIN_EXISTS)
  79. #define DOMHASH_E_NO_SUCH_DOMAIN HRESULT_FROM_WIN32(ERROR_NO_SUCH_DOMAIN)
  80. #define WILDCARD_SIG 'dliW'
  81. #define ENTRY_SIG 'yrtN'
  82. #define DOMAIN_NAME_TABLE_SIG 'hsHD'
  83. #ifndef PAGE_SIZE
  84. #define PAGE_SIZE 4000
  85. #endif //PAGE_SIZE
  86. //---[ UNICODE/ANSI Macros ]---------------------------------------------------
  87. //
  88. //
  89. // The domain hashing function depend on a string structure like UNICODE_STRING
  90. // or ANSI_STRING. If UNICODE is defined, unicode strings and the
  91. // UNICODE_STRING structure will be used... otherwise ANSI_STRING will be used
  92. //
  93. // However, because of the splintering of the NT Headers, I cannot always
  94. // include the files that have ANSI_STRING and UNICODE_STRING defined
  95. //-----------------------------------------------------------------------------
  96. typedef TCHAR * PTCHAR;
  97. typedef TCHAR * PTSTR;
  98. typedef struct _DOMAIN_STRING
  99. {
  100. USHORT Length;
  101. USHORT MaximumLength;
  102. PTCHAR Buffer;
  103. } DOMAIN_STRING, *PDOMAIN_STRING;
  104. //+---------------------------------------------------------------------
  105. //
  106. // Struct: DOMAIN_NAME_TABLE_ENTRY
  107. //
  108. // History: 2/98 modifed from DFS_PREFIX_TABLE_ENTRY by MikeSwa
  109. //
  110. // Notes: Each DOMAIN_NAME_TABLE_ENTRY is in reality a member of two linked
  111. // lists -- a doubly linked list chaining the entries in a bucket
  112. // and a singly linked list establishing the path from any entry to
  113. // the root of the name space. In addition we have the data associated
  114. // with each entry, viz., the name and the data (pData). We also
  115. // keep track of the number of children of each entry. It can also
  116. // be defined as the number of paths to the root of which this entry
  117. // is a member.
  118. //
  119. //----------------------------------------------------------------------
  120. typedef struct _DOMAIN_NAME_TABLE_ENTRY_
  121. {
  122. DWORD dwEntrySig;
  123. struct _DOMAIN_NAME_TABLE_ENTRY_ *pParentEntry;
  124. struct _DOMAIN_NAME_TABLE_ENTRY_ *pNextEntry;
  125. struct _DOMAIN_NAME_TABLE_ENTRY_ *pPrevEntry;
  126. //
  127. // pFirstChildEntry and pSiblingEntry are used purely for enumeration
  128. //
  129. struct _DOMAIN_NAME_TABLE_ENTRY_ *pFirstChildEntry;
  130. struct _DOMAIN_NAME_TABLE_ENTRY_ *pSiblingEntry;
  131. ULONG NoOfChildren;
  132. DOMAIN_STRING PathSegment;
  133. PVOID pData;
  134. DWORD dwWildCardSig;
  135. PVOID pWildCardData;
  136. } DOMAIN_NAME_TABLE_ENTRY, *PDOMAIN_NAME_TABLE_ENTRY;
  137. //+---------------------------------------------------------------------
  138. //
  139. // Struct: DOMAIN_NAME_TABLE_BUCKET
  140. //
  141. // History: 2/8 modified from DFS_PREFIX_TABLE_BUCKET
  142. //
  143. // Notes: The DOMAIN_NAME_TABLE_BUCKET is a doubly linked list of
  144. // DOMAIN_NAME_TABLE_ENTRY's. The current implementation employs
  145. // the notion of a sentinel entry associated with each bucket. The
  146. // end pointers are never null but are always looped back to the
  147. // sentinel entry. The reason we employ such an organization is that
  148. // it considerably simplifies the list manipulation routines. The
  149. // reason this needs to be a doubly linked list is that we would like
  150. // to have the ability of deleting entries without having to traverse
  151. // the buckets from beginning.
  152. //
  153. // The following inline methods ( macro defns. ) are provided for
  154. // inserting, deleting and looking up an entry in the bucket.
  155. //
  156. //----------------------------------------------------------------------
  157. typedef struct _DOMAIN_NAME_TABLE_BUCKET_
  158. {
  159. ULONG NoOfEntries; // High water mark for entries hashing to the bkt.
  160. DOMAIN_NAME_TABLE_ENTRY SentinelEntry;
  161. } DOMAIN_NAME_TABLE_BUCKET, *PDOMAIN_NAME_TABLE_BUCKET;
  162. //+---------------------------------------------------------------------
  163. //
  164. // Struct: NAME_PAGE
  165. //
  166. // History:
  167. //
  168. // Notes: The name segments associated with the various entries are all
  169. // stored together in a name page. This allows us to amortize the
  170. // memory allocation costs over a number of entries and also allows
  171. // us to speed up traversal ( for details see DOMAIN_NAME_TABLE
  172. // definition ).
  173. //
  174. //----------------------------------------------------------------------
  175. #define FREESPACE_IN_NAME_PAGE ((PAGE_SIZE - sizeof(ULONG) - sizeof(PVOID)) / sizeof(TCHAR))
  176. typedef struct _NAME_PAGE_
  177. {
  178. struct _NAME_PAGE_ *pNextPage;
  179. LONG cFreeSpace; // free space avilable in TCHAR's
  180. TCHAR Names[FREESPACE_IN_NAME_PAGE];
  181. } NAME_PAGE, *PNAME_PAGE;
  182. typedef struct _NAME_PAGE_LIST_
  183. {
  184. PNAME_PAGE pFirstPage;
  185. } NAME_PAGE_LIST, *PNAME_PAGE_LIST;
  186. //+---------------------------------------------------------------------
  187. //
  188. // Struct: DOMAIN_NAME_TABLE
  189. //
  190. // History: 2/98 modified from DFS_PREFIX_TABLE
  191. //
  192. // Notes: The DOMAIN_NAME_TABLE is a hashed collection of DOMAIN_NAME_TABLE_ENTRY
  193. // organized in the form of buckets. In addition one other space
  194. // conserving measure is adopted. There is only one copy of each
  195. // name segment stored in the table. As an example consider the
  196. // two name foo.bar and bar.foo. We only store one copy of foo
  197. // and bar eventhough we accomdate both these paths. A beneficial
  198. // side effect of storing single copies is that our traversal of the
  199. // collision chain is considerably speeded up since once we have
  200. // located the pointer to the name, subsequent comparisons need merely
  201. // compare pointers as opposed to strings.
  202. //
  203. //----------------------------------------------------------------------
  204. #define NO_OF_HASH_BUCKETS 997
  205. //prototype of function passed to domain iterator
  206. typedef VOID (* DOMAIN_ITR_FN) (
  207. IN PVOID pvContext, //context passed to HrIterateOverSubDomains
  208. IN PVOID pvData, //data entry to look at
  209. IN BOOL fWildcard, //true if data is a wildcard entry
  210. OUT BOOL *pfContinue, //TRUE if iterator should continue to the next entry
  211. OUT BOOL *pfDelete); //TRUE if entry should be deleted
  212. class DOMAIN_NAME_TABLE
  213. {
  214. private:
  215. DWORD m_dwSignature;
  216. NAME_PAGE_LIST NamePageList;
  217. //
  218. // NextEntry is used purely for enumeration
  219. //
  220. DOMAIN_NAME_TABLE_ENTRY RootEntry;
  221. DOMAIN_NAME_TABLE_BUCKET Buckets[NO_OF_HASH_BUCKETS];
  222. HRESULT HrLookupDomainName(
  223. IN DOMAIN_STRING *pPath,
  224. OUT BOOL *pfExactMatch,
  225. OUT PDOMAIN_NAME_TABLE_ENTRY *ppEntry);
  226. HRESULT HrPrivInsertDomainName(IN PDOMAIN_STRING pstrDomainName,
  227. IN DWORD dwDomainNameTableFlags,
  228. IN PVOID pvNewData,
  229. OUT PVOID *ppvOldData);
  230. inline void LookupBucket(IN PDOMAIN_NAME_TABLE_BUCKET pBucket,
  231. IN PDOMAIN_STRING pName,
  232. IN PDOMAIN_NAME_TABLE_ENTRY pParentEntry,
  233. OUT PDOMAIN_NAME_TABLE_ENTRY *ppEntry,
  234. OUT BOOL *pfNameFound);
  235. PDOMAIN_NAME_TABLE_ENTRY pNextTableEntry(
  236. IN PDOMAIN_NAME_TABLE_ENTRY pEntry,
  237. IN PDOMAIN_NAME_TABLE_ENTRY pRootEntry = NULL);
  238. void DumpTableContents();
  239. void RemoveTableEntry(IN PDOMAIN_NAME_TABLE_ENTRY pEntry);
  240. ULONG m_cLookupAttempts; //Total number of lookup attempts
  241. ULONG m_cLookupSuccesses; //Number of those attempts that where successful
  242. ULONG m_cLookupCollisions; //Number of lookups that had some sort of collision
  243. ULONG m_cHashCollisions; //Number of entries we had to check becuase another
  244. //another string hashed to the same bucket.
  245. //This can be decrease by a better hash or more buckets
  246. ULONG m_cStringCollisions; //Number of entries we had to check becuase the
  247. //same string has different parents ("foo" in
  248. //"foo.com" and "foo.net"
  249. ULONG m_cBucketsUsed; //High water mark bucket usage count
  250. enum {
  251. DMT_INSERT_AS_WILDCARD = 0x00000001,
  252. DMT_REPLACE_EXISTRING = 0x00000002,
  253. };
  254. public:
  255. DOMAIN_NAME_TABLE();
  256. ~DOMAIN_NAME_TABLE();
  257. //NOTE: Init, Insert, and Remove require *external* exclusive lock,
  258. //find and next need a *external* read lock
  259. HRESULT HrInit();
  260. PVOID pvNextDomainName(IN OUT PVOID *ppvContext); //NULL context restarts
  261. inline HRESULT HrInsertDomainName(
  262. IN PDOMAIN_STRING pstrDomainName,
  263. IN PVOID pvData,
  264. IN BOOL fTreatAsWildcard = FALSE,
  265. OUT PVOID *ppvOldData = NULL);
  266. HRESULT HrRemoveDomainName( IN PDOMAIN_STRING pstrDomainName,
  267. OUT PVOID *ppvData);
  268. HRESULT HrFindDomainName( IN PDOMAIN_STRING pstrDomainName,
  269. OUT PVOID *ppvData,
  270. IN BOOL fExactMatch = TRUE);
  271. //Insert Domain Name and replaces old value if neccessary. Returns old
  272. //data as well.
  273. inline HRESULT HrReplaceDomainName(IN PDOMAIN_STRING pstrDomainName,
  274. IN PVOID pvNewData, //New data to insert
  275. IN BOOL fTreatAsWildcard,
  276. OUT PVOID *ppvOldData); //Previous data
  277. HRESULT HrIterateOverSubDomains(
  278. IN DOMAIN_STRING *pstrDomain, //string to search for subdomains of
  279. IN DOMAIN_ITR_FN pfn, //mapping function (described below)
  280. IN PVOID pvContext); //context ptr pass to mapping function
  281. };
  282. typedef DOMAIN_NAME_TABLE * PDOMAIN_NAME_TABLE;
  283. //+---------------------------------------------------------------------------
  284. //
  285. // Function: DOMAIN_NAME_TABLE::HrInsertDomainName
  286. //
  287. // Synopsis: API for inserting a path in the prefix table
  288. //
  289. // Arguments: [pPath] -- the path to be looked up.
  290. //
  291. // [pData] -- BLOB associated with the path
  292. //
  293. // [fTreatAsWildcard] -- TRUE if the domain is NOT a wildcard
  294. // domain, but it should be treated as one (more efficient
  295. // than reallocated a string to prepend "*.".
  296. //
  297. // [ppvOldData] -- Old Data (if any) that was previously associated
  298. // with this domain name. If NULL, previous data will
  299. // not be returned
  300. //
  301. // Returns: HRESULT - S_OK on success
  302. //
  303. // History: 05-11-98 MikeSwa Created
  304. //
  305. // Notes:
  306. //
  307. //----------------------------------------------------------------------------
  308. HRESULT DOMAIN_NAME_TABLE::HrInsertDomainName(
  309. IN PDOMAIN_STRING pstrDomainName,
  310. IN PVOID pvData,
  311. IN BOOL fTreatAsWildcard,
  312. OUT PVOID *ppvOldData)
  313. {
  314. return (HrPrivInsertDomainName(pstrDomainName,
  315. (fTreatAsWildcard ? DMT_INSERT_AS_WILDCARD : 0), pvData, ppvOldData));
  316. }
  317. //+---------------------------------------------------------------------------
  318. //
  319. // Function: DOMAIN_NAME_TABLE::HrReplaceDomainName
  320. //
  321. // Synopsis: API for inserting a path in the prefix table
  322. //
  323. // Arguments: [pPath] -- the path to be looked up.
  324. //
  325. // [pData] -- BLOB associated with the path
  326. //
  327. // [fTreatAsWildcard] -- TRUE if the domain is NOT a wildcard
  328. // domain, but it should be treated as one (more efficient
  329. // than reallocated a string to prepend "*.".
  330. //
  331. // [ppvOldData] -- Old Data (if any) that was previously associated
  332. // with this domain name. If NULL, previous data will
  333. // not be returned
  334. //
  335. // Returns: HRESULT - S_OK on success
  336. //
  337. // History: 05-11-98 MikeSwa Created
  338. //
  339. // Notes:
  340. //
  341. //----------------------------------------------------------------------------
  342. HRESULT DOMAIN_NAME_TABLE::HrReplaceDomainName(
  343. IN PDOMAIN_STRING pstrDomainName,
  344. IN PVOID pvNewData,
  345. IN BOOL fTreatAsWildcard,
  346. OUT PVOID *ppvOldData)
  347. {
  348. return (HrPrivInsertDomainName(pstrDomainName,
  349. (fTreatAsWildcard ? (DMT_INSERT_AS_WILDCARD | DMT_REPLACE_EXISTRING) :
  350. DMT_REPLACE_EXISTRING),
  351. pvNewData, ppvOldData));
  352. }
  353. #endif // __DOMHASH_H__