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.

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