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.

1260 lines
26 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 g_WinsockStartCount = 0;
  17. //
  18. // Async i/o
  19. //
  20. // If want async socket i/o then can create single async socket, with
  21. // corresponding event and always use it. Requires winsock 2.2
  22. //
  23. SOCKET DnsSocket = 0;
  24. OVERLAPPED DnsSocketOverlapped;
  25. HANDLE hDnsSocketEvent = NULL;
  26. //
  27. // App shutdown flag
  28. //
  29. BOOLEAN fApplicationShutdown = FALSE;
  30. DNS_STATUS
  31. Socket_InitWinsock(
  32. VOID
  33. )
  34. /*++
  35. Routine Description:
  36. Initialize winsock for this process.
  37. Currently, assuming process must do WSAStartup() before
  38. calling any dnsapi.dll entry point.
  39. EXPORTED (resolver)
  40. Arguments:
  41. None
  42. Return Value:
  43. ERROR_SUCCESS if successful.
  44. ErrorCode on failure.
  45. --*/
  46. {
  47. DNSDBG( SOCKET, ( "Socket_InitWinsock()\n" ));
  48. //
  49. // start winsock, if not already started
  50. //
  51. if ( g_WinsockStartCount == 0 )
  52. {
  53. DNS_STATUS status;
  54. WSADATA wsaData;
  55. DNSDBG( TRACE, (
  56. "InitWinsock() version %x\n",
  57. DNS_WINSOCK_VERSION ));
  58. status = WSAStartup( DNS_WINSOCK_VERSION, &wsaData );
  59. if ( status != ERROR_SUCCESS )
  60. {
  61. DNS_PRINT(( "ERROR: WSAStartup failure %d.\n", status ));
  62. return( status );
  63. }
  64. DNSDBG( TRACE, (
  65. "Winsock initialized => wHighVersion=0x%x, wVersion=0x%x\n",
  66. wsaData.wHighVersion,
  67. wsaData.wVersion ));
  68. InterlockedIncrement( &g_WinsockStartCount );
  69. }
  70. return( ERROR_SUCCESS );
  71. }
  72. VOID
  73. Socket_CleanupWinsock(
  74. VOID
  75. )
  76. /*++
  77. Routine Description:
  78. Cleanup winsock if it was initialized by dnsapi.dll
  79. EXPORTED (resolver)
  80. Arguments:
  81. None.
  82. Return Value:
  83. None.
  84. --*/
  85. {
  86. DNSDBG( SOCKET, ( "Socket_CleanupWinsock()\n" ));
  87. //
  88. // WSACleanup() for value of ref count
  89. // - ref count pushed down to one below real value, but
  90. // fixed up at end
  91. // - note: the GUI_MODE_SETUP_WS_CLEANUP deal means that
  92. // we can be called other than process detach, making
  93. // interlock necessary
  94. //
  95. while ( InterlockedDecrement( &g_WinsockStartCount ) >= 0 )
  96. {
  97. WSACleanup();
  98. }
  99. InterlockedIncrement( &g_WinsockStartCount );
  100. }
  101. SOCKET
  102. Socket_Create(
  103. IN INT Family,
  104. IN INT SockType,
  105. IN PDNS_ADDR pBindAddr, OPTIONAL
  106. IN USHORT Port,
  107. IN DWORD dwFlags
  108. )
  109. /*++
  110. Routine Description:
  111. Create socket.
  112. EXPORTED function (resolver)
  113. Arguments:
  114. Family -- socket family AF_INET or AF_INET6
  115. SockType -- SOCK_DGRAM or SOCK_STREAM
  116. pBindAddr -- addr to bind to
  117. Port -- desired port in net order
  118. - NET_ORDER_DNS_PORT for DNS listen sockets
  119. - 0 for any port
  120. dwFlags -- specify the attributes of the sockets
  121. Return Value:
  122. Socket if successful.
  123. Otherwise zero.
  124. --*/
  125. {
  126. SOCKET s;
  127. INT err;
  128. INT val;
  129. DNS_STATUS status;
  130. BOOL fretry = FALSE;
  131. DNSDBG( SOCKET, (
  132. "Socket_Create( fam=%d, type=%d, addr=%p, port=%d, flag=%08x )\n",
  133. Family,
  134. SockType,
  135. pBindAddr,
  136. Port,
  137. dwFlags ));
  138. //
  139. // create socket
  140. // - try again if winsock not initialized
  141. while( 1 )
  142. {
  143. s = WSASocket(
  144. Family,
  145. SockType,
  146. 0,
  147. NULL,
  148. 0,
  149. dwFlags );
  150. if ( s != INVALID_SOCKET )
  151. {
  152. break;
  153. }
  154. status = GetLastError();
  155. DNSDBG( SOCKET, (
  156. "ERROR: Failed to open socket of type %d.\n"
  157. "\terror = %d.\n",
  158. SockType,
  159. status ));
  160. if ( status != WSANOTINITIALISED || fretry )
  161. {
  162. SetLastError( DNS_ERROR_NO_TCPIP );
  163. return 0;
  164. }
  165. //
  166. // initialize Winsock if not already started
  167. //
  168. // note: do NOT automatically initialize winsock
  169. // init jacks ref count and will break applications
  170. // which use WSACleanup to close outstanding sockets;
  171. // we'll init only when the choice is that or no service;
  172. // apps can still cleanup with WSACleanup() called
  173. // in loop until WSANOTINITIALISED failure
  174. //
  175. fretry = TRUE;
  176. status = Socket_InitWinsock();
  177. if ( status != NO_ERROR )
  178. {
  179. SetLastError( DNS_ERROR_NO_TCPIP );
  180. return 0;
  181. }
  182. }
  183. //
  184. // bind socket
  185. // - only if specific port given, this keeps remote winsock
  186. // from grabbing it if we are on the local net
  187. //
  188. if ( pBindAddr || Port )
  189. {
  190. SOCKADDR_IN6 sockaddr;
  191. INT sockaddrLength;
  192. if ( !pBindAddr )
  193. {
  194. RtlZeroMemory(
  195. &sockaddr,
  196. sizeof(sockaddr) );
  197. ((PSOCKADDR)&sockaddr)->sa_family = (USHORT)Family;
  198. sockaddrLength = sizeof(SOCKADDR_IN);
  199. if ( Family == AF_INET6 )
  200. {
  201. sockaddrLength = sizeof(SOCKADDR_IN6);
  202. }
  203. }
  204. else
  205. {
  206. sockaddrLength = DnsAddr_WriteSockaddr(
  207. (PSOCKADDR) &sockaddr,
  208. sizeof( sockaddr ),
  209. pBindAddr );
  210. DNS_ASSERT( Family == (INT)((PSOCKADDR)&sockaddr)->sa_family );
  211. }
  212. //
  213. // bind port
  214. // - set in sockaddr
  215. // (note it's in the same place for either protocol)
  216. //
  217. if ( Port > 0 )
  218. {
  219. sockaddr.sin6_port = Port;
  220. }
  221. //
  222. // bind -- try exclusive first, then fail to non-exclusive
  223. //
  224. val = 1;
  225. setsockopt(
  226. s,
  227. SOL_SOCKET,
  228. SO_EXCLUSIVEADDRUSE,
  229. (const char *)&val,
  230. sizeof(val) );
  231. do
  232. {
  233. err = bind(
  234. s,
  235. (PSOCKADDR) &sockaddr,
  236. sockaddrLength );
  237. if ( err == 0 )
  238. {
  239. goto Done;
  240. }
  241. DNSDBG( SOCKET, (
  242. "Failed to bind() socket %d, (fam=%d) to port %d, address %s.\n"
  243. "\terror = %d.\n",
  244. s,
  245. Family,
  246. ntohs(Port),
  247. DNSADDR_STRING( pBindAddr ),
  248. GetLastError() ));
  249. //
  250. // retry with REUSEADDR
  251. // - if port and exclusive
  252. // - otherwise we're done
  253. if ( val == 0 || Port == 0 )
  254. {
  255. closesocket( s );
  256. SetLastError( DNS_ERROR_NO_TCPIP );
  257. return 0;
  258. }
  259. val = 0;
  260. setsockopt(
  261. s,
  262. SOL_SOCKET,
  263. SO_EXCLUSIVEADDRUSE,
  264. (const char *)&val,
  265. sizeof(val) );
  266. val = 1;
  267. setsockopt(
  268. s,
  269. SOL_SOCKET,
  270. SO_REUSEADDR,
  271. (const char *)&val,
  272. sizeof(val) );
  273. val = 0;
  274. continue;
  275. }
  276. while ( 1 );
  277. }
  278. Done:
  279. DNSDBG( SOCKET, (
  280. "Created socket %d, family %d, type %d, address %s, port %d.\n",
  281. s,
  282. Family,
  283. SockType,
  284. DNSADDR_STRING( pBindAddr ),
  285. ntohs(Port) ));
  286. return s;
  287. }
  288. SOCKET
  289. Socket_CreateMulticast(
  290. IN INT SockType,
  291. IN PDNS_ADDR pAddr,
  292. IN WORD Port,
  293. IN BOOL fSend,
  294. IN BOOL fReceive
  295. )
  296. /*++
  297. Routine Description:
  298. Create socket and join it to the multicast DNS address.
  299. Arguments:
  300. pAddr -- binding address
  301. SockType -- SOCK_DGRAM or SOCK_STREAM
  302. Port -- port to use; note, if zero, port in pAddr still used by Socket_Create()
  303. Return Value:
  304. Socket if successful.
  305. Zero on error.
  306. --*/
  307. {
  308. DWORD byteCount;
  309. BOOL bflag;
  310. SOCKET s;
  311. SOCKET sjoined;
  312. INT err;
  313. DNSDBG( SOCKET, (
  314. "Socket_CreateMulticast( %d, %p, %d, %d, %d )\n",
  315. SockType,
  316. pAddr,
  317. Port,
  318. fSend,
  319. fReceive ));
  320. s = Socket_Create(
  321. pAddr->Sockaddr.sa_family,
  322. SockType,
  323. pAddr,
  324. Port,
  325. WSA_FLAG_MULTIPOINT_C_LEAF |
  326. WSA_FLAG_MULTIPOINT_D_LEAF |
  327. WSA_FLAG_OVERLAPPED );
  328. if ( s == 0 )
  329. {
  330. return 0;
  331. }
  332. // set loopback
  333. bflag = TRUE;
  334. err = WSAIoctl(
  335. s,
  336. SIO_MULTIPOINT_LOOPBACK, // loopback iotcl
  337. & bflag, // turn on
  338. sizeof(bflag),
  339. NULL, // no output
  340. 0, // no output size
  341. &byteCount, // bytes returned
  342. NULL, // no overlapped
  343. NULL // no completion routine
  344. );
  345. if ( err == SOCKET_ERROR )
  346. {
  347. DNSDBG( ANY, (
  348. "Unable to turn multicast loopback on for socket %d; error = %d.\n",
  349. s,
  350. GetLastError()
  351. ));
  352. }
  353. //
  354. // join socket to multicast group
  355. //
  356. sjoined = WSAJoinLeaf(
  357. s,
  358. (PSOCKADDR) pAddr,
  359. pAddr->SockaddrLength,
  360. NULL, // caller data buffer
  361. NULL, // callee data buffer
  362. NULL, // socket QOS setting
  363. NULL, // socket group QOS
  364. ((fSend && fReceive) ? JL_BOTH : // send and/or receive
  365. (fSend ? JL_SENDER_ONLY : JL_RECEIVER_ONLY))
  366. );
  367. if ( sjoined == INVALID_SOCKET )
  368. {
  369. DNSDBG( ANY, (
  370. "Unable to join socket %d to multicast address, error = %d.\n",
  371. s,
  372. GetLastError() ));
  373. Socket_Close( s );
  374. sjoined = 0;
  375. }
  376. return sjoined;
  377. }
  378. VOID
  379. Socket_CloseEx(
  380. IN SOCKET Socket,
  381. IN BOOL fShutdown
  382. )
  383. /*++
  384. Routine Description:
  385. Close DNS socket.
  386. Arguments:
  387. Socket -- socket to close
  388. fShutdown -- do a shutdown first
  389. Return Value:
  390. None.
  391. --*/
  392. {
  393. if ( Socket == 0 || Socket == INVALID_SOCKET )
  394. {
  395. DNS_PRINT(( "WARNING: Socket_Close() called on invalid socket %d.\n", Socket ));
  396. return;
  397. }
  398. if ( fShutdown )
  399. {
  400. shutdown( Socket, 2 );
  401. }
  402. DNSDBG( SOCKET, (
  403. "%sclosesocket( %d )\n",
  404. fShutdown ? "shutdown and " : "",
  405. Socket ));
  406. closesocket( Socket );
  407. }
  408. #if 0
  409. //
  410. // Global async socket routines
  411. //
  412. DNS_STATUS
  413. Socket_SetupGlobalAsyncSocket(
  414. VOID
  415. )
  416. /*++
  417. Routine Description:
  418. Create global async UDP socket.
  419. Arguments:
  420. SockType -- SOCK_DGRAM or SOCK_STREAM
  421. IpAddress -- IP address to listen on (net byte order)
  422. Port -- desired port in net order
  423. - NET_ORDER_DNS_PORT for DNS listen sockets
  424. - 0 for any port
  425. Return Value:
  426. socket if successful.
  427. Otherwise INVALID_SOCKET.
  428. --*/
  429. {
  430. DNS_STATUS status;
  431. INT err;
  432. SOCKADDR_IN sockaddrIn;
  433. //
  434. // start winsock, need winsock 2 for async
  435. //
  436. if ( ! fWinsockStarted )
  437. {
  438. WSADATA wsaData;
  439. status = WSAStartup( DNS_WINSOCK_VERSION, &wsaData );
  440. if ( status != ERROR_SUCCESS )
  441. {
  442. DNS_PRINT(( "ERROR: WSAStartup failure %d.\n", status ));
  443. return( status );
  444. }
  445. if ( wsaData.wVersion != DNS_WINSOCK2_VERSION )
  446. {
  447. WSACleanup();
  448. return( WSAVERNOTSUPPORTED );
  449. }
  450. fWinsockStarted = TRUE;
  451. }
  452. //
  453. // setup socket
  454. // - overlapped i\o with event so can run asynchronously in
  455. // this thread and wait with queuing event
  456. //
  457. DnsSocket = WSASocket(
  458. AF_INET,
  459. SOCK_DGRAM,
  460. 0,
  461. NULL,
  462. 0,
  463. WSA_FLAG_OVERLAPPED );
  464. if ( DnsSocket == INVALID_SOCKET )
  465. {
  466. status = GetLastError();
  467. DNS_PRINT(( "\nERROR: Async socket create failed.\n" ));
  468. goto Error;
  469. }
  470. //
  471. // bind socket
  472. //
  473. RtlZeroMemory( &sockaddrIn, sizeof(sockaddrIn) );
  474. sockaddrIn.sin_family = AF_INET;
  475. sockaddrIn.sin_port = 0;
  476. sockaddrIn.sin_addr.s_addr = INADDR_ANY;
  477. err = bind( DnsSocket, (PSOCKADDR)&sockaddrIn, sizeof(sockaddrIn) );
  478. if ( err == SOCKET_ERROR )
  479. {
  480. status = GetLastError();
  481. DNSDBG( SOCKET, (
  482. "Failed to bind() DnsSocket %d.\n"
  483. "\terror = %d.\n",
  484. DnsSocket,
  485. status ));
  486. goto Error;
  487. }
  488. //
  489. // create event to signal on async i/o completion
  490. //
  491. hDnsSocketEvent = CreateEvent(
  492. NULL, // Security Attributes
  493. TRUE, // create Manual-Reset event
  494. FALSE, // start unsignalled -- paused
  495. NULL // event name
  496. );
  497. if ( !hDnsSocketEvent )
  498. {
  499. status = GetLastError();
  500. DNS_PRINT(( "Failed event creation\n" ));
  501. goto Error;
  502. }
  503. DnsSocketOverlapped.hEvent = hDnsSocketEvent;
  504. DNSDBG( SOCKET, (
  505. "Created global async UDP socket %d.\n"
  506. "\toverlapped at %p\n"
  507. "\tevent handle %p\n",
  508. DnsSocket,
  509. DnsSocketOverlapped,
  510. hDnsSocketEvent ));
  511. return ERROR_SUCCESS;
  512. Error:
  513. DNS_PRINT((
  514. "ERROR: Failed async socket creation, status = %d\n",
  515. status ));
  516. closesocket( DnsSocket );
  517. DnsSocket = INVALID_SOCKET;
  518. WSACleanup();
  519. return( status );
  520. }
  521. #endif
  522. //
  523. // Socket caching
  524. //
  525. // Doing limited caching of UDP unbound sockets used for standard
  526. // DNS lookups in resolver. This allows us to prevent denial of
  527. // service attack by using up all ports on the machine.
  528. // Resolver is the main customer for this, but we'll code it to
  529. // be useable by any process.
  530. //
  531. // Implementation notes:
  532. //
  533. // There are a couple specific goals to this implementation:
  534. // - Minimal code impact; Try NOT to change the resolver
  535. // code.
  536. // - Usage driven caching; Don't want to create on startup
  537. // "cache sockets" that we don't use; Instead have actual usage
  538. // drive up the cached socket count.
  539. //
  540. // There are several approaches here.
  541. //
  542. // 1) explicit resolver cache -- passed down sockets
  543. //
  544. // 2) add caching seamlessly into socket open and close
  545. // this was my first choice, but the problem here is that on
  546. // close we must either do additional calls to winsock to determine
  547. // whether cachable (UDP-unbound) socket OR cache must include some
  548. // sort of "in-use" tag and we trust that socket is never closed
  549. // outside of path (otherwise handle reuse could mess us up)
  550. //
  551. // 3) new UDP-unbound open\close function
  552. // this essentially puts the "i-know-i'm-using-UDP-unbound-sockets"
  553. // burden on the caller who must switch to this new API;
  554. // fortunately this meshes well with our "SendAndRecvUdp()" function;
  555. // this approach still allows a caller driven ramp up we desire,
  556. // so i'm using this approach
  557. //
  558. // DCR: FIX6: no cached UDP IP6 sockets
  559. //
  560. //
  561. // Keep array of sockets
  562. //
  563. // Dev note: the Array and MaxCount MUST be kept in sync, no
  564. // independent check of array is done, it is assumed to exist when
  565. // MaxCount is non-zero, so they MUST be in sync when lock released
  566. //
  567. SOCKET * g_pCacheSocketArray = NULL;
  568. DWORD g_CacheSocketMaxCount = 0;
  569. DWORD g_CacheSocketCount = 0;
  570. // Hard limit on what we'll allow folks to keep awake
  571. #define MAX_SOCKET_CACHE_LIMIT (100)
  572. // Lock access with generic lock
  573. // This is very short\fast CS, contention will be minimal
  574. #define LOCK_SOCKET_CACHE() LOCK_GENERAL()
  575. #define UNLOCK_SOCKET_CACHE() UNLOCK_GENERAL()
  576. DNS_STATUS
  577. Socket_CacheInit(
  578. IN DWORD MaxSocketCount
  579. )
  580. /*++
  581. Routine Description:
  582. Initialize socket caching.
  583. EXPORTED (resolver): Socket_CacheInit()
  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. Socket_CacheCleanup(
  630. VOID
  631. )
  632. /*++
  633. Routine Description:
  634. Cleanup socket caching.
  635. EXPORTED (resolver): Socket_CacheCleanup()
  636. Arguments:
  637. None
  638. Return Value:
  639. None
  640. --*/
  641. {
  642. DWORD i;
  643. SOCKET sock;
  644. DNSDBG( SOCKET, ( "Dns_CacheSocketCleanup()\n" ));
  645. //
  646. // close cached sockets
  647. //
  648. LOCK_SOCKET_CACHE();
  649. for ( i=0; i<g_CacheSocketMaxCount; i++ )
  650. {
  651. sock = g_pCacheSocketArray[i];
  652. if ( sock )
  653. {
  654. Socket_Close( sock );
  655. g_CacheSocketCount--;
  656. }
  657. }
  658. DNS_ASSERT( g_CacheSocketCount == 0 );
  659. // dump socket array memory
  660. FREE_HEAP( g_pCacheSocketArray );
  661. // clear globals
  662. g_pCacheSocketArray = NULL;
  663. g_CacheSocketMaxCount = 0;
  664. g_CacheSocketCount = 0;
  665. UNLOCK_SOCKET_CACHE();
  666. }
  667. SOCKET
  668. Socket_GetUdp(
  669. IN INT Family
  670. )
  671. /*++
  672. Routine Description:
  673. Get a cached socket.
  674. Arguments:
  675. Family -- address family
  676. Return Value:
  677. Socket handle if successful.
  678. Zero if no cached socket available.
  679. --*/
  680. {
  681. SOCKET sock;
  682. DWORD i;
  683. //
  684. // quick return if nothing available
  685. // - do outside lock so function can be called cheaply
  686. // without other checks
  687. //
  688. if ( g_CacheSocketCount == 0 )
  689. {
  690. goto Open;
  691. }
  692. //
  693. // get a cached socket
  694. //
  695. LOCK_SOCKET_CACHE();
  696. for ( i=0; i<g_CacheSocketMaxCount; i++ )
  697. {
  698. sock = g_pCacheSocketArray[i];
  699. if ( sock != 0 )
  700. {
  701. g_pCacheSocketArray[i] = 0;
  702. g_CacheSocketCount--;
  703. UNLOCK_SOCKET_CACHE();
  704. //
  705. // DCR: clean out any data on cached socket
  706. // it would be cool to cheaply dump useless data
  707. //
  708. // right now we just let XID match, then question match
  709. // dump data on recv
  710. //
  711. DNSDBG( SOCKET, (
  712. "Returning cached socket %d.\n",
  713. sock ));
  714. return sock;
  715. }
  716. }
  717. UNLOCK_SOCKET_CACHE();
  718. Open:
  719. //
  720. // not found in list -- create
  721. // - set exclusive
  722. //
  723. sock = Socket_Create(
  724. Family,
  725. SOCK_DGRAM,
  726. NULL, // ANY addr binding
  727. 0, // ANY port binding
  728. 0 // no special flags
  729. );
  730. if ( sock )
  731. {
  732. INT val = 1;
  733. setsockopt(
  734. sock,
  735. SOL_SOCKET,
  736. SO_EXCLUSIVEADDRUSE,
  737. (const char *)&val,
  738. sizeof(val) );
  739. }
  740. return sock;
  741. }
  742. VOID
  743. Socket_ReturnUdp(
  744. IN SOCKET Socket,
  745. IN INT Family
  746. )
  747. /*++
  748. Routine Description:
  749. Return UDP socket for possible caching.
  750. Arguments:
  751. Socket -- socket handle
  752. Family -- family of socket
  753. Return Value:
  754. None
  755. --*/
  756. {
  757. SOCKET sock;
  758. DWORD i;
  759. //
  760. // return on bogus sockets to avoid caching them
  761. //
  762. if ( Socket == 0 )
  763. {
  764. DNSDBG( SOCKET, (
  765. "Warning: returning zero socket\n" ));
  766. return;
  767. }
  768. //
  769. // DCR: currently no IP6 socket list
  770. //
  771. if ( Family != AF_INET )
  772. {
  773. goto Close;
  774. }
  775. //
  776. // quick return if not caching
  777. // - do outside lock so function can be called cheaply
  778. // without other checks
  779. //
  780. if ( g_CacheSocketMaxCount == 0 ||
  781. g_CacheSocketMaxCount == g_CacheSocketCount )
  782. {
  783. goto Close;
  784. }
  785. //
  786. // return cached socket
  787. //
  788. LOCK_SOCKET_CACHE();
  789. for ( i=0; i<g_CacheSocketMaxCount; i++ )
  790. {
  791. if ( g_pCacheSocketArray[i] )
  792. {
  793. continue;
  794. }
  795. g_pCacheSocketArray[i] = Socket;
  796. g_CacheSocketCount++;
  797. UNLOCK_SOCKET_CACHE();
  798. DNSDBG( SOCKET, (
  799. "Returned socket %d to cache.\n",
  800. Socket ));
  801. return;
  802. }
  803. UNLOCK_SOCKET_CACHE();
  804. DNSDBG( SOCKET, (
  805. "Socket cache full, closing socket %d.\n"
  806. "WARNING: should only see this message on race!\n",
  807. Socket ));
  808. Close:
  809. Socket_Close( Socket );
  810. }
  811. //
  812. // Message socket routines
  813. //
  814. SOCKET
  815. Socket_CreateMessageSocket(
  816. IN OUT PDNS_MSG_BUF pMsg
  817. )
  818. /*++
  819. Routine Description:
  820. Set the remote address in a message.
  821. Arguments:
  822. pMsg - message to send
  823. Return Value:
  824. Socket handle if successful.
  825. Zero on error.
  826. --*/
  827. {
  828. BOOL is6;
  829. SOCKET sock;
  830. INT family;
  831. DNSDBG( SOCKET, (
  832. "Socket_CreateMessageSocket( %p )\n", pMsg ));
  833. //
  834. // determine 4/6
  835. //
  836. is6 = MSG_SOCKADDR_IS_IP6( pMsg );
  837. //
  838. // check for existing socket
  839. //
  840. if ( is6 )
  841. {
  842. sock = pMsg->Socket6;
  843. family = AF_INET6;
  844. }
  845. else
  846. {
  847. sock = pMsg->Socket4;
  848. family = AF_INET;
  849. }
  850. if ( sock )
  851. {
  852. DNSDBG( SEND, (
  853. "Setting message to use existing IP%c socket %d\n",
  854. is6 ? '6' : '4',
  855. sock ));
  856. goto Done;
  857. }
  858. //
  859. // not existing -- open new (or cached)
  860. //
  861. if ( pMsg->fTcp )
  862. {
  863. sock = Socket_Create(
  864. family,
  865. SOCK_STREAM,
  866. NULL, // ANY addr binding
  867. 0, // ANY port binding
  868. 0 // no flags
  869. );
  870. }
  871. else
  872. {
  873. sock = Socket_GetUdp( family );
  874. }
  875. //
  876. // save socket to message
  877. //
  878. if ( is6 )
  879. {
  880. pMsg->Socket6 = sock;
  881. }
  882. else
  883. {
  884. pMsg->Socket4 = sock;
  885. }
  886. Done:
  887. pMsg->Socket = sock;
  888. return sock;
  889. }
  890. VOID
  891. Socket_ClearMessageSockets(
  892. IN OUT PDNS_MSG_BUF pMsg
  893. )
  894. /*++
  895. Routine Description:
  896. Close message sockets.
  897. Arguments:
  898. pMsg - ptr message
  899. Return Value:
  900. None
  901. --*/
  902. {
  903. pMsg->Socket = 0;
  904. pMsg->Socket4 = 0;
  905. pMsg->Socket6 = 0;
  906. }
  907. VOID
  908. Socket_CloseMessageSockets(
  909. IN OUT PDNS_MSG_BUF pMsg
  910. )
  911. /*++
  912. Routine Description:
  913. Close message sockets.
  914. Arguments:
  915. pMsg - ptr message
  916. Return Value:
  917. Socket handle if successful.
  918. Zero on error.
  919. --*/
  920. {
  921. DNSDBG( SOCKET, (
  922. "Socket_CloseMessageSockets( %p )\n", pMsg ));
  923. //
  924. // TCP -- single connection at a time
  925. // UDP -- may have both IP4 and IP6 sockets open
  926. //
  927. if ( pMsg->fTcp )
  928. {
  929. Socket_CloseConnection( pMsg->Socket );
  930. }
  931. else
  932. {
  933. Socket_ReturnUdp( pMsg->Socket4, AF_INET );
  934. Socket_ReturnUdp( pMsg->Socket6, AF_INET6 );
  935. }
  936. Socket_ClearMessageSockets( pMsg );
  937. }
  938. //
  939. // End socket.c
  940. //