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.

3062 lines
62 KiB

  1. /*++
  2. Copyright (c) 2000-2001 Microsoft Corporation
  3. Module Name:
  4. ncache.c
  5. Abstract:
  6. DNS Resolver Service
  7. Cache routines
  8. Author:
  9. Jim Gilroy (jamesg) April 2001
  10. Revision History:
  11. --*/
  12. #include "local.h"
  13. //
  14. // Heap corruption tracking
  15. //
  16. #define HEAPPROB 1
  17. #define BAD_PTR (PVOID)(-1)
  18. //
  19. // Cache entry definitions
  20. //
  21. // Starting cache record count
  22. //
  23. #define CACHE_DEFAULT_SET_COUNT 3
  24. #if 0
  25. // Should be private but is exposed in remote
  26. // cache enum routines.
  27. typedef struct _CacheEntry
  28. {
  29. struct _CacheEntry * pNext;
  30. PWSTR pName;
  31. DWORD Reserved;
  32. DWORD MaxCount;
  33. PDNS_RECORD Records[ 1 ];
  34. }
  35. CACHE_ENTRY, *PCACHE_ENTRY;
  36. #endif
  37. //
  38. // Cache heap
  39. //
  40. HANDLE g_CacheHeap = NULL;
  41. //
  42. // Cache hash table
  43. //
  44. PCACHE_ENTRY * g_HashTable = NULL;
  45. #define INITIAL_CACHE_HEAP_SIZE (16*1024)
  46. //
  47. // Runtime globals
  48. //
  49. DWORD g_CurrentCacheTime;
  50. DWORD g_RecordSetCount;
  51. DWORD g_RecordSetCountLimit;
  52. DWORD g_RecordSetCountThreshold;
  53. DWORD g_RecordSetCache;
  54. DWORD g_RecordSetFree;
  55. DWORD g_EntryCount;
  56. DWORD g_EntryAlloc;
  57. DWORD g_EntryFree;
  58. BOOL g_fLoadingHostsFile;
  59. //
  60. // Garbage collection
  61. //
  62. BOOL g_GarbageCollectFlag = FALSE;
  63. DWORD g_NextGarbageIndex = 0;
  64. DWORD g_NextGarbageTime = 0;
  65. #define GARBAGE_LOCKOUT_INTERVAL (600) // no more then every ten minutes
  66. //
  67. // Wakeup flag
  68. //
  69. BOOL g_WakeFlag = FALSE;
  70. //
  71. // Cache limits
  72. // - min count of records to hold
  73. // - size of band in which garbage collection occurs
  74. //
  75. #if DBG
  76. #define MIN_DYNAMIC_RECORD_COUNT (20)
  77. #define CLEANUP_RECORD_COUNT_BAND (5)
  78. #else
  79. #define MIN_DYNAMIC_RECORD_COUNT (50)
  80. #define CLEANUP_RECORD_COUNT_BAND (30)
  81. #endif
  82. //
  83. // Static records (hosts file)
  84. //
  85. #define IS_STATIC_RR(prr) (IS_HOSTS_FILE_RR(prr) || IS_CLUSTER_RR(prr))
  86. //
  87. // Compute a hash table index value for a string
  88. //
  89. #define EOS (L'\0')
  90. #define COMPUTE_STRING_HASH_1( _String, _ulHashTableSize, _lpulHash ) \
  91. { \
  92. PWCHAR p; \
  93. ULOND h = 0, g; \
  94. \
  95. for ( p = _String; *p != EOS; p = p + 1 ) \
  96. { \
  97. h = ( h << 4 ) + (DWORD) (*p); \
  98. if ( g = h&0xf0000000 ) \
  99. { \
  100. h = h ^ ( g >> 24 ); \
  101. h = h ^ g; \
  102. } \
  103. } \
  104. *_lpulHash = h % _ulHashTableSize; \
  105. }
  106. //
  107. // Compute a hash table index value for a string
  108. // which is invairant to case
  109. //
  110. #define COMPUTE_STRING_HASH_2( _String, _ulHashTableSize, _lpulHash ) \
  111. { \
  112. PWCHAR _p = _String; \
  113. PWCHAR _ep = _p + wcslen( _String ); \
  114. ULONG h = 0; \
  115. \
  116. while( _p < _ep ) \
  117. { \
  118. h <<= 1; \
  119. h ^= *_p++; \
  120. } \
  121. \
  122. *_lpulHash = h % _ulHashTableSize; \
  123. }
  124. //
  125. // Private prototypes
  126. //
  127. BOOL
  128. Cache_FlushEntryRecords(
  129. IN OUT PCACHE_ENTRY pEntry,
  130. IN DWORD Level,
  131. IN WORD wType
  132. );
  133. VOID
  134. Cache_FlushBucket(
  135. IN ULONG Index,
  136. IN WORD FlushLevel
  137. );
  138. //
  139. // Cache Implementation
  140. //
  141. // Cache is implemented as a hash on name, with chaining in the individual
  142. // buckets. Individual name entries are blocks with name pointer and array
  143. // of up to 3 RR set pointers. The new names\entries are put at the front of
  144. // the bucket chain, so the oldest are at the rear.
  145. //
  146. //
  147. // Cleanup:
  148. //
  149. // The cleanup strategy is to time out all RR sets and cleanup everything
  150. // possible as a result. Then entries beyond a max bucket size (a resizable
  151. // global) are deleted, the oldest queries deleted first.
  152. //
  153. // Ideally, we'd like to keep the most useful entries in the cache while
  154. // being able to limit the overall cache size.
  155. //
  156. // A few observations:
  157. //
  158. // 1) max bucket size is worthless; if sufficient for pruning, it would be
  159. // too small to allow non-uniform distributions
  160. //
  161. // 2) LRU should be required; on busy cache shouldn't prune something queried
  162. // "a while" ago that is being used all the time; that adds much more traffic
  163. // than something recently queried but then unused;
  164. //
  165. // 3) if necessary an LRU index could be kept; but probably some time bucket
  166. // counting to know how "deep" pruning must be is adequate
  167. //
  168. //
  169. // Memory:
  170. //
  171. // Currently hash itself and hash entries come from private resolver heap.
  172. // However, RR sets are built by record parsing of messages received in dnsapi.dll
  173. // and hence are built by the default dnsapi.dll allocator. We must match it.
  174. //
  175. // The downside of this is twofold:
  176. // 1) By being in process heap, we are exposed (debug wise) to any poor code
  177. // in services.exe. Hopefully, there are getting better, but anything that
  178. // trashes memory is likely to cause us to have to debug, because we are the highest
  179. // use service.
  180. // 2) Flush \ cleanup is easy. Just kill the heap.
  181. //
  182. // There are several choices:
  183. //
  184. // 0) Copy the records. We are still susceptible to memory corruption ... but the
  185. // interval is shorter, since we don't keep anything in process heap.
  186. //
  187. // 1) Query can directly call dnslib.lib query routines. Since dnslib.lib is
  188. // explicitly compiled in, it's global for holding the allocators is modules, rather
  189. // than process specific.
  190. //
  191. // 2) Add some parameter to query routines that allows pass of allocator down to
  192. // lowest level. At high level this is straightforward. At lower level it maybe
  193. // problematic. There may be a way to do it with a flag where the allocator is
  194. // "optional" and used only when a flag is set.
  195. //
  196. //
  197. // Cache functions
  198. //
  199. VOID
  200. Cache_Lock(
  201. IN BOOL fNoStart
  202. )
  203. /*++
  204. Routine Description:
  205. Lock the cache
  206. Arguments:
  207. None.
  208. Return Value:
  209. None -- cache is locked.
  210. --*/
  211. {
  212. DNSDBG( LOCK, ( "Enter Cache_Lock() ..." ));
  213. EnterCriticalSection( &CacheCritSec );
  214. DNSDBG( LOCK, (
  215. "through lock (r=%d)\n",
  216. CacheCritSec.RecursionCount ));
  217. // update global time (for TTL set and timeout)
  218. //
  219. // this allows us to eliminate multiple time calls
  220. // within cache
  221. g_CurrentCacheTime = Dns_GetCurrentTimeInSeconds();
  222. //
  223. // if cache not loaded -- load
  224. // this allows us to avoid load on every PnP until we
  225. // are actually queried
  226. //
  227. if ( !fNoStart && !g_HashTable )
  228. {
  229. DNSDBG( ANY, (
  230. "No hash table when took lock -- initializing!\n" ));
  231. Cache_Initialize();
  232. }
  233. }
  234. VOID
  235. Cache_Unlock(
  236. VOID
  237. )
  238. /*++
  239. Routine Description:
  240. Unlock the cache
  241. Arguments:
  242. None.
  243. Return Value:
  244. None.
  245. --*/
  246. {
  247. DNSDBG( LOCK, (
  248. "Cache_Unlock() r=%d\n",
  249. CacheCritSec.RecursionCount ));
  250. LeaveCriticalSection( &CacheCritSec );
  251. }
  252. DNS_STATUS
  253. Cache_Initialize(
  254. VOID
  255. )
  256. /*++
  257. Routine Description:
  258. Initialize the cache.
  259. Create events and locks and setup basic hash.
  260. Arguments:
  261. None.
  262. Return Value:
  263. ERROR_SUCCESS if successful.
  264. ErrorCode on failure.
  265. --*/
  266. {
  267. DNS_STATUS status;
  268. DWORD carryCount;
  269. DNSDBG( INIT, ( "Cache_Initialize()\n" ));
  270. //
  271. // lock -- with "no-start" set to avoid recursion
  272. //
  273. LOCK_CACHE_NO_START();
  274. //
  275. // create cache heap
  276. //
  277. // want to have own heap
  278. // 1) to simplify flush\shutdown
  279. // 2) keep us from "entanglements" with poor services
  280. //
  281. g_CacheHeap = HeapCreate( 0, INITIAL_CACHE_HEAP_SIZE, 0 );
  282. if ( !g_CacheHeap )
  283. {
  284. status = ERROR_NOT_ENOUGH_MEMORY;
  285. g_HashTable = NULL;
  286. goto Done;
  287. }
  288. g_HashTable = CACHE_HEAP_ALLOC_ZERO(
  289. sizeof(PCACHE_ENTRY) * g_HashTableSize );
  290. if ( !g_HashTable )
  291. {
  292. status = ERROR_NOT_ENOUGH_MEMORY;
  293. HeapDestroy( g_CacheHeap );
  294. g_CacheHeap = NULL;
  295. goto Done;
  296. }
  297. g_WakeFlag = FALSE;
  298. g_EntryCount = 0;
  299. g_EntryAlloc = 0;
  300. g_EntryFree = 0;
  301. g_RecordSetCount = 0;
  302. g_RecordSetCache = 0;
  303. g_RecordSetFree = 0;
  304. // eliminate cache size checks during hosts file load
  305. g_RecordSetCountLimit = MAXDWORD;
  306. g_RecordSetCountThreshold = MAXDWORD;
  307. //
  308. // load hosts file into cache
  309. //
  310. g_fLoadingHostsFile = TRUE;
  311. InitCacheWithHostFile();
  312. g_fLoadingHostsFile = FALSE;
  313. //
  314. // set cache size limit
  315. // - above what loaded from hosts file
  316. // - always allow some dynamic space regardless of
  317. // g_MaxCacheSize
  318. // - create slightly higher threshold value for kicking
  319. // off cleanup so cleanup not running all the time
  320. //
  321. carryCount = g_MaxCacheSize;
  322. if ( carryCount < MIN_DYNAMIC_RECORD_COUNT )
  323. {
  324. carryCount = MIN_DYNAMIC_RECORD_COUNT;
  325. }
  326. g_RecordSetCountLimit = g_RecordSetCount + carryCount;
  327. g_RecordSetCountThreshold = g_RecordSetCountLimit + CLEANUP_RECORD_COUNT_BAND;
  328. Done:
  329. UNLOCK_CACHE();
  330. return NO_ERROR;
  331. }
  332. DNS_STATUS
  333. Cache_Shutdown(
  334. VOID
  335. )
  336. /*++
  337. Routine Description:
  338. Shutdown the cache.
  339. Arguments:
  340. None.
  341. Return Value:
  342. ERROR_SUCCESS if successful.
  343. ErrorCode on failure.
  344. --*/
  345. {
  346. DNSDBG( INIT, ( "Cache_Shutdown()\n" ));
  347. //
  348. // clean out cache and delete cache heap
  349. // - currently Cache_Flush() does just this
  350. //
  351. return Cache_Flush();
  352. }
  353. DNS_STATUS
  354. Cache_Flush(
  355. VOID
  356. )
  357. /*++
  358. Routine Description:
  359. Flush the cache.
  360. This flushes all the cache data and rereads host file but does NOT
  361. shut down and restart cache threads (host file monitor or multicast).
  362. Arguments:
  363. None
  364. Return Value:
  365. ERROR_SUCCESS if successful.
  366. ErrorCode on rebuild failure.
  367. --*/
  368. {
  369. DWORD status = ERROR_SUCCESS;
  370. WORD ihash;
  371. WORD RecordIter;
  372. DNSDBG( ANY, ( "\nCache_Flush()\n" ));
  373. //
  374. // wake\stop garbage collection
  375. //
  376. g_WakeFlag = TRUE;
  377. //
  378. // lock with "no start" flag
  379. // - avoids creating cache structs if they don't exist
  380. //
  381. LOCK_CACHE_NO_START();
  382. DNSLOG_F1( "Flushing DNS Cache" );
  383. DNSLOG_F3(
  384. " Before Cache_Flush(): entries %d, record %d",
  385. g_EntryCount,
  386. g_RecordSetCount );
  387. //
  388. // clear entries in each hash bucket
  389. //
  390. if ( g_HashTable )
  391. {
  392. for ( ihash = 0;
  393. ihash < g_HashTableSize;
  394. ihash++ )
  395. {
  396. Cache_FlushBucket(
  397. ihash,
  398. FLUSH_LEVEL_CLEANUP );
  399. }
  400. }
  401. DNSDBG( CACHE, (
  402. "After flushing cache:\n"
  403. "\trecord count = %d\n"
  404. "\tentry count = %d\n",
  405. g_RecordSetCount,
  406. g_EntryCount ));
  407. DNS_ASSERT( g_RecordSetCount == 0 );
  408. DNS_ASSERT( g_EntryCount == 0 );
  409. DNSLOG_F3(
  410. " After Cache_Flush() flush: entries %d, record %d",
  411. g_EntryCount,
  412. g_RecordSetCount );
  413. //
  414. // Note: can NOT delete the cache without stopping mcast
  415. // thread which currently uses cache heap
  416. //
  417. // DCR: have all data in cache in single heap
  418. // - protected
  419. // - single destroy cleans up
  420. // once cleaned up, delete heap
  421. if ( g_CacheHeap )
  422. {
  423. HeapDestroy( g_CacheHeap );
  424. g_CacheHeap = NULL;
  425. }
  426. g_HashTable = NULL;
  427. //
  428. // dump local IP list
  429. // - not dumping on shutdown as the IP cleanup happens
  430. // first and takes away the CS;
  431. //
  432. // note to reviewer:
  433. // this is equivalent to the previous behavior where
  434. // Cache_Flush() FALSE was shutdown and
  435. // everything else used TRUE (for restart) which did a
  436. // RefreshLocalAddrArray() to rebuild IP list
  437. // now we simply dump the IP list rather than rebuilding
  438. //
  439. if ( !g_StopFlag )
  440. {
  441. ClearLocalAddrArray();
  442. }
  443. DNSDBG( ANY, ( "Leave Cache_Flush()\n\n" ));
  444. UNLOCK_CACHE();
  445. return( status );
  446. }
  447. //
  448. // Cache utilities
  449. //
  450. BOOL
  451. Cache_IsRecordTtlValid(
  452. IN PDNS_RECORD pRecord
  453. )
  454. /*++
  455. Routine Description:
  456. Check if TTL is still valid (or has timed out).
  457. Arguments:
  458. pRecord -- record to check
  459. Return Value:
  460. TRUE -- if TTL is still valid
  461. FALSE -- if TTL has timed out
  462. --*/
  463. {
  464. //
  465. // static or TTL not timed out => valid
  466. //
  467. // note: currently flushing all records on PnP, but this is
  468. // not strickly necessary; if stop this then MUST change
  469. // this to whack negative cache entries that are older
  470. // than last PnP time
  471. //
  472. if ( IS_STATIC_RR(pRecord) )
  473. {
  474. return( TRUE );
  475. }
  476. else
  477. {
  478. return( (LONG)(pRecord->dwTtl - g_CurrentCacheTime) > 0 );
  479. }
  480. }
  481. //
  482. // Cache entry routines
  483. //
  484. DWORD
  485. getHashIndex(
  486. IN PWSTR pName,
  487. IN DWORD NameLength OPTIONAL
  488. )
  489. /*++
  490. Routine Description:
  491. Create cannonical cache form of name.
  492. Note: no test for adequacy of buffer is done.
  493. Arguments:
  494. pName -- name
  495. NameLength -- NameLength, OPTIONAL
  496. Return Value:
  497. None
  498. --*/
  499. {
  500. register PWCHAR pstring;
  501. register WCHAR wch;
  502. register DWORD hash = 0;
  503. //
  504. // build hash by XORing characters
  505. //
  506. pstring = pName;
  507. while ( wch = *pstring++ )
  508. {
  509. hash <<= 1;
  510. hash ^= wch;
  511. }
  512. //
  513. // mod over hash table size
  514. //
  515. return( hash % g_HashTableSize );
  516. }
  517. BOOL
  518. makeCannonicalCacheName(
  519. OUT PWCHAR pNameBuffer,
  520. IN DWORD BufferLength,
  521. IN PWSTR pName,
  522. IN DWORD NameLength OPTIONAL
  523. )
  524. /*++
  525. Routine Description:
  526. Create cannonical cache form of name.
  527. Arguments:
  528. pNameBuffer -- buffer to hold cache name
  529. BufferLength -- length of buffer
  530. pName -- ptr to name string
  531. NameLength -- optional, saves wsclen() call if known
  532. Return Value:
  533. TRUE if successful.
  534. FALSE on bogus name.
  535. --*/
  536. {
  537. INT count;
  538. DNSDBG( TRACE, (
  539. "makeCannonicalCacheName( %S )\n",
  540. pName ));
  541. //
  542. // get length if not specified
  543. //
  544. if ( NameLength == 0 )
  545. {
  546. NameLength = wcslen( pName );
  547. }
  548. //
  549. // copy and downcase string
  550. // - "empty" buffer for prefix happiness
  551. //
  552. *pNameBuffer = (WCHAR) 0;
  553. count = Dns_MakeCanonicalNameW(
  554. pNameBuffer,
  555. BufferLength,
  556. pName,
  557. NameLength+1 // convert null terminator
  558. );
  559. if ( count == 0 )
  560. {
  561. ASSERT( GetLastError() == ERROR_INSUFFICIENT_BUFFER );
  562. return( FALSE );
  563. }
  564. ASSERT( count == (INT)NameLength+1 );
  565. //
  566. // whack any trailing dot
  567. // - except for root node
  568. //
  569. count--; // account for null terminator
  570. DNS_ASSERT( count == NameLength );
  571. if ( count > 1 &&
  572. pNameBuffer[count - 1] == L'.' )
  573. {
  574. pNameBuffer[count - 1] = 0;
  575. }
  576. return( TRUE );
  577. }
  578. PCACHE_ENTRY
  579. Cache_CreateEntry(
  580. IN PWSTR pName,
  581. IN BOOL fCanonical
  582. )
  583. /*++
  584. Routine Description:
  585. Create cache entry, including allocation.
  586. Arguments:
  587. pName -- name
  588. fCanonical -- TRUE if name already in cannonical form
  589. Return Value:
  590. Ptr to newly allocated cache entry.
  591. NULL on error.
  592. --*/
  593. {
  594. ULONG index = 0;
  595. PCACHE_ENTRY pentry = NULL;
  596. DWORD nameLength;
  597. DWORD fixedLength;
  598. PWCHAR pnameCache = NULL;
  599. DNSDBG( TRACE, (
  600. "Cache_CreateEntry( %S )\n",
  601. pName ));
  602. if ( !pName || !g_HashTable )
  603. {
  604. return NULL;
  605. }
  606. //
  607. // alloc
  608. //
  609. nameLength = wcslen( pName );
  610. fixedLength = sizeof(CACHE_ENTRY) +
  611. (sizeof(PDNS_RECORD) * (CACHE_DEFAULT_SET_COUNT-1));
  612. pentry = (PCACHE_ENTRY) CACHE_HEAP_ALLOC_ZERO(
  613. fixedLength +
  614. sizeof(WCHAR) * (nameLength+1) );
  615. if ( !pentry )
  616. {
  617. goto Fail;
  618. }
  619. pentry->MaxCount = CACHE_DEFAULT_SET_COUNT;
  620. pnameCache = (PWSTR) ((PBYTE)pentry + fixedLength);
  621. //
  622. // build the name
  623. //
  624. if ( fCanonical )
  625. {
  626. wcscpy( pnameCache, pName );
  627. }
  628. else
  629. {
  630. if ( !makeCannonicalCacheName(
  631. pnameCache,
  632. nameLength+1,
  633. pName,
  634. nameLength ) )
  635. {
  636. goto Fail;
  637. }
  638. }
  639. pentry->pName = pnameCache;
  640. //
  641. // insert cache entry into cache -- first entry in bucket
  642. //
  643. index = getHashIndex( pnameCache, nameLength );
  644. pentry->pNext = g_HashTable[ index ];
  645. g_HashTable[ index ] = pentry;
  646. g_EntryCount++;
  647. g_EntryAlloc++;
  648. //
  649. // DCR: need overload detection
  650. //
  651. return pentry;
  652. Fail:
  653. // dump entry
  654. if ( pentry )
  655. {
  656. CACHE_HEAP_FREE( pentry );
  657. }
  658. return NULL;
  659. }
  660. VOID
  661. Cache_FreeEntry(
  662. IN OUT PCACHE_ENTRY pEntry
  663. )
  664. /*++
  665. Routine Description:
  666. Free cache entry.
  667. Arguments:
  668. pEntry -- cache entry to free
  669. Globals:
  670. g_EntryCount -- decremented appropriately
  671. g_NumberOfRecordsInCache -- decremented appropriately
  672. Return Value:
  673. None
  674. --*/
  675. {
  676. INT iter;
  677. DNSDBG( TRACE, (
  678. "Cache_FreeEntry( %p )\n",
  679. pEntry ));
  680. //
  681. // free entry
  682. // - records
  683. // - name
  684. // - entry itself
  685. //
  686. if ( pEntry )
  687. {
  688. Cache_FlushEntryRecords(
  689. pEntry,
  690. FLUSH_LEVEL_CLEANUP,
  691. 0 );
  692. #if 0
  693. if ( pEntry->pNext )
  694. {
  695. DNSLOG_F1( "Cache_FreeEntry is deleting an entry that still points to other entries!" );
  696. }
  697. #endif
  698. #if HEAPPROB
  699. pEntry->pNext = DNS_BAD_PTR;
  700. #endif
  701. CACHE_HEAP_FREE( pEntry );
  702. g_EntryFree--;
  703. g_EntryCount--;
  704. }
  705. }
  706. PCACHE_ENTRY
  707. Cache_FindEntry(
  708. IN PWSTR pName,
  709. IN BOOL fCreate
  710. )
  711. /*++
  712. Routine Description:
  713. Find or create entry for name in cache.
  714. Arguments:
  715. pName -- name to find
  716. fCreate -- TRUE to create if not found
  717. Return Value:
  718. Ptr to cache entry -- if successful.
  719. NULL on failure.
  720. --*/
  721. {
  722. ULONG index;
  723. PCACHE_ENTRY pentry;
  724. PCACHE_ENTRY pprevEntry = NULL;
  725. WCHAR hashName[ DNS_MAX_NAME_BUFFER_LENGTH+4 ];
  726. if ( !g_HashTable )
  727. {
  728. return NULL;
  729. }
  730. if ( !pName )
  731. {
  732. DNS_ASSERT( FALSE );
  733. return NULL;
  734. }
  735. DNSDBG( TRACE, (
  736. "Cache_FindEntry( %S, create=%d )\n",
  737. pName,
  738. fCreate ));
  739. //
  740. // build cache name
  741. // - if invalid (too long) bail
  742. //
  743. if ( !makeCannonicalCacheName(
  744. hashName,
  745. DNS_MAX_NAME_BUFFER_LENGTH,
  746. pName,
  747. 0 ) )
  748. {
  749. return NULL;
  750. }
  751. //
  752. // find entry in cache
  753. //
  754. LOCK_CACHE();
  755. index = getHashIndex( hashName, 0 );
  756. pentry = g_HashTable[ index ];
  757. DNSDBG( OFF, (
  758. "in Cache_FindEntry\n"
  759. "\tname = %S\n"
  760. "\tindex = %d\n"
  761. "\tpentry = %p\n",
  762. hashName,
  763. index,
  764. pentry ));
  765. while( pentry )
  766. {
  767. if ( DnsNameCompare_W( hashName, pentry->pName ) )
  768. {
  769. //
  770. // found entry
  771. // - move to front, if not already there
  772. if ( pprevEntry )
  773. {
  774. pprevEntry->pNext = pentry->pNext;
  775. pentry->pNext = g_HashTable[ index ];
  776. g_HashTable[ index ] = pentry;
  777. }
  778. break;
  779. }
  780. ELSE
  781. {
  782. DNSDBG( OFF, (
  783. "in Cache_FindEntry -- failed name compare\n"
  784. "\tout name = %S\n"
  785. "\tpentry = %p\n"
  786. "\tname = %S\n",
  787. hashName,
  788. pentry,
  789. pentry->pName ));
  790. }
  791. pprevEntry = pentry;
  792. pentry = pentry->pNext;
  793. }
  794. //
  795. // if not found -- create?
  796. //
  797. // DCR: optimize for create
  798. //
  799. if ( !pentry && fCreate )
  800. {
  801. pentry = Cache_CreateEntry(
  802. hashName,
  803. TRUE // name already canonical
  804. );
  805. }
  806. DNS_ASSERT( !pentry || g_HashTable[ index ] == pentry );
  807. UNLOCK_CACHE();
  808. DNSDBG( TRACE, (
  809. "Leave Cache_FindEntry\n"
  810. "\tname = %S\n"
  811. "\tindex = %d\n"
  812. "\tpentry = %p\n",
  813. hashName,
  814. index,
  815. pentry ));
  816. return pentry;
  817. }
  818. PDNS_RECORD
  819. Cache_FindEntryRecords(
  820. IN PCACHE_ENTRY pEntry,
  821. IN WORD wType
  822. )
  823. /*++
  824. Routine Description:
  825. Find entry in cache.
  826. Arguments:
  827. pEntry -- cache entry to check
  828. Type -- record type to find
  829. Return Value:
  830. Ptr to record set of desired type -- if found.
  831. NULL if not found.
  832. --*/
  833. {
  834. WORD iter;
  835. PDNS_RECORD prr;
  836. DNSDBG( TRACE, (
  837. "Cache_FindEntryRecords %p, type=%d )\n",
  838. pEntry,
  839. wType ));
  840. //
  841. // check all the records at the cache entry
  842. //
  843. for ( iter = 0;
  844. iter < pEntry->MaxCount;
  845. iter++ )
  846. {
  847. prr = pEntry->Records[iter];
  848. if ( !prr )
  849. {
  850. continue;
  851. }
  852. if ( !Cache_IsRecordTtlValid( prr ) )
  853. {
  854. DNSDBG( TRACE, (
  855. "Whacking timed out record %p at cache entry %p\n",
  856. prr,
  857. pEntry ));
  858. Dns_RecordListFree( prr );
  859. pEntry->Records[iter] = NULL;
  860. g_RecordSetCount--;
  861. g_RecordSetFree--;
  862. continue;
  863. }
  864. //
  865. // find matching type
  866. // - direct type match
  867. // - NAME_ERROR
  868. //
  869. if ( prr->wType == wType ||
  870. ( prr->wType == DNS_TYPE_ANY &&
  871. prr->wDataLength == 0 ) )
  872. {
  873. goto Done;
  874. }
  875. //
  876. // CNAME match
  877. // - walk list and determine if for matching type
  878. if ( prr->wType == DNS_TYPE_CNAME &&
  879. wType != DNS_TYPE_CNAME )
  880. {
  881. PDNS_RECORD prrChain = prr->pNext;
  882. while ( prrChain )
  883. {
  884. if ( prrChain->wType == wType )
  885. {
  886. // chain to desired type -- take RR set
  887. goto Done;
  888. }
  889. prrChain = prrChain->pNext;
  890. }
  891. }
  892. // records for another type -- continue
  893. }
  894. // type not found
  895. prr = NULL;
  896. Done:
  897. DNSDBG( TRACE, (
  898. "Leave Cache_FindEntryRecords) => %p\n",
  899. prr ));
  900. return prr;
  901. }
  902. BOOL
  903. Cache_FlushEntryRecords(
  904. IN OUT PCACHE_ENTRY pEntry,
  905. IN DWORD Level,
  906. IN WORD wType
  907. )
  908. /*++
  909. Routine Description:
  910. Free cache entry.
  911. Arguments:
  912. pEntry -- cache entry to flush
  913. FlushLevel -- flush level
  914. FLUSH_LEVEL_NORMAL -- flush matching type, invalid, NAME_ERROR
  915. FLUSH_LEVEL_WIRE -- to flush all wire data, but leave hosts and cluster
  916. FLUSH_LEVEL_INVALID -- flush only invalid records
  917. FLUSH_LEVEL_STRONG -- to flush all but hosts file
  918. FLUSH_LEVEL_CLEANUP -- to flush all records for full cache flush
  919. wType -- flush type for levels with type
  920. DNS type -- to flush specifically this type
  921. Globals:
  922. g_EntryCount -- decremented appropriately
  923. g_NumberOfRecordsInCache -- decremented appropriately
  924. Return Value:
  925. TRUE if entry flushed completely.
  926. FALSE if records left.
  927. --*/
  928. {
  929. INT iter;
  930. BOOL recordsLeft = FALSE;
  931. DNSDBG( TRACE, (
  932. "Cache_FlushEntryRecords( %p, %08x, %d )\n",
  933. pEntry,
  934. Level,
  935. wType ));
  936. //
  937. // loop through records sets -- flush where appropriate
  938. //
  939. // CLEANUP flush
  940. // - everything
  941. //
  942. // STRONG (user initiated) flush
  943. // - all cached records, including cluster
  944. // but hostsfile saved
  945. //
  946. // WIRE flush
  947. // - all wire cached records
  948. // hosts file AND cluster saved
  949. //
  950. // INVALID flush
  951. // - timedout only
  952. //
  953. // NORMAL flush (regular flush done on caching)
  954. // - timed out records
  955. // - records of desired type
  956. // - NAME_ERROR
  957. //
  958. for ( iter = 0;
  959. iter < (INT)pEntry->MaxCount;
  960. iter++ )
  961. {
  962. PDNS_RECORD prr = pEntry->Records[iter];
  963. BOOL flush;
  964. if ( !prr )
  965. {
  966. continue;
  967. }
  968. //
  969. // switch on flush type
  970. // yes there are optimizations, but this is simple
  971. //
  972. if ( Level == FLUSH_LEVEL_NORMAL )
  973. {
  974. flush = ( !IS_STATIC_RR(prr)
  975. &&
  976. ( prr->wType == wType ||
  977. ( prr->wType == DNS_TYPE_ANY &&
  978. prr->wDataLength == 0 ) ) );
  979. }
  980. else if ( Level == FLUSH_LEVEL_WIRE )
  981. {
  982. flush = !IS_STATIC_RR(prr);
  983. }
  984. else if ( Level == FLUSH_LEVEL_INVALID )
  985. {
  986. flush = !Cache_IsRecordTtlValid(prr);
  987. }
  988. else if ( Level == FLUSH_LEVEL_CLEANUP )
  989. {
  990. flush = TRUE;
  991. }
  992. else
  993. {
  994. DNS_ASSERT( Level == FLUSH_LEVEL_STRONG );
  995. flush = !IS_HOSTS_FILE_RR(prr);
  996. }
  997. if ( flush )
  998. {
  999. pEntry->Records[iter] = NULL;
  1000. Dns_RecordListFree( prr );
  1001. g_RecordSetCount--;
  1002. g_RecordSetFree--;
  1003. }
  1004. else
  1005. {
  1006. recordsLeft = TRUE;
  1007. }
  1008. }
  1009. return !recordsLeft;
  1010. }
  1011. VOID
  1012. Cache_FlushBucket(
  1013. IN ULONG Index,
  1014. IN WORD FlushLevel
  1015. )
  1016. /*++
  1017. Routine Description:
  1018. Cleanup cache bucket.
  1019. Arguments:
  1020. Index -- Index of hash bucket to trim.
  1021. FlushLevel -- level of flush desired
  1022. see Cache_FlushEntryRecords() for description of
  1023. flush levels
  1024. Return Value:
  1025. None
  1026. --*/
  1027. {
  1028. PCACHE_ENTRY pentry;
  1029. PCACHE_ENTRY pprev;
  1030. INT countCompleted;
  1031. DNSDBG( CACHE, (
  1032. "Cache_FlushBucket( %d, %08x )\n",
  1033. Index,
  1034. FlushLevel ));
  1035. //
  1036. // flush entries in this bucket
  1037. //
  1038. // note: using hack here that hash table pointer can
  1039. // be treated as cache entry for purposes of accessing
  1040. // it's next pointer (since it's the first field in
  1041. // a CACHE_ENTRY)
  1042. // if this changes, must explicitly fix up "first entry"
  1043. // case or move to double-linked list that can free
  1044. // empty penty without regard to it's location
  1045. //
  1046. if ( !g_HashTable )
  1047. {
  1048. return;
  1049. }
  1050. //
  1051. // flush entries
  1052. //
  1053. // avoid holding lock too long by handling no more then
  1054. // fifty entries at a time
  1055. // note: generally 50 entries will cover entire bucket but
  1056. // can still be completed in reasonable time;
  1057. //
  1058. // DCR: smarter flush -- avoid lock\unlock
  1059. // peer into CS and don't unlock when no one waiting
  1060. // if waiting unlock and give up timeslice
  1061. // DCR: some LRU flush for garbage collection
  1062. //
  1063. countCompleted = 0;
  1064. while ( 1 )
  1065. {
  1066. INT count = 0;
  1067. INT countStop = countCompleted + 50;
  1068. LOCK_CACHE_NO_START();
  1069. if ( !g_HashTable )
  1070. {
  1071. UNLOCK_CACHE();
  1072. break;
  1073. }
  1074. DNSDBG( CACHE, (
  1075. "locked for bucket flush -- completed=%d, stop=%d\n",
  1076. count,
  1077. countStop ));
  1078. pprev = (PCACHE_ENTRY) &g_HashTable[ Index ];
  1079. while ( pentry = pprev->pNext )
  1080. {
  1081. // bypass any previously checked entries
  1082. if ( count++ < countCompleted )
  1083. {
  1084. pprev = pentry;
  1085. continue;
  1086. }
  1087. if ( count > countStop )
  1088. {
  1089. break;
  1090. }
  1091. // flush -- if successful cut from list and
  1092. // drop counts so countCompleted used in bypass
  1093. // will be correct and won't skip anyone
  1094. if ( Cache_FlushEntryRecords(
  1095. pentry,
  1096. FlushLevel,
  1097. 0 ) )
  1098. {
  1099. pprev->pNext = pentry->pNext;
  1100. Cache_FreeEntry( pentry );
  1101. count--;
  1102. countStop--;
  1103. continue;
  1104. }
  1105. pprev = pentry;
  1106. }
  1107. UNLOCK_CACHE();
  1108. countCompleted = count;
  1109. // stop when
  1110. // - cleared all the entries in the bucket
  1111. // - shutdown, except exempt the shutdown flush itself
  1112. if ( !pentry ||
  1113. (g_StopFlag && FlushLevel != FLUSH_LEVEL_CLEANUP) )
  1114. {
  1115. break;
  1116. }
  1117. }
  1118. DNSDBG( CACHE, (
  1119. "Leave Cache_FlushBucket( %d, %08x )\n"
  1120. "\trecord count = %d\n"
  1121. "\tentry count = %d\n",
  1122. Index,
  1123. FlushLevel,
  1124. g_RecordSetCount,
  1125. g_EntryCount ));
  1126. }
  1127. //
  1128. // Cache interface routines
  1129. //
  1130. VOID
  1131. Cache_PrepareRecordList(
  1132. IN OUT PDNS_RECORD pRecordList
  1133. )
  1134. /*++
  1135. Routine Description:
  1136. Prepare record list for cache.
  1137. Arguments:
  1138. pRecordList - record list to put in cache
  1139. Return Value:
  1140. Ptr to screened, prepared record list.
  1141. --*/
  1142. {
  1143. PDNS_RECORD prr = pRecordList;
  1144. PDNS_RECORD pnext;
  1145. DWORD ttl;
  1146. DWORD maxTtl;
  1147. DNSDBG( TRACE, (
  1148. "Cache_PrepareRecordList( rr=%p )\n",
  1149. prr ));
  1150. if ( !prr )
  1151. {
  1152. return;
  1153. }
  1154. //
  1155. // static (currently host file) TTL records
  1156. //
  1157. // currently no action required -- records come one
  1158. // at a time and no capability to even to the pName=NULL
  1159. // step
  1160. //
  1161. if ( IS_STATIC_RR(prr) )
  1162. {
  1163. return;
  1164. }
  1165. //
  1166. // wire records get relative TTL
  1167. // - compute minimum TTL for set
  1168. // - save TTL as timeout (offset by TTL from current time)
  1169. //
  1170. // DCR: TTL still not per set
  1171. // - but this is at least better than Win2K where
  1172. // multiple sets and did NOT find minimum
  1173. //
  1174. maxTtl = g_MaxCacheTtl;
  1175. if ( prr->wType == DNS_TYPE_SOA )
  1176. {
  1177. maxTtl = g_MaxSOACacheEntryTtlLimit;
  1178. }
  1179. //
  1180. // get caching TTL
  1181. // - minimum TTL in set
  1182. // - offset from current time
  1183. ttl = Dns_RecordListGetMinimumTtl( prr );
  1184. if ( ttl > maxTtl )
  1185. {
  1186. ttl = maxTtl;
  1187. }
  1188. ttl += g_CurrentCacheTime;
  1189. #if 0
  1190. // screening done at higher level now
  1191. //
  1192. // screen records
  1193. // - no non-RPCable types
  1194. // - no Authority records
  1195. //
  1196. if ( prr->wType != 0 )
  1197. {
  1198. prr = Dns_RecordListScreen(
  1199. prr,
  1200. SCREEN_OUT_AUTHORITY | SCREEN_OUT_NON_RPC );
  1201. DNS_ASSERT( prr );
  1202. }
  1203. #endif
  1204. //
  1205. // set timeout on all records in set
  1206. //
  1207. // note: FreeOwner handling depends on leading record
  1208. // in having owner name set, otherwise this produces
  1209. // bogus name owner fields
  1210. //
  1211. // DCR: set record list TTL function in dnslib
  1212. //
  1213. pnext = prr;
  1214. while ( pnext )
  1215. {
  1216. pnext->dwTtl = ttl;
  1217. if ( !FLAG_FreeOwner( pnext ) )
  1218. {
  1219. pnext->pName = NULL;
  1220. }
  1221. pnext = pnext->pNext;
  1222. }
  1223. }
  1224. VOID
  1225. Cache_RestoreRecordListForRpc(
  1226. IN OUT PDNS_RECORD pRecordList
  1227. )
  1228. /*++
  1229. Routine Description:
  1230. Restore cache record list for RPC.
  1231. Arguments:
  1232. pRecordList - record list to put in cache
  1233. Return Value:
  1234. None
  1235. --*/
  1236. {
  1237. PDNS_RECORD prr = pRecordList;
  1238. DWORD currentTime;
  1239. DNSDBG( TRACE, (
  1240. "Cache_RestoreRecordListForRpc( rr=%p )\n",
  1241. prr ));
  1242. if ( !prr )
  1243. {
  1244. DNS_ASSERT( FALSE );
  1245. return;
  1246. }
  1247. //
  1248. // static TTL records need no action
  1249. //
  1250. if ( IS_STATIC_RR(prr) )
  1251. {
  1252. return;
  1253. }
  1254. //
  1255. // turn timeouts back into TTLs
  1256. //
  1257. currentTime = g_CurrentCacheTime;
  1258. while ( prr )
  1259. {
  1260. DWORD ttl = prr->dwTtl - currentTime;
  1261. if ( (LONG)ttl < 0 )
  1262. {
  1263. ttl = 0;
  1264. }
  1265. prr->dwTtl = ttl;
  1266. prr = prr->pNext;
  1267. }
  1268. }
  1269. VOID
  1270. Cache_RecordSetAtomic(
  1271. IN PWSTR pwsName,
  1272. IN WORD wType,
  1273. IN PDNS_RECORD pRecordSet
  1274. )
  1275. /*++
  1276. Routine Description:
  1277. Cache record set atomically at entry.
  1278. Cache_RecordList() handles breakup of record list
  1279. and appropriate placing of records. This does caching
  1280. of single blob at particular location.
  1281. Arguments:
  1282. pRecordSet -- record list to add
  1283. Globals:
  1284. g_EntryCount -- decremented appropriately
  1285. g_NumberOfRecordsInCache -- decremented appropriately
  1286. Return Value:
  1287. None
  1288. --*/
  1289. {
  1290. INT iter;
  1291. WORD wtype;
  1292. PWSTR pname;
  1293. BOOL fstatic;
  1294. PCACHE_ENTRY pentry;
  1295. BOOL fretry;
  1296. WORD flushLevel;
  1297. DNSDBG( TRACE, (
  1298. "Cache_RecordSetAtomic( %S, type=%d, rr=%p )\n",
  1299. pwsName,
  1300. wType,
  1301. pRecordSet ));
  1302. if ( !pRecordSet )
  1303. {
  1304. return;
  1305. }
  1306. fstatic = IS_STATIC_RR(pRecordSet);
  1307. DNS_ASSERT( !fstatic ||
  1308. pRecordSet->pNext == NULL ||
  1309. (pRecordSet->wType==DNS_TYPE_CNAME) )
  1310. //
  1311. // determine caching type
  1312. // - specified OR from records
  1313. // CNAMEs will be at the head of a lookup from another type
  1314. //
  1315. wtype = wType;
  1316. if ( !wtype )
  1317. {
  1318. wtype = pRecordSet->wType;
  1319. }
  1320. //
  1321. // if name specified use it, otherwise use from records
  1322. //
  1323. pname = pwsName;
  1324. if ( !pname )
  1325. {
  1326. pname = pRecordSet->pName;
  1327. }
  1328. //
  1329. // prepare RR set for cache
  1330. //
  1331. Cache_PrepareRecordList( pRecordSet );
  1332. //
  1333. // find\create cache entry and cache
  1334. //
  1335. LOCK_CACHE();
  1336. pentry = Cache_FindEntry(
  1337. pname,
  1338. TRUE // create
  1339. );
  1340. if ( !pentry )
  1341. {
  1342. goto Failed;
  1343. }
  1344. //
  1345. // clean up existing records at node
  1346. // - remove stale records
  1347. // - remove records of same type
  1348. // - if NAME_ERROR caching remove everything
  1349. // from wire
  1350. //
  1351. flushLevel = FLUSH_LEVEL_NORMAL;
  1352. if ( wtype == DNS_TYPE_ALL &&
  1353. pRecordSet->wDataLength == 0 )
  1354. {
  1355. flushLevel = FLUSH_LEVEL_WIRE;
  1356. }
  1357. Cache_FlushEntryRecords(
  1358. pentry,
  1359. flushLevel,
  1360. wtype );
  1361. //
  1362. // check for matching record type still there
  1363. //
  1364. for ( iter = 0;
  1365. iter < (INT)pentry->MaxCount;
  1366. iter++ )
  1367. {
  1368. PDNS_RECORD prrExist = pentry->Records[iter];
  1369. if ( !prrExist ||
  1370. prrExist->wType != wtype )
  1371. {
  1372. continue;
  1373. }
  1374. // matching type still there after flush
  1375. // - if trying to cache wire set at hostfile entry, fail
  1376. DNS_ASSERT( IS_STATIC_RR(prrExist) );
  1377. if ( !fstatic )
  1378. {
  1379. DNSDBG( ANY, (
  1380. "ERROR: attempted caching at static (hosts file) record data!\n"
  1381. "\tpRecord = %p\n"
  1382. "\tName = %S\n"
  1383. "\tType = %d\n"
  1384. "\t-- Dumping new cache record list.\n",
  1385. pRecordSet,
  1386. pRecordSet->pName,
  1387. pRecordSet->wType ));
  1388. goto Failed;
  1389. }
  1390. //
  1391. // append host file records
  1392. // - start at "record" which is addr of record ptr entry
  1393. // making pNext field the actual pointer
  1394. // - delete duplicates
  1395. // - tack new RR on end
  1396. // - blow away new RR name if existing record
  1397. //
  1398. // DCR: should have simple "make cache RR set" function that
  1399. // handles name and TTL issues
  1400. //
  1401. // DCR: broken if non-flush load hits wire data; wire data
  1402. // may have multiple RR sets
  1403. //
  1404. else
  1405. {
  1406. PDNS_RECORD prr;
  1407. PDNS_RECORD prrPrev = (PDNS_RECORD) &pentry->Records[iter];
  1408. while ( prr = prrPrev->pNext )
  1409. {
  1410. // matches existing record?
  1411. // - cut existing record from list and free
  1412. if ( Dns_RecordCompare( prr, pRecordSet ) )
  1413. {
  1414. prrPrev->pNext = prr->pNext;
  1415. Dns_RecordFree( prr );
  1416. }
  1417. else
  1418. {
  1419. prrPrev = prr;
  1420. }
  1421. }
  1422. //
  1423. // tack entry on to end
  1424. // - if existing records of type delete name
  1425. //
  1426. if ( prrPrev != (PDNS_RECORD)&pentry->Records[iter] )
  1427. {
  1428. if ( IS_FREE_OWNER(pRecordSet) )
  1429. {
  1430. RECORD_HEAP_FREE( pRecordSet->pName );
  1431. pRecordSet->pName = NULL;
  1432. }
  1433. }
  1434. prrPrev->pNext = pRecordSet;
  1435. goto Done;
  1436. }
  1437. }
  1438. //
  1439. // put record into cache entry
  1440. //
  1441. // if no slot is available, switch to a harder scrub
  1442. //
  1443. // DCR: realloc if out of slots
  1444. //
  1445. fretry = FALSE;
  1446. while ( 1 )
  1447. {
  1448. for ( iter = 0;
  1449. iter < (INT)pentry->MaxCount;
  1450. iter++ )
  1451. {
  1452. if ( pentry->Records[iter] == NULL )
  1453. {
  1454. pentry->Records[iter] = pRecordSet;
  1455. g_RecordSetCount++;
  1456. g_RecordSetCache++;
  1457. goto Done;
  1458. }
  1459. }
  1460. if ( !fretry )
  1461. {
  1462. DNSDBG( QUERY, (
  1463. "No slots caching RR set %p at entry %p\n"
  1464. "\tdoing strong flush to free slot.\n",
  1465. pRecordSet,
  1466. pentry ));
  1467. Cache_FlushEntryRecords(
  1468. pentry,
  1469. FLUSH_LEVEL_WIRE,
  1470. 0 );
  1471. fretry = TRUE;
  1472. continue;
  1473. }
  1474. DNSDBG( ANY, (
  1475. "ERROR: Failed to cache set %p at entry %p\n",
  1476. pRecordSet,
  1477. pentry ));
  1478. goto Failed;
  1479. }
  1480. Failed:
  1481. DNSDBG( TRACE, ( "Cache_RecordSetAtomic() => failed\n" ));
  1482. Dns_RecordListFree( pRecordSet );
  1483. Done:
  1484. UNLOCK_CACHE();
  1485. DNSDBG( TRACE, ( "Leave Cache_RecordSetAtomic()\n" ));
  1486. return;
  1487. }
  1488. VOID
  1489. Cache_RecordList(
  1490. IN OUT PDNS_RECORD pRecordList
  1491. )
  1492. /*++
  1493. Routine Description:
  1494. Cache record list.
  1495. This is cache routine for "oddball" records -- not caching under
  1496. queried name.
  1497. - hostfile
  1498. - answer records at CNAME
  1499. - additional data at additional name
  1500. Arguments:
  1501. pRecordList -- record list to cache
  1502. Return Value:
  1503. None
  1504. --*/
  1505. {
  1506. BOOL fcnameAnswer = FALSE;
  1507. PDNS_RECORD pnextRR = pRecordList;
  1508. PDNS_RECORD prr;
  1509. BOOL fstatic;
  1510. DNSDBG( TRACE, (
  1511. "Cache_RecordList( rr=%p )\n",
  1512. pRecordList ));
  1513. if ( !pRecordList )
  1514. {
  1515. return;
  1516. }
  1517. fstatic = IS_STATIC_RR(pRecordList);
  1518. //
  1519. // cache records:
  1520. // - cache additional records in query
  1521. // - cache CNAME data from query
  1522. // - cache host file data
  1523. //
  1524. // background: Glenn's caching paradigm was to cache all answer
  1525. // data at the queried name in the API call (name might be short).
  1526. // However, not caching the CNAME data can cause problems, so this
  1527. // was tacked on.
  1528. //
  1529. // For CNAME caching we throw away the CNAMEs themselves and just
  1530. // cache the actually data (address) records at the CNAME node.
  1531. //
  1532. //
  1533. // cache additional records
  1534. //
  1535. while ( prr = pnextRR )
  1536. {
  1537. BOOL fcacheSet = FALSE;
  1538. pnextRR = Dns_RecordSetDetach( prr );
  1539. //
  1540. // host file data -- always cache
  1541. //
  1542. // for CNAME want CNAME AND associated answer data
  1543. // - detach to get new next set
  1544. // - append answer data back on to CNAME for caching
  1545. // - next RR set (if exists) will be another CNAME
  1546. // to the same address data
  1547. //
  1548. // DCR: follow CNAMEs in cache
  1549. // then could pull this hack
  1550. // and avoid double building of answer data in dnsapi
  1551. //
  1552. if ( fstatic )
  1553. {
  1554. fcacheSet = TRUE;
  1555. if ( prr->wType == DNS_TYPE_CNAME &&
  1556. pnextRR &&
  1557. pnextRR->wType != DNS_TYPE_CNAME )
  1558. {
  1559. PDNS_RECORD panswer = pnextRR;
  1560. pnextRR = Dns_RecordSetDetach( panswer );
  1561. Dns_RecordListAppend( prr, panswer );
  1562. }
  1563. }
  1564. //
  1565. // wire data -- do NOT cache:
  1566. // - answer records for queried name (not CNAME)
  1567. // - CNAME records when doing caching of answer data under CNAME
  1568. // - authority section records (NS, SOA, etc)
  1569. // - OPT records
  1570. //
  1571. else if ( prr->Flags.S.Section == DNSREC_ANSWER )
  1572. {
  1573. if ( prr->wType == DNS_TYPE_CNAME )
  1574. {
  1575. fcnameAnswer = TRUE;
  1576. }
  1577. else if ( fcnameAnswer )
  1578. {
  1579. fcacheSet = TRUE;
  1580. }
  1581. }
  1582. else if ( prr->Flags.S.Section == DNSREC_ADDITIONAL )
  1583. {
  1584. if ( prr->wType != DNS_TYPE_OPT )
  1585. {
  1586. fcacheSet = TRUE;
  1587. }
  1588. }
  1589. if ( !fcacheSet )
  1590. {
  1591. Dns_RecordListFree( prr );
  1592. continue;
  1593. }
  1594. //
  1595. // cache the set
  1596. //
  1597. // flip the section field to "Answer" section
  1598. //
  1599. // DCR: section caching?
  1600. //
  1601. // note: section fields in cache indicate whether
  1602. // answer data (or additional) once out of
  1603. // cache;
  1604. // this is necessary since we cache everything
  1605. // at node and return it in one RR list; we'd
  1606. // to change must
  1607. // - return in different lists with some indication
  1608. // in cache of what's what
  1609. // OR
  1610. // - another indication of what's what
  1611. //
  1612. //if ( !fstatic )
  1613. // currently HostFile entries get answer too
  1614. {
  1615. PDNS_RECORD ptemp = prr;
  1616. while ( ptemp )
  1617. {
  1618. ptemp->Flags.S.Section = DNSREC_ANSWER;
  1619. ptemp = ptemp->pNext;
  1620. }
  1621. }
  1622. Cache_RecordSetAtomic(
  1623. NULL,
  1624. 0,
  1625. prr );
  1626. }
  1627. DNSDBG( TRACE, ( "Leave Cache_RecordList()\n" ));
  1628. }
  1629. VOID
  1630. Cache_FlushRecords(
  1631. IN PWSTR pName,
  1632. IN DWORD Level,
  1633. IN WORD Type
  1634. )
  1635. /*++
  1636. Routine Description:
  1637. Flush cached records corresponding to a name and type.
  1638. Arguments:
  1639. pName -- name of records to delete
  1640. Level -- flush level
  1641. Type -- type of records to delete;
  1642. 0 to flush all records at name
  1643. Return Value:
  1644. ERROR_SUCCESS if successful.
  1645. ErrorCode on failure.
  1646. --*/
  1647. {
  1648. WORD iter;
  1649. PCACHE_ENTRY pentry = NULL;
  1650. PCACHE_ENTRY pprevEntry = NULL;
  1651. DNSDBG( TRACE, (
  1652. "Cache_FlushRecords( %S, %d )\n",
  1653. pName,
  1654. Type ));
  1655. //
  1656. // lock with no-start
  1657. // - bail if no cache
  1658. //
  1659. // need this as PnP release notifications will attempt to
  1660. // flush local cache entries; this avoids rebuilding when
  1661. // already down
  1662. //
  1663. LOCK_CACHE_NO_START();
  1664. if ( !g_HashTable )
  1665. {
  1666. goto Done;
  1667. }
  1668. //
  1669. // find entry in cache
  1670. //
  1671. pentry = Cache_FindEntry(
  1672. pName,
  1673. FALSE // no create
  1674. );
  1675. if ( !pentry )
  1676. {
  1677. goto Done;
  1678. }
  1679. //
  1680. // flush records of type
  1681. // - zero type will flush all
  1682. //
  1683. // note: Cache_FindEntry() always moves the found entry
  1684. // to the front of the hash bucket list; this allows
  1685. // us to directly whack the entry
  1686. //
  1687. if ( Cache_FlushEntryRecords(
  1688. pentry,
  1689. Level,
  1690. Type ) )
  1691. {
  1692. DWORD index = getHashIndex(
  1693. pentry->pName,
  1694. 0 );
  1695. DNS_ASSERT( pentry == g_HashTable[index] );
  1696. if ( pentry == g_HashTable[index] )
  1697. {
  1698. g_HashTable[ index ] = pentry->pNext;
  1699. Cache_FreeEntry( pentry );
  1700. }
  1701. }
  1702. Done:
  1703. UNLOCK_CACHE();
  1704. }
  1705. #if 0
  1706. BOOL
  1707. ReadCachedResults(
  1708. OUT PDNS_RESULTS pResults,
  1709. IN PWSTR pwsName,
  1710. IN WORD wType
  1711. )
  1712. /*++
  1713. Routine Description:
  1714. Find records of given name and type in cache.
  1715. Arguments:
  1716. pResults -- addr to receive results
  1717. pwsName -- name
  1718. wType -- record type to find
  1719. Return Value:
  1720. TRUE if results found.
  1721. FALSE if no cached data for name and type.
  1722. --*/
  1723. {
  1724. PDNS_RECORD prr;
  1725. DNS_STATUS status;
  1726. BOOL found = FALSE;
  1727. //
  1728. // clear results
  1729. //
  1730. RtlZeroMemory( pResults, sizeof(*pResults) );
  1731. // get cache results
  1732. // break out into results buffer
  1733. if ( found )
  1734. {
  1735. BreakRecordsIntoBlob(
  1736. pResults,
  1737. prr,
  1738. wType );
  1739. pResults->Status = status;
  1740. }
  1741. return( found );
  1742. }
  1743. #endif
  1744. //
  1745. // Cache utilities for remote routines
  1746. //
  1747. PDNS_RECORD
  1748. Cache_FindRecordsPrivate(
  1749. IN PWSTR pwsName,
  1750. IN WORD wType
  1751. )
  1752. /*++
  1753. Routine Description:
  1754. Find records of given name and type in cache.
  1755. Arguments:
  1756. pwsName -- name
  1757. Type -- record type to find
  1758. Return Value:
  1759. Ptr to record set of desired type -- if found.
  1760. NULL if not found.
  1761. --*/
  1762. {
  1763. PCACHE_ENTRY pentry;
  1764. PDNS_RECORD prr = NULL;
  1765. DNSDBG( TRACE, (
  1766. "Cache_FindRecordsPrivate( %S, type=%d )\n",
  1767. pwsName,
  1768. wType ));
  1769. LOCK_CACHE();
  1770. pentry = Cache_FindEntry(
  1771. pwsName,
  1772. FALSE );
  1773. if ( pentry )
  1774. {
  1775. prr = Cache_FindEntryRecords(
  1776. pentry,
  1777. wType );
  1778. }
  1779. UNLOCK_CACHE();
  1780. DNSDBG( TRACE, (
  1781. "Leave Cache_FindRecordsPrivate( %S, type=%d ) => %p\n",
  1782. pwsName,
  1783. wType,
  1784. prr ));
  1785. return prr;
  1786. }
  1787. BOOL
  1788. Cache_GetRecordsForRpc(
  1789. OUT PDNS_RECORD * ppRecordList,
  1790. OUT PDNS_STATUS pStatus,
  1791. IN PWSTR pwsName,
  1792. IN WORD wType,
  1793. IN DWORD Flags
  1794. )
  1795. /*++
  1796. Routine Description:
  1797. Find records of given name and type in cache.
  1798. Arguments:
  1799. ppRecordList -- addr to receive pointer to record list
  1800. pStatus -- addr to get status return
  1801. pwsName -- name
  1802. Type -- record type to find
  1803. Flags -- query flags
  1804. Return Value:
  1805. TRUE if cache hit. OUT params are valid.
  1806. FALSE if cache miss. OUT params are unset.
  1807. --*/
  1808. {
  1809. PDNS_RECORD prr;
  1810. PDNS_RECORD prrResult = NULL;
  1811. DNS_STATUS status = NO_ERROR;
  1812. DNSDBG( RPC, (
  1813. "Cache_GetRecordsForRpc( %S, t=%d )\n",
  1814. pwsName,
  1815. wType ));
  1816. if ( (Flags & DNS_QUERY_BYPASS_CACHE) &&
  1817. (Flags & DNS_QUERY_NO_HOSTS_FILE) )
  1818. {
  1819. return FALSE;
  1820. }
  1821. LOCK_CACHE();
  1822. //
  1823. // check cache for name and type
  1824. // - if name or type missing, jump to wire lookup
  1825. //
  1826. prr = Cache_FindRecordsPrivate(
  1827. pwsName,
  1828. wType );
  1829. if ( !prr )
  1830. {
  1831. goto Failed;
  1832. }
  1833. //
  1834. // cache hit
  1835. //
  1836. // if only interested in host file data ignore
  1837. //
  1838. if ( IS_HOSTS_FILE_RR(prr) )
  1839. {
  1840. if ( Flags & DNS_QUERY_NO_HOSTS_FILE )
  1841. {
  1842. goto Failed;
  1843. }
  1844. }
  1845. else // cache data
  1846. {
  1847. if ( Flags & DNS_QUERY_BYPASS_CACHE )
  1848. {
  1849. goto Failed;
  1850. }
  1851. }
  1852. //
  1853. // build response from cache data
  1854. // - cached NAME_ERROR or empty
  1855. // - cached records
  1856. //
  1857. if ( prr->wDataLength == 0 )
  1858. {
  1859. status = (prr->wType == DNS_TYPE_ANY)
  1860. ? DNS_ERROR_RCODE_NAME_ERROR
  1861. : DNS_INFO_NO_RECORDS;
  1862. }
  1863. else
  1864. {
  1865. // for CNAME query, get only the CNAME record itself
  1866. // not the data at the CNAME
  1867. //
  1868. // DCR: CNAME handling should be optional -- not given
  1869. // for cache display purposes
  1870. //
  1871. if ( wType == DNS_TYPE_CNAME &&
  1872. prr->wType == DNS_TYPE_CNAME &&
  1873. prr->Flags.S.Section == DNSREC_ANSWER )
  1874. {
  1875. prrResult = Dns_RecordCopyEx(
  1876. prr,
  1877. DnsCharSetUnicode,
  1878. DnsCharSetUnicode );
  1879. }
  1880. else
  1881. {
  1882. prrResult = Dns_RecordSetCopyEx(
  1883. prr,
  1884. DnsCharSetUnicode,
  1885. DnsCharSetUnicode );
  1886. }
  1887. if ( prrResult )
  1888. {
  1889. Cache_RestoreRecordListForRpc( prrResult );
  1890. status = ERROR_SUCCESS;
  1891. }
  1892. else
  1893. {
  1894. status = ERROR_NOT_ENOUGH_MEMORY;
  1895. }
  1896. }
  1897. UNLOCK_CACHE();
  1898. // set return values
  1899. *ppRecordList = prrResult;
  1900. *pStatus = status;
  1901. return TRUE;
  1902. Failed:
  1903. UNLOCK_CACHE();
  1904. return FALSE;
  1905. }
  1906. //
  1907. // Garbage collection
  1908. //
  1909. VOID
  1910. Cache_SizeCheck(
  1911. VOID
  1912. )
  1913. /*++
  1914. Routine Description:
  1915. Check cache size.
  1916. Arguments:
  1917. Flag -- flag, currently unused
  1918. Return Value:
  1919. None
  1920. --*/
  1921. {
  1922. //
  1923. // ok -- don't signal for garbage collect
  1924. //
  1925. // - below threshold
  1926. // - already in garbage collection
  1927. // - collected recently
  1928. //
  1929. if ( g_RecordSetCount < g_RecordSetCountThreshold ||
  1930. g_GarbageCollectFlag ||
  1931. g_NextGarbageTime > GetCurrentTimeInSeconds() )
  1932. {
  1933. return;
  1934. }
  1935. DNSDBG( CACHE, (
  1936. "Cache_SizeCheck() over threshold!\n"
  1937. "\tRecordSetCount = %d\n"
  1938. "\tRecordSetCountLimit = %d\n"
  1939. "\tStarting garbage collection ...\n",
  1940. g_RecordSetCount,
  1941. g_RecordSetCountThreshold ));
  1942. //
  1943. // signal within lock, so that service thread
  1944. // can do signal within lock and avoid race on StopFlag check
  1945. // obviously better to simply not overload lock
  1946. //
  1947. LOCK_CACHE();
  1948. if ( !g_StopFlag )
  1949. {
  1950. g_GarbageCollectFlag = TRUE;
  1951. SetEvent( g_hStopEvent );
  1952. }
  1953. UNLOCK_CACHE();
  1954. }
  1955. VOID
  1956. Cache_GarbageCollect(
  1957. IN DWORD Flag
  1958. )
  1959. /*++
  1960. Routine Description:
  1961. Garbage collect cache.
  1962. Arguments:
  1963. Flag -- flag, currently unused
  1964. Return Value:
  1965. None
  1966. --*/
  1967. {
  1968. DWORD iter;
  1969. DWORD index;
  1970. WORD flushLevel;
  1971. DWORD passCount;
  1972. DNSDBG( CACHE, (
  1973. "Cache_GarbageCollect()\n"
  1974. "\tNextIndex = %d\n"
  1975. "\tRecordSetCount = %d\n"
  1976. "\tRecordSetLimit = %d\n"
  1977. "\tRecordSetThreshold = %d\n",
  1978. g_NextGarbageIndex,
  1979. g_RecordSetCount,
  1980. g_RecordSetCountLimit,
  1981. g_RecordSetCountThreshold
  1982. ));
  1983. if ( !g_HashTable )
  1984. {
  1985. return;
  1986. }
  1987. //
  1988. // collect timed out data in cache
  1989. //
  1990. // DCR: smart garbage detect
  1991. // - cleans until below limit
  1992. // - first pass invalid
  1993. // - then the hard stuff
  1994. // use restartable index so get through the cach
  1995. //
  1996. passCount = 0;
  1997. while ( 1 )
  1998. {
  1999. if ( passCount == 0 )
  2000. {
  2001. flushLevel = FLUSH_LEVEL_INVALID;
  2002. }
  2003. else if ( passCount == 1 )
  2004. {
  2005. flushLevel = FLUSH_LEVEL_GARBAGE;
  2006. }
  2007. else
  2008. {
  2009. break;
  2010. }
  2011. passCount++;
  2012. //
  2013. // flush all hash bins at current flush level
  2014. // until
  2015. // - service stop
  2016. // - push cache size below limit
  2017. //
  2018. for ( iter = 0;
  2019. iter < g_HashTableSize;
  2020. iter++ )
  2021. {
  2022. index = (iter + g_NextGarbageIndex) % g_HashTableSize;
  2023. if ( g_StopFlag ||
  2024. g_WakeFlag ||
  2025. g_RecordSetCount < g_RecordSetCountLimit )
  2026. {
  2027. passCount = MAXDWORD;
  2028. break;
  2029. }
  2030. Cache_FlushBucket(
  2031. index,
  2032. flushLevel );
  2033. }
  2034. index++;
  2035. if ( index >= g_HashTableSize )
  2036. {
  2037. index = 0;
  2038. }
  2039. g_NextGarbageIndex = index;
  2040. }
  2041. //
  2042. // reset garbage globals
  2043. // - lockout for interval
  2044. // - clear signal flag
  2045. // - reset event (if not shuttting down)
  2046. //
  2047. // note: reset signal within lock, so that service thread
  2048. // can do signal within lock and avoid race on StopFlag check
  2049. // obviously better to simply not overload lock
  2050. //
  2051. g_NextGarbageTime = GetCurrentTimeInSeconds() + GARBAGE_LOCKOUT_INTERVAL;
  2052. LOCK_CACHE();
  2053. if ( !g_StopFlag )
  2054. {
  2055. g_GarbageCollectFlag = FALSE;
  2056. ResetEvent( g_hStopEvent );
  2057. }
  2058. UNLOCK_CACHE();
  2059. DNSDBG( CACHE, (
  2060. "Leave Cache_GarbageCollect()\n"
  2061. "\tNextIndex = %d\n"
  2062. "\tNextTime = %d\n"
  2063. "\tRecordSetCount = %d\n"
  2064. "\tRecordSetLimit = %d\n"
  2065. "\tRecordSetThreshold = %d\n",
  2066. g_NextGarbageIndex,
  2067. g_NextGarbageTime,
  2068. g_RecordSetCount,
  2069. g_RecordSetCountLimit,
  2070. g_RecordSetCountThreshold
  2071. ));
  2072. }
  2073. //
  2074. // Hostfile load stuff
  2075. //
  2076. VOID
  2077. LoadHostFileIntoCache(
  2078. IN PSTR pszFileName
  2079. )
  2080. /*++
  2081. Routine Description:
  2082. Read hosts file into cache.
  2083. Arguments:
  2084. pFileName -- file name to load
  2085. Return Value:
  2086. None.
  2087. --*/
  2088. {
  2089. HOST_FILE_INFO hostInfo;
  2090. DNSDBG( INIT, ( "Enter LoadHostFileIntoCache\n" ));
  2091. //
  2092. // read entries from host file until exhausted
  2093. // - cache A record for each name and alias
  2094. // - cache PTR to name
  2095. //
  2096. RtlZeroMemory(
  2097. &hostInfo,
  2098. sizeof(hostInfo) );
  2099. hostInfo.pszFileName = pszFileName;
  2100. if ( !Dns_OpenHostFile( &hostInfo ) )
  2101. {
  2102. return;
  2103. }
  2104. hostInfo.fBuildRecords = TRUE;
  2105. while ( Dns_ReadHostFileLine( &hostInfo ) )
  2106. {
  2107. // cache all the records we sucked out
  2108. Cache_RecordList( hostInfo.pForwardRR );
  2109. Cache_RecordList( hostInfo.pReverseRR );
  2110. Cache_RecordList( hostInfo.pAliasRR );
  2111. }
  2112. Dns_CloseHostFile( &hostInfo );
  2113. DNSDBG( INIT, ( "Leave LoadHostFileIntoCache\n" ));
  2114. }
  2115. VOID
  2116. InitCacheWithHostFile(
  2117. VOID
  2118. )
  2119. /*++
  2120. Routine Description:
  2121. Initialize cache with host(s) file.
  2122. This handles regular cache file and ICS file if it
  2123. exists.
  2124. Arguments:
  2125. None
  2126. Return Value:
  2127. None.
  2128. --*/
  2129. {
  2130. DNSDBG( INIT, ( "Enter InitCacheWithHostFile\n" ));
  2131. //
  2132. // load host file into cache
  2133. //
  2134. LoadHostFileIntoCache( NULL );
  2135. //
  2136. // if running ICS, load it's file also
  2137. //
  2138. LoadHostFileIntoCache( "hosts.ics" );
  2139. DNSDBG( INIT, ( "Leave InitCacheWithHostFile\n\n\n" ));
  2140. }
  2141. DNS_STATUS
  2142. Cache_QueryResponse(
  2143. IN OUT PQUERY_BLOB pBlob
  2144. )
  2145. /*++
  2146. Routine Description:
  2147. Find records of given name and type in cache.
  2148. Arguments:
  2149. pBlob -- query blob
  2150. Uses:
  2151. pwsName
  2152. wType
  2153. Status
  2154. pRecords
  2155. fCacheNegativeResponse
  2156. Sets:
  2157. pRecords - may be reset to exclude non-RPCable records
  2158. Return Value:
  2159. ErrorStatus -- same as query status, unless processing error during caching
  2160. --*/
  2161. {
  2162. DNS_STATUS status = pBlob->Status;
  2163. PWSTR pname = pBlob->pNameOrig;
  2164. WORD wtype = pBlob->wType;
  2165. PDNS_RECORD presultRR = pBlob->pRecords;
  2166. DNSDBG( RPC, (
  2167. "\nCache_QueryResponse( %S, type %d )\n",
  2168. pname,
  2169. wtype ));
  2170. //
  2171. // successful response
  2172. // - make copy of records to return to caller
  2173. // - cache actual query record set
  2174. // - make copy to cache any additional data
  2175. //
  2176. if ( status == ERROR_SUCCESS && presultRR )
  2177. {
  2178. DWORD copyFlag;
  2179. PDNS_RECORD prrCache;
  2180. // cleanup for RPC and caching
  2181. prrCache = Dns_RecordListScreen(
  2182. presultRR,
  2183. SCREEN_OUT_AUTHORITY | SCREEN_OUT_NON_RPC );
  2184. //
  2185. // make copy for return
  2186. // - don't include authority records
  2187. //
  2188. // NOTE: IMPORTANT
  2189. // we return (RPC) a COPY of the wire set and cache the
  2190. // wire set; this is because the wire set has imbedded data
  2191. // (the data pointers are not actual heap allocations) and
  2192. // and hence can not be RPC'd (without changing the RPC
  2193. // definition to flat data)
  2194. //
  2195. // if we later want to return authority data on first query,
  2196. // then
  2197. // - clean non-RPC only
  2198. // - including owner name fixups
  2199. // - copy for result set
  2200. // - clean original for authority -- cache
  2201. // - clean any additional -- cache
  2202. //
  2203. // note: do name pointer fixup by making round trip into cache format
  2204. //
  2205. // DCR: shouldn't have external name pointers anywhere
  2206. // DCR: do RPC-able cleanup on original set before copy
  2207. // OR
  2208. // DCR: have "cache state" on record
  2209. // then could move original results to cache state and caching
  2210. // routines could detect state and avoid double TTLing
  2211. presultRR = Dns_RecordListCopyEx(
  2212. prrCache,
  2213. 0,
  2214. // SCREEN_OUT_AUTHORITY
  2215. DnsCharSetUnicode,
  2216. DnsCharSetUnicode );
  2217. pBlob->pRecords = presultRR;
  2218. if ( !presultRR )
  2219. {
  2220. Dns_RecordListFree( prrCache );
  2221. status = DNS_ERROR_NO_MEMORY;
  2222. goto Done;
  2223. }
  2224. // name pointer fixup
  2225. Cache_PrepareRecordList( presultRR );
  2226. Cache_RestoreRecordListForRpc( presultRR );
  2227. //
  2228. // do NOT cache local records
  2229. //
  2230. // note: we went through this function only to get
  2231. // PTR records and CNAME records in RPC format
  2232. // (no imbedded pointers)
  2233. //
  2234. if ( pBlob->pLocalRecords )
  2235. {
  2236. Dns_RecordListFree( prrCache );
  2237. goto Done;
  2238. }
  2239. //
  2240. // cache original data
  2241. //
  2242. if ( prrCache )
  2243. {
  2244. Cache_RecordSetAtomic(
  2245. pname,
  2246. wtype,
  2247. prrCache );
  2248. }
  2249. //
  2250. // extra records
  2251. // - additional data
  2252. // - CNAME answer data to cache at CNAME itself
  2253. // in CNAME case must include ANSWER data, but
  2254. // skip the CNAME itself
  2255. //
  2256. // Cache_RecordList() breaks records into RR sets before caching
  2257. //
  2258. prrCache = presultRR;
  2259. copyFlag = SCREEN_OUT_ANSWER | SCREEN_OUT_AUTHORITY;
  2260. if ( prrCache->wType == DNS_TYPE_CNAME )
  2261. {
  2262. prrCache = prrCache->pNext;
  2263. copyFlag = SCREEN_OUT_AUTHORITY;
  2264. }
  2265. prrCache = Dns_RecordListCopyEx(
  2266. prrCache,
  2267. copyFlag,
  2268. DnsCharSetUnicode,
  2269. DnsCharSetUnicode );
  2270. if ( prrCache )
  2271. {
  2272. Cache_RecordList( prrCache );
  2273. }
  2274. }
  2275. //
  2276. // negative response
  2277. //
  2278. else if ( status == DNS_ERROR_RCODE_NAME_ERROR ||
  2279. status == DNS_INFO_NO_RECORDS )
  2280. {
  2281. DWORD ttl;
  2282. PDNS_RECORD prr;
  2283. if ( !pBlob->fCacheNegative )
  2284. {
  2285. DNSDBG( QUERY, (
  2286. "No negative caching for %S, type=%d\n",
  2287. pname, wtype ));
  2288. goto Done;
  2289. }
  2290. //
  2291. // create negative cache entry
  2292. //
  2293. // DCR: should use TTL returned in SOA
  2294. //
  2295. prr = Dns_AllocateRecord( 0 );
  2296. if ( !prr )
  2297. {
  2298. status = ERROR_NOT_ENOUGH_MEMORY;
  2299. goto Done;
  2300. }
  2301. prr->pName = (PWSTR) Dns_StringCopyAllocate(
  2302. (PCHAR) pname,
  2303. 0, // NULL terminated
  2304. DnsCharSetUnicode,
  2305. DnsCharSetUnicode );
  2306. if ( prr->pName )
  2307. {
  2308. SET_FREE_OWNER( prr );
  2309. }
  2310. prr->wDataLength = 0;
  2311. ttl = g_MaxNegativeCacheTtl;
  2312. if ( wtype == DNS_TYPE_SOA
  2313. &&
  2314. ttl > g_NegativeSOACacheTime )
  2315. {
  2316. ttl = g_NegativeSOACacheTime;
  2317. }
  2318. prr->dwTtl = ttl;
  2319. prr->Flags.S.CharSet = DnsCharSetUnicode;
  2320. prr->Flags.S.Section = DNSREC_ANSWER;
  2321. prr->Flags.DW |= DNSREC_NOEXIST;
  2322. if ( status == DNS_ERROR_RCODE_NAME_ERROR )
  2323. {
  2324. prr->wType = DNS_TYPE_ANY;
  2325. }
  2326. else
  2327. {
  2328. prr->wType = wtype;
  2329. }
  2330. Cache_RecordSetAtomic(
  2331. NULL, // default name
  2332. 0, // default type
  2333. prr );
  2334. }
  2335. // failure return from query
  2336. // - nothing to cache
  2337. else
  2338. {
  2339. DNSDBG( QUERY, (
  2340. "Uncacheable error code %d -- no caching for %S, type=%d\n",
  2341. status,
  2342. pname,
  2343. wtype ));
  2344. }
  2345. Done:
  2346. //
  2347. // check cache size to see if garbage collect necessary
  2348. //
  2349. // note we do this only on query caching; this avoids
  2350. // - jamming ourselves in hosts file load
  2351. // - wakeup and grabbing lock between separate sets of query response
  2352. //
  2353. Cache_SizeCheck();
  2354. return status;
  2355. }
  2356. //
  2357. // End ncache.c
  2358. //