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

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