Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

2743 lines
78 KiB

  1. /*++
  2. Copyright (c) 2000-2002 Microsoft Corporation
  3. Module Name:
  4. uctdi.c
  5. Abstract:
  6. Contains the TDI related functionality for the HTTP client side stuff.
  7. Author:
  8. Henry Sanders (henrysa) 07-Aug-2000
  9. Rajesh Sundaram (rajeshsu) 01-Oct-2000
  10. Revision History:
  11. --*/
  12. #include "precomp.h"
  13. #ifdef ALLOC_PRAGMA
  14. #pragma alloc_text( PAGEUC, UcClientConnect)
  15. #pragma alloc_text( PAGEUC, UcCloseConnection)
  16. #pragma alloc_text( PAGEUC, UcSendData)
  17. #pragma alloc_text( PAGEUC, UcReceiveData)
  18. #pragma alloc_text( PAGEUC, UcpTdiDisconnectHandler)
  19. #pragma alloc_text( PAGEUC, UcpCloseRawConnection)
  20. #pragma alloc_text( PAGEUC, UcCloseRawFilterConnection)
  21. #pragma alloc_text( PAGEUC, UcDisconnectRawFilterConnection)
  22. #pragma alloc_text( PAGEUC, UcpSendRawData)
  23. #pragma alloc_text( PAGEUC, UcpReceiveRawData)
  24. #pragma alloc_text( PAGEUC, UcpTdiReceiveHandler)
  25. #pragma alloc_text( PAGEUC, UcpReceiveExpeditedHandler)
  26. #pragma alloc_text( PAGEUC, UcpRestartSendData)
  27. #pragma alloc_text( PAGEUC, UcpBeginDisconnect)
  28. #pragma alloc_text( PAGEUC, UcpRestartDisconnect)
  29. #pragma alloc_text( PAGEUC, UcpBeginAbort)
  30. #pragma alloc_text( PAGEUC, UcpRestartAbort)
  31. #pragma alloc_text( PAGEUC, UcpRestartReceive)
  32. #pragma alloc_text( PAGEUC, UcpRestartClientReceive)
  33. #pragma alloc_text( PAGEUC, UcpConnectComplete)
  34. #pragma alloc_text( PAGEUC, UcSetFlag)
  35. #pragma alloc_text( PAGEUC, UcpBuildTdiReceiveBuffer)
  36. #endif // ALLOC_PRAGMA
  37. //
  38. // Public functions.
  39. //
  40. /***************************************************************************++
  41. Routine Description:
  42. Connects an UC connection to a remote server. We take as input an
  43. HTTP connection object. It's assumed that the connection object
  44. already has the remote address information filled in.
  45. Arguments:
  46. pConnection - Pointer to the HTTP connection object to be connected.
  47. pIrp - Pointer to Irp to use for the connect request.
  48. Return Value:
  49. NTSTATUS - Completion status.
  50. --***************************************************************************/
  51. NTSTATUS
  52. UcClientConnect(
  53. IN PUC_CLIENT_CONNECTION pConnection,
  54. IN PIRP pIrp
  55. )
  56. {
  57. NTSTATUS status;
  58. LONGLONG llTimeOut;
  59. PLONGLONG pllTimeOut = NULL;
  60. USHORT AddressType;
  61. #if CLIENT_IP_ADDRESS_TRACE
  62. CHAR IpAddressString[MAX_IP_ADDR_AND_PORT_STRING_LEN + 1];
  63. ULONG Length;
  64. #endif
  65. AddressType = pConnection->pNextAddress->AddressType;
  66. ASSERT(AddressType == TDI_ADDRESS_TYPE_IP ||
  67. AddressType == TDI_ADDRESS_TYPE_IP6);
  68. #if CLIENT_IP_ADDRESS_TRACE
  69. Length = HostAddressAndPortToString(
  70. IpAddressString,
  71. pConnection->pNextAddress->Address,
  72. AddressType
  73. );
  74. ASSERT(Length < sizeof(IpAddressString));
  75. UlTrace(TDI, ("[UcClientConnect]: Trying Address %s \n", IpAddressString));
  76. #endif
  77. //
  78. // Format the connect IRP. When the IRP completes our completion routine
  79. // (UcConnectComplete) will be called.
  80. //
  81. pConnection->pTdiObjects->TdiInfo.RemoteAddress =
  82. &pConnection->RemoteAddress;
  83. pConnection->pTdiObjects->TdiInfo.RemoteAddressLength =
  84. (FIELD_OFFSET(TRANSPORT_ADDRESS, Address) +
  85. FIELD_OFFSET(TA_ADDRESS, Address) +
  86. pConnection->pNextAddress->AddressLength
  87. );
  88. pConnection->RemoteAddress.GenericTransportAddress.TAAddressCount = 1;
  89. ASSERT(sizeof(pConnection->RemoteAddress) >=
  90. pConnection->pTdiObjects->TdiInfo.RemoteAddressLength);
  91. RtlCopyMemory(
  92. pConnection->RemoteAddress.GenericTransportAddress.Address,
  93. pConnection->pNextAddress,
  94. FIELD_OFFSET(TA_ADDRESS, Address) +
  95. pConnection->pNextAddress->AddressLength
  96. );
  97. if(pConnection->pServerInfo->ConnectionTimeout)
  98. {
  99. llTimeOut = Int32x32To64(pConnection->pServerInfo->ConnectionTimeout,
  100. -10000);
  101. pllTimeOut = &llTimeOut;
  102. }
  103. TdiBuildConnect(
  104. pIrp,
  105. pConnection->pTdiObjects->ConnectionObject.pDeviceObject,
  106. pConnection->pTdiObjects->ConnectionObject.pFileObject,
  107. UcpConnectComplete,
  108. pConnection,
  109. pllTimeOut,
  110. &pConnection->pTdiObjects->TdiInfo,
  111. NULL
  112. );
  113. status = UlCallDriver(
  114. pConnection->pTdiObjects->ConnectionObject.pDeviceObject,
  115. pIrp
  116. );
  117. return status;
  118. }
  119. /***************************************************************************++
  120. Routine Description:
  121. Closes a previously accepted connection.
  122. Arguments:
  123. pConnection - Supplies a pointer to a connection as previously
  124. indicated to the PUL_CONNECTION_REQUEST handler.
  125. AbortiveDisconnect - Supplies TRUE if the connection is to be abortively
  126. disconnected, FALSE if it should be gracefully disconnected.
  127. pCompletionRoutine - Supplies a pointer to a completion routine to
  128. invoke after the connection is fully closed.
  129. pCompletionContext - Supplies an uninterpreted context value for the
  130. completion routine.
  131. Return Value:
  132. NTSTATUS - Completion status.
  133. --***************************************************************************/
  134. NTSTATUS
  135. UcCloseConnection(
  136. IN PVOID pConnectionContext,
  137. IN BOOLEAN AbortiveDisconnect,
  138. IN PUL_COMPLETION_ROUTINE pCompletionRoutine,
  139. IN PVOID pCompletionContext,
  140. IN NTSTATUS status
  141. )
  142. {
  143. KIRQL OldIrql;
  144. PUC_CLIENT_CONNECTION pConnection;
  145. //
  146. // Sanity check.
  147. //
  148. pConnection = (PUC_CLIENT_CONNECTION) pConnectionContext;
  149. ASSERT( UC_IS_VALID_CLIENT_CONNECTION( pConnection ) );
  150. UlAcquireSpinLock(&pConnection->SpinLock, &OldIrql);
  151. if(AbortiveDisconnect)
  152. {
  153. switch(pConnection->ConnectionState)
  154. {
  155. case UcConnectStateConnectComplete:
  156. case UcConnectStateProxySslConnect:
  157. case UcConnectStateProxySslConnectComplete:
  158. case UcConnectStateConnectReady:
  159. case UcConnectStateDisconnectComplete:
  160. case UcConnectStatePerformingSslHandshake:
  161. pConnection->ConnectionState = UcConnectStateAbortPending;
  162. pConnection->ConnectionStatus = status;
  163. UlReleaseSpinLock(&pConnection->SpinLock, OldIrql);
  164. status = UcpCloseRawConnection(
  165. pConnection,
  166. AbortiveDisconnect,
  167. pCompletionRoutine,
  168. pCompletionContext
  169. );
  170. break;
  171. case UcConnectStateDisconnectPending:
  172. // We had originally sent a graceful disconnect, but now
  173. // we intend to RST the connection. We should propagate the
  174. // new error code.
  175. pConnection->ConnectionStatus = status;
  176. pConnection->Flags |= CLIENT_CONN_FLAG_ABORT_PENDING;
  177. UlReleaseSpinLock(&pConnection->SpinLock, OldIrql);
  178. break;
  179. default:
  180. UlReleaseSpinLock(&pConnection->SpinLock, OldIrql);
  181. break;
  182. }
  183. }
  184. else
  185. {
  186. switch(pConnection->ConnectionState)
  187. {
  188. case UcConnectStateConnectReady:
  189. //
  190. // We only send graceful disconnects through the filter
  191. // process. There's also no point in going through the
  192. // filter if the connection is already being closed or
  193. // aborted.
  194. //
  195. pConnection->ConnectionStatus = status;
  196. if(pConnection->FilterInfo.pFilterChannel)
  197. {
  198. pConnection->ConnectionState =
  199. UcConnectStateIssueFilterClose;
  200. ASSERT(pCompletionRoutine == NULL);
  201. ASSERT(pCompletionContext == NULL);
  202. UcKickOffConnectionStateMachine(
  203. pConnection,
  204. OldIrql,
  205. UcConnectionWorkItem
  206. );
  207. }
  208. else
  209. {
  210. pConnection->ConnectionState =
  211. UcConnectStateDisconnectPending;
  212. UlReleaseSpinLock(&pConnection->SpinLock, OldIrql);
  213. //
  214. // Really close the connection.
  215. //
  216. status = UcpCloseRawConnection(
  217. pConnection,
  218. AbortiveDisconnect,
  219. pCompletionRoutine,
  220. pCompletionContext
  221. );
  222. }
  223. break;
  224. default:
  225. UlReleaseSpinLock(&pConnection->SpinLock, OldIrql);
  226. break;
  227. }
  228. }
  229. return status;
  230. } // UcCloseConnection
  231. /*********************************************************************++
  232. Routine Description:
  233. This is our basic TDI send routine. We take an request structure, format
  234. the IRP as a TDI send IRP, and send it.
  235. Arguments:
  236. pRequest - Pointer to request to be sent.
  237. pConnection - Connection on which request is to be sent.
  238. Return Value:
  239. NTSTATUS - Status of send.
  240. --*********************************************************************/
  241. NTSTATUS
  242. UcSendData(
  243. IN PUC_CLIENT_CONNECTION pConnection,
  244. IN PMDL pMdlChain,
  245. IN ULONG Length,
  246. IN PUL_COMPLETION_ROUTINE pCompletionRoutine,
  247. IN PVOID pCompletionContext,
  248. IN PIRP pIrp,
  249. IN BOOLEAN RawSend
  250. )
  251. {
  252. PUL_IRP_CONTEXT pIrpContext;
  253. NTSTATUS status;
  254. //
  255. // Sanity Checks.
  256. //
  257. ASSERT( UC_IS_VALID_CLIENT_CONNECTION(pConnection) );
  258. ASSERT( pMdlChain != NULL);
  259. ASSERT( Length > 0);
  260. ASSERT( pCompletionRoutine != NULL);
  261. //
  262. // Allocate and initialize the IRP context
  263. //
  264. pIrpContext = UlPplAllocateIrpContext();
  265. if(pIrpContext == NULL)
  266. {
  267. status = STATUS_INSUFFICIENT_RESOURCES;
  268. goto fatal;
  269. }
  270. ASSERT( IS_VALID_IRP_CONTEXT( pIrpContext ) );
  271. pIrpContext->pConnectionContext = (PVOID)pConnection;
  272. pIrpContext->pCompletionContext = pCompletionContext;
  273. pIrpContext->pOwnIrp = pIrp;
  274. pIrpContext->pCompletionRoutine = pCompletionRoutine;
  275. pIrpContext->OwnIrpContext = FALSE;
  276. //
  277. // Try to send the data.
  278. //
  279. if (pConnection->FilterInfo.pFilterChannel && !RawSend)
  280. {
  281. PAGED_CODE();
  282. //
  283. // First go through the filter.
  284. //
  285. status = UlFilterSendHandler(
  286. &pConnection->FilterInfo,
  287. pMdlChain,
  288. Length,
  289. pIrpContext
  290. );
  291. ASSERT(status == STATUS_PENDING);
  292. }
  293. else
  294. {
  295. //
  296. // Just send it directly to the network.
  297. //
  298. status = UcpSendRawData(
  299. pConnection,
  300. pMdlChain,
  301. Length,
  302. pIrpContext,
  303. FALSE
  304. );
  305. }
  306. if (!NT_SUCCESS(status))
  307. {
  308. goto fatal;
  309. }
  310. return STATUS_PENDING;
  311. fatal:
  312. ASSERT(!NT_SUCCESS(status));
  313. if(pIrpContext != NULL)
  314. {
  315. UlPplFreeIrpContext(pIrpContext);
  316. }
  317. UC_CLOSE_CONNECTION(pConnection, TRUE, status);
  318. status = UlInvokeCompletionRoutine(
  319. status,
  320. 0,
  321. pCompletionRoutine,
  322. pCompletionContext
  323. );
  324. return status;
  325. } // UcSendData
  326. /***************************************************************************++
  327. Routine Description:
  328. Receives data from the specified connection. This function is
  329. typically used after a receive indication handler has failed to
  330. consume all of the indicated data.
  331. If the connection is filtered, the data will be read from the filter
  332. channel.
  333. Arguments:
  334. pConnection - Supplies a pointer to a connection as previously
  335. indicated to the PUL_CONNECTION_REQUEST handler.
  336. pBuffer - Supplies a pointer to the target buffer for the received
  337. data.
  338. BufferLength - Supplies the length of pBuffer.
  339. pCompletionRoutine - Supplies a pointer to a completion routine to
  340. invoke after the listening endpoint is fully closed.
  341. pCompletionContext - Supplies an uninterpreted context value for the
  342. completion routine.
  343. Return Value:
  344. NTSTATUS - Completion status.
  345. --***************************************************************************/
  346. NTSTATUS
  347. UcReceiveData(
  348. IN PVOID pConnectionContext,
  349. IN PVOID pBuffer,
  350. IN ULONG BufferLength,
  351. IN PUL_COMPLETION_ROUTINE pCompletionRoutine,
  352. IN PVOID pCompletionContext
  353. )
  354. {
  355. NTSTATUS status;
  356. PUC_CLIENT_CONNECTION pConnection;
  357. pConnection = (PUC_CLIENT_CONNECTION) pConnectionContext;
  358. //
  359. // Sanity check.
  360. //
  361. ASSERT( UC_IS_VALID_CLIENT_CONNECTION( pConnection ) );
  362. if(pConnection->FilterInfo.pFilterChannel)
  363. {
  364. //
  365. // This is a filtered connection, get the data from the
  366. // filter.
  367. //
  368. status = UlFilterReadHandler(
  369. &pConnection->FilterInfo,
  370. (PBYTE)pBuffer,
  371. BufferLength,
  372. pCompletionRoutine,
  373. pCompletionContext
  374. );
  375. }
  376. else
  377. {
  378. //
  379. // This is not a filtered connection. Get the data from
  380. // TDI.
  381. //
  382. status = UcpReceiveRawData(
  383. pConnectionContext,
  384. pBuffer,
  385. BufferLength,
  386. pCompletionRoutine,
  387. pCompletionContext
  388. );
  389. }
  390. return status;
  391. }
  392. //
  393. // Private Functions
  394. //
  395. /***************************************************************************++
  396. Routine Description:
  397. Handler for disconnect requests.
  398. Arguments:
  399. pTdiEventContext - Supplies the context associated with the address
  400. object. This should be a PUL_ENDPOINT.
  401. ConnectionContext - Supplies the context associated with the
  402. connection object. This should be a PUC_CONNECTION.
  403. DisconnectDataLength - Optionally supplies the length of any
  404. disconnect data associated with the disconnect request.
  405. pDisconnectData - Optionally supplies a pointer to any disconnect
  406. data associated with the disconnect request.
  407. DisconnectInformationLength - Optionally supplies the length of any
  408. disconnect information associated with the disconnect request.
  409. pDisconnectInformation - Optionally supplies a pointer to any
  410. disconnect information associated with the disconnect request.
  411. DisconnectFlags - Supplies the disconnect flags. This will be zero
  412. or more TDI_DISCONNECT_* flags.
  413. Return Value:
  414. NTSTATUS - Completion status.
  415. --***************************************************************************/
  416. NTSTATUS
  417. UcpTdiDisconnectHandler(
  418. IN PVOID pTdiEventContext,
  419. IN CONNECTION_CONTEXT ConnectionContext,
  420. IN LONG DisconnectDataLength,
  421. IN PVOID pDisconnectData,
  422. IN LONG DisconnectInformationLength,
  423. IN PVOID pDisconnectInformation,
  424. IN ULONG DisconnectFlags
  425. )
  426. {
  427. PUC_CLIENT_CONNECTION pConnection;
  428. PUC_TDI_OBJECTS pTdiObjects;
  429. NTSTATUS status = STATUS_SUCCESS;
  430. KIRQL OldIrql;
  431. UNREFERENCED_PARAMETER(pDisconnectInformation);
  432. UNREFERENCED_PARAMETER(DisconnectInformationLength);
  433. UNREFERENCED_PARAMETER(pDisconnectData);
  434. UNREFERENCED_PARAMETER(DisconnectDataLength);
  435. UNREFERENCED_PARAMETER(pTdiEventContext);
  436. UL_ENTER_DRIVER("UcpTdiDisconnectHandler", NULL);
  437. pTdiObjects = (PUC_TDI_OBJECTS) ConnectionContext;
  438. pConnection = pTdiObjects->pConnection;
  439. if(pConnection == NULL)
  440. {
  441. status = STATUS_INVALID_DEVICE_REQUEST;
  442. goto end;
  443. }
  444. ASSERT( UC_IS_VALID_CLIENT_CONNECTION(pConnection) );
  445. UlAcquireSpinLock(&pConnection->SpinLock, &OldIrql);
  446. //
  447. // Update the connection state based on the type of disconnect.
  448. //
  449. if(DisconnectFlags & TDI_DISCONNECT_ABORT)
  450. {
  451. pConnection->Flags |= CLIENT_CONN_FLAG_ABORT_RECEIVED;
  452. UC_WRITE_TRACE_LOG(
  453. g_pUcTraceLog,
  454. UC_ACTION_CONNECTION_TDI_DISCONNECT,
  455. pConnection,
  456. UlongToPtr((ULONG)STATUS_CONNECTION_ABORTED),
  457. UlongToPtr(pConnection->ConnectionState),
  458. UlongToPtr(pConnection->Flags)
  459. );
  460. switch(pConnection->ConnectionState)
  461. {
  462. case UcConnectStateConnectReady:
  463. case UcConnectStateDisconnectComplete:
  464. case UcConnectStatePerformingSslHandshake:
  465. case UcConnectStateConnectComplete:
  466. case UcConnectStateProxySslConnectComplete:
  467. case UcConnectStateProxySslConnect:
  468. // Received an abort when we were connected or have completed
  469. // our half close, proceed to cleanup. Cleanup can be done
  470. // only at passive, so we start the worker.
  471. pConnection->ConnectionStatus = STATUS_CONNECTION_ABORTED;
  472. pConnection->ConnectionState = UcConnectStateConnectCleanup;
  473. UC_WRITE_TRACE_LOG(
  474. g_pUcTraceLog,
  475. UC_ACTION_CONNECTION_CLEANUP,
  476. pConnection,
  477. UlongToPtr((ULONG)pConnection->ConnectionStatus),
  478. UlongToPtr(pConnection->ConnectionState),
  479. UlongToPtr(pConnection->Flags)
  480. );
  481. UcKickOffConnectionStateMachine(
  482. pConnection,
  483. OldIrql,
  484. UcConnectionWorkItem
  485. );
  486. break;
  487. case UcConnectStateDisconnectPending:
  488. // We got a RST when we had a pending disconnect. Let's flag
  489. // the connection so that we complete the cleanup when our
  490. // Disconnect Completes.
  491. pConnection->ConnectionStatus = STATUS_CONNECTION_ABORTED;
  492. UlReleaseSpinLock(&pConnection->SpinLock,OldIrql);
  493. break;
  494. case UcConnectStateDisconnectIndicatedPending:
  495. // When we get a disconnect indication, we issue one ourselves.
  496. // Therefore, there is no need for us to do anything with this
  497. // abort. When our pending disconnect compeltes, we'll
  498. // cleanup anyway.
  499. pConnection->ConnectionStatus = STATUS_CONNECTION_ABORTED;
  500. UlReleaseSpinLock(&pConnection->SpinLock,OldIrql);
  501. break;
  502. default:
  503. //
  504. // We don't have to do anything here.
  505. //
  506. UlReleaseSpinLock(&pConnection->SpinLock,OldIrql);
  507. break;
  508. }
  509. }
  510. else
  511. {
  512. pConnection->Flags |= CLIENT_CONN_FLAG_DISCONNECT_RECEIVED;
  513. UC_WRITE_TRACE_LOG(
  514. g_pUcTraceLog,
  515. UC_ACTION_CONNECTION_TDI_DISCONNECT,
  516. pConnection,
  517. UlongToPtr((ULONG)STATUS_CONNECTION_DISCONNECTED),
  518. UlongToPtr(pConnection->ConnectionState),
  519. UlongToPtr(pConnection->Flags)
  520. );
  521. switch(pConnection->ConnectionState)
  522. {
  523. case UcConnectStateConnectReady:
  524. pConnection->ConnectionStatus = STATUS_CONNECTION_DISCONNECTED;
  525. if(pConnection->FilterInfo.pFilterChannel)
  526. {
  527. //
  528. // When we receive a graceful close, it means that the
  529. // server has finished sending data on this connection
  530. // & has initiated a half close. However, some of this
  531. // received data might be stuck in the filter.
  532. //
  533. // Therefore, we have to wait till the filter calls us back
  534. // in the receive handler before we cleanup this
  535. // connection. Hence we will send the disconnect
  536. // indication via the filter.
  537. //
  538. // This allows the filter routine to call us back
  539. // (via HttpCloseFilter, which will result in a call to
  540. // UcpCloseRawConnection) after it has indicated all the
  541. // data.
  542. //
  543. // Since we are at DPC, we cannot issue this from here.
  544. // We'll fire the connection worker to achieve this.
  545. //
  546. pConnection->ConnectionState =
  547. UcConnectStateIssueFilterDisconnect;
  548. UcKickOffConnectionStateMachine(
  549. pConnection,
  550. OldIrql,
  551. UcConnectionWorkItem
  552. );
  553. }
  554. else
  555. {
  556. pConnection->ConnectionState =
  557. UcConnectStateDisconnectIndicatedPending;
  558. UlReleaseSpinLock(&pConnection->SpinLock, OldIrql);
  559. UcpCloseRawConnection( pConnection,
  560. FALSE,
  561. NULL,
  562. NULL
  563. );
  564. }
  565. break;
  566. case UcConnectStateConnectComplete:
  567. case UcConnectStatePerformingSslHandshake:
  568. case UcConnectStateProxySslConnectComplete:
  569. case UcConnectStateProxySslConnect:
  570. // We were waiting for the server cert to be negotiated, but
  571. // we got called in the disconnect handler. We'll treat this
  572. // as a normal Disconnect.
  573. pConnection->ConnectionStatus = STATUS_CONNECTION_DISCONNECTED;
  574. pConnection->ConnectionState =
  575. UcConnectStateDisconnectIndicatedPending;
  576. UlReleaseSpinLock(&pConnection->SpinLock, OldIrql);
  577. UcpCloseRawConnection( pConnection,
  578. FALSE,
  579. NULL,
  580. NULL
  581. );
  582. break;
  583. case UcConnectStateDisconnectComplete:
  584. //
  585. // If we receive a graceful close in this state, we still
  586. // need to bounce this via the filter, since we need to
  587. // synchronize this close with the already indicated data.
  588. // (see description above). However, when the filter calls
  589. // us back, we must proceed directly to clean the
  590. // connection.
  591. //
  592. if(pConnection->FilterInfo.pFilterChannel &&
  593. !(pConnection->Flags & CLIENT_CONN_FLAG_FILTER_CLOSED))
  594. {
  595. //
  596. // Flag it so that we will directly cleanup when we get
  597. // called back by the filter.
  598. //
  599. pConnection->Flags |= CLIENT_CONN_FLAG_FILTER_CLEANUP;
  600. pConnection->ConnectionState =
  601. UcConnectStateIssueFilterDisconnect;
  602. }
  603. else
  604. {
  605. pConnection->ConnectionState = UcConnectStateConnectCleanup;
  606. UC_WRITE_TRACE_LOG(
  607. g_pUcTraceLog,
  608. UC_ACTION_CONNECTION_CLEANUP,
  609. pConnection,
  610. UlongToPtr((ULONG)pConnection->ConnectionStatus),
  611. UlongToPtr(pConnection->ConnectionState),
  612. UlongToPtr(pConnection->Flags)
  613. );
  614. }
  615. UcKickOffConnectionStateMachine(
  616. pConnection,
  617. OldIrql,
  618. UcConnectionWorkItem
  619. );
  620. break;
  621. case UcConnectStateDisconnectPending:
  622. // We have received a disconnect when we have sent ours,
  623. // which is not yet complete. Flag the connection so that
  624. // we do the cleanup when the disconnect is complete.
  625. UlReleaseSpinLock(&pConnection->SpinLock, OldIrql);
  626. break;
  627. default:
  628. UlReleaseSpinLock(&pConnection->SpinLock, OldIrql);
  629. break;
  630. }
  631. }
  632. end:
  633. UL_LEAVE_DRIVER("UcpTdiDisconnectHandler");
  634. return status;
  635. }
  636. /***************************************************************************++
  637. Routine Description:
  638. Closes a previously open connection.
  639. Arguments:
  640. pConnection- Supplies the connection object
  641. AbortiveDisconnect - TRUE if the connection has to be abortively
  642. disconnected, FALSE if it has to be gracefully
  643. disconnected.
  644. Return Value:
  645. NTSTATUS - Completion status.
  646. --***************************************************************************/
  647. NTSTATUS
  648. UcpCloseRawConnection(
  649. IN PVOID pConn,
  650. IN BOOLEAN AbortiveDisconnect,
  651. IN PUL_COMPLETION_ROUTINE pCompletionRoutine,
  652. IN PVOID pCompletionContext
  653. )
  654. {
  655. PUC_CLIENT_CONNECTION pConnection = (PUC_CLIENT_CONNECTION) pConn;
  656. ASSERT( UC_IS_VALID_CLIENT_CONNECTION(pConnection) );
  657. UC_WRITE_TRACE_LOG(
  658. g_pUcTraceLog,
  659. UC_ACTION_CONNECTION_RAW_CLOSE,
  660. pConnection,
  661. UlongToPtr(AbortiveDisconnect),
  662. UlongToPtr(pConnection->Flags),
  663. UlongToPtr(pConnection->ConnectionState)
  664. );
  665. //
  666. // This is the final close handler for all types of connections
  667. // filter, non filter. We should not go through this path twice
  668. //
  669. if(AbortiveDisconnect)
  670. {
  671. ASSERT(pConnection->ConnectionState == UcConnectStateAbortPending);
  672. return UcpBeginAbort(
  673. pConnection,
  674. pCompletionRoutine,
  675. pCompletionContext
  676. );
  677. }
  678. else
  679. {
  680. ASSERT(pConnection->ConnectionState ==
  681. UcConnectStateDisconnectIndicatedPending ||
  682. pConnection->ConnectionState ==
  683. UcConnectStateDisconnectPending);
  684. return UcpBeginDisconnect(
  685. pConnection,
  686. pCompletionRoutine,
  687. pCompletionContext
  688. );
  689. }
  690. }
  691. /***************************************************************************++
  692. Routine Description:
  693. Closes a previously open connection; called from the filter code. The
  694. server code just uses UlpCloseRawConnection for this routine.
  695. We need a seperate routine because we want to conditionally call
  696. UcpCloseRawConnection based on some state.
  697. Arguments:
  698. pConnection- Supplies the connection object
  699. AbortiveDisconnect - TRUE if the connection has to be abortively
  700. disconnected, FALSE if it has to be gracefully
  701. disconnected.
  702. Return Value:
  703. NTSTATUS - Completion status.
  704. --***************************************************************************/
  705. NTSTATUS
  706. UcCloseRawFilterConnection(
  707. IN PVOID pConn,
  708. IN BOOLEAN AbortiveDisconnect,
  709. IN PUL_COMPLETION_ROUTINE pCompletionRoutine,
  710. IN PVOID pCompletionContext
  711. )
  712. {
  713. KIRQL OldIrql;
  714. PUC_CLIENT_CONNECTION pConnection = (PUC_CLIENT_CONNECTION) pConn;
  715. ASSERT( UC_IS_VALID_CLIENT_CONNECTION(pConnection) );
  716. UC_WRITE_TRACE_LOG(
  717. g_pUcTraceLog,
  718. UC_ACTION_CONNECTION_RAW_FILTER_CLOSE,
  719. pConnection,
  720. UlongToPtr(AbortiveDisconnect),
  721. UlongToPtr(pConnection->Flags),
  722. UlongToPtr(pConnection->ConnectionState)
  723. );
  724. if(AbortiveDisconnect)
  725. {
  726. //
  727. // This will do some state checks & land up calling
  728. // UcpCloseRawConnection. In order to modularize the code, we just
  729. // call UcCloseConnection.
  730. //
  731. return UcCloseConnection(pConnection,
  732. AbortiveDisconnect,
  733. pCompletionRoutine,
  734. pCompletionContext,
  735. STATUS_CONNECTION_ABORTED
  736. );
  737. }
  738. UlAcquireSpinLock(&pConnection->SpinLock, &OldIrql);
  739. pConnection->Flags |= CLIENT_CONN_FLAG_FILTER_CLOSED;
  740. if(pConnection->ConnectionState == UcConnectStateDisconnectPending ||
  741. pConnection->ConnectionState == UcConnectStatePerformingSslHandshake ||
  742. pConnection->ConnectionState == UcConnectStateIssueFilterDisconnect ||
  743. pConnection->ConnectionState == UcConnectStateDisconnectIndicatedPending)
  744. {
  745. pConnection->ConnectionState = UcConnectStateDisconnectPending;
  746. UlReleaseSpinLock(&pConnection->SpinLock, OldIrql);
  747. //
  748. // We've routed the disconnect via the filter. We can just proceed
  749. // to close the raw connection.
  750. //
  751. return UcpCloseRawConnection(
  752. pConnection,
  753. AbortiveDisconnect,
  754. pCompletionRoutine,
  755. pCompletionContext
  756. );
  757. }
  758. else
  759. {
  760. UlReleaseSpinLock(&pConnection->SpinLock, OldIrql);
  761. return UlInvokeCompletionRoutine(
  762. STATUS_SUCCESS,
  763. 0,
  764. pCompletionRoutine,
  765. pCompletionContext
  766. );
  767. }
  768. }
  769. /***************************************************************************++
  770. Routine Description:
  771. The filter calls us back in this routine after it's processed the incoming
  772. disconnet indication.
  773. Arguments:
  774. pConnection - Supplies a pointer to a connection
  775. --***************************************************************************/
  776. VOID
  777. UcDisconnectRawFilterConnection(
  778. IN PVOID pConnectionContext
  779. )
  780. {
  781. KIRQL OldIrql;
  782. PUC_CLIENT_CONNECTION pConnection;
  783. pConnection = (PUC_CLIENT_CONNECTION)pConnectionContext;
  784. //
  785. // Sanity check.
  786. //
  787. ASSERT(UC_IS_VALID_CLIENT_CONNECTION(pConnection));
  788. UlAcquireSpinLock(&pConnection->SpinLock, &OldIrql);
  789. UC_WRITE_TRACE_LOG(
  790. g_pUcTraceLog,
  791. UC_ACTION_CONNECTION_RAW_FILTER_DISCONNECT,
  792. pConnection,
  793. UlongToPtr(pConnection->Flags),
  794. UlongToPtr(pConnection->ConnectionState),
  795. 0
  796. );
  797. if(pConnection->ConnectionState == UcConnectStateDisconnectIndicatedPending)
  798. {
  799. if(pConnection->Flags & CLIENT_CONN_FLAG_FILTER_CLEANUP)
  800. {
  801. pConnection->ConnectionState = UcConnectStateConnectCleanup;
  802. UcKickOffConnectionStateMachine(
  803. pConnection,
  804. OldIrql,
  805. UcConnectionWorkItem
  806. );
  807. }
  808. else
  809. {
  810. UlReleaseSpinLock(&pConnection->SpinLock, OldIrql);
  811. UcpCloseRawConnection(
  812. pConnection,
  813. FALSE, // Abortive Disconnect
  814. NULL,
  815. NULL
  816. );
  817. }
  818. }
  819. else
  820. {
  821. // Sometimes, the wierd filter calls us more than once for the
  822. // same connection.
  823. UlReleaseSpinLock(&pConnection->SpinLock, OldIrql);
  824. }
  825. } // UcDisconnectRawFilterConnection
  826. /*********************************************************************++
  827. Routine Description:
  828. Sends a block of data on the specified connection.
  829. Arguments:
  830. pConnection - Supplies a pointer to a connection as previously
  831. indicated to the PUL_CONNECTION_REQUEST handler.
  832. pMdlChain - Supplies a pointer to a MDL chain describing the
  833. data buffers to send.
  834. Length - Supplies the length of the data referenced by the MDL
  835. chain.
  836. pIrpContext - used to indicate completion to the caller.
  837. InitiateDisconnect - Supplies TRUE if a graceful disconnect should
  838. be initiated immediately after initiating the send (i.e. before
  839. the send actually completes).
  840. --*********************************************************************/
  841. NTSTATUS
  842. UcpSendRawData(
  843. IN PVOID pConnectionContext,
  844. IN PMDL pMdlChain,
  845. IN ULONG Length,
  846. IN PUL_IRP_CONTEXT pIrpContext,
  847. IN BOOLEAN InitiateDisconnect
  848. )
  849. {
  850. PUC_CLIENT_CONNECTION pConnection;
  851. NTSTATUS status;
  852. PIRP pIrp;
  853. BOOLEAN OwnIrpContext = TRUE;
  854. UNREFERENCED_PARAMETER(InitiateDisconnect);
  855. pConnection = (PUC_CLIENT_CONNECTION) pConnectionContext;
  856. pIrp = pIrpContext->pOwnIrp;
  857. ASSERT( UC_IS_VALID_CLIENT_CONNECTION(pConnection) );
  858. //
  859. // See if there is space in the IRP to handle this request.
  860. //
  861. if(pIrp == NULL ||
  862. pIrp->CurrentLocation -
  863. pConnection->pTdiObjects->ConnectionObject.pDeviceObject->StackSize < 1)
  864. {
  865. pIrp =
  866. UlAllocateIrp(
  867. pConnection->pTdiObjects->ConnectionObject.pDeviceObject->StackSize,
  868. FALSE
  869. );
  870. if(!pIrp)
  871. {
  872. status = STATUS_INSUFFICIENT_RESOURCES;
  873. goto fatal;
  874. }
  875. OwnIrpContext = FALSE;
  876. }
  877. ASSERT( pIrp );
  878. //
  879. // The connection is already referenced for us while the request is
  880. // on a queue, so we don't need to do it again.
  881. pIrp->RequestorMode = KernelMode;
  882. // pIrp->Tail.Overlay.Thread = PsGetCurrentThread();
  883. // pIrp->Tail.Overlay.OriginalFileObject = pTdiObject->pFileObject;
  884. TdiBuildSend(
  885. pIrp,
  886. pConnection->pTdiObjects->ConnectionObject.pDeviceObject,
  887. pConnection->pTdiObjects->ConnectionObject.pFileObject,
  888. &UcpRestartSendData,
  889. pIrpContext,
  890. pMdlChain,
  891. 0,
  892. Length
  893. );
  894. WRITE_REF_TRACE_LOG(
  895. g_pMdlTraceLog,
  896. REF_ACTION_SEND_MDL,
  897. PtrToLong(pMdlChain->Next), // bugbug64
  898. pMdlChain,
  899. __FILE__,
  900. __LINE__
  901. );
  902. //
  903. // Submit the IRP.
  904. // UC_BUGBUG (PERF) UL does this thing called fast send, check later.
  905. //
  906. UlCallDriver(
  907. pConnection->pTdiObjects->ConnectionObject.pDeviceObject,
  908. pIrp
  909. );
  910. return STATUS_PENDING;
  911. fatal:
  912. ASSERT(!NT_SUCCESS(status));
  913. if(pIrp != NULL && OwnIrpContext == FALSE)
  914. {
  915. UlFreeIrp(pIrp);
  916. }
  917. UC_CLOSE_CONNECTION(pConnection, TRUE, status);
  918. return status;
  919. }
  920. /***************************************************************************++
  921. Routine Description:
  922. Receives data from the specified connection. This function is
  923. typically used after a receive indication handler has failed to
  924. consume all of the indicated data.
  925. Arguments:
  926. pConnection - Supplies a pointer to a connection as previously
  927. indicated to the PUL_CONNECTION_REQUEST handler.
  928. pBuffer - Supplies a pointer to the target buffer for the received
  929. data.
  930. BufferLength - Supplies the length of pBuffer.
  931. pCompletionRoutine - Supplies a pointer to a completion routine to
  932. invoke after the listening endpoint is fully closed.
  933. pCompletionContext - Supplies an uninterpreted context value for the
  934. completion routine.
  935. Return Value:
  936. NTSTATUS - Completion status.
  937. --***************************************************************************/
  938. NTSTATUS
  939. UcpReceiveRawData(
  940. IN PVOID pConnectionContext,
  941. IN PVOID pBuffer,
  942. IN ULONG BufferLength,
  943. IN PUL_COMPLETION_ROUTINE pCompletionRoutine,
  944. IN PVOID pCompletionContext
  945. )
  946. {
  947. NTSTATUS Status;
  948. PUX_TDI_OBJECT pTdiObject;
  949. PUL_IRP_CONTEXT pIrpContext;
  950. PIRP pIrp;
  951. PMDL pMdl;
  952. PUC_CLIENT_CONNECTION pConnection;
  953. pConnection = (PUC_CLIENT_CONNECTION) pConnectionContext;
  954. ASSERT(UC_IS_VALID_CLIENT_CONNECTION(pConnection));
  955. pTdiObject = &pConnection->pTdiObjects->ConnectionObject;
  956. ASSERT( IS_VALID_TDI_OBJECT( pTdiObject ) );
  957. ASSERT( pCompletionRoutine != NULL );
  958. //
  959. // Setup locals so we know how to cleanup on failure.
  960. //
  961. pIrpContext = NULL;
  962. pIrp = NULL;
  963. pMdl = NULL;
  964. //
  965. // Create & initialize a receive IRP.
  966. //
  967. pIrp = UlAllocateIrp(
  968. pTdiObject->pDeviceObject->StackSize, // StackSize
  969. FALSE // ChargeQuota
  970. );
  971. if (pIrp != NULL)
  972. {
  973. //
  974. // Snag an IRP context.
  975. //
  976. pIrpContext = UlPplAllocateIrpContext();
  977. if (pIrpContext != NULL)
  978. {
  979. ASSERT( IS_VALID_IRP_CONTEXT( pIrpContext ) );
  980. pIrpContext->pConnectionContext = (PVOID)pConnection;
  981. pIrpContext->pCompletionRoutine = pCompletionRoutine;
  982. pIrpContext->pCompletionContext = pCompletionContext;
  983. pIrpContext->OwnIrpContext = FALSE;
  984. //
  985. // Create an MDL describing the client's buffer.
  986. //
  987. pMdl = UlAllocateMdl(
  988. pBuffer, // VirtualAddress
  989. BufferLength, // Length
  990. FALSE, // SecondaryBuffer
  991. FALSE, // ChargeQuota
  992. NULL // Irp
  993. );
  994. if (pMdl != NULL)
  995. {
  996. //
  997. // Adjust the MDL for our non-paged buffer.
  998. //
  999. MmBuildMdlForNonPagedPool( pMdl );
  1000. //
  1001. // Reference the connection, finish building the IRP.
  1002. //
  1003. REFERENCE_CLIENT_CONNECTION( pConnection );
  1004. TdiBuildReceive(
  1005. pIrp, // Irp
  1006. pTdiObject->pDeviceObject, // DeviceObject
  1007. pTdiObject->pFileObject, // FileObject
  1008. &UcpRestartClientReceive, // CompletionRoutine
  1009. pIrpContext, // CompletionContext
  1010. pMdl, // Mdl
  1011. TDI_RECEIVE_NORMAL, // Flags
  1012. BufferLength // Length
  1013. );
  1014. //
  1015. // Let the transport do the rest.
  1016. //
  1017. UlCallDriver( pTdiObject->pDeviceObject, pIrp );
  1018. return STATUS_PENDING;
  1019. }
  1020. }
  1021. }
  1022. //
  1023. // We only make it this point if we hit an allocation failure.
  1024. //
  1025. if (pMdl != NULL)
  1026. {
  1027. UlFreeMdl( pMdl );
  1028. }
  1029. if (pIrpContext != NULL)
  1030. {
  1031. UlPplFreeIrpContext( pIrpContext );
  1032. }
  1033. if (pIrp != NULL)
  1034. {
  1035. UlFreeIrp( pIrp );
  1036. }
  1037. Status = UlInvokeCompletionRoutine(
  1038. STATUS_INSUFFICIENT_RESOURCES,
  1039. 0,
  1040. pCompletionRoutine,
  1041. pCompletionContext
  1042. );
  1043. return Status;
  1044. } // UcpReceiveRawData
  1045. /***************************************************************************++
  1046. Routine Description:
  1047. Handler for normal receive data.
  1048. Arguments:
  1049. pTdiEventContext - Supplies the context associated with the address
  1050. object. This should be a PUL_ENDPOINT.
  1051. ConnectionContext - Supplies the context associated with the
  1052. connection object. This should be a PUC_CONNECTION.
  1053. ReceiveFlags - Supplies the receive flags. This will be zero or more
  1054. TDI_RECEIVE_* flags.
  1055. BytesIndicated - Supplies the number of bytes indicated in pTsdu.
  1056. BytesAvailable - Supplies the number of bytes available in this
  1057. TSDU.
  1058. pBytesTaken - Receives the number of bytes consumed by this handler.
  1059. pTsdu - Supplies a pointer to the indicated data.
  1060. pIrp - Receives an IRP if the handler needs more data than indicated.
  1061. Return Value:
  1062. NTSTATUS - Completion status.
  1063. --***************************************************************************/
  1064. NTSTATUS
  1065. UcpTdiReceiveHandler(
  1066. IN PVOID pTdiEventContext,
  1067. IN CONNECTION_CONTEXT ConnectionContext,
  1068. IN ULONG ReceiveFlags,
  1069. IN ULONG BytesIndicated,
  1070. IN ULONG BytesAvailable,
  1071. OUT ULONG *pBytesTaken,
  1072. IN PVOID pTsdu,
  1073. OUT PIRP *pIrp
  1074. )
  1075. {
  1076. NTSTATUS status;
  1077. PUC_TDI_OBJECTS pTdiObjects;
  1078. PUC_CLIENT_CONNECTION pConnection;
  1079. PUX_TDI_OBJECT pTdiObject;
  1080. KIRQL OldIrql;
  1081. UNREFERENCED_PARAMETER(ReceiveFlags);
  1082. UNREFERENCED_PARAMETER(pTdiEventContext);
  1083. UL_ENTER_DRIVER("UcpTdiReceiveHandler", NULL);
  1084. //
  1085. // Sanity check.
  1086. //
  1087. pTdiObjects = (PUC_TDI_OBJECTS) ConnectionContext;
  1088. pConnection = pTdiObjects->pConnection;
  1089. ASSERT( UC_IS_VALID_CLIENT_CONNECTION( pConnection ) );
  1090. pTdiObject = &pConnection->pTdiObjects->ConnectionObject;
  1091. ASSERT( IS_VALID_TDI_OBJECT( pTdiObject ) );
  1092. //
  1093. // Clear the bytes taken output var
  1094. //
  1095. *pBytesTaken = 0;
  1096. if(pConnection->FilterInfo.pFilterChannel)
  1097. {
  1098. if(pConnection->ConnectionState ==
  1099. UcConnectStateConnectReady ||
  1100. pConnection->ConnectionState ==
  1101. UcConnectStatePerformingSslHandshake
  1102. )
  1103. {
  1104. //
  1105. // Needs to go through a filter.
  1106. //
  1107. status = UlFilterReceiveHandler(
  1108. &pConnection->FilterInfo,
  1109. pTsdu,
  1110. BytesIndicated,
  1111. BytesAvailable - BytesIndicated,
  1112. pBytesTaken
  1113. );
  1114. }
  1115. else
  1116. {
  1117. // We have not delivered the connection to the filter as yet.
  1118. // Let's first do that with the state transistion & then pass the
  1119. // data on.
  1120. UlAcquireSpinLock(&pConnection->SpinLock, &OldIrql);
  1121. switch(pConnection->ConnectionState)
  1122. {
  1123. case UcConnectStateConnectComplete:
  1124. {
  1125. ULONG TakenLength;
  1126. pConnection->ConnectionState =
  1127. UcConnectStatePerformingSslHandshake;
  1128. UlReleaseSpinLock(&pConnection->SpinLock, OldIrql);
  1129. UlDeliverConnectionToFilter(
  1130. &pConnection->FilterInfo,
  1131. NULL,
  1132. 0,
  1133. &TakenLength
  1134. );
  1135. ASSERT(TakenLength == 0);
  1136. status = UlFilterReceiveHandler(
  1137. &pConnection->FilterInfo,
  1138. pTsdu,
  1139. BytesIndicated,
  1140. BytesAvailable - BytesIndicated,
  1141. pBytesTaken
  1142. );
  1143. }
  1144. break;
  1145. case UcConnectStateProxySslConnect:
  1146. UlReleaseSpinLock(&pConnection->SpinLock, OldIrql);
  1147. goto handle_response;
  1148. break;
  1149. default:
  1150. UlReleaseSpinLock(&pConnection->SpinLock, OldIrql);
  1151. status = UlFilterReceiveHandler(
  1152. &pConnection->FilterInfo,
  1153. pTsdu,
  1154. BytesIndicated,
  1155. BytesAvailable - BytesIndicated,
  1156. pBytesTaken
  1157. );
  1158. break;
  1159. }
  1160. }
  1161. ASSERT( *pBytesTaken <= BytesIndicated);
  1162. ASSERT( status != STATUS_MORE_PROCESSING_REQUIRED);
  1163. }
  1164. else
  1165. {
  1166. handle_response:
  1167. if(BytesAvailable > BytesIndicated)
  1168. {
  1169. status = STATUS_MORE_PROCESSING_REQUIRED;
  1170. }
  1171. else
  1172. {
  1173. //
  1174. // otherwise, give the client a crack at the data.
  1175. //
  1176. status = UcHandleResponse(
  1177. NULL,
  1178. pConnection,
  1179. pTsdu,
  1180. BytesIndicated,
  1181. 0,
  1182. pBytesTaken
  1183. );
  1184. ASSERT( status != STATUS_MORE_PROCESSING_REQUIRED);
  1185. }
  1186. }
  1187. if (status == STATUS_SUCCESS)
  1188. {
  1189. //
  1190. // done.
  1191. //
  1192. }
  1193. else if (status == STATUS_MORE_PROCESSING_REQUIRED)
  1194. {
  1195. //
  1196. // The client consumed part of the indicated data.
  1197. //
  1198. // A subsequent receive indication will be made to the client when
  1199. // additional data is available. This subsequent indication will
  1200. // include the unconsumed data from the current indication plus
  1201. // any additional data received.
  1202. //
  1203. // We need to allocate a receive buffer so we can pass an IRP back
  1204. // to the transport.
  1205. //
  1206. status = UcpBuildTdiReceiveBuffer(pTdiObject,
  1207. pConnection,
  1208. pIrp
  1209. );
  1210. if(status == STATUS_MORE_PROCESSING_REQUIRED)
  1211. {
  1212. //
  1213. // Make the next stack location current. Normally, UlCallDriver
  1214. // would do this for us, but since we're bypassing UlCallDriver,
  1215. // we must do it ourselves.
  1216. //
  1217. IoSetNextIrpStackLocation( *pIrp );
  1218. }
  1219. else
  1220. {
  1221. goto fatal;
  1222. }
  1223. }
  1224. else
  1225. {
  1226. fatal:
  1227. //
  1228. // If we made it this far, then we've hit a fatal condition. Either the
  1229. // client returned a status code other than STATUS_SUCCESS or
  1230. // STATUS_MORE_PROCESSING_REQUIRED, or we failed to allocation the
  1231. // receive IRP to pass back to the transport. In either case, we need
  1232. // to abort the connection.
  1233. //
  1234. UC_CLOSE_CONNECTION(pConnection, TRUE, status);
  1235. }
  1236. UL_LEAVE_DRIVER("UcpTdiReceiveHandler");
  1237. return status;
  1238. } // UcpTdiReceiveHandler
  1239. /***************************************************************************++
  1240. Routine Description:
  1241. Handler for expedited receive data.
  1242. Arguments:
  1243. pTdiEventContext - Supplies the context associated with the address
  1244. object. This should be a PUL_ENDPOINT.
  1245. ConnectionContext - Supplies the context associated with the
  1246. connection object. This should be a PUL_CONNECTION.
  1247. ReceiveFlags - Supplies the receive flags. This will be zero or more
  1248. TDI_RECEIVE_* flags.
  1249. BytesIndiated - Supplies the number of bytes indicated in pTsdu.
  1250. BytesAvailable - Supplies the number of bytes available in this
  1251. TSDU.
  1252. pBytesTaken - Receives the number of bytes consumed by this handler.
  1253. pTsdu - Supplies a pointer to the indicated data.
  1254. pIrp - Receives an IRP if the handler needs more data than indicated.
  1255. Return Value:
  1256. NTSTATUS - Completion status.
  1257. --***************************************************************************/
  1258. NTSTATUS
  1259. UcpReceiveExpeditedHandler(
  1260. IN PVOID pTdiEventContext,
  1261. IN CONNECTION_CONTEXT ConnectionContext,
  1262. IN ULONG ReceiveFlags,
  1263. IN ULONG BytesIndicated,
  1264. IN ULONG BytesAvailable,
  1265. OUT ULONG *pBytesTaken,
  1266. IN PVOID pTsdu,
  1267. OUT PIRP *pIrp
  1268. )
  1269. {
  1270. PUC_CLIENT_CONNECTION pConnection;
  1271. UNREFERENCED_PARAMETER(pIrp);
  1272. UNREFERENCED_PARAMETER(pTsdu);
  1273. UNREFERENCED_PARAMETER(BytesIndicated);
  1274. UNREFERENCED_PARAMETER(ReceiveFlags);
  1275. UNREFERENCED_PARAMETER(pTdiEventContext);
  1276. UL_ENTER_DRIVER("UcpReceiveExpeditedHandler", NULL);
  1277. pConnection = (PUC_CLIENT_CONNECTION)ConnectionContext;
  1278. ASSERT( UC_IS_VALID_CLIENT_CONNECTION(pConnection) );
  1279. //
  1280. // We don't support expedited data, so just consume it all.
  1281. //
  1282. *pBytesTaken = BytesAvailable;
  1283. UL_LEAVE_DRIVER("UcpReceiveExpeditedHandler");
  1284. return STATUS_SUCCESS;
  1285. }
  1286. /***************************************************************************++
  1287. Routine Description:
  1288. Completion handler for send IRPs.
  1289. Arguments:
  1290. pDeviceObject - Supplies the device object for the IRP being
  1291. completed.
  1292. pIrp - Supplies the IRP being completed.
  1293. pContext - Supplies the context associated with this request.
  1294. This is actually a PUL_IRP_CONTEXT.
  1295. Return Value:
  1296. NTSTATUS - STATUS_SUCCESS if IO should continue processing this
  1297. IRP, STATUS_MORE_PROCESSING_REQUIRED if IO should stop processing
  1298. this IRP.
  1299. --***************************************************************************/
  1300. NTSTATUS
  1301. UcpRestartSendData(
  1302. IN PDEVICE_OBJECT pDeviceObject,
  1303. IN PIRP pIrp,
  1304. IN PVOID pContext
  1305. )
  1306. {
  1307. PUC_CLIENT_CONNECTION pConnection;
  1308. PUL_IRP_CONTEXT pIrpContext;
  1309. BOOLEAN OwnIrpContext;
  1310. UNREFERENCED_PARAMETER(pDeviceObject);
  1311. //
  1312. // Sanity check.
  1313. //
  1314. pIrpContext = (PUL_IRP_CONTEXT) pContext;
  1315. ASSERT( IS_VALID_IRP_CONTEXT( pIrpContext ) );
  1316. ASSERT( pIrpContext->pCompletionRoutine != NULL );
  1317. pConnection = (PUC_CLIENT_CONNECTION) pIrpContext->pConnectionContext;
  1318. ASSERT( UC_IS_VALID_CLIENT_CONNECTION( pConnection ) );
  1319. OwnIrpContext = (BOOLEAN)(pIrpContext->pOwnIrp == NULL);
  1320. //
  1321. // Tell the client that the send is complete.
  1322. //
  1323. (pIrpContext->pCompletionRoutine)(
  1324. pIrpContext->pCompletionContext,
  1325. pIrp->IoStatus.Status,
  1326. pIrp->IoStatus.Information
  1327. );
  1328. //
  1329. // Free the context & the IRP since we're done with them, then
  1330. // tell IO to stop processing the IRP.
  1331. //
  1332. UlPplFreeIrpContext( pIrpContext );
  1333. if(OwnIrpContext)
  1334. {
  1335. UlFreeIrp( pIrp );
  1336. }
  1337. return STATUS_MORE_PROCESSING_REQUIRED;
  1338. } // UcpRestartSendData
  1339. /***************************************************************************++
  1340. Routine Description:
  1341. Initiates a graceful disconnect on the specified connection.
  1342. Arguments:
  1343. pConnection - Supplies the connection to disconnect.
  1344. pCompletionRoutine - Supplies a pointer to a completion routine to
  1345. invoke after the connection is disconnected.
  1346. pCompletionContext - Supplies an uninterpreted context value for the
  1347. completion routine.
  1348. CleaningUp - TRUE if we're cleaning up the connection.
  1349. Return Value:
  1350. NTSTATUS - Completion status.
  1351. --***************************************************************************/
  1352. NTSTATUS
  1353. UcpBeginDisconnect(
  1354. IN PUC_CLIENT_CONNECTION pConnection,
  1355. IN PUL_COMPLETION_ROUTINE pCompletionRoutine,
  1356. IN PVOID pCompletionContext
  1357. )
  1358. {
  1359. PIRP pIrp;
  1360. PUL_IRP_CONTEXT pIrpContext;
  1361. //
  1362. // Sanity check.
  1363. //
  1364. ASSERT( UC_IS_VALID_CLIENT_CONNECTION( pConnection ) );
  1365. UC_WRITE_TRACE_LOG(
  1366. g_pUcTraceLog,
  1367. UC_ACTION_CONNECTION_BEGIN_DISCONNECT,
  1368. pConnection,
  1369. 0,
  1370. NULL,
  1371. 0
  1372. );
  1373. pIrpContext = &pConnection->pTdiObjects->IrpContext;
  1374. ASSERT( IS_VALID_IRP_CONTEXT( pIrpContext ) );
  1375. pIrpContext->pConnectionContext = (PVOID)pConnection;
  1376. pIrpContext->pCompletionRoutine = pCompletionRoutine;
  1377. pIrpContext->pCompletionContext = pCompletionContext;
  1378. pIrpContext->OwnIrpContext = TRUE;
  1379. pIrp = pConnection->pTdiObjects->pIrp;
  1380. UxInitializeDisconnectIrp(
  1381. pIrp,
  1382. &pConnection->pTdiObjects->ConnectionObject,
  1383. TDI_DISCONNECT_RELEASE,
  1384. &UcpRestartDisconnect,
  1385. pIrpContext
  1386. );
  1387. //
  1388. // Add a reference to the connection, then call the driver to initiate
  1389. // the disconnect.
  1390. //
  1391. REFERENCE_CLIENT_CONNECTION( pConnection );
  1392. UlCallDriver(
  1393. pConnection->pTdiObjects->ConnectionObject.pDeviceObject,
  1394. pIrp
  1395. );
  1396. return STATUS_PENDING;
  1397. } // BeginDisconnect
  1398. /***************************************************************************++
  1399. Routine Description:
  1400. Completion handler for graceful disconnect IRPs.
  1401. Arguments:
  1402. pDeviceObject - Supplies the device object for the IRP being
  1403. completed.
  1404. pIrp - Supplies the IRP being completed.
  1405. pContext - Supplies the context associated with this request.
  1406. This is actually a PUL_IRP_CONTEXT.
  1407. Return Value:
  1408. NTSTATUS - STATUS_SUCCESS if IO should continue processing this
  1409. IRP, STATUS_MORE_PROCESSING_REQUIRED if IO should stop processing
  1410. this IRP.
  1411. --***************************************************************************/
  1412. NTSTATUS
  1413. UcpRestartDisconnect(
  1414. IN PDEVICE_OBJECT pDeviceObject,
  1415. IN PIRP pIrp,
  1416. IN PVOID pContext
  1417. )
  1418. {
  1419. PUL_IRP_CONTEXT pIrpContext;
  1420. PUC_CLIENT_CONNECTION pConnection;
  1421. KIRQL OldIrql;
  1422. NTSTATUS Status = STATUS_MORE_PROCESSING_REQUIRED;
  1423. NTSTATUS IrpStatus;
  1424. ULONG_PTR IrpInformation;
  1425. PUL_COMPLETION_ROUTINE pCompletionRoutine;
  1426. PVOID pCompletionContext;
  1427. UNREFERENCED_PARAMETER(pDeviceObject);
  1428. //
  1429. // Sanity check.
  1430. //
  1431. pIrpContext = (PUL_IRP_CONTEXT) pContext;
  1432. ASSERT( IS_VALID_IRP_CONTEXT( pIrpContext ) );
  1433. pConnection = (PUC_CLIENT_CONNECTION) pIrpContext->pConnectionContext;
  1434. ASSERT( UC_IS_VALID_CLIENT_CONNECTION( pConnection ) );
  1435. UC_WRITE_TRACE_LOG(
  1436. g_pUcTraceLog,
  1437. UC_ACTION_CONNECTION_RESTART_DISCONNECT,
  1438. pConnection,
  1439. 0,
  1440. NULL,
  1441. 0
  1442. );
  1443. //
  1444. // Remember the completion routine, completion context, Irp status,
  1445. // Irp information fields before calling the connection state machine.
  1446. // This is done because the connection state machine might change/free
  1447. // them.
  1448. //
  1449. pCompletionRoutine = pIrpContext->pCompletionRoutine;
  1450. pCompletionContext = pIrpContext->pCompletionContext;
  1451. IrpStatus = pIrp->IoStatus.Status;
  1452. IrpInformation = pIrp->IoStatus.Information;
  1453. UlAcquireSpinLock(&pConnection->SpinLock, &OldIrql);
  1454. pConnection->Flags |= CLIENT_CONN_FLAG_DISCONNECT_COMPLETE;
  1455. if(pConnection->Flags & CLIENT_CONN_FLAG_ABORT_RECEIVED)
  1456. {
  1457. pConnection->ConnectionState = UcConnectStateConnectCleanup;
  1458. UC_WRITE_TRACE_LOG(
  1459. g_pUcTraceLog,
  1460. UC_ACTION_CONNECTION_CLEANUP,
  1461. pConnection,
  1462. UlongToPtr((ULONG)pConnection->ConnectionStatus),
  1463. UlongToPtr(pConnection->ConnectionState),
  1464. UlongToPtr(pConnection->Flags)
  1465. );
  1466. UcKickOffConnectionStateMachine(
  1467. pConnection,
  1468. OldIrql,
  1469. UcConnectionWorkItem
  1470. );
  1471. }
  1472. else if(pConnection->Flags & CLIENT_CONN_FLAG_ABORT_PENDING)
  1473. {
  1474. pConnection->ConnectionState = UcConnectStateAbortPending;
  1475. UlReleaseSpinLock(&pConnection->SpinLock, OldIrql);
  1476. UcpBeginAbort(pConnection,
  1477. pIrpContext->pCompletionRoutine,
  1478. pIrpContext->pCompletionContext
  1479. );
  1480. //
  1481. // Don't complete the user's completion routine below, as it will
  1482. // be handled when the Abort completes.
  1483. //
  1484. DEREFERENCE_CLIENT_CONNECTION( pConnection );
  1485. return Status;
  1486. }
  1487. else if(pConnection->Flags & CLIENT_CONN_FLAG_DISCONNECT_RECEIVED ||
  1488. pConnection->ConnectionState ==
  1489. UcConnectStateDisconnectIndicatedPending)
  1490. {
  1491. pConnection->ConnectionState = UcConnectStateConnectCleanup;
  1492. UC_WRITE_TRACE_LOG(
  1493. g_pUcTraceLog,
  1494. UC_ACTION_CONNECTION_CLEANUP,
  1495. pConnection,
  1496. UlongToPtr((ULONG)pConnection->ConnectionStatus),
  1497. UlongToPtr(pConnection->ConnectionState),
  1498. UlongToPtr(pConnection->Flags)
  1499. );
  1500. UcKickOffConnectionStateMachine(
  1501. pConnection,
  1502. OldIrql,
  1503. UcConnectionWorkItem
  1504. );
  1505. }
  1506. else
  1507. {
  1508. pConnection->ConnectionState = UcConnectStateDisconnectComplete;
  1509. UlReleaseSpinLock(&pConnection->SpinLock, OldIrql);
  1510. }
  1511. #if 0
  1512. if(!newFlags.DisconnectIndicated && !newFlags.AbortIndicated)
  1513. {
  1514. //
  1515. // Only try to drain if it is not already aborted or disconnect
  1516. // indication is not already happened.
  1517. //
  1518. if (pConnection->FilterInfo.pFilterChannel)
  1519. {
  1520. //
  1521. // Put a reference on filter connection until the drain
  1522. // is done.
  1523. //
  1524. REFERENCE_FILTER_CONNECTION(&pConnection->FilterInfo);
  1525. UL_QUEUE_WORK_ITEM(
  1526. &pConnection->FilterInfo.WorkItem,
  1527. &UlFilterDrainIndicatedData
  1528. );
  1529. }
  1530. }
  1531. #endif
  1532. //
  1533. // Invoke the user's completion routine.
  1534. //
  1535. if (pCompletionRoutine)
  1536. {
  1537. pCompletionRoutine(pCompletionContext, IrpStatus, IrpInformation);
  1538. }
  1539. //
  1540. // The connection was referenced in BeginDisconnect function.
  1541. // Deference it.
  1542. //
  1543. DEREFERENCE_CLIENT_CONNECTION( pConnection );
  1544. return Status;
  1545. } // UcpRestartDisconnect
  1546. /***************************************************************************++
  1547. Routine Description:
  1548. Initiates an abortive disconnect on the specified connection.
  1549. Arguments:
  1550. pConnection - Supplies the connection to disconnect.
  1551. Return Value:
  1552. NTSTATUS - Completion status.
  1553. --***************************************************************************/
  1554. NTSTATUS
  1555. UcpBeginAbort(
  1556. IN PUC_CLIENT_CONNECTION pConnection,
  1557. IN PUL_COMPLETION_ROUTINE pCompletionRoutine,
  1558. IN PVOID pCompletionContext
  1559. )
  1560. {
  1561. PIRP pIrp;
  1562. PUL_IRP_CONTEXT pIrpContext;
  1563. ASSERT( UC_IS_VALID_CLIENT_CONNECTION(pConnection) );
  1564. UC_WRITE_TRACE_LOG(
  1565. g_pUcTraceLog,
  1566. UC_ACTION_CONNECTION_BEGIN_ABORT,
  1567. pConnection,
  1568. 0,
  1569. NULL,
  1570. 0
  1571. );
  1572. pIrpContext = &pConnection->pTdiObjects->IrpContext;
  1573. ASSERT( IS_VALID_IRP_CONTEXT( pIrpContext ) );
  1574. pIrpContext->pConnectionContext = (PVOID)pConnection;
  1575. pIrpContext->pCompletionRoutine = pCompletionRoutine;
  1576. pIrpContext->pCompletionContext = pCompletionContext;
  1577. pIrpContext->OwnIrpContext = TRUE;
  1578. pIrp = pConnection->pTdiObjects->pIrp;
  1579. UxInitializeDisconnectIrp(
  1580. pIrp,
  1581. &pConnection->pTdiObjects->ConnectionObject,
  1582. TDI_DISCONNECT_ABORT,
  1583. &UcpRestartAbort,
  1584. pIrpContext
  1585. );
  1586. //
  1587. // Add a reference to the connection, then call the driver to initialize
  1588. // the disconnect.
  1589. //
  1590. REFERENCE_CLIENT_CONNECTION(pConnection);
  1591. UlCallDriver(
  1592. pConnection->pTdiObjects->ConnectionObject.pDeviceObject,
  1593. pIrp
  1594. );
  1595. return STATUS_PENDING;
  1596. }
  1597. /***************************************************************************++
  1598. Routine Description:
  1599. Completion handler for abortive disconnect IRPs.
  1600. Arguments:
  1601. pDeviceObject - Supplies the device object for the IRP being
  1602. completed.
  1603. pIrp - Supplies the IRP being completed.
  1604. pContext - Supplies the context associated with this request.
  1605. This is actually a PUL_IRP_CONTEXT.
  1606. Return Value:
  1607. NTSTATUS - STATUS_SUCCESS if IO should continue processing this
  1608. IRP, STATUS_MORE_PROCESSING_REQUIRED if IO should stop processing
  1609. this IRP.
  1610. --***************************************************************************/
  1611. NTSTATUS
  1612. UcpRestartAbort(
  1613. IN PDEVICE_OBJECT pDeviceObject,
  1614. IN PIRP pIrp,
  1615. IN PVOID pContext
  1616. )
  1617. {
  1618. PUL_IRP_CONTEXT pIrpContext;
  1619. PUC_CLIENT_CONNECTION pConnection;
  1620. KIRQL OldIrql;
  1621. PUL_COMPLETION_ROUTINE pCompletionRoutine;
  1622. PVOID pCompletionContext;
  1623. NTSTATUS IrpStatus;
  1624. ULONG_PTR IrpInformation;
  1625. UNREFERENCED_PARAMETER(pDeviceObject);
  1626. //
  1627. // Sanity check.
  1628. //
  1629. pIrpContext = (PUL_IRP_CONTEXT)pContext;
  1630. ASSERT( IS_VALID_IRP_CONTEXT( pIrpContext ) );
  1631. pConnection = (PUC_CLIENT_CONNECTION)pIrpContext->pConnectionContext;
  1632. ASSERT( UC_IS_VALID_CLIENT_CONNECTION( pConnection ) );
  1633. UC_WRITE_TRACE_LOG(
  1634. g_pUcTraceLog,
  1635. UC_ACTION_CONNECTION_RESTART_ABORT,
  1636. pConnection,
  1637. 0,
  1638. 0,
  1639. 0
  1640. );
  1641. //
  1642. // Remember the completion routine, completion context, Irp status,
  1643. // Irp information fields before calling the connection state machine.
  1644. // This is done because the connection state machine might change/free
  1645. // them.
  1646. //
  1647. pCompletionRoutine = pIrpContext->pCompletionRoutine;
  1648. pCompletionContext = pIrpContext->pCompletionContext;
  1649. IrpStatus = pIrp->IoStatus.Status;
  1650. IrpInformation = pIrp->IoStatus.Information;
  1651. UlAcquireSpinLock(&pConnection->SpinLock, &OldIrql);
  1652. pConnection->Flags |= CLIENT_CONN_FLAG_ABORT_COMPLETE;
  1653. pConnection->ConnectionState = UcConnectStateConnectCleanup;
  1654. UC_WRITE_TRACE_LOG(
  1655. g_pUcTraceLog,
  1656. UC_ACTION_CONNECTION_CLEANUP,
  1657. pConnection,
  1658. UlongToPtr((ULONG)pConnection->ConnectionStatus),
  1659. UlongToPtr(pConnection->ConnectionState),
  1660. UlongToPtr(pConnection->Flags)
  1661. );
  1662. UcKickOffConnectionStateMachine(
  1663. pConnection,
  1664. OldIrql,
  1665. UcConnectionWorkItem
  1666. );
  1667. //
  1668. // Invoke the user's completion routine.
  1669. //
  1670. if (pCompletionRoutine)
  1671. {
  1672. pCompletionRoutine(pCompletionContext, IrpStatus, IrpInformation);
  1673. }
  1674. //
  1675. // The connection was referenced in BeginAbort. Dereference it.
  1676. //
  1677. DEREFERENCE_CLIENT_CONNECTION( pConnection );
  1678. return STATUS_MORE_PROCESSING_REQUIRED;
  1679. } // UcpRestartAbort
  1680. /***************************************************************************++
  1681. Routine Description:
  1682. Completion handler for receive IRPs passed back to the transport from
  1683. our receive indication handler.
  1684. Arguments:
  1685. pDeviceObject - Supplies the device object for the IRP being
  1686. completed.
  1687. pIrp - Supplies the IRP being completed.
  1688. pContext - Supplies the context associated with this request.
  1689. This is actually a PUL_RECEIVE_BUFFER.
  1690. Return Value:
  1691. NTSTATUS - STATUS_SUCCESS if IO should continue processing this
  1692. IRP, STATUS_MORE_PROCESSING_REQUIRED if IO should stop processing
  1693. this IRP.
  1694. --***************************************************************************/
  1695. NTSTATUS
  1696. UcpRestartReceive(
  1697. IN PDEVICE_OBJECT pDeviceObject,
  1698. IN PIRP pIrp,
  1699. IN PVOID pContext
  1700. )
  1701. {
  1702. NTSTATUS status;
  1703. PUL_RECEIVE_BUFFER pBuffer;
  1704. PUC_CLIENT_CONNECTION pConnection;
  1705. PUX_TDI_OBJECT pTdiObject;
  1706. ULONG bytesTaken;
  1707. ULONG bytesRemaining;
  1708. UNREFERENCED_PARAMETER(pDeviceObject);
  1709. //
  1710. // Sanity check.
  1711. //
  1712. pBuffer = (PUL_RECEIVE_BUFFER)pContext;
  1713. ASSERT( IS_VALID_RECEIVE_BUFFER( pBuffer ) );
  1714. pConnection = (PUC_CLIENT_CONNECTION) pBuffer->pConnectionContext;
  1715. ASSERT( UC_IS_VALID_CLIENT_CONNECTION( pConnection ) );
  1716. pTdiObject = &pConnection->pTdiObjects->ConnectionObject;
  1717. ASSERT( IS_VALID_TDI_OBJECT( pTdiObject ) );
  1718. // The connection could be destroyed before we get a chance to
  1719. // receive the completion for the receive IRP. In that case the
  1720. // irp status won't be success but STATUS_CONNECTION_RESET or similar.
  1721. // We should not attempt to pass this case to the client.
  1722. //
  1723. status = pBuffer->pIrp->IoStatus.Status;
  1724. if(status != STATUS_SUCCESS)
  1725. {
  1726. // The HttpConnection has already been destroyed
  1727. // or receive completion failed for some reason
  1728. // no need to go to client
  1729. goto end;
  1730. }
  1731. //
  1732. // Fake a receive indication to the client.
  1733. //
  1734. pBuffer->UnreadDataLength += (ULONG)pBuffer->pIrp->IoStatus.Information;
  1735. bytesTaken = 0;
  1736. //
  1737. // Pass the data on.
  1738. //
  1739. if (pConnection->FilterInfo.pFilterChannel)
  1740. {
  1741. //
  1742. // Needs to go through a filter.
  1743. //
  1744. status = UlFilterReceiveHandler(
  1745. &pConnection->FilterInfo,
  1746. pBuffer->pDataArea,
  1747. pBuffer->UnreadDataLength,
  1748. 0,
  1749. &bytesTaken
  1750. );
  1751. }
  1752. else
  1753. {
  1754. //
  1755. // Go directly to client.
  1756. //
  1757. status = UcHandleResponse(
  1758. NULL,
  1759. pConnection,
  1760. pBuffer->pDataArea,
  1761. pBuffer->UnreadDataLength,
  1762. 0,
  1763. &bytesTaken
  1764. );
  1765. }
  1766. ASSERT( bytesTaken <= pBuffer->UnreadDataLength );
  1767. ASSERT(status != STATUS_MORE_PROCESSING_REQUIRED);
  1768. //
  1769. // Note that this basically duplicates the logic that's currently in
  1770. // UcpTdiReceiveHandler.
  1771. //
  1772. if(status == STATUS_SUCCESS)
  1773. {
  1774. //
  1775. // The client consumed part of the indicated data.
  1776. //
  1777. // We'll need to copy the untaken data forward within the receive
  1778. // buffer, build an MDL describing the remaining part of the buffer,
  1779. // then repost the receive IRP.
  1780. //
  1781. bytesRemaining = pBuffer->UnreadDataLength - bytesTaken;
  1782. if(bytesRemaining != 0)
  1783. {
  1784. //
  1785. // Do we have enough buffer space for more?
  1786. //
  1787. if (bytesRemaining < g_UlReceiveBufferSize)
  1788. {
  1789. //
  1790. // Move the unread portion of the buffer to the beginning.
  1791. //
  1792. RtlMoveMemory(
  1793. pBuffer->pDataArea,
  1794. (PUCHAR)pBuffer->pDataArea + bytesTaken,
  1795. bytesRemaining
  1796. );
  1797. pBuffer->UnreadDataLength = bytesRemaining;
  1798. //
  1799. // Build a partial mdl representing the remainder of the
  1800. // buffer.
  1801. //
  1802. IoBuildPartialMdl(
  1803. pBuffer->pMdl, // SourceMdl
  1804. pBuffer->pPartialMdl, // TargetMdl
  1805. (PUCHAR)pBuffer->pDataArea + bytesRemaining,// VA
  1806. g_UlReceiveBufferSize - bytesRemaining // Length
  1807. );
  1808. //
  1809. // Finish initializing the IRP.
  1810. //
  1811. TdiBuildReceive(
  1812. pBuffer->pIrp, // Irp
  1813. pTdiObject->pDeviceObject, // DeviceObject
  1814. pTdiObject->pFileObject, // FileObject
  1815. &UcpRestartReceive, // CompletionRoutine
  1816. pBuffer, // CompletionContext
  1817. pBuffer->pPartialMdl, // MdlAddress
  1818. TDI_RECEIVE_NORMAL, // Flags
  1819. g_UlReceiveBufferSize - bytesRemaining // Length
  1820. );
  1821. //
  1822. // Call the driver.
  1823. //
  1824. UlCallDriver(
  1825. pConnection->pTdiObjects->ConnectionObject.pDeviceObject,
  1826. pIrp
  1827. );
  1828. //
  1829. // Tell IO to stop processing this request.
  1830. //
  1831. return STATUS_MORE_PROCESSING_REQUIRED;
  1832. }
  1833. else
  1834. {
  1835. status = STATUS_BUFFER_OVERFLOW;
  1836. }
  1837. }
  1838. }
  1839. end:
  1840. if (status != STATUS_SUCCESS)
  1841. {
  1842. //
  1843. // The client failed the indication. Abort the connection.
  1844. //
  1845. UC_CLOSE_CONNECTION(pConnection, TRUE, status);
  1846. }
  1847. if (pTdiObject->pDeviceObject->StackSize > DEFAULT_IRP_STACK_SIZE)
  1848. {
  1849. UlFreeReceiveBufferPool( pBuffer );
  1850. }
  1851. else
  1852. {
  1853. UlPplFreeReceiveBuffer( pBuffer );
  1854. }
  1855. //
  1856. // Remove the connection we added in the receive indication handler,
  1857. // free the receive buffer, then tell IO to stop processing the IRP.
  1858. //
  1859. DEREFERENCE_CLIENT_CONNECTION( pConnection );
  1860. return STATUS_MORE_PROCESSING_REQUIRED;
  1861. } // UcpRestartReceive
  1862. /***************************************************************************++
  1863. Routine Description:
  1864. Completion handler for receive IRPs initiated from UcReceiveData().
  1865. Arguments:
  1866. pDeviceObject - Supplies the device object for the IRP being
  1867. completed.
  1868. pIrp - Supplies the IRP being completed.
  1869. pContext - Supplies the context associated with this request.
  1870. This is actually a PUL_IRP_CONTEXT.
  1871. Return Value:
  1872. NTSTATUS - STATUS_SUCCESS if IO should continue processing this
  1873. IRP, STATUS_MORE_PROCESSING_REQUIRED if IO should stop processing
  1874. this IRP.
  1875. --***************************************************************************/
  1876. NTSTATUS
  1877. UcpRestartClientReceive(
  1878. IN PDEVICE_OBJECT pDeviceObject,
  1879. IN PIRP pIrp,
  1880. IN PVOID pContext
  1881. )
  1882. {
  1883. PUL_IRP_CONTEXT pIrpContext;
  1884. PUC_CLIENT_CONNECTION pConnection;
  1885. UNREFERENCED_PARAMETER(pDeviceObject);
  1886. //
  1887. // Sanity check.
  1888. //
  1889. pIrpContext= (PUL_IRP_CONTEXT)pContext;
  1890. ASSERT( IS_VALID_IRP_CONTEXT( pIrpContext ) );
  1891. pConnection = (PUC_CLIENT_CONNECTION)pIrpContext->pConnectionContext;
  1892. ASSERT( UC_IS_VALID_CLIENT_CONNECTION( pConnection ) );
  1893. //
  1894. // Invoke the client's completion handler.
  1895. //
  1896. (pIrpContext->pCompletionRoutine)(
  1897. pIrpContext->pCompletionContext,
  1898. pIrp->IoStatus.Status,
  1899. pIrp->IoStatus.Information
  1900. );
  1901. //
  1902. // Free the IRP context we allocated.
  1903. //
  1904. UlPplFreeIrpContext(pIrpContext);
  1905. //
  1906. // IO can't handle completing an IRP with a non-paged MDL attached
  1907. // to it, so we'll free the MDL here.
  1908. //
  1909. ASSERT( pIrp->MdlAddress != NULL );
  1910. UlFreeMdl( pIrp->MdlAddress );
  1911. pIrp->MdlAddress = NULL;
  1912. //
  1913. // Remove the connection we added in UcReceiveData(), then tell IO to
  1914. // continue processing this IRP.
  1915. //
  1916. DEREFERENCE_CLIENT_CONNECTION( pConnection );
  1917. return STATUS_MORE_PROCESSING_REQUIRED;
  1918. }
  1919. /*********************************************************************++
  1920. Routine Description:
  1921. This is our connection completion routine. It's called by an underlying
  1922. transport when a connection request completes, either good or bad. We
  1923. figure out what happened, free the IRP, and call upwards to notify
  1924. the rest of the code.
  1925. Arguments:
  1926. pDeviceObject - The device object we called.
  1927. pIrp - The IRP that is completing.
  1928. Context - Our context value, really a pointer to an
  1929. HTTP client connection structure.
  1930. Return Value:
  1931. STATUS_MORE_PROCESSING_REQUIRED so the I/O system doesn't do anything
  1932. else.
  1933. --*********************************************************************/
  1934. NTSTATUS
  1935. UcpConnectComplete(
  1936. PDEVICE_OBJECT pDeviceObject,
  1937. PIRP pIrp,
  1938. PVOID Context
  1939. )
  1940. {
  1941. PUC_CLIENT_CONNECTION pConnection;
  1942. NTSTATUS Status;
  1943. KIRQL OldIrql;
  1944. UNREFERENCED_PARAMETER(pDeviceObject);
  1945. pConnection = (PUC_CLIENT_CONNECTION)Context;
  1946. Status = pIrp->IoStatus.Status;
  1947. ASSERT( UC_IS_VALID_CLIENT_CONNECTION( pConnection ) );
  1948. UcRestartClientConnect(pConnection, Status);
  1949. //
  1950. // We need to kick off the connection state machine.
  1951. //
  1952. UlAcquireSpinLock(&pConnection->SpinLock, &OldIrql);
  1953. UcKickOffConnectionStateMachine(
  1954. pConnection,
  1955. OldIrql,
  1956. UcConnectionWorkItem
  1957. );
  1958. //
  1959. // Deref for the CONNECT
  1960. //
  1961. DEREFERENCE_CLIENT_CONNECTION( pConnection );
  1962. return STATUS_MORE_PROCESSING_REQUIRED;
  1963. }
  1964. /***************************************************************************++
  1965. Routine Description:
  1966. This function sets a new flag in the connection's flag set. The setting
  1967. of the flag is synchronized such that only one flag is set at a time.
  1968. Arguments:
  1969. ConnFlag - Supplies a pointer to the location which stores the current flag.
  1970. NewFlag - Supplies a 32-bit value to be or-ed into the current flag set.
  1971. Return Value:
  1972. The new set of connection flags after the update.
  1973. --***************************************************************************/
  1974. ULONG
  1975. UcSetFlag(
  1976. IN OUT PLONG ConnFlag,
  1977. IN LONG NewFlag
  1978. )
  1979. {
  1980. LONG MynewFlags;
  1981. LONG oldFlags;
  1982. //
  1983. // Sanity check.
  1984. //
  1985. do
  1986. {
  1987. //
  1988. // Capture the current value and initialize the new value.
  1989. //
  1990. oldFlags = *ConnFlag;
  1991. MynewFlags = (*ConnFlag) | NewFlag;
  1992. if (InterlockedCompareExchange(
  1993. ConnFlag,
  1994. MynewFlags,
  1995. oldFlags) == oldFlags)
  1996. {
  1997. break;
  1998. }
  1999. } while (TRUE);
  2000. return MynewFlags;
  2001. } // UcSetFlag
  2002. /***************************************************************************++
  2003. Routine Description:
  2004. Build a receive buffer and IRP to TDI to get any pending data.
  2005. Arguments:
  2006. pTdiObject - Supplies the TDI connection object to manipulate.
  2007. pConnection - Supplies the UL_CONNECTION object.
  2008. Return Value:
  2009. NTSTATUS - Completion status.
  2010. --***************************************************************************/
  2011. NTSTATUS
  2012. UcpBuildTdiReceiveBuffer(
  2013. IN PUX_TDI_OBJECT pTdiObject,
  2014. IN PUC_CLIENT_CONNECTION pConnection,
  2015. OUT PIRP *pIrp
  2016. )
  2017. {
  2018. PUL_RECEIVE_BUFFER pBuffer;
  2019. if (pTdiObject->pDeviceObject->StackSize > DEFAULT_IRP_STACK_SIZE)
  2020. {
  2021. pBuffer = UlAllocateReceiveBuffer(
  2022. pTdiObject->pDeviceObject->StackSize
  2023. );
  2024. }
  2025. else
  2026. {
  2027. pBuffer = UlPplAllocateReceiveBuffer();
  2028. }
  2029. if (pBuffer != NULL)
  2030. {
  2031. //
  2032. // Finish initializing the buffer and the IRP.
  2033. //
  2034. REFERENCE_CLIENT_CONNECTION( pConnection );
  2035. pBuffer->pConnectionContext = pConnection;
  2036. pBuffer->UnreadDataLength = 0;
  2037. TdiBuildReceive(
  2038. pBuffer->pIrp, // Irp
  2039. pTdiObject->pDeviceObject, // DeviceObject
  2040. pTdiObject->pFileObject, // FileObject
  2041. &UcpRestartReceive, // CompletionRoutine
  2042. pBuffer, // CompletionContext
  2043. pBuffer->pMdl, // MdlAddress
  2044. TDI_RECEIVE_NORMAL, // Flags
  2045. g_UlReceiveBufferSize // Length
  2046. );
  2047. //
  2048. // We must trace the IRP before we set the next stack
  2049. // location so the trace code can pull goodies from the
  2050. // IRP correctly.
  2051. //
  2052. TRACE_IRP( IRP_ACTION_CALL_DRIVER, pBuffer->pIrp );
  2053. //
  2054. // Pass the IRP back to the transport.
  2055. //
  2056. *pIrp = pBuffer->pIrp;
  2057. return STATUS_MORE_PROCESSING_REQUIRED;
  2058. }
  2059. return STATUS_INSUFFICIENT_RESOURCES;
  2060. } // UcpBuildTdiReceiveBuffer