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.

1767 lines
48 KiB

  1. /*++
  2. Copyright (c) 1992 Microsoft Corporation
  3. Module Name:
  4. blkconn.c
  5. Abstract:
  6. This module contains allocate, free, close, reference, and dereference
  7. routines for AFD connections.
  8. Author:
  9. David Treadwell (davidtr) 10-Mar-1992
  10. Revision History:
  11. --*/
  12. #include "afdp.h"
  13. VOID
  14. AfdFreeConnection (
  15. IN PVOID Context
  16. );
  17. VOID
  18. AfdFreeConnectionResources (
  19. PAFD_CONNECTION connection
  20. );
  21. VOID
  22. AfdFreeNPConnectionResources (
  23. PAFD_CONNECTION connection
  24. );
  25. VOID
  26. AfdRefreshConnection (
  27. PAFD_CONNECTION connection
  28. );
  29. PAFD_CONNECTION
  30. AfdReuseConnection (
  31. );
  32. #ifdef ALLOC_PRAGMA
  33. #pragma alloc_text( PAGEAFD, AfdAbortConnection )
  34. #pragma alloc_text( PAGE, AfdAddFreeConnection )
  35. #pragma alloc_text( PAGE, AfdAllocateConnection )
  36. #pragma alloc_text( PAGE, AfdCreateConnection )
  37. #pragma alloc_text( PAGE, AfdFreeConnection )
  38. #pragma alloc_text( PAGE, AfdFreeConnectionResources )
  39. #pragma alloc_text( PAGE, AfdReuseConnection )
  40. #pragma alloc_text( PAGEAFD, AfdRefreshConnection )
  41. #pragma alloc_text( PAGEAFD, AfdFreeNPConnectionResources )
  42. #pragma alloc_text( PAGEAFD, AfdGetConnectionReferenceFromEndpoint )
  43. #if REFERENCE_DEBUG
  44. #pragma alloc_text( PAGEAFD, AfdReferenceConnection )
  45. #pragma alloc_text( PAGEAFD, AfdDereferenceConnection )
  46. #else
  47. #pragma alloc_text( PAGEAFD, AfdCloseConnection )
  48. #endif
  49. #pragma alloc_text( PAGEAFD, AfdGetFreeConnection )
  50. #pragma alloc_text( PAGEAFD, AfdGetReturnedConnection )
  51. #pragma alloc_text( PAGEAFD, AfdFindReturnedConnection )
  52. #pragma alloc_text( PAGEAFD, AfdGetUnacceptedConnection )
  53. #pragma alloc_text( PAGEAFD, AfdAddConnectedReference )
  54. #pragma alloc_text( PAGEAFD, AfdDeleteConnectedReference )
  55. #endif
  56. #if GLOBAL_REFERENCE_DEBUG
  57. AFD_GLOBAL_REFERENCE_DEBUG AfdGlobalReference[MAX_GLOBAL_REFERENCE];
  58. LONG AfdGlobalReferenceSlot = -1;
  59. #endif
  60. #if AFD_PERF_DBG
  61. #define CONNECTION_REUSE_DISABLED (AfdDisableConnectionReuse)
  62. #else
  63. #define CONNECTION_REUSE_DISABLED (FALSE)
  64. #endif
  65. VOID
  66. AfdAbortConnection (
  67. IN PAFD_CONNECTION Connection
  68. )
  69. {
  70. NTSTATUS status;
  71. ASSERT( Connection != NULL );
  72. ASSERT( Connection->ConnectedReferenceAdded );
  73. //
  74. // Abort the connection. We need to set the CleanupBegun flag
  75. // before initiating the abort so that the connected reference
  76. // will get properly removed in AfdRestartAbort.
  77. //
  78. // Note that if AfdBeginAbort fails then AfdRestartAbort will not
  79. // get invoked, so we must remove the connected reference ourselves.
  80. //
  81. Connection->CleanupBegun = TRUE;
  82. status = AfdBeginAbort( Connection );
  83. if( !NT_SUCCESS(status) ) {
  84. AfdDeleteConnectedReference( Connection, FALSE );
  85. }
  86. //
  87. // Remove the active reference.
  88. //
  89. DEREFERENCE_CONNECTION( Connection );
  90. } // AfdAbortConnection
  91. NTSTATUS
  92. AfdAddFreeConnection (
  93. IN PAFD_ENDPOINT Endpoint
  94. )
  95. /*++
  96. Routine Description:
  97. Adds a connection object to an endpoints pool of connections available
  98. to satisfy a connect indication.
  99. Arguments:
  100. Endpoint - a pointer to the endpoint to which to add a connection.
  101. Return Value:
  102. NTSTATUS -- Indicates the status of the request.
  103. --*/
  104. {
  105. PAFD_CONNECTION connection;
  106. NTSTATUS status;
  107. PAGED_CODE( );
  108. ASSERT( Endpoint->Type == AfdBlockTypeVcListening ||
  109. Endpoint->Type == AfdBlockTypeVcBoth );
  110. //
  111. // Create a new connection block and associated connection object.
  112. //
  113. status = AfdCreateConnection(
  114. &Endpoint->TransportInfo->TransportDeviceName,
  115. Endpoint->AddressHandle,
  116. IS_TDI_BUFFERRING(Endpoint),
  117. Endpoint->InLine,
  118. Endpoint->OwningProcess,
  119. &connection
  120. );
  121. if ( NT_SUCCESS(status) ) {
  122. ASSERT( IS_TDI_BUFFERRING(Endpoint) == connection->TdiBufferring );
  123. if (IS_DELAYED_ACCEPTANCE_ENDPOINT (Endpoint)) {
  124. status = AfdDelayedAcceptListen (Endpoint, connection);
  125. if (!NT_SUCCESS (status)) {
  126. DEREFERENCE_CONNECTION (connection);
  127. }
  128. }
  129. else {
  130. //
  131. // Set up the handle in the listening connection structure and place
  132. // the connection on the endpoint's list of listening connections.
  133. //
  134. ASSERT (connection->Endpoint==NULL);
  135. InterlockedPushEntrySList(
  136. &Endpoint->Common.VcListening.FreeConnectionListHead,
  137. &connection->SListEntry);
  138. status = STATUS_SUCCESS;
  139. }
  140. }
  141. return status;
  142. } // AfdAddFreeConnection
  143. PAFD_CONNECTION
  144. AfdAllocateConnection (
  145. VOID
  146. )
  147. {
  148. PAFD_CONNECTION connection;
  149. PAGED_CODE( );
  150. if ((AfdConnectionsFreeing<AFD_CONNECTIONS_FREEING_MAX)
  151. || ((connection = AfdReuseConnection ())==NULL)) {
  152. //
  153. // Allocate a buffer to hold the connection structure.
  154. //
  155. connection = AFD_ALLOCATE_POOL(
  156. NonPagedPool,
  157. sizeof(AFD_CONNECTION),
  158. AFD_CONNECTION_POOL_TAG
  159. );
  160. if ( connection == NULL ) {
  161. return NULL;
  162. }
  163. }
  164. RtlZeroMemory( connection, sizeof(AFD_CONNECTION) );
  165. //
  166. // Initialize the reference count to 1 to account for the caller's
  167. // reference. Connection blocks are temporary--as soon as the last
  168. // reference goes away, so does the connection. There is no active
  169. // reference on a connection block.
  170. //
  171. connection->ReferenceCount = 1;
  172. //
  173. // Initialize the connection structure.
  174. //
  175. connection->Type = AfdBlockTypeConnection;
  176. connection->State = AfdConnectionStateFree;
  177. //connection->Handle = NULL;
  178. //connection->FileObject = NULL;
  179. //connection->RemoteAddress = NULL;
  180. //connection->Endpoint = NULL;
  181. //connection->ReceiveBytesIndicated = 0;
  182. //connection->ReceiveBytesTaken = 0;
  183. //connection->ReceiveBytesOutstanding = 0;
  184. //connection->ReceiveExpeditedBytesIndicated = 0;
  185. //connection->ReceiveExpeditedBytesTaken = 0;
  186. //connection->ReceiveExpeditedBytesOutstanding = 0;
  187. //connection->ConnectDataBuffers = NULL;
  188. //connection->DisconnectIndicated = FALSE;
  189. //connection->AbortIndicated = FALSE;
  190. //connection->ConnectedReferenceAdded = FALSE;
  191. //connection->SpecialCondition = FALSE;
  192. //connection->CleanupBegun = FALSE;
  193. //connection->OwningProcess = NULL;
  194. //connection->ClosePendedTransmit = FALSE;
  195. #if REFERENCE_DEBUG
  196. connection->CurrentReferenceSlot = -1;
  197. RtlZeroMemory(
  198. &connection->ReferenceDebug,
  199. sizeof(AFD_REFERENCE_DEBUG) * MAX_REFERENCE
  200. );
  201. #endif
  202. //
  203. // Return a pointer to the new connection to the caller.
  204. //
  205. IF_DEBUG(CONNECTION) {
  206. KdPrintEx(( DPFLTR_WSOCKTRANSPORT_ID, DPFLTR_TRACE_LEVEL,
  207. "AfdAllocateConnection: connection at %p\n", connection ));
  208. }
  209. return connection;
  210. } // AfdAllocateConnection
  211. NTSTATUS
  212. AfdCreateConnection (
  213. IN PUNICODE_STRING TransportDeviceName,
  214. IN HANDLE AddressHandle,
  215. IN BOOLEAN TdiBufferring,
  216. IN LOGICAL InLine,
  217. IN PEPROCESS ProcessToCharge,
  218. OUT PAFD_CONNECTION *Connection
  219. )
  220. /*++
  221. Routine Description:
  222. Allocates a connection block and creates a connection object to
  223. go with the block. This routine also associates the connection
  224. with the specified address handle (if any).
  225. Arguments:
  226. TransportDeviceName - Name to use when creating the connection object.
  227. AddressHandle - a handle to an address object for the specified
  228. transport. If specified (non NULL), the connection object that
  229. is created is associated with the address object.
  230. TdiBufferring - whether the TDI provider supports data bufferring.
  231. Only passed so that it can be stored in the connection
  232. structure.
  233. InLine - if TRUE, the endpoint should be created in OOB inline
  234. mode.
  235. ProcessToCharge - the process which should be charged the quota
  236. for this connection.
  237. Connection - receives a pointer to the new connection.
  238. Return Value:
  239. NTSTATUS -- Indicates the status of the request.
  240. --*/
  241. {
  242. NTSTATUS status;
  243. IO_STATUS_BLOCK ioStatusBlock;
  244. OBJECT_ATTRIBUTES objectAttributes;
  245. CHAR eaBuffer[sizeof(FILE_FULL_EA_INFORMATION) - 1 +
  246. TDI_CONNECTION_CONTEXT_LENGTH + 1 +
  247. sizeof(CONNECTION_CONTEXT)];
  248. PFILE_FULL_EA_INFORMATION ea;
  249. CONNECTION_CONTEXT UNALIGNED *ctx;
  250. PAFD_CONNECTION connection;
  251. PAGED_CODE( );
  252. //
  253. // Attempt to charge this process quota for the data bufferring we
  254. // will do on its behalf.
  255. //
  256. status = PsChargeProcessPoolQuota(
  257. ProcessToCharge,
  258. NonPagedPool,
  259. sizeof (AFD_CONNECTION)
  260. );
  261. if (!NT_SUCCESS (status)) {
  262. KdPrintEx(( DPFLTR_WSOCKTRANSPORT_ID, DPFLTR_INFO_LEVEL,
  263. "AfdCreateConnection: PsChargeProcessPoolQuota failed.\n" ));
  264. return status;
  265. }
  266. //
  267. // Allocate a connection block.
  268. //
  269. connection = AfdAllocateConnection( );
  270. if ( connection == NULL ) {
  271. PsReturnPoolQuota(
  272. ProcessToCharge,
  273. NonPagedPool,
  274. sizeof (AFD_CONNECTION)
  275. );
  276. return STATUS_INSUFFICIENT_RESOURCES;
  277. }
  278. AfdRecordQuotaHistory(
  279. ProcessToCharge,
  280. (LONG)sizeof (AFD_CONNECTION),
  281. "CreateConn ",
  282. connection
  283. );
  284. AfdRecordPoolQuotaCharged(sizeof (AFD_CONNECTION));
  285. //
  286. // Remember the process that got charged the pool quota for this
  287. // connection object. Also reference the process to which we're
  288. // going to charge the quota so that it is still around when we
  289. // return the quota.
  290. //
  291. ASSERT( connection->OwningProcess == NULL );
  292. connection->OwningProcess = ProcessToCharge;
  293. ObReferenceObject( ProcessToCharge );
  294. //
  295. // If the provider does not buffer, initialize appropriate lists in
  296. // the connection object.
  297. //
  298. connection->TdiBufferring = TdiBufferring;
  299. if ( !TdiBufferring ) {
  300. InitializeListHead( &connection->VcReceiveIrpListHead );
  301. InitializeListHead( &connection->VcSendIrpListHead );
  302. InitializeListHead( &connection->VcReceiveBufferListHead );
  303. connection->VcBufferredReceiveBytes = 0;
  304. connection->VcBufferredExpeditedBytes = 0;
  305. connection->VcBufferredReceiveCount = 0;
  306. connection->VcBufferredExpeditedCount = 0;
  307. connection->VcReceiveBytesInTransport = 0;
  308. #if DBG
  309. connection->VcReceiveIrpsInTransport = 0;
  310. #endif
  311. connection->VcBufferredSendBytes = 0;
  312. connection->VcBufferredSendCount = 0;
  313. } else {
  314. connection->VcNonBlockingSendPossible = TRUE;
  315. connection->VcZeroByteReceiveIndicated = FALSE;
  316. }
  317. //
  318. // Set up the send and receive window with default maximums.
  319. //
  320. connection->MaxBufferredReceiveBytes = AfdReceiveWindowSize;
  321. connection->MaxBufferredSendBytes = AfdSendWindowSize;
  322. //
  323. // We need to open a connection object to the TDI provider for this
  324. // endpoint. First create the EA for the connection context and the
  325. // object attributes structure which will be used for all the
  326. // connections we open here.
  327. //
  328. ea = (PFILE_FULL_EA_INFORMATION)eaBuffer;
  329. ea->NextEntryOffset = 0;
  330. ea->Flags = 0;
  331. ea->EaNameLength = TDI_CONNECTION_CONTEXT_LENGTH;
  332. ea->EaValueLength = sizeof(CONNECTION_CONTEXT);
  333. RtlMoveMemory( ea->EaName, TdiConnectionContext, ea->EaNameLength + 1 );
  334. //
  335. // Use the pointer to the connection block as the connection context.
  336. //
  337. ctx = (CONNECTION_CONTEXT UNALIGNED *)&ea->EaName[ea->EaNameLength + 1];
  338. *ctx = (CONNECTION_CONTEXT)connection;
  339. // We ask to create a kernel handle which is
  340. // the handle in the context of the system process
  341. // so that application cannot close it on us while
  342. // we are creating and referencing it.
  343. InitializeObjectAttributes(
  344. &objectAttributes,
  345. TransportDeviceName,
  346. OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, // attributes
  347. NULL,
  348. NULL
  349. );
  350. //
  351. // Do the actual open of the connection object.
  352. //
  353. status = IoCreateFile(
  354. &connection->Handle,
  355. GENERIC_READ | GENERIC_WRITE | SYNCHRONIZE,
  356. &objectAttributes,
  357. &ioStatusBlock,
  358. NULL, // AllocationSize
  359. 0, // FileAttributes
  360. 0, // ShareAccess
  361. FILE_CREATE, // CreateDisposition
  362. 0, // CreateOptions
  363. eaBuffer,
  364. FIELD_OFFSET( FILE_FULL_EA_INFORMATION, EaName[0] ) +
  365. ea->EaNameLength + 1 + ea->EaValueLength,
  366. CreateFileTypeNone, // CreateFileType
  367. NULL, // ExtraCreateParameters
  368. IO_NO_PARAMETER_CHECKING // Options
  369. );
  370. if ( NT_SUCCESS(status) ) {
  371. status = ioStatusBlock.Status;
  372. }
  373. if ( !NT_SUCCESS(status) ) {
  374. DEREFERENCE_CONNECTION( connection );
  375. return status;
  376. }
  377. #if DBG
  378. {
  379. NTSTATUS status1;
  380. OBJECT_HANDLE_FLAG_INFORMATION handleInfo;
  381. handleInfo.Inherit = FALSE;
  382. handleInfo.ProtectFromClose = TRUE;
  383. status1 = ZwSetInformationObject (
  384. connection->Handle,
  385. ObjectHandleFlagInformation,
  386. &handleInfo,
  387. sizeof (handleInfo)
  388. );
  389. ASSERT (NT_SUCCESS (status1));
  390. }
  391. #endif
  392. AfdRecordConnOpened();
  393. //
  394. // Reference the connection's file object.
  395. //
  396. status = ObReferenceObjectByHandle(
  397. connection->Handle,
  398. 0,
  399. (POBJECT_TYPE) NULL,
  400. KernelMode,
  401. (PVOID *)&connection->FileObject,
  402. NULL
  403. );
  404. ASSERT( NT_SUCCESS(status) );
  405. IF_DEBUG(OPEN_CLOSE) {
  406. KdPrintEx(( DPFLTR_WSOCKTRANSPORT_ID, DPFLTR_TRACE_LEVEL,
  407. "AfdCreateConnection: file object for connection %p at %p\n",
  408. connection, connection->FileObject ));
  409. }
  410. AfdRecordConnRef();
  411. //
  412. // Remember the device object to which we need to give requests for
  413. // this connection object. We can't just use the
  414. // fileObject->DeviceObject pointer because there may be a device
  415. // attached to the transport protocol.
  416. //
  417. connection->DeviceObject =
  418. IoGetRelatedDeviceObject( connection->FileObject );
  419. //
  420. // Associate the connection with the address object on the endpoint if
  421. // an address handle was specified.
  422. //
  423. if ( AddressHandle != NULL ) {
  424. TDI_REQUEST_KERNEL_ASSOCIATE associateRequest;
  425. associateRequest.AddressHandle = AddressHandle;
  426. status = AfdIssueDeviceControl(
  427. connection->FileObject,
  428. &associateRequest,
  429. sizeof (associateRequest),
  430. NULL,
  431. 0,
  432. TDI_ASSOCIATE_ADDRESS
  433. );
  434. if ( !NT_SUCCESS(status) ) {
  435. DEREFERENCE_CONNECTION( connection );
  436. return status;
  437. }
  438. }
  439. //
  440. // If requested, set the connection to be inline.
  441. //
  442. if ( InLine ) {
  443. status = AfdSetInLineMode( connection, TRUE );
  444. if ( !NT_SUCCESS(status) ) {
  445. DEREFERENCE_CONNECTION( connection );
  446. return status;
  447. }
  448. }
  449. //
  450. // Set up the connection pointer and return.
  451. //
  452. *Connection = connection;
  453. UPDATE_CONN2( connection, "Connection object handle: %lx", HandleToUlong (connection->Handle));
  454. return STATUS_SUCCESS;
  455. } // AfdCreateConnection
  456. VOID
  457. AfdFreeConnection (
  458. IN PVOID Context
  459. )
  460. {
  461. PAFD_CONNECTION connection;
  462. PAFD_ENDPOINT listenEndpoint;
  463. PAGED_CODE( );
  464. InterlockedDecrement (&AfdConnectionsFreeing);
  465. ASSERT( Context != NULL );
  466. connection = CONTAINING_RECORD(
  467. Context,
  468. AFD_CONNECTION,
  469. WorkItem
  470. );
  471. if (connection->Endpoint != NULL &&
  472. !CONNECTION_REUSE_DISABLED &&
  473. !connection->Endpoint->EndpointCleanedUp &&
  474. connection->Endpoint->Type == AfdBlockTypeVcConnecting &&
  475. (listenEndpoint=connection->Endpoint->Common.VcConnecting.ListenEndpoint) != NULL &&
  476. -listenEndpoint->Common.VcListening.FailedConnectionAdds <
  477. listenEndpoint->Common.VcListening.MaxExtraConnections &&
  478. (IS_DELAYED_ACCEPTANCE_ENDPOINT (listenEndpoint) ||
  479. ExQueryDepthSList (
  480. &listenEndpoint->Common.VcListening.FreeConnectionListHead)
  481. < AFD_MAXIMUM_FREE_CONNECTIONS ) ) {
  482. AfdRefreshConnection (connection);
  483. }
  484. else {
  485. AfdFreeConnectionResources (connection);
  486. //
  487. // Free the space that holds the connection itself.
  488. //
  489. IF_DEBUG(CONNECTION) {
  490. KdPrintEx(( DPFLTR_WSOCKTRANSPORT_ID, DPFLTR_TRACE_LEVEL,
  491. "AfdFreeConnection: Freeing connection at %p\n",
  492. connection ));
  493. }
  494. connection->Type = AfdBlockTypeInvalidConnection;
  495. AFD_FREE_POOL(
  496. connection,
  497. AFD_CONNECTION_POOL_TAG
  498. );
  499. }
  500. } // AfdFreeConnection
  501. PAFD_CONNECTION
  502. AfdReuseConnection (
  503. ) {
  504. PAFD_CONNECTION connection;
  505. PAFD_ENDPOINT listenEndpoint;
  506. PVOID Context;
  507. PAGED_CODE( );
  508. while ((Context = AfdGetWorkerByRoutine (AfdFreeConnection))!=NULL) {
  509. connection = CONTAINING_RECORD(
  510. Context,
  511. AFD_CONNECTION,
  512. WorkItem
  513. );
  514. if (connection->Endpoint != NULL &&
  515. !CONNECTION_REUSE_DISABLED &&
  516. !connection->Endpoint->EndpointCleanedUp &&
  517. connection->Endpoint->Type == AfdBlockTypeVcConnecting &&
  518. (listenEndpoint=connection->Endpoint->Common.VcConnecting.ListenEndpoint) != NULL &&
  519. -listenEndpoint->Common.VcListening.FailedConnectionAdds <
  520. listenEndpoint->Common.VcListening.MaxExtraConnections &&
  521. (IS_DELAYED_ACCEPTANCE_ENDPOINT (listenEndpoint) ||
  522. ExQueryDepthSList (
  523. &listenEndpoint->Common.VcListening.FreeConnectionListHead)
  524. < AFD_MAXIMUM_FREE_CONNECTIONS ) ) {
  525. AfdRefreshConnection (connection);
  526. }
  527. else {
  528. AfdFreeConnectionResources (connection);
  529. return connection;
  530. }
  531. }
  532. return NULL;
  533. }
  534. VOID
  535. AfdFreeNPConnectionResources (
  536. PAFD_CONNECTION connection
  537. )
  538. {
  539. if ( !connection->TdiBufferring && connection->VcDisconnectIrp != NULL ) {
  540. IoFreeIrp( connection->VcDisconnectIrp );
  541. connection->VcDisconnectIrp = NULL;
  542. }
  543. if ( connection->ConnectDataBuffers != NULL ) {
  544. AfdFreeConnectDataBuffers( connection->ConnectDataBuffers );
  545. connection->ConnectDataBuffers = NULL;
  546. }
  547. //
  548. // If this is a bufferring connection, remove all the AFD buffers
  549. // from the connection's lists and free them.
  550. //
  551. if ( !connection->TdiBufferring ) {
  552. PAFD_BUFFER_HEADER afdBuffer;
  553. PLIST_ENTRY listEntry;
  554. ASSERT( IsListEmpty( &connection->VcReceiveIrpListHead ) );
  555. ASSERT( IsListEmpty( &connection->VcSendIrpListHead ) );
  556. while ( !IsListEmpty( &connection->VcReceiveBufferListHead ) ) {
  557. listEntry = RemoveHeadList( &connection->VcReceiveBufferListHead );
  558. afdBuffer = CONTAINING_RECORD( listEntry, AFD_BUFFER_HEADER, BufferListEntry );
  559. ASSERT (afdBuffer->RefCount == 1);
  560. afdBuffer->ExpeditedData = FALSE;
  561. AfdReturnBuffer( afdBuffer, connection->OwningProcess );
  562. }
  563. }
  564. if ( connection->Endpoint != NULL ) {
  565. //
  566. // If there is a transmit file IRP on the endpoint, complete it.
  567. //
  568. if ( connection->ClosePendedTransmit ) {
  569. AfdCompleteClosePendedTPackets( connection->Endpoint );
  570. }
  571. DEREFERENCE_ENDPOINT( connection->Endpoint );
  572. connection->Endpoint = NULL;
  573. }
  574. }
  575. VOID
  576. AfdRefreshConnection (
  577. PAFD_CONNECTION connection
  578. )
  579. {
  580. PAFD_ENDPOINT listeningEndpoint;
  581. ASSERT( connection->ReferenceCount == 0 );
  582. ASSERT( connection->Type == AfdBlockTypeConnection );
  583. ASSERT( connection->OnLRList == FALSE );
  584. UPDATE_CONN( connection);
  585. //
  586. // Reference the listening endpoint so that it does not
  587. // go away while we are cleaning up this connection object
  588. // for reuse. Note that we actually have an implicit reference
  589. // to the listening endpoint through the connection's endpoint
  590. //
  591. listeningEndpoint = connection->Endpoint->Common.VcConnecting.ListenEndpoint;
  592. #if REFERENCE_DEBUG
  593. {
  594. BOOLEAN res;
  595. CHECK_REFERENCE_ENDPOINT (listeningEndpoint, res);
  596. ASSERT (res);
  597. }
  598. #else
  599. REFERENCE_ENDPOINT( listeningEndpoint );
  600. #endif
  601. ASSERT( listeningEndpoint->Type == AfdBlockTypeVcListening ||
  602. listeningEndpoint->Type == AfdBlockTypeVcBoth );
  603. AfdFreeNPConnectionResources (connection);
  604. //
  605. // Reinitialize various fields in the connection object.
  606. //
  607. connection->ReferenceCount = 1;
  608. ASSERT( connection->Type == AfdBlockTypeConnection );
  609. connection->State = AfdConnectionStateFree;
  610. connection->ConnectionStateFlags = 0;
  611. connection->TdiBufferring = IS_TDI_BUFFERRING (listeningEndpoint);
  612. if ( !connection->TdiBufferring ) {
  613. ASSERT( IsListEmpty( &connection->VcReceiveIrpListHead ) );
  614. ASSERT( IsListEmpty( &connection->VcSendIrpListHead ) );
  615. ASSERT( IsListEmpty( &connection->VcReceiveBufferListHead ) );
  616. connection->VcBufferredReceiveBytes = 0;
  617. connection->VcBufferredExpeditedBytes = 0;
  618. connection->VcBufferredReceiveCount = 0;
  619. connection->VcBufferredExpeditedCount = 0;
  620. connection->VcReceiveBytesInTransport = 0;
  621. #if DBG
  622. connection->VcReceiveIrpsInTransport = 0;
  623. #endif
  624. connection->VcBufferredSendBytes = 0;
  625. connection->VcBufferredSendCount = 0;
  626. } else {
  627. connection->VcNonBlockingSendPossible = TRUE;
  628. connection->VcZeroByteReceiveIndicated = FALSE;
  629. }
  630. if (IS_DELAYED_ACCEPTANCE_ENDPOINT (listeningEndpoint)) {
  631. NTSTATUS status;
  632. status = AfdDelayedAcceptListen (listeningEndpoint, connection);
  633. if (NT_SUCCESS (status)) {
  634. //
  635. // Reduce the count of failed connection adds on the listening
  636. // endpoint to account for this connection object which we're
  637. // adding back onto the queue.
  638. //
  639. InterlockedDecrement(
  640. &listeningEndpoint->Common.VcListening.FailedConnectionAdds
  641. );
  642. AfdRecordConnectionsReused ();
  643. }
  644. else {
  645. DEREFERENCE_CONNECTION (connection);
  646. }
  647. }
  648. else {
  649. //
  650. // Place the connection on the listening endpoint's list of
  651. // available connections.
  652. //
  653. ASSERT (connection->Endpoint == NULL);
  654. InterlockedPushEntrySList(
  655. &listeningEndpoint->Common.VcListening.FreeConnectionListHead,
  656. &connection->SListEntry);
  657. //
  658. // Reduce the count of failed connection adds on the listening
  659. // endpoint to account for this connection object which we're
  660. // adding back onto the queue.
  661. //
  662. InterlockedDecrement(
  663. &listeningEndpoint->Common.VcListening.FailedConnectionAdds
  664. );
  665. AfdRecordConnectionsReused ();
  666. }
  667. //
  668. // Get rid of the reference we added to the listening endpoint
  669. // above.
  670. //
  671. DEREFERENCE_ENDPOINT( listeningEndpoint );
  672. }
  673. VOID
  674. AfdFreeConnectionResources (
  675. PAFD_CONNECTION connection
  676. )
  677. {
  678. NTSTATUS status;
  679. PAGED_CODE( );
  680. ASSERT( connection->ReferenceCount == 0 );
  681. ASSERT( connection->Type == AfdBlockTypeConnection );
  682. ASSERT( connection->OnLRList == FALSE );
  683. UPDATE_CONN( connection );
  684. //
  685. // Free and dereference the various objects on the connection.
  686. // Close and dereference the TDI connection object on the endpoint,
  687. // if any.
  688. //
  689. if ( connection->Handle != NULL ) {
  690. //
  691. // Disassociate this connection object from the address object.
  692. //
  693. status = AfdIssueDeviceControl(
  694. connection->FileObject,
  695. NULL,
  696. 0,
  697. NULL,
  698. 0,
  699. TDI_DISASSOCIATE_ADDRESS
  700. );
  701. // ASSERT( NT_SUCCESS(status) );
  702. //
  703. // Close the handle.
  704. //
  705. #if DBG
  706. {
  707. NTSTATUS status1;
  708. OBJECT_HANDLE_FLAG_INFORMATION handleInfo;
  709. handleInfo.Inherit = FALSE;
  710. handleInfo.ProtectFromClose = FALSE;
  711. status1 = ZwSetInformationObject (
  712. connection->Handle,
  713. ObjectHandleFlagInformation,
  714. &handleInfo,
  715. sizeof (handleInfo)
  716. );
  717. ASSERT (NT_SUCCESS (status1));
  718. }
  719. #endif
  720. status = ZwClose( connection->Handle );
  721. #if DBG
  722. if (!NT_SUCCESS(status) ) {
  723. KdPrintEx(( DPFLTR_WSOCKTRANSPORT_ID, DPFLTR_ERROR_LEVEL,
  724. "AfdFreeConnectionResources: ZwClose() failed (%lx)\n",
  725. status));
  726. ASSERT (FALSE);
  727. }
  728. #endif
  729. AfdRecordConnClosed();
  730. }
  731. if ( connection->FileObject != NULL ) {
  732. ObDereferenceObject( connection->FileObject );
  733. connection->FileObject = NULL;
  734. AfdRecordConnDeref();
  735. }
  736. //
  737. // Free remaining buffers and return quota charges associated with them.
  738. //
  739. AfdFreeNPConnectionResources (connection);
  740. //
  741. // Return the quota we charged to this process when we allocated
  742. // the connection object and buffered data on it.
  743. //
  744. PsReturnPoolQuota(
  745. connection->OwningProcess,
  746. NonPagedPool,
  747. sizeof (AFD_CONNECTION)
  748. );
  749. AfdRecordQuotaHistory(
  750. connection->OwningProcess,
  751. -(LONG)sizeof (AFD_CONNECTION),
  752. "ConnDealloc ",
  753. connection
  754. );
  755. AfdRecordPoolQuotaReturned(
  756. sizeof (AFD_CONNECTION)
  757. );
  758. //
  759. // Dereference the process that got the quota charge.
  760. //
  761. ASSERT( connection->OwningProcess != NULL );
  762. ObDereferenceObject( connection->OwningProcess );
  763. connection->OwningProcess = NULL;
  764. if ( connection->RemoteAddress != NULL ) {
  765. AFD_RETURN_REMOTE_ADDRESS (
  766. connection->RemoteAddress,
  767. connection->RemoteAddressLength,
  768. );
  769. connection->RemoteAddress = NULL;
  770. }
  771. }
  772. #if REFERENCE_DEBUG
  773. VOID
  774. AfdReferenceConnection (
  775. IN PAFD_CONNECTION Connection,
  776. IN LONG LocationId,
  777. IN ULONG Param
  778. )
  779. {
  780. LONG result;
  781. ASSERT( Connection->Type == AfdBlockTypeConnection );
  782. ASSERT( Connection->ReferenceCount > 0 );
  783. ASSERT( Connection->ReferenceCount != 0xD1000000 );
  784. IF_DEBUG(CONNECTION) {
  785. KdPrintEx(( DPFLTR_WSOCKTRANSPORT_ID, DPFLTR_TRACE_LEVEL,
  786. "AfdReferenceConnection: connection %p, new refcnt %ld\n",
  787. Connection, Connection->ReferenceCount+1 ));
  788. }
  789. //
  790. // Do the actual increment of the reference count.
  791. //
  792. result = InterlockedIncrement( (PLONG)&Connection->ReferenceCount );
  793. #if REFERENCE_DEBUG
  794. AFD_UPDATE_REFERENCE_DEBUG(Connection, result, LocationId, Param)
  795. #endif
  796. } // AfdReferenceConnection
  797. #endif
  798. PAFD_CONNECTION
  799. AfdGetConnectionReferenceFromEndpoint (
  800. PAFD_ENDPOINT Endpoint
  801. )
  802. // Why do we need this routine?
  803. // If VC endpoint is in connected state it maintains the referenced
  804. // pointer to the connection object until it is closed (e.g. all references
  805. // to the underlying file object are removed). So checking for connected
  806. // state should be enough in any dispatch routine (or any routine called
  807. // from the dispatch routine) because Irp that used to get to AFD maintains
  808. // a reference to the corresponding file object.
  809. // However, there exist a notable exception from this case: TransmitFile
  810. // can remove the reference to the connection object in the process of endpoint
  811. // reuse. So, to be 100% safe, it is better to use this routine in all cases.
  812. {
  813. AFD_LOCK_QUEUE_HANDLE lockHandle;
  814. PAFD_CONNECTION connection;
  815. AfdAcquireSpinLock (&Endpoint->SpinLock, &lockHandle);
  816. connection = AFD_CONNECTION_FROM_ENDPOINT (Endpoint);
  817. if (connection!=NULL) {
  818. REFERENCE_CONNECTION (connection);
  819. }
  820. AfdReleaseSpinLock (&Endpoint->SpinLock, &lockHandle);
  821. return connection;
  822. }
  823. #if REFERENCE_DEBUG
  824. VOID
  825. AfdDereferenceConnection (
  826. IN PAFD_CONNECTION Connection,
  827. IN LONG LocationId,
  828. IN ULONG Param
  829. )
  830. {
  831. LONG result;
  832. PAFD_ENDPOINT listenEndpoint;
  833. ASSERT( Connection->Type == AfdBlockTypeConnection );
  834. ASSERT( Connection->ReferenceCount > 0 );
  835. ASSERT( Connection->ReferenceCount != 0xD1000000 );
  836. IF_DEBUG(CONNECTION) {
  837. KdPrintEx(( DPFLTR_WSOCKTRANSPORT_ID, DPFLTR_TRACE_LEVEL,
  838. "AfdDereferenceConnection: connection %p, new refcnt %ld\n",
  839. Connection, Connection->ReferenceCount-1 ));
  840. }
  841. //
  842. // Note that if we're tracking refcnts, we *must* call
  843. // AfdUpdateConnectionTrack before doing the dereference. This is
  844. // because the connection object might go away in another thread as
  845. // soon as we do the dereference. However, because of this,
  846. // the refcnt we store with this may sometimes be incorrect.
  847. //
  848. AFD_UPDATE_REFERENCE_DEBUG(Connection, Connection->ReferenceCount-1, LocationId, Param);
  849. //
  850. // We must hold AfdSpinLock while doing the dereference and check
  851. // for free. This is because some code makes the assumption that
  852. // the connection structure will not go away while AfdSpinLock is
  853. // held, and that code references the endpoint before releasing
  854. // AfdSpinLock. If we did the InterlockedDecrement() without the
  855. // lock held, our count may go to zero, that code may reference the
  856. // connection, and then a double free might occur.
  857. //
  858. // There is no such code anymore. The endpoint spinlock is now
  859. // held when getting a connection from endpoint structure.
  860. // Other code uses InterlockedCompareExchange to never increment
  861. // connection reference if it is at 0.
  862. //
  863. //
  864. result = InterlockedDecrement( (PLONG)&Connection->ReferenceCount );
  865. //
  866. // If the reference count is now 0, free the connection in an
  867. // executive worker thread.
  868. //
  869. if ( result == 0 ) {
  870. #else
  871. VOID
  872. AfdCloseConnection (
  873. IN PAFD_CONNECTION Connection
  874. )
  875. {
  876. PAFD_ENDPOINT listenEndpoint;
  877. #endif
  878. if (Connection->Endpoint != NULL &&
  879. !CONNECTION_REUSE_DISABLED &&
  880. !Connection->Endpoint->EndpointCleanedUp &&
  881. Connection->Endpoint->Type == AfdBlockTypeVcConnecting &&
  882. (listenEndpoint=Connection->Endpoint->Common.VcConnecting.ListenEndpoint) != NULL &&
  883. -listenEndpoint->Common.VcListening.FailedConnectionAdds <
  884. listenEndpoint->Common.VcListening.MaxExtraConnections &&
  885. (IS_DELAYED_ACCEPTANCE_ENDPOINT (listenEndpoint) ||
  886. ExQueryDepthSList (
  887. &listenEndpoint->Common.VcListening.FreeConnectionListHead)
  888. < AFD_MAXIMUM_FREE_CONNECTIONS ) ) {
  889. AfdRefreshConnection (Connection);
  890. }
  891. else {
  892. InterlockedIncrement (&AfdConnectionsFreeing);
  893. //
  894. // We're going to do this by queueing a request to an executive
  895. // worker thread. We do this for several reasons: to ensure
  896. // that we're at IRQL 0 so we can free pageable memory, and to
  897. // ensure that we're in a legitimate context for a close
  898. // operation
  899. //
  900. AfdQueueWorkItem(
  901. AfdFreeConnection,
  902. &Connection->WorkItem
  903. );
  904. }
  905. #if REFERENCE_DEBUG
  906. }
  907. } // AfdDereferenceConnection
  908. #else
  909. } // AfdCloseConnection
  910. #endif
  911. #if REFERENCE_DEBUG
  912. BOOLEAN
  913. AfdCheckAndReferenceConnection (
  914. PAFD_CONNECTION Connection,
  915. IN LONG LocationId,
  916. IN ULONG Param
  917. )
  918. #else
  919. BOOLEAN
  920. AfdCheckAndReferenceConnection (
  921. PAFD_CONNECTION Connection
  922. )
  923. #endif
  924. {
  925. LONG result;
  926. do {
  927. result = Connection->ReferenceCount;
  928. if (result<=0) {
  929. result = 0;
  930. break;
  931. }
  932. }
  933. while (InterlockedCompareExchange ((PLONG)&Connection->ReferenceCount,
  934. (result+1),
  935. result)!=result);
  936. if (result>0) {
  937. #if REFERENCE_DEBUG
  938. AFD_UPDATE_REFERENCE_DEBUG(Connection, result+1, LocationId, Param);
  939. #endif
  940. ASSERT( result < 0xFFFF );
  941. return TRUE;
  942. }
  943. else {
  944. KdPrintEx(( DPFLTR_WSOCKTRANSPORT_ID, DPFLTR_ERROR_LEVEL,
  945. "AfdCheckAndReferenceConnection: Connection %p is gone (refcount: %ld!\n",
  946. Connection, result));
  947. return FALSE;
  948. }
  949. }
  950. PAFD_CONNECTION
  951. AfdGetFreeConnection (
  952. IN PAFD_ENDPOINT Endpoint,
  953. OUT PIRP *Irp
  954. )
  955. /*++
  956. Routine Description:
  957. Takes a connection off of the endpoint's queue of listening
  958. connections.
  959. Arguments:
  960. Endpoint - a pointer to the endpoint from which to get a connection.
  961. Irp - place to return a super accept IRP if we have any
  962. Return Value:
  963. AFD_CONNECTION - a pointer to an AFD connection block.
  964. --*/
  965. {
  966. PAFD_CONNECTION connection;
  967. PSINGLE_LIST_ENTRY listEntry;
  968. PIRP irp;
  969. ASSERT( Endpoint->Type == AfdBlockTypeVcListening ||
  970. Endpoint->Type == AfdBlockTypeVcBoth );
  971. //
  972. // First try pre-accepted connections
  973. //
  974. while ((listEntry = InterlockedPopEntrySList (
  975. &Endpoint->Common.VcListening.PreacceptedConnectionsListHead
  976. ))!=NULL) {
  977. //
  978. // Find the connection pointer from the list entry and return a
  979. // pointer to the connection object.
  980. //
  981. connection = CONTAINING_RECORD(
  982. listEntry,
  983. AFD_CONNECTION,
  984. SListEntry
  985. );
  986. //
  987. // Check if super accept Irp has not been cancelled
  988. //
  989. irp = InterlockedExchangePointer ((PVOID *)&connection->AcceptIrp, NULL);
  990. if ((irp!=NULL) && (IoSetCancelRoutine (irp, NULL)!=NULL)) {
  991. //
  992. // Return the IRP to the caller along with the connection.
  993. //
  994. *Irp = irp;
  995. goto ReturnConnection;
  996. }
  997. //
  998. // Irp has been or is about to be cancelled
  999. //
  1000. if (irp!=NULL) {
  1001. KIRQL cancelIrql;
  1002. //
  1003. // Cleanup and cancel the super accept IRP.
  1004. //
  1005. AfdCleanupSuperAccept (irp, STATUS_CANCELLED);
  1006. //
  1007. // The cancel routine won't find the IRP in the connection,
  1008. // so we need to cancel it ourselves. Just make sure that
  1009. // the cancel routine is done before doing so.
  1010. //
  1011. IoAcquireCancelSpinLock (&cancelIrql);
  1012. IoReleaseCancelSpinLock (cancelIrql);
  1013. IoCompleteRequest (irp, AfdPriorityBoost);
  1014. }
  1015. //
  1016. // This connection has already been diassociated from endpoint.
  1017. // If backlog is below the level we need, put it on the free
  1018. // list, otherwise, get rid of it.
  1019. //
  1020. ASSERT (connection->Endpoint==NULL);
  1021. if (Endpoint->Common.VcListening.FailedConnectionAdds>=0 &&
  1022. ExQueryDepthSList (&Endpoint->Common.VcListening.FreeConnectionListHead)<AFD_MAXIMUM_FREE_CONNECTIONS) {
  1023. InterlockedPushEntrySList (
  1024. &Endpoint->Common.VcListening.FreeConnectionListHead,
  1025. &connection->SListEntry);
  1026. }
  1027. else {
  1028. InterlockedIncrement (&Endpoint->Common.VcListening.FailedConnectionAdds);
  1029. DEREFERENCE_CONNECTION (connection);
  1030. }
  1031. }
  1032. //
  1033. // Remove the first entry from the list. If the list is empty,
  1034. // return NULL.
  1035. //
  1036. listEntry = InterlockedPopEntrySList (
  1037. &Endpoint->Common.VcListening.FreeConnectionListHead);
  1038. if (listEntry==NULL) {
  1039. return NULL;
  1040. }
  1041. //
  1042. // Find the connection pointer from the list entry and return a
  1043. // pointer to the connection object.
  1044. //
  1045. connection = CONTAINING_RECORD(
  1046. listEntry,
  1047. AFD_CONNECTION,
  1048. SListEntry
  1049. );
  1050. *Irp = NULL;
  1051. ReturnConnection:
  1052. //
  1053. // Assign unique non-zero sequence number (unique in the context
  1054. // of the given listening endpoint).
  1055. //
  1056. connection->Sequence = InterlockedIncrement (&Endpoint->Common.VcListening.Sequence);
  1057. if (connection->Sequence==0) {
  1058. connection->Sequence = InterlockedIncrement (&Endpoint->Common.VcListening.Sequence);
  1059. ASSERT (connection->Sequence!=0);
  1060. }
  1061. return connection;
  1062. } // AfdGetFreeConnection
  1063. PAFD_CONNECTION
  1064. AfdGetReturnedConnection (
  1065. IN PAFD_ENDPOINT Endpoint,
  1066. IN LONG Sequence
  1067. )
  1068. /*++
  1069. Routine Description:
  1070. Takes a connection off of the endpoint's queue of returned
  1071. connections.
  1072. *** NOTE: This routine must be called with endpoint spinlock held!!
  1073. Arguments:
  1074. Endpoint - a pointer to the endpoint from which to get a connection.
  1075. Sequence - the sequence the connection must match. If 0, the first returned
  1076. connection is used.
  1077. Return Value:
  1078. AFD_CONNECTION - a pointer to an AFD connection block.
  1079. --*/
  1080. {
  1081. PAFD_CONNECTION connection;
  1082. PLIST_ENTRY listEntry;
  1083. ASSERT( Endpoint->Type == AfdBlockTypeVcListening ||
  1084. Endpoint->Type == AfdBlockTypeVcBoth );
  1085. //
  1086. // Walk the endpoint's list of returned connections until we reach
  1087. // the end or until we find one with a matching sequence.
  1088. //
  1089. for ( listEntry = Endpoint->Common.VcListening.ReturnedConnectionListHead.Flink;
  1090. listEntry != &Endpoint->Common.VcListening.ReturnedConnectionListHead;
  1091. listEntry = listEntry->Flink ) {
  1092. connection = CONTAINING_RECORD(
  1093. listEntry,
  1094. AFD_CONNECTION,
  1095. ListEntry
  1096. );
  1097. if ( Sequence == connection->Sequence || Sequence == 0 ) {
  1098. //
  1099. // Found the connection we were looking for. Remove
  1100. // the connection from the list, release the spin lock,
  1101. // and return the connection.
  1102. //
  1103. RemoveEntryList( listEntry );
  1104. return connection;
  1105. }
  1106. }
  1107. return NULL;
  1108. } // AfdGetReturnedConnection
  1109. PAFD_CONNECTION
  1110. AfdFindReturnedConnection(
  1111. IN PAFD_ENDPOINT Endpoint,
  1112. IN LONG Sequence
  1113. )
  1114. /*++
  1115. Routine Description:
  1116. Scans the endpoints queue of returned connections looking for one
  1117. with the specified sequence number.
  1118. Arguments:
  1119. Endpoint - A pointer to the endpoint from which to get a connection.
  1120. Sequence - The sequence the connection must match.
  1121. Return Value:
  1122. AFD_CONNECTION - A pointer to an AFD connection block if successful,
  1123. NULL if not.
  1124. --*/
  1125. {
  1126. PAFD_CONNECTION connection;
  1127. PLIST_ENTRY listEntry;
  1128. ASSERT( Endpoint != NULL );
  1129. ASSERT( IS_AFD_ENDPOINT_TYPE( Endpoint ) );
  1130. //
  1131. // Walk the endpoint's list of returned connections until we reach
  1132. // the end or until we find one with a matching sequence.
  1133. //
  1134. for( listEntry = Endpoint->Common.VcListening.ReturnedConnectionListHead.Flink;
  1135. listEntry != &Endpoint->Common.VcListening.ReturnedConnectionListHead;
  1136. listEntry = listEntry->Flink ) {
  1137. connection = CONTAINING_RECORD(
  1138. listEntry,
  1139. AFD_CONNECTION,
  1140. ListEntry
  1141. );
  1142. if( Sequence == connection->Sequence ) {
  1143. return connection;
  1144. }
  1145. }
  1146. return NULL;
  1147. } // AfdFindReturnedConnection
  1148. PAFD_CONNECTION
  1149. AfdGetUnacceptedConnection (
  1150. IN PAFD_ENDPOINT Endpoint
  1151. )
  1152. /*++
  1153. Routine Description:
  1154. Takes a connection of the endpoint's queue of unaccpted connections.
  1155. *** NOTE: This routine must be called with endpoint spinlock held!!
  1156. Arguments:
  1157. Endpoint - a pointer to the endpoint from which to get a connection.
  1158. Return Value:
  1159. AFD_CONNECTION - a pointer to an AFD connection block.
  1160. --*/
  1161. {
  1162. PAFD_CONNECTION connection;
  1163. PLIST_ENTRY listEntry;
  1164. ASSERT( Endpoint->Type == AfdBlockTypeVcListening ||
  1165. Endpoint->Type == AfdBlockTypeVcBoth );
  1166. ASSERT( KeGetCurrentIrql( ) == DISPATCH_LEVEL );
  1167. if ( IsListEmpty( &Endpoint->Common.VcListening.UnacceptedConnectionListHead ) ) {
  1168. return NULL;
  1169. }
  1170. //
  1171. // Dequeue a listening connection and remember its handle.
  1172. //
  1173. listEntry = RemoveHeadList( &Endpoint->Common.VcListening.UnacceptedConnectionListHead );
  1174. connection = CONTAINING_RECORD( listEntry, AFD_CONNECTION, ListEntry );
  1175. return connection;
  1176. } // AfdGetUnacceptedConnection
  1177. VOID
  1178. AfdAddConnectedReference (
  1179. IN PAFD_CONNECTION Connection
  1180. )
  1181. /*++
  1182. Routine Description:
  1183. Adds the connected reference to an AFD connection block. The
  1184. connected reference is special because it prevents the connection
  1185. object from being freed until we receive a disconnect event, or know
  1186. through some other means that the virtual circuit is disconnected.
  1187. Arguments:
  1188. Connection - a pointer to an AFD connection block.
  1189. Return Value:
  1190. None.
  1191. --*/
  1192. {
  1193. AFD_LOCK_QUEUE_HANDLE lockHandle;
  1194. AfdAcquireSpinLock( &Connection->Endpoint->SpinLock, &lockHandle );
  1195. IF_DEBUG(CONNECTION) {
  1196. KdPrintEx(( DPFLTR_WSOCKTRANSPORT_ID, DPFLTR_TRACE_LEVEL,
  1197. "AfdAddConnectedReference: connection %p, new refcnt %ld\n",
  1198. Connection, Connection->ReferenceCount+1 ));
  1199. }
  1200. ASSERT( !Connection->ConnectedReferenceAdded );
  1201. ASSERT( Connection->Type == AfdBlockTypeConnection );
  1202. //
  1203. // Increment the reference count and remember that the connected
  1204. // reference has been placed on the connection object.
  1205. //
  1206. Connection->ConnectedReferenceAdded = TRUE;
  1207. AfdRecordConnectedReferencesAdded();
  1208. AfdReleaseSpinLock( &Connection->Endpoint->SpinLock, &lockHandle );
  1209. REFERENCE_CONNECTION( Connection );
  1210. } // AfdAddConnectedReference
  1211. VOID
  1212. AfdDeleteConnectedReference (
  1213. IN PAFD_CONNECTION Connection,
  1214. IN BOOLEAN EndpointLockHeld
  1215. )
  1216. /*++
  1217. Routine Description:
  1218. Removes the connected reference to an AFD connection block. If the
  1219. connected reference has already been removed, this routine does
  1220. nothing. The connected reference should be removed as soon as we
  1221. know that it is OK to close the connection object handle, but not
  1222. before. Removing this reference too soon could abort a connection
  1223. which shouldn't get aborted.
  1224. Arguments:
  1225. Connection - a pointer to an AFD connection block.
  1226. EndpointLockHeld - TRUE if the caller already has the endpoint
  1227. spin lock. The lock remains held on exit.
  1228. Return Value:
  1229. None.
  1230. --*/
  1231. {
  1232. AFD_LOCK_QUEUE_HANDLE lockHandle;
  1233. PAFD_ENDPOINT endpoint;
  1234. #if REFERENCE_DEBUG
  1235. PVOID caller, callersCaller;
  1236. RtlGetCallersAddress( &caller, &callersCaller );
  1237. #endif
  1238. endpoint = Connection->Endpoint;
  1239. if ( !EndpointLockHeld ) {
  1240. AfdAcquireSpinLock( &endpoint->SpinLock, &lockHandle );
  1241. }
  1242. //
  1243. // Only do a dereference if the connected reference is still active
  1244. // on the connectiuon object.
  1245. //
  1246. if ( Connection->ConnectedReferenceAdded ) {
  1247. //
  1248. // Three things must be true before we can remove the connected
  1249. // reference:
  1250. //
  1251. // 1) There must be no sends outstanding on the connection if
  1252. // the TDI provider does not support bufferring. This is
  1253. // because AfdRestartBufferSend() looks at the connection
  1254. // object.
  1255. //
  1256. // 2) Cleanup must have started on the endpoint. Until we get a
  1257. // cleanup IRP on the endpoint, we could still get new sends.
  1258. //
  1259. // 3) We have been indicated with a disconnect on the
  1260. // connection. We want to keep the connection object around
  1261. // until we get a disconnect indication in order to avoid
  1262. // premature closes on the connection object resulting in an
  1263. // unintended abort. If the transport does not support
  1264. // orderly release, then this condition is not necessary.
  1265. //
  1266. if ( (Connection->TdiBufferring ||
  1267. Connection->VcBufferredSendCount == 0)
  1268. &&
  1269. Connection->CleanupBegun
  1270. &&
  1271. (Connection->AbortIndicated || Connection->DisconnectIndicated ||
  1272. !IS_TDI_ORDERLY_RELEASE(endpoint) ||
  1273. IS_CROOT_ENDPOINT(endpoint)) ) {
  1274. IF_DEBUG(CONNECTION) {
  1275. KdPrintEx(( DPFLTR_WSOCKTRANSPORT_ID, DPFLTR_TRACE_LEVEL,
  1276. "AfdDeleteConnectedReference: connection %p, new refcnt %ld\n",
  1277. Connection, Connection->ReferenceCount-1 ));
  1278. }
  1279. //
  1280. // Be careful about the order of things here. We must FIRST
  1281. // reset the flag, then release the spin lock and call
  1282. // AfdDereferenceConnection(). Note that it is illegal to
  1283. // call AfdDereferenceConnection() with a spin lock held.
  1284. //
  1285. Connection->ConnectedReferenceAdded = FALSE;
  1286. AfdRecordConnectedReferencesDeleted();
  1287. if ( !EndpointLockHeld ) {
  1288. AfdReleaseSpinLock( &endpoint->SpinLock, &lockHandle );
  1289. }
  1290. DEREFERENCE_CONNECTION( Connection );
  1291. } else {
  1292. IF_DEBUG(CONNECTION) {
  1293. KdPrintEx(( DPFLTR_WSOCKTRANSPORT_ID, DPFLTR_TRACE_LEVEL,
  1294. "AfdDeleteConnectedReference: connection %p, %ld sends pending\n",
  1295. Connection, Connection->VcBufferredSendCount ));
  1296. }
  1297. UPDATE_CONN2( Connection, "Not removing cref, state flags: %lx",
  1298. Connection->ConnectionStateFlags);
  1299. //
  1300. // Remember that the connected reference deletion is still
  1301. // pending, i.e. there is a special condition on the
  1302. // endpoint. This will cause AfdRestartBufferSend() to do
  1303. // the actual dereference when the last send completes.
  1304. //
  1305. Connection->SpecialCondition = TRUE;
  1306. if ( !EndpointLockHeld ) {
  1307. AfdReleaseSpinLock( &endpoint->SpinLock, &lockHandle );
  1308. }
  1309. }
  1310. } else {
  1311. IF_DEBUG(CONNECTION) {
  1312. KdPrintEx(( DPFLTR_WSOCKTRANSPORT_ID, DPFLTR_TRACE_LEVEL,
  1313. "AfdDeleteConnectedReference: already removed on connection %p, refcnt %ld\n",
  1314. Connection, Connection->ReferenceCount ));
  1315. }
  1316. if ( !EndpointLockHeld ) {
  1317. AfdReleaseSpinLock( &endpoint->SpinLock, &lockHandle );
  1318. }
  1319. }
  1320. return;
  1321. } // AfdDeleteConnectedReference
  1322. #if REFERENCE_DEBUG
  1323. VOID
  1324. AfdUpdateConnectionTrack (
  1325. IN PAFD_CONNECTION Connection,
  1326. IN LONG LocationId,
  1327. IN ULONG Param
  1328. )
  1329. {
  1330. AFD_UPDATE_REFERENCE_DEBUG (Connection, Connection->ReferenceCount, LocationId, Param);
  1331. #if GLOBAL_REFERENCE_DEBUG
  1332. {
  1333. PAFD_GLOBAL_REFERENCE_DEBUG globalSlot;
  1334. newSlot = InterlockedIncrement( &AfdGlobalReferenceSlot );
  1335. globalSlot = &AfdGlobalReference[newSlot % MAX_GLOBAL_REFERENCE];
  1336. globalSlot->Info1 = Info1;
  1337. globalSlot->Info2 = Info2;
  1338. globalSlot->Action = Action;
  1339. globalSlot->NewCount = NewReferenceCount;
  1340. globalSlot->Connection = Connection;
  1341. KeQueryTickCount( &globalSlot->TickCounter );
  1342. }
  1343. #endif
  1344. } // AfdUpdateConnectionTrack
  1345. #endif