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.

993 lines
31 KiB

  1. /*++
  2. Copyright (c) 2000 Microsoft Corporation
  3. Module Name:
  4. ALGio.c
  5. Abstract:
  6. This module contains code for the ALG transparent proxy's network
  7. I/O completion routines.
  8. Author:
  9. Qiang Wang (qiangw) 10-Apr-2000
  10. Revision History:
  11. --*/
  12. #include "precomp.h"
  13. #pragma hdrstop
  14. #include "Algmsg.h"
  15. VOID
  16. AlgAcceptCompletionRoutine(
  17. ULONG ErrorCode,
  18. ULONG BytesTransferred,
  19. PNH_BUFFER Bufferp
  20. )
  21. /*++
  22. Routine Description:
  23. This routine is invoked upon completion of an accept operation
  24. on a ALG transparent proxy stream socket.
  25. Arguments:
  26. ErrorCode - Win32 status code for the I/O operation
  27. BytesTransferred - number of bytes in 'Bufferp'
  28. Bufferp - holds the local and remote IP address and port
  29. for the connection.
  30. Return Value:
  31. none.
  32. Environment:
  33. Runs in the context of a worker-thread which has just dequeued
  34. an I/O completion packet from the common I/O completion port
  35. with which our stream sockets are associated.
  36. A reference to the component will have been made on our behalf
  37. by 'NhAcceptStreamSocket'.
  38. A reference to the interface will have been made on our behalf
  39. by whoever issued the I/O request.
  40. --*/
  41. {
  42. SOCKET AcceptedSocket;
  43. PALG_CONNECTION Connectionp;
  44. ULONG Error;
  45. PALG_INTERFACE Interfacep;
  46. SOCKET ListeningSocket;
  47. PROFILE("AlgAcceptCompletionRoutine");
  48. do {
  49. AcceptedSocket = (SOCKET)Bufferp->Socket;
  50. Interfacep = (PALG_INTERFACE)Bufferp->Context;
  51. ListeningSocket = (SOCKET)Bufferp->Context2;
  52. //
  53. // Acquire three additional references to the interface
  54. // for the followup requests that we will issue below,
  55. // and lock the interface.
  56. //
  57. EnterCriticalSection(&AlgInterfaceLock);
  58. if (!ALG_REFERENCE_INTERFACE(Interfacep)) {
  59. LeaveCriticalSection(&AlgInterfaceLock);
  60. NhReleaseBuffer(Bufferp);
  61. NhDeleteStreamSocket(AcceptedSocket);
  62. break;
  63. }
  64. ALG_REFERENCE_INTERFACE(Interfacep);
  65. ALG_REFERENCE_INTERFACE(Interfacep);
  66. LeaveCriticalSection(&AlgInterfaceLock);
  67. ACQUIRE_LOCK(Interfacep);
  68. //
  69. // Process the accept-completion.
  70. // First look for an error code. If an error occurred
  71. // and the interface is no longer active, end the completion-handling.
  72. // Otherwise, attempt to reissue the accept-request.
  73. //
  74. if (ErrorCode) {
  75. NhTrace(
  76. TRACE_FLAG_IO,
  77. "AlgAcceptCompletionRoutine: error %d for interface %d",
  78. ErrorCode, Interfacep->Index
  79. );
  80. //
  81. // See if the interface is still active and, if so, reissue
  82. // the accept-request. Since we will not be creating an active
  83. // endpoint, we won't need the second reference to the interface.
  84. //
  85. ALG_DEREFERENCE_INTERFACE(Interfacep);
  86. ALG_DEREFERENCE_INTERFACE(Interfacep);
  87. if (!ALG_INTERFACE_ACTIVE(Interfacep)) {
  88. RELEASE_LOCK(Interfacep);
  89. ALG_DEREFERENCE_INTERFACE(Interfacep);
  90. NhReleaseBuffer(Bufferp);
  91. NhDeleteStreamSocket(AcceptedSocket);
  92. } else {
  93. //
  94. // Reissue the accept-request. Note that the callee is now
  95. // responsible for the reference we made to the interface.
  96. //
  97. Error =
  98. AlgAcceptConnectionInterface(
  99. Interfacep,
  100. ListeningSocket,
  101. AcceptedSocket,
  102. Bufferp,
  103. NULL
  104. );
  105. RELEASE_LOCK(Interfacep);
  106. if (Error) {
  107. NhReleaseBuffer(Bufferp);
  108. NhDeleteStreamSocket(AcceptedSocket);
  109. NhTrace(
  110. TRACE_FLAG_IO,
  111. "AlgAcceptCompletionRoutine: error %d reissuing accept",
  112. Error
  113. );
  114. }
  115. }
  116. break;
  117. }
  118. //
  119. // Now see if the interface is operational.
  120. // If it isn't, we need to destroy the accepted socket
  121. // and return control.
  122. //
  123. if (!ALG_INTERFACE_ACTIVE(Interfacep)) {
  124. RELEASE_LOCK(Interfacep);
  125. ALG_DEREFERENCE_INTERFACE(Interfacep);
  126. ALG_DEREFERENCE_INTERFACE(Interfacep);
  127. ALG_DEREFERENCE_INTERFACE(Interfacep);
  128. NhReleaseBuffer(Bufferp);
  129. NhDeleteStreamSocket(AcceptedSocket);
  130. NhTrace(
  131. TRACE_FLAG_IO,
  132. "AlgAcceptCompletionRoutine: interface %d inactive",
  133. Interfacep->Index
  134. );
  135. InterlockedIncrement(
  136. reinterpret_cast<LPLONG>(&AlgStatistics.ConnectionsDropped)
  137. );
  138. break;
  139. }
  140. //
  141. // We now create a 'ALG_CONNECTION' for the new connection,
  142. // in the process launching operations for the connection.
  143. // The connection management module will handle the accepted socket
  144. // from here onward, and is responsible for the references to the
  145. // interface that were made above.
  146. //
  147. NhTrace(
  148. TRACE_FLAG_IO,
  149. "AlgAcceptCompletionRoutine: socket %d accepting connection",
  150. ListeningSocket
  151. );
  152. Error =
  153. AlgCreateConnection(
  154. Interfacep,
  155. ListeningSocket,
  156. AcceptedSocket,
  157. Bufferp->Buffer,
  158. &Connectionp
  159. );
  160. if (Error) {
  161. InterlockedIncrement(
  162. reinterpret_cast<LPLONG>(&AlgStatistics.ConnectionsDropped)
  163. );
  164. } else {
  165. InterlockedIncrement(
  166. reinterpret_cast<LPLONG>(&AlgStatistics.ConnectionsAccepted)
  167. );
  168. }
  169. //
  170. // Finally, issue an accept operation for the next connection-request
  171. // on the listening socket. Note that the callee is responsible
  172. // for releasing the reference to the interface in case of a failure.
  173. //
  174. Error =
  175. AlgAcceptConnectionInterface(
  176. Interfacep,
  177. ListeningSocket,
  178. INVALID_SOCKET,
  179. Bufferp,
  180. NULL
  181. );
  182. RELEASE_LOCK(Interfacep);
  183. if (Error) { NhReleaseBuffer(Bufferp); }
  184. } while(FALSE);
  185. ALG_DEREFERENCE_INTERFACE(Interfacep);
  186. DEREFERENCE_ALG();
  187. } // AlgAcceptCompletionRoutine
  188. VOID
  189. AlgCloseEndpointNotificationRoutine(
  190. ULONG ErrorCode,
  191. ULONG BytesTransferred,
  192. PNH_BUFFER Bufferp
  193. )
  194. /*++
  195. Routine Description:
  196. This routine is invoked upon notification of a close operation
  197. on a ALG transparent proxy stream socket.
  198. Arguments:
  199. ErrorCode - Win32 status code for the I/O operation
  200. BytesTransferred - number of bytes in 'Bufferp'
  201. Bufferp - holds context information for the closed socket.
  202. Note that we are not allowed to release this buffer here.
  203. Return Value:
  204. none.
  205. Environment:
  206. Runs in the context of a wait-thread.
  207. A reference to the component will have been made on our behalf
  208. by 'NhAcceptStreamSocket' or 'NhConnectStreamSocket'.
  209. A reference to the interface will have been made on our behalf
  210. by whoever issued the I/O request.
  211. Both of these references are released here.
  212. --*/
  213. {
  214. SOCKET ClosedSocket;
  215. ULONG EndpointId;
  216. PALG_INTERFACE Interfacep;
  217. PROFILE("AlgCloseEndpointNotificationRoutine");
  218. do {
  219. ClosedSocket = (SOCKET)Bufferp->Socket;
  220. Interfacep = (PALG_INTERFACE)Bufferp->Context;
  221. EndpointId = PtrToUlong(Bufferp->Context2);
  222. NhTrace(
  223. TRACE_FLAG_IO,
  224. "AlgCloseEndpointNotificationRoutine: endpoint %d socket %d "
  225. "closed, error %d",
  226. EndpointId, ClosedSocket, ErrorCode
  227. );
  228. #if 0
  229. PALG_ENDPOINT Endpointp;
  230. //
  231. // Lock the interface, and retrieve the endpoint whose socket has
  232. // been closed.
  233. //
  234. ACQUIRE_LOCK(Interfacep);
  235. Endpointp = AlgLookupInterfaceEndpoint(Interfacep, EndpointId, NULL);
  236. if (Endpointp) {
  237. AlgCloseActiveEndpoint(Endpointp, ClosedSocket);
  238. }
  239. RELEASE_LOCK(Interfacep);
  240. #endif
  241. } while(FALSE);
  242. ALG_DEREFERENCE_INTERFACE(Interfacep);
  243. DEREFERENCE_ALG();
  244. } // AlgCloseEndpointNotificationRoutine
  245. VOID
  246. AlgConnectEndpointCompletionRoutine(
  247. ULONG ErrorCode,
  248. ULONG BytesTransferred,
  249. PNH_BUFFER Bufferp
  250. )
  251. /*++
  252. Routine Description:
  253. This routine is invoked upon completion of a connect operation
  254. on a ALG transparent proxy stream socket.
  255. Arguments:
  256. ErrorCode - Win32 status code for the I/O operation
  257. BytesTransferred - number of bytes in 'Bufferp'
  258. Bufferp - holds the context information for the endpoint.
  259. Note that we are not allowed to release this buffer here.
  260. Return Value:
  261. none.
  262. Environment:
  263. Runs in the context of a wait-thread.
  264. A reference to the component will have been made on our behalf
  265. by 'NhConnectStreamSocket'.
  266. A reference to the interface will have been made on our behalf
  267. by whoever issued the I/O request.
  268. Neither of these references may be released here; they are both
  269. released in the close-notification routine, which we are guaranteed
  270. will be invoked. (Eventually.)
  271. --*/
  272. {
  273. SOCKET ConnectedSocket;
  274. ULONG EndpointId;
  275. PALG_ENDPOINT Endpointp;
  276. ULONG Error;
  277. PALG_INTERFACE Interfacep;
  278. PROFILE("AlgConnectEndpointCompletionRoutine");
  279. do {
  280. ConnectedSocket = (SOCKET)Bufferp->Socket;
  281. Interfacep = (PALG_INTERFACE)Bufferp->Context;
  282. EndpointId = PtrToUlong(Bufferp->Context2);
  283. //
  284. // Acquire two additional references to the interface
  285. // for the endpoint-activation that we will initiate below,
  286. // lock the interface, and retrieve the endpoint.
  287. //
  288. EnterCriticalSection(&AlgInterfaceLock);
  289. if (!ALG_REFERENCE_INTERFACE(Interfacep)) {
  290. LeaveCriticalSection(&AlgInterfaceLock);
  291. break;
  292. }
  293. ALG_REFERENCE_INTERFACE(Interfacep);
  294. LeaveCriticalSection(&AlgInterfaceLock);
  295. ACQUIRE_LOCK(Interfacep);
  296. Endpointp = AlgLookupInterfaceEndpoint(Interfacep, EndpointId, NULL);
  297. //
  298. // First look for an error code.
  299. // If an error occurred and the interface is still active,
  300. // destroy the endpoint.
  301. // If the interface is inactive, we're done, since the endpoint
  302. // will have already been destroyed.
  303. // If the interface is active but the endpoint has already
  304. // been destroyed, end this connection-attempt.
  305. //
  306. if (ErrorCode) {
  307. if (Endpointp) {
  308. NhTrace(
  309. TRACE_FLAG_IO,
  310. "AlgConnectEndpointCompletionRoutine: deleting endpoint %d "
  311. "on error %d", EndpointId, ErrorCode
  312. );
  313. AlgDeleteActiveEndpoint(Endpointp);
  314. }
  315. RELEASE_LOCK(Interfacep);
  316. ALG_DEREFERENCE_INTERFACE(Interfacep);
  317. ALG_DEREFERENCE_INTERFACE(Interfacep);
  318. break;
  319. } else if (!ALG_INTERFACE_ACTIVE(Interfacep)) {
  320. RELEASE_LOCK(Interfacep);
  321. ALG_DEREFERENCE_INTERFACE(Interfacep);
  322. ALG_DEREFERENCE_INTERFACE(Interfacep);
  323. NhTrace(
  324. TRACE_FLAG_IO,
  325. "AlgConnectEndpointCompletionRoutine: interface %d inactive",
  326. Interfacep->Index
  327. );
  328. break;
  329. } else if (!Endpointp) {
  330. RELEASE_LOCK(Interfacep);
  331. ALG_DEREFERENCE_INTERFACE(Interfacep);
  332. ALG_DEREFERENCE_INTERFACE(Interfacep);
  333. NhTrace(
  334. TRACE_FLAG_IO,
  335. "AlgConnectEndpointCompletionRoutine: endpoint %d removed",
  336. EndpointId
  337. );
  338. break;
  339. }
  340. //
  341. // We now activate the endpoint, beginning data transfer.
  342. // Note that it is the caller's responsibility to release
  343. // the two new references to the interface if an error occurs.
  344. //
  345. NhTrace(
  346. TRACE_FLAG_IO,
  347. "AlgConnectEndpointCompletionRoutine: endpoint %d socket %d "
  348. "connected", EndpointId, ConnectedSocket
  349. );
  350. Error = AlgActivateActiveEndpoint(Interfacep, Endpointp);
  351. RELEASE_LOCK(Interfacep);
  352. } while(FALSE);
  353. } // AlgConnectEndpointCompletionRoutine
  354. VOID
  355. AlgReadEndpointCompletionRoutine(
  356. ULONG ErrorCode,
  357. ULONG BytesTransferred,
  358. PNH_BUFFER Bufferp
  359. )
  360. /*++
  361. Routine Description:
  362. This routine is invoked upon completion of a read operation
  363. on a ALG transparent proxy stream socket.
  364. The contexts for all reads are the interface and endpoint-identifier
  365. corresponding to the socket, stored in 'Context' and 'Context2',
  366. respectively.
  367. Arguments:
  368. ErrorCode - Win32 status code for the I/O operation
  369. BytesTransferred - number of bytes in 'Bufferp'
  370. Bufferp - holds data read from the socket
  371. Return Value:
  372. none.
  373. Environment:
  374. Runs in the context of a worker-thread which has just dequeued an
  375. I/O completion packet from the common I/O completion port with which
  376. our stream sockets are associated.
  377. A reference to the component will have been made on our behalf
  378. by 'NhReadStreamSocket'.
  379. A reference to the interface will have been made on our behalf
  380. by whoever issued the I/O request.
  381. --*/
  382. {
  383. ULONG EndpointId;
  384. PALG_ENDPOINT Endpointp;
  385. ULONG Error;
  386. PALG_INTERFACE Interfacep;
  387. PROFILE("AlgReadEndpointCompletionRoutine");
  388. do {
  389. Interfacep = (PALG_INTERFACE)Bufferp->Context;
  390. EndpointId = PtrToUlong(Bufferp->Context2);
  391. //
  392. // Acquire two additional references to the interface
  393. // for the followup requests that we will issue below,
  394. // lock the interface, and retrieve the endpoint.
  395. //
  396. EnterCriticalSection(&AlgInterfaceLock);
  397. if (!ALG_REFERENCE_INTERFACE(Interfacep)) {
  398. LeaveCriticalSection(&AlgInterfaceLock);
  399. NhReleaseBuffer(Bufferp);
  400. break;
  401. }
  402. ALG_REFERENCE_INTERFACE(Interfacep);
  403. LeaveCriticalSection(&AlgInterfaceLock);
  404. ACQUIRE_LOCK(Interfacep);
  405. Endpointp = AlgLookupInterfaceEndpoint(Interfacep, EndpointId, NULL);
  406. //
  407. // Process the read-completion. First we look for an error-code,
  408. // and if we find one, we decide whether to re-issue the read-request.
  409. // If the interface is still active, the error-code is non-fatal, and
  410. // the endpoint still exists, we reissue the read.
  411. //
  412. if (ErrorCode) {
  413. //
  414. // We won't be needing the second reference to the interface,
  415. // since we won't be calling 'AlgProcessMessage.
  416. //
  417. ALG_DEREFERENCE_INTERFACE(Interfacep);
  418. NhTrace(
  419. TRACE_FLAG_IO,
  420. "AlgReadEndpointCompletionRoutine: error %d for endpoint %d",
  421. ErrorCode, EndpointId
  422. );
  423. if (!ALG_INTERFACE_ACTIVE(Interfacep) || !Endpointp) {
  424. RELEASE_LOCK(Interfacep);
  425. ALG_DEREFERENCE_INTERFACE(Interfacep);
  426. NhReleaseBuffer(Bufferp);
  427. } else if (NhIsFatalSocketError(ErrorCode)) {
  428. AlgDeleteActiveEndpoint(Endpointp);
  429. RELEASE_LOCK(Interfacep);
  430. ALG_DEREFERENCE_INTERFACE(Interfacep);
  431. NhReleaseBuffer(Bufferp);
  432. NhTrace(
  433. TRACE_FLAG_IO,
  434. "AlgReadEndpointCompletionRoutine: deleting endpoint %d "
  435. "on fatal read-error %d", EndpointId, ErrorCode
  436. );
  437. } else {
  438. //
  439. // We need to repost the buffer for another read operation,
  440. // so we now reissue a read for the same number of bytes as
  441. // before.
  442. //
  443. Error =
  444. NhReadStreamSocket(
  445. &AlgComponentReference,
  446. Bufferp->Socket,
  447. Bufferp,
  448. Bufferp->BytesToTransfer,
  449. Bufferp->TransferOffset,
  450. AlgReadEndpointCompletionRoutine,
  451. Bufferp->Context,
  452. Bufferp->Context2
  453. );
  454. if (Error) {
  455. AlgDeleteActiveEndpoint(Endpointp);
  456. RELEASE_LOCK(Interfacep);
  457. ALG_DEREFERENCE_INTERFACE(Interfacep);
  458. NhTrace(
  459. TRACE_FLAG_IO,
  460. "AlgReadEndpointCompletionRoutine: deleting endpoint "
  461. "%d, NhReadStreamSocket=%d", EndpointId, Error
  462. );
  463. if (Error != ERROR_NETNAME_DELETED) {
  464. NhWarningLog(
  465. IP_ALG_LOG_RECEIVE_FAILED,
  466. Error,
  467. "%I",
  468. NhQueryAddressSocket(Bufferp->Socket)
  469. );
  470. }
  471. NhReleaseBuffer(Bufferp);
  472. break;
  473. }
  474. RELEASE_LOCK(Interfacep);
  475. }
  476. break;
  477. } else if (!BytesTransferred) {
  478. //
  479. // Zero bytes were read from the endpoint's socket.
  480. // This indicates that the sender has closed the socket.
  481. // We now propagate the closure to the alternate socket
  482. // for the endpoint. When the 'other' sender is done,
  483. // this endpoint will be removed altogether.
  484. //
  485. NhTrace(
  486. TRACE_FLAG_IO,
  487. "AlgReadEndpointCompletionRoutine: endpoint %d socket %d "
  488. "closed", EndpointId, Bufferp->Socket
  489. );
  490. if (Endpointp) {
  491. AlgCloseActiveEndpoint(Endpointp, Bufferp->Socket);
  492. }
  493. RELEASE_LOCK(Interfacep);
  494. ALG_DEREFERENCE_INTERFACE(Interfacep);
  495. ALG_DEREFERENCE_INTERFACE(Interfacep);
  496. NhReleaseBuffer(Bufferp);
  497. break;
  498. }
  499. //
  500. // The original request completed successfully.
  501. // Now see if the interface and endpoint are operational and,
  502. // if not, return control.
  503. //
  504. if (!ALG_INTERFACE_ACTIVE(Interfacep)) {
  505. RELEASE_LOCK(Interfacep);
  506. ALG_DEREFERENCE_INTERFACE(Interfacep);
  507. ALG_DEREFERENCE_INTERFACE(Interfacep);
  508. NhReleaseBuffer(Bufferp);
  509. NhTrace(
  510. TRACE_FLAG_IO,
  511. "AlgReadEndpointCompletionRoutine: interface %d inactive",
  512. Interfacep->Index
  513. );
  514. break;
  515. } else if (!Endpointp) {
  516. RELEASE_LOCK(Interfacep);
  517. ALG_DEREFERENCE_INTERFACE(Interfacep);
  518. ALG_DEREFERENCE_INTERFACE(Interfacep);
  519. NhReleaseBuffer(Bufferp);
  520. NhTrace(
  521. TRACE_FLAG_IO,
  522. "AlgReadEndpointCompletionRoutine: endpoint %d not found",
  523. EndpointId
  524. );
  525. break;
  526. }
  527. //
  528. // Record the number of bytes read, and issue a read-request
  529. // for the remainder if necessary. Otherwise, process the completed
  530. // message.
  531. //
  532. NhTrace(
  533. TRACE_FLAG_IO,
  534. "AlgReadEndpointCompletionRoutine: endpoint %d socket %d read %d "
  535. "bytes", EndpointId, Bufferp->Socket, BytesTransferred
  536. );
  537. ASSERT(BytesTransferred <= Bufferp->BytesToTransfer);
  538. Bufferp->BytesToTransfer -= BytesTransferred;
  539. Bufferp->TransferOffset += BytesTransferred;
  540. if (Bufferp->BytesToTransfer > 0 &&
  541. AlgIsFullMessage(
  542. reinterpret_cast<CHAR*>(Bufferp->Buffer),
  543. Bufferp->TransferOffset
  544. ) == NULL) {
  545. //
  546. // Read the remainder of the message, after releasing
  547. // the second reference to the interface, which is needed
  548. // only when we call 'AlgProcessMessage'.
  549. //
  550. ALG_DEREFERENCE_INTERFACE(Interfacep);
  551. Error =
  552. NhReadStreamSocket(
  553. &AlgComponentReference,
  554. Bufferp->Socket,
  555. Bufferp,
  556. Bufferp->BytesToTransfer,
  557. Bufferp->TransferOffset,
  558. AlgReadEndpointCompletionRoutine,
  559. Bufferp->Context,
  560. Bufferp->Context2
  561. );
  562. if (Error) {
  563. AlgDeleteActiveEndpoint(Endpointp);
  564. RELEASE_LOCK(Interfacep);
  565. ALG_DEREFERENCE_INTERFACE(Interfacep);
  566. NhTrace(
  567. TRACE_FLAG_IO,
  568. "AlgReadEndpointCompletionRoutine: deleting endpoint "
  569. "%d, NhReadStreamSocket=%d", EndpointId, Error
  570. );
  571. if (Error != ERROR_NETNAME_DELETED) {
  572. NhWarningLog(
  573. IP_ALG_LOG_RECEIVE_FAILED,
  574. Error,
  575. "%I",
  576. NhQueryAddressSocket(Bufferp->Socket)
  577. );
  578. }
  579. NhReleaseBuffer(Bufferp);
  580. break;
  581. }
  582. } else {
  583. //
  584. // We've finished reading something. Process it.
  585. //
  586. AlgProcessMessage(Interfacep, Endpointp, Bufferp);
  587. }
  588. RELEASE_LOCK(Interfacep);
  589. } while(FALSE);
  590. ALG_DEREFERENCE_INTERFACE(Interfacep);
  591. DEREFERENCE_ALG();
  592. } // AlgReadEndpointCompletionRoutine
  593. VOID
  594. AlgWriteEndpointCompletionRoutine(
  595. ULONG ErrorCode,
  596. ULONG BytesTransferred,
  597. PNH_BUFFER Bufferp
  598. )
  599. /*++
  600. Routine Description:
  601. This routine is invoked upon completion of a write-operation
  602. on a stream socket for a ALG control-channel connection.
  603. The contexts for all writes are the interface and endpoint-identifier
  604. corresponding to the socket, stored in 'Context' and 'Context2',
  605. respectively.
  606. Arguments:
  607. ErrorCode - Win32 status code for the I/O operation
  608. BytesTransferred - number of bytes in 'Bufferp'
  609. Bufferp - holds data read from the stream socket
  610. Return Value:
  611. none.
  612. Environment:
  613. Runs in the context of a worker-thread which has just dequeued an
  614. I/O completion packet from the common I/O completion port with which our
  615. stream sockets are associated.
  616. A reference to the component will have been made on our behalf
  617. by 'NhWriteStreamSocket'.
  618. A reference to the interface will have been made on our behalf
  619. by whoever issued the I/O request.
  620. --*/
  621. {
  622. ULONG Error;
  623. ULONG EndpointId;
  624. PALG_ENDPOINT Endpointp;
  625. PALG_INTERFACE Interfacep;
  626. PROFILE("AlgWriteEndpointCompletionRoutine");
  627. do {
  628. Interfacep = (PALG_INTERFACE)Bufferp->Context;
  629. EndpointId = PtrToUlong(Bufferp->Context2);
  630. //
  631. // Acquire an additional reference to the interface
  632. // for the followup requests that we will issue below,
  633. // lock the interface, and retrieve the endpoint.
  634. //
  635. EnterCriticalSection(&AlgInterfaceLock);
  636. if (!ALG_REFERENCE_INTERFACE(Interfacep)) {
  637. LeaveCriticalSection(&AlgInterfaceLock);
  638. NhReleaseBuffer(Bufferp);
  639. break;
  640. }
  641. LeaveCriticalSection(&AlgInterfaceLock);
  642. ACQUIRE_LOCK(Interfacep);
  643. Endpointp = AlgLookupInterfaceEndpoint(Interfacep, EndpointId, NULL);
  644. //
  645. // Process the write-completion. First we look for an error-code,
  646. // and if we find one, we decide whether to re-issue the write-request.
  647. // If the interface is still active, the error-code is non-fatal, and
  648. // the endpoint still exists, we reissue the write.
  649. //
  650. if (ErrorCode) {
  651. NhTrace(
  652. TRACE_FLAG_IO,
  653. "AlgWriteEndpointCompletionRoutine: error %d for endpoint %d",
  654. ErrorCode, EndpointId
  655. );
  656. if (!ALG_INTERFACE_ACTIVE(Interfacep) || !Endpointp) {
  657. RELEASE_LOCK(Interfacep);
  658. ALG_DEREFERENCE_INTERFACE(Interfacep);
  659. NhReleaseBuffer(Bufferp);
  660. } else if (NhIsFatalSocketError(ErrorCode)) {
  661. AlgDeleteActiveEndpoint(Endpointp);
  662. RELEASE_LOCK(Interfacep);
  663. ALG_DEREFERENCE_INTERFACE(Interfacep);
  664. NhReleaseBuffer(Bufferp);
  665. NhTrace(
  666. TRACE_FLAG_IO,
  667. "AlgWriteEndpointCompletionRoutine: deleting endpoint %d "
  668. "on fatal write-error %d", EndpointId, ErrorCode
  669. );
  670. } else {
  671. //
  672. // We need to repost the buffer for another write operation,
  673. // so we now reissue a write for the same number of bytes
  674. // as before.
  675. //
  676. Error =
  677. NhWriteStreamSocket(
  678. &AlgComponentReference,
  679. Bufferp->Socket,
  680. Bufferp,
  681. Bufferp->BytesToTransfer,
  682. Bufferp->TransferOffset,
  683. AlgWriteEndpointCompletionRoutine,
  684. Bufferp->Context,
  685. Bufferp->Context2
  686. );
  687. if (Error) {
  688. AlgDeleteActiveEndpoint(Endpointp);
  689. RELEASE_LOCK(Interfacep);
  690. ALG_DEREFERENCE_INTERFACE(Interfacep);
  691. NhTrace(
  692. TRACE_FLAG_IO,
  693. "AlgWriteEndpointCompletionRoutine: deleting endpoint "
  694. "%d, NhWriteStreamSocket=%d", EndpointId, Error
  695. );
  696. NhWarningLog(
  697. IP_ALG_LOG_SEND_FAILED,
  698. Error,
  699. "%I",
  700. NhQueryAddressSocket(Bufferp->Socket)
  701. );
  702. NhReleaseBuffer(Bufferp);
  703. break;
  704. }
  705. RELEASE_LOCK(Interfacep);
  706. }
  707. break;
  708. }
  709. //
  710. // The original request completed successfully.
  711. // Now see if the interface and endpoint are operational and,
  712. // if not, return control.
  713. //
  714. if (!ALG_INTERFACE_ACTIVE(Interfacep)) {
  715. RELEASE_LOCK(Interfacep);
  716. ALG_DEREFERENCE_INTERFACE(Interfacep);
  717. NhReleaseBuffer(Bufferp);
  718. NhTrace(
  719. TRACE_FLAG_IO,
  720. "AlgWriteEndpointCompletionRoutine: interface %d inactive",
  721. Interfacep->Index
  722. );
  723. break;
  724. } else if (!Endpointp) {
  725. RELEASE_LOCK(Interfacep);
  726. ALG_DEREFERENCE_INTERFACE(Interfacep);
  727. NhReleaseBuffer(Bufferp);
  728. NhTrace(
  729. TRACE_FLAG_IO,
  730. "AlgWriteEndpointCompletionRoutine: endpoint %d not found",
  731. EndpointId
  732. );
  733. break;
  734. }
  735. //
  736. // Record the number of bytes written, and issue a write-request
  737. // for the remainder if necessary. Otherwise, we are done,
  738. // and we return to reading from the 'other' socket for the
  739. // control-channel.
  740. //
  741. NhTrace(
  742. TRACE_FLAG_IO,
  743. "AlgWriteEndpointCompletionRoutine: endpoint %d socket %d wrote %d "
  744. "bytes", EndpointId, Bufferp->Socket, BytesTransferred
  745. );
  746. ASSERT(BytesTransferred <= Bufferp->BytesToTransfer);
  747. Bufferp->BytesToTransfer -= BytesTransferred;
  748. Bufferp->TransferOffset += BytesTransferred;
  749. if (Bufferp->BytesToTransfer) {
  750. //
  751. // Write the remainder of the message
  752. //
  753. Error =
  754. NhWriteStreamSocket(
  755. &AlgComponentReference,
  756. Bufferp->Socket,
  757. Bufferp,
  758. Bufferp->BytesToTransfer,
  759. Bufferp->TransferOffset,
  760. AlgWriteEndpointCompletionRoutine,
  761. Bufferp->Context,
  762. Bufferp->Context2
  763. );
  764. if (Error) {
  765. AlgDeleteActiveEndpoint(Endpointp);
  766. RELEASE_LOCK(Interfacep);
  767. ALG_DEREFERENCE_INTERFACE(Interfacep);
  768. NhTrace(
  769. TRACE_FLAG_IO,
  770. "AlgWriteEndpointCompletionRoutine: deleting endpoint %d, "
  771. "NhWriteStreamSocket=%d", EndpointId, Error
  772. );
  773. NhWarningLog(
  774. IP_ALG_LOG_SEND_FAILED,
  775. Error,
  776. "%I",
  777. NhQueryAddressSocket(Bufferp->Socket)
  778. );
  779. NhReleaseBuffer(Bufferp);
  780. break;
  781. }
  782. } else {
  783. SOCKET Socket;
  784. ULONG UserFlags;
  785. //
  786. // We now go back to reading from the other socket of the
  787. // endpoint, by issuing the next read on the endpoint's other
  788. // socket. Note that it is the responsibility of the callee
  789. // to release the reference to the interface if a failure occurs.
  790. //
  791. UserFlags = Bufferp->UserFlags;
  792. if (UserFlags & ALG_BUFFER_FLAG_FROM_ACTUAL_CLIENT) {
  793. Socket = Endpointp->HostSocket;
  794. UserFlags &= ~(ULONG)ALG_BUFFER_FLAG_CONTINUATION;
  795. UserFlags |= ALG_BUFFER_FLAG_FROM_ACTUAL_CLIENT;
  796. } else {
  797. Socket = Endpointp->ClientSocket;
  798. UserFlags &= ~(ULONG)ALG_BUFFER_FLAG_CONTINUATION;
  799. UserFlags |= ALG_BUFFER_FLAG_FROM_ACTUAL_HOST;
  800. }
  801. NhReleaseBuffer(Bufferp);
  802. Error =
  803. AlgReadActiveEndpoint(
  804. Interfacep,
  805. Endpointp,
  806. Socket,
  807. UserFlags
  808. );
  809. if (Error) {
  810. NhTrace(
  811. TRACE_FLAG_IO,
  812. "AlgWriteEndpointCompletionRoutine: deleting endpoint %d, "
  813. "AlgReadActiveEndpoint=%d", EndpointId, Error
  814. );
  815. AlgDeleteActiveEndpoint(Endpointp);
  816. RELEASE_LOCK(Interfacep);
  817. NhWarningLog(
  818. IP_ALG_LOG_RECEIVE_FAILED,
  819. Error,
  820. "%I",
  821. NhQueryAddressSocket(Socket)
  822. );
  823. break;
  824. }
  825. }
  826. RELEASE_LOCK(Interfacep);
  827. } while(FALSE);
  828. ALG_DEREFERENCE_INTERFACE(Interfacep);
  829. DEREFERENCE_ALG();
  830. } // AlgWriteEndpointCompletionRoutine