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.

6897 lines
172 KiB

  1. /*++
  2. Copyright (c) 1998-2001 Microsoft Corporation
  3. Module Name:
  4. ultdi.cxx
  5. Abstract:
  6. This module implements the TDI/MUX/SSL component.
  7. Author:
  8. Keith Moore (keithmo) 15-Jun-1998
  9. Revision History:
  10. --*/
  11. #include "precomp.h"
  12. #include "repltrace.h"
  13. //
  14. // Private globals.
  15. //
  16. //
  17. // Global lists of all active and all waiting-to-be-deleted endpoints.
  18. //
  19. LIST_ENTRY g_TdiEndpointListHead;
  20. LIST_ENTRY g_TdiDeletedEndpointListHead; // for debugging
  21. ULONG g_TdiEndpointCount; // #elements in active endpoint list
  22. //
  23. // Global lists of all connections, active or idle
  24. //
  25. LIST_ENTRY g_TdiConnectionListHead;
  26. ULONG g_TdiConnectionCount; // #elements in connection list
  27. //
  28. // Spinlock protecting the above lists.
  29. //
  30. UL_SPIN_LOCK g_TdiSpinLock;
  31. //
  32. // Global initialization flag.
  33. //
  34. BOOLEAN g_TdiInitialized;
  35. //
  36. // Used to wait for endpoints and connections to close on shutdown
  37. //
  38. BOOLEAN g_TdiWaitingForEndpointDrain;
  39. KEVENT g_TdiEndpointDrainEvent;
  40. KEVENT g_TdiConnectionDrainEvent;
  41. //
  42. // TCP Send routine if Fast Send is possible.
  43. //
  44. PUL_TCPSEND_DISPATCH g_TcpFastSend = NULL;
  45. #ifdef ALLOC_PRAGMA
  46. #pragma alloc_text( INIT, UlInitializeTdi )
  47. #pragma alloc_text( INIT, UlpQueryTcpFastSend )
  48. #pragma alloc_text( PAGE, UlTerminateTdi )
  49. #pragma alloc_text( PAGE, UlCloseListeningEndpoint )
  50. #pragma alloc_text( PAGE, UlpEndpointCleanupWorker )
  51. #pragma alloc_text( PAGE, UlpConnectionCleanupWorker )
  52. #pragma alloc_text( PAGE, UlpAssociateConnection )
  53. #pragma alloc_text( PAGE, UlpDisassociateConnection )
  54. #pragma alloc_text( PAGE, UlpReplenishEndpoint )
  55. #pragma alloc_text( PAGE, UlpReplenishEndpointWorker )
  56. #pragma alloc_text( PAGE, UlpInitializeConnection )
  57. #pragma alloc_text( PAGE, UlpUrlToAddress )
  58. #pragma alloc_text( PAGE, UlpSetNagling )
  59. #endif // ALLOC_PRAGMA
  60. #if 0
  61. NOT PAGEABLE -- UlWaitForEndpointDrain
  62. NOT PAGEABLE -- UlCreateListeningEndpoint
  63. NOT PAGEABLE -- UlCloseConnection
  64. NOT PAGEABLE -- UlReceiveData
  65. NOT PAGEABLE -- UlSendData
  66. NOT PAGEABLE -- UlAddSiteToEndpointList
  67. NOT PAGEABLE -- UlRemoveSiteFromEndpointList
  68. NOT PAGEABLE -- UlpDestroyEndpoint
  69. NOT PAGEABLE -- UlpDestroyConnection
  70. NOT PAGEABLE -- UlpDequeueIdleConnection
  71. NOT PAGEABLE -- UlpEnqueueIdleConnection
  72. NOT PAGEABLE -- UlpEnqueueActiveConnection
  73. NOT PAGEABLE -- UlpConnectHandler
  74. NOT PAGEABLE -- UlpDisconnectHandler
  75. NOT PAGEABLE -- UlpCloseRawConnection
  76. NOT PAGEABLE -- UlpSendRawData
  77. NOT PAGEABLE -- UlpReceiveRawData
  78. NOT PAGEABLE -- UlpReceiveHandler
  79. NOT PAGEABLE -- UlpDummyReceiveHandler
  80. NOT PAGEABLE -- UlpReceiveExpeditedHandler
  81. NOT PAGEABLE -- UlpRestartAccept
  82. NOT PAGEABLE -- UlpRestartSendData
  83. NOT PAGEABLE -- UlpReferenceEndpoint
  84. NOT PAGEABLE -- UlpDereferenceEndpoint
  85. NOT PAGEABLE -- UlReferenceConnection
  86. NOT PAGEABLE -- UlDereferenceConnection
  87. NOT PAGEABLE -- UlpCleanupConnectionId
  88. NOT PAGEABLE -- UlpDecrementIdleConnections
  89. NOT PAGEABLE -- UlpIncrementIdleConnections
  90. NOT PAGEABLE -- UlpClearReplenishScheduledFlag
  91. NOT PAGEABLE -- UlpCreateConnection
  92. NOT PAGEABLE -- UlpSetConnectionFlag
  93. NOT PAGEABLE -- UlpBeginDisconnect
  94. NOT PAGEABLE -- UlpRestartDisconnect
  95. NOT PAGEABLE -- UlpBeginAbort
  96. NOT PAGEABLE -- UlpRestartAbort
  97. NOT PAGEABLE -- UlpRemoveFinalReference
  98. NOT PAGEABLE -- UlpRestartReceive
  99. NOT PAGEABLE -- UlpRestartClientReceive
  100. NOT PAGEABLE -- UlpDisconnectAllActiveConnections
  101. NOT PAGEABLE -- UlpUnbindConnectionFromEndpoint
  102. NOT PAGEABLE -- UlpSynchronousIoComplete
  103. NOT PAGEABLE -- UlpFindEndpointForAddress
  104. NOT PAGEABLE -- UlpRestartQueryAddress
  105. #endif
  106. //
  107. // Public functions.
  108. //
  109. /***************************************************************************++
  110. Routine Description:
  111. Performs global initialization of this module.
  112. Return Value:
  113. NTSTATUS - Completion status.
  114. --***************************************************************************/
  115. NTSTATUS
  116. UlInitializeTdi(
  117. VOID
  118. )
  119. {
  120. NTSTATUS status;
  121. //
  122. // Sanity check.
  123. //
  124. PAGED_CODE();
  125. ASSERT( !g_TdiInitialized );
  126. //
  127. // Initialize global data.
  128. //
  129. InitializeListHead( &g_TdiEndpointListHead );
  130. InitializeListHead( &g_TdiDeletedEndpointListHead );
  131. InitializeListHead( &g_TdiConnectionListHead );
  132. UlInitializeSpinLock( &g_TdiSpinLock, "g_TdiSpinLock" );
  133. g_TdiEndpointCount = 0;
  134. g_TdiConnectionCount = 0;
  135. KeInitializeEvent(
  136. &g_TdiEndpointDrainEvent,
  137. NotificationEvent,
  138. FALSE
  139. );
  140. KeInitializeEvent(
  141. &g_TdiConnectionDrainEvent,
  142. NotificationEvent,
  143. FALSE
  144. );
  145. status = UlpQueryTcpFastSend();
  146. if (NT_SUCCESS(status))
  147. {
  148. g_TdiInitialized = TRUE;
  149. }
  150. return status;
  151. } // UlInitializeTdi
  152. /***************************************************************************++
  153. Routine Description:
  154. Performs global termination of this module.
  155. --***************************************************************************/
  156. VOID
  157. UlTerminateTdi(
  158. VOID
  159. )
  160. {
  161. //
  162. // Sanity check.
  163. //
  164. PAGED_CODE();
  165. if (g_TdiInitialized)
  166. {
  167. ASSERT( IsListEmpty( &g_TdiEndpointListHead )) ;
  168. ASSERT( IsListEmpty( &g_TdiDeletedEndpointListHead )) ;
  169. ASSERT( IsListEmpty( &g_TdiConnectionListHead )) ;
  170. ASSERT( g_TdiEndpointCount == 0 );
  171. ASSERT( g_TdiConnectionCount == 0 );
  172. g_TdiInitialized = FALSE;
  173. }
  174. } // UlTerminateTdi
  175. /***************************************************************************++
  176. Routine Description:
  177. This function blocks until the endpoint list is empty. It also prevents
  178. new endpoints from being created.
  179. Arguments:
  180. None.
  181. --***************************************************************************/
  182. VOID
  183. UlWaitForEndpointDrain(
  184. VOID
  185. )
  186. {
  187. KIRQL oldIrql;
  188. BOOLEAN Wait = FALSE;
  189. if (g_TdiInitialized)
  190. {
  191. UlAcquireSpinLock( &g_TdiSpinLock, &oldIrql );
  192. if (!g_TdiWaitingForEndpointDrain)
  193. {
  194. g_TdiWaitingForEndpointDrain = TRUE;
  195. }
  196. if (g_TdiEndpointCount > 0 || g_TdiConnectionCount > 0)
  197. {
  198. Wait = TRUE;
  199. }
  200. UlReleaseSpinLock( &g_TdiSpinLock, oldIrql );
  201. if (Wait)
  202. {
  203. PVOID Events[2] = {
  204. &g_TdiEndpointDrainEvent,
  205. &g_TdiConnectionDrainEvent
  206. };
  207. KeWaitForMultipleObjects(
  208. 2,
  209. Events,
  210. WaitAll,
  211. UserRequest,
  212. KernelMode,
  213. FALSE,
  214. NULL,
  215. NULL
  216. );
  217. }
  218. }
  219. } // UlWaitForEndpointDrain
  220. /***************************************************************************++
  221. Routine Description:
  222. Creates a new listening endpoint bound to the specified address.
  223. Arguments:
  224. pLocalAddress - Supplies the local address to bind the endpoint to.
  225. LocalAddressLength - Supplies the length of pLocalAddress.
  226. InitialBacklog - Supplies the initial number of idle connections
  227. to add to the endpoint.
  228. pConnectionRequestHandler - Supplies a pointer to an indication
  229. handler to invoke when incoming connections arrive.
  230. pConnectionCompleteHandler - Supplies a pointer to an indication
  231. handler to invoke when either a) the incoming connection is
  232. fully accepted, or b) the incoming connection could not be
  233. accepted due to a fatal error.
  234. pConnectionDisconnectHandler - Supplies a pointer to an indication
  235. handler to invoke when connections are disconnected by the
  236. remote (client) side.
  237. pConnectionDestroyedHandler - Supplies a pointer to an indication
  238. handle to invoke after a connection has been fully destroyed.
  239. This is typically the TDI client's opportunity to cleanup
  240. any allocated resources.
  241. pDataReceiveHandler - Supplies a pointer to an indication handler to
  242. invoke when incoming data arrives.
  243. pListeningContext - Supplies an uninterpreted context value to
  244. associate with the new listening endpoint.
  245. ppListeningEndpoint - Receives a pointer to the new listening
  246. endpoint if successful.
  247. Return Value:
  248. NTSTATUS - Completion status.
  249. --***************************************************************************/
  250. NTSTATUS
  251. UlCreateListeningEndpoint(
  252. IN PTRANSPORT_ADDRESS pLocalAddress,
  253. IN ULONG LocalAddressLength,
  254. IN BOOLEAN Secure,
  255. IN ULONG InitialBacklog,
  256. IN PUL_CONNECTION_REQUEST pConnectionRequestHandler,
  257. IN PUL_CONNECTION_COMPLETE pConnectionCompleteHandler,
  258. IN PUL_CONNECTION_DISCONNECT pConnectionDisconnectHandler,
  259. IN PUL_CONNECTION_DISCONNECT_COMPLETE pConnectionDisconnectCompleteHandler,
  260. IN PUL_CONNECTION_DESTROYED pConnectionDestroyedHandler,
  261. IN PUL_DATA_RECEIVE pDataReceiveHandler,
  262. IN PVOID pListeningContext,
  263. OUT PUL_ENDPOINT *ppListeningEndpoint
  264. )
  265. {
  266. NTSTATUS status;
  267. PUL_ENDPOINT pEndpoint;
  268. UNICODE_STRING deviceName;
  269. LONG i;
  270. //
  271. // Sanity check.
  272. //
  273. ASSERT( LocalAddressLength == sizeof(TA_IP_ADDRESS) );
  274. ASSERT( InitialBacklog < 0x7FFFFFFF );
  275. //
  276. // Setup locals so we know how to cleanup on a fatal exit.
  277. //
  278. pEndpoint = NULL;
  279. //
  280. // Allocate enough pool for the endpoint structure and the
  281. // local address.
  282. //
  283. pEndpoint = UL_ALLOCATE_STRUCT_WITH_SPACE(
  284. NonPagedPool,
  285. UL_ENDPOINT,
  286. LocalAddressLength,
  287. UL_ENDPOINT_POOL_TAG
  288. );
  289. if (pEndpoint == NULL)
  290. {
  291. status = STATUS_INSUFFICIENT_RESOURCES;
  292. goto fatal;
  293. }
  294. InterlockedIncrement((PLONG) &g_TdiEndpointCount);
  295. //
  296. // Initialize the easy parts.
  297. //
  298. pEndpoint->Signature = UL_ENDPOINT_SIGNATURE;
  299. pEndpoint->ReferenceCount = 0;
  300. pEndpoint->UsageCount = 1;
  301. #if ENABLE_OWNER_REF_TRACE
  302. pEndpoint->pEndpointRefOwner = NULL;
  303. CREATE_OWNER_REF_TRACE_LOG( pEndpoint->pOwnerRefTraceLog, 8000, 0 );
  304. #endif // ENABLE_OWNER_REF_TRACE
  305. REFERENCE_ENDPOINT_SELF(pEndpoint, REF_ACTION_INIT);
  306. ExInitializeSListHead( &pEndpoint->IdleConnectionSListHead );
  307. for (i = 0; i < DEFAULT_MAX_CONNECTION_ACTIVE_LISTS; i++)
  308. {
  309. InitializeListHead( &pEndpoint->ActiveConnectionListHead[i] );
  310. UlInitializeSpinLock(
  311. &pEndpoint->ActiveConnectionSpinLock[i],
  312. "ActiveConnectionSpinLock"
  313. );
  314. }
  315. pEndpoint->ActiveConnectionIndex = 0;
  316. UlInitializeSpinLock( &pEndpoint->IdleConnectionSpinLock, "IdleConnectionSpinLock" );
  317. UlInitializeSpinLock( &pEndpoint->EndpointSpinLock, "EndpointSpinLock" );
  318. pEndpoint->AddressObject.Handle = NULL;
  319. pEndpoint->AddressObject.pFileObject = NULL;
  320. pEndpoint->AddressObject.pDeviceObject = NULL;
  321. pEndpoint->pConnectionRequestHandler = pConnectionRequestHandler;
  322. pEndpoint->pConnectionCompleteHandler = pConnectionCompleteHandler;
  323. pEndpoint->pConnectionDisconnectHandler = pConnectionDisconnectHandler;
  324. pEndpoint->pConnectionDisconnectCompleteHandler = pConnectionDisconnectCompleteHandler;
  325. pEndpoint->pConnectionDestroyedHandler = pConnectionDestroyedHandler;
  326. pEndpoint->pDataReceiveHandler = pDataReceiveHandler;
  327. pEndpoint->pListeningContext = pListeningContext;
  328. pEndpoint->pLocalAddress = (PTRANSPORT_ADDRESS)(pEndpoint + 1);
  329. pEndpoint->LocalAddressLength = LocalAddressLength;
  330. RtlCopyMemory(
  331. pEndpoint->pLocalAddress,
  332. pLocalAddress,
  333. LocalAddressLength
  334. );
  335. pEndpoint->Secure = Secure;
  336. pEndpoint->Deleted = FALSE;
  337. pEndpoint->GlobalEndpointListEntry.Flink = NULL;
  338. pEndpoint->EndpointSynch.ReplenishScheduled = TRUE;
  339. pEndpoint->EndpointSynch.IdleConnections = 0;
  340. RtlZeroMemory(
  341. &pEndpoint->CleanupIrpContext,
  342. sizeof(UL_IRP_CONTEXT)
  343. );
  344. pEndpoint->CleanupIrpContext.Signature = UL_IRP_CONTEXT_SIGNATURE;
  345. //
  346. // Open the TDI address object for this endpoint.
  347. //
  348. status = UxOpenTdiAddressObject(
  349. pLocalAddress,
  350. LocalAddressLength,
  351. &pEndpoint->AddressObject
  352. );
  353. if (!NT_SUCCESS(status))
  354. {
  355. goto fatal;
  356. }
  357. //
  358. // Set the TDI event handlers.
  359. //
  360. status = UxSetEventHandler(
  361. &pEndpoint->AddressObject,
  362. TDI_EVENT_CONNECT,
  363. &UlpConnectHandler,
  364. pEndpoint
  365. );
  366. if (!NT_SUCCESS(status))
  367. {
  368. goto fatal;
  369. }
  370. status = UxSetEventHandler(
  371. &pEndpoint->AddressObject,
  372. TDI_EVENT_DISCONNECT,
  373. &UlpDisconnectHandler,
  374. pEndpoint
  375. );
  376. if (!NT_SUCCESS(status))
  377. {
  378. goto fatal;
  379. }
  380. status = UxSetEventHandler(
  381. &pEndpoint->AddressObject,
  382. TDI_EVENT_RECEIVE,
  383. &UlpReceiveHandler,
  384. pEndpoint
  385. );
  386. if (!NT_SUCCESS(status))
  387. {
  388. goto fatal;
  389. }
  390. status = UxSetEventHandler(
  391. &pEndpoint->AddressObject,
  392. TDI_EVENT_RECEIVE_EXPEDITED,
  393. &UlpReceiveExpeditedHandler,
  394. pEndpoint
  395. );
  396. //
  397. // Put the endpoint onto the global list.
  398. //
  399. ExInterlockedInsertTailList(
  400. &g_TdiEndpointListHead,
  401. &pEndpoint->GlobalEndpointListEntry,
  402. KSPIN_LOCK_FROM_UL_SPIN_LOCK(&g_TdiSpinLock)
  403. );
  404. //
  405. // Replenish the idle connection pool.
  406. //
  407. UlpReplenishEndpoint( pEndpoint );
  408. //
  409. // Success!
  410. //
  411. UlTrace(TDI, (
  412. "UlCreateListeningEndpoint: endpoint %p, addrobj %p\n",
  413. pEndpoint,
  414. pEndpoint->AddressObject.Handle
  415. ));
  416. *ppListeningEndpoint = pEndpoint;
  417. return STATUS_SUCCESS;
  418. fatal:
  419. ASSERT( !NT_SUCCESS(status) );
  420. if (pEndpoint != NULL)
  421. {
  422. //
  423. // Release the one-and-only reference on the endpoint, which
  424. // will cause it to destroy itself. Done this way to keep
  425. // the ownerref tracelogging happy, as it will complain if
  426. // the refcount doesn't drop to zero.
  427. //
  428. ASSERT(1 == pEndpoint->ReferenceCount);
  429. DEREFERENCE_ENDPOINT_SELF(pEndpoint, REF_ACTION_FINAL_DEREF);
  430. }
  431. return status;
  432. } // UlCreateListeningEndpoint
  433. /***************************************************************************++
  434. Routine Description:
  435. Closes an existing listening endpoint.
  436. Arguments:
  437. pListeningEndpoint - Supplies a pointer to a listening endpoint
  438. previously created with UlCreateListeningEndpoint().
  439. pCompletionRoutine - Supplies a pointer to a completion routine to
  440. invoke after the listening endpoint is fully closed.
  441. pCompletionContext - Supplies an uninterpreted context value for the
  442. completion routine.
  443. Return Value:
  444. NTSTATUS - Completion status.
  445. --***************************************************************************/
  446. NTSTATUS
  447. UlCloseListeningEndpoint(
  448. IN PUL_ENDPOINT pListeningEndpoint,
  449. IN PUL_COMPLETION_ROUTINE pCompletionRoutine,
  450. IN PVOID pCompletionContext
  451. )
  452. {
  453. PUL_IRP_CONTEXT pIrpContext;
  454. NTSTATUS status;
  455. //
  456. // Sanity check.
  457. //
  458. PAGED_CODE();
  459. ASSERT( IS_VALID_ENDPOINT( pListeningEndpoint ) );
  460. ASSERT( pCompletionRoutine != NULL );
  461. UlTrace(TDI, (
  462. "UlCloseListeningEndpoint: endpoint %p, completion %p, ctx %p\n",
  463. pListeningEndpoint,
  464. pCompletionRoutine,
  465. pCompletionContext
  466. ));
  467. pIrpContext = &pListeningEndpoint->CleanupIrpContext;
  468. pIrpContext->pCompletionRoutine = pCompletionRoutine;
  469. pIrpContext->pCompletionContext = pCompletionContext;
  470. pIrpContext->pOwnIrp = NULL;
  471. //
  472. // Let UlpDisconnectAllActiveConnections do the dirty work.
  473. //
  474. status = UlpDisconnectAllActiveConnections( pListeningEndpoint );
  475. return status;
  476. } // UlCloseListeningEndpoint
  477. /***************************************************************************++
  478. Routine Description:
  479. Closes a previously accepted connection.
  480. Arguments:
  481. pConnection - Supplies a pointer to a connection as previously
  482. indicated to the PUL_CONNECTION_REQUEST handler.
  483. AbortiveDisconnect - Supplies TRUE if the connection is to be abortively
  484. disconnected, FALSE if it should be gracefully disconnected.
  485. pCompletionRoutine - Supplies a pointer to a completion routine to
  486. invoke after the connection is fully closed.
  487. pCompletionContext - Supplies an uninterpreted context value for the
  488. completion routine.
  489. Return Value:
  490. NTSTATUS - Completion status.
  491. --***************************************************************************/
  492. NTSTATUS
  493. UlCloseConnection(
  494. IN PVOID pObject,
  495. IN BOOLEAN AbortiveDisconnect,
  496. IN PUL_COMPLETION_ROUTINE pCompletionRoutine,
  497. IN PVOID pCompletionContext
  498. )
  499. {
  500. NTSTATUS status;
  501. PUL_CONNECTION pConnection = (PUL_CONNECTION) pObject;
  502. //
  503. // Sanity check.
  504. //
  505. ASSERT( IS_VALID_CONNECTION( pConnection ) );
  506. UlTrace(TDI, (
  507. "UlCloseConnection: connection %p, abort %lu\n",
  508. pConnection,
  509. (ULONG)AbortiveDisconnect
  510. ));
  511. WRITE_REF_TRACE_LOG2(
  512. g_pTdiTraceLog,
  513. pConnection->pTraceLog,
  514. (AbortiveDisconnect ?
  515. REF_ACTION_CLOSE_UL_CONNECTION_ABORTIVE :
  516. REF_ACTION_CLOSE_UL_CONNECTION_GRACEFUL),
  517. pConnection->ReferenceCount,
  518. pConnection,
  519. __FILE__,
  520. __LINE__
  521. );
  522. //
  523. // We only send graceful disconnects through the filter
  524. // process. There's also no point in going through the
  525. // filter if the connection is already being closed or
  526. // aborted.
  527. //
  528. if (pConnection->FilterInfo.pFilterChannel &&
  529. !pConnection->ConnectionFlags.CleanupBegun &&
  530. !pConnection->ConnectionFlags.DisconnectIndicated &&
  531. !pConnection->ConnectionFlags.AbortIndicated &&
  532. !AbortiveDisconnect)
  533. {
  534. //
  535. // Send graceful disconnect through the filter process.
  536. //
  537. status = UlFilterCloseHandler(
  538. &pConnection->FilterInfo,
  539. pCompletionRoutine,
  540. pCompletionContext
  541. );
  542. }
  543. else
  544. {
  545. //
  546. // Really close the connection.
  547. //
  548. status = UlpCloseRawConnection(
  549. pConnection,
  550. AbortiveDisconnect,
  551. pCompletionRoutine,
  552. pCompletionContext
  553. );
  554. }
  555. return status;
  556. } // UlCloseConnection
  557. /***************************************************************************++
  558. Routine Description:
  559. Sends a block of data on the specified connection. If the connection
  560. is filtered, the data will be sent to the filter first.
  561. Arguments:
  562. pConnection - Supplies a pointer to a connection as previously
  563. indicated to the PUL_CONNECTION_REQUEST handler.
  564. pMdlChain - Supplies a pointer to a MDL chain describing the
  565. data buffers to send.
  566. Length - Supplies the length of the data referenced by the MDL
  567. chain.
  568. pCompletionRoutine - Supplies a pointer to a completion routine to
  569. invoke after the data is sent.
  570. pCompletionContext - Supplies an uninterpreted context value for the
  571. completion routine.
  572. InitiateDisconnect - Supplies TRUE if a graceful disconnect should
  573. be initiated immediately after initiating the send (i.e. before
  574. the send actually completes).
  575. Return Value:
  576. NTSTATUS - Completion status.
  577. --***************************************************************************/
  578. NTSTATUS
  579. UlSendData(
  580. IN PUL_CONNECTION pConnection,
  581. IN PMDL pMdlChain,
  582. IN ULONG Length,
  583. IN PUL_COMPLETION_ROUTINE pCompletionRoutine,
  584. IN PVOID pCompletionContext,
  585. IN PIRP pOwnIrp,
  586. IN PUL_IRP_CONTEXT pOwnIrpContext,
  587. IN BOOLEAN InitiateDisconnect
  588. )
  589. {
  590. NTSTATUS status;
  591. PUL_IRP_CONTEXT pIrpContext;
  592. //
  593. // Sanity check.
  594. //
  595. ASSERT( IS_VALID_CONNECTION( pConnection ) );
  596. ASSERT( pMdlChain != NULL );
  597. ASSERT( Length > 0 );
  598. ASSERT( pCompletionRoutine != NULL );
  599. UlTrace(TDI, (
  600. "UlSendData: connection %p, mdl %p, length %lu\n",
  601. pConnection,
  602. pMdlChain,
  603. Length
  604. ));
  605. //
  606. // Connection should be around until we make a call
  607. // to close connection. See below.
  608. //
  609. REFERENCE_CONNECTION( pConnection );
  610. //
  611. // Allocate & initialize a context structure if necessary.
  612. //
  613. if (pOwnIrpContext == NULL)
  614. {
  615. pIrpContext = UlPplAllocateIrpContext();
  616. }
  617. else
  618. {
  619. ASSERT( pOwnIrp != NULL );
  620. pIrpContext = pOwnIrpContext;
  621. }
  622. if (pIrpContext == NULL)
  623. {
  624. status = STATUS_INSUFFICIENT_RESOURCES;
  625. goto fatal;
  626. }
  627. ASSERT( IS_VALID_IRP_CONTEXT( pIrpContext ) );
  628. pIrpContext->pConnectionContext = (PVOID)pConnection;
  629. pIrpContext->pCompletionRoutine = pCompletionRoutine;
  630. pIrpContext->pCompletionContext = pCompletionContext;
  631. pIrpContext->pOwnIrp = pOwnIrp;
  632. //
  633. // Try to send the data. This send operation may complete inline
  634. // fast, if the connection has already been aborted by the client
  635. // In that case connection may gone away. To prevent this we
  636. // keep additional refcount until we make a call to close connection
  637. // below.
  638. //
  639. if (pConnection->FilterInfo.pFilterChannel)
  640. {
  641. //
  642. // First go through the filter.
  643. //
  644. status = UlFilterSendHandler(
  645. &pConnection->FilterInfo,
  646. pMdlChain,
  647. Length,
  648. pIrpContext
  649. );
  650. UlTrace(TDI, (
  651. "UlSendData: sent filtered data, status = 0x%x\n",
  652. status
  653. ));
  654. ASSERT(status == STATUS_PENDING);
  655. if (pIrpContext != NULL && pIrpContext != pOwnIrpContext)
  656. {
  657. UlPplFreeIrpContext( pIrpContext );
  658. }
  659. }
  660. else
  661. {
  662. //
  663. // Just send it directly to the network.
  664. //
  665. status = UlpSendRawData(
  666. pConnection,
  667. pMdlChain,
  668. Length,
  669. pIrpContext
  670. );
  671. UlTrace(TDI, (
  672. "UlSendData: sent raw data, status = 0x%x\n",
  673. status
  674. ));
  675. }
  676. if (!NT_SUCCESS(status))
  677. {
  678. goto fatal;
  679. }
  680. //
  681. // Now that the send is "in flight", initiate a disconnect if
  682. // so requested.
  683. //
  684. // CODEWORK: Investigate the new-for-NT5 TDI_SEND_AND_DISCONNECT flag.
  685. //
  686. if (InitiateDisconnect)
  687. {
  688. WRITE_REF_TRACE_LOG2(
  689. g_pTdiTraceLog,
  690. pConnection->pTraceLog,
  691. REF_ACTION_CLOSE_UL_CONNECTION_GRACEFUL,
  692. pConnection->ReferenceCount,
  693. pConnection,
  694. __FILE__,
  695. __LINE__
  696. );
  697. (VOID)UlCloseConnection(
  698. pConnection,
  699. FALSE, // AbortiveDisconnect
  700. NULL, // pCompletionRoutine
  701. NULL // pCompletionContext
  702. );
  703. UlTrace(TDI, (
  704. "UlSendData: closed conn\n"
  705. ));
  706. }
  707. DEREFERENCE_CONNECTION( pConnection );
  708. return STATUS_PENDING;
  709. fatal:
  710. ASSERT( !NT_SUCCESS(status) );
  711. if (pIrpContext != NULL && pIrpContext != pOwnIrpContext)
  712. {
  713. UlPplFreeIrpContext( pIrpContext );
  714. }
  715. (VOID)UlpCloseRawConnection(
  716. pConnection,
  717. TRUE, // AbortiveDisconnect
  718. NULL, // pCompletionRoutine
  719. NULL // pCompletionContext
  720. );
  721. UlTrace(TDI, (
  722. "UlSendData: error occurred; closed raw conn\n"
  723. ));
  724. status = UlInvokeCompletionRoutine(
  725. status,
  726. 0,
  727. pCompletionRoutine,
  728. pCompletionContext
  729. );
  730. UlTrace(TDI, (
  731. "UlSendData: finished completion routine: status = 0x%x\n",
  732. status
  733. ));
  734. DEREFERENCE_CONNECTION( pConnection );
  735. return status;
  736. } // UlSendData
  737. /***************************************************************************++
  738. Routine Description:
  739. Receives data from the specified connection. This function is
  740. typically used after a receive indication handler has failed to
  741. consume all of the indicated data.
  742. If the connection is filtered the data will be read from the
  743. filter channel.
  744. Arguments:
  745. pConnection - Supplies a pointer to a connection as previously
  746. indicated to the PUL_CONNECTION_REQUEST handler.
  747. pBuffer - Supplies a pointer to the target buffer for the received
  748. data.
  749. BufferLength - Supplies the length of pBuffer.
  750. pCompletionRoutine - Supplies a pointer to a completion routine to
  751. invoke after the listening endpoint is fully closed.
  752. pCompletionContext - Supplies an uninterpreted context value for the
  753. completion routine.
  754. Return Value:
  755. NTSTATUS - Completion status.
  756. --***************************************************************************/
  757. NTSTATUS
  758. UlReceiveData(
  759. IN PVOID pConnectionContext,
  760. IN PVOID pBuffer,
  761. IN ULONG BufferLength,
  762. IN PUL_COMPLETION_ROUTINE pCompletionRoutine,
  763. IN PVOID pCompletionContext
  764. )
  765. {
  766. NTSTATUS status;
  767. PUL_CONNECTION pConnection = (PUL_CONNECTION)pConnectionContext;
  768. //
  769. // Sanity check.
  770. //
  771. ASSERT(IS_VALID_CONNECTION(pConnection));
  772. if (pConnection->FilterInfo.pFilterChannel)
  773. {
  774. //
  775. // This is a filtered connection, get the data from the
  776. // filter.
  777. //
  778. status = UlFilterReadHandler(
  779. &pConnection->FilterInfo,
  780. (PBYTE)pBuffer,
  781. BufferLength,
  782. pCompletionRoutine,
  783. pCompletionContext
  784. );
  785. }
  786. else
  787. {
  788. //
  789. // This is not a filtered connection. Get the data from
  790. // TDI.
  791. //
  792. status = UlpReceiveRawData(
  793. pConnectionContext,
  794. pBuffer,
  795. BufferLength,
  796. pCompletionRoutine,
  797. pCompletionContext
  798. );
  799. }
  800. return status;
  801. } // UlReceiveData
  802. /***************************************************************************++
  803. Routine Description:
  804. Either create a new endpoint for the specified address or, if one
  805. already exists, reference it.
  806. Arguments:
  807. pSiteUrl - Supplies the URL specifying the site to add.
  808. Return Value:
  809. NTSTATUS - Completion status.
  810. --***************************************************************************/
  811. NTSTATUS
  812. UlAddSiteToEndpointList(
  813. IN PWSTR pSiteUrl
  814. )
  815. {
  816. NTSTATUS status;
  817. TA_IP_ADDRESS address;
  818. BOOLEAN secure;
  819. PUL_ENDPOINT pEndpoint;
  820. KIRQL oldIrql;
  821. //
  822. // N.B. pSiteUrl is paged and cannot be manipulated with the
  823. // spinlock held. Even though this routine cannot be pageable
  824. // (due to the spinlock aquisition), it must be called at
  825. // low IRQL.
  826. //
  827. ASSERT( KeGetCurrentIrql() == PASSIVE_LEVEL );
  828. UlTrace(SITE, (
  829. "UlAddSiteToEndpointList: URL = %ws\n",
  830. pSiteUrl
  831. ));
  832. //
  833. // Convert the string into an address.
  834. //
  835. status = UlpUrlToAddress(pSiteUrl, &address, &secure);
  836. if (!NT_SUCCESS(status))
  837. {
  838. goto cleanup;
  839. }
  840. UlAcquireSpinLock( &g_TdiSpinLock, &oldIrql );
  841. //
  842. // make sure we're not shutting down
  843. //
  844. if (g_TdiWaitingForEndpointDrain) {
  845. UlReleaseSpinLock( &g_TdiSpinLock, oldIrql );
  846. status = STATUS_DEVICE_BUSY;
  847. goto cleanup;
  848. }
  849. //
  850. // Find an existing endpoint for this address.
  851. //
  852. pEndpoint = UlpFindEndpointForAddress(
  853. (PTRANSPORT_ADDRESS)&address,
  854. sizeof(address)
  855. );
  856. //
  857. // Did we find one?
  858. //
  859. if (pEndpoint == NULL)
  860. {
  861. //
  862. // Didn't find it. Try to create one. Since we must release
  863. // the TDI spinlock before we can create a new listening endpoint,
  864. // there is the opportunity for a race condition with other
  865. // threads creating endpoints.
  866. //
  867. UlReleaseSpinLock( &g_TdiSpinLock, oldIrql );
  868. UlTrace(SITE, (
  869. "UlAddSiteToEndpointList: no site for %ws, creating\n",
  870. pSiteUrl
  871. ));
  872. status = UlCreateListeningEndpoint(
  873. (PTRANSPORT_ADDRESS)&address, // pLocalAddress
  874. sizeof(address), // LocalAddressLength
  875. secure, // Secure (SSL) endpoint?
  876. g_UlMinIdleConnections, // InitialBacklog
  877. &UlConnectionRequest, // callback functions
  878. &UlConnectionComplete,
  879. &UlConnectionDisconnect,
  880. &UlConnectionDisconnectComplete,
  881. &UlConnectionDestroyed,
  882. &UlHttpReceive,
  883. NULL, // pListeningContext
  884. &pEndpoint
  885. );
  886. if (!NT_SUCCESS(status))
  887. {
  888. //
  889. // Maybe another thread has already created it?
  890. //
  891. UlAcquireSpinLock( &g_TdiSpinLock, &oldIrql );
  892. pEndpoint = UlpFindEndpointForAddress(
  893. (PTRANSPORT_ADDRESS)&address,
  894. sizeof(address)
  895. );
  896. if (pEndpoint != NULL)
  897. {
  898. //
  899. // Adjust the usage count.
  900. //
  901. pEndpoint->UsageCount++;
  902. ASSERT( pEndpoint->UsageCount > 0 );
  903. status = STATUS_SUCCESS;
  904. }
  905. //
  906. // The endpoint doesn't exist. This is a "real" failure.
  907. //
  908. UlReleaseSpinLock( &g_TdiSpinLock, oldIrql );
  909. }
  910. }
  911. else
  912. {
  913. //
  914. // Adjust the usage count.
  915. //
  916. pEndpoint->UsageCount++;
  917. ASSERT( pEndpoint->UsageCount > 0 );
  918. UlReleaseSpinLock( &g_TdiSpinLock, oldIrql );
  919. }
  920. UlTrace(SITE, (
  921. "UlAddSiteToEndpointList: using endpoint %p for URL %ws\n",
  922. pEndpoint,
  923. pSiteUrl
  924. ));
  925. cleanup:
  926. RETURN(status);
  927. } // UlAddSiteToEndpointList
  928. /***************************************************************************++
  929. Routine Description:
  930. Dereference the endpoint corresponding to the specified address.
  931. Arguments:
  932. pSiteUrl - Supplies the URL specifying the site to remove.
  933. Return Value:
  934. NTSTATUS - Completion status.
  935. --***************************************************************************/
  936. NTSTATUS
  937. UlRemoveSiteFromEndpointList(
  938. IN PWSTR pSiteUrl
  939. )
  940. {
  941. NTSTATUS status;
  942. TA_IP_ADDRESS address;
  943. BOOLEAN secure;
  944. PUL_ENDPOINT pEndpoint;
  945. KIRQL oldIrql;
  946. BOOLEAN spinlockHeld = FALSE;
  947. UL_STATUS_BLOCK ulStatus;
  948. //
  949. // N.B. pSiteUrl is paged and cannot be manipulated with the
  950. // spinlock held. Even though this routine cannot be pageable
  951. // (due to the spinlock aquisition), it must be called at
  952. // low IRQL.
  953. //
  954. ASSERT( KeGetCurrentIrql() == PASSIVE_LEVEL );
  955. UlTrace(SITE, (
  956. "UlRemoveSiteFromEndpointList: URL = %ws\n",
  957. pSiteUrl
  958. ));
  959. //
  960. // Convert the string into an address.
  961. //
  962. status = UlpUrlToAddress(pSiteUrl, &address, &secure);
  963. if (!NT_SUCCESS(status))
  964. {
  965. goto cleanup;
  966. }
  967. //
  968. // Find an existing endpoint for this address.
  969. //
  970. UlAcquireSpinLock( &g_TdiSpinLock, &oldIrql );
  971. spinlockHeld = TRUE;
  972. pEndpoint = UlpFindEndpointForAddress(
  973. (PTRANSPORT_ADDRESS)&address,
  974. sizeof(address)
  975. );
  976. //
  977. // Did we find one?
  978. //
  979. if (pEndpoint == NULL)
  980. {
  981. //
  982. // Ideally, this should never happen.
  983. //
  984. status = STATUS_NOT_FOUND;
  985. goto cleanup;
  986. }
  987. //
  988. // Adjust the usage count. If it drops to zero, blow away the
  989. // endpoint.
  990. //
  991. ASSERT( pEndpoint->UsageCount > 0 );
  992. pEndpoint->UsageCount--;
  993. if (pEndpoint->UsageCount == 0)
  994. {
  995. //
  996. // We can't call UlCloseListeningEndpoint() with the TDI spinlock
  997. // held. If the endpoint is still on the global list, then go
  998. // ahead and remove it now, release the TDI spinlock, and then
  999. // close the endpoint.
  1000. //
  1001. if (! pEndpoint->Deleted)
  1002. {
  1003. ASSERT(NULL != pEndpoint->GlobalEndpointListEntry.Flink);
  1004. RemoveEntryList( &pEndpoint->GlobalEndpointListEntry );
  1005. InsertTailList(
  1006. &g_TdiDeletedEndpointListHead,
  1007. &pEndpoint->GlobalEndpointListEntry
  1008. );
  1009. pEndpoint->Deleted = TRUE;
  1010. }
  1011. UlReleaseSpinLock( &g_TdiSpinLock, oldIrql );
  1012. spinlockHeld = FALSE;
  1013. UlTrace(SITE, (
  1014. "UlRemoveSiteFromEndpointList: closing endpoint %p for URL %ws\n",
  1015. pEndpoint,
  1016. pSiteUrl
  1017. ));
  1018. //
  1019. // Initialize a status block. We'll pass a pointer to this as
  1020. // the completion context to UlCloseListeningEndpoint(). The
  1021. // completion routine will update the status block and signal
  1022. // the event.
  1023. //
  1024. UlInitializeStatusBlock( &ulStatus );
  1025. status = UlCloseListeningEndpoint(
  1026. pEndpoint,
  1027. &UlpSynchronousIoComplete,
  1028. &ulStatus
  1029. );
  1030. if (status == STATUS_PENDING)
  1031. {
  1032. //
  1033. // Wait for it to finish.
  1034. //
  1035. UlWaitForStatusBlockEvent( &ulStatus );
  1036. //
  1037. // Retrieve the updated status.
  1038. //
  1039. status = ulStatus.IoStatus.Status;
  1040. }
  1041. }
  1042. cleanup:
  1043. if (spinlockHeld)
  1044. {
  1045. UlReleaseSpinLock( &g_TdiSpinLock, oldIrql );
  1046. }
  1047. #if DBG
  1048. if (status == STATUS_NOT_FOUND)
  1049. {
  1050. UlTrace(SITE, (
  1051. "UlRemoveSiteFromEndpointList: cannot find endpoint for URL %ws\n",
  1052. pSiteUrl
  1053. ));
  1054. }
  1055. #endif
  1056. RETURN(status);
  1057. } // UlRemoveSiteFromEndpointList
  1058. //
  1059. // Private functions.
  1060. //
  1061. /***************************************************************************++
  1062. Routine Description:
  1063. Destroys all resources allocated to an endpoint, including the
  1064. endpoint structure itself.
  1065. Arguments:
  1066. pEndpoint - Supplies the endpoint to destroy.
  1067. --***************************************************************************/
  1068. VOID
  1069. UlpDestroyEndpoint(
  1070. IN PUL_ENDPOINT pEndpoint
  1071. )
  1072. {
  1073. PUL_IRP_CONTEXT pIrpContext;
  1074. PUL_CONNECTION pConnection;
  1075. ULONG EndpointCount;
  1076. KIRQL oldIrql;
  1077. //
  1078. // Sanity check.
  1079. //
  1080. ASSERT( IS_VALID_ENDPOINT( pEndpoint ) );
  1081. ASSERT(0 == pEndpoint->ReferenceCount);
  1082. UlTrace(TDI, (
  1083. "UlpDestroyEndpoint: endpoint %p\n",
  1084. pEndpoint
  1085. ));
  1086. //
  1087. // Purge the idle queue.
  1088. //
  1089. for (;;)
  1090. {
  1091. pConnection = UlpDequeueIdleConnection( pEndpoint, FALSE );
  1092. if (pConnection == NULL )
  1093. {
  1094. break;
  1095. }
  1096. ASSERT( IS_VALID_CONNECTION( pConnection ) );
  1097. if (pConnection->FilterInfo.pFilterChannel)
  1098. {
  1099. HTTP_RAW_CONNECTION_ID ConnectionId;
  1100. ConnectionId = pConnection->FilterInfo.ConnectionId;
  1101. HTTP_SET_NULL_ID( &pConnection->FilterInfo.ConnectionId );
  1102. if (! HTTP_IS_NULL_ID( &ConnectionId ))
  1103. {
  1104. UlFreeOpaqueId(ConnectionId, UlOpaqueIdTypeRawConnection);
  1105. ASSERT( pConnection->ReferenceCount >= 2 );
  1106. DEREFERENCE_CONNECTION(pConnection);
  1107. }
  1108. }
  1109. UlpDestroyConnection( pConnection );
  1110. }
  1111. //
  1112. // Invoke the completion routine in the IRP context if specified.
  1113. //
  1114. pIrpContext = &pEndpoint->CleanupIrpContext;
  1115. ASSERT( IS_VALID_IRP_CONTEXT( pIrpContext ) );
  1116. if (pIrpContext->pCompletionRoutine != NULL)
  1117. {
  1118. (pIrpContext->pCompletionRoutine)(
  1119. pIrpContext->pCompletionContext,
  1120. STATUS_SUCCESS,
  1121. 0
  1122. );
  1123. }
  1124. //
  1125. // Close the TDI object.
  1126. //
  1127. UxCloseTdiObject( &pEndpoint->AddressObject );
  1128. //
  1129. // Remove the endpoint from g_TdiDeletedEndpointListHead
  1130. //
  1131. ASSERT( pEndpoint->Deleted );
  1132. ASSERT( NULL != pEndpoint->GlobalEndpointListEntry.Flink );
  1133. UlAcquireSpinLock( &g_TdiSpinLock, &oldIrql );
  1134. RemoveEntryList( &pEndpoint->GlobalEndpointListEntry );
  1135. UlReleaseSpinLock( &g_TdiSpinLock, oldIrql );
  1136. //
  1137. // Zap the owner ref trace log
  1138. //
  1139. DESTROY_OWNER_REF_TRACE_LOG(pEndpoint->pOwnerRefTraceLog);
  1140. //
  1141. // Free the endpoint structure.
  1142. //
  1143. pEndpoint->Signature = UL_ENDPOINT_SIGNATURE_X;
  1144. UL_FREE_POOL( pEndpoint, UL_ENDPOINT_POOL_TAG );
  1145. //
  1146. // Decrement the global endpoint count.
  1147. //
  1148. EndpointCount = InterlockedDecrement((PLONG) &g_TdiEndpointCount);
  1149. if (g_TdiWaitingForEndpointDrain && (EndpointCount == 0))
  1150. {
  1151. KeSetEvent(&g_TdiEndpointDrainEvent, 0, FALSE);
  1152. }
  1153. } // UlpDestroyEndpoint
  1154. /***************************************************************************++
  1155. Routine Description:
  1156. Destroys all resources allocated to an connection, including the
  1157. connection structure itself.
  1158. Arguments:
  1159. pConnection - Supplies the connection to destroy.
  1160. --***************************************************************************/
  1161. VOID
  1162. UlpDestroyConnection(
  1163. IN PUL_CONNECTION pConnection
  1164. )
  1165. {
  1166. KIRQL OldIrql;
  1167. LONG ConnectionCount;
  1168. //
  1169. // Sanity check.
  1170. //
  1171. ASSERT( IS_VALID_CONNECTION( pConnection ) );
  1172. ASSERT( pConnection->ActiveListEntry.Flink == NULL );
  1173. ASSERT( pConnection->IdleSListEntry.Next == NULL );
  1174. UlTrace(TDI, (
  1175. "UlpDestroyConnection: connection %p\n",
  1176. pConnection
  1177. ));
  1178. //
  1179. // Release the filter channel if we still have a ref.
  1180. // This only happens when we destroy idle connections.
  1181. //
  1182. if (pConnection->FilterInfo.pFilterChannel)
  1183. {
  1184. ASSERT(pConnection->FilterInfo.ConnState == UlFilterConnStateInactive);
  1185. DEREFERENCE_FILTER_CHANNEL(pConnection->FilterInfo.pFilterChannel);
  1186. pConnection->FilterInfo.pFilterChannel = NULL;
  1187. }
  1188. // If OpaqueId is non-zero, then refCount should not be zero
  1189. ASSERT(HTTP_IS_NULL_ID(&pConnection->FilterInfo.ConnectionId));
  1190. #if INVESTIGATE_LATER
  1191. //
  1192. // Free the filter connection ID
  1193. //
  1194. UlFreeOpaqueId(
  1195. pConnection->FilterInfo.ConnectionId,
  1196. UlOpaqueIdTypeRawConnection);
  1197. #endif
  1198. DESTROY_REF_TRACE_LOG( pConnection->pTraceLog );
  1199. DESTROY_REF_TRACE_LOG( pConnection->HttpConnection.pTraceLog );
  1200. //
  1201. // Close the TDI object.
  1202. //
  1203. UxCloseTdiObject( &pConnection->ConnectionObject );
  1204. //
  1205. // Free the accept IRP.
  1206. //
  1207. if (pConnection->pIrp != NULL)
  1208. {
  1209. UlFreeIrp( pConnection->pIrp );
  1210. }
  1211. //
  1212. // Remove from global list of connections
  1213. //
  1214. UlAcquireSpinLock( &g_TdiSpinLock, &OldIrql );
  1215. RemoveEntryList( &pConnection->GlobalConnectionListEntry );
  1216. UlReleaseSpinLock( &g_TdiSpinLock, OldIrql );
  1217. ConnectionCount = InterlockedDecrement((PLONG) &g_TdiConnectionCount);
  1218. //
  1219. // Free the connection structure.
  1220. //
  1221. pConnection->Signature = UL_CONNECTION_SIGNATURE_X;
  1222. UL_FREE_POOL( pConnection, UL_CONNECTION_POOL_TAG );
  1223. // allow us to shut down
  1224. if (g_TdiWaitingForEndpointDrain && (ConnectionCount == 0))
  1225. {
  1226. KeSetEvent(&g_TdiConnectionDrainEvent, 0, FALSE);
  1227. }
  1228. } // UlpDestroyConnection
  1229. /***************************************************************************++
  1230. Routine Description:
  1231. Dequeues an idle connection from the specified endpoint.
  1232. Arguments:
  1233. pEndpoint - Supplies the endpoint to dequeue from.
  1234. ScheduleReplenish - Supplies TRUE if a replenishment of the
  1235. idle connection list should be scheduled.
  1236. Return Value:
  1237. PUL_CONNECTION - Pointer to an idle connection is successful,
  1238. NULL otherwise.
  1239. --***************************************************************************/
  1240. PUL_CONNECTION
  1241. UlpDequeueIdleConnection(
  1242. IN PUL_ENDPOINT pEndpoint,
  1243. IN BOOLEAN ScheduleReplenish
  1244. )
  1245. {
  1246. PSINGLE_LIST_ENTRY pSListEntry;
  1247. PUL_CONNECTION pConnection;
  1248. BOOLEAN ReplenishNeeded;
  1249. //
  1250. // Sanity check.
  1251. //
  1252. ASSERT( IS_VALID_ENDPOINT( pEndpoint ) );
  1253. //
  1254. // Pop an entry off the list.
  1255. //
  1256. pSListEntry = ExInterlockedPopEntrySList(
  1257. &pEndpoint->IdleConnectionSListHead,
  1258. KSPIN_LOCK_FROM_UL_SPIN_LOCK(&pEndpoint->IdleConnectionSpinLock)
  1259. );
  1260. if (pSListEntry != NULL)
  1261. {
  1262. pConnection = CONTAINING_RECORD(
  1263. pSListEntry,
  1264. UL_CONNECTION,
  1265. IdleSListEntry
  1266. );
  1267. pConnection->IdleSListEntry.Next = NULL;
  1268. ASSERT( IS_VALID_CONNECTION( pConnection ) );
  1269. ASSERT(pConnection->ConnectionFlags.Value == 0);
  1270. if ( pConnection->FilterInfo.pFilterChannel )
  1271. {
  1272. //
  1273. // If the idle connection has filter attached on it, it will have
  1274. // an additional refcount because of the opaque id assigned to the
  1275. // ul_connection, filter API uses this id to communicate with the
  1276. // filter app through various IOCTLs.
  1277. //
  1278. ASSERT( 2 == pConnection->ReferenceCount );
  1279. }
  1280. else
  1281. {
  1282. //
  1283. // As long as the connection doesn get destroyed it will sit
  1284. // in the idle list with one refcount on it.
  1285. //
  1286. ASSERT( 1 == pConnection->ReferenceCount );
  1287. }
  1288. SET_OWNER_REF_TRACE_LOG_MONOTONIC_ID(
  1289. pConnection->MonotonicId,
  1290. pConnection->pOwningEndpoint->pOwnerRefTraceLog);
  1291. //
  1292. // See if we need to generate more connections.
  1293. //
  1294. ReplenishNeeded = UlpDecrementIdleConnections(pEndpoint);
  1295. }
  1296. else
  1297. {
  1298. //
  1299. // The idle list is empty. However, we should not schedule
  1300. // a replenish at this time. The driver's init code ensures
  1301. // that the min idle connections for an endpoint is always
  1302. // at least two, so the thread that decremented the counter
  1303. // to one will have scheduled a replenish by now anyway,
  1304. // and the replenish will continue adding connections until
  1305. // there are at least the min number of connections.
  1306. //
  1307. ReplenishNeeded = FALSE;
  1308. pConnection = NULL;
  1309. }
  1310. //
  1311. // Schedule a replenish if necessary.
  1312. //
  1313. if (ReplenishNeeded && ScheduleReplenish)
  1314. {
  1315. TRACE_REPLENISH(
  1316. pEndpoint,
  1317. DummySynch,
  1318. pEndpoint->EndpointSynch,
  1319. REPLENISH_ACTION_QUEUE_REPLENISH
  1320. );
  1321. //
  1322. // Add a reference to the endpoint to ensure that it doesn't
  1323. // disappear from under us. UlpReplenishEndpointWorker will
  1324. // remove the reference once it's finished.
  1325. //
  1326. REFERENCE_ENDPOINT_SELF(pEndpoint, REF_ACTION_REPLENISH);
  1327. UL_QUEUE_WORK_ITEM(
  1328. &pEndpoint->WorkItem,
  1329. &UlpReplenishEndpointWorker
  1330. );
  1331. }
  1332. return pConnection;
  1333. } // UlpDequeueIdleConnection
  1334. /***************************************************************************++
  1335. Routine Description:
  1336. Enqueues an idle connection onto the specified endpoint.
  1337. Arguments:
  1338. pConnection - Supplies the connection to enqueue.
  1339. Replinishing - TRUE if the connection is being added as part
  1340. of a replenish.
  1341. Return values:
  1342. Returns TRUE if the number of connections on the queue is still less
  1343. than the minimum required.
  1344. --***************************************************************************/
  1345. BOOLEAN
  1346. UlpEnqueueIdleConnection(
  1347. IN PUL_CONNECTION pConnection,
  1348. IN BOOLEAN Replenishing
  1349. )
  1350. {
  1351. PUL_ENDPOINT pEndpoint;
  1352. BOOLEAN ContinueReplenish;
  1353. //
  1354. // Sanity check.
  1355. //
  1356. ASSERT( IS_VALID_CONNECTION( pConnection ) );
  1357. pEndpoint = pConnection->pOwningEndpoint;
  1358. ASSERT( IS_VALID_ENDPOINT( pEndpoint ) );
  1359. ASSERT(pConnection->ConnectionFlags.Value == 0);
  1360. ASSERT(pConnection->ActiveListEntry.Flink == NULL);
  1361. // The idle list holds a reference; the filter channel (if it exists)
  1362. // holds another reference.
  1363. ASSERT(pConnection->ReferenceCount ==
  1364. 1 + (pConnection->FilterInfo.pFilterChannel != NULL));
  1365. //
  1366. // Increment the count of connections and see if we need
  1367. // to continue the replenish. We need to increment before
  1368. // we actually put the item on the list because otherwise
  1369. // someone else might pull the entry off and decrement the
  1370. // count below zero before we increment. There is no harm
  1371. // in the count being temporarily higher than the actual
  1372. // size of the list.
  1373. //
  1374. ContinueReplenish = UlpIncrementIdleConnections(
  1375. pEndpoint,
  1376. Replenishing
  1377. );
  1378. //
  1379. // Push it onto the list.
  1380. //
  1381. ExInterlockedPushEntrySList(
  1382. &pEndpoint->IdleConnectionSListHead,
  1383. &pConnection->IdleSListEntry,
  1384. KSPIN_LOCK_FROM_UL_SPIN_LOCK(&pEndpoint->IdleConnectionSpinLock)
  1385. );
  1386. return ContinueReplenish;
  1387. } // UlpEnqueueIdleConnection
  1388. /***************************************************************************++
  1389. Routine Description:
  1390. Enqueues an active connection onto the specified endpoint.
  1391. Arguments:
  1392. pConnection - Supplies the connection to enqueue.
  1393. --***************************************************************************/
  1394. VOID
  1395. UlpEnqueueActiveConnection(
  1396. IN PUL_CONNECTION pConnection
  1397. )
  1398. {
  1399. PUL_ENDPOINT pEndpoint;
  1400. //
  1401. // Sanity check.
  1402. //
  1403. ASSERT( IS_VALID_CONNECTION( pConnection ) );
  1404. ASSERT(pConnection->IdleSListEntry.Next == NULL);
  1405. pEndpoint = pConnection->pOwningEndpoint;
  1406. ASSERT( IS_VALID_ENDPOINT( pEndpoint ) );
  1407. //
  1408. // Append it to the list.
  1409. //
  1410. REFERENCE_CONNECTION(pConnection);
  1411. ExInterlockedInsertHeadList(
  1412. &pEndpoint->ActiveConnectionListHead[pConnection->ActiveListIndex],
  1413. &pConnection->ActiveListEntry,
  1414. KSPIN_LOCK_FROM_UL_SPIN_LOCK(&pEndpoint->ActiveConnectionSpinLock[pConnection->ActiveListIndex])
  1415. );
  1416. } // UlpEnqueueActiveConnection
  1417. /***************************************************************************++
  1418. Routine Description:
  1419. Handler for incoming connections.
  1420. Arguments:
  1421. pTdiEventContext - Supplies the context associated with the address
  1422. object. This should be a PUL_ENDPOINT.
  1423. RemoteAddressLength - Supplies the length of the remote (client-
  1424. side) address.
  1425. pRemoteAddress - Supplies a pointer to the remote address as
  1426. stored in a TRANSPORT_ADDRESS structure.
  1427. UserDataLength - Optionally supplies the length of any connect
  1428. data associated with the connection request.
  1429. pUserData - Optionally supplies a pointer to any connect data
  1430. associated with the connection request.
  1431. OptionsLength - Optionally supplies the length of any connect
  1432. options associated with the connection request.
  1433. pOptions - Optionally supplies a pointer to any connect options
  1434. associated with the connection request.
  1435. pConnectionContext - Receives the context to associate with this
  1436. connection. We'll always use a PUL_CONNECTION as the context.
  1437. pAcceptIrp - Receives an IRP that will be completed by the transport
  1438. when the incoming connection is fully accepted.
  1439. Return Value:
  1440. NTSTATUS - Completion status.
  1441. --***************************************************************************/
  1442. NTSTATUS
  1443. UlpConnectHandler(
  1444. IN PVOID pTdiEventContext,
  1445. IN LONG RemoteAddressLength,
  1446. IN PVOID pRemoteAddress,
  1447. IN LONG UserDataLength,
  1448. IN PVOID pUserData,
  1449. IN LONG OptionsLength,
  1450. IN PVOID pOptions,
  1451. OUT CONNECTION_CONTEXT *pConnectionContext,
  1452. OUT PIRP *pAcceptIrp
  1453. )
  1454. {
  1455. NTSTATUS status;
  1456. BOOLEAN result;
  1457. PUL_ENDPOINT pEndpoint;
  1458. PUL_CONNECTION pConnection;
  1459. PUX_TDI_OBJECT pTdiObject;
  1460. PIRP pIrp;
  1461. BOOLEAN handlerCalled;
  1462. TRANSPORT_ADDRESS UNALIGNED *TAList;
  1463. PTA_ADDRESS TA;
  1464. UL_ENTER_DRIVER("UlpConnectHandler", NULL);
  1465. //
  1466. // Sanity check.
  1467. //
  1468. pEndpoint = (PUL_ENDPOINT)pTdiEventContext;
  1469. ASSERT( IS_VALID_ENDPOINT( pEndpoint ) );
  1470. UlTrace(TDI,("UlpConnectHandler: endpoint %p\n", pTdiEventContext));
  1471. //
  1472. // Setup locals so we know how to cleanup on fatal exit.
  1473. //
  1474. pConnection = NULL;
  1475. handlerCalled = FALSE;
  1476. //
  1477. // make sure that we are not in the process of destroying this
  1478. // endpoint. UlRemoveSiteFromEndpointList will do that and
  1479. // start the cleanup process when UsageCount hits 0.
  1480. //
  1481. if (pEndpoint->UsageCount == 0)
  1482. {
  1483. status = STATUS_CONNECTION_REFUSED;
  1484. goto fatal;
  1485. }
  1486. //
  1487. // Try to pull an idle connection from the endpoint.
  1488. //
  1489. for (;;)
  1490. {
  1491. pConnection = UlpDequeueIdleConnection( pEndpoint, TRUE );
  1492. if (pConnection == NULL )
  1493. {
  1494. status = STATUS_INSUFFICIENT_RESOURCES;
  1495. goto fatal;
  1496. }
  1497. ASSERT( IS_VALID_CONNECTION( pConnection ) );
  1498. //
  1499. // Establish a referenced pointer from the connection back
  1500. // to the endpoint.
  1501. //
  1502. ASSERT( pConnection->pOwningEndpoint == pEndpoint );
  1503. REFERENCE_ENDPOINT_CONNECTION(
  1504. pEndpoint,
  1505. REF_ACTION_CONNECT,
  1506. pConnection
  1507. );
  1508. //
  1509. // Make sure the filter settings are up to date.
  1510. //
  1511. if (UlValidateFilterChannel(
  1512. pConnection->FilterInfo.pFilterChannel,
  1513. pConnection->FilterInfo.SecureConnection
  1514. ))
  1515. {
  1516. //
  1517. // We found a good connection.
  1518. // Break out of the loop and go on.
  1519. //
  1520. break;
  1521. }
  1522. //
  1523. // This connection doesn't have up to date filter
  1524. // settings. Destroy it and get a new connection.
  1525. //
  1526. // Grab a reference. Worker will deref it.
  1527. REFERENCE_CONNECTION( pConnection );
  1528. UL_CALL_PASSIVE(
  1529. &pConnection->WorkItem,
  1530. &UlpCleanupEarlyConnection
  1531. );
  1532. }
  1533. //
  1534. // We should have a good connection now.
  1535. //
  1536. ASSERT(IS_VALID_CONNECTION(pConnection));
  1537. pTdiObject = &pConnection->ConnectionObject;
  1538. //
  1539. // Store the remote address in the connection.
  1540. //
  1541. TAList = (TRANSPORT_ADDRESS UNALIGNED *) pRemoteAddress;
  1542. TA = (PTA_ADDRESS) TAList->Address;
  1543. if (TDI_ADDRESS_TYPE_IP == TA->AddressType) {
  1544. if (TA->AddressLength >= TDI_ADDRESS_LENGTH_IP) {
  1545. TDI_ADDRESS_IP UNALIGNED * ValidAddr = (TDI_ADDRESS_IP UNALIGNED *) TA->Address;
  1546. pConnection->RemoteAddress = SWAP_LONG(ValidAddr->in_addr);
  1547. pConnection->RemotePort = SWAP_SHORT(ValidAddr->sin_port);
  1548. }
  1549. } else {
  1550. // Add support for IP6 here
  1551. }
  1552. //
  1553. // Invoke the client's handler to see if they can accept
  1554. // this connection. If they refuse it, bail.
  1555. //
  1556. result = (pEndpoint->pConnectionRequestHandler)(
  1557. pEndpoint->pListeningContext,
  1558. pConnection,
  1559. (PTRANSPORT_ADDRESS)(pRemoteAddress),
  1560. RemoteAddressLength,
  1561. &pConnection->pConnectionContext
  1562. );
  1563. if (!result)
  1564. {
  1565. status = STATUS_CONNECTION_REFUSED;
  1566. goto fatal;
  1567. }
  1568. //
  1569. // Remember that we've called the handler. If we hit a fatal
  1570. // condition (say, out of memory) after this point, we'll
  1571. // fake a "failed connection complete" indication to the client
  1572. // so they can cleanup their state.
  1573. //
  1574. handlerCalled = TRUE;
  1575. pConnection->pIrp->Tail.Overlay.Thread = PsGetCurrentThread();
  1576. pConnection->pIrp->Tail.Overlay.OriginalFileObject = pTdiObject->pFileObject;
  1577. TdiBuildAccept(
  1578. pConnection->pIrp, // Irp
  1579. pTdiObject->pDeviceObject, // DeviceObject
  1580. pTdiObject->pFileObject, // FileObject
  1581. &UlpRestartAccept, // CompletionRoutine
  1582. pConnection, // Context
  1583. &(pConnection->TdiConnectionInformation), // RequestConnectionInfo
  1584. NULL // ReturnConnectionInfo
  1585. );
  1586. //
  1587. // We must trace the IRP before we set the next stack location
  1588. // so the trace code can pull goodies from the IRP correctly.
  1589. //
  1590. TRACE_IRP( IRP_ACTION_CALL_DRIVER, pConnection->pIrp );
  1591. //
  1592. // Make the next stack location current. Normally, UlCallDriver would
  1593. // do this for us, but since we're bypassing UlCallDriver, we must do
  1594. // it ourselves.
  1595. //
  1596. IoSetNextIrpStackLocation( pConnection->pIrp );
  1597. //
  1598. // Return the IRP to the transport.
  1599. //
  1600. *pAcceptIrp = pConnection->pIrp;
  1601. //
  1602. // Establish the connection context.
  1603. //
  1604. *pConnectionContext = (CONNECTION_CONTEXT)pConnection;
  1605. pConnection->ConnectionFlags.AcceptPending = TRUE;
  1606. //
  1607. // Reference the connection so it doesn't go away before
  1608. // the accept IRP completes.
  1609. //
  1610. REFERENCE_CONNECTION( pConnection );
  1611. UL_LEAVE_DRIVER("UlpConnectHandler");
  1612. //
  1613. // Tell TDI that we gave it an IRP to complete.
  1614. //
  1615. return STATUS_MORE_PROCESSING_REQUIRED;
  1616. //
  1617. // Cleanup for fatal error conditions.
  1618. //
  1619. fatal:
  1620. UlTrace(TDI, (
  1621. "UlpConnectHandler: endpoint %p, failure %08lx\n",
  1622. pTdiEventContext,
  1623. status
  1624. ));
  1625. if (handlerCalled)
  1626. {
  1627. //
  1628. // Fake a "failed connection complete" indication.
  1629. //
  1630. (pEndpoint->pConnectionCompleteHandler)(
  1631. pEndpoint->pListeningContext,
  1632. pConnection->pConnectionContext,
  1633. status
  1634. );
  1635. }
  1636. //
  1637. // If we managed to pull a connection off the idle list, then
  1638. // put it back and remove the endpoint reference we added.
  1639. //
  1640. if (pConnection != NULL)
  1641. {
  1642. // Fake refcount up. Worker will deref it.
  1643. REFERENCE_CONNECTION( pConnection );
  1644. UL_CALL_PASSIVE(
  1645. &pConnection->WorkItem,
  1646. &UlpCleanupEarlyConnection
  1647. );
  1648. }
  1649. UL_LEAVE_DRIVER("UlpConnectHandler");
  1650. return status;
  1651. } // UlpConnectHandler
  1652. /***************************************************************************++
  1653. Routine Description:
  1654. Handler for disconnect requests.
  1655. Arguments:
  1656. pTdiEventContext - Supplies the context associated with the address
  1657. object. This should be a PUL_ENDPOINT.
  1658. ConnectionContext - Supplies the context associated with the
  1659. connection object. This should be a PUL_CONNECTION.
  1660. DisconnectDataLength - Optionally supplies the length of any
  1661. disconnect data associated with the disconnect request.
  1662. pDisconnectData - Optionally supplies a pointer to any disconnect
  1663. data associated with the disconnect request.
  1664. DisconnectInformationLength - Optionally supplies the length of any
  1665. disconnect information associated with the disconnect request.
  1666. pDisconnectInformation - Optionally supplies a pointer to any
  1667. disconnect information associated with the disconnect request.
  1668. DisconnectFlags - Supplies the disconnect flags. This will be zero
  1669. or more TDI_DISCONNECT_* flags.
  1670. Return Value:
  1671. NTSTATUS - Completion status.
  1672. --***************************************************************************/
  1673. NTSTATUS
  1674. UlpDisconnectHandler(
  1675. IN PVOID pTdiEventContext,
  1676. IN CONNECTION_CONTEXT ConnectionContext,
  1677. IN LONG DisconnectDataLength,
  1678. IN PVOID pDisconnectData,
  1679. IN LONG DisconnectInformationLength,
  1680. IN PVOID pDisconnectInformation,
  1681. IN ULONG DisconnectFlags
  1682. )
  1683. {
  1684. PUL_ENDPOINT pEndpoint;
  1685. PUL_CONNECTION pConnection;
  1686. PVOID pListeningContext;
  1687. PVOID pConnectionContext;
  1688. NTSTATUS status;
  1689. UL_CONNECTION_FLAGS newFlags;
  1690. UL_ENTER_DRIVER("UlpDisconnectHandler", NULL);
  1691. //
  1692. // Sanity check.
  1693. //
  1694. pEndpoint = (PUL_ENDPOINT)pTdiEventContext;
  1695. ASSERT( IS_VALID_ENDPOINT( pEndpoint ) );
  1696. pConnection = (PUL_CONNECTION)ConnectionContext;
  1697. ASSERT( IS_VALID_CONNECTION( pConnection ) );
  1698. ASSERT( pConnection->pOwningEndpoint == pEndpoint );
  1699. UlTrace(TDI, (
  1700. "UlpDisconnectHandler: endpoint %p, connection %p, flags %08lx\n",
  1701. pTdiEventContext,
  1702. (PVOID)ConnectionContext,
  1703. DisconnectFlags
  1704. ));
  1705. //
  1706. // If it's a filtered connection, make sure we stop passing
  1707. // on AppWrite data.
  1708. //
  1709. if (pConnection->FilterInfo.pFilterChannel)
  1710. {
  1711. UlDestroyFilterConnection(&pConnection->FilterInfo);
  1712. }
  1713. //
  1714. // Update the connection state based on the type of disconnect.
  1715. //
  1716. if (DisconnectFlags & TDI_DISCONNECT_ABORT)
  1717. {
  1718. status = STATUS_CONNECTION_ABORTED;
  1719. }
  1720. else
  1721. {
  1722. status = STATUS_SUCCESS;
  1723. }
  1724. //
  1725. // Capture the endpoint and connection context values here so we can
  1726. // invoke the client's handler *after* dereferencing the connection.
  1727. //
  1728. pListeningContext = pEndpoint->pListeningContext;
  1729. pConnectionContext = pConnection->pConnectionContext;
  1730. //
  1731. // Tell the client, but only if the accept IRP has already completed.
  1732. //
  1733. newFlags.Value =
  1734. *((volatile LONG *)&pConnection->ConnectionFlags.Value);
  1735. if (newFlags.AcceptComplete)
  1736. {
  1737. //
  1738. // Silently close the connection. No need to go httprcv
  1739. // disconnect handler. It's just going to callback us anyway.
  1740. //
  1741. UlpCloseRawConnection( pConnection,
  1742. FALSE,
  1743. NULL,
  1744. NULL
  1745. );
  1746. }
  1747. //
  1748. // Done with the disconnect mark the flag, before attempting
  1749. // to remove the final reference.
  1750. //
  1751. if (DisconnectFlags & TDI_DISCONNECT_ABORT)
  1752. {
  1753. newFlags = UlpSetConnectionFlag(
  1754. pConnection,
  1755. MakeAbortIndicatedFlag()
  1756. );
  1757. }
  1758. else
  1759. {
  1760. newFlags = UlpSetConnectionFlag(
  1761. pConnection,
  1762. MakeDisconnectIndicatedFlag()
  1763. );
  1764. }
  1765. //
  1766. // If cleanup has begun on the connection, remove the final reference.
  1767. //
  1768. UlpRemoveFinalReference( pConnection, newFlags );
  1769. UL_LEAVE_DRIVER("UlpDisconnectHandler");
  1770. return STATUS_SUCCESS;
  1771. } // UlpDisconnectHandler
  1772. /***************************************************************************++
  1773. Routine Description:
  1774. Closes a previously accepted connection.
  1775. Arguments:
  1776. pConnection - Supplies a pointer to a connection as previously
  1777. indicated to the PUL_CONNECTION_REQUEST handler.
  1778. AbortiveDisconnect - Supplies TRUE if the connection is to be abortively
  1779. disconnected, FALSE if it should be gracefully disconnected.
  1780. pCompletionRoutine - Supplies a pointer to a completion routine to
  1781. invoke after the connection is fully closed.
  1782. pCompletionContext - Supplies an uninterpreted context value for the
  1783. completion routine.
  1784. Return Value:
  1785. NTSTATUS - Completion status.
  1786. --***************************************************************************/
  1787. NTSTATUS
  1788. UlpCloseRawConnection(
  1789. IN PVOID pConn,
  1790. IN BOOLEAN AbortiveDisconnect,
  1791. IN PUL_COMPLETION_ROUTINE pCompletionRoutine,
  1792. IN PVOID pCompletionContext
  1793. )
  1794. {
  1795. NTSTATUS status;
  1796. PUL_CONNECTION pConnection = (PUL_CONNECTION)pConn;
  1797. //
  1798. // Sanity check.
  1799. //
  1800. ASSERT( IS_VALID_CONNECTION( pConnection ) );
  1801. UlTrace(TDI, (
  1802. "UlpCloseRawConnection: connection %p, abort %lu\n",
  1803. pConnection,
  1804. (ULONG)AbortiveDisconnect
  1805. ));
  1806. //
  1807. // This is the final close handler for all types of connections
  1808. // filter, non filter. We should not go through this path twice
  1809. //
  1810. if (FALSE != InterlockedExchange(&pConnection->Terminated, TRUE))
  1811. {
  1812. //
  1813. // we've already done it. don't do it twice.
  1814. //
  1815. status = UlInvokeCompletionRoutine(
  1816. STATUS_SUCCESS,
  1817. 0,
  1818. pCompletionRoutine,
  1819. pCompletionContext
  1820. );
  1821. return status;
  1822. }
  1823. WRITE_REF_TRACE_LOG2(
  1824. g_pTdiTraceLog,
  1825. pConnection->pTraceLog,
  1826. REF_ACTION_CLOSE_UL_CONNECTION_RAW_CLOSE,
  1827. pConnection->ReferenceCount,
  1828. pConnection,
  1829. __FILE__,
  1830. __LINE__
  1831. );
  1832. //
  1833. // Get rid of our opaque id if we're a filtered connection.
  1834. // Also make sure we stop delivering AppWrite data to the parser.
  1835. //
  1836. if (pConnection->FilterInfo.pFilterChannel)
  1837. {
  1838. UL_CALL_PASSIVE(
  1839. &pConnection->WorkItem,
  1840. &UlpCleanupConnectionId
  1841. );
  1842. UlDestroyFilterConnection(&pConnection->FilterInfo);
  1843. }
  1844. //
  1845. // Begin a disconnect and let the completion routine do the
  1846. // dirty work.
  1847. //
  1848. if (AbortiveDisconnect)
  1849. {
  1850. status = UlpBeginAbort(
  1851. pConnection,
  1852. pCompletionRoutine,
  1853. pCompletionContext
  1854. );
  1855. }
  1856. else
  1857. {
  1858. status = UlpBeginDisconnect(
  1859. pConnection,
  1860. pCompletionRoutine,
  1861. pCompletionContext
  1862. );
  1863. }
  1864. return status;
  1865. } // UlpCloseRawConnection
  1866. /***************************************************************************++
  1867. Routine Description:
  1868. Sends a block of data on the specified connection.
  1869. Arguments:
  1870. pConnection - Supplies a pointer to a connection as previously
  1871. indicated to the PUL_CONNECTION_REQUEST handler.
  1872. pMdlChain - Supplies a pointer to a MDL chain describing the
  1873. data buffers to send.
  1874. Length - Supplies the length of the data referenced by the MDL
  1875. chain.
  1876. pIrpContext - used to indicate completion to the caller.
  1877. InitiateDisconnect - Supplies TRUE if a graceful disconnect should
  1878. be initiated immediately after initiating the send (i.e. before
  1879. the send actually completes).
  1880. --***************************************************************************/
  1881. NTSTATUS
  1882. UlpSendRawData(
  1883. IN PVOID pObject,
  1884. IN PMDL pMdlChain,
  1885. IN ULONG Length,
  1886. PUL_IRP_CONTEXT pIrpContext
  1887. )
  1888. {
  1889. NTSTATUS status;
  1890. PIRP pIrp;
  1891. PUX_TDI_OBJECT pTdiObject;
  1892. PUL_CONNECTION pConnection = (PUL_CONNECTION) pObject;
  1893. BOOLEAN OwnIrpContext;
  1894. //
  1895. // Sanity check.
  1896. //
  1897. ASSERT( IS_VALID_CONNECTION( pConnection ) );
  1898. pTdiObject = &pConnection->ConnectionObject;
  1899. ASSERT( IS_VALID_TDI_OBJECT( pTdiObject ) );
  1900. ASSERT( pMdlChain != NULL );
  1901. ASSERT( Length > 0 );
  1902. ASSERT( pIrpContext != NULL );
  1903. //
  1904. // Allocate an IRP.
  1905. //
  1906. if (pIrpContext->pOwnIrp)
  1907. {
  1908. OwnIrpContext = TRUE;
  1909. pIrp = pIrpContext->pOwnIrp;
  1910. }
  1911. else
  1912. {
  1913. OwnIrpContext = FALSE;
  1914. pIrp = UlAllocateIrp(
  1915. pTdiObject->pDeviceObject->StackSize, // StackSize
  1916. FALSE // ChargeQuota
  1917. );
  1918. if (pIrp == NULL)
  1919. {
  1920. status = STATUS_INSUFFICIENT_RESOURCES;
  1921. goto fatal;
  1922. }
  1923. }
  1924. //
  1925. // Build the send IRP, call the transport.
  1926. //
  1927. pIrp->RequestorMode = KernelMode;
  1928. pIrp->Tail.Overlay.Thread = PsGetCurrentThread();
  1929. pIrp->Tail.Overlay.OriginalFileObject = pTdiObject->pFileObject;
  1930. TdiBuildSend(
  1931. pIrp, // Irp
  1932. pTdiObject->pDeviceObject, // DeviceObject
  1933. pTdiObject->pFileObject, // FileObject
  1934. &UlpRestartSendData, // CompletionRoutine
  1935. pIrpContext, // Context
  1936. pMdlChain, // MdlAddress
  1937. 0, // Flags
  1938. Length // SendLength
  1939. );
  1940. UlTrace(TDI, (
  1941. "UlpSendRawData: allocated irp %p for connection %p\n",
  1942. pIrp,
  1943. pConnection
  1944. ));
  1945. WRITE_REF_TRACE_LOG(
  1946. g_pMdlTraceLog,
  1947. REF_ACTION_SEND_MDL,
  1948. PtrToLong(pMdlChain->Next), // bugbug64
  1949. pMdlChain,
  1950. __FILE__,
  1951. __LINE__
  1952. );
  1953. #ifdef SPECIAL_MDL_FLAG
  1954. {
  1955. PMDL scan = pMdlChain;
  1956. while (scan != NULL)
  1957. {
  1958. ASSERT( (scan->MdlFlags & SPECIAL_MDL_FLAG) == 0 );
  1959. scan->MdlFlags |= SPECIAL_MDL_FLAG;
  1960. scan = scan->Next;
  1961. }
  1962. }
  1963. #endif
  1964. IF_DEBUG2(TDI, VERBOSE)
  1965. {
  1966. PMDL pMdl;
  1967. ULONG i, NumMdls = 0;
  1968. for (pMdl = pMdlChain; pMdl != NULL; pMdl = pMdl->Next)
  1969. {
  1970. ++NumMdls;
  1971. }
  1972. UlTrace(TDI, (
  1973. "UlpSendRawData: irp %p, %d MDLs, %d bytes, [[[[.\n",
  1974. pIrp, NumMdls, Length
  1975. ));
  1976. for (pMdl = pMdlChain, i = 1; pMdl != NULL; pMdl = pMdl->Next, ++i)
  1977. {
  1978. PVOID pBuffer;
  1979. UlTrace(TDI, (
  1980. "UlpSendRawData: irp %p, MDL[%d of %d], %d bytes.\n",
  1981. pIrp, i, NumMdls, pMdl->ByteCount
  1982. ));
  1983. pBuffer = MmGetSystemAddressForMdlSafe(pMdl, NormalPagePriority);
  1984. if (pBuffer != NULL)
  1985. UlDbgPrettyPrintBuffer((UCHAR*) pBuffer, pMdl->ByteCount);
  1986. }
  1987. UlTrace(TDI, (
  1988. "UlpSendRawData: irp %p ]]]].\n",
  1989. pIrp
  1990. ));
  1991. }
  1992. //
  1993. // Add a reference to the connection, then call the driver to initiate
  1994. // the send.
  1995. //
  1996. REFERENCE_CONNECTION( pConnection );
  1997. ASSERT( g_TcpFastSend != NULL );
  1998. IoSetNextIrpStackLocation(pIrp);
  1999. (*g_TcpFastSend)(
  2000. pIrp,
  2001. IoGetCurrentIrpStackLocation(pIrp)
  2002. );
  2003. UlTrace(TDI, (
  2004. "UlpSendRawData: called driver for irp %p; "
  2005. "returning STATUS_PENDING\n",
  2006. pIrp
  2007. ));
  2008. return STATUS_PENDING;
  2009. fatal:
  2010. ASSERT( !NT_SUCCESS(status) );
  2011. if (pIrp != NULL && OwnIrpContext == FALSE)
  2012. {
  2013. UlFreeIrp( pIrp );
  2014. }
  2015. (VOID)UlpCloseRawConnection(
  2016. pConnection,
  2017. TRUE,
  2018. NULL,
  2019. NULL
  2020. );
  2021. return status;
  2022. } // UlpSendRawData
  2023. /***************************************************************************++
  2024. Routine Description:
  2025. Receives data from the specified connection. This function is
  2026. typically used after a receive indication handler has failed to
  2027. consume all of the indicated data.
  2028. Arguments:
  2029. pConnection - Supplies a pointer to a connection as previously
  2030. indicated to the PUL_CONNECTION_REQUEST handler.
  2031. pBuffer - Supplies a pointer to the target buffer for the received
  2032. data.
  2033. BufferLength - Supplies the length of pBuffer.
  2034. pCompletionRoutine - Supplies a pointer to a completion routine to
  2035. invoke after the listening endpoint is fully closed.
  2036. pCompletionContext - Supplies an uninterpreted context value for the
  2037. completion routine.
  2038. Return Value:
  2039. NTSTATUS - Completion status.
  2040. --***************************************************************************/
  2041. NTSTATUS
  2042. UlpReceiveRawData(
  2043. IN PVOID pConnectionContext,
  2044. IN PVOID pBuffer,
  2045. IN ULONG BufferLength,
  2046. IN PUL_COMPLETION_ROUTINE pCompletionRoutine,
  2047. IN PVOID pCompletionContext
  2048. )
  2049. {
  2050. NTSTATUS status;
  2051. PUX_TDI_OBJECT pTdiObject;
  2052. PUL_IRP_CONTEXT pIrpContext;
  2053. PIRP pIrp;
  2054. PMDL pMdl;
  2055. KIRQL oldIrql;
  2056. PUL_CONNECTION pConnection = (PUL_CONNECTION) pConnectionContext;
  2057. //
  2058. // Sanity check.
  2059. //
  2060. ASSERT( IS_VALID_CONNECTION( pConnection ) );
  2061. pTdiObject = &pConnection->ConnectionObject;
  2062. ASSERT( IS_VALID_TDI_OBJECT( pTdiObject ) );
  2063. ASSERT( pCompletionRoutine != NULL );
  2064. UlTrace(TDI, (
  2065. "UlpReceiveRawData: connection %p, buffer %p, length %lu\n",
  2066. pConnection,
  2067. pBuffer,
  2068. BufferLength
  2069. ));
  2070. //
  2071. // Setup locals so we know how to cleanup on failure.
  2072. //
  2073. pIrpContext = NULL;
  2074. pIrp = NULL;
  2075. pMdl = NULL;
  2076. //
  2077. // Create & initialize a receive IRP.
  2078. //
  2079. pIrp = UlAllocateIrp(
  2080. pTdiObject->pDeviceObject->StackSize, // StackSize
  2081. FALSE // ChargeQuota
  2082. );
  2083. if (pIrp != NULL)
  2084. {
  2085. //
  2086. // Snag an IRP context.
  2087. //
  2088. pIrpContext = UlPplAllocateIrpContext();
  2089. if (pIrpContext != NULL)
  2090. {
  2091. ASSERT( IS_VALID_IRP_CONTEXT( pIrpContext ) );
  2092. pIrpContext->pConnectionContext = (PVOID)pConnection;
  2093. pIrpContext->pCompletionRoutine = pCompletionRoutine;
  2094. pIrpContext->pCompletionContext = pCompletionContext;
  2095. pIrpContext->pOwnIrp = NULL;
  2096. //
  2097. // Create an MDL describing the client's buffer.
  2098. //
  2099. pMdl = UlAllocateMdl(
  2100. pBuffer, // VirtualAddress
  2101. BufferLength, // Length
  2102. FALSE, // SecondaryBuffer
  2103. FALSE, // ChargeQuota
  2104. NULL // Irp
  2105. );
  2106. if (pMdl != NULL)
  2107. {
  2108. //
  2109. // Adjust the MDL for our non-paged buffer.
  2110. //
  2111. MmBuildMdlForNonPagedPool( pMdl );
  2112. //
  2113. // Reference the connection, finish building the IRP.
  2114. //
  2115. REFERENCE_CONNECTION( pConnection );
  2116. TdiBuildReceive(
  2117. pIrp, // Irp
  2118. pTdiObject->pDeviceObject, // DeviceObject
  2119. pTdiObject->pFileObject, // FileObject
  2120. &UlpRestartClientReceive, // CompletionRoutine
  2121. pIrpContext, // CompletionContext
  2122. pMdl, // Mdl
  2123. TDI_RECEIVE_NORMAL, // Flags
  2124. BufferLength // Length
  2125. );
  2126. UlTrace(TDI, (
  2127. "UlpReceiveRawData: allocated irp %p for connection %p\n",
  2128. pIrp,
  2129. pConnection
  2130. ));
  2131. //
  2132. // Let the transport do the rest.
  2133. //
  2134. UlCallDriver( pTdiObject->pDeviceObject, pIrp );
  2135. return STATUS_PENDING;
  2136. }
  2137. }
  2138. }
  2139. //
  2140. // We only make it this point if we hit an allocation failure.
  2141. //
  2142. if (pMdl != NULL)
  2143. {
  2144. UlFreeMdl( pMdl );
  2145. }
  2146. if (pIrpContext != NULL)
  2147. {
  2148. UlPplFreeIrpContext( pIrpContext );
  2149. }
  2150. if (pIrp != NULL)
  2151. {
  2152. UlFreeIrp( pIrp );
  2153. }
  2154. status = UlInvokeCompletionRoutine(
  2155. STATUS_INSUFFICIENT_RESOURCES,
  2156. 0,
  2157. pCompletionRoutine,
  2158. pCompletionContext
  2159. );
  2160. return status;
  2161. } // UlpReceiveRawData
  2162. /***************************************************************************++
  2163. Routine Description:
  2164. A Dummy handler that is called by the filter code. This just calls
  2165. back into UlHttpReceive.
  2166. Arguments:
  2167. Return Value:
  2168. NTSTATUS - Completion status.
  2169. --***************************************************************************/
  2170. NTSTATUS
  2171. UlpDummyReceiveHandler(
  2172. IN PVOID pTdiEventContext,
  2173. IN PVOID ConnectionContext,
  2174. IN PVOID pTsdu,
  2175. IN ULONG BytesIndicated,
  2176. IN ULONG BytesUnreceived,
  2177. OUT ULONG *pBytesTaken
  2178. )
  2179. {
  2180. PUL_ENDPOINT pEndpoint;
  2181. PUL_CONNECTION pConnection;
  2182. //
  2183. // Sanity check.
  2184. //
  2185. ASSERT(pTdiEventContext == NULL);
  2186. ASSERT(BytesUnreceived == 0);
  2187. pConnection = (PUL_CONNECTION)ConnectionContext;
  2188. ASSERT( IS_VALID_CONNECTION( pConnection ) );
  2189. pEndpoint = pConnection->pOwningEndpoint;
  2190. ASSERT( IS_VALID_ENDPOINT( pEndpoint ) );
  2191. return (pEndpoint->pDataReceiveHandler)(
  2192. pEndpoint->pListeningContext,
  2193. pConnection->pConnectionContext,
  2194. pTsdu,
  2195. BytesIndicated,
  2196. BytesUnreceived,
  2197. pBytesTaken
  2198. );
  2199. } // UlpDummyReceiveHandler
  2200. /***************************************************************************++
  2201. Routine Description:
  2202. Handler for normal receive data.
  2203. Arguments:
  2204. pTdiEventContext - Supplies the context associated with the address
  2205. object. This should be a PUL_ENDPOINT.
  2206. ConnectionContext - Supplies the context associated with the
  2207. connection object. This should be a PUL_CONNECTION.
  2208. ReceiveFlags - Supplies the receive flags. This will be zero or more
  2209. TDI_RECEIVE_* flags.
  2210. BytesIndicated - Supplies the number of bytes indicated in pTsdu.
  2211. BytesAvailable - Supplies the number of bytes available in this
  2212. TSDU.
  2213. pBytesTaken - Receives the number of bytes consumed by this handler.
  2214. pTsdu - Supplies a pointer to the indicated data.
  2215. pIrp - Receives an IRP if the handler needs more data than indicated.
  2216. Return Value:
  2217. NTSTATUS - Completion status.
  2218. --***************************************************************************/
  2219. NTSTATUS
  2220. UlpReceiveHandler(
  2221. IN PVOID pTdiEventContext,
  2222. IN CONNECTION_CONTEXT ConnectionContext,
  2223. IN ULONG ReceiveFlags,
  2224. IN ULONG BytesIndicated,
  2225. IN ULONG BytesAvailable,
  2226. OUT ULONG *pBytesTaken,
  2227. IN PVOID pTsdu,
  2228. OUT PIRP *pIrp
  2229. )
  2230. {
  2231. NTSTATUS status;
  2232. PUL_ENDPOINT pEndpoint;
  2233. PUL_CONNECTION pConnection;
  2234. PUX_TDI_OBJECT pTdiObject;
  2235. UL_CONNECTION_FLAGS ConnectionFlags;
  2236. UL_ENTER_DRIVER("UlpReceiveHandler", NULL);
  2237. //
  2238. // Sanity check.
  2239. //
  2240. pEndpoint = (PUL_ENDPOINT)pTdiEventContext;
  2241. ASSERT( IS_VALID_ENDPOINT( pEndpoint ) );
  2242. pConnection = (PUL_CONNECTION)ConnectionContext;
  2243. ASSERT( IS_VALID_CONNECTION( pConnection ) );
  2244. ASSERT( pConnection->pOwningEndpoint == pEndpoint );
  2245. pTdiObject = &pConnection->ConnectionObject;
  2246. ASSERT( IS_VALID_TDI_OBJECT( pTdiObject ) );
  2247. UlTrace(TDI, (
  2248. "UlpReceiveHandler: endpoint %p, connection %p, length %lu,%lu\n",
  2249. pTdiEventContext,
  2250. (PVOID)ConnectionContext,
  2251. BytesIndicated,
  2252. BytesAvailable
  2253. ));
  2254. //
  2255. // Clear the bytes taken output var
  2256. //
  2257. *pBytesTaken = 0;
  2258. //
  2259. // Wait for the local address to be set just in case the receive happens
  2260. // before accept. This is possible (but rare) on MP machines even when
  2261. // using TDI_ACCEPT. We set the ReceivePending flag and reject
  2262. // the data if this ever happens. When accept is completed, we will build
  2263. // a receive IRP to flush the data if ReceivePending is set.
  2264. //
  2265. ConnectionFlags.Value = *((volatile LONG *)&pConnection->ConnectionFlags.Value);
  2266. if (0 == ConnectionFlags.LocalAddressValid)
  2267. {
  2268. pConnection->ConnectionFlags.ReceivePending = 1;
  2269. status = STATUS_DATA_NOT_ACCEPTED;
  2270. goto end;
  2271. }
  2272. //
  2273. // Give the client a crack at the data.
  2274. //
  2275. if (pConnection->FilterInfo.pFilterChannel)
  2276. {
  2277. //
  2278. // Needs to go through a filter.
  2279. //
  2280. status = UlFilterReceiveHandler(
  2281. &pConnection->FilterInfo,
  2282. pTsdu,
  2283. BytesIndicated,
  2284. BytesAvailable - BytesIndicated,
  2285. pBytesTaken
  2286. );
  2287. }
  2288. else
  2289. {
  2290. //
  2291. // Go directly to client.
  2292. //
  2293. status = (pEndpoint->pDataReceiveHandler)(
  2294. pEndpoint->pListeningContext,
  2295. pConnection->pConnectionContext,
  2296. pTsdu,
  2297. BytesIndicated,
  2298. BytesAvailable - BytesIndicated,
  2299. pBytesTaken
  2300. );
  2301. }
  2302. ASSERT( *pBytesTaken <= BytesIndicated );
  2303. if (status == STATUS_SUCCESS)
  2304. {
  2305. goto end;
  2306. }
  2307. else if (status == STATUS_MORE_PROCESSING_REQUIRED)
  2308. {
  2309. ASSERT(!"How could this ever happen?");
  2310. //
  2311. // The client consumed part of the indicated data.
  2312. //
  2313. // A subsequent receive indication will be made to the client when
  2314. // additional data is available. This subsequent indication will
  2315. // include the unconsumed data from the current indication plus
  2316. // any additional data received.
  2317. //
  2318. // We need to allocate a receive buffer so we can pass an IRP back
  2319. // to the transport.
  2320. //
  2321. status = UlpBuildTdiReceiveBuffer(pTdiObject, pConnection, pIrp);
  2322. if (status == STATUS_MORE_PROCESSING_REQUIRED)
  2323. {
  2324. //
  2325. // Make the next stack location current. Normally, UlCallDriver
  2326. // would do this for us, but since we're bypassing UlCallDriver,
  2327. // we must do it ourselves.
  2328. //
  2329. IoSetNextIrpStackLocation( *pIrp );
  2330. goto end;
  2331. }
  2332. }
  2333. //
  2334. // If we made it this far, then we've hit a fatal condition. Either the
  2335. // client returned a status code other than STATUS_SUCCESS or
  2336. // STATUS_MORE_PROCESSING_REQUIRED, or we failed to allocation the
  2337. // receive IRP to pass back to the transport. In either case, we need
  2338. // to abort the connection.
  2339. //
  2340. UlpCloseRawConnection(
  2341. pConnection,
  2342. TRUE, // AbortiveDisconnect
  2343. NULL, // pCompletionRoutine
  2344. NULL // pCompletionContext
  2345. );
  2346. end:
  2347. UlTrace(TDI, (
  2348. "UlpReceiveHandler: endpoint %p, connection %p, length %lu,%lu, taken %lu, status %x\n",
  2349. pTdiEventContext,
  2350. (PVOID)ConnectionContext,
  2351. BytesIndicated,
  2352. BytesAvailable,
  2353. *pBytesTaken,
  2354. status
  2355. ));
  2356. UL_LEAVE_DRIVER("UlpReceiveHandler");
  2357. return status;
  2358. } // UlpReceiveHandler
  2359. /***************************************************************************++
  2360. Routine Description:
  2361. Handler for expedited receive data.
  2362. Arguments:
  2363. pTdiEventContext - Supplies the context associated with the address
  2364. object. This should be a PUL_ENDPOINT.
  2365. ConnectionContext - Supplies the context associated with the
  2366. connection object. This should be a PUL_CONNECTION.
  2367. ReceiveFlags - Supplies the receive flags. This will be zero or more
  2368. TDI_RECEIVE_* flags.
  2369. BytesIndiated - Supplies the number of bytes indicated in pTsdu.
  2370. BytesAvailable - Supplies the number of bytes available in this
  2371. TSDU.
  2372. pBytesTaken - Receives the number of bytes consumed by this handler.
  2373. pTsdu - Supplies a pointer to the indicated data.
  2374. pIrp - Receives an IRP if the handler needs more data than indicated.
  2375. Return Value:
  2376. NTSTATUS - Completion status.
  2377. --***************************************************************************/
  2378. NTSTATUS
  2379. UlpReceiveExpeditedHandler(
  2380. IN PVOID pTdiEventContext,
  2381. IN CONNECTION_CONTEXT ConnectionContext,
  2382. IN ULONG ReceiveFlags,
  2383. IN ULONG BytesIndicated,
  2384. IN ULONG BytesAvailable,
  2385. OUT ULONG *pBytesTaken,
  2386. IN PVOID pTsdu,
  2387. OUT PIRP *pIrp
  2388. )
  2389. {
  2390. PUL_ENDPOINT pEndpoint;
  2391. PUL_CONNECTION pConnection;
  2392. PUX_TDI_OBJECT pTdiObject;
  2393. UL_ENTER_DRIVER("UlpReceiveExpeditedHandler", NULL);
  2394. //
  2395. // Sanity check.
  2396. //
  2397. pEndpoint = (PUL_ENDPOINT)pTdiEventContext;
  2398. ASSERT( IS_VALID_ENDPOINT( pEndpoint ) );
  2399. pConnection = (PUL_CONNECTION)ConnectionContext;
  2400. ASSERT( IS_VALID_CONNECTION( pConnection ) );
  2401. ASSERT( pConnection->pOwningEndpoint == pEndpoint );
  2402. pTdiObject = &pConnection->ConnectionObject;
  2403. ASSERT( IS_VALID_TDI_OBJECT( pTdiObject ) );
  2404. UlTrace(TDI, (
  2405. "UlpReceiveExpeditedHandler: endpoint %p, connection %p, length %lu,%lu\n",
  2406. pTdiEventContext,
  2407. (PVOID)ConnectionContext,
  2408. BytesIndicated,
  2409. BytesAvailable
  2410. ));
  2411. //
  2412. // We don't support expedited data, so just consume it all.
  2413. //
  2414. *pBytesTaken = BytesAvailable;
  2415. UL_LEAVE_DRIVER("UlpReceiveExpeditedHandler");
  2416. return STATUS_SUCCESS;
  2417. } // UlpReceiveExpeditedHandler
  2418. /***************************************************************************++
  2419. Routine Description:
  2420. Completion handler for accept IRPs.
  2421. Arguments:
  2422. pDeviceObject - Supplies the device object for the IRP being
  2423. completed.
  2424. pIrp - Supplies the IRP being completed.
  2425. pContext - Supplies the context associated with this request.
  2426. This is actually a PUL_CONNECTION.
  2427. Return Value:
  2428. NTSTATUS - STATUS_SUCCESS if IO should continue processing this
  2429. IRP, STATUS_MORE_PROCESSING_REQUIRED if IO should stop processing
  2430. this IRP.
  2431. --***************************************************************************/
  2432. NTSTATUS
  2433. UlpRestartAccept(
  2434. IN PDEVICE_OBJECT pDeviceObject,
  2435. IN PIRP pIrp,
  2436. IN PVOID pContext
  2437. )
  2438. {
  2439. PUL_CONNECTION pConnection;
  2440. PUL_ENDPOINT pEndpoint;
  2441. BOOLEAN needDisconnect;
  2442. NTSTATUS queryStatus;
  2443. NTSTATUS irpStatus;
  2444. UL_CONNECTION_FLAGS newFlags;
  2445. PTA_IP_ADDRESS pIpAddress;
  2446. //
  2447. // Sanity check.
  2448. //
  2449. pConnection = (PUL_CONNECTION)pContext;
  2450. ASSERT( IS_VALID_CONNECTION( pConnection ) );
  2451. ASSERT( pConnection->ConnectionFlags.AcceptPending );
  2452. pEndpoint = pConnection->pOwningEndpoint;
  2453. ASSERT( IS_VALID_ENDPOINT( pEndpoint ) );
  2454. UlTrace(TDI, (
  2455. "UlpRestartAccept: irp %p, endpoint %p, connection %p, status %08lx\n",
  2456. pIrp,
  2457. pEndpoint,
  2458. pConnection,
  2459. pIrp->IoStatus.Status
  2460. ));
  2461. //
  2462. // Assume for now that we don't need to issue a disconnect.
  2463. //
  2464. needDisconnect = FALSE;
  2465. //
  2466. // Capture the status from the IRP then free it.
  2467. //
  2468. irpStatus = pIrp->IoStatus.Status;
  2469. //
  2470. // If the connection was fully accepted (successfully), then
  2471. // move it to the endpoint's active list.
  2472. //
  2473. if (NT_SUCCESS(irpStatus))
  2474. {
  2475. UlpEnqueueActiveConnection( pConnection );
  2476. //
  2477. // Get the Local Address Info
  2478. //
  2479. pIpAddress = &(pConnection->IpAddress);
  2480. if (TDI_ADDRESS_TYPE_IP == pIpAddress->Address[0].AddressType)
  2481. {
  2482. if (pIpAddress->Address[0].AddressLength >= TDI_ADDRESS_LENGTH_IP)
  2483. {
  2484. pConnection->LocalAddress = SWAP_LONG(pIpAddress->Address[0].Address[0].in_addr);
  2485. pConnection->LocalPort = SWAP_SHORT(pIpAddress->Address[0].Address[0].sin_port);
  2486. pConnection->ConnectionFlags.LocalAddressValid = TRUE;
  2487. }
  2488. }
  2489. else
  2490. {
  2491. // Sabama: Add support for IP6 here
  2492. }
  2493. //
  2494. // Set the AcceptComplete flag. If an abort or disconnect has
  2495. // already been indicated, then remember this fact so we can
  2496. // fake a call to the client's connection disconnect handler
  2497. // after we invoke the connection complete handler.
  2498. //
  2499. newFlags.Value =
  2500. *((volatile LONG *)&pConnection->ConnectionFlags.Value);
  2501. if (newFlags.AbortIndicated || newFlags.DisconnectIndicated)
  2502. {
  2503. needDisconnect = TRUE;
  2504. }
  2505. if (needDisconnect == FALSE && newFlags.ReceivePending)
  2506. {
  2507. PIRP pReceiveIrp;
  2508. NTSTATUS status;
  2509. //
  2510. // We may have pending receives that we rejected early on
  2511. // inside the receive handler. Build an IRP to flush the
  2512. // data now.
  2513. //
  2514. status = UlpBuildTdiReceiveBuffer(
  2515. &pConnection->ConnectionObject,
  2516. pConnection,
  2517. &pReceiveIrp
  2518. );
  2519. if (status != STATUS_MORE_PROCESSING_REQUIRED)
  2520. {
  2521. needDisconnect = TRUE;
  2522. }
  2523. else
  2524. {
  2525. UlCallDriver(
  2526. pConnection->ConnectionObject.pDeviceObject,
  2527. pReceiveIrp
  2528. );
  2529. }
  2530. }
  2531. }
  2532. //
  2533. // Tell the client that the connection is complete. If necessary, also
  2534. // tell them that the connection has been disconnected.
  2535. //
  2536. (pEndpoint->pConnectionCompleteHandler)(
  2537. pEndpoint->pListeningContext,
  2538. pConnection->pConnectionContext,
  2539. irpStatus
  2540. );
  2541. if (needDisconnect)
  2542. {
  2543. //
  2544. // Silently close the connection. No need to go httprcv
  2545. // disconnect handler. It's just going to callback us anyway.
  2546. //
  2547. UlpCloseRawConnection( pConnection,
  2548. FALSE,
  2549. NULL,
  2550. NULL
  2551. );
  2552. }
  2553. //
  2554. // If the accept failed, then mark the connection so we know there is
  2555. // no longer an accept pending, enqueue the connection back onto the
  2556. // endpoint's idle list, and then remove the endpoint reference added
  2557. // in the connect handler,
  2558. //
  2559. if (!NT_SUCCESS(irpStatus))
  2560. {
  2561. pConnection->ConnectionFlags.AcceptPending = FALSE;
  2562. //
  2563. // Need to get rid of our opaque id if we're a filtered connection.
  2564. //
  2565. UL_CALL_PASSIVE(
  2566. &pConnection->WorkItem,
  2567. &UlpCleanupEarlyConnection
  2568. );
  2569. }
  2570. else
  2571. {
  2572. //
  2573. // Mark we are done with the accept. And try to disconnect
  2574. // if necessary.
  2575. //
  2576. newFlags = UlpSetConnectionFlag(
  2577. pConnection,
  2578. MakeAcceptCompleteFlag()
  2579. );
  2580. if (needDisconnect)
  2581. {
  2582. //
  2583. // We now may be able to remove the final reference since
  2584. // we have now set the AcceptComplete flag.
  2585. //
  2586. UlpRemoveFinalReference(pConnection, newFlags);
  2587. }
  2588. //
  2589. // Drop the reference added in UlpConnectHandler.
  2590. //
  2591. DEREFERENCE_CONNECTION( pConnection );
  2592. }
  2593. return STATUS_MORE_PROCESSING_REQUIRED;
  2594. } // UlpRestartAccept
  2595. /***************************************************************************++
  2596. Routine Description:
  2597. Completion handler for send IRPs.
  2598. Arguments:
  2599. pDeviceObject - Supplies the device object for the IRP being
  2600. completed.
  2601. pIrp - Supplies the IRP being completed.
  2602. pContext - Supplies the context associated with this request.
  2603. This is actually a PUL_IRP_CONTEXT.
  2604. Return Value:
  2605. NTSTATUS - STATUS_SUCCESS if IO should continue processing this
  2606. IRP, STATUS_MORE_PROCESSING_REQUIRED if IO should stop processing
  2607. this IRP.
  2608. --***************************************************************************/
  2609. NTSTATUS
  2610. UlpRestartSendData(
  2611. IN PDEVICE_OBJECT pDeviceObject,
  2612. IN PIRP pIrp,
  2613. IN PVOID pContext
  2614. )
  2615. {
  2616. PIO_STACK_LOCATION pIrpSp;
  2617. PUL_CONNECTION pConnection;
  2618. PUL_IRP_CONTEXT pIrpContext;
  2619. BOOLEAN OwnIrpContext;
  2620. //
  2621. // Sanity check.
  2622. //
  2623. pIrpContext = (PUL_IRP_CONTEXT)pContext;
  2624. OwnIrpContext = (pIrpContext->pOwnIrp != NULL);
  2625. ASSERT( IS_VALID_IRP_CONTEXT( pIrpContext ) );
  2626. ASSERT( pIrpContext->pCompletionRoutine != NULL );
  2627. pConnection = (PUL_CONNECTION)pIrpContext->pConnectionContext;
  2628. ASSERT( IS_VALID_CONNECTION( pConnection ) );
  2629. ASSERT( IS_VALID_ENDPOINT( pConnection->pOwningEndpoint ) );
  2630. UlTrace(TDI, (
  2631. "UlpRestartSendData: irp %p, connection %p, status %08lx, info %lx\n",
  2632. pIrp,
  2633. pConnection,
  2634. pIrp->IoStatus.Status,
  2635. (ULONG)pIrp->IoStatus.Information
  2636. ));
  2637. WRITE_REF_TRACE_LOG(
  2638. g_pMdlTraceLog,
  2639. REF_ACTION_SEND_MDL_COMPLETE,
  2640. PtrToLong(pIrp->MdlAddress->Next), // bugbug64
  2641. pIrp->MdlAddress,
  2642. __FILE__,
  2643. __LINE__
  2644. );
  2645. #ifdef SPECIAL_MDL_FLAG
  2646. {
  2647. PMDL scan = pIrp->MdlAddress;
  2648. while (scan != NULL)
  2649. {
  2650. ASSERT( (scan->MdlFlags & SPECIAL_MDL_FLAG) != 0 );
  2651. scan->MdlFlags &= ~SPECIAL_MDL_FLAG;
  2652. scan = scan->Next;
  2653. }
  2654. }
  2655. #endif
  2656. //
  2657. // Tell the client that the send is complete.
  2658. //
  2659. (pIrpContext->pCompletionRoutine)(
  2660. pIrpContext->pCompletionContext,
  2661. pIrp->IoStatus.Status,
  2662. pIrp->IoStatus.Information
  2663. );
  2664. //
  2665. // Remove the reference we added in UlSendData().
  2666. //
  2667. DEREFERENCE_CONNECTION( pConnection );
  2668. //
  2669. // Free the context & the IRP since we're done with them, then
  2670. // tell IO to stop processing the IRP.
  2671. //
  2672. if (OwnIrpContext == FALSE)
  2673. {
  2674. UlFreeIrp( pIrp );
  2675. UlPplFreeIrpContext( pIrpContext );
  2676. }
  2677. return STATUS_MORE_PROCESSING_REQUIRED;
  2678. } // UlpRestartSendData
  2679. /***************************************************************************++
  2680. Routine Description:
  2681. Increments the reference count on the specified endpoint.
  2682. Arguments:
  2683. pEndpoint - Supplies the endpoint to reference.
  2684. pFileName (REFERENCE_DEBUG only) - Supplies the name of the file
  2685. containing the calling function.
  2686. LineNumber (REFERENCE_DEBUG only) - Supplies the line number of
  2687. the calling function.
  2688. --***************************************************************************/
  2689. VOID
  2690. UlpReferenceEndpoint(
  2691. IN PUL_ENDPOINT pEndpoint
  2692. OWNER_REFERENCE_DEBUG_FORMAL_PARAMS
  2693. )
  2694. {
  2695. LONG refCount;
  2696. //
  2697. // Sanity check.
  2698. //
  2699. ASSERT( IS_VALID_ENDPOINT( pEndpoint ) );
  2700. //
  2701. // Reference it.
  2702. //
  2703. refCount = InterlockedIncrement( &pEndpoint->ReferenceCount );
  2704. ASSERT( refCount > 0 );
  2705. WRITE_REF_TRACE_LOG(
  2706. g_pTdiTraceLog,
  2707. REF_ACTION_REFERENCE_ENDPOINT,
  2708. refCount,
  2709. pEndpoint,
  2710. pFileName,
  2711. LineNumber
  2712. );
  2713. WRITE_OWNER_REF_TRACE_LOG(
  2714. pEndpoint->pOwnerRefTraceLog,
  2715. pOwner,
  2716. ppRefOwner,
  2717. OwnerSignature,
  2718. Action,
  2719. refCount, // absolute refcount
  2720. MonotonicId,
  2721. +1, // increment relative refcount
  2722. pFileName,
  2723. LineNumber
  2724. );
  2725. UlTrace(TDI, (
  2726. "UlpReferenceEndpoint: endpoint %p, refcount %ld\n",
  2727. pEndpoint,
  2728. refCount
  2729. ));
  2730. } // UlpReferenceEndpoint
  2731. /***************************************************************************++
  2732. Routine Description:
  2733. Decrements the reference count on the specified endpoint.
  2734. Arguments:
  2735. pEndpoint - Supplies the endpoint to dereference.
  2736. pFileName (REFERENCE_DEBUG only) - Supplies the name of the file
  2737. containing the calling function.
  2738. LineNumber (REFERENCE_DEBUG only) - Supplies the line number of
  2739. the calling function.
  2740. --***************************************************************************/
  2741. VOID
  2742. UlpDereferenceEndpoint(
  2743. IN PUL_ENDPOINT pEndpoint
  2744. OWNER_REFERENCE_DEBUG_FORMAL_PARAMS
  2745. )
  2746. {
  2747. LONG refCount;
  2748. KIRQL oldIrql;
  2749. //
  2750. // Sanity check.
  2751. //
  2752. ASSERT( IS_VALID_ENDPOINT( pEndpoint ) );
  2753. //
  2754. // Dereference it.
  2755. //
  2756. refCount = InterlockedDecrement( &pEndpoint->ReferenceCount );
  2757. ASSERT( refCount >= 0 );
  2758. WRITE_REF_TRACE_LOG(
  2759. g_pTdiTraceLog,
  2760. REF_ACTION_DEREFERENCE_ENDPOINT,
  2761. refCount,
  2762. pEndpoint,
  2763. pFileName,
  2764. LineNumber
  2765. );
  2766. WRITE_OWNER_REF_TRACE_LOG(
  2767. pEndpoint->pOwnerRefTraceLog,
  2768. pOwner,
  2769. ppRefOwner,
  2770. OwnerSignature,
  2771. Action,
  2772. refCount, // absolute refcount
  2773. MonotonicId,
  2774. -1, // decrement relative refcount
  2775. pFileName,
  2776. LineNumber
  2777. );
  2778. UlTrace(TDI, (
  2779. "UlpDereferenceEndpoint: endpoint %p, refcount %ld\n",
  2780. pEndpoint,
  2781. refCount
  2782. ));
  2783. if (refCount == 0)
  2784. {
  2785. //
  2786. // The final reference to the endpoint has been removed, so
  2787. // it's time to destroy the endpoint. We'll remove the
  2788. // endpoint from the global list and move it to the deleted
  2789. // list (if necessary), release the TDI spinlock,
  2790. // then destroy the connection.
  2791. //
  2792. UlAcquireSpinLock( &g_TdiSpinLock, &oldIrql );
  2793. if (! pEndpoint->Deleted)
  2794. {
  2795. // If this routine was called by the `fatal' section of
  2796. // UlCreateListeningEndpoint, then the endpoint was never
  2797. // added to g_TdiEndpointListHead.
  2798. if (NULL != pEndpoint->GlobalEndpointListEntry.Flink)
  2799. RemoveEntryList( &pEndpoint->GlobalEndpointListEntry );
  2800. InsertTailList(
  2801. &g_TdiDeletedEndpointListHead,
  2802. &pEndpoint->GlobalEndpointListEntry
  2803. );
  2804. pEndpoint->Deleted = TRUE;
  2805. }
  2806. else
  2807. {
  2808. ASSERT(NULL != pEndpoint->GlobalEndpointListEntry.Flink);
  2809. }
  2810. UlReleaseSpinLock( &g_TdiSpinLock, oldIrql );
  2811. //
  2812. // The endpoint is going away. Do final cleanup & resource
  2813. // release at passive IRQL.
  2814. //
  2815. UL_CALL_PASSIVE(
  2816. &pEndpoint->WorkItem,
  2817. &UlpEndpointCleanupWorker
  2818. );
  2819. }
  2820. } // UlpDereferenceEndpoint
  2821. /***************************************************************************++
  2822. Routine Description:
  2823. Increments the reference count on the specified connection.
  2824. Arguments:
  2825. pConnection - Supplies the connection to reference.
  2826. pFileName (REFERENCE_DEBUG only) - Supplies the name of the file
  2827. containing the calling function.
  2828. LineNumber (REFERENCE_DEBUG only) - Supplies the line number of
  2829. the calling function.
  2830. --***************************************************************************/
  2831. VOID
  2832. UlReferenceConnection(
  2833. IN PVOID pObject
  2834. REFERENCE_DEBUG_FORMAL_PARAMS
  2835. )
  2836. {
  2837. PUL_ENDPOINT pEndpoint;
  2838. LONG refCount;
  2839. PUL_CONNECTION pConnection = (PUL_CONNECTION) pObject;
  2840. //
  2841. // Sanity check.
  2842. //
  2843. ASSERT( IS_VALID_CONNECTION( pConnection ) );
  2844. pEndpoint = pConnection->pOwningEndpoint;
  2845. ASSERT( IS_VALID_ENDPOINT( pEndpoint ) );
  2846. //
  2847. // Reference it.
  2848. //
  2849. refCount = InterlockedIncrement( &pConnection->ReferenceCount );
  2850. ASSERT( refCount > 1 );
  2851. WRITE_REF_TRACE_LOG2(
  2852. g_pTdiTraceLog,
  2853. pConnection->pTraceLog,
  2854. REF_ACTION_REFERENCE_CONNECTION,
  2855. refCount,
  2856. pConnection,
  2857. pFileName,
  2858. LineNumber
  2859. );
  2860. UlTrace(TDI, (
  2861. "UlReferenceConnection: connection %p, refcount %ld\n",
  2862. pConnection,
  2863. refCount
  2864. ));
  2865. } // UlReferenceConnection
  2866. /***************************************************************************++
  2867. Routine Description:
  2868. Decrements the reference count on the specified connection.
  2869. Arguments:
  2870. pConnection - Supplies the connection to dereference.
  2871. pFileName (REFERENCE_DEBUG only) - Supplies the name of the file
  2872. containing the calling function.
  2873. LineNumber (REFERENCE_DEBUG only) - Supplies the line number of
  2874. the calling function.
  2875. --***************************************************************************/
  2876. VOID
  2877. UlDereferenceConnection(
  2878. IN PVOID pObject
  2879. REFERENCE_DEBUG_FORMAL_PARAMS
  2880. )
  2881. {
  2882. PUL_ENDPOINT pEndpoint;
  2883. LONG refCount;
  2884. PUL_CONNECTION pConnection = (PUL_CONNECTION) pObject;
  2885. //
  2886. // Sanity check.
  2887. //
  2888. ASSERT( IS_VALID_CONNECTION( pConnection ) );
  2889. pEndpoint = pConnection->pOwningEndpoint;
  2890. ASSERT( IS_VALID_ENDPOINT( pEndpoint ) );
  2891. //
  2892. // Dereference it.
  2893. //
  2894. refCount = InterlockedDecrement( &pConnection->ReferenceCount );
  2895. ASSERT( refCount >= 0 );
  2896. WRITE_REF_TRACE_LOG2(
  2897. g_pTdiTraceLog,
  2898. pConnection->pTraceLog,
  2899. REF_ACTION_DEREFERENCE_CONNECTION,
  2900. refCount,
  2901. pConnection,
  2902. pFileName,
  2903. LineNumber
  2904. );
  2905. UlTrace(TDI, (
  2906. "UlDereferenceConnection: connection %p, refcount %ld\n",
  2907. pConnection,
  2908. refCount
  2909. ));
  2910. if (refCount == 0)
  2911. {
  2912. //
  2913. // The final reference to the connection has been removed, so
  2914. // it's time to destroy the connection. We'll release the
  2915. // endpoint spinlock, dereference the endpoint, then destroy
  2916. // the connection.
  2917. //
  2918. ASSERT(pConnection->ActiveListEntry.Flink == NULL);
  2919. //
  2920. // Do final cleanup & resource release at passive IRQL. Also
  2921. // cleanupworker requires to be running under system process.
  2922. //
  2923. UL_QUEUE_WORK_ITEM(
  2924. &pConnection->WorkItem,
  2925. &UlpConnectionCleanupWorker
  2926. );
  2927. }
  2928. } // UlDereferenceConnection
  2929. /***************************************************************************++
  2930. Routine Description:
  2931. Deferred cleanup routine for dead endpoints.
  2932. Arguments:
  2933. pWorkItem - Supplies a pointer to the work item queued. This should
  2934. point to the WORK_ITEM structure embedded in a UL_ENDPOINT.
  2935. --***************************************************************************/
  2936. VOID
  2937. UlpEndpointCleanupWorker(
  2938. IN PUL_WORK_ITEM pWorkItem
  2939. )
  2940. {
  2941. PUL_ENDPOINT pEndpoint;
  2942. //
  2943. // Sanity check.
  2944. //
  2945. PAGED_CODE();
  2946. pEndpoint = CONTAINING_RECORD(
  2947. pWorkItem,
  2948. UL_ENDPOINT,
  2949. WorkItem
  2950. );
  2951. ASSERT( IS_VALID_ENDPOINT( pEndpoint ) );
  2952. //
  2953. // Nuke it.
  2954. //
  2955. UlpDestroyEndpoint( pEndpoint );
  2956. } // UlpEndpointCleanupWorker
  2957. /***************************************************************************++
  2958. Routine Description:
  2959. Removes the opaque id from a connection. This has to happen at passive
  2960. level because the opaque id table can't handle high IRQL.
  2961. Arguments:
  2962. pWorkItem - embedded in the connection object.
  2963. --***************************************************************************/
  2964. VOID
  2965. UlpCleanupConnectionId(
  2966. IN PUL_WORK_ITEM pWorkItem
  2967. )
  2968. {
  2969. KIRQL oldIrql;
  2970. PUL_CONNECTION pConnection;
  2971. HTTP_RAW_CONNECTION_ID ConnectionId;
  2972. //
  2973. // Sanity check.
  2974. //
  2975. ASSERT( KeGetCurrentIrql() == PASSIVE_LEVEL );
  2976. //
  2977. // Grab the connection.
  2978. //
  2979. pConnection = CONTAINING_RECORD(
  2980. pWorkItem,
  2981. UL_CONNECTION,
  2982. WorkItem
  2983. );
  2984. ASSERT( IS_VALID_CONNECTION(pConnection) );
  2985. //
  2986. // Pull the id off the connection.
  2987. //
  2988. UlAcquireSpinLock( &pConnection->FilterInfo.FilterConnLock, &oldIrql );
  2989. ConnectionId = pConnection->FilterInfo.ConnectionId;
  2990. HTTP_SET_NULL_ID( &pConnection->FilterInfo.ConnectionId );
  2991. UlReleaseSpinLock( &pConnection->FilterInfo.FilterConnLock, oldIrql );
  2992. //
  2993. // Actually get rid of it at low IRQL.
  2994. //
  2995. if (!HTTP_IS_NULL_ID( &ConnectionId ))
  2996. {
  2997. UlTrace(TDI, (
  2998. "UlpCleanupConnectionId: conn=%p id=%I64x\n",
  2999. pConnection, ConnectionId
  3000. ));
  3001. UlFreeOpaqueId(ConnectionId, UlOpaqueIdTypeRawConnection);
  3002. DEREFERENCE_CONNECTION(pConnection);
  3003. }
  3004. } // UlpCleanupConnectionId
  3005. /***************************************************************************++
  3006. Routine Description:
  3007. This function gets called if RestartAccept fails and we cannot establish
  3008. a connection on a secure endpoint, or if something goes wrong in
  3009. UlpConnectHandler.
  3010. The connections over secure endpoints keep an extra refcount to
  3011. the UL_CONNECTION because of their opaqueid. They normally
  3012. get removed after the CloseRawConnection happens but in the above case
  3013. close won't happen and we have to explicitly cleanup the id. This has
  3014. to happen at passive level because the opaque id table can't handle high
  3015. IRQL.
  3016. Arguments:
  3017. pWorkItem - embedded in the connection object.
  3018. --***************************************************************************/
  3019. VOID
  3020. UlpCleanupEarlyConnection(
  3021. IN PUL_WORK_ITEM pWorkItem
  3022. )
  3023. {
  3024. PUL_CONNECTION pConnection;
  3025. UL_CONNECTION_FLAGS Flags;
  3026. //
  3027. // Sanity check.
  3028. //
  3029. ASSERT( KeGetCurrentIrql() == PASSIVE_LEVEL );
  3030. //
  3031. // Grab the connection.
  3032. //
  3033. pConnection = CONTAINING_RECORD(
  3034. pWorkItem,
  3035. UL_CONNECTION,
  3036. WorkItem
  3037. );
  3038. ASSERT( IS_VALID_CONNECTION(pConnection) );
  3039. //
  3040. // If we are failing early we should never have been to
  3041. // FinalReferenceRemoved in the first place.
  3042. //
  3043. Flags.Value = *((volatile LONG *)&pConnection->ConnectionFlags.Value);
  3044. ASSERT( !Flags.FinalReferenceRemoved );
  3045. if (pConnection->FilterInfo.pFilterChannel)
  3046. {
  3047. //
  3048. // Cleanup opaque id. And release the final refcount
  3049. //
  3050. UlpCleanupConnectionId( pWorkItem );
  3051. }
  3052. //
  3053. // Drop the reference added in UlpConnectHandler.
  3054. //
  3055. DEREFERENCE_CONNECTION( pConnection );
  3056. //
  3057. // Remove the final reference.
  3058. //
  3059. DEREFERENCE_CONNECTION( pConnection );
  3060. } // UlpCleanupEarlyConnection
  3061. /***************************************************************************++
  3062. Routine Description:
  3063. Deferred cleanup routine for dead connections. We have to be queued as a
  3064. work item and should be running on the passive IRQL. See below comment.
  3065. Arguments:
  3066. pWorkItem - Supplies a pointer to the work item queued. This should
  3067. point to the WORK_ITEM structure embedded in a UL_CONNECTION.
  3068. --***************************************************************************/
  3069. VOID
  3070. UlpConnectionCleanupWorker(
  3071. IN PUL_WORK_ITEM pWorkItem
  3072. )
  3073. {
  3074. PUL_CONNECTION pConnection;
  3075. PUL_ENDPOINT pEndpoint;
  3076. NTSTATUS status;
  3077. //
  3078. // Sanity check.
  3079. //
  3080. PAGED_CODE();
  3081. //
  3082. // Initialize locals.
  3083. //
  3084. status = STATUS_SUCCESS;
  3085. pConnection = CONTAINING_RECORD(
  3086. pWorkItem,
  3087. UL_CONNECTION,
  3088. WorkItem
  3089. );
  3090. ASSERT( IS_VALID_CONNECTION( pConnection ) );
  3091. ASSERT( IS_VALID_ENDPOINT( pConnection->pOwningEndpoint ) );
  3092. ASSERT( pConnection->ReferenceCount == 0 );
  3093. ASSERT( pConnection->HttpConnection.RefCount == 0 );
  3094. //
  3095. // Grab the endpoint.
  3096. //
  3097. pEndpoint = pConnection->pOwningEndpoint;
  3098. //
  3099. // Get rid of any buffers we allocated for
  3100. // certificate information.
  3101. //
  3102. if (pConnection->FilterInfo.SslInfo.pServerCertData)
  3103. {
  3104. UL_FREE_POOL(
  3105. pConnection->FilterInfo.SslInfo.pServerCertData,
  3106. UL_SSL_CERT_DATA_POOL_TAG
  3107. );
  3108. pConnection->FilterInfo.SslInfo.pServerCertData = NULL;
  3109. }
  3110. if (pConnection->FilterInfo.SslInfo.pCertEncoded)
  3111. {
  3112. UL_FREE_POOL(
  3113. pConnection->FilterInfo.SslInfo.pCertEncoded,
  3114. UL_SSL_CERT_DATA_POOL_TAG
  3115. );
  3116. pConnection->FilterInfo.SslInfo.pCertEncoded = NULL;
  3117. }
  3118. if (pConnection->FilterInfo.SslInfo.Token)
  3119. {
  3120. HANDLE Token;
  3121. Token = (HANDLE) pConnection->FilterInfo.SslInfo.Token;
  3122. //
  3123. // If we are not running under the system process. And if the
  3124. // thread we are running under has some APCs queued currently
  3125. // KeAttachProcess won't allow us to attach to another process
  3126. // and will bugcheck 5. We have to be queued as a work item and
  3127. // should be running on the passive IRQL.
  3128. //
  3129. ASSERT( PsGetCurrentProcess() == (PEPROCESS) g_pUlSystemProcess );
  3130. ZwClose(Token);
  3131. }
  3132. //
  3133. // Release the filter channel.
  3134. //
  3135. if (pConnection->FilterInfo.pFilterChannel)
  3136. {
  3137. DEREFERENCE_FILTER_CHANNEL(pConnection->FilterInfo.pFilterChannel);
  3138. pConnection->FilterInfo.pFilterChannel = NULL;
  3139. }
  3140. //
  3141. // Check if g_UlEnableConnectionReuse is enabled or we are about to
  3142. // exceed g_UlMaxIdleConnections.
  3143. //
  3144. if (ExQueryDepthSList(&pEndpoint->IdleConnectionSListHead) >=
  3145. g_UlMaxIdleConnections)
  3146. {
  3147. status = STATUS_ALLOTTED_SPACE_EXCEEDED;
  3148. }
  3149. if (g_UlEnableConnectionReuse == FALSE)
  3150. {
  3151. status = STATUS_NOT_SUPPORTED;
  3152. }
  3153. //
  3154. // If the connection is still ok and we're reusing
  3155. // connection objects, throw it back on the idle list.
  3156. //
  3157. if (NT_SUCCESS(status))
  3158. {
  3159. //
  3160. // Initialize the connection for reuse.
  3161. //
  3162. status = UlpInitializeConnection(pConnection);
  3163. if (NT_SUCCESS(status))
  3164. {
  3165. //
  3166. // Stick the connection back on the idle list.
  3167. //
  3168. UlpEnqueueIdleConnection(pConnection, FALSE);
  3169. }
  3170. }
  3171. //
  3172. // Active connections hold a reference to the ENDPOINT. Release
  3173. // that reference. See the comment on UlpCreateConnection.
  3174. //
  3175. DEREFERENCE_ENDPOINT_CONNECTION(
  3176. pEndpoint,
  3177. REF_ACTION_CONN_CLEANUP,
  3178. pConnection);
  3179. //
  3180. // If anything went amiss, blow away the connection.
  3181. //
  3182. if (!NT_SUCCESS(status))
  3183. {
  3184. UlpDestroyConnection( pConnection );
  3185. }
  3186. } // UlpConnectionCleanupWorker
  3187. /***************************************************************************++
  3188. Routine Description:
  3189. Associates the TDI connection object contained in the specified
  3190. connection to the TDI address object contained in the specified
  3191. endpoint.
  3192. Arguments:
  3193. pConnection - Supplies the connection to associate with the endpoint.
  3194. pEndpoint - Supplies the endpoint to associated with the connection.
  3195. Return Value:
  3196. NTSTATUS - Completion status.
  3197. --***************************************************************************/
  3198. NTSTATUS
  3199. UlpAssociateConnection(
  3200. IN PUL_CONNECTION pConnection,
  3201. IN PUL_ENDPOINT pEndpoint
  3202. )
  3203. {
  3204. NTSTATUS status;
  3205. IO_STATUS_BLOCK ioStatusBlock;
  3206. HANDLE handle;
  3207. TDI_REQUEST_USER_ASSOCIATE associateInfo;
  3208. //
  3209. // Sanity check.
  3210. //
  3211. PAGED_CODE();
  3212. ASSERT( IS_VALID_CONNECTION( pConnection ) );
  3213. ASSERT( IS_VALID_ENDPOINT( pEndpoint ) );
  3214. ASSERT( pConnection->pOwningEndpoint == NULL );
  3215. //
  3216. // Associate the connection with the address object.
  3217. //
  3218. associateInfo.AddressHandle = pEndpoint->AddressObject.Handle;
  3219. ASSERT( associateInfo.AddressHandle != NULL );
  3220. handle = pConnection->ConnectionObject.Handle;
  3221. ASSERT( handle != NULL );
  3222. UlAttachToSystemProcess();
  3223. status = ZwDeviceIoControlFile(
  3224. handle, // FileHandle
  3225. NULL, // Event
  3226. NULL, // ApcRoutine
  3227. NULL, // ApcContext
  3228. &ioStatusBlock, // IoStatusBlock
  3229. IOCTL_TDI_ASSOCIATE_ADDRESS, // IoControlCode
  3230. &associateInfo, // InputBuffer
  3231. sizeof(associateInfo), // InputBufferLength
  3232. NULL, // OutputBuffer
  3233. 0 // OutputBufferLength
  3234. );
  3235. if (status == STATUS_PENDING)
  3236. {
  3237. status = ZwWaitForSingleObject(
  3238. handle, // Handle
  3239. TRUE, // Alertable
  3240. NULL // Timeout
  3241. );
  3242. ASSERT( NT_SUCCESS(status) );
  3243. status = ioStatusBlock.Status;
  3244. }
  3245. UlDetachFromSystemProcess();
  3246. if (NT_SUCCESS(status))
  3247. {
  3248. pConnection->pOwningEndpoint = pEndpoint;
  3249. pConnection->pConnectionDestroyedHandler = pEndpoint->pConnectionDestroyedHandler;
  3250. pConnection->pListeningContext = pEndpoint->pListeningContext;
  3251. }
  3252. else
  3253. {
  3254. UlTrace(TDI, (
  3255. "UlpAssociateConnection conn=%p, endp=%p, status = %08lx\n",
  3256. pConnection,
  3257. pEndpoint,
  3258. status
  3259. ));
  3260. }
  3261. return status;
  3262. } // UlpAssociateConnection
  3263. /***************************************************************************++
  3264. Routine Description:
  3265. Disassociates the TDI connection object contained in the specified
  3266. connection from its TDI address object.
  3267. Arguments:
  3268. pConnection - Supplies the connection to disassociate.
  3269. Return Value:
  3270. NTSTATUS - Completion status.
  3271. --***************************************************************************/
  3272. NTSTATUS
  3273. UlpDisassociateConnection(
  3274. IN PUL_CONNECTION pConnection
  3275. )
  3276. {
  3277. NTSTATUS status;
  3278. IO_STATUS_BLOCK ioStatusBlock;
  3279. HANDLE handle;
  3280. //
  3281. // Sanity check.
  3282. //
  3283. PAGED_CODE();
  3284. ASSERT( IS_VALID_CONNECTION( pConnection ) );
  3285. ASSERT( IS_VALID_ENDPOINT( pConnection->pOwningEndpoint ) );
  3286. //
  3287. // Disassociate the connection from the address object.
  3288. //
  3289. handle = pConnection->ConnectionObject.Handle;
  3290. UlAttachToSystemProcess();
  3291. status = ZwDeviceIoControlFile(
  3292. handle, // FileHandle
  3293. NULL, // Event
  3294. NULL, // ApcRoutine
  3295. NULL, // ApcContext
  3296. &ioStatusBlock, // IoStatusBlock
  3297. IOCTL_TDI_DISASSOCIATE_ADDRESS, // IoControlCode
  3298. NULL, // InputBuffer
  3299. 0, // InputBufferLength
  3300. NULL, // OutputBuffer
  3301. 0 // OutputBufferLength
  3302. );
  3303. if (status == STATUS_PENDING)
  3304. {
  3305. status = ZwWaitForSingleObject(
  3306. handle, // Handle
  3307. TRUE, // Alertable
  3308. NULL // Timeout
  3309. );
  3310. ASSERT( NT_SUCCESS(status) );
  3311. status = ioStatusBlock.Status;
  3312. }
  3313. UlDetachFromSystemProcess();
  3314. //
  3315. // Proceed with the disassociate even if the IOCTL failed.
  3316. //
  3317. pConnection->pOwningEndpoint = NULL;
  3318. return status;
  3319. } // UlpDisassociateConnection
  3320. /***************************************************************************++
  3321. Routine Description:
  3322. Replenishes the idle connection pool in the specified endpoint.
  3323. Arguments:
  3324. pEndpoint - Supplies the endpoint to replenish.
  3325. --***************************************************************************/
  3326. VOID
  3327. UlpReplenishEndpoint(
  3328. IN PUL_ENDPOINT pEndpoint
  3329. )
  3330. {
  3331. NTSTATUS status;
  3332. PUL_CONNECTION pConnection;
  3333. BOOLEAN ContinueReplenish;
  3334. //
  3335. // Sanity check.
  3336. //
  3337. PAGED_CODE();
  3338. ASSERT( IS_VALID_ENDPOINT( pEndpoint ) );
  3339. UlTrace(TDI, (
  3340. "UlpReplenishEndpoint: endpoint %p\n",
  3341. pEndpoint
  3342. ));
  3343. TRACE_REPLENISH(
  3344. pEndpoint,
  3345. DummySynch,
  3346. pEndpoint->EndpointSynch,
  3347. REPLENISH_ACTION_START_REPLENISH
  3348. );
  3349. //
  3350. // Loop, creating connections until we're fully replenished.
  3351. //
  3352. do
  3353. {
  3354. //
  3355. // Create a new connection.
  3356. //
  3357. status = UlpCreateConnection(
  3358. pEndpoint, // pEndpoint
  3359. pEndpoint->LocalAddressLength, // AddressLength
  3360. &pConnection // ppConnection
  3361. );
  3362. if (!NT_SUCCESS(status))
  3363. {
  3364. break;
  3365. }
  3366. status = UlpInitializeConnection(
  3367. pConnection
  3368. );
  3369. if (!NT_SUCCESS(status))
  3370. {
  3371. UlpDestroyConnection(pConnection);
  3372. break;
  3373. }
  3374. //
  3375. // Enqueue the connection onto the endpoint.
  3376. //
  3377. ContinueReplenish = UlpEnqueueIdleConnection( pConnection, TRUE );
  3378. } while (ContinueReplenish);
  3379. TRACE_REPLENISH(
  3380. pEndpoint,
  3381. DummySynch,
  3382. pEndpoint->EndpointSynch,
  3383. REPLENISH_ACTION_END_REPLENISH
  3384. );
  3385. //
  3386. // We are done with creating new connections for now. Clear
  3387. // the "replenish scheduled" flag so future replenish attempts
  3388. // will queue the work.
  3389. //
  3390. UlpClearReplenishScheduledFlag( pEndpoint );
  3391. } // UlpReplenishEndpoint
  3392. /***************************************************************************++
  3393. Routine Description:
  3394. Deferred endpoint replenish routine.
  3395. Arguments:
  3396. pWorkItem - Supplies a pointer to the work item queued. This should
  3397. point to the WORK_ITEM structure embedded in a UL_ENDPOINT.
  3398. --***************************************************************************/
  3399. VOID
  3400. UlpReplenishEndpointWorker(
  3401. IN PUL_WORK_ITEM pWorkItem
  3402. )
  3403. {
  3404. PUL_ENDPOINT pEndpoint;
  3405. //
  3406. // Sanity check.
  3407. //
  3408. PAGED_CODE();
  3409. pEndpoint = CONTAINING_RECORD(
  3410. pWorkItem,
  3411. UL_ENDPOINT,
  3412. WorkItem
  3413. );
  3414. UlTrace(TDI, (
  3415. "UlpReplenishEndpointWorker: endpoint %p\n",
  3416. pEndpoint
  3417. ));
  3418. ASSERT( IS_VALID_ENDPOINT( pEndpoint ) );
  3419. //
  3420. // Let UlpReplenishEndpoint() do the dirty work.
  3421. //
  3422. UlpReplenishEndpoint( pEndpoint );
  3423. //
  3424. // Remove the reference that UlpDequeueIdleConnection added for
  3425. // this call.
  3426. //
  3427. DEREFERENCE_ENDPOINT_SELF(pEndpoint, REF_ACTION_REPLENISH);
  3428. } // UlpReplenishEndpointWorker
  3429. /***************************************************************************++
  3430. Routine Description:
  3431. Decrements the number of idle connections availabe on the specified
  3432. endpoint and determines if a replenish should be scheduled.
  3433. Arguments:
  3434. pEndpoint - Supplies the endpoint to increment.
  3435. Return Value:
  3436. BOOLEAN - TRUE if a replenish should be rescheduled, FALSE otherwise.
  3437. --***************************************************************************/
  3438. BOOLEAN
  3439. UlpDecrementIdleConnections(
  3440. IN PUL_ENDPOINT pEndpoint
  3441. )
  3442. {
  3443. ENDPOINT_SYNCH oldState;
  3444. ENDPOINT_SYNCH newState;
  3445. //
  3446. // Sanity check.
  3447. //
  3448. ASSERT( IS_VALID_ENDPOINT( pEndpoint ) );
  3449. do
  3450. {
  3451. //
  3452. // Capture the current count and initialize the proposed
  3453. // new value.
  3454. //
  3455. newState.Value = oldState.Value =
  3456. *((volatile LONG *)&pEndpoint->EndpointSynch.Value);
  3457. newState.IdleConnections--;
  3458. ASSERT( newState.IdleConnections >= 0 );
  3459. if (newState.IdleConnections < g_UlMinIdleConnections)
  3460. {
  3461. newState.ReplenishScheduled = TRUE;
  3462. }
  3463. if (UlInterlockedCompareExchange(
  3464. &pEndpoint->EndpointSynch.Value,
  3465. newState.Value,
  3466. oldState.Value
  3467. ) == oldState.Value)
  3468. {
  3469. break;
  3470. }
  3471. } while (TRUE);
  3472. UlTrace(TDI, (
  3473. "ul!UlpDecrementIdleConnections(pEndpoint = %p)\n"
  3474. " idle = %d, replenish = %s, returning %s\n",
  3475. pEndpoint,
  3476. newState.IdleConnections,
  3477. newState.ReplenishScheduled ? "TRUE" : "FALSE",
  3478. (newState.ReplenishScheduled && !oldState.ReplenishScheduled) ? "TRUE" : "FALSE"
  3479. ));
  3480. TRACE_REPLENISH(
  3481. pEndpoint,
  3482. oldState,
  3483. newState,
  3484. REPLENISH_ACTION_DECREMENT
  3485. );
  3486. //
  3487. // If the "ReplenishScheduled" flag transitioned from FALSE to TRUE,
  3488. // then we need to schedule a replenish.
  3489. //
  3490. return (newState.ReplenishScheduled && !oldState.ReplenishScheduled);
  3491. } // UlpDecrementIdleConnections
  3492. /***************************************************************************++
  3493. Routine Description:
  3494. Increments the number of idle connections available on the specified
  3495. endpoint.
  3496. Arguments:
  3497. pEndpoint - Supplies the endpoint to decrement.
  3498. Replenishing - TRUE if the connection was added as part of
  3499. a replenish operation.
  3500. Return Value:
  3501. BOOLEAN - TRUE if the count has not reached the minimum number
  3502. of idle connections for the endpoint.
  3503. --***************************************************************************/
  3504. BOOLEAN
  3505. UlpIncrementIdleConnections(
  3506. IN PUL_ENDPOINT pEndpoint,
  3507. IN BOOLEAN Replenishing
  3508. )
  3509. {
  3510. ENDPOINT_SYNCH oldState;
  3511. ENDPOINT_SYNCH newState;
  3512. BOOLEAN ContinueReplenish;
  3513. //
  3514. // Sanity check.
  3515. //
  3516. ASSERT( IS_VALID_ENDPOINT( pEndpoint ) );
  3517. ContinueReplenish = TRUE;
  3518. do
  3519. {
  3520. //
  3521. // Capture the current count and initialize the proposed
  3522. // new value.
  3523. //
  3524. newState.Value = oldState.Value =
  3525. *((volatile LONG *)&pEndpoint->EndpointSynch.Value);
  3526. newState.IdleConnections++;
  3527. ASSERT( newState.IdleConnections >= 0 );
  3528. if (newState.IdleConnections >= g_UlMinIdleConnections)
  3529. {
  3530. ContinueReplenish = FALSE;
  3531. }
  3532. if (UlInterlockedCompareExchange(
  3533. &pEndpoint->EndpointSynch.Value,
  3534. newState.Value,
  3535. oldState.Value
  3536. ) == oldState.Value)
  3537. {
  3538. break;
  3539. }
  3540. } while (TRUE);
  3541. UlTrace(TDI, (
  3542. "ul!UlpIncrementIdleConnections(pEndpoint = %p)\n"
  3543. " idle = %d, replenish = %s\n",
  3544. pEndpoint,
  3545. newState.IdleConnections,
  3546. newState.ReplenishScheduled ? "TRUE" : "FALSE"
  3547. ));
  3548. TRACE_REPLENISH(
  3549. pEndpoint,
  3550. oldState,
  3551. newState,
  3552. REPLENISH_ACTION_INCREMENT
  3553. );
  3554. //
  3555. // If we still don't have enough connections we must
  3556. // continue the replenish.
  3557. //
  3558. return ContinueReplenish;
  3559. } // UlpIncrementIdleConnections
  3560. /***************************************************************************++
  3561. Routine Description:
  3562. Clears the "replenish scheduled" flag on the endpoint. This is only
  3563. called after a replenish failure. The flag is cleared so that future
  3564. attempts to replenish will schedule properly.
  3565. Arguments:
  3566. pEndpoint - Supplies the endpoint to manipulate.
  3567. Return Value:
  3568. None.
  3569. --***************************************************************************/
  3570. VOID
  3571. UlpClearReplenishScheduledFlag(
  3572. IN PUL_ENDPOINT pEndpoint
  3573. )
  3574. {
  3575. ENDPOINT_SYNCH oldState;
  3576. ENDPOINT_SYNCH newState;
  3577. //
  3578. // Sanity check.
  3579. //
  3580. ASSERT( IS_VALID_ENDPOINT( pEndpoint ) );
  3581. do
  3582. {
  3583. //
  3584. // Capture the current count and initialize the proposed
  3585. // new value.
  3586. //
  3587. newState.Value = oldState.Value =
  3588. *((volatile LONG *)&pEndpoint->EndpointSynch.Value);
  3589. newState.ReplenishScheduled = FALSE;
  3590. if (UlInterlockedCompareExchange(
  3591. &pEndpoint->EndpointSynch.Value,
  3592. newState.Value,
  3593. oldState.Value
  3594. ) == oldState.Value)
  3595. {
  3596. break;
  3597. }
  3598. } while (TRUE);
  3599. } // UlpClearReplenishScheduledFlag
  3600. /***************************************************************************++
  3601. Routine Description:
  3602. Creates a new UL_CONNECTION object and opens the corresponding
  3603. TDI connection object.
  3604. Note: The connection returned from this function will contain
  3605. an unreferenced pointer to the owning endpoint. Only active
  3606. connections have references to the endpoint because the refcount
  3607. is used to decide when to clean up the list of idle connections.
  3608. Arguments:
  3609. AddressLength - Supplies the length of the TDI addresses used
  3610. by the transport associated with this connection.
  3611. ppConnection - Receives the pointer to a new UL_CONNECTION if
  3612. successful.
  3613. Return Value:
  3614. NTSTATUS - Completion status. *ppConnection is undefined if the
  3615. return value is not STATUS_SUCCESS.
  3616. --***************************************************************************/
  3617. NTSTATUS
  3618. UlpCreateConnection(
  3619. IN PUL_ENDPOINT pEndpoint,
  3620. IN ULONG AddressLength,
  3621. OUT PUL_CONNECTION *ppConnection
  3622. )
  3623. {
  3624. NTSTATUS status;
  3625. PUL_CONNECTION pConnection;
  3626. PSINGLE_LIST_ENTRY pSListEntry;
  3627. BOOLEAN FilterOnlySsl;
  3628. PUX_TDI_OBJECT pTdiObject;
  3629. ASSERT(NULL != ppConnection);
  3630. //
  3631. // Allocate the pool for the connection structure.
  3632. //
  3633. pConnection = UL_ALLOCATE_STRUCT(
  3634. NonPagedPool,
  3635. UL_CONNECTION,
  3636. UL_CONNECTION_POOL_TAG
  3637. );
  3638. if (pConnection == NULL)
  3639. {
  3640. status = STATUS_INSUFFICIENT_RESOURCES;
  3641. goto fatal;
  3642. }
  3643. //
  3644. // One time field initialization.
  3645. //
  3646. pConnection->Signature = UL_CONNECTION_SIGNATURE;
  3647. ExInterlockedInsertTailList(
  3648. &g_TdiConnectionListHead,
  3649. &pConnection->GlobalConnectionListEntry,
  3650. KSPIN_LOCK_FROM_UL_SPIN_LOCK(&g_TdiSpinLock)
  3651. );
  3652. InterlockedIncrement((PLONG) &g_TdiConnectionCount);
  3653. pConnection->pConnectionContext = NULL;
  3654. pConnection->pOwningEndpoint = NULL;
  3655. #if ENABLE_OWNER_REF_TRACE
  3656. pConnection->pConnRefOwner = NULL;
  3657. pConnection->MonotonicId = 0;
  3658. #endif // ENABLE_OWNER_REF_TRACE
  3659. pConnection->FilterInfo.pFilterChannel = NULL;
  3660. HTTP_SET_NULL_ID( &pConnection->FilterInfo.ConnectionId );
  3661. pConnection->pIrp = NULL;
  3662. pConnection->ActiveListEntry.Flink = NULL;
  3663. pConnection->IdleSListEntry.Next = NULL;
  3664. //
  3665. // Initialize a private trace log.
  3666. //
  3667. CREATE_REF_TRACE_LOG( pConnection->pTraceLog,
  3668. 96 - REF_TRACE_OVERHEAD, 0 );
  3669. CREATE_REF_TRACE_LOG( pConnection->HttpConnection.pTraceLog,
  3670. 32 - REF_TRACE_OVERHEAD, 0 );
  3671. //
  3672. // Open the TDI connection object for this connection.
  3673. //
  3674. status = UxOpenTdiConnectionObject(
  3675. (CONNECTION_CONTEXT)pConnection,
  3676. &pConnection->ConnectionObject
  3677. );
  3678. if (!NT_SUCCESS(status))
  3679. {
  3680. goto fatal;
  3681. }
  3682. ASSERT( IS_VALID_TDI_OBJECT( &pConnection->ConnectionObject ) );
  3683. //
  3684. // Associate the connection with the endpoint.
  3685. //
  3686. status = UlpAssociateConnection( pConnection, pEndpoint );
  3687. if (!NT_SUCCESS(status))
  3688. {
  3689. goto fatal;
  3690. }
  3691. pTdiObject = &pConnection->ConnectionObject;
  3692. pConnection->pIrp = UlAllocateIrp(
  3693. pTdiObject->pDeviceObject->StackSize, // StackSize
  3694. FALSE // ChargeQuota
  3695. );
  3696. if (pConnection->pIrp == NULL)
  3697. {
  3698. status = STATUS_INSUFFICIENT_RESOURCES;
  3699. goto fatal;
  3700. }
  3701. pConnection->pIrp->RequestorMode = KernelMode;
  3702. //
  3703. // Success!
  3704. //
  3705. UlTrace(TDI, (
  3706. "UlpCreateConnecton: created %p\n",
  3707. pConnection
  3708. ));
  3709. *ppConnection = pConnection;
  3710. return STATUS_SUCCESS;
  3711. fatal:
  3712. UlTrace(TDI, (
  3713. "UlpCreateConnecton: failure %08lx\n",
  3714. status
  3715. ));
  3716. ASSERT( !NT_SUCCESS(status) );
  3717. if (pConnection != NULL)
  3718. {
  3719. UlpDestroyConnection( pConnection );
  3720. }
  3721. *ppConnection = NULL;
  3722. return status;
  3723. } // UlpCreateConnection
  3724. /***************************************************************************++
  3725. Routine Description:
  3726. Initializes a UL_CONNECTION for use.
  3727. Note: inactive connections do not have a reference to the endpoint,
  3728. so the caller to this function *must* have a reference.
  3729. Arguments:
  3730. pConnection - Pointer to the UL_CONNECTION to initialize.
  3731. SecureConnection - TRUE if this connection is for a secure endpoint.
  3732. --***************************************************************************/
  3733. NTSTATUS
  3734. UlpInitializeConnection(
  3735. IN PUL_CONNECTION pConnection
  3736. )
  3737. {
  3738. NTSTATUS status;
  3739. BOOLEAN SecureConnection;
  3740. PUL_FILTER_CHANNEL pChannel;
  3741. //
  3742. // Sanity check.
  3743. //
  3744. PAGED_CODE();
  3745. ASSERT(pConnection);
  3746. ASSERT(IS_VALID_ENDPOINT(pConnection->pOwningEndpoint));
  3747. //
  3748. // Initialize locals.
  3749. //
  3750. status = STATUS_SUCCESS;
  3751. SecureConnection = pConnection->pOwningEndpoint->Secure;
  3752. //
  3753. // Initialize the easy parts.
  3754. //
  3755. pConnection->ReferenceCount = 1;
  3756. pConnection->ConnectionFlags.Value = 0;
  3757. pConnection->ActiveListEntry.Flink = NULL;
  3758. pConnection->Terminated = FALSE;
  3759. //
  3760. // Setup the Tdi Connection Information space to be filled with Local Address
  3761. // Information at the completion of the Accept Irp.
  3762. //
  3763. pConnection->TdiConnectionInformation.UserDataLength = 0;
  3764. pConnection->TdiConnectionInformation.UserData = NULL;
  3765. pConnection->TdiConnectionInformation.OptionsLength = 0;
  3766. pConnection->TdiConnectionInformation.Options = NULL;
  3767. pConnection->TdiConnectionInformation.RemoteAddressLength = sizeof(TA_IP_ADDRESS);
  3768. pConnection->TdiConnectionInformation.RemoteAddress = &(pConnection->IpAddress);
  3769. //
  3770. // Init the index to the ActiveConnectionLists.
  3771. //
  3772. if (g_UlNumberOfProcessors == 1)
  3773. {
  3774. pConnection->ActiveListIndex = 0;
  3775. }
  3776. else
  3777. {
  3778. pConnection->ActiveListIndex =
  3779. pConnection->pOwningEndpoint->ActiveConnectionIndex %
  3780. DEFAULT_MAX_CONNECTION_ACTIVE_LISTS;
  3781. pConnection->pOwningEndpoint->ActiveConnectionIndex += 1;
  3782. }
  3783. //
  3784. // Init the IrpContext.
  3785. //
  3786. pConnection->IrpContext.Signature = UL_IRP_CONTEXT_SIGNATURE;
  3787. //
  3788. // Init the HTTP_CONNECTION.
  3789. //
  3790. pConnection->HttpConnection.RefCount = 0;
  3791. pChannel = UlQueryFilterChannel(SecureConnection);
  3792. status = UxInitializeFilterConnection(
  3793. &pConnection->FilterInfo,
  3794. pChannel,
  3795. SecureConnection,
  3796. &UlReferenceConnection,
  3797. &UlDereferenceConnection,
  3798. &UlpCloseRawConnection,
  3799. &UlpSendRawData,
  3800. &UlpReceiveRawData,
  3801. &UlpDummyReceiveHandler,
  3802. &UlpComputeHttpRawConnectionLength,
  3803. &UlpGenerateHttpRawConnectionInfo,
  3804. NULL,
  3805. pConnection->pOwningEndpoint,
  3806. pConnection
  3807. );
  3808. return status;
  3809. } // UlpInitializeConnection
  3810. /***************************************************************************++
  3811. Routine Description:
  3812. This function sets a new flag in the connection's flag set. The setting
  3813. of the flag is synchronized such that only one flag is set at a time.
  3814. Arguments:
  3815. pConnection - Supplies the connection whose flags are to be set.
  3816. NewFlag - Supplies a 32-bit value to be or-ed into the current flag set.
  3817. Return Value:
  3818. UL_CONNECTION_FLAGS - The new set of connection flags after the update.
  3819. --***************************************************************************/
  3820. UL_CONNECTION_FLAGS
  3821. UlpSetConnectionFlag(
  3822. IN OUT PUL_CONNECTION pConnection,
  3823. IN LONG NewFlag
  3824. )
  3825. {
  3826. UL_CONNECTION_FLAGS oldFlags;
  3827. UL_CONNECTION_FLAGS newFlags;
  3828. //
  3829. // Sanity check.
  3830. //
  3831. ASSERT( IS_VALID_CONNECTION( pConnection ) );
  3832. do
  3833. {
  3834. //
  3835. // Capture the current value and initialize the new value.
  3836. //
  3837. newFlags.Value = oldFlags.Value =
  3838. *((volatile LONG *)&pConnection->ConnectionFlags.Value);
  3839. newFlags.Value |= NewFlag;
  3840. if (UlInterlockedCompareExchange(
  3841. &pConnection->ConnectionFlags.Value,
  3842. newFlags.Value,
  3843. oldFlags.Value
  3844. ) == oldFlags.Value)
  3845. {
  3846. break;
  3847. }
  3848. } while (TRUE);
  3849. return newFlags;
  3850. } // UlpSetConnectionFlag
  3851. /***************************************************************************++
  3852. Routine Description:
  3853. Initiates a graceful disconnect on the specified connection.
  3854. Arguments:
  3855. pConnection - Supplies the connection to disconnect.
  3856. pCompletionRoutine - Supplies a pointer to a completion routine to
  3857. invoke after the connection is disconnected.
  3858. pCompletionContext - Supplies an uninterpreted context value for the
  3859. completion routine.
  3860. CleaningUp - TRUE if we're cleaning up the connection.
  3861. Return Value:
  3862. NTSTATUS - Completion status.
  3863. --***************************************************************************/
  3864. NTSTATUS
  3865. UlpBeginDisconnect(
  3866. IN PUL_CONNECTION pConnection,
  3867. IN PUL_COMPLETION_ROUTINE pCompletionRoutine,
  3868. IN PVOID pCompletionContext
  3869. )
  3870. {
  3871. PIRP pIrp;
  3872. UL_CONNECTION_FLAGS newFlags;
  3873. LONG flagsToSet;
  3874. PUL_IRP_CONTEXT pIrpContext;
  3875. //
  3876. // Sanity check.
  3877. //
  3878. ASSERT( IS_VALID_CONNECTION( pConnection ) );
  3879. UlTrace(TDI, (
  3880. "UlpBeginDisconnect: connection %p\n",
  3881. pConnection
  3882. ));
  3883. //
  3884. // Allocate and initialize an IRP context for this request.
  3885. //
  3886. pIrpContext = &pConnection->IrpContext;
  3887. ASSERT( IS_VALID_IRP_CONTEXT( pIrpContext ) );
  3888. pIrpContext->pConnectionContext = (PVOID)pConnection;
  3889. pIrpContext->pCompletionRoutine = pCompletionRoutine;
  3890. pIrpContext->pCompletionContext = pCompletionContext;
  3891. //
  3892. // Allocate and initialize an IRP for the disconnect. Note that we do
  3893. // this *before* manipulating the connection state so that we don't have
  3894. // to back out the state changes after an IRP allocation failure.
  3895. //
  3896. pIrp = pConnection->pIrp;
  3897. UxInitializeDisconnectIrp(
  3898. pIrp,
  3899. &pConnection->ConnectionObject,
  3900. TDI_DISCONNECT_RELEASE,
  3901. &UlpRestartDisconnect,
  3902. pIrpContext
  3903. );
  3904. //
  3905. // Add a reference to the connection
  3906. //
  3907. REFERENCE_CONNECTION( pConnection );
  3908. //
  3909. // Set the flag indicating that a disconnect is pending &
  3910. // we're cleaning up.
  3911. //
  3912. flagsToSet = MakeDisconnectPendingFlag();
  3913. flagsToSet |= MakeCleanupBegunFlag();
  3914. newFlags = UlpSetConnectionFlag( pConnection, flagsToSet );
  3915. //
  3916. // Then call the driver to initiate
  3917. // the disconnect.
  3918. //
  3919. UlCallDriver( pConnection->ConnectionObject.pDeviceObject, pIrp );
  3920. return STATUS_PENDING;
  3921. } // UlpBeginDisconnect
  3922. /***************************************************************************++
  3923. Routine Description:
  3924. Completion handler for graceful disconnect IRPs.
  3925. Arguments:
  3926. pDeviceObject - Supplies the device object for the IRP being
  3927. completed.
  3928. pIrp - Supplies the IRP being completed.
  3929. pContext - Supplies the context associated with this request.
  3930. This is actually a PUL_IRP_CONTEXT.
  3931. Return Value:
  3932. NTSTATUS - STATUS_SUCCESS if IO should continue processing this
  3933. IRP, STATUS_MORE_PROCESSING_REQUIRED if IO should stop processing
  3934. this IRP.
  3935. --***************************************************************************/
  3936. NTSTATUS
  3937. UlpRestartDisconnect(
  3938. IN PDEVICE_OBJECT pDeviceObject,
  3939. IN PIRP pIrp,
  3940. IN PVOID pContext
  3941. )
  3942. {
  3943. PUL_IRP_CONTEXT pIrpContext;
  3944. PUL_CONNECTION pConnection;
  3945. UL_CONNECTION_FLAGS newFlags;
  3946. PUL_ENDPOINT pEndpoint;
  3947. //
  3948. // Sanity check.
  3949. //
  3950. pIrpContext = (PUL_IRP_CONTEXT)pContext;
  3951. ASSERT( IS_VALID_IRP_CONTEXT( pIrpContext ) );
  3952. pConnection = (PUL_CONNECTION)pIrpContext->pConnectionContext;
  3953. ASSERT( IS_VALID_CONNECTION( pConnection ) );
  3954. ASSERT( pConnection->ConnectionFlags.DisconnectPending );
  3955. UlTrace(TDI, (
  3956. "UlpRestartDisconnect: connection %p\n",
  3957. pConnection
  3958. ));
  3959. pEndpoint = pConnection->pOwningEndpoint;
  3960. newFlags.Value =
  3961. *((volatile LONG *)&pConnection->ConnectionFlags.Value);
  3962. if (!newFlags.DisconnectIndicated &&
  3963. !newFlags.AbortIndicated &&
  3964. pConnection->FilterInfo.pFilterChannel == NULL
  3965. )
  3966. {
  3967. // Only try to drain if its non-filter connection. Also it's not
  3968. // necessary to drain if the connection has already been aborted.
  3969. // CODEWORK: Filter code should also be updated to introduce the
  3970. // same drain functionality.
  3971. (pEndpoint->pConnectionDisconnectCompleteHandler)(
  3972. pEndpoint->pListeningContext,
  3973. pConnection->pConnectionContext
  3974. );
  3975. }
  3976. //
  3977. // Set the flag indicating that a disconnect has completed. If we're
  3978. // in the midst of cleaning up this endpoint and we've already received
  3979. // a disconnect (graceful or abortive) from the client, then remove the
  3980. // final reference to the connection.
  3981. //
  3982. newFlags = UlpSetConnectionFlag(
  3983. pConnection,
  3984. MakeDisconnectCompleteFlag()
  3985. );
  3986. UlpRemoveFinalReference( pConnection, newFlags );
  3987. //
  3988. // Invoke the user's completion routine, then free the IRP context.
  3989. //
  3990. if (pIrpContext->pCompletionRoutine)
  3991. {
  3992. (pIrpContext->pCompletionRoutine)(
  3993. pIrpContext->pCompletionContext,
  3994. pIrp->IoStatus.Status,
  3995. pIrp->IoStatus.Information
  3996. );
  3997. }
  3998. DEREFERENCE_CONNECTION( pConnection );
  3999. return STATUS_MORE_PROCESSING_REQUIRED;
  4000. } // UlpRestartDisconnect
  4001. /***************************************************************************++
  4002. Routine Description:
  4003. Initiates an abortive disconnect on the specified connection.
  4004. Arguments:
  4005. pConnection - Supplies the connection to disconnect.
  4006. pCompletionRoutine - Supplies a pointer to a completion routine to
  4007. invoke after the connection is disconnected.
  4008. pCompletionContext - Supplies an uninterpreted context value for the
  4009. completion routine.
  4010. Return Value:
  4011. NTSTATUS - Completion status.
  4012. --***************************************************************************/
  4013. NTSTATUS
  4014. UlpBeginAbort(
  4015. IN PUL_CONNECTION pConnection,
  4016. IN PUL_COMPLETION_ROUTINE pCompletionRoutine,
  4017. IN PVOID pCompletionContext
  4018. )
  4019. {
  4020. PIRP pIrp;
  4021. UL_CONNECTION_FLAGS newFlags;
  4022. LONG flagsToSet;
  4023. PUL_IRP_CONTEXT pIrpContext;
  4024. //
  4025. // Sanity check.
  4026. //
  4027. ASSERT( IS_VALID_CONNECTION( pConnection ) );
  4028. UlTrace(TDI, (
  4029. "UlpBeginAbort: connection %p\n",
  4030. pConnection
  4031. ));
  4032. //
  4033. // Allocate and initialize an IRP context for this request.
  4034. //
  4035. pIrpContext = &pConnection->IrpContext;
  4036. ASSERT( IS_VALID_IRP_CONTEXT( pIrpContext ) );
  4037. pIrpContext->pConnectionContext = (PVOID)pConnection;
  4038. pIrpContext->pCompletionRoutine = pCompletionRoutine;
  4039. pIrpContext->pCompletionContext = pCompletionContext;
  4040. //
  4041. // Allocate and initialize an IRP for the disconnect. Note that we do
  4042. // this *before* manipulating the connection state so that we don't have
  4043. // to back out the state changes after an IRP allocation failure.
  4044. //
  4045. pIrp = pConnection->pIrp;
  4046. UxInitializeDisconnectIrp(
  4047. pIrp,
  4048. &pConnection->ConnectionObject,
  4049. TDI_DISCONNECT_ABORT,
  4050. &UlpRestartAbort,
  4051. pIrpContext
  4052. );
  4053. //
  4054. // Add a reference to the connection,
  4055. //
  4056. REFERENCE_CONNECTION( pConnection );
  4057. //
  4058. // Set the flag indicating that a disconnect is pending &
  4059. // we're cleaning up.
  4060. //
  4061. flagsToSet = MakeAbortPendingFlag();
  4062. flagsToSet |= MakeCleanupBegunFlag();
  4063. newFlags = UlpSetConnectionFlag( pConnection, flagsToSet );
  4064. //
  4065. // Then call the driver to initiate the disconnect.
  4066. //
  4067. UlCallDriver( pConnection->ConnectionObject.pDeviceObject, pIrp );
  4068. return STATUS_PENDING;
  4069. } // UlpBeginAbort
  4070. /***************************************************************************++
  4071. Routine Description:
  4072. Completion handler for abortive disconnect IRPs.
  4073. Arguments:
  4074. pDeviceObject - Supplies the device object for the IRP being
  4075. completed.
  4076. pIrp - Supplies the IRP being completed.
  4077. pContext - Supplies the context associated with this request.
  4078. This is actually a PUL_IRP_CONTEXT.
  4079. Return Value:
  4080. NTSTATUS - STATUS_SUCCESS if IO should continue processing this
  4081. IRP, STATUS_MORE_PROCESSING_REQUIRED if IO should stop processing
  4082. this IRP.
  4083. --***************************************************************************/
  4084. NTSTATUS
  4085. UlpRestartAbort(
  4086. IN PDEVICE_OBJECT pDeviceObject,
  4087. IN PIRP pIrp,
  4088. IN PVOID pContext
  4089. )
  4090. {
  4091. PUL_IRP_CONTEXT pIrpContext;
  4092. PUL_CONNECTION pConnection;
  4093. UL_CONNECTION_FLAGS newFlags;
  4094. //
  4095. // Sanity check.
  4096. //
  4097. pIrpContext = (PUL_IRP_CONTEXT)pContext;
  4098. ASSERT( IS_VALID_IRP_CONTEXT( pIrpContext ) );
  4099. pConnection = (PUL_CONNECTION)pIrpContext->pConnectionContext;
  4100. ASSERT( IS_VALID_CONNECTION( pConnection ) );
  4101. ASSERT( pConnection->ConnectionFlags.AbortPending );
  4102. UlTrace(TDI, (
  4103. "UlpRestartAbort: connection %p\n",
  4104. pConnection
  4105. ));
  4106. //
  4107. // Set the flag indicating that an abort has completed. If we're in the
  4108. // midst of cleaning up this endpoint and we've already received a
  4109. // disconnect (graceful or abortive) from the client, then remove the
  4110. // final reference to the connection.
  4111. //
  4112. newFlags = UlpSetConnectionFlag(
  4113. pConnection,
  4114. MakeAbortCompleteFlag()
  4115. );
  4116. UlpRemoveFinalReference( pConnection, newFlags );
  4117. //
  4118. // Invoke the user's completion routine, then free the IRP context.
  4119. //
  4120. if (pIrpContext->pCompletionRoutine)
  4121. {
  4122. (pIrpContext->pCompletionRoutine)(
  4123. pIrpContext->pCompletionContext,
  4124. pIrp->IoStatus.Status,
  4125. pIrp->IoStatus.Information
  4126. );
  4127. }
  4128. DEREFERENCE_CONNECTION( pConnection );
  4129. return STATUS_MORE_PROCESSING_REQUIRED;
  4130. } // UlpRestartAbort
  4131. /***************************************************************************++
  4132. Routine Description:
  4133. Removes the final reference from a connection if the conditions are
  4134. right. See comments within this function for details on the conditions
  4135. required.
  4136. Arguments:
  4137. pConnection - Supplies the connection to dereference.
  4138. Flags - Supplies the connection flags from the most recent update.
  4139. Note:
  4140. It is very important that the caller of this routine has established
  4141. its own reference to the connection. If necessary, this reference
  4142. can be immediately removed after calling this routine, but not before.
  4143. --***************************************************************************/
  4144. VOID
  4145. UlpRemoveFinalReference(
  4146. IN PUL_CONNECTION pConnection,
  4147. IN UL_CONNECTION_FLAGS Flags
  4148. )
  4149. {
  4150. UL_CONNECTION_FLAGS oldFlags;
  4151. UL_CONNECTION_FLAGS newFlags;
  4152. //
  4153. // Sanity check.
  4154. //
  4155. ASSERT( IS_VALID_CONNECTION( pConnection ) );
  4156. //
  4157. // We can only remove the final reference if:
  4158. //
  4159. // We've begun connection cleanup.
  4160. //
  4161. // We've completed an accept.
  4162. //
  4163. // We've received a disconnect or abort indication or we've
  4164. // issued & completed an abort.
  4165. //
  4166. // We don't have a disconnect or abort pending.
  4167. //
  4168. // We haven't already removed it.
  4169. //
  4170. if (Flags.CleanupBegun &&
  4171. Flags.AcceptComplete &&
  4172. (Flags.DisconnectIndicated || Flags.AbortIndicated || Flags.AbortComplete) &&
  4173. (!Flags.DisconnectPending || Flags.DisconnectComplete) &&
  4174. (!Flags.AbortPending || Flags.AbortComplete) &&
  4175. !Flags.FinalReferenceRemoved)
  4176. {
  4177. //
  4178. // It looks like we may be able to remove the final reference.
  4179. // Attempt to set the "FinalReferenceRemoved" flag and determine
  4180. // if this thread is the one that actually needs to remove it.
  4181. //
  4182. do
  4183. {
  4184. //
  4185. // Capture the current flags and initialize the proposed
  4186. // new value.
  4187. //
  4188. newFlags.Value = oldFlags.Value =
  4189. *((volatile LONG *)&pConnection->ConnectionFlags.Value);
  4190. newFlags.Value |= MakeFinalReferenceRemovedFlag();
  4191. if (UlInterlockedCompareExchange(
  4192. &pConnection->ConnectionFlags.Value,
  4193. newFlags.Value,
  4194. oldFlags.Value
  4195. ) == oldFlags.Value)
  4196. {
  4197. break;
  4198. }
  4199. } while (TRUE);
  4200. //
  4201. // See if WE actually set the flag.
  4202. //
  4203. if (!oldFlags.FinalReferenceRemoved)
  4204. {
  4205. UlTrace(TDI, (
  4206. "UlpRemoveFinalReference: connection %p\n",
  4207. pConnection
  4208. ));
  4209. //
  4210. // Tell the client that the connection is now fully destroyed.
  4211. //
  4212. (pConnection->pConnectionDestroyedHandler)(
  4213. pConnection->pListeningContext,
  4214. pConnection->pConnectionContext
  4215. );
  4216. //
  4217. // Unbind from the endpoint if we're still attached.
  4218. // This allows it to release any refs it has on the connection.
  4219. //
  4220. UlpUnbindConnectionFromEndpoint(pConnection);
  4221. //
  4222. // Release the filter channel.
  4223. // This allows it to release any refs it has on the connection.
  4224. //
  4225. if (pConnection->FilterInfo.pFilterChannel)
  4226. {
  4227. UlUnbindConnectionFromFilter(&pConnection->FilterInfo);
  4228. }
  4229. //
  4230. // Remove the final reference.
  4231. //
  4232. DEREFERENCE_CONNECTION( pConnection );
  4233. WRITE_OWNER_REF_TRACE_LOG(
  4234. pConnection->pOwningEndpoint->pOwnerRefTraceLog,
  4235. pConnection,
  4236. &pConnection->pConnRefOwner,
  4237. UL_CONNECTION_SIGNATURE,
  4238. REF_ACTION_FINAL_DEREF,
  4239. -1, // newrefct: ignored
  4240. pConnection->MonotonicId,
  4241. 0, // don't adjust local ref count
  4242. __FILE__,
  4243. __LINE__
  4244. );
  4245. }
  4246. }
  4247. else
  4248. {
  4249. UlTrace(TDI, (
  4250. "UlpRemoveFinalReference: cannot remove %p, flags = %08lx:\n",
  4251. pConnection,
  4252. Flags.Value
  4253. ));
  4254. }
  4255. } // UlpRemoveFinalReference
  4256. /***************************************************************************++
  4257. Routine Description:
  4258. Completion handler for receive IRPs passed back to the transport from
  4259. our receive indication handler.
  4260. Arguments:
  4261. pDeviceObject - Supplies the device object for the IRP being
  4262. completed.
  4263. pIrp - Supplies the IRP being completed.
  4264. pContext - Supplies the context associated with this request.
  4265. This is actually a PUL_RECEIVE_BUFFER.
  4266. Return Value:
  4267. NTSTATUS - STATUS_SUCCESS if IO should continue processing this
  4268. IRP, STATUS_MORE_PROCESSING_REQUIRED if IO should stop processing
  4269. this IRP.
  4270. --***************************************************************************/
  4271. NTSTATUS
  4272. UlpRestartReceive(
  4273. IN PDEVICE_OBJECT pDeviceObject,
  4274. IN PIRP pIrp,
  4275. IN PVOID pContext
  4276. )
  4277. {
  4278. NTSTATUS status;
  4279. PUL_RECEIVE_BUFFER pBuffer;
  4280. PUL_CONNECTION pConnection;
  4281. PUL_ENDPOINT pEndpoint;
  4282. PUX_TDI_OBJECT pTdiObject;
  4283. ULONG bytesAvailable;
  4284. ULONG bytesTaken;
  4285. ULONG bytesRemaining;
  4286. //
  4287. // Sanity check.
  4288. //
  4289. pBuffer = (PUL_RECEIVE_BUFFER) pContext;
  4290. ASSERT( IS_VALID_RECEIVE_BUFFER( pBuffer ) );
  4291. pConnection = (PUL_CONNECTION) pBuffer->pConnectionContext;
  4292. ASSERT( IS_VALID_CONNECTION( pConnection ) );
  4293. pTdiObject = &pConnection->ConnectionObject;
  4294. ASSERT( IS_VALID_TDI_OBJECT( pTdiObject ) );
  4295. pEndpoint = pConnection->pOwningEndpoint;
  4296. ASSERT( IS_VALID_ENDPOINT( pEndpoint ) );
  4297. //
  4298. // The connection could be destroyed before we get a chance to
  4299. // receive the completion for the receive IRP. In that case the
  4300. // irp status won't be success but STATUS_CONNECTION_RESET or similar.
  4301. // We should not attempt to pass this case to the client.
  4302. //
  4303. status = pBuffer->pIrp->IoStatus.Status;
  4304. if ( status != STATUS_SUCCESS )
  4305. {
  4306. //
  4307. // The HttpConnection has already been destroyed
  4308. // or receive completion failed for some reason.
  4309. // No need to go to client.
  4310. //
  4311. goto end;
  4312. }
  4313. //
  4314. // Fake a receive indication to the client.
  4315. //
  4316. pBuffer->UnreadDataLength += (ULONG)pBuffer->pIrp->IoStatus.Information;
  4317. bytesTaken = 0;
  4318. UlTrace(TDI, (
  4319. "UlpRestartReceive: endpoint %p, connection %p, length %lu\n",
  4320. pEndpoint,
  4321. pConnection,
  4322. pBuffer->UnreadDataLength
  4323. ));
  4324. //
  4325. // Pass the data on.
  4326. //
  4327. if (pConnection->FilterInfo.pFilterChannel)
  4328. {
  4329. //
  4330. // Needs to go through a filter.
  4331. //
  4332. status = UlFilterReceiveHandler(
  4333. &pConnection->FilterInfo,
  4334. pBuffer->pDataArea,
  4335. pBuffer->UnreadDataLength,
  4336. 0,
  4337. &bytesTaken
  4338. );
  4339. }
  4340. else
  4341. {
  4342. //
  4343. // Go directly to client.
  4344. //
  4345. status = (pEndpoint->pDataReceiveHandler)(
  4346. pEndpoint->pListeningContext,
  4347. pConnection->pConnectionContext,
  4348. pBuffer->pDataArea,
  4349. pBuffer->UnreadDataLength,
  4350. 0,
  4351. &bytesTaken
  4352. );
  4353. }
  4354. ASSERT( bytesTaken <= pBuffer->UnreadDataLength );
  4355. //
  4356. // Note that this basically duplicates the logic that's currently in
  4357. // UlpReceiveHandler.
  4358. //
  4359. if (status == STATUS_MORE_PROCESSING_REQUIRED)
  4360. {
  4361. //
  4362. // The client consumed part of the indicated data.
  4363. //
  4364. // We'll need to copy the untaken data forward within the receive
  4365. // buffer, build an MDL describing the remaining part of the buffer,
  4366. // then repost the receive IRP.
  4367. //
  4368. bytesRemaining = pBuffer->UnreadDataLength - bytesTaken;
  4369. //
  4370. // Do we have enough buffer space for more?
  4371. //
  4372. if (bytesRemaining < g_UlReceiveBufferSize)
  4373. {
  4374. //
  4375. // Move the unread portion of the buffer to the beginning.
  4376. //
  4377. RtlMoveMemory(
  4378. pBuffer->pDataArea,
  4379. (PUCHAR)pBuffer->pDataArea + bytesTaken,
  4380. bytesRemaining
  4381. );
  4382. pBuffer->UnreadDataLength = bytesRemaining;
  4383. //
  4384. // Build a partial mdl representing the remainder of the
  4385. // buffer.
  4386. //
  4387. IoBuildPartialMdl(
  4388. pBuffer->pMdl, // SourceMdl
  4389. pBuffer->pPartialMdl, // TargetMdl
  4390. (PUCHAR)pBuffer->pDataArea + bytesRemaining,// VirtualAddress
  4391. g_UlReceiveBufferSize - bytesRemaining // Length
  4392. );
  4393. //
  4394. // Finish initializing the IRP.
  4395. //
  4396. TdiBuildReceive(
  4397. pBuffer->pIrp, // Irp
  4398. pTdiObject->pDeviceObject, // DeviceObject
  4399. pTdiObject->pFileObject, // FileObject
  4400. &UlpRestartReceive, // CompletionRoutine
  4401. pBuffer, // CompletionContext
  4402. pBuffer->pPartialMdl, // MdlAddress
  4403. TDI_RECEIVE_NORMAL, // Flags
  4404. g_UlReceiveBufferSize - bytesRemaining // Length
  4405. );
  4406. UlTrace(TDI, (
  4407. "UlpRestartReceive: connection %p, reusing irp %p to grab more data\n",
  4408. pConnection,
  4409. pBuffer->pIrp
  4410. ));
  4411. //
  4412. // Call the driver.
  4413. //
  4414. UlCallDriver( pTdiObject->pDeviceObject, pIrp );
  4415. //
  4416. // Tell IO to stop processing this request.
  4417. //
  4418. return STATUS_MORE_PROCESSING_REQUIRED;
  4419. }
  4420. status = STATUS_BUFFER_OVERFLOW;
  4421. }
  4422. end:
  4423. if (status != STATUS_SUCCESS)
  4424. {
  4425. //
  4426. // The client failed the indication. Abort the connection.
  4427. //
  4428. //
  4429. // BUGBUG need to add code to return a response
  4430. //
  4431. UlpCloseRawConnection(
  4432. pConnection,
  4433. TRUE, // AbortiveDisconnect
  4434. NULL, // pCompletionRoutine
  4435. NULL // pCompletionContext
  4436. );
  4437. }
  4438. //
  4439. // Remove the connection we added in the receive indication handler,
  4440. // free the receive buffer, then tell IO to stop processing the IRP.
  4441. //
  4442. DEREFERENCE_CONNECTION( pConnection );
  4443. UlPplFreeReceiveBuffer( pBuffer );
  4444. UlTrace(TDI, (
  4445. "UlpRestartReceive: endpoint %p, connection %p, length %lu, taken %lu, status %x\n",
  4446. pEndpoint,
  4447. pConnection,
  4448. pBuffer->UnreadDataLength,
  4449. bytesTaken,
  4450. status
  4451. ));
  4452. return STATUS_MORE_PROCESSING_REQUIRED;
  4453. } // UlpRestartReceive
  4454. /***************************************************************************++
  4455. Routine Description:
  4456. Completion handler for receive IRPs initiated from UlReceiveData().
  4457. Arguments:
  4458. pDeviceObject - Supplies the device object for the IRP being
  4459. completed.
  4460. pIrp - Supplies the IRP being completed.
  4461. pContext - Supplies the context associated with this request.
  4462. This is actually a PUL_IRP_CONTEXT.
  4463. Return Value:
  4464. NTSTATUS - STATUS_SUCCESS if IO should continue processing this
  4465. IRP, STATUS_MORE_PROCESSING_REQUIRED if IO should stop processing
  4466. this IRP.
  4467. --***************************************************************************/
  4468. NTSTATUS
  4469. UlpRestartClientReceive(
  4470. IN PDEVICE_OBJECT pDeviceObject,
  4471. IN PIRP pIrp,
  4472. IN PVOID pContext
  4473. )
  4474. {
  4475. PUL_IRP_CONTEXT pIrpContext;
  4476. PUL_CONNECTION pConnection;
  4477. //
  4478. // Sanity check.
  4479. //
  4480. pIrpContext= (PUL_IRP_CONTEXT)pContext;
  4481. ASSERT( IS_VALID_IRP_CONTEXT( pIrpContext ) );
  4482. pConnection = (PUL_CONNECTION)pIrpContext->pConnectionContext;
  4483. ASSERT( IS_VALID_CONNECTION( pConnection ) );
  4484. UlTrace(TDI, (
  4485. "UlpRestartClientReceive: irp %p, connection %p, status %08lx\n",
  4486. pIrp,
  4487. pConnection,
  4488. pIrp->IoStatus.Status
  4489. ));
  4490. //
  4491. // Invoke the client's completion handler.
  4492. //
  4493. (pIrpContext->pCompletionRoutine)(
  4494. pIrpContext->pCompletionContext,
  4495. pIrp->IoStatus.Status,
  4496. pIrp->IoStatus.Information
  4497. );
  4498. //
  4499. // Free the IRP context we allocated.
  4500. //
  4501. UlPplFreeIrpContext(pIrpContext);
  4502. //
  4503. // IO can't handle completing an IRP with a non-paged MDL attached
  4504. // to it, so we'll free the MDL here.
  4505. //
  4506. ASSERT( pIrp->MdlAddress != NULL );
  4507. UlFreeMdl( pIrp->MdlAddress );
  4508. pIrp->MdlAddress = NULL;
  4509. //
  4510. // Remove the connection we added in UlReceiveData()
  4511. //
  4512. DEREFERENCE_CONNECTION( pConnection );
  4513. //
  4514. // Free the IRP since we're done with it, then tell IO to
  4515. // stop processing the IRP.
  4516. //
  4517. UlFreeIrp(pIrp);
  4518. return STATUS_MORE_PROCESSING_REQUIRED;
  4519. } // UlpRestartClientReceive
  4520. /***************************************************************************++
  4521. Routine Description:
  4522. Removes all active connections from the specified endpoint and initiates
  4523. abortive disconnects.
  4524. Arguments:
  4525. pEndpoint - Supplies the endpoint to purge.
  4526. Return Value:
  4527. NTSTATUS - completion status
  4528. --***************************************************************************/
  4529. NTSTATUS
  4530. UlpDisconnectAllActiveConnections(
  4531. IN PUL_ENDPOINT pEndpoint
  4532. )
  4533. {
  4534. KIRQL oldIrql;
  4535. PLIST_ENTRY pListEntry;
  4536. PUL_CONNECTION pConnection;
  4537. PUL_IRP_CONTEXT pIrpContext = &pEndpoint->CleanupIrpContext;
  4538. NTSTATUS Status;
  4539. UL_STATUS_BLOCK ulStatus;
  4540. LONG i;
  4541. //
  4542. // Sanity check.
  4543. //
  4544. ASSERT( IS_VALID_ENDPOINT( pEndpoint ) );
  4545. ASSERT( IS_VALID_IRP_CONTEXT( pIrpContext ) );
  4546. UlTrace(TDI, (
  4547. "UlpDisconnectAllActiveConnections: endpoint %p\n",
  4548. pEndpoint
  4549. ));
  4550. //
  4551. // This routine is not pageable because it must acquire a spinlock.
  4552. // However, it must be called at passive IRQL because it must
  4553. // block on an event object.
  4554. //
  4555. ASSERT( KeGetCurrentIrql() == PASSIVE_LEVEL );
  4556. //
  4557. // Initialize a status block. We'll pass a pointer to this as
  4558. // the completion context to UlpCloseRawConnection(). The
  4559. // completion routine will update the status block and signal
  4560. // the event.
  4561. //
  4562. UlInitializeStatusBlock( &ulStatus );
  4563. //
  4564. // Loop through all of the active connections.
  4565. //
  4566. for (i = 0; i < DEFAULT_MAX_CONNECTION_ACTIVE_LISTS; i++)
  4567. {
  4568. for (;;)
  4569. {
  4570. //
  4571. // Remove an active connection.
  4572. //
  4573. UlAcquireSpinLock(
  4574. &pEndpoint->ActiveConnectionSpinLock[i],
  4575. &oldIrql
  4576. );
  4577. pListEntry = RemoveHeadList( &pEndpoint->ActiveConnectionListHead[i] );
  4578. if (pListEntry == &pEndpoint->ActiveConnectionListHead[i])
  4579. {
  4580. UlReleaseSpinLock(
  4581. &pEndpoint->ActiveConnectionSpinLock[i],
  4582. oldIrql
  4583. );
  4584. break;
  4585. }
  4586. //
  4587. // Validate the connection.
  4588. //
  4589. pConnection = CONTAINING_RECORD(
  4590. pListEntry,
  4591. UL_CONNECTION,
  4592. ActiveListEntry
  4593. );
  4594. ASSERT( IS_VALID_CONNECTION( pConnection ) );
  4595. ASSERT( pConnection->pOwningEndpoint == pEndpoint );
  4596. pConnection->ActiveListEntry.Flink = NULL;
  4597. WRITE_OWNER_REF_TRACE_LOG(
  4598. pEndpoint->pOwnerRefTraceLog,
  4599. pConnection,
  4600. &pConnection->pConnRefOwner,
  4601. UL_CONNECTION_SIGNATURE,
  4602. REF_ACTION_DISCONN_ALL,
  4603. -1, // newrefct: ignored
  4604. pConnection->MonotonicId,
  4605. 0, // don't adjust local ref count
  4606. __FILE__,
  4607. __LINE__
  4608. );
  4609. UlReleaseSpinLock(
  4610. &pEndpoint->ActiveConnectionSpinLock[i],
  4611. oldIrql
  4612. );
  4613. //
  4614. // Abort it.
  4615. //
  4616. UlResetStatusBlockEvent( &ulStatus );
  4617. Status = UlpCloseRawConnection(
  4618. pConnection,
  4619. TRUE,
  4620. &UlpSynchronousIoComplete,
  4621. &ulStatus
  4622. );
  4623. ASSERT( Status == STATUS_PENDING );
  4624. //
  4625. // Wait for it to complete.
  4626. //
  4627. UlWaitForStatusBlockEvent( &ulStatus );
  4628. //
  4629. // Remove the active list's reference.
  4630. //
  4631. DEREFERENCE_CONNECTION(pConnection);
  4632. }
  4633. }
  4634. //
  4635. // No active connections, nuke the endpoint.
  4636. //
  4637. // We must set the IRP context in the endpoint so that the
  4638. // completion will be invoked when the endpoint's reference
  4639. // count drops to zero. Since the completion routine may be
  4640. // invoked at a later time, we always return STATUS_PENDING.
  4641. //
  4642. pIrpContext->pConnectionContext = (PVOID)pEndpoint;
  4643. DEREFERENCE_ENDPOINT_SELF(pEndpoint, REF_ACTION_DISCONN_ACTIVE);
  4644. return STATUS_PENDING;
  4645. } // UlpDisconnectAllActiveConnections
  4646. /***************************************************************************++
  4647. Routine Description:
  4648. Unbinds an active connection from the endpoint. If the connection
  4649. is on the active list this routine removes it and drops the
  4650. list's reference to the connection.
  4651. Arguments:
  4652. pConnection - the connection to unbind
  4653. --***************************************************************************/
  4654. VOID
  4655. UlpUnbindConnectionFromEndpoint(
  4656. IN PUL_CONNECTION pConnection
  4657. )
  4658. {
  4659. KIRQL oldIrql;
  4660. PUL_ENDPOINT pEndpoint;
  4661. BOOLEAN Dereference;
  4662. //
  4663. // Sanity check.
  4664. //
  4665. ASSERT(IS_VALID_CONNECTION(pConnection));
  4666. pEndpoint = pConnection->pOwningEndpoint;
  4667. ASSERT(IS_VALID_ENDPOINT(pEndpoint));
  4668. //
  4669. // Init locals.
  4670. //
  4671. Dereference = FALSE;
  4672. //
  4673. // Unbind.
  4674. //
  4675. UlAcquireSpinLock(
  4676. &pEndpoint->ActiveConnectionSpinLock[pConnection->ActiveListIndex],
  4677. &oldIrql
  4678. );
  4679. if (pConnection->ActiveListEntry.Flink != NULL)
  4680. {
  4681. RemoveEntryList(&pConnection->ActiveListEntry);
  4682. pConnection->ActiveListEntry.Flink = NULL;
  4683. WRITE_OWNER_REF_TRACE_LOG(
  4684. pConnection->pOwningEndpoint->pOwnerRefTraceLog,
  4685. pConnection,
  4686. &pConnection->pConnRefOwner,
  4687. UL_CONNECTION_SIGNATURE,
  4688. REF_ACTION_UNBIND_CONN,
  4689. -1, // newrefct: ignored
  4690. pConnection->MonotonicId,
  4691. 0, // don't adjust local ref count
  4692. __FILE__,
  4693. __LINE__
  4694. );
  4695. Dereference = TRUE;
  4696. }
  4697. UlReleaseSpinLock(
  4698. &pEndpoint->ActiveConnectionSpinLock[pConnection->ActiveListIndex],
  4699. oldIrql
  4700. );
  4701. //
  4702. // If the list had a reference, remove it.
  4703. //
  4704. if (Dereference)
  4705. {
  4706. DEREFERENCE_CONNECTION(pConnection);
  4707. }
  4708. } // UlpUnbindConnectionFromEndpoint
  4709. /***************************************************************************++
  4710. Routine Description:
  4711. Convert the input url to a TA_IP_ADDRESS.
  4712. Arguments:
  4713. pUrl - Supplies the URL to convert.
  4714. pAddress - Receives the address.
  4715. Return Value:
  4716. NTSTATUS - Completion status.
  4717. --***************************************************************************/
  4718. NTSTATUS
  4719. UlpUrlToAddress(
  4720. IN PWSTR pSiteUrl,
  4721. OUT PTA_IP_ADDRESS pAddress,
  4722. OUT PBOOLEAN pSecure
  4723. )
  4724. {
  4725. NTSTATUS status;
  4726. PWSTR pToken;
  4727. PWSTR pHost;
  4728. PWSTR pPort;
  4729. ULONG port;
  4730. UNICODE_STRING portString;
  4731. BOOLEAN secure;
  4732. //
  4733. // Sanity check.
  4734. //
  4735. PAGED_CODE();
  4736. ASSERT(pAddress);
  4737. ASSERT(pSecure);
  4738. //
  4739. // Find the first '/'.
  4740. //
  4741. pToken = wcschr(pSiteUrl, '/');
  4742. if (pToken == NULL)
  4743. {
  4744. return STATUS_INVALID_PARAMETER;
  4745. }
  4746. //
  4747. // Is this valid http url?
  4748. //
  4749. if (DIFF(pToken - pSiteUrl) == (sizeof(L"https:")-1)/sizeof(WCHAR))
  4750. {
  4751. if (_wcsnicmp(pSiteUrl, L"https:", (sizeof(L"https:")-1)/sizeof(WCHAR)) != 0)
  4752. {
  4753. return STATUS_INVALID_PARAMETER;
  4754. }
  4755. secure = TRUE;
  4756. }
  4757. else if (DIFF(pToken - pSiteUrl) == (sizeof(L"http:")-1)/sizeof(WCHAR))
  4758. {
  4759. if (_wcsnicmp(pSiteUrl, L"http:", (sizeof(L"http:")-1)/sizeof(WCHAR)) != 0)
  4760. {
  4761. return STATUS_INVALID_PARAMETER;
  4762. }
  4763. secure = FALSE;
  4764. }
  4765. else
  4766. {
  4767. return STATUS_INVALID_PARAMETER;
  4768. }
  4769. //
  4770. // Parse out the host name.
  4771. //
  4772. //
  4773. // Skip the second '/'.
  4774. //
  4775. if (pToken[1] != '/')
  4776. {
  4777. return STATUS_INVALID_PARAMETER;
  4778. }
  4779. pToken += 2;
  4780. pHost = pToken;
  4781. //
  4782. // Find the ':'.
  4783. //
  4784. pToken = wcschr(pToken, ':');
  4785. if (pToken == NULL)
  4786. {
  4787. return STATUS_INVALID_PARAMETER;
  4788. }
  4789. pToken += 1;
  4790. pPort = pToken;
  4791. //
  4792. // Find the end of the string (either UNICODE_NULL or '/' terminated).
  4793. //
  4794. while (pToken[0] != UNICODE_NULL && pToken[0] != L'/')
  4795. {
  4796. pToken += 1;
  4797. }
  4798. //
  4799. // Compute the port #.
  4800. //
  4801. portString.Buffer = pPort;
  4802. portString.Length = DIFF(pToken - pPort) * sizeof(WCHAR);
  4803. status = RtlUnicodeStringToInteger(&portString, 10, &port);
  4804. if (NT_SUCCESS(status) == FALSE)
  4805. {
  4806. return status;
  4807. }
  4808. if (port > 0xffff)
  4809. {
  4810. return STATUS_INVALID_PARAMETER;
  4811. }
  4812. //
  4813. // Is this an IP address or hostname?
  4814. //
  4815. //
  4816. // CODEWORK: crack the ip address out
  4817. //
  4818. UlInitializeIpTransportAddress(pAddress, 0, (USHORT)port);
  4819. *pSecure = secure;
  4820. return STATUS_SUCCESS;
  4821. } // UlpUrlToAddress
  4822. /***************************************************************************++
  4823. Routine Description:
  4824. Scan the endpoint list looking for one corresponding to the supplied
  4825. address.
  4826. Note: This routine assumes the TDI spinlock is held.
  4827. Arguments:
  4828. pAddress - Supplies the address to search for.
  4829. AddressLength - Supplies the length of the address structure.
  4830. Return Value:
  4831. PUL_ENDPOINT - The corresponding endpoint if successful, NULL otherwise.
  4832. --***************************************************************************/
  4833. PUL_ENDPOINT
  4834. UlpFindEndpointForAddress(
  4835. IN PTRANSPORT_ADDRESS pAddress,
  4836. IN ULONG AddressLength
  4837. )
  4838. {
  4839. PUL_ENDPOINT pEndpoint;
  4840. PLIST_ENTRY pListEntry;
  4841. //
  4842. // Sanity check.
  4843. //
  4844. ASSERT( UlDbgSpinLockOwned( &g_TdiSpinLock ) );
  4845. ASSERT( AddressLength == sizeof(TA_IP_ADDRESS) );
  4846. //
  4847. // Scan the endpoint list.
  4848. //
  4849. // CODEWORK: linear searches are BAD, if the list grows long.
  4850. // May need to augment this with a hash table or something.
  4851. //
  4852. for (pListEntry = g_TdiEndpointListHead.Flink ;
  4853. pListEntry != &g_TdiEndpointListHead ;
  4854. pListEntry = pListEntry->Flink)
  4855. {
  4856. pEndpoint = CONTAINING_RECORD(
  4857. pListEntry,
  4858. UL_ENDPOINT,
  4859. GlobalEndpointListEntry
  4860. );
  4861. if (pEndpoint->LocalAddressLength == AddressLength &&
  4862. RtlEqualMemory(pEndpoint->pLocalAddress, pAddress, AddressLength))
  4863. {
  4864. //
  4865. // Found the address; return it.
  4866. //
  4867. return pEndpoint;
  4868. }
  4869. }
  4870. //
  4871. // If we made it this far, then we did not find the address.
  4872. //
  4873. return NULL;
  4874. } // UlpFindEndpointForAddress
  4875. /***************************************************************************++
  4876. Routine Description:
  4877. Completion handler for synthetic synchronous IRPs.
  4878. Arguments:
  4879. pCompletionContext - Supplies an uninterpreted context value
  4880. as passed to the asynchronous API. In this case, this is
  4881. a pointer to a UL_STATUS_BLOCK structure.
  4882. Status - Supplies the final completion status of the
  4883. asynchronous API.
  4884. Information - Optionally supplies additional information about
  4885. the completed operation, such as the number of bytes
  4886. transferred. This field is unused for UlCloseListeningEndpoint().
  4887. --***************************************************************************/
  4888. VOID
  4889. UlpSynchronousIoComplete(
  4890. IN PVOID pCompletionContext,
  4891. IN NTSTATUS Status,
  4892. IN ULONG_PTR Information
  4893. )
  4894. {
  4895. PUL_STATUS_BLOCK pStatus;
  4896. //
  4897. // Snag the status block pointer.
  4898. //
  4899. pStatus = (PUL_STATUS_BLOCK)pCompletionContext;
  4900. //
  4901. // Update the completion status and signal the event.
  4902. //
  4903. UlSignalStatusBlock( pStatus, Status, Information );
  4904. } // UlpSynchronousIoComplete
  4905. /***************************************************************************++
  4906. Routine Description:
  4907. Enable/disable Nagle's Algorithm on the specified TDI connection object.
  4908. Arguments:
  4909. pTdiObject - Supplies the TDI connection object to manipulate.
  4910. Flag - Supplies TRUE to enable Nagling, FALSE to disable it.
  4911. Return Value:
  4912. NTSTATUS - Completion status.
  4913. --***************************************************************************/
  4914. NTSTATUS
  4915. UlpSetNagling(
  4916. IN PUX_TDI_OBJECT pTdiObject,
  4917. IN BOOLEAN Flag
  4918. )
  4919. {
  4920. NTSTATUS status;
  4921. IO_STATUS_BLOCK ioStatusBlock;
  4922. PTCP_REQUEST_SET_INFORMATION_EX pSetInfoEx;
  4923. ULONG value;
  4924. UCHAR buffer[sizeof(*pSetInfoEx) - sizeof(pSetInfoEx->Buffer) + sizeof(value)];
  4925. //
  4926. // Sanity check.
  4927. //
  4928. PAGED_CODE();
  4929. ASSERT( IS_VALID_TDI_OBJECT( pTdiObject ) );
  4930. //
  4931. // Note: NODELAY semantics are inverted from the usual enable/disable
  4932. // semantics.
  4933. //
  4934. value = (ULONG)!Flag;
  4935. //
  4936. // Setup the buffer.
  4937. //
  4938. pSetInfoEx = (PTCP_REQUEST_SET_INFORMATION_EX)buffer;
  4939. pSetInfoEx->ID.toi_entity.tei_entity = CO_TL_ENTITY;
  4940. pSetInfoEx->ID.toi_entity.tei_instance = TL_INSTANCE;
  4941. pSetInfoEx->ID.toi_class = INFO_CLASS_PROTOCOL;
  4942. pSetInfoEx->ID.toi_type = INFO_TYPE_CONNECTION;
  4943. pSetInfoEx->ID.toi_id = TCP_SOCKET_NODELAY;
  4944. pSetInfoEx->BufferSize = sizeof(value);
  4945. RtlCopyMemory( pSetInfoEx->Buffer, &value, sizeof(value) );
  4946. UlAttachToSystemProcess();
  4947. status = ZwDeviceIoControlFile(
  4948. pTdiObject->Handle, // FileHandle
  4949. NULL, // Event
  4950. NULL, // ApcRoutine
  4951. NULL, // ApcContext
  4952. &ioStatusBlock, // IoStatusBlock
  4953. IOCTL_TCP_SET_INFORMATION_EX, // IoControlCode
  4954. pSetInfoEx, // InputBuffer
  4955. sizeof(buffer), // InputBufferLength
  4956. NULL, // OutputBuffer
  4957. 0 // OutputBufferLength
  4958. );
  4959. if (status == STATUS_PENDING)
  4960. {
  4961. status = ZwWaitForSingleObject(
  4962. pTdiObject->Handle, // Handle
  4963. TRUE, // Alertable
  4964. NULL // Timeout
  4965. );
  4966. ASSERT( NT_SUCCESS(status) );
  4967. status = ioStatusBlock.Status;
  4968. }
  4969. UlDetachFromSystemProcess();
  4970. return status;
  4971. } // UlpSetNagling
  4972. /***************************************************************************++
  4973. Routine Description:
  4974. Query the TCP fast send routine if fast send is possible.
  4975. Arguments:
  4976. Return Value:
  4977. --***************************************************************************/
  4978. NTSTATUS
  4979. UlpQueryTcpFastSend()
  4980. {
  4981. UNICODE_STRING TCPDeviceName;
  4982. PFILE_OBJECT pTCPFileObject;
  4983. PDEVICE_OBJECT pTCPDeviceObject;
  4984. PIRP Irp;
  4985. IO_STATUS_BLOCK StatusBlock;
  4986. KEVENT Event;
  4987. NTSTATUS status;
  4988. RtlInitUnicodeString(&TCPDeviceName, DD_TCP_DEVICE_NAME);
  4989. status = IoGetDeviceObjectPointer(
  4990. &TCPDeviceName,
  4991. FILE_ALL_ACCESS,
  4992. &pTCPFileObject,
  4993. &pTCPDeviceObject
  4994. );
  4995. if (!NT_SUCCESS(status))
  4996. {
  4997. return status;
  4998. }
  4999. KeInitializeEvent(&Event, SynchronizationEvent, FALSE);
  5000. Irp = IoBuildDeviceIoControlRequest(
  5001. IOCTL_TDI_QUERY_DIRECT_SEND_HANDLER,
  5002. pTCPDeviceObject,
  5003. &g_TcpFastSend,
  5004. sizeof(g_TcpFastSend),
  5005. NULL,
  5006. 0,
  5007. FALSE,
  5008. &Event,
  5009. &StatusBlock);
  5010. if (Irp)
  5011. {
  5012. status = UlCallDriver(pTCPDeviceObject, Irp);
  5013. if (status == STATUS_PENDING)
  5014. {
  5015. KeWaitForSingleObject(
  5016. &Event,
  5017. Executive,
  5018. KernelMode,
  5019. FALSE,
  5020. NULL
  5021. );
  5022. status = StatusBlock.Status;
  5023. }
  5024. }
  5025. else
  5026. {
  5027. status = STATUS_NO_MEMORY;
  5028. }
  5029. ObDereferenceObject(pTCPFileObject);
  5030. return status;
  5031. } // UlpQueryTcpFastSend
  5032. /***************************************************************************++
  5033. Routine Description:
  5034. Build a receive buffer and IRP to TDI to get any pending data.
  5035. Arguments:
  5036. pTdiObject - Supplies the TDI connection object to manipulate.
  5037. pConnection - Supplies the UL_CONNECTION object.
  5038. Return Value:
  5039. NTSTATUS - Completion status.
  5040. --***************************************************************************/
  5041. NTSTATUS
  5042. UlpBuildTdiReceiveBuffer(
  5043. IN PUX_TDI_OBJECT pTdiObject,
  5044. IN PUL_CONNECTION pConnection,
  5045. OUT PIRP *pIrp
  5046. )
  5047. {
  5048. PUL_RECEIVE_BUFFER pBuffer;
  5049. pBuffer = UlPplAllocateReceiveBuffer();
  5050. if (pBuffer != NULL)
  5051. {
  5052. //
  5053. // Finish initializing the buffer and the IRP.
  5054. //
  5055. REFERENCE_CONNECTION( pConnection );
  5056. pBuffer->pConnectionContext = pConnection;
  5057. pBuffer->UnreadDataLength = 0;
  5058. TdiBuildReceive(
  5059. pBuffer->pIrp, // Irp
  5060. pTdiObject->pDeviceObject, // DeviceObject
  5061. pTdiObject->pFileObject, // FileObject
  5062. &UlpRestartReceive, // CompletionRoutine
  5063. pBuffer, // CompletionContext
  5064. pBuffer->pMdl, // MdlAddress
  5065. TDI_RECEIVE_NORMAL, // Flags
  5066. g_UlReceiveBufferSize // Length
  5067. );
  5068. UlTrace(TDI, (
  5069. "UlpBuildTdiReceiveBuffer: connection %p, "
  5070. "allocated irp %p to grab more data\n",
  5071. (PVOID)pConnection,
  5072. pBuffer->pIrp
  5073. ));
  5074. //
  5075. // We must trace the IRP before we set the next stack
  5076. // location so the trace code can pull goodies from the
  5077. // IRP correctly.
  5078. //
  5079. TRACE_IRP( IRP_ACTION_CALL_DRIVER, pBuffer->pIrp );
  5080. //
  5081. // Pass the IRP back to the transport.
  5082. //
  5083. *pIrp = pBuffer->pIrp;
  5084. return STATUS_MORE_PROCESSING_REQUIRED;
  5085. }
  5086. return STATUS_INSUFFICIENT_RESOURCES;
  5087. } // UlpBuildTdiReceiveBuffer
  5088. /***************************************************************************++
  5089. Routine Description:
  5090. Returns the length required for HTTP_RAW_CONNECTION
  5091. Arguments:
  5092. pConnectionContext - Pointer to the UL_CONNECTION
  5093. --***************************************************************************/
  5094. ULONG
  5095. UlpComputeHttpRawConnectionLength(
  5096. IN PVOID pConnectionContext
  5097. )
  5098. {
  5099. return (sizeof(HTTP_RAW_CONNECTION_INFO) +
  5100. sizeof(HTTP_NETWORK_ADDRESS_IPV4) * 2
  5101. );
  5102. }
  5103. /***************************************************************************++
  5104. Routine Description:
  5105. Builds the HTTP_RAW_CONNECTION structure
  5106. Arguments:
  5107. pContext - Pointer to the UL_CONNECTION
  5108. pKernelBuffer - Pointer to kernel buffer
  5109. pUserBuffer - Pointer to user buffer
  5110. OutputBufferLength - Length of output buffer
  5111. pBuffer - Buffer for holding any data
  5112. InitialLength - Size of input data.
  5113. --***************************************************************************/
  5114. ULONG
  5115. UlpGenerateHttpRawConnectionInfo(
  5116. IN PVOID pContext,
  5117. IN PUCHAR pKernelBuffer,
  5118. IN PVOID pUserBuffer,
  5119. IN ULONG OutputBufferLength,
  5120. IN PUCHAR pBuffer,
  5121. IN ULONG InitialLength
  5122. )
  5123. {
  5124. PHTTP_RAW_CONNECTION_INFO pConnInfo;
  5125. PHTTP_NETWORK_ADDRESS_IPV4 pLocalAddress;
  5126. PHTTP_NETWORK_ADDRESS_IPV4 pRemoteAddress;
  5127. PHTTP_TRANSPORT_ADDRESS pAddress;
  5128. ULONG BytesCopied = 0;
  5129. PUCHAR pInitialData;
  5130. PUL_CONNECTION pConnection = (PUL_CONNECTION) pContext;
  5131. ASSERT( IS_VALID_CONNECTION( pConnection ) );
  5132. pConnInfo = (PHTTP_RAW_CONNECTION_INFO) pKernelBuffer;
  5133. pLocalAddress = (PHTTP_NETWORK_ADDRESS_IPV4)( pConnInfo + 1 );
  5134. pRemoteAddress = pLocalAddress + 1;
  5135. pInitialData = (PUCHAR) (pRemoteAddress + 1);
  5136. //
  5137. // Now fill in the raw connection data structure.
  5138. // BUGBUG: handle other address types.
  5139. //
  5140. pConnInfo->ConnectionId = pConnection->FilterInfo.ConnectionId;
  5141. pAddress = &pConnInfo->Address;
  5142. pAddress->RemoteAddressLength = sizeof(HTTP_NETWORK_ADDRESS_IPV4);
  5143. pAddress->RemoteAddressType = HTTP_NETWORK_ADDRESS_TYPE_IPV4;
  5144. pAddress->pRemoteAddress = FIXUP_PTR(
  5145. PVOID,
  5146. pUserBuffer,
  5147. pKernelBuffer,
  5148. pRemoteAddress,
  5149. OutputBufferLength
  5150. );
  5151. pAddress->LocalAddressLength = sizeof(HTTP_NETWORK_ADDRESS_IPV4);
  5152. pAddress->LocalAddressType = HTTP_NETWORK_ADDRESS_TYPE_IPV4;
  5153. pAddress->pLocalAddress = FIXUP_PTR(
  5154. PVOID,
  5155. pUserBuffer,
  5156. pKernelBuffer,
  5157. pLocalAddress,
  5158. OutputBufferLength
  5159. );
  5160. pRemoteAddress->IpAddress = pConnection->RemoteAddress;
  5161. pRemoteAddress->Port = pConnection->RemotePort;
  5162. pLocalAddress->IpAddress = pConnection->LocalAddress;
  5163. pLocalAddress->Port = pConnection->LocalPort;
  5164. //
  5165. // Copy any initial data.
  5166. //
  5167. if (InitialLength)
  5168. {
  5169. ASSERT(pBuffer);
  5170. pConnInfo->InitialDataSize = InitialLength;
  5171. pConnInfo->pInitialData = FIXUP_PTR(
  5172. PVOID, // Type
  5173. pUserBuffer, // pUserPtr
  5174. pKernelBuffer, // pKernelPtr
  5175. pInitialData, // pOffsetPtr
  5176. OutputBufferLength // BufferLength
  5177. );
  5178. RtlCopyMemory(
  5179. pInitialData,
  5180. pBuffer,
  5181. InitialLength
  5182. );
  5183. BytesCopied += InitialLength;
  5184. }
  5185. return BytesCopied;
  5186. }