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.

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