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.

1793 lines
48 KiB

  1. /*++
  2. Copyright (c) 1998, Microsoft Corporation
  3. Module Name:
  4. socket.c
  5. Abstract:
  6. This module contains code for socket-management.
  7. The routines provided generally follow the same asynchronous model
  8. using a completion routine that is invoked in the context of
  9. a callback thread.
  10. Author:
  11. Abolade Gbadegesin (aboladeg) 2-Mar-1998
  12. Revision History:
  13. Abolade Gbadegesin (aboladeg) 23-May-1999
  14. Added support for stream sockets.
  15. Jonathan Burstein (jonburs) 12-April-2001
  16. Added support for raw datagram sockets.
  17. --*/
  18. #include "precomp.h"
  19. #pragma hdrstop
  20. #include <ws2tcpip.h>
  21. #include <mstcpip.h>
  22. #include <mswsock.h>
  23. #if DBG
  24. ULONG NhpReadCount = 0;
  25. #endif
  26. ULONG UnusedBytesTransferred;
  27. typedef struct _NH_CLOSE_BUFFER {
  28. HANDLE Event OPTIONAL;
  29. HANDLE WaitHandle OPTIONAL;
  30. PNH_COMPLETION_ROUTINE CloseNotificationRoutine;
  31. } NH_CLOSE_BUFFER, *PNH_CLOSE_BUFFER;
  32. typedef struct _NH_CONNECT_BUFFER {
  33. HANDLE Event;
  34. HANDLE WaitHandle;
  35. PNH_COMPLETION_ROUTINE CloseNotificationRoutine OPTIONAL;
  36. BOOLEAN CloseNotificationReceived;
  37. } NH_CONNECT_BUFFER, *PNH_CONNECT_BUFFER;
  38. //
  39. // FORWARD DECLARATIONS
  40. //
  41. VOID NTAPI
  42. NhpCloseNotificationCallbackRoutine(
  43. PVOID Context,
  44. BOOLEAN WaitCompleted
  45. );
  46. VOID NTAPI
  47. NhpConnectOrCloseCallbackRoutine(
  48. PVOID Context,
  49. BOOLEAN WaitCompleted
  50. );
  51. VOID WINAPI
  52. NhpIoCompletionRoutine(
  53. ULONG ErrorCode,
  54. ULONG BytesTransferred,
  55. LPOVERLAPPED Overlapped
  56. );
  57. VOID APIENTRY
  58. NhpIoWorkerRoutine(
  59. PVOID Context
  60. );
  61. ULONG
  62. NhAcceptStreamSocket(
  63. PCOMPONENT_REFERENCE Component,
  64. SOCKET ListeningSocket,
  65. SOCKET AcceptedSocket OPTIONAL,
  66. PNH_BUFFER Bufferp,
  67. PNH_COMPLETION_ROUTINE AcceptCompletionRoutine,
  68. PVOID Context,
  69. PVOID Context2
  70. )
  71. /*++
  72. Routine Description:
  73. This routine is invoked to accept an incoming connection-request
  74. on a listening stream socket using 'AcceptEx'. The I/O system invokes
  75. the provided 'CompletionRoutine' upon completion of the read.
  76. It is the completion-routine's responsibility to use 'setsockopt' to
  77. set the SO_UPDATE_ACCEPT_CONTEXT option on the accepted socket before
  78. the accepted socket can be used with Winsock2 routines.
  79. A reference is made to the given component, if any, if the request is
  80. submitted successfully. This guarantees the component will not be unloaded
  81. before the completion routine runs.
  82. Arguments:
  83. Component - the component to be referenced for the completion routine
  84. ListeningSocket - the endpoint that is listening for connection-requests
  85. AcceptedSocket - the endpoint to be assigned a connection-request,
  86. or INVALID_SOCKET to create a new endpoint
  87. Bufferp - the buffer to be used for asynchronous completion
  88. or NULL to acquire a new buffer
  89. AcceptCompletionRoutine - the routine to be invoked upon completion
  90. Context - the context to be associated with the accept-request;
  91. this can be obtained from 'Bufferp->Context' upon completion.
  92. Context2 - secondary context
  93. Return Value:
  94. ULONG - Win32/Winsock2 status code.
  95. A success code is a guarantee that the accept-completion routine
  96. will be invoked.
  97. Conversely, a failure code is a guarantee that the routine will not
  98. be invoked.
  99. --*/
  100. {
  101. ULONG Error;
  102. PNH_BUFFER LocalBufferp = NULL;
  103. SOCKET LocalSocket = INVALID_SOCKET;
  104. if (Component) {
  105. REFERENCE_COMPONENT_OR_RETURN(Component, ERROR_CAN_NOT_COMPLETE);
  106. }
  107. if (!Bufferp) {
  108. Bufferp = LocalBufferp = NhAcquireBuffer();
  109. if (!Bufferp) {
  110. NhTrace(TRACE_FLAG_SOCKET, "error allocating buffer for accept");
  111. if (Component) { DEREFERENCE_COMPONENT(Component); }
  112. return ERROR_NOT_ENOUGH_MEMORY;
  113. }
  114. }
  115. if (AcceptedSocket == INVALID_SOCKET) {
  116. Error = NhCreateStreamSocket(INADDR_NONE, 0, &LocalSocket);
  117. if (Error) {
  118. NhTrace(
  119. TRACE_FLAG_SOCKET, "error %d creating socket for accept", Error
  120. );
  121. if (LocalBufferp) { NhReleaseBuffer(LocalBufferp); }
  122. if (Component) { DEREFERENCE_COMPONENT(Component); }
  123. return ERROR_NOT_ENOUGH_MEMORY;
  124. }
  125. AcceptedSocket = LocalSocket;
  126. }
  127. ZeroMemory(&Bufferp->Overlapped, sizeof(Bufferp->Overlapped));
  128. Bufferp->Socket = AcceptedSocket;
  129. Bufferp->CompletionRoutine = AcceptCompletionRoutine;
  130. Bufferp->Context = Context;
  131. Bufferp->Context2 = Context2;
  132. if (AcceptEx(
  133. ListeningSocket,
  134. AcceptedSocket,
  135. Bufferp->Buffer,
  136. 0,
  137. sizeof(SOCKADDR_IN) + 16,
  138. sizeof(SOCKADDR_IN) + 16,
  139. &UnusedBytesTransferred,
  140. &Bufferp->Overlapped
  141. )) {
  142. Error = NO_ERROR;
  143. } else {
  144. if ((Error = WSAGetLastError()) == ERROR_IO_PENDING) {
  145. Error = NO_ERROR;
  146. } else if (Error) {
  147. if (LocalSocket != INVALID_SOCKET) {
  148. NhDeleteStreamSocket(LocalSocket);
  149. }
  150. if (LocalBufferp) { NhReleaseBuffer(LocalBufferp); }
  151. if (Component) { DEREFERENCE_COMPONENT(Component); }
  152. NhTrace(
  153. TRACE_FLAG_SOCKET, "error %d returned by 'AcceptEx'", Error
  154. );
  155. }
  156. }
  157. return Error;
  158. } // NhAcceptStreamSocket
  159. ULONG
  160. NhConnectStreamSocket(
  161. PCOMPONENT_REFERENCE Component,
  162. SOCKET ConnectingSocket,
  163. ULONG Address,
  164. USHORT Port,
  165. PNH_BUFFER Bufferp OPTIONAL,
  166. PNH_COMPLETION_ROUTINE ConnectCompletionRoutine,
  167. PNH_COMPLETION_ROUTINE CloseNotificationRoutine OPTIONAL,
  168. PVOID Context,
  169. PVOID Context2
  170. )
  171. /*++
  172. Routine Description:
  173. This routine is invoked to establish a connection using a stream socket.
  174. A reference is made to the given component, if any, if the request is
  175. submitted successfully. This guarantees the component will not be unloaded
  176. before the completion routine runs.
  177. Since Windows Sockets does not deliver connect-notifications to
  178. I/O completion ports, we need to make some special arrangements in order
  179. to notify the caller's completion routine the way we do for send-requests
  180. and receive-requests. Specifically, we create an event-handle and
  181. request connect-notification on it by calling 'WSAEventSelect'.
  182. We then register a wait on the event-handle, specifying a private
  183. completion routine. (See 'NhpConnectOrCloseCallbackRoutine'.)
  184. When this completion routine runs, it extracts the status code of the
  185. connection-attempt using 'WSAEnumNetworkEvents'. It then passes the status
  186. along with the usual parameters to the caller's completion routine.
  187. The caller may optionally receive notification when the remote endpoint
  188. closes the socket after a successful connection. We use the same
  189. 'WSAEventSelect' mechanism to detect that condition and invoke the
  190. caller's notification routine.
  191. N.B. The buffer supplied to this routine may not be released by either
  192. the connect-completion routine or the close-notification routine.
  193. (See 'NhpConnectOrCloseCallbackRoutine' for more information.)
  194. Arguments:
  195. Component - the component to be referenced for the completion routine
  196. Socket - the socket with which to establish a connection
  197. Address - the IP address of the remote endpoint
  198. Port - the port number of the remote endpoint
  199. Bufferp - optionally supplies the buffer to be used to hold context
  200. during the connection-attempt
  201. ConnectCompletionRoutine - a routine to be invoked upon completion
  202. of the connect-attempt
  203. CloseNotificationRoutine - optionally specifies a routine to be invoked
  204. upon notification of the resulting socket's closure by the remote
  205. endpoint
  206. Context - passed to the 'ConnectCompletionRoutine' and
  207. 'CloseNotificationRoutine'
  208. Context2 - secondary context
  209. Return Value:
  210. ULONG - Win32/Winsock2 status code
  211. A success code is a guarantee that both the connect-completion routine
  212. and the close-notification routine, if any, will be invoked.
  213. Conversely, a failure code is a guarantee that the neither routine will
  214. be invoked.
  215. --*/
  216. {
  217. PNH_CONNECT_BUFFER Contextp;
  218. ULONG Error;
  219. PNH_BUFFER LocalBufferp = NULL;
  220. if (Component) {
  221. REFERENCE_COMPONENT_OR_RETURN(Component, ERROR_CAN_NOT_COMPLETE);
  222. }
  223. if (!Bufferp) {
  224. Bufferp = LocalBufferp = NhAcquireBuffer();
  225. if (!Bufferp) {
  226. NhTrace(
  227. TRACE_FLAG_SOCKET,
  228. "NhConnectStreamSocket: error allocating buffer for connect"
  229. );
  230. if (Component) { DEREFERENCE_COMPONENT(Component); }
  231. return ERROR_NOT_ENOUGH_MEMORY;
  232. }
  233. }
  234. Bufferp->Socket = ConnectingSocket;
  235. Bufferp->ReceiveFlags = 0;
  236. Bufferp->CompletionRoutine = ConnectCompletionRoutine;
  237. Bufferp->Context = Context;
  238. Bufferp->Context2 = Context2;
  239. Bufferp->ConnectAddress.sin_family = AF_INET;
  240. Bufferp->ConnectAddress.sin_addr.s_addr = Address;
  241. Bufferp->ConnectAddress.sin_port = Port;
  242. Contextp = (PNH_CONNECT_BUFFER)Bufferp->Buffer;
  243. Contextp->CloseNotificationReceived = FALSE;
  244. Contextp->CloseNotificationRoutine = CloseNotificationRoutine;
  245. Contextp->WaitHandle = NULL;
  246. Contextp->Event = CreateEvent(NULL, FALSE, FALSE, NULL);
  247. if (!Contextp->Event ||
  248. !RegisterWaitForSingleObject(
  249. &Contextp->WaitHandle,
  250. Contextp->Event,
  251. NhpConnectOrCloseCallbackRoutine,
  252. Bufferp,
  253. INFINITE,
  254. WT_EXECUTEINIOTHREAD
  255. )) {
  256. Error = GetLastError();
  257. } else {
  258. ULONG EventsSelected = FD_CONNECT;
  259. if (CloseNotificationRoutine) { EventsSelected |= FD_CLOSE; }
  260. Error =
  261. WSAEventSelect(
  262. ConnectingSocket, Contextp->Event, EventsSelected
  263. );
  264. if (Error == SOCKET_ERROR) {
  265. Error = WSAGetLastError();
  266. } else {
  267. Error =
  268. WSAConnect(
  269. ConnectingSocket,
  270. (PSOCKADDR)&Bufferp->ConnectAddress,
  271. sizeof(Bufferp->ConnectAddress),
  272. NULL,
  273. NULL,
  274. NULL,
  275. NULL
  276. );
  277. }
  278. }
  279. if (Error == SOCKET_ERROR &&
  280. (Error = WSAGetLastError()) == WSAEWOULDBLOCK) {
  281. Error = NO_ERROR;
  282. } else if (Error) {
  283. if (Contextp->WaitHandle) { UnregisterWait(Contextp->WaitHandle); }
  284. if (Contextp->Event) { CloseHandle(Contextp->Event); }
  285. if (LocalBufferp) { NhReleaseBuffer(LocalBufferp); }
  286. if (Component) { DEREFERENCE_COMPONENT(Component); }
  287. }
  288. return Error;
  289. } // NhConnectStreamSocket
  290. ULONG
  291. NhCreateDatagramSocket(
  292. ULONG Address,
  293. USHORT Port,
  294. OUT SOCKET* Socketp
  295. )
  296. /*++
  297. Routine Description:
  298. This routine is called to initialize a datagram socket.
  299. Arguments:
  300. Address - the IP address to which the socket should be bound (network-order)
  301. Port - the UDP port to which the socket should be bound (network-order)
  302. Socketp - receives the created socket
  303. Return Value:
  304. ULONG - Win32/Winsock2 error code
  305. --*/
  306. {
  307. ULONG Error;
  308. ULONG Option;
  309. ULONG OutputBufferLength;
  310. SOCKET Socket;
  311. SOCKADDR_IN SocketAddress;
  312. do {
  313. //
  314. // Create a new socket
  315. //
  316. Socket =
  317. WSASocket(
  318. AF_INET, SOCK_DGRAM, IPPROTO_UDP, NULL, 0, WSA_FLAG_OVERLAPPED
  319. );
  320. if (Socket == INVALID_SOCKET) {
  321. Error = WSAGetLastError();
  322. NhTrace(
  323. TRACE_FLAG_SOCKET,
  324. "NhCreateDatagramSocket: error %d creating socket", Error
  325. );
  326. break;
  327. }
  328. //
  329. // Associate the socket with our I/O completion port
  330. //
  331. if (FALSE == BindIoCompletionCallback(
  332. (HANDLE)Socket,
  333. NhpIoCompletionRoutine,
  334. 0)) {
  335. Error = GetLastError();
  336. NhTrace(
  337. TRACE_FLAG_SOCKET,
  338. "NhCreateDatagramSocket: error %d binding callback", Error
  339. );
  340. break;
  341. }
  342. //
  343. // Attempt to enable endpoint-reuse on the socket
  344. //
  345. Option = 1;
  346. Error =
  347. setsockopt(
  348. Socket,
  349. SOL_SOCKET,
  350. SO_REUSEADDR,
  351. (PCHAR)&Option,
  352. sizeof(Option)
  353. );
  354. //
  355. // Attempt to enable broadcasting on the socket
  356. //
  357. Option = 1;
  358. Error =
  359. setsockopt(
  360. Socket,
  361. SOL_SOCKET,
  362. SO_BROADCAST,
  363. (PCHAR)&Option,
  364. sizeof(Option)
  365. );
  366. //
  367. // Limit broadcasts to the outgoing network
  368. // (the default is to send broadcasts on all interfaces).
  369. //
  370. Option = 1;
  371. WSAIoctl(
  372. Socket,
  373. SIO_LIMIT_BROADCASTS,
  374. &Option,
  375. sizeof(Option),
  376. NULL,
  377. 0,
  378. &OutputBufferLength,
  379. NULL,
  380. NULL
  381. );
  382. //
  383. // Bind the socket
  384. //
  385. SocketAddress.sin_family = AF_INET;
  386. SocketAddress.sin_port = Port;
  387. SocketAddress.sin_addr.s_addr = Address;
  388. Error = bind(Socket, (PSOCKADDR)&SocketAddress, sizeof(SocketAddress));
  389. if (Error == SOCKET_ERROR) {
  390. Error = WSAGetLastError();
  391. NhTrace(
  392. TRACE_FLAG_SOCKET,
  393. "NhCreateDatagramSocket: error %d binding socket", Error
  394. );
  395. break;
  396. }
  397. //
  398. // Save the socket and return
  399. //
  400. *Socketp = Socket;
  401. return NO_ERROR;
  402. } while (FALSE);
  403. if (Socket != INVALID_SOCKET) { closesocket(Socket); }
  404. return Error;
  405. } // NhCreateDatagramSocket
  406. ULONG
  407. NhCreateRawDatagramSocket(
  408. OUT SOCKET* Socketp
  409. )
  410. /*++
  411. Routine Description:
  412. This routine is called to initialize a raw, header-include
  413. datagram socket.
  414. Arguments:
  415. Socketp - receives the created socket
  416. Return Value:
  417. ULONG - Win32/Winsock2 error code
  418. --*/
  419. {
  420. ULONG Error;
  421. ULONG Option;
  422. ULONG OutputBufferLength;
  423. SOCKET Socket;
  424. SOCKADDR_IN SocketAddress;
  425. do {
  426. //
  427. // Create a new socket
  428. //
  429. Socket =
  430. WSASocket(
  431. AF_INET, SOCK_RAW, IPPROTO_UDP, NULL, 0, WSA_FLAG_OVERLAPPED
  432. );
  433. if (Socket == INVALID_SOCKET) {
  434. Error = WSAGetLastError();
  435. NhTrace(
  436. TRACE_FLAG_SOCKET,
  437. "NhCreateRawDatagramSocket: error %d creating socket", Error
  438. );
  439. break;
  440. }
  441. //
  442. // Associate the socket with our I/O completion port
  443. //
  444. if (FALSE == BindIoCompletionCallback(
  445. (HANDLE)Socket,
  446. NhpIoCompletionRoutine,
  447. 0)) {
  448. Error = GetLastError();
  449. NhTrace(
  450. TRACE_FLAG_SOCKET,
  451. "NhCreateRawDatagramSocket: error %d binding callback", Error
  452. );
  453. break;
  454. }
  455. //
  456. // Turn on header-include mode
  457. //
  458. Option = 1;
  459. Error =
  460. setsockopt(
  461. Socket,
  462. IPPROTO_IP,
  463. IP_HDRINCL,
  464. (PCHAR)&Option,
  465. sizeof(Option)
  466. );
  467. if (SOCKET_ERROR == Error) {
  468. Error = WSAGetLastError();
  469. NhTrace(
  470. TRACE_FLAG_SOCKET,
  471. "NhCreateRawDatagramSocket: error %d setting IP_HDRINCL", Error
  472. );
  473. break;
  474. }
  475. //
  476. // Limit broadcasts to the outgoing network
  477. // (the default is to send broadcasts on all interfaces).
  478. //
  479. Option = 1;
  480. WSAIoctl(
  481. Socket,
  482. SIO_LIMIT_BROADCASTS,
  483. &Option,
  484. sizeof(Option),
  485. NULL,
  486. 0,
  487. &OutputBufferLength,
  488. NULL,
  489. NULL
  490. );
  491. //
  492. // Save the socket and return
  493. //
  494. *Socketp = Socket;
  495. return NO_ERROR;
  496. } while (FALSE);
  497. if (Socket != INVALID_SOCKET) { closesocket(Socket); }
  498. return Error;
  499. } // NhCreateRawDatagramSocket
  500. ULONG
  501. NhCreateStreamSocket(
  502. ULONG Address OPTIONAL,
  503. USHORT Port OPTIONAL,
  504. OUT SOCKET* Socketp
  505. )
  506. /*++
  507. Routine Description:
  508. This routine is invoked to create and initialize a stream socket.
  509. The socket will also be bound to a local IP address and port,
  510. unless none is specified.
  511. Arguments:
  512. Address - the local IP address to which the new socket should be bound,
  513. or INADDR_ANY to allow the system to leave the IP address unspecified,
  514. or INADDR_NONE if the socket should not be bound at all.
  515. Port - the port number to which the new socket should be bound,
  516. or 0 if to allow the system to select a port number.
  517. Socketp - receives initialized socket
  518. Return Value:
  519. ULONG - Win32/Winsock2 status code.
  520. --*/
  521. {
  522. ULONG Error;
  523. ULONG Option;
  524. SOCKET Socket;
  525. SOCKADDR_IN SocketAddress;
  526. do {
  527. //
  528. // Create a new stream socket.
  529. //
  530. Socket =
  531. WSASocket(
  532. AF_INET, SOCK_STREAM, IPPROTO_TCP, NULL, 0, WSA_FLAG_OVERLAPPED
  533. );
  534. if (Socket == INVALID_SOCKET) {
  535. Error = WSAGetLastError();
  536. NhTrace(
  537. TRACE_FLAG_SOCKET,
  538. "NhCreateStreamSocket: error %d creating socket", Error
  539. );
  540. break;
  541. }
  542. //
  543. // Associate the socket with our I/O completion port
  544. //
  545. if (FALSE == BindIoCompletionCallback(
  546. (HANDLE)Socket,
  547. NhpIoCompletionRoutine,
  548. 0)) {
  549. Error = GetLastError();
  550. NhTrace(
  551. TRACE_FLAG_SOCKET,
  552. "NhCreateStreamSocket: error %d binding callback", Error
  553. );
  554. break;
  555. }
  556. //
  557. // Disable send and receive buffering in AFD,
  558. // since we will be operating asynchronously with a receive-buffer
  559. // (almost) always outstanding, and since in any case we want
  560. // TCP/IP's flow-control to limit the sender's sending rate properly.
  561. //
  562. Option = 0;
  563. setsockopt(
  564. Socket,
  565. SOL_SOCKET,
  566. SO_SNDBUF,
  567. (PCHAR)&Option,
  568. sizeof(Option)
  569. );
  570. Option = 0;
  571. setsockopt(
  572. Socket,
  573. SOL_SOCKET,
  574. SO_SNDBUF,
  575. (PCHAR)&Option,
  576. sizeof(Option)
  577. );
  578. //
  579. // If the caller has requested that the socket be bound by specifying
  580. // a local IP address, bind the socket now.
  581. //
  582. if (Address != INADDR_NONE) {
  583. SocketAddress.sin_family = AF_INET;
  584. SocketAddress.sin_port = Port;
  585. SocketAddress.sin_addr.s_addr = Address;
  586. Error =
  587. bind(Socket, (PSOCKADDR)&SocketAddress, sizeof(SocketAddress));
  588. if (Error == SOCKET_ERROR) {
  589. Error = WSAGetLastError();
  590. NhTrace(
  591. TRACE_FLAG_SOCKET,
  592. "NhCreateStreamSocket: error %d binding socket", Error
  593. );
  594. break;
  595. }
  596. }
  597. //
  598. // Store the new socket in the caller's output-parameter, and return.
  599. //
  600. *Socketp = Socket;
  601. return NO_ERROR;
  602. } while(FALSE);
  603. if (Socket != INVALID_SOCKET) { closesocket(Socket); }
  604. return Error;
  605. } // NhCreateStreamSocket
  606. VOID
  607. NhDeleteSocket(
  608. SOCKET Socket
  609. )
  610. /*++
  611. Routine Description:
  612. This routine releases network resources for a socket.
  613. Arguments:
  614. Socket - the socket to be deleted
  615. Return Value:
  616. none.
  617. --*/
  618. {
  619. if (Socket != INVALID_SOCKET) { closesocket(Socket); }
  620. } // NhDeleteSocket
  621. ULONG
  622. NhNotifyOnCloseStreamSocket(
  623. PCOMPONENT_REFERENCE Component,
  624. SOCKET Socket,
  625. PNH_BUFFER Bufferp OPTIONAL,
  626. PNH_COMPLETION_ROUTINE CloseNotificationRoutine,
  627. PVOID Context,
  628. PVOID Context2
  629. )
  630. /*++
  631. Routine Description:
  632. This routine is invoked to request notification of a socket's closure.
  633. A reference is made to the given component, if any, if the request is
  634. submitted successfully. This guarantees the component will not be unloaded
  635. before the notification routine runs.
  636. Arguments:
  637. Component - the component to be referenced for the notification routine
  638. Socket - the endpoint for which close-notification is requested
  639. Bufferp - the buffer to be used to hold context-informatio for the request,
  640. or NULL to acquire a new buffer.
  641. CloseNotificationRoutine - the routine to be invoked upon closure of the
  642. socket
  643. Context - the context to be associated with the notification-request;
  644. this can be obtained from 'Bufferp->Context' upon completion.
  645. Context2 - secondary context
  646. Return Value:
  647. ULONG - Win32/Winsock2 status code.
  648. A success code is a guarantee that the notification routine will be invoked.
  649. Conversely, a failure code is a guarantee that the notification routine
  650. will not be invoked.
  651. --*/
  652. {
  653. PNH_CLOSE_BUFFER Contextp;
  654. ULONG Error;
  655. PNH_BUFFER LocalBufferp = NULL;
  656. if (Component) {
  657. REFERENCE_COMPONENT_OR_RETURN(Component, ERROR_CAN_NOT_COMPLETE);
  658. }
  659. if (!Bufferp) {
  660. Bufferp = LocalBufferp = NhAcquireBuffer();
  661. if (!Bufferp) {
  662. if (Component) { DEREFERENCE_COMPONENT(Component); }
  663. return ERROR_NOT_ENOUGH_MEMORY;
  664. }
  665. }
  666. Bufferp->Socket = Socket;
  667. Bufferp->CompletionRoutine = NULL;
  668. Bufferp->Context = Context;
  669. Bufferp->Context2 = Context2;
  670. Contextp = (PNH_CLOSE_BUFFER)Bufferp->Buffer;
  671. Contextp->CloseNotificationRoutine = CloseNotificationRoutine;
  672. Contextp->WaitHandle = NULL;
  673. Contextp->Event = CreateEvent(NULL, FALSE, FALSE, NULL);
  674. if (!Contextp->Event ||
  675. !RegisterWaitForSingleObject(
  676. &Contextp->WaitHandle,
  677. Contextp->Event,
  678. NhpCloseNotificationCallbackRoutine,
  679. Bufferp,
  680. INFINITE,
  681. WT_EXECUTEINIOTHREAD
  682. )) {
  683. Error = GetLastError();
  684. } else {
  685. Error = WSAEventSelect(Socket, Contextp->Event, FD_CLOSE);
  686. if (Error == SOCKET_ERROR) { Error = WSAGetLastError(); }
  687. }
  688. if (Error) {
  689. if (Contextp->WaitHandle) { UnregisterWait(Contextp->WaitHandle); }
  690. if (Contextp->Event) { CloseHandle(Contextp->Event); }
  691. if (LocalBufferp) { NhReleaseBuffer(LocalBufferp); }
  692. if (Component) { DEREFERENCE_COMPONENT(Component); }
  693. }
  694. return Error;
  695. } // NhNotifyOnCloseStreamSocket
  696. VOID NTAPI
  697. NhpCloseNotificationCallbackRoutine(
  698. PVOID Context,
  699. BOOLEAN WaitCompleted
  700. )
  701. /*++
  702. Routine Description:
  703. This routine is invoked upon closure of an accepted connection by the
  704. remote endpoint.
  705. It runs in the context of a thread executing a callback-routine associated
  706. with a wait-handle. The wait-handle is registered for the event-handle
  707. that is passed to 'WSAEventSelect' when connection-acceptance is initiated.
  708. Arguments:
  709. Context - context-field associated with the completed wait
  710. WaitCompleted - indicates whether the wait completed or was timed-out
  711. Return Value:
  712. none.
  713. Environment:
  714. Runs in the context of a system wait thread.
  715. --*/
  716. {
  717. PNH_BUFFER Bufferp = (PNH_BUFFER)Context;
  718. PNH_CLOSE_BUFFER Contextp = (PNH_CLOSE_BUFFER)Bufferp->Buffer;
  719. ULONG Error;
  720. WSANETWORKEVENTS NetworkEvents;
  721. //
  722. // Retrieve the network events for which we're being invoked
  723. // When invoked for 'FD_CLOSE', we unregister the wait since there's
  724. // nothing left to wait for.
  725. //
  726. Bufferp->BytesTransferred = 0;
  727. NetworkEvents.lNetworkEvents = 0;
  728. Error =
  729. WSAEnumNetworkEvents(
  730. Bufferp->Socket, Contextp->Event, &NetworkEvents
  731. );
  732. if (Error || !(NetworkEvents.lNetworkEvents & FD_CLOSE)) {
  733. //
  734. // We couldn't determine which events occurred on the socket,
  735. // so call the notification routine with an error, and fall through
  736. // to the cleanup code below.
  737. //
  738. if (Contextp->CloseNotificationRoutine) {
  739. Contextp->CloseNotificationRoutine(
  740. ERROR_OPERATION_ABORTED, 0, Bufferp
  741. );
  742. }
  743. } else {
  744. //
  745. // A close occurred on the socket, so retrieve the error code,
  746. // invoke the close-notification routine if any, and fall through
  747. // to the cleanup code below.
  748. //
  749. Error = NetworkEvents.iErrorCode[FD_CLOSE_BIT];
  750. if (Contextp->CloseNotificationRoutine) {
  751. Contextp->CloseNotificationRoutine(Error, 0, Bufferp);
  752. }
  753. }
  754. UnregisterWait(Contextp->WaitHandle);
  755. CloseHandle(Contextp->Event);
  756. NhReleaseBuffer(Bufferp);
  757. } // NhpCloseNotificationCallbackRoutine
  758. VOID NTAPI
  759. NhpConnectOrCloseCallbackRoutine(
  760. PVOID Context,
  761. BOOLEAN WaitCompleted
  762. )
  763. /*++
  764. Routine Description:
  765. This routine is invoked by upon completion of a connect-operation
  766. or upon closure of the connection by the remote endpoint.
  767. It runs in the context of a thread executing a callback-routine associated
  768. with a wait-handle. The wait-handle is registered for the event-handle
  769. that is passed to 'WSAEventSelect' when a connection-attempt is initiated.
  770. Arguments:
  771. Context - context-field associated with the completed wait
  772. WaitCompleted - indicates whether the wait completed or was timed-out
  773. Return Value:
  774. none.
  775. Environment:
  776. Runs in the context of a system wait thread.
  777. --*/
  778. {
  779. PNH_BUFFER Bufferp = (PNH_BUFFER)Context;
  780. PNH_CONNECT_BUFFER Contextp = (PNH_CONNECT_BUFFER)Bufferp->Buffer;
  781. ULONG Error;
  782. WSANETWORKEVENTS NetworkEvents;
  783. //
  784. // Retrieve the network events for which we're being invoked
  785. // When invoked for 'FD_CONNECT', we unregister the wait if an error
  786. // occurred. When invoked for 'FD_CLOSE', we unregister the wait
  787. // since there's nothing left to wait for.
  788. //
  789. // In essence, our goal is to guarantee that whatever the success
  790. // or failure or sequence of events on the socket, the connect-completion
  791. // and close-notification routines will both be called for the socket,
  792. // in that order.
  793. //
  794. // N.B. Neither routine is allowed to release the connect-buffer,
  795. // since we may need to preserve it on behalf of the close-notification
  796. // routine, if any.
  797. //
  798. // N.B. We may be invoked with both the 'FD_CONNECT' and 'FD_CLOSE' bits
  799. // set, for instance when the socket is closed. In that case we call
  800. // both routines here.
  801. //
  802. Bufferp->BytesTransferred = 0;
  803. NetworkEvents.lNetworkEvents = 0;
  804. Error =
  805. WSAEnumNetworkEvents(
  806. Bufferp->Socket, Contextp->Event, &NetworkEvents
  807. );
  808. if (Error) {
  809. //
  810. // We couldn't determine which events occurred on the socket,
  811. // so call the routines with errors, and fall through
  812. // to the cleanup code below.
  813. //
  814. if (Bufferp->CompletionRoutine) {
  815. Bufferp->CompletionRoutine(ERROR_OPERATION_ABORTED, 0, Bufferp);
  816. Bufferp->CompletionRoutine = NULL;
  817. }
  818. if (Contextp->CloseNotificationRoutine) {
  819. Contextp->CloseNotificationRoutine(
  820. ERROR_OPERATION_ABORTED, 0, Bufferp
  821. );
  822. }
  823. Contextp->CloseNotificationReceived = TRUE;
  824. } else {
  825. if (NetworkEvents.lNetworkEvents & FD_CONNECT) {
  826. //
  827. // The connect completed, so retrieve the error code and invoke
  828. // the connect-completion routine. If the connect failed,
  829. // we may never receive close-notification (unless the bit
  830. // is already set) so we need to simulate close-notification
  831. // here so that the cleanup code below executes.
  832. //
  833. Error = NetworkEvents.iErrorCode[FD_CONNECT_BIT];
  834. if (Bufferp->CompletionRoutine) {
  835. Bufferp->CompletionRoutine(Error, 0, Bufferp);
  836. Bufferp->CompletionRoutine = NULL;
  837. }
  838. if (Error && !(NetworkEvents.lNetworkEvents & FD_CLOSE)) {
  839. if (Contextp->CloseNotificationRoutine) {
  840. Contextp->CloseNotificationRoutine(Error, 0, Bufferp);
  841. }
  842. Contextp->CloseNotificationReceived = TRUE;
  843. }
  844. }
  845. if (NetworkEvents.lNetworkEvents & FD_CLOSE) {
  846. //
  847. // A close occurred on the socket, so retrieve the error code,
  848. // invoke the close-notification routine if any, and fall through
  849. // to the cleanup code below.
  850. //
  851. Error = NetworkEvents.iErrorCode[FD_CLOSE_BIT];
  852. if (Contextp->CloseNotificationRoutine) {
  853. Contextp->CloseNotificationRoutine(Error, 0, Bufferp);
  854. }
  855. Contextp->CloseNotificationReceived = TRUE;
  856. }
  857. }
  858. //
  859. // If both the connect-completion and close-notification routines have run,
  860. // we are done with this wait-handle and buffer.
  861. //
  862. if (!Bufferp->CompletionRoutine && Contextp->CloseNotificationReceived) {
  863. UnregisterWait(Contextp->WaitHandle);
  864. CloseHandle(Contextp->Event);
  865. NhReleaseBuffer(Bufferp);
  866. }
  867. } // NhpConnectOrCloseCallbackRoutine
  868. VOID
  869. NhpIoCompletionRoutine(
  870. ULONG ErrorCode,
  871. ULONG BytesTransferred,
  872. LPOVERLAPPED Overlapped
  873. )
  874. /*++
  875. Routine Description:
  876. This routine is invoked by the I/O system upon completion of an operation.
  877. Arguments:
  878. ErrorCode - system-supplied error code
  879. BytesTransferred - system-supplied byte-count
  880. Overlapped - caller-supplied context area
  881. Return Value:
  882. none.
  883. Environment:
  884. Runs in the context of an RTUTILS.DLL worker thread.
  885. --*/
  886. {
  887. PNH_BUFFER Bufferp = CONTAINING_RECORD(Overlapped, NH_BUFFER, Overlapped);
  888. NTSTATUS status;
  889. Bufferp->ErrorCode = ErrorCode;
  890. Bufferp->BytesTransferred = BytesTransferred;
  891. Bufferp->CompletionRoutine(
  892. Bufferp->ErrorCode,
  893. Bufferp->BytesTransferred,
  894. Bufferp
  895. );
  896. } // NhpIoCompletionRoutine
  897. VOID APIENTRY
  898. NhpIoWorkerRoutine(
  899. PVOID Context
  900. )
  901. /*++
  902. Routine Description:
  903. This routine is invoked to continue processing of completed I/O
  904. in the context of an alertably waiting thread which does not exit idly.
  905. Arguments:
  906. Context - holds the buffer associated with the completed I/O operation.
  907. Return Value:
  908. none.
  909. Environment:
  910. Runs in the context of an RTUTILS.DLL alertable worker thread.
  911. --*/
  912. {
  913. ((PNH_BUFFER)Context)->CompletionRoutine(
  914. ((PNH_BUFFER)Context)->ErrorCode,
  915. ((PNH_BUFFER)Context)->BytesTransferred,
  916. ((PNH_BUFFER)Context)
  917. );
  918. } // NhpIoWorkerRoutine
  919. VOID
  920. NhQueryAcceptEndpoints(
  921. PUCHAR AcceptBuffer,
  922. PULONG LocalAddress OPTIONAL,
  923. PUSHORT LocalPort OPTIONAL,
  924. PULONG RemoteAddress OPTIONAL,
  925. PUSHORT RemotePort OPTIONAL
  926. )
  927. {
  928. PSOCKADDR_IN LocalSockAddr = NULL;
  929. ULONG LocalLength = sizeof(LocalSockAddr);
  930. PSOCKADDR_IN RemoteSockAddr = NULL;
  931. ULONG RemoteLength = sizeof(RemoteSockAddr);
  932. GetAcceptExSockaddrs(
  933. AcceptBuffer,
  934. 0,
  935. sizeof(SOCKADDR_IN) + 16,
  936. sizeof(SOCKADDR_IN) + 16,
  937. (PSOCKADDR*)&LocalSockAddr,
  938. reinterpret_cast<LPINT>(&LocalLength),
  939. (PSOCKADDR*)&RemoteSockAddr,
  940. (LPINT)&RemoteLength
  941. );
  942. if (LocalAddress && LocalSockAddr) {
  943. *LocalAddress = LocalSockAddr->sin_addr.s_addr;
  944. }
  945. if (LocalPort && LocalSockAddr) {
  946. *LocalPort = LocalSockAddr->sin_port;
  947. }
  948. if (RemoteAddress && RemoteSockAddr) {
  949. *RemoteAddress = RemoteSockAddr->sin_addr.s_addr;
  950. }
  951. if (RemotePort && RemoteSockAddr) {
  952. *RemotePort = RemoteSockAddr->sin_port;
  953. }
  954. } // NhQueryAcceptEndpoints
  955. ULONG
  956. NhQueryAddressSocket(
  957. SOCKET Socket
  958. )
  959. /*++
  960. Routine Description:
  961. This routine is invoked to retrieve the IP address associated with
  962. a socket.
  963. Arguments:
  964. Socket - the socket to be queried
  965. Return Value:
  966. ULONG - the IP address retrieved
  967. --*/
  968. {
  969. SOCKADDR_IN Address;
  970. LONG AddressLength;
  971. AddressLength = sizeof(Address);
  972. getsockname(Socket, (PSOCKADDR)&Address, (int*)&AddressLength);
  973. return Address.sin_addr.s_addr;
  974. } // NhQueryAddressSocket
  975. ULONG
  976. NhQueryLocalEndpointSocket(
  977. SOCKET Socket,
  978. PULONG Address OPTIONAL,
  979. PUSHORT Port
  980. )
  981. {
  982. SOCKADDR_IN SockAddr;
  983. LONG Length;
  984. Length = sizeof(SockAddr);
  985. if (getsockname(Socket, (PSOCKADDR)&SockAddr, (int*)&Length) == SOCKET_ERROR) {
  986. return WSAGetLastError();
  987. }
  988. if (Address) { *Address = SockAddr.sin_addr.s_addr; }
  989. if (Port) { *Port = SockAddr.sin_port; }
  990. return NO_ERROR;
  991. } // NhQueryEndpointSocket
  992. USHORT
  993. NhQueryPortSocket(
  994. SOCKET Socket
  995. )
  996. /*++
  997. Routine Description:
  998. This routine retrieves the port number to which a socket is bound.
  999. Arguments:
  1000. Socket - the socket to be queried
  1001. Return Value:
  1002. USHORT - the port number retrieved
  1003. --*/
  1004. {
  1005. SOCKADDR_IN Address;
  1006. LONG AddressLength;
  1007. AddressLength = sizeof(Address);
  1008. getsockname(Socket, (PSOCKADDR)&Address, (int*)&AddressLength);
  1009. return Address.sin_port;
  1010. } // NhQueryPortSocket
  1011. ULONG
  1012. NhQueryRemoteEndpointSocket(
  1013. SOCKET Socket,
  1014. PULONG Address OPTIONAL,
  1015. PUSHORT Port OPTIONAL
  1016. )
  1017. {
  1018. SOCKADDR_IN SockAddr;
  1019. LONG Length;
  1020. Length = sizeof(SockAddr);
  1021. if (getpeername(Socket, (PSOCKADDR)&SockAddr, (int*)&Length) == SOCKET_ERROR) {
  1022. return WSAGetLastError();
  1023. }
  1024. if (Address) { *Address = SockAddr.sin_addr.s_addr; }
  1025. if (Port) { *Port = SockAddr.sin_port; }
  1026. return NO_ERROR;
  1027. } // NhQueryRemoteEndpointSocket
  1028. ULONG
  1029. NhReadDatagramSocket(
  1030. PCOMPONENT_REFERENCE Component,
  1031. SOCKET Socket,
  1032. PNH_BUFFER Bufferp,
  1033. PNH_COMPLETION_ROUTINE CompletionRoutine,
  1034. PVOID Context,
  1035. PVOID Context2
  1036. )
  1037. /*++
  1038. Routine Description:
  1039. This routine is invoked to read a message from a datagram socket.
  1040. The I/O system invokes the provided 'CompletionRoutine' upon completion
  1041. of the read.
  1042. A reference is made to the given component, if any, if the request is
  1043. submitted successfully. This guarantees the component will not be unloaded
  1044. before the completion routine runs.
  1045. Arguments:
  1046. Component - the component to be referenced for the completion routine
  1047. Socket - the endpoint on which to read a message
  1048. Bufferp - the buffer into which the message should be read,
  1049. or NULL to acquire a new buffer. If no buffer is supplied,
  1050. the resulting message is assumed to fit inside a fixed-length buffer
  1051. CompletionRoutine - the routine to be invoked upon completion of the read
  1052. Context - the context to be associated with the read-request;
  1053. this can be obtained from 'Bufferp->Context' upon completion.
  1054. Context2 - secondary context
  1055. Return Value:
  1056. ULONG - Win32/Winsock2 status code.
  1057. A success code is a guarantee that the completion routine will be invoked.
  1058. Conversely, a failure code is a guarantee that the completion routine will
  1059. not be invoked.
  1060. --*/
  1061. {
  1062. ULONG Error;
  1063. PNH_BUFFER LocalBufferp = NULL;
  1064. WSABUF WsaBuf;
  1065. if (Component) {
  1066. REFERENCE_COMPONENT_OR_RETURN(Component, ERROR_CAN_NOT_COMPLETE);
  1067. }
  1068. if (!Bufferp) {
  1069. Bufferp = LocalBufferp = NhAcquireBuffer();
  1070. if (!Bufferp) {
  1071. NhTrace(
  1072. TRACE_FLAG_SOCKET,
  1073. "NhReadDatagramSocket: error allocating buffer for receive"
  1074. );
  1075. if (Component) { DEREFERENCE_COMPONENT(Component); }
  1076. return ERROR_NOT_ENOUGH_MEMORY;
  1077. }
  1078. }
  1079. ZeroMemory(&Bufferp->Overlapped, sizeof(Bufferp->Overlapped));
  1080. Bufferp->Socket = Socket;
  1081. Bufferp->ReceiveFlags = 0;
  1082. Bufferp->CompletionRoutine = CompletionRoutine;
  1083. Bufferp->Context = Context;
  1084. Bufferp->Context2 = Context2;
  1085. Bufferp->AddressLength = sizeof(Bufferp->ReadAddress);
  1086. WsaBuf.buf = reinterpret_cast<char*>(Bufferp->Buffer);
  1087. WsaBuf.len = NH_BUFFER_SIZE;
  1088. Error =
  1089. WSARecvFrom(
  1090. Socket,
  1091. &WsaBuf,
  1092. 1,
  1093. &UnusedBytesTransferred,
  1094. &Bufferp->ReceiveFlags,
  1095. (PSOCKADDR)&Bufferp->ReadAddress,
  1096. (LPINT)&Bufferp->AddressLength,
  1097. &Bufferp->Overlapped,
  1098. NULL
  1099. );
  1100. if (Error == SOCKET_ERROR &&
  1101. (Error = WSAGetLastError()) == WSA_IO_PENDING) {
  1102. Error = NO_ERROR;
  1103. } else if (Error) {
  1104. if (Component) { DEREFERENCE_COMPONENT(Component); }
  1105. if (LocalBufferp) { NhReleaseBuffer(LocalBufferp); }
  1106. NhTrace(
  1107. TRACE_FLAG_SOCKET,
  1108. "NhReadDatagramSocket: error %d returned by 'WSARecvFrom'", Error
  1109. );
  1110. }
  1111. return Error;
  1112. } // NhReadDatagramSocket
  1113. ULONG
  1114. NhReadStreamSocket(
  1115. PCOMPONENT_REFERENCE Component,
  1116. SOCKET Socket,
  1117. PNH_BUFFER Bufferp,
  1118. ULONG Length,
  1119. ULONG Offset,
  1120. PNH_COMPLETION_ROUTINE CompletionRoutine,
  1121. PVOID Context,
  1122. PVOID Context2
  1123. )
  1124. /*++
  1125. Routine Description:
  1126. This routine is invoked to read a message from a stream socket.
  1127. The I/O system invokes the provided 'CompletionRoutine' upon completion
  1128. of the read.
  1129. A reference is made to the given component, if any, if the request is
  1130. submitted successfully. This guarantees the component will not be unloaded
  1131. before the completion routine runs.
  1132. Arguments:
  1133. Component - the component to be referenced for the completion routine
  1134. Socket - the endpoint on which to read a message
  1135. Bufferp - the buffer into which the message should be read,
  1136. or NULL to acquire a new buffer
  1137. Length - the maximum number of bytes to be read
  1138. Offset - the offset into the buffer at which the read should begin,
  1139. valid only if 'Bufferp' is provided.
  1140. CompletionRoutine - the routine to be invoked upon completion of the read
  1141. Context - the context to be associated with the read-request;
  1142. this can be obtained from 'Bufferp->Context' upon completion.
  1143. Context2 - secondary context
  1144. Return Value:
  1145. ULONG - Win32/Winsock2 status code.
  1146. A success code is a guarantee that the completion routine will be invoked.
  1147. Conversely, a failure code is a guarantee that the completion routine will
  1148. not be invoked.
  1149. --*/
  1150. {
  1151. ULONG Error;
  1152. PNH_BUFFER LocalBufferp = NULL;
  1153. WSABUF WsaBuf;
  1154. if (Component) {
  1155. REFERENCE_COMPONENT_OR_RETURN(Component, ERROR_CAN_NOT_COMPLETE);
  1156. }
  1157. if (!Bufferp) {
  1158. Offset = 0;
  1159. Bufferp = LocalBufferp = NhAcquireVariableLengthBuffer(Length);
  1160. if (!Bufferp) {
  1161. NhTrace(
  1162. TRACE_FLAG_SOCKET,
  1163. "NhReadStreamSocket: error allocating buffer for receive"
  1164. );
  1165. if (Component) { DEREFERENCE_COMPONENT(Component); }
  1166. return ERROR_NOT_ENOUGH_MEMORY;
  1167. }
  1168. }
  1169. ZeroMemory(&Bufferp->Overlapped, sizeof(Bufferp->Overlapped));
  1170. Bufferp->Socket = Socket;
  1171. Bufferp->ReceiveFlags = 0;
  1172. Bufferp->CompletionRoutine = CompletionRoutine;
  1173. Bufferp->Context = Context;
  1174. Bufferp->Context2 = Context2;
  1175. #if 1
  1176. if (ReadFile(
  1177. (HANDLE)Bufferp->Socket,
  1178. Bufferp->Buffer + Offset,
  1179. Length,
  1180. &UnusedBytesTransferred,
  1181. &Bufferp->Overlapped
  1182. ) ||
  1183. (Error = GetLastError()) == ERROR_IO_PENDING) {
  1184. Error = NO_ERROR;
  1185. } else {
  1186. if (Component) { DEREFERENCE_COMPONENT(Component); }
  1187. if (LocalBufferp) { NhReleaseBuffer(LocalBufferp); }
  1188. NhTrace(
  1189. TRACE_FLAG_SOCKET,
  1190. "NhReadStreamSocket: error %d returned by 'ReadFile'", Error
  1191. );
  1192. }
  1193. #else
  1194. WsaBuf.buf = Bufferp->Buffer + Offset;
  1195. WsaBuf.len = Length;
  1196. Error =
  1197. WSARecv(
  1198. Socket,
  1199. &WsaBuf,
  1200. 1,
  1201. &UnusedBytesTransferred,
  1202. &Bufferp->ReceiveFlags,
  1203. &Bufferp->Overlapped,
  1204. NULL
  1205. );
  1206. if (Error == SOCKET_ERROR &&
  1207. (Error = WSAGetLastError()) == WSA_IO_PENDING) {
  1208. Error = NO_ERROR;
  1209. } else if (Error) {
  1210. if (Component) { DEREFERENCE_COMPONENT(Component); }
  1211. if (LocalBufferp) { NhReleaseBuffer(LocalBufferp); }
  1212. NhTrace(
  1213. TRACE_FLAG_SOCKET,
  1214. "NhReadStreamSocket: error %d returned by 'WSARecv'", Error
  1215. );
  1216. }
  1217. #endif
  1218. return Error;
  1219. } // NhReadStreamSocket
  1220. ULONG
  1221. NhWriteDatagramSocket(
  1222. PCOMPONENT_REFERENCE Component,
  1223. SOCKET Socket,
  1224. ULONG Address,
  1225. USHORT Port,
  1226. PNH_BUFFER Bufferp,
  1227. ULONG Length,
  1228. PNH_COMPLETION_ROUTINE CompletionRoutine,
  1229. PVOID Context,
  1230. PVOID Context2
  1231. )
  1232. /*++
  1233. Routine Description:
  1234. This routine is invoked to send a message on a datagram socket.
  1235. A reference is made to the given component, if any, if the request is
  1236. submitted successfully. This guarantees the component will not be unloaded
  1237. before the completion routine runs.
  1238. Arguments:
  1239. Component - the component to be referenced for the completion routine
  1240. Socket - the socket on which to send the message
  1241. Address - the address of the message's destination
  1242. Port - the port of the message's destination
  1243. Bufferp - the buffer containing the message to be sent
  1244. Length - the number of bytes to transfer
  1245. CompletionRoutine - the routine to be invoked upon completion of the send
  1246. Context - passed to the 'CompletionRoutine' upon completion of the send
  1247. Context2 - secondary context
  1248. Return Value:
  1249. ULONG - Win32/Winsock2 status code
  1250. A success code is a guarantee that the completion routine will be invoked.
  1251. Conversely, a failure code is a guarantee that the completion routine will
  1252. not be invoked.
  1253. --*/
  1254. {
  1255. LONG AddressLength;
  1256. ULONG Error;
  1257. WSABUF WsaBuf;
  1258. if (Component) {
  1259. REFERENCE_COMPONENT_OR_RETURN(Component, ERROR_CAN_NOT_COMPLETE);
  1260. }
  1261. ZeroMemory(&Bufferp->Overlapped, sizeof(Bufferp->Overlapped));
  1262. Bufferp->Socket = Socket;
  1263. Bufferp->CompletionRoutine = CompletionRoutine;
  1264. Bufferp->Context = Context;
  1265. Bufferp->Context2 = Context2;
  1266. Bufferp->WriteAddress.sin_family = AF_INET;
  1267. Bufferp->WriteAddress.sin_addr.s_addr = Address;
  1268. Bufferp->WriteAddress.sin_port = Port;
  1269. AddressLength = sizeof(Bufferp->WriteAddress);
  1270. WsaBuf.buf = reinterpret_cast<char*>(Bufferp->Buffer);
  1271. WsaBuf.len = Length;
  1272. Error =
  1273. WSASendTo(
  1274. Socket,
  1275. &WsaBuf,
  1276. 1,
  1277. &UnusedBytesTransferred,
  1278. 0,
  1279. (PSOCKADDR)&Bufferp->WriteAddress,
  1280. AddressLength,
  1281. &Bufferp->Overlapped,
  1282. NULL
  1283. );
  1284. if (Error == SOCKET_ERROR &&
  1285. (Error = WSAGetLastError()) == WSA_IO_PENDING) {
  1286. Error = NO_ERROR;
  1287. } else if (Error) {
  1288. NhTrace(
  1289. TRACE_FLAG_SOCKET,
  1290. "NhWriteDatagramSocket: error %d returned by 'WSASendTo'", Error
  1291. );
  1292. if (Component) { DEREFERENCE_COMPONENT(Component); }
  1293. }
  1294. return Error;
  1295. } // NhWriteDatagramSocket
  1296. ULONG
  1297. NhWriteStreamSocket(
  1298. PCOMPONENT_REFERENCE Component,
  1299. SOCKET Socket,
  1300. PNH_BUFFER Bufferp,
  1301. ULONG Length,
  1302. ULONG Offset,
  1303. PNH_COMPLETION_ROUTINE CompletionRoutine,
  1304. PVOID Context,
  1305. PVOID Context2
  1306. )
  1307. /*++
  1308. Routine Description:
  1309. This routine is invoked to send a message on a stream socket.
  1310. A reference is made to the given component, if any, if the request is
  1311. submitted successfully. This guarantees the component will not be unloaded
  1312. before the completion routine runs.
  1313. Arguments:
  1314. Component - the component to be referenced for the completion routine
  1315. Socket - the socket on which to send the message
  1316. Bufferp - the buffer containing the message to be sent
  1317. Length - the number of bytes to transfer
  1318. Offset - the offset into the buffer at which the data to be sent begins
  1319. CompletionRoutine - the routine to be invoked upon completion of the send
  1320. Context - passed to the 'CompletionRoutine' upon completion of the send
  1321. Context2 - secondary context
  1322. Return Value:
  1323. ULONG - Win32/Winsock2 status code
  1324. A success code is a guarantee that the completion routine will be invoked.
  1325. Conversely, a failure code is a guarantee that the completion routine will
  1326. not be invoked.
  1327. --*/
  1328. {
  1329. ULONG Error;
  1330. WSABUF WsaBuf;
  1331. if (Component) {
  1332. REFERENCE_COMPONENT_OR_RETURN(Component, ERROR_CAN_NOT_COMPLETE);
  1333. }
  1334. ZeroMemory(&Bufferp->Overlapped, sizeof(Bufferp->Overlapped));
  1335. Bufferp->Socket = Socket;
  1336. Bufferp->CompletionRoutine = CompletionRoutine;
  1337. Bufferp->Context = Context;
  1338. Bufferp->Context2 = Context2;
  1339. #if 1
  1340. if (WriteFile(
  1341. (HANDLE)Bufferp->Socket,
  1342. Bufferp->Buffer + Offset,
  1343. Length,
  1344. &UnusedBytesTransferred,
  1345. &Bufferp->Overlapped
  1346. ) ||
  1347. (Error = GetLastError()) == ERROR_IO_PENDING) {
  1348. Error = NO_ERROR;
  1349. } else {
  1350. NhTrace(
  1351. TRACE_FLAG_SOCKET,
  1352. "NhWriteStreamSocket: error %d returned by 'WriteFile'", Error
  1353. );
  1354. if (Component) { DEREFERENCE_COMPONENT(Component); }
  1355. }
  1356. #else
  1357. WsaBuf.buf = Bufferp->Buffer + Offset;
  1358. WsaBuf.len = Length;
  1359. Error =
  1360. WSASend(
  1361. Socket,
  1362. &WsaBuf,
  1363. 1,
  1364. &UnusedBytesTransferred,
  1365. 0,
  1366. &Bufferp->Overlapped,
  1367. NULL
  1368. );
  1369. if (Error == SOCKET_ERROR &&
  1370. (Error = WSAGetLastError()) == WSA_IO_PENDING) {
  1371. Error = NO_ERROR;
  1372. } else if (Error) {
  1373. NhTrace(
  1374. TRACE_FLAG_SOCKET,
  1375. "NhWriteStreamSocket: error %d returned by 'WSASend'", Error
  1376. );
  1377. if (Component) { DEREFERENCE_COMPONENT(Component); }
  1378. }
  1379. #endif
  1380. return Error;
  1381. } // NhWriteStreamSocket