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.

2018 lines
44 KiB

  1. /*++
  2. Copyright (c) 1994 Microsoft Corporation
  3. Module Name:
  4. rescache.cxx
  5. Abstract:
  6. Contains functions which manipulate resolver cache for winsock
  7. name resolution calls
  8. Contents:
  9. InitializeResolverCache
  10. TerminateResolverCache
  11. QueryResolverCache
  12. AddResolverCacheEntry
  13. FlushResolverCache
  14. ReleaseResolverCacheEntry
  15. (RemoveCacheEntry)
  16. (ResolverCacheHit)
  17. (AddrInfoMatch)
  18. (CreateCacheEntry)
  19. Author:
  20. Richard L Firth (rfirth) 10-Jul-1994
  21. Environment:
  22. Win-16/32 user level
  23. Revision History:
  24. rfirth 10-Jul-1994
  25. Created
  26. --*/
  27. //
  28. // includes
  29. //
  30. #include "wininetp.h"
  31. //
  32. // private manifests
  33. //
  34. //
  35. // private macros
  36. //
  37. #define SET_EXPIRATION_TIME(cacheEntry)
  38. //
  39. // private data
  40. //
  41. PRIVATE BOOL ResolverCacheInitialized = FALSE;
  42. //
  43. // DnsCachingEnabled - caching is enabled by default
  44. //
  45. PRIVATE BOOL DnsCachingEnabled = TRUE;
  46. //
  47. // DnsCacheTimeout - number of seconds before a cache entry expires. This value
  48. // is added to the current time (in seconds) to get the expiry time
  49. //
  50. PRIVATE DWORD DnsCacheTimeout = DEFAULT_DNS_CACHE_TIMEOUT;
  51. //
  52. // MaximumDnsCacheEntries - the maximum number of RESOLVER_CACHE_ENTRYs in the
  53. // cache before we start throwing out the LRU
  54. //
  55. PRIVATE INT MaximumDnsCacheEntries = DEFAULT_DNS_CACHE_ENTRIES;
  56. //
  57. // CurrentDnsCacheEntries - the number of RESOLVER_CACHE_ENTRYs currently in the
  58. // cache
  59. //
  60. PRIVATE INT CurrentDnsCacheEntries = 0;
  61. //
  62. // ResolverCache - serialized list of RESOLVER_CACHE_ENTRYs, kept in MRU order.
  63. // We only need to remove the tail of the list to remove the LRU entry
  64. //
  65. PRIVATE SERIALIZED_LIST ResolverCache = {0};
  66. //
  67. // private prototypes
  68. //
  69. PRIVATE
  70. VOID
  71. RemoveCacheEntry(
  72. IN LPRESOLVER_CACHE_ENTRY lpCacheEntry
  73. );
  74. PRIVATE
  75. BOOL
  76. ResolverCacheHit(
  77. IN LPRESOLVER_CACHE_ENTRY lpCacheEntry,
  78. IN LPSTR Name OPTIONAL,
  79. IN LPSOCKADDR Address OPTIONAL
  80. );
  81. PRIVATE
  82. BOOL
  83. AddrInfoMatch(
  84. IN LPADDRINFO AddrInfo,
  85. IN LPSTR Name OPTIONAL,
  86. IN LPSOCKADDR Address OPTIONAL
  87. );
  88. PRIVATE
  89. LPRESOLVER_CACHE_ENTRY
  90. CreateCacheEntry(
  91. IN LPSTR lpszHostName,
  92. IN LPADDRINFO AddrInfo,
  93. IN DWORD TimeToLive
  94. );
  95. #if INET_DEBUG
  96. PRIVATE
  97. DEBUG_FUNCTION
  98. LPSTR
  99. CacheTimestr(
  100. IN DWORD Time
  101. );
  102. PRIVATE
  103. DEBUG_FUNCTION
  104. LPSTR
  105. CacheAddrInfoStr(
  106. IN LPADDRINFO AddrInfo
  107. );
  108. PRIVATE
  109. DEBUG_FUNCTION
  110. LPSTR
  111. CacheMapSockAddress(
  112. IN LPSOCKADDR Address
  113. );
  114. #endif
  115. //
  116. // functions
  117. //
  118. VOID
  119. InitializeResolverCache(
  120. VOID
  121. )
  122. /*++
  123. Routine Description:
  124. Initializes the resolver cache:
  125. * Initializes the cache list anchor
  126. * loads the cache
  127. Arguments:
  128. None.
  129. Return Value:
  130. None.
  131. --*/
  132. {
  133. DEBUG_ENTER((DBG_SOCKETS,
  134. None,
  135. "InitializeResolverCache",
  136. NULL
  137. ));
  138. if (!(BOOL)InterlockedExchange((LPLONG)&ResolverCacheInitialized, TRUE)) {
  139. InternetReadRegistryDword("DnsCacheEnabled", (LPDWORD)&DnsCachingEnabled);
  140. InternetReadRegistryDword("DnsCacheEntries", (LPDWORD)&MaximumDnsCacheEntries);
  141. InternetReadRegistryDword("DnsCacheTimeout", &DnsCacheTimeout);
  142. InitializeSerializedList(&ResolverCache);
  143. //
  144. // if the size of the cache in the registry is 0 then its the same as
  145. // no caching
  146. //
  147. if (MaximumDnsCacheEntries == 0) {
  148. DnsCachingEnabled = FALSE;
  149. }
  150. } else {
  151. //
  152. // shouldn't be calling this more than once
  153. //
  154. INET_ASSERT(FALSE);
  155. }
  156. DEBUG_LEAVE(0);
  157. }
  158. VOID
  159. TerminateResolverCache(
  160. VOID
  161. )
  162. /*++
  163. Routine Description:
  164. Free up all resources allocated by InitializeResolverCache()
  165. Arguments:
  166. None.
  167. Return Value:
  168. None.
  169. --*/
  170. {
  171. DEBUG_ENTER((DBG_SOCKETS,
  172. None,
  173. "TerminateResolverCache",
  174. NULL
  175. ));
  176. if (InterlockedExchange((LPLONG)&ResolverCacheInitialized, FALSE)) {
  177. //
  178. // short-circuit any other cache attempts (shouldn't be any by now)
  179. //
  180. DnsCachingEnabled = FALSE;
  181. //
  182. // and clear out the list
  183. //
  184. FlushResolverCache();
  185. //
  186. // we are done with the serialized list
  187. //
  188. TerminateSerializedList(&ResolverCache);
  189. }
  190. DEBUG_LEAVE(0);
  191. }
  192. LPRESOLVER_CACHE_ENTRY
  193. QueryResolverCache(
  194. IN LPSTR Name OPTIONAL,
  195. IN LPSOCKADDR Address OPTIONAL,
  196. OUT LPADDRINFO * AddrInfo,
  197. OUT LPDWORD TimeToLive
  198. )
  199. /*++
  200. Routine Description:
  201. Checks if Name is stored in the last resolved name cache. If the entry is
  202. found, but has expired then it is removed from the cache
  203. Arguments:
  204. Name - pointer to name string
  205. Address - pointer to IP address (in sockaddr format)
  206. AddrInfo - pointer to returned pointer to addrinfo
  207. TimeToLive - pointer to returned time to live
  208. Return Value:
  209. BOOL
  210. --*/
  211. {
  212. DEBUG_ENTER((DBG_SOCKETS,
  213. Bool,
  214. "QueryResolverCache",
  215. "%q, %s, %#x, %#x",
  216. Name,
  217. CacheMapSockAddress(Address),
  218. AddrInfo,
  219. TimeToLive
  220. ));
  221. LPRESOLVER_CACHE_ENTRY lpEntry;
  222. if (!DnsCachingEnabled) {
  223. DEBUG_PRINT(SOCKETS,
  224. WARNING,
  225. ("DNS caching disabled\n"
  226. ));
  227. *AddrInfo = NULL;
  228. lpEntry = NULL;
  229. goto quit;
  230. }
  231. LockSerializedList(&ResolverCache);
  232. LPRESOLVER_CACHE_ENTRY cacheEntry;
  233. LPRESOLVER_CACHE_ENTRY previousEntry;
  234. DWORD timeNow;
  235. cacheEntry = (LPRESOLVER_CACHE_ENTRY)HeadOfSerializedList(&ResolverCache);
  236. timeNow = (DWORD)time(NULL);
  237. while (cacheEntry != (LPRESOLVER_CACHE_ENTRY)SlSelf(&ResolverCache)) {
  238. //
  239. // on every cache lookup, purge any stale entries. LIVE_FOREVER means
  240. // that we don't expect the entry's net address to expire, but it
  241. // DOESN'T mean that we can't throw out the entry if its the LRU and
  242. // we're at maximum cache capacity. We can't do this if the item is
  243. // still in-use. In this case, we mark it stale
  244. //
  245. if ((cacheEntry->ExpirationTime != LIVE_FOREVER)
  246. && (cacheEntry->ExpirationTime <= timeNow)) {
  247. //
  248. // if reference count not zero then another thread is using
  249. // this entry - mark as stale else delete it
  250. //
  251. if (cacheEntry->ReferenceCount != 0) {
  252. INET_ASSERT(cacheEntry->State == ENTRY_IN_USE);
  253. cacheEntry->State = ENTRY_DELETE;
  254. } else {
  255. //
  256. // this entry is stale; throw it out
  257. // "my hovercraft is full of eels"
  258. //
  259. DEBUG_PRINT(SOCKETS,
  260. INFO,
  261. ("throwing out stale DNS entry %q, expiry = %s\n",
  262. cacheEntry->AddrInfo->ai_canonname,
  263. CacheTimestr(cacheEntry->ExpirationTime)
  264. ));
  265. //
  266. // BUGBUG - what happens if ExpirationTime == timeNow?
  267. //
  268. previousEntry = (LPRESOLVER_CACHE_ENTRY)cacheEntry->ListEntry.Blink;
  269. RemoveCacheEntry(cacheEntry);
  270. cacheEntry = previousEntry;
  271. }
  272. } else if (ResolverCacheHit(cacheEntry, Name, Address)
  273. && ((cacheEntry->State == ENTRY_UNUSED)
  274. || (cacheEntry->State == ENTRY_IN_USE))) {
  275. //
  276. // we found the entry, and it still has time to live. Make it the
  277. // head of the list (MRU first), set the state to in-use and increase
  278. // the reference count
  279. //
  280. RemoveFromSerializedList(&ResolverCache, &cacheEntry->ListEntry);
  281. InsertAtHeadOfSerializedList(&ResolverCache, &cacheEntry->ListEntry);
  282. cacheEntry->State = ENTRY_IN_USE;
  283. ++cacheEntry->ReferenceCount;
  284. *AddrInfo = cacheEntry->AddrInfo;
  285. lpEntry = cacheEntry;
  286. DEBUG_PRINT(SOCKETS,
  287. INFO,
  288. ("entry found in DNS cache\n"
  289. ));
  290. goto done;
  291. }
  292. cacheEntry = (LPRESOLVER_CACHE_ENTRY)cacheEntry->ListEntry.Flink;
  293. }
  294. *AddrInfo = NULL;
  295. lpEntry = NULL;
  296. DEBUG_PRINT(SOCKETS,
  297. INFO,
  298. ("didn't find entry in DNS cache\n"
  299. ));
  300. done:
  301. UnlockSerializedList(&ResolverCache);
  302. quit:
  303. DEBUG_LEAVE(lpEntry);
  304. return lpEntry;
  305. }
  306. VOID
  307. AddResolverCacheEntry(
  308. IN LPSTR lpszHostName,
  309. IN LPADDRINFO AddrInfo,
  310. IN DWORD TimeToLive
  311. )
  312. /*++
  313. Routine Description:
  314. Adds an addrinfo pointer to the cache. Creates a new entry to hold it
  315. and links it into the cache list, displacing the LRU entry if required.
  316. If we cannot create the entry, the addrinfo is freed, no errors returned
  317. N.B.: Calling this routine gives the resolver cache "ownership" of the
  318. addrinfo chain. Caller should not use AddrInfo pointer afterwards.
  319. Arguments:
  320. lpszHostName - the name we originally requested be resolved. May be
  321. different than the names returned by the resolver, e.g.
  322. "proxy" => "proxy1.microsoft.com, proxy2.microsoft.com"
  323. AddrInfo - pointer to addrinfo chain to add to the cache
  324. TimeToLive - amount of time this information has to live. Can be:
  325. LIVE_FOREVER - don't timeout (but can be discarded)
  326. LIVE_DEFAULT - use the default value
  327. anything else - number of seconds to live
  328. Return Value:
  329. None.
  330. --*/
  331. {
  332. DEBUG_ENTER((DBG_SOCKETS,
  333. None,
  334. "AddResolverCacheEntry",
  335. "%q, %#x, %d",
  336. lpszHostName,
  337. AddrInfo,
  338. TimeToLive
  339. ));
  340. BOOL bAdded = FALSE;
  341. if (!DnsCachingEnabled) {
  342. DEBUG_PRINT(SOCKETS,
  343. WARNING,
  344. ("DNS caching disabled\n"
  345. ));
  346. goto quit;
  347. }
  348. LockSerializedList(&ResolverCache);
  349. //
  350. // check that the entry is not already in the cache - 2 or more threads may
  351. // have been simultaneously resolving the same name
  352. //
  353. LPADDRINFO lpAddrInfo;
  354. DWORD ttl;
  355. LPRESOLVER_CACHE_ENTRY lpResolverCacheEntry;
  356. INET_ASSERT(lpszHostName != NULL);
  357. if (!(lpResolverCacheEntry = QueryResolverCache(lpszHostName, NULL, &lpAddrInfo, &ttl))) {
  358. LPRESOLVER_CACHE_ENTRY cacheEntry;
  359. //
  360. // remove as many entries as we can beginning at the tail of the list.
  361. // We try to remove enough to get the cache size back below the limit.
  362. // This may consist of removing expired entries or entries marked as
  363. // DELETE. If there are expired, in-use entries then we mark them as
  364. // DELETE. This may result in the cache list growing until those threads
  365. // which have referenced cache entries release them
  366. //
  367. cacheEntry = (LPRESOLVER_CACHE_ENTRY)TailOfSerializedList(&ResolverCache);
  368. while ((CurrentDnsCacheEntries >= MaximumDnsCacheEntries)
  369. && (cacheEntry != (LPRESOLVER_CACHE_ENTRY)SlSelf(&ResolverCache))) {
  370. //
  371. // cache has maximum entries: throw out the Least Recently Used (its
  372. // the one at the back of the queue, ma'am) but only if no-one else
  373. // is currently accessing it
  374. //
  375. if ((cacheEntry->State != ENTRY_IN_USE)
  376. && (cacheEntry->ReferenceCount == 0)) {
  377. INET_ASSERT((cacheEntry->State == ENTRY_UNUSED)
  378. || (cacheEntry->State == ENTRY_DELETE));
  379. DEBUG_PRINT(SOCKETS,
  380. INFO,
  381. ("throwing out LRU %q\n",
  382. cacheEntry->AddrInfo->ai_canonname
  383. ));
  384. LPRESOLVER_CACHE_ENTRY nextEntry;
  385. nextEntry = (LPRESOLVER_CACHE_ENTRY)cacheEntry->ListEntry.Flink;
  386. RemoveCacheEntry(cacheEntry);
  387. cacheEntry = nextEntry;
  388. } else if (cacheEntry->State == ENTRY_IN_USE) {
  389. //
  390. // this entry needs to be freed when it is released
  391. //
  392. cacheEntry->State = ENTRY_DELETE;
  393. }
  394. cacheEntry = (LPRESOLVER_CACHE_ENTRY)cacheEntry->ListEntry.Blink;
  395. }
  396. //
  397. // add the entry at the head of the queue - it is the Most Recently Used
  398. // after all. If we fail to allocate memory, its no problem: it'll just
  399. // take a little longer if this entry would have been hit before we needed
  400. // to throw out another entry
  401. //
  402. if (cacheEntry = CreateCacheEntry(lpszHostName, AddrInfo, TimeToLive)) {
  403. DEBUG_PRINT(SOCKETS,
  404. INFO,
  405. ("caching %q, expiry = %s\n",
  406. CacheAddrInfoStr(cacheEntry->AddrInfo),
  407. CacheTimestr(cacheEntry->ExpirationTime)
  408. ));
  409. InsertAtHeadOfSerializedList(&ResolverCache, &cacheEntry->ListEntry);
  410. ++CurrentDnsCacheEntries;
  411. bAdded = TRUE;
  412. }
  413. } else {
  414. //
  415. // this entry is already in the cache. 2 or more threads must have been
  416. // resolving the same name simultaneously. We just bump the expiration
  417. // time to the more recent value
  418. //
  419. DEBUG_PRINT(SOCKETS,
  420. WARNING,
  421. ("found %q already in the cache!?\n",
  422. lpszHostName
  423. ));
  424. ReleaseResolverCacheEntry(lpResolverCacheEntry);
  425. }
  426. UnlockSerializedList(&ResolverCache);
  427. quit:
  428. if (!bAdded) {
  429. //
  430. // failed to add this entry to the cache, so free it
  431. //
  432. _I_freeaddrinfo(AddrInfo);
  433. }
  434. DEBUG_LEAVE(0);
  435. }
  436. VOID
  437. FlushResolverCache(
  438. VOID
  439. )
  440. /*++
  441. Routine Description:
  442. Removes all entries in DNS resolver cache
  443. Arguments:
  444. None.
  445. Return Value:
  446. None.
  447. --*/
  448. {
  449. DEBUG_ENTER((DBG_SOCKETS,
  450. None,
  451. "FlushResolverCache",
  452. NULL
  453. ));
  454. LPRESOLVER_CACHE_ENTRY cacheEntry;
  455. LPRESOLVER_CACHE_ENTRY previousEntry;
  456. LockSerializedList(&ResolverCache);
  457. previousEntry = (LPRESOLVER_CACHE_ENTRY)SlSelf(&ResolverCache);
  458. cacheEntry = (LPRESOLVER_CACHE_ENTRY)HeadOfSerializedList(&ResolverCache);
  459. while (cacheEntry != (LPRESOLVER_CACHE_ENTRY)SlSelf(&ResolverCache)) {
  460. if (cacheEntry->State == ENTRY_UNUSED) {
  461. RemoveCacheEntry(cacheEntry);
  462. } else {
  463. DEBUG_PRINT(SOCKETS,
  464. WARNING,
  465. ("cache entry %#x (%q) still in-use\n",
  466. cacheEntry->HostName
  467. ));
  468. cacheEntry->State = ENTRY_DELETE;
  469. previousEntry = cacheEntry;
  470. }
  471. cacheEntry = (LPRESOLVER_CACHE_ENTRY)previousEntry->ListEntry.Flink;
  472. }
  473. UnlockSerializedList(&ResolverCache);
  474. DEBUG_LEAVE(0);
  475. }
  476. VOID
  477. ReleaseResolverCacheEntry(
  478. IN LPRESOLVER_CACHE_ENTRY cacheEntry
  479. )
  480. /*++
  481. Routine Description:
  482. Either mark a entry unused or if it is stale, delete it
  483. Arguments:
  484. lpAddrInfo - pointer to AddrInfo field of entry to free
  485. Return Value:
  486. None.
  487. --*/
  488. {
  489. DEBUG_ENTER((DBG_SOCKETS,
  490. None,
  491. "ReleaseResolverCacheEntry",
  492. "%#x, %#x",
  493. cacheEntry, (cacheEntry ? cacheEntry->AddrInfo : NULL)
  494. ));
  495. LockSerializedList(&ResolverCache);
  496. //
  497. // reference count should never go below zero!
  498. //
  499. INET_ASSERT(cacheEntry->ReferenceCount > 0);
  500. if (--cacheEntry->ReferenceCount <= 0) {
  501. //
  502. // last releaser gets to decide what to do - mark unused or delete
  503. //
  504. if (cacheEntry->State == ENTRY_IN_USE) {
  505. cacheEntry->State = ENTRY_UNUSED;
  506. } else if (cacheEntry->State == ENTRY_DELETE) {
  507. //
  508. // entry is already stale - throw it out
  509. //
  510. RemoveCacheEntry(cacheEntry);
  511. } else {
  512. //
  513. // unused? or bogus value? Someone changed state while refcount
  514. // not zero?
  515. //
  516. INET_ASSERT((cacheEntry->State == ENTRY_IN_USE)
  517. || (cacheEntry->State == ENTRY_DELETE));
  518. }
  519. }
  520. UnlockSerializedList(&ResolverCache);
  521. DEBUG_LEAVE(0);
  522. }
  523. VOID
  524. ThrowOutResolverCacheEntry(
  525. IN LPADDRINFO lpAddrInfo
  526. )
  527. /*++
  528. Routine Description:
  529. Removes this entry from the DNS cache, based on the host name. We assume
  530. that the entry came from the cache, so unless it has been already purged,
  531. we should be able to throw it out
  532. Arguments:
  533. lpAddrInfo - pointer to addrinfo field with name of entry to throw out
  534. Return Value:
  535. None.
  536. --*/
  537. {
  538. DEBUG_ENTER((DBG_SOCKETS,
  539. None,
  540. "ThrowOutResolverCacheEntry",
  541. "%#x [%q]",
  542. lpAddrInfo,
  543. lpAddrInfo->ai_canonname
  544. ));
  545. if (DnsCachingEnabled) {
  546. LockSerializedList(&ResolverCache);
  547. LPRESOLVER_CACHE_ENTRY cacheEntry;
  548. cacheEntry = (LPRESOLVER_CACHE_ENTRY)HeadOfSerializedList(&ResolverCache);
  549. while (cacheEntry != (LPRESOLVER_CACHE_ENTRY)SlSelf(&ResolverCache)) {
  550. if (AddrInfoMatch(cacheEntry->AddrInfo, lpAddrInfo->ai_canonname, NULL)) {
  551. //
  552. // if the entry is unused then we can delete it, else we have
  553. // to leave it to the thread with the last reference
  554. //
  555. if (cacheEntry->State == ENTRY_UNUSED) {
  556. RemoveCacheEntry(cacheEntry);
  557. } else {
  558. cacheEntry->State = ENTRY_DELETE;
  559. }
  560. break;
  561. }
  562. }
  563. UnlockSerializedList(&ResolverCache);
  564. } else {
  565. DEBUG_PRINT(SOCKETS,
  566. WARNING,
  567. ("DNS caching disabled\n"
  568. ));
  569. }
  570. DEBUG_LEAVE(0);
  571. }
  572. PRIVATE
  573. VOID
  574. RemoveCacheEntry(
  575. IN LPRESOLVER_CACHE_ENTRY lpCacheEntry
  576. )
  577. /*++
  578. Routine Description:
  579. Takes a cache entry off the list and frees it
  580. N.B.: This function must be called with the resolver cache serialized list
  581. already locked
  582. Arguments:
  583. lpCacheEntry - currently queued entry to remove
  584. Return Value:
  585. None.
  586. --*/
  587. {
  588. DEBUG_ENTER((DBG_SOCKETS,
  589. None,
  590. "RemoveCacheEntry",
  591. "%#x",
  592. lpCacheEntry
  593. ));
  594. RemoveFromSerializedList(&ResolverCache, &lpCacheEntry->ListEntry);
  595. INET_ASSERT(lpCacheEntry->ReferenceCount == 0);
  596. INET_ASSERT((lpCacheEntry->State == ENTRY_UNUSED)
  597. || (lpCacheEntry->State == ENTRY_DELETE));
  598. DEBUG_PRINT(SOCKETS,
  599. INFO,
  600. ("throwing out %q, expiry = %s\n",
  601. CacheAddrInfoStr(lpCacheEntry->AddrInfo),
  602. CacheTimestr(lpCacheEntry->ExpirationTime)
  603. ));
  604. _I_freeaddrinfo(lpCacheEntry->AddrInfo);
  605. lpCacheEntry = (LPRESOLVER_CACHE_ENTRY)FREE_MEMORY((HLOCAL)lpCacheEntry);
  606. INET_ASSERT(lpCacheEntry == NULL);
  607. --CurrentDnsCacheEntries;
  608. DEBUG_PRINT(SOCKETS,
  609. INFO,
  610. ("CurrentDnsCacheEntries = %d\n",
  611. CurrentDnsCacheEntries
  612. ));
  613. INET_ASSERT((CurrentDnsCacheEntries >= 0)
  614. && (CurrentDnsCacheEntries <= MaximumDnsCacheEntries));
  615. DEBUG_LEAVE(0);
  616. }
  617. PRIVATE
  618. BOOL
  619. ResolverCacheHit(
  620. IN LPRESOLVER_CACHE_ENTRY lpCacheEntry,
  621. IN LPSTR Name OPTIONAL,
  622. IN LPSOCKADDR Address OPTIONAL
  623. )
  624. /*++
  625. Routine Description:
  626. Checks this RESOLVER_CACHE_ENTRY for a match with Name or Address. If Name,
  627. can match with ai_canonname in addrinfo, or with originally resolved name
  628. Arguments:
  629. lpCacheEntry - pointer to RESOLVER_CACHE_ENTRY to check
  630. Name - optional name to check
  631. Address - optional server address to check
  632. Return Value:
  633. BOOL
  634. --*/
  635. {
  636. DEBUG_ENTER((DBG_SOCKETS,
  637. Bool,
  638. "ResolverCacheHit",
  639. "%#x, %q, %s",
  640. lpCacheEntry,
  641. Name,
  642. CacheMapSockAddress(Address)
  643. ));
  644. BOOL found;
  645. if ((Name != NULL)
  646. && (lpCacheEntry->HostName != NULL)
  647. && (lstrcmpi(lpCacheEntry->HostName, Name) == 0)) {
  648. DEBUG_PRINT(SOCKETS,
  649. INFO,
  650. ("matched name %q\n",
  651. lpCacheEntry->HostName
  652. ));
  653. found = TRUE;
  654. } else {
  655. found = FALSE;
  656. Name = NULL;
  657. }
  658. if (!found && Address) {
  659. found = AddrInfoMatch(lpCacheEntry->AddrInfo, Name, Address);
  660. }
  661. DEBUG_LEAVE(found);
  662. return found;
  663. }
  664. PRIVATE
  665. BOOL
  666. AddrInfoMatch(
  667. IN LPADDRINFO AddrInfo,
  668. IN LPSTR Name OPTIONAL,
  669. IN LPSOCKADDR Address OPTIONAL
  670. )
  671. /*++
  672. Routine Description:
  673. Compares a getaddrinfo result for a match with a host name or address
  674. Arguments:
  675. AddrInfo - pointer to addrinfo chain to compare
  676. Name - pointer to name string
  677. Address - pointer to IP address (as a sockaddr)
  678. Return Value:
  679. BOOL
  680. --*/
  681. {
  682. DEBUG_ENTER((DBG_SOCKETS,
  683. Bool,
  684. "AddrInfoMatch",
  685. "%#x, %q, %s",
  686. AddrInfo,
  687. Name,
  688. CacheMapSockAddress(Address)
  689. ));
  690. BOOL found = FALSE;
  691. if (Name) {
  692. if ((AddrInfo->ai_canonname != NULL) &&
  693. (lstrcmpi(AddrInfo->ai_canonname, Name) == 0))
  694. found = TRUE;
  695. } else {
  696. INET_ASSERT(Address != NULL);
  697. do {
  698. if ((AddrInfo->ai_addr->sa_family == Address->sa_family)
  699. && (memcmp(AddrInfo->ai_addr, Address, AddrInfo->ai_addrlen) == 0)) {
  700. DEBUG_PRINT(SOCKETS,
  701. INFO,
  702. ("matched %s\n",
  703. CacheMapSockAddress(Address)
  704. ));
  705. found = TRUE;
  706. break;
  707. }
  708. } while (AddrInfo = AddrInfo->ai_next);
  709. }
  710. if (found) {
  711. DEBUG_PRINT(SOCKETS,
  712. INFO,
  713. ("addrinfo = %q\n",
  714. CacheAddrInfoStr(AddrInfo)
  715. ));
  716. }
  717. DEBUG_LEAVE(found);
  718. return found;
  719. }
  720. PRIVATE
  721. LPRESOLVER_CACHE_ENTRY
  722. CreateCacheEntry(
  723. IN LPSTR lpszHostName,
  724. IN LPADDRINFO AddrInfo,
  725. IN DWORD TimeToLive
  726. )
  727. /*++
  728. Routine Description:
  729. Allocates a RESOLVER_CACHE_ENTRY and packs it with the addrinfo information
  730. and sets the ExpirationTime
  731. Arguments:
  732. lpszHostName - name we resolved
  733. AddrInfo - pointer to addrinfo chain to store in new entry
  734. TimeToLive - amount of time before this entry expires
  735. Return Value:
  736. LPRESOLVER_CACHE_ENTRY
  737. --*/
  738. {
  739. LPRESOLVER_CACHE_ENTRY cacheEntry;
  740. INET_ASSERT(lpszHostName != NULL);
  741. //
  742. // only copy lpszHostName if it is different from the name in addrinfo
  743. //
  744. UINT hostNameSize;
  745. if ((AddrInfo->ai_canonname != NULL)
  746. && lstrcmpi(AddrInfo->ai_canonname, lpszHostName) != 0)
  747. {
  748. hostNameSize = lstrlen(lpszHostName) + 1;
  749. }
  750. else if (AddrInfo->ai_canonname == NULL)
  751. {
  752. // if ap_canonname is null, we have to save the lpszHoatName
  753. hostNameSize = lstrlen(lpszHostName) + 1;
  754. }
  755. else
  756. {
  757. hostNameSize = 0;
  758. }
  759. //
  760. // allocate space for the cache entry
  761. //
  762. cacheEntry = (LPRESOLVER_CACHE_ENTRY)ALLOCATE_MEMORY(LMEM_FIXED,
  763. sizeof(RESOLVER_CACHE_ENTRY)
  764. + hostNameSize
  765. );
  766. if (cacheEntry != NULL) {
  767. //
  768. // cache the getaddrinfo result
  769. //
  770. cacheEntry->AddrInfo = AddrInfo;
  771. //
  772. // copy the host name to the end of the buffer if required
  773. //
  774. if (hostNameSize != 0) {
  775. cacheEntry->HostName = (LPSTR)(cacheEntry + 1);
  776. RtlCopyMemory(cacheEntry->HostName, lpszHostName, hostNameSize);
  777. } else {
  778. cacheEntry->HostName = NULL;
  779. }
  780. //
  781. // calculate the expiration time as the current time (in seconds since
  782. // 1/1/70) + number of seconds to live OR indefinite if TimeToLive is
  783. // specified as LIVE_FOREVER, which is what we use if the host
  784. // information didn't originate from DNS
  785. //
  786. cacheEntry->ExpirationTime = (DWORD)((TimeToLive == LIVE_FOREVER)
  787. ? LIVE_FOREVER
  788. : time(NULL)
  789. + ((TimeToLive == LIVE_DEFAULT)
  790. ? DnsCacheTimeout
  791. : TimeToLive) );
  792. //
  793. // the entry state is initially unused
  794. //
  795. cacheEntry->State = ENTRY_UNUSED;
  796. //
  797. // and reference is zero
  798. //
  799. cacheEntry->ReferenceCount = 0;
  800. }
  801. return cacheEntry;
  802. }
  803. #if INET_DEBUG
  804. //
  805. // CAVEAT - can only call these functions once per printf() etc. because of
  806. // static buffers (but still thread-safe)
  807. //
  808. PRIVATE
  809. DEBUG_FUNCTION
  810. LPSTR
  811. CacheTimestr(IN DWORD Time) {
  812. //
  813. // previous code - writes formatted human-sensible date/time to buffer
  814. //
  815. //LPSTR p;
  816. //
  817. ////
  818. //// remove the LF from the time string returned by ctime()
  819. ////
  820. //
  821. //p = ctime((const time_t *)&Time);
  822. //p[strlen(p) - 1] = '\0';
  823. //return p;
  824. //
  825. // abbreviated CRT version - just write # seconds since 1970 to buffer
  826. //
  827. static char buf[16];
  828. wsprintf(buf, "%d", Time);
  829. return (LPSTR)buf;
  830. }
  831. PRIVATE
  832. DEBUG_FUNCTION
  833. LPSTR
  834. CacheAddrInfoStr(IN LPADDRINFO AddrInfo) {
  835. static char buf[2048];
  836. LPSTR p;
  837. int Count;
  838. p = buf;
  839. for (Count = 1; AddrInfo != NULL; AddrInfo = AddrInfo->ai_next) {
  840. p += wsprintf(p, "AddrInfo #%u:\n", Count++);
  841. p += wsprintf(p, "ai_flags = %u\n", AddrInfo->ai_flags);
  842. p += wsprintf(p, "ai_family = %u\n", AddrInfo->ai_family);
  843. p += wsprintf(p, "ai_socktype = %u\n", AddrInfo->ai_socktype);
  844. p += wsprintf(p, "ai_protocol = %u\n", AddrInfo->ai_protocol);
  845. p += wsprintf(p, "ai_addrlen = %u\n", AddrInfo->ai_addrlen);
  846. p += wsprintf(p, "ai_canonname = %s\n", AddrInfo->ai_canonname ? AddrInfo->ai_canonname : "NULL");
  847. p += wsprintf(p, "ai_addr:\n%s\n", CacheMapSockAddress(AddrInfo->ai_addr));
  848. }
  849. return (LPSTR)buf;
  850. }
  851. PRIVATE
  852. DEBUG_FUNCTION
  853. LPSTR
  854. CacheMapSockAddress(IN LPSOCKADDR Address) {
  855. if (!Address) {
  856. return "<null>";
  857. }
  858. static char buf[1024];
  859. LPSTR p;
  860. p = buf;
  861. if (Address->sa_family == AF_INET) {
  862. struct sockaddr_in *sin;
  863. sin = (struct sockaddr_in *)Address;
  864. p += wsprintf(p, "sin_family = %u\n", sin->sin_family);
  865. p += wsprintf(p, "sin_port = %u\n", _I_ntohs(sin->sin_port));
  866. p += wsprintf(p, "sin_addr = %s\n", _I_inet_ntoa(sin->sin_addr));
  867. } else if (Address->sa_family == AF_INET6) {
  868. struct sockaddr_in6 *sin6;
  869. sin6 = (struct sockaddr_in6 *)Address;
  870. p += wsprintf(p, "sin6_family = %u\n", sin6->sin6_family);
  871. p += wsprintf(p, "sin6_port = %u\n", _I_ntohs(sin6->sin6_port));
  872. p += wsprintf(p, "sin6_flowinfo = %u\n", sin6->sin6_flowinfo);
  873. p += wsprintf(p, "sin6_scope_id = %u\n", sin6->sin6_scope_id);
  874. p += wsprintf(p, "sin6_addr = %2x%2x:%2x%2x:%2x%2x:%2x%2x:%2x%2x:%2x%2x:%2x%2x:%2x%2x\n",
  875. sin6->sin6_addr.u.Byte[0],
  876. sin6->sin6_addr.u.Byte[1],
  877. sin6->sin6_addr.u.Byte[2],
  878. sin6->sin6_addr.u.Byte[3],
  879. sin6->sin6_addr.u.Byte[4],
  880. sin6->sin6_addr.u.Byte[5],
  881. sin6->sin6_addr.u.Byte[6],
  882. sin6->sin6_addr.u.Byte[7],
  883. sin6->sin6_addr.u.Byte[8],
  884. sin6->sin6_addr.u.Byte[9],
  885. sin6->sin6_addr.u.Byte[10],
  886. sin6->sin6_addr.u.Byte[11],
  887. sin6->sin6_addr.u.Byte[12],
  888. sin6->sin6_addr.u.Byte[13],
  889. sin6->sin6_addr.u.Byte[14],
  890. sin6->sin6_addr.u.Byte[15]);
  891. } else {
  892. p += wsprintf(p, "sa_family = %u\n", Address->sa_family);
  893. }
  894. return (LPSTR)buf;
  895. }
  896. #endif
  897. #if defined(RNR_SUPPORTED)
  898. /*++
  899. Copyright (c) 1996 Microsoft Corporation
  900. Module Name:
  901. rescache.c
  902. Abstract:
  903. Contains name resolution cache
  904. Contents:
  905. Author:
  906. Shishir Pardikar 2-14-96
  907. Environment:
  908. Win32 user mode
  909. Revision History:
  910. 2-14-96 shishirp
  911. Created
  912. --*/
  913. //
  914. //BUGBUG: This include should be removed, duplicate of above
  915. //
  916. #ifndef SPX_SUPPORT
  917. #include <wininetp.h>
  918. #endif
  919. //
  920. // private manifests
  921. //
  922. #define NAMERES_CACHE_USED 0x00000001
  923. #define NAMERES_CACHE_USES_GUID 0x00000002
  924. #define ENTERCRIT_NAMERESCACHE() EnterCriticalSection(&vcritNameresCache)
  925. #define LEAVECRIT_NAMERESCACHE() LeaveCriticalSection(&vcritNameresCache)
  926. #define IS_EMPTY(indx) ((vlpNameresCache[(indx)].dwFlags & NAMERES_CACHE_USED) == 0)
  927. #define USES_GUID(indx) ((vlpNameresCache[(indx)].dwFlags & NAMERES_CACHE_USES_GUID))
  928. // number of cache entries
  929. #define DEFAULT_NAMERES_CACHE_ENTRIES 10
  930. // expiry time for an addresslist
  931. #define DEFAULT_EXPIRY_DELTA (24 * 60 * 60 * (LONGLONG)10000000)
  932. //
  933. // structure definition
  934. //
  935. typedef struct tagNAMERES_CACHE {
  936. DWORD dwFlags; // general flags to be used as needed
  937. DWORD dwNameSpace; // namespace ??
  938. GUID sGuid; // GUID describing service type
  939. LPSTR lpszName; // ptr to name that needs resolution
  940. FILETIME ftLastUsedTime; // last accesstime, mainly for purging
  941. FILETIME ftCreationTime;// When it was created
  942. ADDRESS_INFO_LIST sAddrList; // List of address (defined in ixport.h)
  943. } NAMERES_CACHE, far *LPNAMERES_CACHE;
  944. //
  945. // private variables for name resolution cache
  946. //
  947. // Name cache size allocated in init
  948. LPNAMERES_CACHE vlpNameresCache = NULL;
  949. // Number of elements allowed in the nameres cache
  950. int vcntNameresCacheEntries = DEFAULT_NAMERES_CACHE_ENTRIES;
  951. // time in 100ns after which an address is expired
  952. LONGLONG vftExpiryDelta = DEFAULT_EXPIRY_DELTA;
  953. BOOL vfNameresCacheInited = FALSE;
  954. // serialization
  955. CRITICAL_SECTION vcritNameresCache;
  956. //
  957. // private function prototypes
  958. //
  959. PRIVATE
  960. DWORD
  961. CreateNameresCacheEntry(
  962. int indx,
  963. DWORD dwNameSpace,
  964. LPGUID lpGuid,
  965. LPSTR lpszName,
  966. INT cntAddresses,
  967. LPCSADDR_INFO lpCsaddrInfo
  968. );
  969. PRIVATE
  970. DWORD
  971. DeleteNameresCacheEntry(
  972. int indx
  973. );
  974. PRIVATE
  975. int
  976. FindNameresCacheEntry(
  977. DWORD dwNameSpace,
  978. LPGUID lpGuid,
  979. LPSTR lpszName
  980. );
  981. PRIVATE
  982. int
  983. FindNameresCacheEntryByAddr(
  984. int cntAddr,
  985. LPCSADDR_INFO lpCsaddrInfo
  986. );
  987. PRIVATE
  988. int
  989. PurgeEntries(
  990. BOOL fForce // purge atleast one entry
  991. );
  992. PRIVATE
  993. DWORD
  994. CopyCsaddr(
  995. LPCSADDR_INFO lpSrc,
  996. int cntAddr,
  997. LPCSADDR_INFO *lplpDst
  998. );
  999. //
  1000. // functions
  1001. //
  1002. DWORD
  1003. InitNameresCache(
  1004. VOID
  1005. )
  1006. /*++
  1007. Routine Description:
  1008. Init name resolution cache. This routine a) allocates a table of
  1009. name cache entries b)
  1010. Arguments:
  1011. None.
  1012. Return Value:
  1013. ERROR_SUCCESS if successful.
  1014. --*/
  1015. {
  1016. if (vfNameresCacheInited) {
  1017. return (ERROR_SUCCESS);
  1018. }
  1019. // first try to alloc the memory, if it fails just quit
  1020. vlpNameresCache = (LPNAMERES_CACHE)ALLOCATE_MEMORY(
  1021. LPTR,
  1022. vcntNameresCacheEntries * sizeof(NAMERES_CACHE)
  1023. );
  1024. if (!vlpNameresCache) {
  1025. return (ERROR_NOT_ENOUGH_MEMORY);
  1026. }
  1027. InitializeCriticalSection(&vcritNameresCache);
  1028. ENTERCRIT_NAMERESCACHE();
  1029. vfNameresCacheInited = TRUE;
  1030. LEAVECRIT_NAMERESCACHE();
  1031. return (ERROR_SUCCESS);
  1032. }
  1033. DWORD
  1034. AddNameresCacheEntry(
  1035. DWORD dwNameSpace,
  1036. LPGUID lpGuid,
  1037. LPSTR lpName,
  1038. int cntAddresses,
  1039. LPCSADDR_INFO lpCsaddrInfo
  1040. )
  1041. /*++
  1042. Routine Description:
  1043. Arguments:
  1044. Return Value:
  1045. ERROR_SUCCESS if successful.
  1046. --*/
  1047. {
  1048. int indx;
  1049. DWORD dwError = ERROR_SUCCESS;
  1050. if (!vfNameresCacheInited) {
  1051. return (ERROR_INVALID_PARAMETER);
  1052. }
  1053. ENTERCRIT_NAMERESCACHE();
  1054. indx = FindNameresCacheEntry(dwNameSpace, lpGuid, lpName);
  1055. // if indx is valid, delete the entry, do some purging too
  1056. if (indx != -1) {
  1057. DeleteNameresCacheEntry(indx);
  1058. PurgeEntries(FALSE);
  1059. }
  1060. else {
  1061. // create atleast one hole
  1062. indx = PurgeEntries(TRUE);
  1063. }
  1064. INET_ASSERT((indx >=0 && (indx < vcntNameresCacheEntries)));
  1065. dwError = CreateNameresCacheEntry(indx,
  1066. dwNameSpace,
  1067. lpGuid,
  1068. lpName,
  1069. cntAddresses,
  1070. lpCsaddrInfo);
  1071. LEAVECRIT_NAMERESCACHE();
  1072. return (dwError);
  1073. }
  1074. DWORD
  1075. RemoveNameresCacheEntry(
  1076. DWORD dwNameSpace,
  1077. LPGUID lpGuid,
  1078. LPSTR lpszName
  1079. )
  1080. /*++
  1081. Routine Description:
  1082. Arguments:
  1083. Return Value:
  1084. ERROR_SUCCESS if successful.
  1085. --*/
  1086. {
  1087. int indx;
  1088. DWORD dwError = ERROR_INVALID_PARAMETER;
  1089. if (vfNameresCacheInited) {
  1090. ENTERCRIT_NAMERESCACHE();
  1091. indx = FindNameresCacheEntry(dwNameSpace, lpGuid, lpszName);
  1092. if (indx != -1) {
  1093. DeleteNameresCacheEntry(indx);
  1094. dwError = ERROR_SUCCESS;
  1095. }
  1096. else {
  1097. dwError = ERROR_FILE_NOT_FOUND; //yuk
  1098. }
  1099. LEAVECRIT_NAMERESCACHE();
  1100. }
  1101. return (dwError);
  1102. }
  1103. #ifdef MAYBE
  1104. DWORD
  1105. RemoveNameresCacheEntryByAddr(
  1106. int cntAddresses,
  1107. LPCSADDR_INFO lpCsaddrInfo
  1108. )
  1109. /*++
  1110. Routine Description:
  1111. Arguments:
  1112. Return Value:
  1113. ERROR_SUCCESS if successful.
  1114. --*/
  1115. {
  1116. int indx;
  1117. DWORD dwError = ERROR_INVALID_PARAMETER;
  1118. if (vfNameresCacheInited) {
  1119. ENTERCRIT_NAMERESCACHE();
  1120. indx = FindNameresCacheEntryByAddr(cntAddresses, lpCsaddrInfo);
  1121. if (indx != -1) {
  1122. DeleteNameresCacheEntry(indx);
  1123. dwError = ERROR_SUCCESS;
  1124. }
  1125. else {
  1126. dwError = ERROR_FILE_NOT_FOUND;
  1127. }
  1128. LEAVECRIT_NAMERESCACHE();
  1129. }
  1130. return (dwError);
  1131. }
  1132. #endif //MAYBE
  1133. DWORD
  1134. GetNameresCacheEntry(
  1135. DWORD dwNameSpace,
  1136. LPGUID lpGuid,
  1137. LPSTR lpName,
  1138. INT *lpcntAddresses,
  1139. LPCSADDR_INFO *lplpCsaddrInfo
  1140. )
  1141. /*++
  1142. Routine Description:
  1143. This routine looks up the cache and returns the list of addresses
  1144. corresponding to lpGuid/lpName.
  1145. Arguments:
  1146. Return Value:
  1147. ERROR_SUCCESS if successful.
  1148. --*/
  1149. {
  1150. int indx;
  1151. DWORD dwError = ERROR_FILE_NOT_FOUND; // poor error
  1152. if (!vfNameresCacheInited) {
  1153. return (ERROR_INVALID_PARAMETER);
  1154. }
  1155. ENTERCRIT_NAMERESCACHE();
  1156. // is this entry already cached?
  1157. indx = FindNameresCacheEntry(dwNameSpace, lpGuid, lpName);
  1158. if (indx != -1) {
  1159. // yes, let use give back the info
  1160. *lpcntAddresses = vlpNameresCache[indx].sAddrList.AddressCount;
  1161. if ((dwError = CopyCsaddr(vlpNameresCache[indx].sAddrList.Addresses, *lpcntAddresses, lplpCsaddrInfo))
  1162. != ERROR_SUCCESS) {
  1163. goto bailout;
  1164. }
  1165. // update the last used time, we will use this to
  1166. // age out the entries
  1167. GetCurrentGmtTime(&(vlpNameresCache[indx].ftLastUsedTime));
  1168. dwError = ERROR_SUCCESS;
  1169. }
  1170. bailout:
  1171. LEAVECRIT_NAMERESCACHE();
  1172. return (dwError);
  1173. }
  1174. DWORD
  1175. DeinitNameresCache(
  1176. VOID
  1177. )
  1178. /*++
  1179. Routine Description:
  1180. Arguments:
  1181. Return Value:
  1182. ERROR_SUCCESS if successful.
  1183. --*/
  1184. {
  1185. int i;
  1186. if (vfNameresCacheInited) {
  1187. ENTERCRIT_NAMERESCACHE();
  1188. for (i = 0; i < vcntNameresCacheEntries; ++i) {
  1189. if (!IS_EMPTY(i)) {
  1190. DeleteNameresCacheEntry(i);
  1191. }
  1192. }
  1193. FREE_MEMORY(vlpNameresCache);
  1194. vlpNameresCache = NULL;
  1195. vfNameresCacheInited = FALSE;
  1196. LEAVECRIT_NAMERESCACHE();
  1197. DeleteCriticalSection(&vcritNameresCache);
  1198. }
  1199. return (ERROR_SUCCESS);
  1200. }
  1201. PRIVATE
  1202. DWORD
  1203. CreateNameresCacheEntry(
  1204. int indx,
  1205. DWORD dwNameSpace,
  1206. LPGUID lpGuid,
  1207. LPSTR lpszName,
  1208. int cntAddresses,
  1209. LPCSADDR_INFO lpCsaddrInfo
  1210. )
  1211. /*++
  1212. Routine Description:
  1213. Arguments:
  1214. Return Value:
  1215. ERROR_SUCCESS if successful.
  1216. --*/
  1217. {
  1218. DWORD dwError = ERROR_NOT_ENOUGH_MEMORY;
  1219. INET_ASSERT((indx >=0 && (indx < vcntNameresCacheEntries)));
  1220. INET_ASSERT(IS_EMPTY(indx));
  1221. memset(&vlpNameresCache[indx], 0, sizeof(vlpNameresCache[indx]));
  1222. // we could get a name or a guid
  1223. // do it for name first before doing it for GUID
  1224. // BUGBUG in future we should consider name+GUID+port
  1225. if (lpszName) {
  1226. vlpNameresCache[indx].lpszName = (LPSTR)ALLOCATE_MEMORY(LPTR, lstrlen(lpszName)+1);
  1227. if (!vlpNameresCache[indx].lpszName) {
  1228. goto bailout;
  1229. }
  1230. strcpy(vlpNameresCache[indx].lpszName, lpszName);
  1231. }
  1232. else if (lpGuid) {
  1233. INET_ASSERT(FALSE); // rigth now. In future this should go away
  1234. memcpy(&(vlpNameresCache[indx].sGuid), lpGuid, sizeof(GUID));
  1235. vlpNameresCache[indx].dwFlags |= NAMERES_CACHE_USES_GUID;
  1236. }
  1237. else {
  1238. dwError = ERROR_INVALID_PARAMETER;
  1239. goto bailout;
  1240. }
  1241. INET_ASSERT(cntAddresses > 0);
  1242. if (CopyCsaddr(lpCsaddrInfo, cntAddresses, &(vlpNameresCache[indx].sAddrList.Addresses))
  1243. != ERROR_SUCCESS) {
  1244. goto bailout;
  1245. }
  1246. vlpNameresCache[indx].sAddrList.AddressCount = cntAddresses;
  1247. // mark this as being non-empty
  1248. vlpNameresCache[indx].dwFlags |= NAMERES_CACHE_USED;
  1249. // set the creation and last-used times as now
  1250. GetCurrentGmtTime(&(vlpNameresCache[indx].ftCreationTime));
  1251. vlpNameresCache[indx].ftLastUsedTime = vlpNameresCache[indx].ftCreationTime ;
  1252. dwError = ERROR_SUCCESS;
  1253. bailout:
  1254. if (dwError != ERROR_SUCCESS) {
  1255. if (vlpNameresCache[indx].sAddrList.Addresses) {
  1256. FREE_MEMORY(vlpNameresCache[indx].sAddrList.Addresses);
  1257. vlpNameresCache[indx].sAddrList.Addresses = NULL;
  1258. }
  1259. if (vlpNameresCache[indx].lpszName) {
  1260. FREE_MEMORY(vlpNameresCache[indx].lpszName);
  1261. vlpNameresCache[indx].lpszName = NULL;
  1262. }
  1263. memset(&vlpNameresCache[indx], 0, sizeof(vlpNameresCache[indx]));
  1264. }
  1265. return (dwError);
  1266. }
  1267. PRIVATE
  1268. DWORD
  1269. DeleteNameresCacheEntry(
  1270. int indx
  1271. )
  1272. /*++
  1273. Routine Description:
  1274. Arguments:
  1275. Return Value:
  1276. ERROR_SUCCESS if successful.
  1277. --*/
  1278. {
  1279. INET_ASSERT((indx >=0) && (indx < vcntNameresCacheEntries));
  1280. if (vlpNameresCache[indx].lpszName) {
  1281. FREE_MEMORY(vlpNameresCache[indx].lpszName);
  1282. }
  1283. INET_ASSERT(vlpNameresCache[indx].sAddrList.Addresses);
  1284. FREE_MEMORY(vlpNameresCache[indx].sAddrList.Addresses);
  1285. memset(&vlpNameresCache[indx], 0, sizeof(NAMERES_CACHE));
  1286. return (ERROR_SUCCESS);
  1287. }
  1288. #ifdef MAYBE
  1289. PRIVATE
  1290. int
  1291. FindNameresCacheEntryByAddr(
  1292. int cntAddr,
  1293. LPCSADDR_INFO lpCsaddrInfo
  1294. )
  1295. /*++
  1296. Routine Description:
  1297. Arguments:
  1298. Return Value:
  1299. ERROR_SUCCESS if successful.
  1300. --*/
  1301. {
  1302. int i;
  1303. for (i = 0; i < vcntNameresCacheEntries; ++i) {
  1304. if (!IS_EMPTY(i) && // not empty
  1305. (vlpNameresCache[i].sAddrList.AddressCount == cntAddr) && // count is the same
  1306. (!memcmp(vlpNameresCache[i].sAddrList.Addresses, // list matches
  1307. lpCsaddrInfo,
  1308. cntAddr * sizeof(CSADDR_INFO)))) {
  1309. return (i);
  1310. }
  1311. }
  1312. return (-1);
  1313. }
  1314. #endif //MAYBE
  1315. PRIVATE
  1316. int
  1317. FindNameresCacheEntry(
  1318. DWORD dwNameSpace,
  1319. LPGUID lpGuid,
  1320. LPSTR lpszName
  1321. )
  1322. /*++
  1323. Routine Description:
  1324. Arguments:
  1325. Return Value:
  1326. ERROR_SUCCESS if successful.
  1327. --*/
  1328. {
  1329. int i;
  1330. for (i = 0; i < vcntNameresCacheEntries; ++i) {
  1331. if (!IS_EMPTY(i)) {
  1332. if (vlpNameresCache[i].dwNameSpace == dwNameSpace) {
  1333. if (!USES_GUID(i)) {
  1334. INET_ASSERT(vlpNameresCache[i].lpszName);
  1335. if (lpszName &&
  1336. !lstrcmpi(lpszName, vlpNameresCache[i].lpszName)) {
  1337. return (i);
  1338. }
  1339. }
  1340. else{
  1341. if (lpGuid && !memcmp(lpGuid, &vlpNameresCache[i].sGuid, sizeof(GUID))) {
  1342. return (i);
  1343. }
  1344. }
  1345. }
  1346. }
  1347. }
  1348. return (-1);
  1349. }
  1350. PRIVATE
  1351. int
  1352. PurgeEntries(
  1353. BOOL fForce // purge atleast one entry
  1354. )
  1355. /*++
  1356. Routine Description:
  1357. Arguments:
  1358. Return Value:
  1359. index of a free entry
  1360. --*/
  1361. {
  1362. int i, indxlru = -1, indxHole=-1;
  1363. FILETIME ft;
  1364. BOOL fFoundHole = FALSE;
  1365. GetCurrentGmtTime(&ft);
  1366. for (i = 0; i < vcntNameresCacheEntries; ++i) {
  1367. if (!IS_EMPTY(i)) {
  1368. // purge stale entries
  1369. if ( (FT2LL(ft) - FT2LL(vlpNameresCache[i].ftCreationTime))
  1370. > FT2LL(vftExpiryDelta)) {
  1371. DeleteNameresCacheEntry(i);
  1372. indxHole = i;
  1373. }
  1374. else if (FT2LL(vlpNameresCache[i].ftLastUsedTime) <= FT2LL(ft)) {
  1375. ft = vlpNameresCache[i].ftLastUsedTime;
  1376. indxlru = i; // LRU entry if we need to purge it
  1377. }
  1378. }
  1379. else {
  1380. indxHole = i;
  1381. }
  1382. }
  1383. // if there is no hole, purge the LRU entry if forced
  1384. if (indxHole == -1) {
  1385. INET_ASSERT(indxlru != -1);
  1386. if (fForce) {
  1387. DeleteNameresCacheEntry(indxlru);
  1388. indxHole = indxlru;
  1389. }
  1390. }
  1391. return (indxHole);
  1392. }
  1393. PRIVATE
  1394. DWORD
  1395. CopyCsaddr(
  1396. LPCSADDR_INFO lpSrc,
  1397. int cntAddr,
  1398. LPCSADDR_INFO *lplpDst
  1399. )
  1400. {
  1401. int i;
  1402. LPCSADDR_INFO lpDst;
  1403. UINT uSize;
  1404. // BUGBUG assumes the way Compressaddress (ixport.cxx) allocates memory
  1405. uSize = LocalSize(lpSrc);
  1406. if (!uSize) {
  1407. return (GetLastError());
  1408. }
  1409. *lplpDst = (LPCSADDR_INFO)ALLOCATE_MEMORY(LPTR, uSize);
  1410. if (!*lplpDst) {
  1411. return (ERROR_NOT_ENOUGH_MEMORY);
  1412. }
  1413. lpDst = *lplpDst;
  1414. memcpy(lpDst, lpSrc, uSize);
  1415. // now start doing fixups
  1416. for (i=0; i<cntAddr; ++i) {
  1417. lpDst[i].LocalAddr.lpSockaddr = (LPSOCKADDR)((LPBYTE)lpDst+((DWORD)(lpSrc[i].LocalAddr.lpSockaddr) - (DWORD)lpSrc));
  1418. lpDst[i].RemoteAddr.lpSockaddr = (LPSOCKADDR)((LPBYTE)lpDst+((DWORD)(lpSrc[i].RemoteAddr.lpSockaddr) - (DWORD)lpSrc));
  1419. }
  1420. return (ERROR_SUCCESS);
  1421. }
  1422. #endif // defined(RNR_SUPPORTED)