Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1056 lines
22 KiB

  1. /*++
  2. Copyright (c) 1996-2000 Microsoft Corporation
  3. Module Name:
  4. socket.c
  5. Abstract:
  6. Domain Name System (DNS) API
  7. Socket setup.
  8. Author:
  9. Jim Gilroy (jamesg) October, 1996
  10. Revision History:
  11. --*/
  12. #include "local.h"
  13. //
  14. // Winsock startup
  15. //
  16. LONG WinsockStartCount = 0;
  17. WSADATA WsaData;
  18. //
  19. // Async i/o
  20. //
  21. // If want async socket i/o then can create single async socket, with
  22. // corresponding event and always use it. Requires winsock 2.2
  23. //
  24. SOCKET DnsSocket = 0;
  25. OVERLAPPED DnsSocketOverlapped;
  26. HANDLE hDnsSocketEvent = NULL;
  27. //
  28. // App shutdown flag
  29. //
  30. BOOLEAN fApplicationShutdown = FALSE;
  31. DNS_STATUS
  32. Dns_InitializeWinsock(
  33. VOID
  34. )
  35. /*++
  36. Routine Description:
  37. Initialize winsock for this process.
  38. Currently, assuming process must do WSAStartup() before
  39. calling any Dns_Api entry point.
  40. Arguments:
  41. None
  42. Return Value:
  43. ERROR_SUCCESS if successful.
  44. ErrorCode on failure.
  45. --*/
  46. {
  47. DNSDBG( SOCKET, ( "Dns_InitializeWinsock()\n" ));
  48. //
  49. // start winsock, if not already started
  50. //
  51. if ( WinsockStartCount == 0 )
  52. {
  53. DNS_STATUS status;
  54. DNSDBG( TRACE, (
  55. "Dns_InitializeWinsock() version %x\n",
  56. DNS_WINSOCK_VERSION ));
  57. status = WSAStartup( DNS_WINSOCK_VERSION, &WsaData );
  58. if ( status != ERROR_SUCCESS )
  59. {
  60. DNS_PRINT(( "ERROR: WSAStartup failure %d.\n", status ));
  61. return( status );
  62. }
  63. DNSDBG( TRACE, (
  64. "Winsock initialized => wHighVersion=0x%x, wVersion=0x%x\n",
  65. WsaData.wHighVersion,
  66. WsaData.wVersion ));
  67. InterlockedIncrement( &WinsockStartCount );
  68. }
  69. return( ERROR_SUCCESS );
  70. }
  71. DNS_STATUS
  72. Dns_InitializeWinsockEx(
  73. IN BOOL fForce
  74. )
  75. /*++
  76. Routine Description:
  77. Dummy -- just in case called somewhere
  78. DCR: eliminate Dns_InitializeWinsockEx()
  79. --*/
  80. {
  81. return Dns_InitializeWinsock();
  82. }
  83. VOID
  84. Dns_CleanupWinsock(
  85. VOID
  86. )
  87. /*++
  88. Routine Description:
  89. Cleanup winsock if it was initialized by dnsapi.dll
  90. Arguments:
  91. None.
  92. Return Value:
  93. None.
  94. --*/
  95. {
  96. DNSDBG( SOCKET, ( "Dns_CleanupWinsock()\n" ));
  97. //
  98. // WSACleanup() for value of ref count
  99. // - ref count pushed down to one below real value, but
  100. // fixed up at end
  101. // - note: the GUI_MODE_SETUP_WS_CLEANUP deal means that
  102. // we can be called other than process detach, making
  103. // interlock necessary
  104. //
  105. while ( InterlockedDecrement( &WinsockStartCount ) >= 0 )
  106. {
  107. WSACleanup();
  108. }
  109. InterlockedIncrement( &WinsockStartCount );
  110. }
  111. SOCKET
  112. Dns_CreateSocketEx(
  113. IN INT Family,
  114. IN INT SockType,
  115. IN IP_ADDRESS IpAddress,
  116. IN USHORT Port,
  117. IN DWORD dwFlags
  118. )
  119. /*++
  120. Routine Description:
  121. Create socket.
  122. Arguments:
  123. Family -- socket family AF_INET or AF_INET6
  124. SockType -- SOCK_DGRAM or SOCK_STREAM
  125. IpAddress -- IP address to listen on (net byte order)
  126. DCR: will need to change to IP6_ADDRESS then use MAPPED to extract
  127. Port -- desired port in net order
  128. - NET_ORDER_DNS_PORT for DNS listen sockets
  129. - 0 for any port
  130. dwFlags -- specifiy the attributes of the sockets
  131. Return Value:
  132. Socket if successful.
  133. Otherwise INVALID_SOCKET.
  134. --*/
  135. {
  136. SOCKET s;
  137. INT err;
  138. INT val;
  139. DNS_STATUS status;
  140. BOOL fretry = FALSE;
  141. //
  142. // create socket
  143. // - try again if winsock not initialized
  144. while( 1 )
  145. {
  146. s = WSASocket(
  147. Family,
  148. SockType,
  149. 0,
  150. NULL,
  151. 0,
  152. dwFlags );
  153. if ( s != INVALID_SOCKET )
  154. {
  155. break;
  156. }
  157. status = GetLastError();
  158. DNSDBG( SOCKET, (
  159. "ERROR: Failed to open socket of type %d.\n"
  160. "\terror = %d.\n",
  161. SockType,
  162. status ));
  163. if ( status != WSANOTINITIALISED || fretry )
  164. {
  165. SetLastError( DNS_ERROR_NO_TCPIP );
  166. return INVALID_SOCKET;
  167. }
  168. //
  169. // initialize Winsock if not already started
  170. //
  171. // note: do NOT automatically initialize winsock
  172. // init jacks ref count and will break applications
  173. // which use WSACleanup to close outstanding sockets;
  174. // we'll init only when the choice is that or no service;
  175. // apps can still cleanup with WSACleanup() called
  176. // in loop until WSANOTINITIALISED failure
  177. //
  178. fretry = TRUE;
  179. status = Dns_InitializeWinsock();
  180. if ( status != NO_ERROR )
  181. {
  182. SetLastError( DNS_ERROR_NO_TCPIP );
  183. return INVALID_SOCKET;
  184. }
  185. }
  186. //
  187. // bind socket
  188. // - only if specific port given, this keeps remote winsock
  189. // from grabbing it if we are on the local net
  190. //
  191. if ( IpAddress || Port )
  192. {
  193. SOCKADDR_IN6 sockaddr;
  194. INT sockaddrLength;
  195. if ( Family == AF_INET )
  196. {
  197. PSOCKADDR_IN psin = (PSOCKADDR_IN) &sockaddr;
  198. sockaddrLength = sizeof(*psin);
  199. RtlZeroMemory( psin, sockaddrLength );
  200. psin->sin_family = AF_INET;
  201. psin->sin_port = Port;
  202. psin->sin_addr.s_addr = IpAddress;
  203. }
  204. else
  205. {
  206. PSOCKADDR_IN6 psin = (PSOCKADDR_IN6) &sockaddr;
  207. DNS_ASSERT( Family == AF_INET6 );
  208. sockaddrLength = sizeof(*psin);
  209. RtlZeroMemory( psin, sockaddrLength );
  210. psin->sin6_family = AF_INET6;
  211. psin->sin6_port = Port;
  212. //psin->sin6_addr = IpAddress;
  213. }
  214. if ( Port > 0 )
  215. {
  216. // allow us to bind to a port that someone else is already listening on
  217. val = 1;
  218. setsockopt(
  219. s,
  220. SOL_SOCKET,
  221. SO_REUSEADDR,
  222. (const char *)&val,
  223. sizeof(val) );
  224. }
  225. err = bind(
  226. s,
  227. (PSOCKADDR) &sockaddr,
  228. sockaddrLength );
  229. if ( err == SOCKET_ERROR )
  230. {
  231. DNSDBG( SOCKET, (
  232. "Failed to bind() socket %d, to port %d, address %s.\n"
  233. "\terror = %d.\n",
  234. s,
  235. ntohs(Port),
  236. IP_STRING( IpAddress ),
  237. GetLastError() ));
  238. closesocket( s );
  239. SetLastError( DNS_ERROR_NO_TCPIP );
  240. return INVALID_SOCKET;
  241. }
  242. }
  243. DNSDBG( SOCKET, (
  244. "Created socket %d, of type %d, for address %s, port %d.\n",
  245. s,
  246. SockType,
  247. inet_ntoa( *(struct in_addr *) &IpAddress ),
  248. ntohs(Port) ));
  249. return s;
  250. }
  251. SOCKET
  252. Dns_CreateSocket(
  253. IN INT SockType,
  254. IN IP_ADDRESS IpAddress,
  255. IN USHORT Port
  256. )
  257. /*++
  258. Routine Description:
  259. Wrapper function for CreateSocketAux. Passes in 0 for dwFlags (as opposed
  260. to Dns_CreateMulticastSocket, which passes in flags to specify that
  261. the socket is to be used for multicasting).
  262. Arguments:
  263. SockType -- SOCK_DGRAM or SOCK_STREAM
  264. IpAddress -- IP address to listen on (net byte order)
  265. Port -- desired port in net order
  266. - NET_ORDER_DNS_PORT for DNS listen sockets
  267. - 0 for any port
  268. Return Value:
  269. socket if successful.
  270. Otherwise INVALID_SOCKET.
  271. --*/
  272. {
  273. return Dns_CreateSocketEx(
  274. AF_INET,
  275. SockType,
  276. IpAddress,
  277. Port,
  278. 0 // no flags
  279. );
  280. }
  281. SOCKET
  282. Dns_CreateMulticastSocket(
  283. IN INT SockType,
  284. IN IP_ADDRESS IpAddress,
  285. IN USHORT Port,
  286. IN BOOL fSend,
  287. IN BOOL fReceive
  288. )
  289. /*++
  290. Routine Description:
  291. Create socket and join it to the multicast DNS address.
  292. Arguments:
  293. SockType -- SOCK_DGRAM or SOCK_STREAM
  294. IpAddress -- IP address to listen on (net byte order)
  295. Port -- desired port in net order
  296. - NET_ORDER_DNS_PORT for DNS listen sockets
  297. - 0 for any port
  298. Return Value:
  299. socket if successful.
  300. Otherwise INVALID_SOCKET.
  301. --*/
  302. {
  303. SOCKADDR_IN multicastAddress;
  304. DWORD byteCount;
  305. BOOL bflag;
  306. SOCKET s;
  307. INT err;
  308. s = Dns_CreateSocketEx(
  309. AF_INET,
  310. SockType,
  311. IpAddress,
  312. Port,
  313. WSA_FLAG_MULTIPOINT_C_LEAF |
  314. WSA_FLAG_MULTIPOINT_D_LEAF |
  315. WSA_FLAG_OVERLAPPED );
  316. if ( s != INVALID_SOCKET )
  317. {
  318. multicastAddress.sin_family = PF_INET;
  319. multicastAddress.sin_addr.s_addr = MULTICAST_DNS_RADDR;
  320. multicastAddress.sin_port = Port;
  321. // set loopback
  322. bflag = TRUE;
  323. err = WSAIoctl(
  324. s,
  325. SIO_MULTIPOINT_LOOPBACK, // loopback iotcl
  326. & bflag, // turn on
  327. sizeof(bflag),
  328. NULL, // no output
  329. 0, // no output size
  330. &byteCount, // bytes returned
  331. NULL, // no overlapped
  332. NULL // no completion routine
  333. );
  334. if ( err == SOCKET_ERROR )
  335. {
  336. DNSDBG( SOCKET, (
  337. "Unable to turn multicast loopback on for socket %d; error = %d.\n",
  338. s,
  339. GetLastError()
  340. ));
  341. }
  342. //
  343. // join socket to multicast group
  344. //
  345. s = WSAJoinLeaf(
  346. s,
  347. (PSOCKADDR)&multicastAddress,
  348. sizeof (multicastAddress),
  349. NULL, // caller data buffer
  350. NULL, // callee data buffer
  351. NULL, // socket QOS setting
  352. NULL, // socket group QOS
  353. ((fSend && fReceive) ? JL_BOTH : // send and/or receive
  354. (fSend ? JL_SENDER_ONLY : JL_RECEIVER_ONLY))
  355. );
  356. if ( s == INVALID_SOCKET )
  357. {
  358. DNSDBG( SOCKET, (
  359. "Unable to join socket %d to multicast address, error = %d.\n",
  360. s,
  361. GetLastError() ));
  362. }
  363. }
  364. return s;
  365. }
  366. VOID
  367. Dns_CloseSocket(
  368. IN SOCKET Socket
  369. )
  370. /*++
  371. Routine Description:
  372. Close DNS socket.
  373. Arguments:
  374. Socket -- socket to close
  375. Return Value:
  376. None.
  377. --*/
  378. {
  379. if ( Socket == 0 || Socket == INVALID_SOCKET )
  380. {
  381. DNS_PRINT(( "WARNING: Dns_CloseSocket() called on invalid socket %d.\n", Socket ));
  382. return;
  383. }
  384. DNSDBG( SOCKET, ( "closesocket( %d )\n", Socket ));
  385. closesocket( Socket );
  386. }
  387. VOID
  388. Dns_CloseConnection(
  389. IN SOCKET Socket
  390. )
  391. /*++
  392. Routine Description:
  393. Close connection on socket.
  394. Arguments:
  395. Socket -- socket to close
  396. Return Value:
  397. None.
  398. --*/
  399. {
  400. if ( Socket == 0 || Socket == INVALID_SOCKET )
  401. {
  402. DNS_PRINT((
  403. "WARNING: Dns_CloseTcpConnection() called on invalid socket.\n" ));
  404. //DNS_ASSERT( FALSE );
  405. return;
  406. }
  407. // shutdown connection, then close
  408. DNSDBG( SOCKET, ( "shutdown and closesocket( %d )\n", Socket ));
  409. shutdown( Socket, 2 );
  410. closesocket( Socket );
  411. }
  412. #if 0
  413. //
  414. // Global async socket routines
  415. //
  416. DNS_STATUS
  417. Dns_SetupGlobalAsyncSocket(
  418. VOID
  419. )
  420. /*++
  421. Routine Description:
  422. Create global async UDP socket.
  423. Arguments:
  424. SockType -- SOCK_DGRAM or SOCK_STREAM
  425. IpAddress -- IP address to listen on (net byte order)
  426. Port -- desired port in net order
  427. - NET_ORDER_DNS_PORT for DNS listen sockets
  428. - 0 for any port
  429. Return Value:
  430. socket if successful.
  431. Otherwise INVALID_SOCKET.
  432. --*/
  433. {
  434. DNS_STATUS status;
  435. INT err;
  436. SOCKADDR_IN sockaddrIn;
  437. //
  438. // start winsock, need winsock 2 for async
  439. //
  440. if ( ! fWinsockStarted )
  441. {
  442. status = WSAStartup( DNS_WINSOCK_VERSION, &WsaData );
  443. if ( status != ERROR_SUCCESS )
  444. {
  445. DNS_PRINT(( "ERROR: WSAStartup failure %d.\n", status ));
  446. return( status );
  447. }
  448. if ( WsaData.wVersion != DNS_WINSOCK2_VERSION )
  449. {
  450. WSACleanup();
  451. return( WSAVERNOTSUPPORTED );
  452. }
  453. fWinsockStarted = TRUE;
  454. }
  455. //
  456. // setup socket
  457. // - overlapped i\o with event so can run asynchronously in
  458. // this thread and wait with queuing event
  459. //
  460. DnsSocket = WSASocket(
  461. AF_INET,
  462. SOCK_DGRAM,
  463. 0,
  464. NULL,
  465. 0,
  466. WSA_FLAG_OVERLAPPED );
  467. if ( DnsSocket == INVALID_SOCKET )
  468. {
  469. status = GetLastError();
  470. DNS_PRINT(( "\nERROR: Async socket create failed.\n" ));
  471. goto Error;
  472. }
  473. //
  474. // bind socket
  475. //
  476. RtlZeroMemory( &sockaddrIn, sizeof(sockaddrIn) );
  477. sockaddrIn.sin_family = AF_INET;
  478. sockaddrIn.sin_port = 0;
  479. sockaddrIn.sin_addr.s_addr = INADDR_ANY;
  480. err = bind( DnsSocket, (PSOCKADDR)&sockaddrIn, sizeof(sockaddrIn) );
  481. if ( err == SOCKET_ERROR )
  482. {
  483. status = GetLastError();
  484. DNSDBG( SOCKET, (
  485. "Failed to bind() DnsSocket %d.\n"
  486. "\terror = %d.\n",
  487. DnsSocket,
  488. status ));
  489. goto Error;
  490. }
  491. //
  492. // create event to signal on async i/o completion
  493. //
  494. hDnsSocketEvent = CreateEvent(
  495. NULL, // Security Attributes
  496. TRUE, // create Manual-Reset event
  497. FALSE, // start unsignalled -- paused
  498. NULL // event name
  499. );
  500. if ( !hDnsSocketEvent )
  501. {
  502. status = GetLastError();
  503. DNS_PRINT(( "Failed event creation\n" ));
  504. goto Error;
  505. }
  506. DnsSocketOverlapped.hEvent = hDnsSocketEvent;
  507. DNSDBG( SOCKET, (
  508. "Created global async UDP socket %d.\n"
  509. "\toverlapped at %p\n"
  510. "\tevent handle %p\n",
  511. DnsSocket,
  512. DnsSocketOverlapped,
  513. hDnsSocketEvent ));
  514. return ERROR_SUCCESS;
  515. Error:
  516. DNS_PRINT((
  517. "ERROR: Failed async socket creation, status = %d\n",
  518. status ));
  519. closesocket( DnsSocket );
  520. DnsSocket = INVALID_SOCKET;
  521. WSACleanup();
  522. return( status );
  523. }
  524. #endif
  525. //
  526. // Socket caching
  527. //
  528. // Doing limited caching of UDP unbound sockets used for standard
  529. // DNS lookups in resolver. This allows us to prevent denial of
  530. // service attack by using up all ports on the machine.
  531. // Resolver is the main customer for this, but we'll code it to
  532. // be useable by any process.
  533. //
  534. // Implementation notes:
  535. //
  536. // There are a couple specific goals to this implementation:
  537. // - Minimal code impact; Try NOT to change the resolver
  538. // code.
  539. // - Usage driven caching; Don't want to create on startup
  540. // "cache sockets" that we don't use; Instead have actual usage
  541. // drive up the cached socket count.
  542. //
  543. // There are several approaches here.
  544. //
  545. // 1) explicit resolver cache -- passed down sockets
  546. //
  547. // 2) add caching seamlessly into socket open and close
  548. // this was my first choice, but the problem here is that on
  549. // close we must either do additional calls to winsock to determine
  550. // whether cachable (UDP-unbound) socket OR cache must include some
  551. // sort of "in-use" tag and we trust that socket is never closed
  552. // outside of path (otherwise handle reuse could mess us up)
  553. //
  554. // 3) new UDP-unbound open\close function
  555. // this essentially puts the "i-know-i'm-using-UDP-unbound-sockets"
  556. // burden on the caller who must switch to this new API;
  557. // fortunately this meshes well with our "SendAndRecvUdp()" function;
  558. // this approach still allows a caller driven ramp up we desire,
  559. // so i'm using this approach
  560. //
  561. //
  562. // Keep array of sockets
  563. //
  564. // Dev note: the Array and MaxCount MUST be kept in sync, no
  565. // independent check of array is done, it is assumed to exist when
  566. // MaxCount is non-zero, so they MUST be in sync when lock released
  567. //
  568. SOCKET * g_pCacheSocketArray = NULL;
  569. DWORD g_CacheSocketMaxCount = 0;
  570. DWORD g_CacheSocketCount = 0;
  571. // Hard limit on what we'll allow folks to keep awake
  572. #define MAX_SOCKET_CACHE_LIMIT (100)
  573. // Lock access with generic lock
  574. // This is very short\fast CS, contention will be minimal
  575. #define LOCK_SOCKET_CACHE() LOCK_GENERAL()
  576. #define UNLOCK_SOCKET_CACHE() UNLOCK_GENERAL()
  577. DNS_STATUS
  578. Dns_CacheSocketInit(
  579. IN DWORD MaxSocketCount
  580. )
  581. /*++
  582. Routine Description:
  583. Initialize socket caching.
  584. Arguments:
  585. MaxSocketCount -- max count of sockets to cache
  586. Return Value:
  587. ERROR_SUCCESS if successful.
  588. DNS_ERROR_NO_MEMORY on alloc failure.
  589. ERROR_INVALID_PARAMETER if already initialized or bogus count.
  590. --*/
  591. {
  592. SOCKET * parray;
  593. DNS_STATUS status = NO_ERROR;
  594. DNSDBG( SOCKET, ( "Dns_CacheSocketInit()\n" ));
  595. //
  596. // validity check
  597. // - note, one byte of the apple, we don't let you raise
  598. // count, though we later could; i see this as at most a
  599. // "configure for machine use" kind of deal
  600. //
  601. LOCK_SOCKET_CACHE();
  602. if ( MaxSocketCount == 0 || g_CacheSocketMaxCount != 0 )
  603. {
  604. status = ERROR_INVALID_PARAMETER;
  605. goto Done;
  606. }
  607. //
  608. // allocate
  609. //
  610. if ( MaxSocketCount > MAX_SOCKET_CACHE_LIMIT )
  611. {
  612. MaxSocketCount = MAX_SOCKET_CACHE_LIMIT;
  613. }
  614. parray = (SOCKET *) ALLOCATE_HEAP_ZERO( sizeof(SOCKET) * MaxSocketCount );
  615. if ( !parray )
  616. {
  617. status = DNS_ERROR_NO_MEMORY;
  618. goto Done;
  619. }
  620. // set globals
  621. g_pCacheSocketArray = parray;
  622. g_CacheSocketMaxCount = MaxSocketCount;
  623. g_CacheSocketCount = 0;
  624. Done:
  625. UNLOCK_SOCKET_CACHE();
  626. return status;
  627. }
  628. VOID
  629. Dns_CacheSocketCleanup(
  630. VOID
  631. )
  632. /*++
  633. Routine Description:
  634. Cleanup socket caching.
  635. Arguments:
  636. None
  637. Return Value:
  638. None
  639. --*/
  640. {
  641. DWORD i;
  642. SOCKET sock;
  643. DNSDBG( SOCKET, ( "Dns_CacheSocketCleanup()\n" ));
  644. //
  645. // close cached sockets
  646. //
  647. LOCK_SOCKET_CACHE();
  648. for ( i=0; i<g_CacheSocketMaxCount; i++ )
  649. {
  650. sock = g_pCacheSocketArray[i];
  651. if ( sock )
  652. {
  653. Dns_CloseSocket( sock );
  654. g_CacheSocketCount--;
  655. }
  656. }
  657. DNS_ASSERT( g_CacheSocketCount == 0 );
  658. // dump socket array memory
  659. FREE_HEAP( g_pCacheSocketArray );
  660. // clear globals
  661. g_pCacheSocketArray = NULL;
  662. g_CacheSocketMaxCount = 0;
  663. g_CacheSocketCount = 0;
  664. UNLOCK_SOCKET_CACHE();
  665. }
  666. SOCKET
  667. Dns_GetUdpSocket(
  668. VOID
  669. )
  670. /*++
  671. Routine Description:
  672. Get a cached socket.
  673. Arguments:
  674. None
  675. Return Value:
  676. Socket handle if successful.
  677. Zero if no cached socket available.
  678. --*/
  679. {
  680. SOCKET sock;
  681. DWORD i;
  682. //
  683. // quick return if nothing available
  684. // - do outside lock so function can be called cheaply
  685. // without other checks
  686. //
  687. if ( g_CacheSocketCount == 0 )
  688. {
  689. goto Open;
  690. }
  691. //
  692. // get a cached socket
  693. //
  694. LOCK_SOCKET_CACHE();
  695. for ( i=0; i<g_CacheSocketMaxCount; i++ )
  696. {
  697. sock = g_pCacheSocketArray[i];
  698. if ( sock != 0 )
  699. {
  700. g_pCacheSocketArray[i] = 0;
  701. g_CacheSocketCount--;
  702. UNLOCK_SOCKET_CACHE();
  703. //
  704. // DCR: clean out any data on cached socket
  705. // it would be cool to cheaply dump useless data
  706. //
  707. // right now we just let XID match, then question match
  708. // dump data on recv
  709. //
  710. DNSDBG( SOCKET, (
  711. "Returning cached socket %d.\n",
  712. sock ));
  713. return sock;
  714. }
  715. }
  716. UNLOCK_SOCKET_CACHE();
  717. Open:
  718. sock = Dns_CreateSocket(
  719. SOCK_DGRAM,
  720. INADDR_ANY,
  721. 0 );
  722. return sock;
  723. }
  724. VOID
  725. Dns_ReturnUdpSocket(
  726. IN SOCKET Socket
  727. )
  728. /*++
  729. Routine Description:
  730. Return UDP socket for possible caching.
  731. Arguments:
  732. Socket -- socket handle
  733. Return Value:
  734. None
  735. --*/
  736. {
  737. SOCKET sock;
  738. DWORD i;
  739. //
  740. // quick return if not caching
  741. // - do outside lock so function can be called cheaply
  742. // without other checks
  743. //
  744. if ( g_CacheSocketMaxCount == 0 ||
  745. g_CacheSocketMaxCount == g_CacheSocketCount )
  746. {
  747. goto Close;
  748. }
  749. //
  750. // return cached socket
  751. //
  752. LOCK_SOCKET_CACHE();
  753. for ( i=0; i<g_CacheSocketMaxCount; i++ )
  754. {
  755. if ( g_pCacheSocketArray[i] )
  756. {
  757. continue;
  758. }
  759. g_pCacheSocketArray[i] = Socket;
  760. g_CacheSocketCount++;
  761. UNLOCK_SOCKET_CACHE();
  762. DNSDBG( SOCKET, (
  763. "Returned socket %d to cache.\n",
  764. Socket ));
  765. return;
  766. }
  767. UNLOCK_SOCKET_CACHE();
  768. DNSDBG( SOCKET, (
  769. "Socket cache full, closing socket %d.\n"
  770. "WARNING: should only see this message on race!\n",
  771. Socket ));
  772. Close:
  773. Dns_CloseSocket( Socket );
  774. }
  775. //
  776. // End socket.c
  777. //