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.

2223 lines
49 KiB

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