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.

1116 lines
28 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. --*/
  16. #include "precomp.h"
  17. #pragma hdrstop
  18. #include <stdio.h>
  19. extern bool g_bStoping;
  20. #if DBG
  21. ULONG MyHelperpReadCount = 0;
  22. #endif
  23. ULONG UnusedBytesTransferred;
  24. typedef struct _NH_CONNECT_BUFFER {
  25. HANDLE Event;
  26. HANDLE WaitHandle;
  27. } NH_CONNECT_BUFFER, *PNH_CONNECT_BUFFER;
  28. //
  29. // FORWARD DECLARATIONS
  30. //
  31. VOID NTAPI
  32. MyHelperpConnectCallbackRoutine(
  33. PVOID Context,
  34. BOOLEAN WaitCompleted
  35. );
  36. VOID WINAPI
  37. MyHelperpIoCompletionRoutine(
  38. ULONG ErrorCode,
  39. ULONG BytesTransferred,
  40. LPOVERLAPPED Overlapped
  41. );
  42. VOID APIENTRY
  43. MyHelperpIoWorkerRoutine(
  44. PVOID Context
  45. );
  46. ULONG
  47. MyHelperAcceptStreamSocket(
  48. PCOMPONENT_REFERENCE Component,
  49. SOCKET ListeningSocket,
  50. SOCKET AcceptedSocket OPTIONAL,
  51. PNH_BUFFER Bufferp,
  52. PNH_COMPLETION_ROUTINE AcceptCompletionRoutine,
  53. PVOID Context,
  54. PVOID Context2
  55. )
  56. /*++
  57. Routine Description:
  58. This routine is invoked to accept an incoming connection-request
  59. on a listening stream socket using 'AcceptEx'. The I/O system invokes
  60. the provided 'CompletionRoutine' upon completion of the read.
  61. It is the completion-routine's responsibility to use 'setsockopt' to
  62. set the SO_UPDATE_ACCEPT_CONTEXT option on the accepted socket before
  63. the accepted socket can be used with Winsock2 routines.
  64. A reference is made to the given component, if any, if the request is
  65. submitted successfully. This guarantees the component will not be unloaded
  66. before the completion routine runs.
  67. Arguments:
  68. Component - the component to be referenced for the completion routine
  69. ListeningSocket - the endpoint that is listening for connection-requests
  70. AcceptedSocket - the endpoint to be assigned a connection-request,
  71. or INVALID_SOCKET to create a new endpoint
  72. Bufferp - the buffer to be used for asynchronous completion
  73. or NULL to acquire a new buffer
  74. AcceptCompletionRoutine - the routine to be invoked upon completion
  75. Context - the context to be associated with the accept-request;
  76. this can be obtained from 'Bufferp->Context' upon completion.
  77. Context2 - secondary context
  78. Return Value:
  79. ULONG - Win32/Winsock2 status code.
  80. A success code is a guarantee that the accept-completion routine
  81. will be invoked.
  82. Conversely, a failure code is a guarantee that the routine will not
  83. be invoked.
  84. --*/
  85. {
  86. ULONG Error;
  87. PNH_BUFFER LocalBufferp = NULL;
  88. SOCKET LocalSocket = INVALID_SOCKET;
  89. if (Component) {
  90. REFERENCE_COMPONENT_OR_RETURN(Component, ERROR_CAN_NOT_COMPLETE);
  91. }
  92. if (!Bufferp) {
  93. Bufferp = LocalBufferp = MyHelperAcquireBuffer();
  94. if (!Bufferp) {
  95. //MyHelperTrace(TRACE_FLAG_SOCKET, "error allocating buffer for accept");
  96. if (Component) { DEREFERENCE_COMPONENT(Component); }
  97. return ERROR_NOT_ENOUGH_MEMORY;
  98. }
  99. }
  100. if (AcceptedSocket == INVALID_SOCKET) {
  101. Error = MyHelperCreateStreamSocket(INADDR_NONE, 0, &LocalSocket);
  102. if (Error) {
  103. //MyHelperTrace(
  104. //TRACE_FLAG_SOCKET, "error %d creating socket for accept", Error
  105. //);
  106. if (LocalBufferp) { MyHelperReleaseBuffer(LocalBufferp); }
  107. if (Component) { DEREFERENCE_COMPONENT(Component); }
  108. return ERROR_NOT_ENOUGH_MEMORY;
  109. }
  110. AcceptedSocket = LocalSocket;
  111. }
  112. ZeroMemory(&Bufferp->Overlapped, sizeof(Bufferp->Overlapped));
  113. Bufferp->Socket = AcceptedSocket;
  114. Bufferp->CompletionRoutine = AcceptCompletionRoutine;
  115. Bufferp->Context = Context;
  116. Bufferp->Context2 = Context2;
  117. if ( !g_bStoping &&
  118. AcceptEx(
  119. ListeningSocket,
  120. AcceptedSocket,
  121. Bufferp->Buffer,
  122. 0,
  123. sizeof(SOCKADDR_IN) + 16,
  124. sizeof(SOCKADDR_IN) + 16,
  125. &UnusedBytesTransferred,
  126. &Bufferp->Overlapped
  127. ))
  128. {
  129. Error = NO_ERROR;
  130. }
  131. else
  132. {
  133. if ((Error = WSAGetLastError()) == ERROR_IO_PENDING) {
  134. Error = NO_ERROR;
  135. } else if (Error) {
  136. if (LocalSocket != INVALID_SOCKET) {
  137. MyHelperDeleteStreamSocket(LocalSocket);
  138. }
  139. if (LocalBufferp) { MyHelperReleaseBuffer(LocalBufferp); }
  140. if (Component) { DEREFERENCE_COMPONENT(Component); }
  141. //MyHelperTrace(
  142. //TRACE_FLAG_SOCKET, "error %d returned by 'AcceptEx'", Error
  143. //);
  144. }
  145. }
  146. return Error;
  147. } // MyHelperAcceptStreamSocket
  148. ULONG
  149. MyHelperConnectStreamSocket(
  150. PCOMPONENT_REFERENCE Component,
  151. SOCKET ConnectingSocket,
  152. ULONG Address,
  153. USHORT Port,
  154. PNH_BUFFER Bufferp OPTIONAL,
  155. PNH_COMPLETION_ROUTINE ConnectCompletionRoutine,
  156. PVOID Context,
  157. PVOID Context2
  158. )
  159. /*++
  160. Routine Description:
  161. This routine is invoked to establish a connection using a stream socket.
  162. A reference is made to the given component, if any, if the request is
  163. submitted successfully. This guarantees the component will not be unloaded
  164. before the completion routine runs.
  165. Since Windows Sockets does not deliver connect-notifications to
  166. I/O completion ports, we need to make some special arrangements in order
  167. to notify the caller's completion routine the way we do for send-requests
  168. and receive-requests. Specifically, we create an event-handle and
  169. request connect-notification on it by calling 'WSAEventSelect'.
  170. We then register a wait on the event-handle, specifying a private
  171. completion routine. (See 'MyHelperpConnectCallbackRoutine'.)
  172. When this completion routine runs, it extracts the status code of the
  173. connection-attempt using 'WSAEnumNetworkEvents'. It then passes the status
  174. along with the usual parameters to the caller's completion routine.
  175. N.B. The buffer supplied to this routine may not be released by
  176. the connect-completion routine.
  177. (See 'MyHelperpConnectCallbackRoutine' for more information.)
  178. Arguments:
  179. Component - the component to be referenced for the completion routine
  180. Socket - the socket with which to establish a connection
  181. Address - the IP address of the remote endpoint
  182. Port - the port number of the remote endpoint
  183. Bufferp - optionally supplies the buffer to be used to hold context
  184. during the connection-attempt
  185. ConnectCompletionRoutine - a routine to be invoked upon completion
  186. of the connect-attempt
  187. Context - passed to the 'ConnectCompletionRoutine'
  188. Context2 - secondary context
  189. Return Value:
  190. ULONG - Win32/Winsock2 status code
  191. A success code is a guarantee that the connect-completion routine,
  192. if supplied, will be invoked.
  193. Conversely, a failure code is a guarantee that the neither routine will
  194. be invoked.
  195. --*/
  196. {
  197. MYTRACE_ENTER("ALGFTP:MyHelperConnectStreamSocket");
  198. ULONG nSourceAddress;
  199. USHORT nSourcePort;
  200. MyHelperQueryLocalEndpointSocket(ConnectingSocket,&nSourceAddress,&nSourcePort);
  201. MYTRACE("From Source %s:%d", MYTRACE_IP(nSourceAddress), ntohs(nSourcePort) );
  202. MYTRACE("To Destination %s:%d", MYTRACE_IP(Address), ntohs(Port) );
  203. PNH_CONNECT_BUFFER Contextp;
  204. ULONG Error;
  205. PNH_BUFFER LocalBufferp = NULL;
  206. if (Component) {
  207. REFERENCE_COMPONENT_OR_RETURN(Component, ERROR_CAN_NOT_COMPLETE);
  208. }
  209. if (!Bufferp) {
  210. Bufferp = LocalBufferp = MyHelperAcquireBuffer();
  211. if (!Bufferp) {
  212. //MyHelperTrace(
  213. //TRACE_FLAG_SOCKET,
  214. //"MyHelperConnectStreamSocket: error allocating buffer for connect"
  215. //);
  216. if (Component) { DEREFERENCE_COMPONENT(Component); }
  217. return ERROR_NOT_ENOUGH_MEMORY;
  218. }
  219. }
  220. Bufferp->Socket = ConnectingSocket;
  221. Bufferp->ReceiveFlags = 0;
  222. Bufferp->CompletionRoutine = ConnectCompletionRoutine;
  223. Bufferp->Context = Context;
  224. Bufferp->Context2 = Context2;
  225. Bufferp->ConnectAddress.sin_family = AF_INET;
  226. Bufferp->ConnectAddress.sin_addr.s_addr = Address;
  227. Bufferp->ConnectAddress.sin_port = Port;
  228. Contextp = (PNH_CONNECT_BUFFER)Bufferp->Buffer;
  229. Contextp->WaitHandle = NULL;
  230. Contextp->Event = CreateEvent(NULL, FALSE, FALSE, NULL);
  231. if (!Contextp->Event ||
  232. !RegisterWaitForSingleObject(
  233. &Contextp->WaitHandle,
  234. Contextp->Event,
  235. MyHelperpConnectCallbackRoutine,
  236. Bufferp,
  237. INFINITE,
  238. WT_EXECUTEINIOTHREAD
  239. )) {
  240. Error = GetLastError();
  241. } else {
  242. ULONG EventsSelected = FD_CONNECT;
  243. Error =
  244. WSAEventSelect(
  245. ConnectingSocket, Contextp->Event, EventsSelected
  246. );
  247. if (Error == SOCKET_ERROR) {
  248. Error = WSAGetLastError();
  249. } else {
  250. Error =
  251. WSAConnect(
  252. ConnectingSocket,
  253. (PSOCKADDR)&Bufferp->ConnectAddress,
  254. sizeof(Bufferp->ConnectAddress),
  255. NULL,
  256. NULL,
  257. NULL,
  258. NULL
  259. );
  260. }
  261. }
  262. if (Error == SOCKET_ERROR &&
  263. (Error = WSAGetLastError()) == WSAEWOULDBLOCK) {
  264. Error = NO_ERROR;
  265. } else if (Error) {
  266. if (Contextp->WaitHandle) { UnregisterWait(Contextp->WaitHandle); }
  267. if (Contextp->Event) { CloseHandle(Contextp->Event); }
  268. if (LocalBufferp) { MyHelperReleaseBuffer(LocalBufferp); }
  269. if (Component) { DEREFERENCE_COMPONENT(Component); }
  270. }
  271. return Error;
  272. } // MyHelperConnectStreamSocket
  273. ULONG
  274. MyHelperCreateStreamSocket(
  275. ULONG Address OPTIONAL,
  276. USHORT Port OPTIONAL,
  277. OUT SOCKET* Socketp
  278. )
  279. /*++
  280. Routine Description:
  281. This routine is invoked to create and initialize a stream socket.
  282. The socket will also be bound to a local IP address and port,
  283. unless none is specified.
  284. Arguments:
  285. Address - the local IP address to which the new socket should be bound,
  286. or INADDR_ANY to allow the system to leave the IP address unspecified,
  287. or INADDR_NONE if the socket should not be bound at all.
  288. Port - the port number to which the new socket should be bound,
  289. or 0 if to allow the system to select a port number.
  290. Socketp - receives initialized socket
  291. Return Value:
  292. ULONG - Win32/Winsock2 status code.
  293. --*/
  294. {
  295. MYTRACE_ENTER("AlgFTP:MyHelperCreateStreamSocket");
  296. MYTRACE("Address %s:%d", MYTRACE_IP(Address), ntohs(Port));
  297. ULONG Error;
  298. ULONG Option;
  299. SOCKET Socket;
  300. SOCKADDR_IN SocketAddress;
  301. do {
  302. //
  303. // Create a new stream socket.
  304. //
  305. Socket =
  306. WSASocket(
  307. AF_INET, SOCK_STREAM, IPPROTO_TCP, NULL, 0, WSA_FLAG_OVERLAPPED
  308. );
  309. if (Socket == INVALID_SOCKET)
  310. {
  311. Error = WSAGetLastError();
  312. MYTRACE_ERROR("from WSASocket", Error);
  313. break;
  314. }
  315. //
  316. // Associate the socket with our I/O completion port
  317. //
  318. BindIoCompletionCallback((HANDLE)Socket, MyHelperpIoCompletionRoutine, 0);
  319. //
  320. // Disable send and receive buffering in AFD,
  321. // since we will be operating asynchronously with a receive-buffer
  322. // (almost) always outstanding, and since in any case we want
  323. // TCP/IP's flow-control to limit the sender's sending rate properly.
  324. //
  325. Option = 0;
  326. setsockopt(
  327. Socket,
  328. SOL_SOCKET,
  329. SO_SNDBUF,
  330. (PCHAR)&Option,
  331. sizeof(Option)
  332. );
  333. Option = 0;
  334. setsockopt(
  335. Socket,
  336. SOL_SOCKET,
  337. SO_SNDBUF,
  338. (PCHAR)&Option,
  339. sizeof(Option)
  340. );
  341. //
  342. // If the caller has requested that the socket be bound by specifying
  343. // a local IP address, bind the socket now.
  344. //
  345. if (Address != INADDR_NONE) {
  346. SocketAddress.sin_family = AF_INET;
  347. SocketAddress.sin_port = Port;
  348. SocketAddress.sin_addr.s_addr = Address;
  349. Error =
  350. bind(Socket, (PSOCKADDR)&SocketAddress, sizeof(SocketAddress));
  351. if (Error == SOCKET_ERROR)
  352. {
  353. Error = WSAGetLastError();
  354. MYTRACE_ERROR("from BIND", Error);
  355. break;
  356. }
  357. }
  358. //
  359. // Store the new socket in the caller's output-parameter, and return.
  360. //
  361. *Socketp = Socket;
  362. return NO_ERROR;
  363. } while(FALSE);
  364. if (Socket != INVALID_SOCKET) { closesocket(Socket); }
  365. return Error;
  366. } // MyHelperCreateStreamSocket
  367. VOID
  368. MyHelperDeleteSocket(
  369. SOCKET Socket
  370. )
  371. /*++
  372. Routine Description:
  373. This routine releases network resources for a socket.
  374. Arguments:
  375. Socket - the socket to be deleted
  376. Return Value:
  377. none.
  378. --*/
  379. {
  380. if (Socket != INVALID_SOCKET) { closesocket(Socket); }
  381. } // MyHelperDeleteSocket
  382. VOID NTAPI
  383. MyHelperpConnectCallbackRoutine(
  384. PVOID Context,
  385. BOOLEAN WaitCompleted
  386. )
  387. /*++
  388. Routine Description:
  389. This routine is invoked by upon completion of a connect-operation
  390. or upon closure of the connection by the remote endpoint.
  391. It runs in the context of a thread executing a callback-routine associated
  392. with a wait-handle. The wait-handle is registered for the event-handle
  393. that is passed to 'WSAEventSelect' when a connection-attempt is initiated.
  394. Arguments:
  395. Context - context-field associated with the completed wait
  396. WaitCompleted - indicates whether the wait completed or was timed-out
  397. Return Value:
  398. none.
  399. Environment:
  400. Runs in the context of a system wait thread.
  401. --*/
  402. {
  403. PNH_BUFFER Bufferp = (PNH_BUFFER)Context;
  404. PNH_CONNECT_BUFFER Contextp = (PNH_CONNECT_BUFFER)Bufferp->Buffer;
  405. ULONG Error;
  406. WSANETWORKEVENTS NetworkEvents;
  407. //
  408. // Retrieve the network events for which we're being invoked
  409. // When invoked for 'FD_CONNECT', we unregister the wait if an error
  410. // occurred.
  411. //
  412. // In essence, our goal is to guarantee that whatever the success
  413. // or failure or sequence of events on the socket, the connect-completion
  414. // routines will be called for the socket,
  415. //
  416. // N.B. routine is not allowed to release the connect-buffer,
  417. // since we will free it
  418. //
  419. //
  420. Bufferp->BytesTransferred = 0;
  421. NetworkEvents.lNetworkEvents = 0;
  422. PNH_COMPLETION_ROUTINE CallbackConnectCompletion = Bufferp->CompletionRoutine;
  423. if ( CallbackConnectCompletion )
  424. {
  425. Bufferp->CompletionRoutine = NULL;
  426. if ( g_bStoping )
  427. {
  428. Error = ERROR_OPERATION_ABORTED;
  429. }
  430. else
  431. {
  432. Error = WSAEnumNetworkEvents(Bufferp->Socket, Contextp->Event, &NetworkEvents);
  433. if ( Error )
  434. {
  435. //
  436. // We couldn't determine which events occurred on the socket,
  437. // so call the routines with errors, and fall through
  438. // to the cleanup code below.
  439. //
  440. Error = ERROR_OPERATION_ABORTED;
  441. }
  442. else
  443. {
  444. if ( NetworkEvents.lNetworkEvents & FD_CONNECT )
  445. {
  446. Error = NetworkEvents.iErrorCode[FD_CONNECT_BIT];
  447. }
  448. else
  449. {
  450. //
  451. // Not sure what even was sent to US we only requested FD_CONNECT so treat this as an error
  452. //
  453. Error = ERROR_OPERATION_ABORTED;
  454. }
  455. }
  456. }
  457. //
  458. // We are about to call the User Completion routine
  459. // but to insure that the buffer is freed and that any event the
  460. // CompletionRoutine generates (Shutdown the process) and we did not have time to free
  461. // we will free now and call
  462. //
  463. PNH_BUFFER pUserContext = (PNH_BUFFER)Bufferp->Context;
  464. UnregisterWait(Contextp->WaitHandle);
  465. CloseHandle(Contextp->Event);
  466. MyHelperReleaseBuffer(Bufferp);
  467. //
  468. // Now call the UserCallback routine
  469. //
  470. if ( CallbackConnectCompletion )
  471. {
  472. CallbackConnectCompletion(Error, 0, pUserContext);
  473. }
  474. }
  475. else
  476. {
  477. //
  478. // The completion routine was call and resource freed previously
  479. // and now we are getting a EVENT that we never solicitated.
  480. //
  481. }
  482. } // MyHelperpConnectCallbackRoutine
  483. VOID
  484. MyHelperpIoCompletionRoutine(
  485. ULONG ErrorCode,
  486. ULONG BytesTransferred,
  487. LPOVERLAPPED Overlapped
  488. )
  489. /*++
  490. Routine Description:
  491. This routine is invoked by the I/O system upon completion of an operation.
  492. Arguments:
  493. ErrorCode - system-supplied error code
  494. BytesTransferred - system-supplied byte-count
  495. Overlapped - caller-supplied context area
  496. Return Value:
  497. none.
  498. Environment:
  499. Runs in the context of an RTUTILS.DLL worker thread.
  500. --*/
  501. {
  502. PNH_BUFFER Bufferp = CONTAINING_RECORD(Overlapped, NH_BUFFER, Overlapped);
  503. Bufferp->ErrorCode = ErrorCode;
  504. Bufferp->BytesTransferred = BytesTransferred;
  505. Bufferp->CompletionRoutine(
  506. Bufferp->ErrorCode,
  507. Bufferp->BytesTransferred,
  508. Bufferp
  509. );
  510. } // MyHelperpIoCompletionRoutine
  511. VOID APIENTRY
  512. MyHelperpIoWorkerRoutine(
  513. PVOID Context
  514. )
  515. /*++
  516. Routine Description:
  517. This routine is invoked to continue processing of completed I/O
  518. in the context of an alertably waiting thread which does not exit idly.
  519. Arguments:
  520. Context - holds the buffer associated with the completed I/O operation.
  521. Return Value:
  522. none.
  523. Environment:
  524. Runs in the context of an RTUTILS.DLL alertable worker thread.
  525. --*/
  526. {
  527. ((PNH_BUFFER)Context)->CompletionRoutine(
  528. ((PNH_BUFFER)Context)->ErrorCode,
  529. ((PNH_BUFFER)Context)->BytesTransferred,
  530. ((PNH_BUFFER)Context)
  531. );
  532. } // MyHelperpIoWorkerRoutine
  533. VOID
  534. MyHelperQueryAcceptEndpoints(
  535. PUCHAR AcceptBuffer,
  536. PULONG LocalAddress OPTIONAL,
  537. PUSHORT LocalPort OPTIONAL,
  538. PULONG RemoteAddress OPTIONAL,
  539. PUSHORT RemotePort OPTIONAL
  540. )
  541. {
  542. PSOCKADDR_IN LocalSockAddr = NULL;
  543. ULONG LocalLength = sizeof(LocalSockAddr);
  544. PSOCKADDR_IN RemoteSockAddr = NULL;
  545. ULONG RemoteLength = sizeof(RemoteSockAddr);
  546. GetAcceptExSockaddrs(
  547. AcceptBuffer,
  548. 0,
  549. sizeof(SOCKADDR_IN) + 16,
  550. sizeof(SOCKADDR_IN) + 16,
  551. (PSOCKADDR*)&LocalSockAddr,
  552. reinterpret_cast<LPINT>(&LocalLength),
  553. (PSOCKADDR*)&RemoteSockAddr,
  554. (LPINT)&RemoteLength
  555. );
  556. if (LocalAddress && LocalSockAddr) {
  557. *LocalAddress = LocalSockAddr->sin_addr.s_addr;
  558. }
  559. if (LocalPort && LocalSockAddr) {
  560. *LocalPort = LocalSockAddr->sin_port;
  561. }
  562. if (RemoteAddress && RemoteSockAddr) {
  563. *RemoteAddress = RemoteSockAddr->sin_addr.s_addr;
  564. }
  565. if (RemotePort && RemoteSockAddr) {
  566. *RemotePort = RemoteSockAddr->sin_port;
  567. }
  568. } // MyHelperQueryAcceptEndpoints
  569. ULONG
  570. MyHelperQueryAddressSocket(
  571. SOCKET Socket
  572. )
  573. /*++
  574. Routine Description:
  575. This routine is invoked to retrieve the IP address associated with
  576. a socket.
  577. Arguments:
  578. Socket - the socket to be queried
  579. Return Value:
  580. ULONG - the IP address retrieved
  581. --*/
  582. {
  583. SOCKADDR_IN Address;
  584. LONG AddressLength;
  585. AddressLength = sizeof(Address);
  586. getsockname(Socket, (PSOCKADDR)&Address, (int*)&AddressLength);
  587. return Address.sin_addr.s_addr;
  588. } // MyHelperQueryAddressSocket
  589. ULONG
  590. MyHelperQueryLocalEndpointSocket(
  591. SOCKET Socket,
  592. PULONG Address OPTIONAL,
  593. PUSHORT Port
  594. )
  595. {
  596. SOCKADDR_IN SockAddr;
  597. LONG Length;
  598. Length = sizeof(SockAddr);
  599. if (getsockname(Socket, (PSOCKADDR)&SockAddr, (int*)&Length) == SOCKET_ERROR) {
  600. return WSAGetLastError();
  601. }
  602. if (Address) { *Address = SockAddr.sin_addr.s_addr; }
  603. if (Port) { *Port = SockAddr.sin_port; }
  604. return NO_ERROR;
  605. } // MyHelperQueryEndpointSocket
  606. USHORT
  607. MyHelperQueryPortSocket(
  608. SOCKET Socket
  609. )
  610. /*++
  611. Routine Description:
  612. This routine retrieves the port number to which a socket is bound.
  613. Arguments:
  614. Socket - the socket to be queried
  615. Return Value:
  616. USHORT - the port number retrieved
  617. --*/
  618. {
  619. SOCKADDR_IN Address;
  620. LONG AddressLength;
  621. AddressLength = sizeof(Address);
  622. getsockname(Socket, (PSOCKADDR)&Address, (int*)&AddressLength);
  623. return Address.sin_port;
  624. } // MyHelperQueryPortSocket
  625. ULONG
  626. MyHelperQueryRemoteEndpointSocket(
  627. SOCKET Socket,
  628. PULONG Address OPTIONAL,
  629. PUSHORT Port OPTIONAL
  630. )
  631. {
  632. SOCKADDR_IN SockAddr;
  633. LONG Length;
  634. Length = sizeof(SockAddr);
  635. if (getpeername(Socket, (PSOCKADDR)&SockAddr, (int*)&Length) == SOCKET_ERROR) {
  636. return WSAGetLastError();
  637. }
  638. if (Address) { *Address = SockAddr.sin_addr.s_addr; }
  639. if (Port) { *Port = SockAddr.sin_port; }
  640. return NO_ERROR;
  641. } // MyHelperQueryRemoteEndpointSocket
  642. ULONG
  643. MyHelperReadStreamSocket(
  644. PCOMPONENT_REFERENCE Component,
  645. SOCKET Socket,
  646. PNH_BUFFER Bufferp,
  647. ULONG Length,
  648. ULONG Offset,
  649. PNH_COMPLETION_ROUTINE CompletionRoutine,
  650. PVOID Context,
  651. PVOID Context2
  652. )
  653. /*++
  654. Routine Description:
  655. This routine is invoked to read a message from a stream socket.
  656. The I/O system invokes the provided 'CompletionRoutine' upon completion
  657. of the read.
  658. A reference is made to the given component, if any, if the request is
  659. submitted successfully. This guarantees the component will not be unloaded
  660. before the completion routine runs.
  661. Arguments:
  662. Component - the component to be referenced for the completion routine
  663. Socket - the endpoint on which to read a message
  664. Bufferp - the buffer into which the message should be read,
  665. or NULL to acquire a new buffer
  666. Length - the maximum number of bytes to be read
  667. Offset - the offset into the buffer at which the read should begin,
  668. valid only if 'Bufferp' is provided.
  669. CompletionRoutine - the routine to be invoked upon completion of the read
  670. Context - the context to be associated with the read-request;
  671. this can be obtained from 'Bufferp->Context' upon completion.
  672. Context2 - secondary context
  673. Return Value:
  674. ULONG - Win32/Winsock2 status code.
  675. A success code is a guarantee that the completion routine will be invoked.
  676. Conversely, a failure code is a guarantee that the completion routine will
  677. not be invoked.
  678. --*/
  679. {
  680. ULONG Error;
  681. PNH_BUFFER LocalBufferp = NULL;
  682. WSABUF WsaBuf;
  683. if (Component) {
  684. REFERENCE_COMPONENT_OR_RETURN(Component, ERROR_CAN_NOT_COMPLETE);
  685. }
  686. if (!Bufferp) {
  687. Offset = 0;
  688. Bufferp = LocalBufferp = MyHelperAcquireVariableLengthBuffer(Length);
  689. if (!Bufferp) {
  690. //MyHelperTrace(
  691. //TRACE_FLAG_SOCKET,
  692. //"MyHelperReadStreamSocket: error allocating buffer for receive"
  693. //);
  694. if (Component) { DEREFERENCE_COMPONENT(Component); }
  695. return ERROR_NOT_ENOUGH_MEMORY;
  696. }
  697. }
  698. ZeroMemory(&Bufferp->Overlapped, sizeof(Bufferp->Overlapped));
  699. Bufferp->Socket = Socket;
  700. Bufferp->ReceiveFlags = 0;
  701. Bufferp->CompletionRoutine = CompletionRoutine;
  702. Bufferp->Context = Context;
  703. Bufferp->Context2 = Context2;
  704. #if 1
  705. if (ReadFile(
  706. (HANDLE)Bufferp->Socket,
  707. Bufferp->Buffer + Offset,
  708. Length,
  709. &UnusedBytesTransferred,
  710. &Bufferp->Overlapped
  711. ) ||
  712. (Error = GetLastError()) == ERROR_IO_PENDING) {
  713. Error = NO_ERROR;
  714. } else {
  715. if (Component) { DEREFERENCE_COMPONENT(Component); }
  716. if (LocalBufferp) { MyHelperReleaseBuffer(LocalBufferp); }
  717. //MyHelperTrace(
  718. //TRACE_FLAG_SOCKET,
  719. //"MyHelperReadStreamSocket: error %d returned by 'ReadFile'", Error
  720. //);
  721. }
  722. #else
  723. WsaBuf.buf = Bufferp->Buffer + Offset;
  724. WsaBuf.len = Length;
  725. Error =
  726. WSARecv(
  727. Socket,
  728. &WsaBuf,
  729. 1,
  730. &UnusedBytesTransferred,
  731. &Bufferp->ReceiveFlags,
  732. &Bufferp->Overlapped,
  733. NULL
  734. );
  735. if (Error == SOCKET_ERROR &&
  736. (Error = WSAGetLastError()) == WSA_IO_PENDING) {
  737. Error = NO_ERROR;
  738. } else if (Error) {
  739. if (Component) { DEREFERENCE_COMPONENT(Component); }
  740. if (LocalBufferp) { MyHelperReleaseBuffer(LocalBufferp); }
  741. //MyHelperTrace(
  742. //TRACE_FLAG_SOCKET,
  743. //"MyHelperReadStreamSocket: error %d returned by 'WSARecv'", Error
  744. //);
  745. }
  746. #endif
  747. return Error;
  748. } // MyHelperReadStreamSocket
  749. ULONG
  750. MyHelperWriteStreamSocket(
  751. PCOMPONENT_REFERENCE Component,
  752. SOCKET Socket,
  753. PNH_BUFFER Bufferp,
  754. ULONG Length,
  755. ULONG Offset,
  756. PNH_COMPLETION_ROUTINE CompletionRoutine,
  757. PVOID Context,
  758. PVOID Context2
  759. )
  760. /*++
  761. Routine Description:
  762. This routine is invoked to send a message on a stream socket.
  763. A reference is made to the given component, if any, if the request is
  764. submitted successfully. This guarantees the component will not be unloaded
  765. before the completion routine runs.
  766. Arguments:
  767. Component - the component to be referenced for the completion routine
  768. Socket - the socket on which to send the message
  769. Bufferp - the buffer containing the message to be sent
  770. Length - the number of bytes to transfer
  771. Offset - the offset into the buffer at which the data to be sent begins
  772. CompletionRoutine - the routine to be invoked upon completion of the send
  773. Context - passed to the 'CompletionRoutine' upon completion of the send
  774. Context2 - secondary context
  775. Return Value:
  776. ULONG - Win32/Winsock2 status code
  777. A success code is a guarantee that the completion routine will be invoked.
  778. Conversely, a failure code is a guarantee that the completion routine will
  779. not be invoked.
  780. --*/
  781. {
  782. ULONG Error;
  783. WSABUF WsaBuf;
  784. if (Component) {
  785. REFERENCE_COMPONENT_OR_RETURN(Component, ERROR_CAN_NOT_COMPLETE);
  786. }
  787. ZeroMemory(&Bufferp->Overlapped, sizeof(Bufferp->Overlapped));
  788. Bufferp->Socket = Socket;
  789. Bufferp->CompletionRoutine = CompletionRoutine;
  790. Bufferp->Context = Context;
  791. Bufferp->Context2 = Context2;
  792. #if 1
  793. if (WriteFile(
  794. (HANDLE)Bufferp->Socket,
  795. Bufferp->Buffer + Offset,
  796. Length,
  797. &UnusedBytesTransferred,
  798. &Bufferp->Overlapped
  799. ) ||
  800. (Error = GetLastError()) == ERROR_IO_PENDING) {
  801. Error = NO_ERROR;
  802. } else {
  803. //MyHelperTrace(
  804. //TRACE_FLAG_SOCKET,
  805. //"MyHelperWriteStreamSocket: error %d returned by 'WriteFile'", Error
  806. //);
  807. if (Component) { DEREFERENCE_COMPONENT(Component); }
  808. }
  809. #else
  810. WsaBuf.buf = Bufferp->Buffer + Offset;
  811. WsaBuf.len = Length;
  812. Error =
  813. WSASend(
  814. Socket,
  815. &WsaBuf,
  816. 1,
  817. &UnusedBytesTransferred,
  818. 0,
  819. &Bufferp->Overlapped,
  820. NULL
  821. );
  822. if (Error == SOCKET_ERROR &&
  823. (Error = WSAGetLastError()) == WSA_IO_PENDING) {
  824. Error = NO_ERROR;
  825. } else if (Error) {
  826. //MyHelperTrace(
  827. //TRACE_FLAG_SOCKET,
  828. //"MyHelperWriteStreamSocket: error %d returned by 'WSASend'", Error
  829. //);
  830. if (Component) { DEREFERENCE_COMPONENT(Component); }
  831. }
  832. #endif
  833. return Error;
  834. } // MyHelperWriteStreamSocket