Windows NT 4.0 source code leak
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.

1453 lines
38 KiB

4 years ago
  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. #ifdef ALLOC_PRAGMA
  18. #pragma alloc_text( PAGEAFD, AfdAbortConnection )
  19. #pragma alloc_text( PAGE, AfdAddFreeConnection )
  20. #pragma alloc_text( PAGE, AfdAllocateConnection )
  21. #pragma alloc_text( PAGE, AfdCreateConnection )
  22. #pragma alloc_text( PAGE, AfdFreeConnection )
  23. #pragma alloc_text( PAGEAFD, AfdDereferenceConnection )
  24. #if REFERENCE_DEBUG
  25. #pragma alloc_text( PAGEAFD, AfdReferenceConnection )
  26. #endif
  27. #pragma alloc_text( PAGEAFD, AfdGetFreeConnection )
  28. #pragma alloc_text( PAGEAFD, AfdGetReturnedConnection )
  29. #pragma alloc_text( PAGEAFD, AfdGetUnacceptedConnection )
  30. #pragma alloc_text( PAGEAFD, AfdAddConnectedReference )
  31. #pragma alloc_text( PAGEAFD, AfdDeleteConnectedReference )
  32. #endif
  33. #if GLOBAL_REFERENCE_DEBUG
  34. AFD_GLOBAL_REFERENCE_DEBUG AfdGlobalReference[MAX_GLOBAL_REFERENCE];
  35. LONG AfdGlobalReferenceSlot = -1;
  36. #endif
  37. #if AFD_PERF_DBG
  38. #define CONNECTION_REUSE_DISABLED (AfdDisableConnectionReuse)
  39. #else
  40. #define CONNECTION_REUSE_DISABLED (FALSE)
  41. #endif
  42. VOID
  43. AfdAbortConnection (
  44. IN PAFD_CONNECTION Connection
  45. )
  46. {
  47. NTSTATUS status;
  48. ASSERT( Connection != NULL );
  49. ASSERT( Connection->ConnectedReferenceAdded );
  50. //
  51. // Abort the connection. We need to set the CleanupBegun flag
  52. // before initiating the abort so that the connected reference
  53. // will get properly removed in AfdRestartAbort.
  54. //
  55. // Note that if AfdBeginAbort fails then AfdRestartAbort will not
  56. // get invoked, so we must remove the connected reference ourselves.
  57. //
  58. Connection->CleanupBegun = TRUE;
  59. status = AfdBeginAbort( Connection );
  60. if( !NT_SUCCESS(status) ) {
  61. Connection->AbortIndicated = TRUE;
  62. AfdDeleteConnectedReference( Connection, FALSE );
  63. }
  64. //
  65. // Remove the active reference.
  66. //
  67. DEREFERENCE_CONNECTION( Connection );
  68. } // AfdAbortConnection
  69. NTSTATUS
  70. AfdAddFreeConnection (
  71. IN PAFD_ENDPOINT Endpoint
  72. )
  73. /*++
  74. Routine Description:
  75. Adds a connection object to an endpoints pool of connections available
  76. to satisfy a connect indication.
  77. Arguments:
  78. Endpoint - a pointer to the endpoint to which to add a connection.
  79. Return Value:
  80. NTSTATUS -- Indicates the status of the request.
  81. --*/
  82. {
  83. PAFD_CONNECTION connection;
  84. NTSTATUS status;
  85. PAGED_CODE( );
  86. ASSERT( Endpoint->Type == AfdBlockTypeVcListening );
  87. //
  88. // Create a new connection block and associated connection object.
  89. //
  90. status = AfdCreateConnection(
  91. &Endpoint->TransportInfo->TransportDeviceName,
  92. Endpoint->AddressHandle,
  93. Endpoint->TdiBufferring,
  94. Endpoint->InLine,
  95. Endpoint->OwningProcess,
  96. &connection
  97. );
  98. if ( !NT_SUCCESS(status) ) {
  99. return status;
  100. }
  101. ASSERT( Endpoint->TdiBufferring == connection->TdiBufferring );
  102. //
  103. // Set up the handle in the listening connection structure and place
  104. // the connection on the endpoint's list of listening connections.
  105. //
  106. ExInterlockedInsertTailList(
  107. &Endpoint->Common.VcListening.FreeConnectionListHead,
  108. &connection->ListEntry,
  109. &AfdSpinLock
  110. );
  111. InterlockedIncrement(
  112. &Endpoint->Common.VcListening.FreeConnectionCount
  113. );
  114. return STATUS_SUCCESS;
  115. } // AfdAddFreeConnection
  116. PAFD_CONNECTION
  117. AfdAllocateConnection (
  118. VOID
  119. )
  120. {
  121. PAFD_CONNECTION connection;
  122. PAGED_CODE( );
  123. //
  124. // Allocate a buffer to hold the endpoint structure.
  125. //
  126. connection = AFD_ALLOCATE_POOL(
  127. NonPagedPool,
  128. sizeof(AFD_CONNECTION),
  129. AFD_CONNECTION_POOL_TAG
  130. );
  131. if ( connection == NULL ) {
  132. return NULL;
  133. }
  134. RtlZeroMemory( connection, sizeof(AFD_CONNECTION) );
  135. //
  136. // Initialize the reference count to 1 to account for the caller's
  137. // reference. Connection blocks are temporary--as soon as the last
  138. // reference goes away, so does the connection. There is no active
  139. // reference on a connection block.
  140. //
  141. connection->ReferenceCount = 1;
  142. //
  143. // Initialize the connection structure.
  144. //
  145. connection->Type = AfdBlockTypeConnection;
  146. connection->State = AfdConnectionStateFree;
  147. //connection->Handle = NULL;
  148. //connection->FileObject = NULL;
  149. //connection->RemoteAddress = NULL;
  150. //connection->Endpoint = NULL;
  151. //connection->ReceiveBytesIndicated = 0;
  152. //connection->ReceiveBytesTaken = 0;
  153. //connection->ReceiveBytesOutstanding = 0;
  154. //connection->ReceiveExpeditedBytesIndicated = 0;
  155. //connection->ReceiveExpeditedBytesTaken = 0;
  156. //connection->ReceiveExpeditedBytesOutstanding = 0;
  157. //connection->ConnectDataBuffers = NULL;
  158. //connection->DisconnectIndicated = FALSE;
  159. //connection->AbortIndicated = FALSE;
  160. //connection->ConnectedReferenceAdded = FALSE;
  161. //connection->SpecialCondition = FALSE;
  162. //connection->CleanupBegun = FALSE;
  163. //connection->OwningProcess = NULL;
  164. //connection->ClosePendedTransmit = FALSE;
  165. #if REFERENCE_DEBUG
  166. connection->CurrentReferenceSlot = -1;
  167. RtlZeroMemory(
  168. &connection->ReferenceDebug,
  169. sizeof(AFD_REFERENCE_DEBUG) * MAX_REFERENCE
  170. );
  171. #endif
  172. //
  173. // Return a pointer to the new connection to the caller.
  174. //
  175. IF_DEBUG(CONNECTION) {
  176. KdPrint(( "AfdAllocateConnection: connection at %lx\n", connection ));
  177. }
  178. return connection;
  179. } // AfdAllocateConnection
  180. NTSTATUS
  181. AfdCreateConnection (
  182. IN PUNICODE_STRING TransportDeviceName,
  183. IN HANDLE AddressHandle,
  184. IN BOOLEAN TdiBufferring,
  185. IN BOOLEAN InLine,
  186. IN PEPROCESS ProcessToCharge,
  187. OUT PAFD_CONNECTION *Connection
  188. )
  189. /*++
  190. Routine Description:
  191. Allocates a connection block and creates a connection object to
  192. go with the block. This routine also associates the connection
  193. with the specified address handle (if any).
  194. Arguments:
  195. TransportDeviceName - Name to use when creating the connection object.
  196. AddressHandle - a handle to an address object for the specified
  197. transport. If specified (non NULL), the connection object that
  198. is created is associated with the address object.
  199. TdiBufferring - whether the TDI provider supports data bufferring.
  200. Only passed so that it can be stored in the connection
  201. structure.
  202. InLine - if TRUE, the endpoint should be created in OOB inline
  203. mode.
  204. ProcessToCharge - the process which should be charged the quota
  205. for this connection.
  206. Connection - receives a pointer to the new connection.
  207. Return Value:
  208. NTSTATUS -- Indicates the status of the request.
  209. --*/
  210. {
  211. NTSTATUS status;
  212. IO_STATUS_BLOCK ioStatusBlock;
  213. OBJECT_ATTRIBUTES objectAttributes;
  214. CHAR eaBuffer[sizeof(FILE_FULL_EA_INFORMATION) - 1 +
  215. TDI_CONNECTION_CONTEXT_LENGTH + 1 +
  216. sizeof(CONNECTION_CONTEXT)];
  217. PFILE_FULL_EA_INFORMATION ea;
  218. CONNECTION_CONTEXT UNALIGNED *ctx;
  219. PAFD_CONNECTION connection;
  220. PAGED_CODE( );
  221. //
  222. // Attempt to charge this process quota for the data bufferring we
  223. // will do on its behalf.
  224. //
  225. try {
  226. PsChargePoolQuota(
  227. ProcessToCharge,
  228. NonPagedPool,
  229. AfdReceiveWindowSize + AfdSendWindowSize
  230. );
  231. } except ( EXCEPTION_EXECUTE_HANDLER ) {
  232. #if DBG
  233. DbgPrint( "AfdCreateConnection: PsChargePoolQuota failed.\n" );
  234. #endif
  235. return STATUS_QUOTA_EXCEEDED;
  236. }
  237. //
  238. // Allocate a connection block.
  239. //
  240. connection = AfdAllocateConnection( );
  241. if ( connection == NULL ) {
  242. PsReturnPoolQuota(
  243. ProcessToCharge,
  244. NonPagedPool,
  245. AfdReceiveWindowSize + AfdSendWindowSize
  246. );
  247. return STATUS_INSUFFICIENT_RESOURCES;
  248. }
  249. AfdRecordQuotaHistory(
  250. ProcessToCharge,
  251. (LONG)(AfdReceiveWindowSize+AfdSendWindowSize),
  252. "CreateConn ",
  253. connection
  254. );
  255. AfdRecordPoolQuotaCharged( AfdReceiveWindowSize + AfdSendWindowSize );
  256. //
  257. // Remember the process that got charged the pool quota for this
  258. // connection object. Also reference the process to which we're
  259. // going to charge the quota so that it is still around when we
  260. // return the quota.
  261. //
  262. ASSERT( connection->OwningProcess == NULL );
  263. connection->OwningProcess = ProcessToCharge;
  264. ObReferenceObject( ProcessToCharge );
  265. //
  266. // If the provider does not buffer, initialize appropriate lists in
  267. // the connection object.
  268. //
  269. connection->TdiBufferring = TdiBufferring;
  270. if ( !TdiBufferring ) {
  271. InitializeListHead( &connection->VcReceiveIrpListHead );
  272. InitializeListHead( &connection->VcSendIrpListHead );
  273. InitializeListHead( &connection->VcReceiveBufferListHead );
  274. connection->VcBufferredReceiveBytes = 0;
  275. connection->VcBufferredExpeditedBytes = 0;
  276. connection->VcBufferredReceiveCount = 0;
  277. connection->VcBufferredExpeditedCount = 0;
  278. connection->VcReceiveBytesInTransport = 0;
  279. connection->VcReceiveCountInTransport = 0;
  280. connection->VcBufferredSendBytes = 0;
  281. connection->VcBufferredSendCount = 0;
  282. } else {
  283. connection->VcNonBlockingSendPossible = TRUE;
  284. connection->VcZeroByteReceiveIndicated = FALSE;
  285. }
  286. //
  287. // Set up the send and receive window with default maximums.
  288. //
  289. connection->MaxBufferredReceiveBytes = AfdReceiveWindowSize;
  290. connection->MaxBufferredReceiveCount =
  291. (CSHORT)(AfdReceiveWindowSize / AfdBufferMultiplier);
  292. connection->MaxBufferredSendBytes = AfdSendWindowSize;
  293. connection->MaxBufferredSendCount =
  294. (CSHORT)(AfdSendWindowSize / AfdBufferMultiplier);
  295. //
  296. // We need to open a connection object to the TDI provider for this
  297. // endpoint. First create the EA for the connection context and the
  298. // object attributes structure which will be used for all the
  299. // connections we open here.
  300. //
  301. ea = (PFILE_FULL_EA_INFORMATION)eaBuffer;
  302. ea->NextEntryOffset = 0;
  303. ea->Flags = 0;
  304. ea->EaNameLength = TDI_CONNECTION_CONTEXT_LENGTH;
  305. ea->EaValueLength = sizeof(CONNECTION_CONTEXT);
  306. RtlMoveMemory( ea->EaName, TdiConnectionContext, ea->EaNameLength + 1 );
  307. //
  308. // Use the pointer to the connection block as the connection context.
  309. //
  310. ctx = (CONNECTION_CONTEXT UNALIGNED *)&ea->EaName[ea->EaNameLength + 1];
  311. *ctx = (CONNECTION_CONTEXT)connection;
  312. InitializeObjectAttributes(
  313. &objectAttributes,
  314. TransportDeviceName,
  315. OBJ_CASE_INSENSITIVE, // attributes
  316. NULL,
  317. NULL
  318. );
  319. //
  320. // Do the actual open of the connection object.
  321. //
  322. KeAttachProcess( AfdSystemProcess );
  323. status = ZwCreateFile(
  324. &connection->Handle,
  325. GENERIC_READ | GENERIC_WRITE | SYNCHRONIZE,
  326. &objectAttributes,
  327. &ioStatusBlock,
  328. NULL, // AllocationSize
  329. 0, // FileAttributes
  330. 0, // ShareAccess
  331. 0, // CreateDisposition
  332. 0, // CreateOptions
  333. eaBuffer,
  334. FIELD_OFFSET( FILE_FULL_EA_INFORMATION, EaName[0] ) +
  335. ea->EaNameLength + 1 + ea->EaValueLength
  336. );
  337. if ( NT_SUCCESS(status) ) {
  338. status = ioStatusBlock.Status;
  339. }
  340. if ( !NT_SUCCESS(status) ) {
  341. KeDetachProcess( );
  342. DEREFERENCE_CONNECTION( connection );
  343. return status;
  344. }
  345. AfdRecordConnOpened();
  346. //
  347. // Reference the connection's file object.
  348. //
  349. status = ObReferenceObjectByHandle(
  350. connection->Handle,
  351. 0,
  352. (POBJECT_TYPE) NULL,
  353. KernelMode,
  354. (PVOID *)&connection->FileObject,
  355. NULL
  356. );
  357. ASSERT( NT_SUCCESS(status) );
  358. IF_DEBUG(OPEN_CLOSE) {
  359. KdPrint(( "AfdCreateConnection: file object for connection %lx at "
  360. "%lx\n", connection, connection->FileObject ));
  361. }
  362. AfdRecordConnRef();
  363. //
  364. // Remember the device object to which we need to give requests for
  365. // this connection object. We can't just use the
  366. // fileObject->DeviceObject pointer because there may be a device
  367. // attached to the transport protocol.
  368. //
  369. connection->DeviceObject =
  370. IoGetRelatedDeviceObject( connection->FileObject );
  371. //
  372. // Associate the connection with the address object on the endpoint if
  373. // an address handle was specified.
  374. //
  375. if ( AddressHandle != NULL ) {
  376. TDI_REQUEST_USER_ASSOCIATE associateRequest;
  377. associateRequest.AddressHandle = AddressHandle;
  378. status = ZwDeviceIoControlFile(
  379. connection->Handle,
  380. NULL, // EventHandle
  381. NULL, // APC Routine
  382. NULL, // APC Context
  383. &ioStatusBlock,
  384. IOCTL_TDI_ASSOCIATE_ADDRESS,
  385. (PVOID)&associateRequest, // InputBuffer
  386. sizeof(associateRequest), // InputBufferLength
  387. NULL, // OutputBuffer
  388. 0 // OutputBufferLength
  389. );
  390. if ( status == STATUS_PENDING ) {
  391. status = ZwWaitForSingleObject( connection->Handle, TRUE, NULL );
  392. ASSERT( NT_SUCCESS(status) );
  393. status = ioStatusBlock.Status;
  394. }
  395. }
  396. KeDetachProcess( );
  397. //
  398. // If requested, set the connection to be inline.
  399. //
  400. if ( InLine ) {
  401. status = AfdSetInLineMode( connection, TRUE );
  402. if ( !NT_SUCCESS(status) ) {
  403. DEREFERENCE_CONNECTION( connection );
  404. return status;
  405. }
  406. }
  407. //
  408. // Set up the connection pointer and return.
  409. //
  410. *Connection = connection;
  411. UPDATE_CONN( connection, connection->FileObject );
  412. return STATUS_SUCCESS;
  413. } // AfdCreateConnection
  414. VOID
  415. AfdFreeConnection (
  416. IN PVOID Context
  417. )
  418. {
  419. NTSTATUS status;
  420. PAFD_CONNECTION connection;
  421. BOOLEAN reuseConnection;
  422. PAFD_ENDPOINT listeningEndpoint;
  423. PAGED_CODE( );
  424. ASSERT( Context != NULL );
  425. connection = CONTAINING_RECORD(
  426. Context,
  427. AFD_CONNECTION,
  428. WorkItem
  429. );
  430. ASSERT( connection->ReferenceCount == 0 );
  431. ASSERT( connection->Type == AfdBlockTypeConnection );
  432. //
  433. // Determine whether we can reuse this connection object. We reuse
  434. // connection objects to assist performance when the connection
  435. // object is from a listening endpoint.
  436. //
  437. if ( connection->Endpoint != NULL &&
  438. !CONNECTION_REUSE_DISABLED &&
  439. !connection->Endpoint->EndpointCleanedUp &&
  440. connection->Endpoint->Type == AfdBlockTypeVcConnecting &&
  441. connection->Endpoint->Common.VcConnecting.ListenEndpoint != NULL ) {
  442. UPDATE_CONN( connection, 0 );
  443. //
  444. // Reference the listening endpoint so that it does not
  445. // go away while we are cleaning up this connection object
  446. // for reuse.
  447. //
  448. listeningEndpoint = connection->Endpoint->Common.VcConnecting.ListenEndpoint;
  449. ASSERT( listeningEndpoint->Type == AfdBlockTypeVcListening );
  450. REFERENCE_ENDPOINT( listeningEndpoint );
  451. reuseConnection = TRUE;
  452. } else {
  453. UPDATE_CONN( connection, 0 );
  454. reuseConnection = FALSE;
  455. //
  456. // Free and dereference the various objects on the connection.
  457. // Close and dereference the TDI connection object on the endpoint,
  458. // if any.
  459. //
  460. if ( connection->Handle != NULL ) {
  461. IO_STATUS_BLOCK ioStatusBlock;
  462. HANDLE handle;
  463. KeAttachProcess( AfdSystemProcess );
  464. handle = connection->Handle;
  465. connection->Handle = NULL;
  466. //
  467. // Disassociate this connection object from the address object.
  468. //
  469. status = ZwDeviceIoControlFile(
  470. handle, // FileHandle
  471. NULL, // Event
  472. NULL, // ApcRoutine
  473. NULL, // ApcContext
  474. &ioStatusBlock, // IoStatusBlock
  475. IOCTL_TDI_DISASSOCIATE_ADDRESS, // IoControlCode
  476. NULL, // InputBuffer
  477. 0, // InputBufferLength
  478. NULL, // OutputBuffer
  479. 0 // OutputBufferLength
  480. );
  481. if( status == STATUS_PENDING ) {
  482. status = ZwWaitForSingleObject(
  483. handle,
  484. TRUE,
  485. NULL
  486. );
  487. ASSERT( NT_SUCCESS(status) );
  488. status = ioStatusBlock.Status;
  489. }
  490. // ASSERT( NT_SUCCESS(status) );
  491. //
  492. // Close the handle.
  493. //
  494. status = ZwClose( handle );
  495. ASSERT( NT_SUCCESS(status) );
  496. AfdRecordConnClosed();
  497. KeDetachProcess( );
  498. }
  499. if ( connection->FileObject != NULL ) {
  500. ObDereferenceObject( connection->FileObject );
  501. connection->FileObject = NULL;
  502. AfdRecordConnDeref();
  503. }
  504. //
  505. // Return the quota we charged to this process when we allocated
  506. // the connection object.
  507. //
  508. PsReturnPoolQuota(
  509. connection->OwningProcess,
  510. NonPagedPool,
  511. connection->MaxBufferredReceiveBytes + connection->MaxBufferredSendBytes
  512. );
  513. AfdRecordQuotaHistory(
  514. connection->OwningProcess,
  515. -(LONG)(connection->MaxBufferredReceiveBytes + connection->MaxBufferredSendBytes),
  516. "ConnDealloc ",
  517. connection
  518. );
  519. AfdRecordPoolQuotaReturned(
  520. connection->MaxBufferredReceiveBytes + connection->MaxBufferredSendBytes
  521. );
  522. //
  523. // Dereference the process that got the quota charge.
  524. //
  525. ASSERT( connection->OwningProcess != NULL );
  526. ObDereferenceObject( connection->OwningProcess );
  527. connection->OwningProcess = NULL;
  528. }
  529. if ( !connection->TdiBufferring && connection->VcDisconnectIrp != NULL ) {
  530. IoFreeIrp( connection->VcDisconnectIrp );
  531. connection->VcDisconnectIrp = NULL;
  532. }
  533. //
  534. // If we're going to reuse this connection, don't free the remote
  535. // address structure--we'll reuse it as well.
  536. //
  537. if ( connection->RemoteAddress != NULL && !reuseConnection ) {
  538. AFD_FREE_POOL(
  539. connection->RemoteAddress,
  540. AFD_REMOTE_ADDRESS_POOL_TAG
  541. );
  542. connection->RemoteAddress = NULL;
  543. }
  544. if ( connection->ConnectDataBuffers != NULL ) {
  545. AfdFreeConnectDataBuffers( connection->ConnectDataBuffers );
  546. connection->ConnectDataBuffers = NULL;
  547. }
  548. //
  549. // If this is a bufferring connection, remove all the AFD buffers
  550. // from the connection's lists and free them.
  551. //
  552. if ( !connection->TdiBufferring ) {
  553. PAFD_BUFFER afdBuffer;
  554. PLIST_ENTRY listEntry;
  555. ASSERT( IsListEmpty( &connection->VcReceiveIrpListHead ) );
  556. ASSERT( IsListEmpty( &connection->VcSendIrpListHead ) );
  557. while ( !IsListEmpty( &connection->VcReceiveBufferListHead ) ) {
  558. listEntry = RemoveHeadList( &connection->VcReceiveBufferListHead );
  559. afdBuffer = CONTAINING_RECORD( listEntry, AFD_BUFFER, BufferListEntry );
  560. afdBuffer->DataOffset = 0;
  561. afdBuffer->ExpeditedData = FALSE;
  562. AfdReturnBuffer( afdBuffer );
  563. }
  564. }
  565. if ( connection->Endpoint != NULL ) {
  566. //
  567. // If there is a transmit file IRP on the endpoint, complete it.
  568. //
  569. if ( connection->ClosePendedTransmit ) {
  570. AfdCompleteClosePendedTransmit( connection->Endpoint );
  571. }
  572. DEREFERENCE_ENDPOINT( connection->Endpoint );
  573. connection->Endpoint = NULL;
  574. }
  575. //
  576. // Either free the actual connection block or put it back on the
  577. // listening endpoint's list of available connection objects.
  578. //
  579. if ( reuseConnection ) {
  580. //
  581. // Reinitialize various fields in the connection object.
  582. //
  583. connection->ReferenceCount = 1;
  584. ASSERT( connection->Type == AfdBlockTypeConnection );
  585. connection->State = AfdConnectionStateFree;
  586. connection->DisconnectIndicated = FALSE;
  587. connection->AbortIndicated = FALSE;
  588. connection->ConnectedReferenceAdded = FALSE;
  589. connection->SpecialCondition = FALSE;
  590. connection->CleanupBegun = FALSE;
  591. connection->ClosePendedTransmit = FALSE;
  592. if ( !connection->TdiBufferring ) {
  593. ASSERT( IsListEmpty( &connection->VcReceiveIrpListHead ) );
  594. ASSERT( IsListEmpty( &connection->VcSendIrpListHead ) );
  595. ASSERT( IsListEmpty( &connection->VcReceiveBufferListHead ) );
  596. connection->VcBufferredReceiveBytes = 0;
  597. connection->VcBufferredExpeditedBytes = 0;
  598. connection->VcBufferredReceiveCount = 0;
  599. connection->VcBufferredExpeditedCount = 0;
  600. connection->VcReceiveBytesInTransport = 0;
  601. connection->VcReceiveCountInTransport = 0;
  602. connection->VcBufferredSendBytes = 0;
  603. connection->VcBufferredSendCount = 0;
  604. } else {
  605. connection->VcNonBlockingSendPossible = TRUE;
  606. connection->VcZeroByteReceiveIndicated = FALSE;
  607. }
  608. //
  609. // Place the connection on the listening endpoint's list of
  610. // available connections.
  611. //
  612. ExInterlockedInsertHeadList(
  613. &listeningEndpoint->Common.VcListening.FreeConnectionListHead,
  614. &connection->ListEntry,
  615. &AfdSpinLock
  616. );
  617. //
  618. // Reduce the count of failed connection adds on the listening
  619. // endpoint to account for this connection object which we're
  620. // adding back onto the queue.
  621. //
  622. InterlockedDecrement(
  623. &listeningEndpoint->Common.VcListening.FailedConnectionAdds
  624. );
  625. InterlockedIncrement(
  626. &listeningEndpoint->Common.VcListening.FreeConnectionCount
  627. );
  628. //
  629. // Get rid of the reference we added to the listening endpoint
  630. // above.
  631. //
  632. DEREFERENCE_ENDPOINT( listeningEndpoint );
  633. } else {
  634. #if ENABLE_ABORT_TIMER_HACK
  635. //
  636. // Free any attached abort timer.
  637. //
  638. if( connection->AbortTimerInfo != NULL ) {
  639. AFD_FREE_POOL(
  640. connection->AbortTimerInfo,
  641. AFD_ABORT_TIMER_HACK_POOL_TAG
  642. );
  643. }
  644. #endif // ENABLE_ABORT_TIMER_HACK
  645. //
  646. // Free the space that holds the connection itself.
  647. //
  648. IF_DEBUG(CONNECTION) {
  649. KdPrint(( "AfdFreeConnection: Freeing connection at %lx\n", connection ));
  650. }
  651. connection->Type = 0xAFDF;
  652. AFD_FREE_POOL(
  653. connection,
  654. AFD_CONNECTION_POOL_TAG
  655. );
  656. }
  657. } // AfdFreeConnection
  658. #if REFERENCE_DEBUG
  659. VOID
  660. AfdDereferenceConnection (
  661. IN PAFD_CONNECTION Connection,
  662. IN PVOID Info1,
  663. IN PVOID Info2
  664. )
  665. #else
  666. VOID
  667. AfdDereferenceConnection (
  668. IN PAFD_CONNECTION Connection
  669. )
  670. #endif
  671. {
  672. LONG result;
  673. KIRQL oldIrql;
  674. ASSERT( Connection->Type == AfdBlockTypeConnection );
  675. ASSERT( Connection->ReferenceCount > 0 );
  676. ASSERT( Connection->ReferenceCount != 0xD1000000 );
  677. IF_DEBUG(CONNECTION) {
  678. KdPrint(( "AfdDereferenceConnection: connection %lx, new refcnt %ld\n",
  679. Connection, Connection->ReferenceCount-1 ));
  680. }
  681. //
  682. // Note that if we're tracking refcnts, we *must* call
  683. // AfdUpdateConnectionTrack before doing the dereference. This is
  684. // because the connection object might go away in another thread as
  685. // soon as we do the dereference. However, because of this,
  686. // the refcnt we store with this may sometimes be incorrect.
  687. //
  688. #if REFERENCE_DEBUG
  689. AfdUpdateConnectionTrack(
  690. Connection,
  691. Connection->ReferenceCount - 1,
  692. Info1,
  693. Info2,
  694. 0xFFFFFFFF
  695. );
  696. #endif
  697. //
  698. // We must hold AfdSpinLock while doing the dereference and check
  699. // for free. This is because some code makes the assumption that
  700. // the connection structure will not go away while AfdSpinLock is
  701. // held, and that code references the endpoint before releasing
  702. // AfdSpinLock. If we did the InterlockedDecrement() without the
  703. // lock held, our count may go to zero, that code may reference the
  704. // connection, and then a double free might occur.
  705. //
  706. // It is still valuable to use the interlocked routines for
  707. // increment and decrement of structures because it allows us to
  708. // avoid having to hold the spin lock for a reference.
  709. //
  710. AfdAcquireSpinLock( &AfdSpinLock, &oldIrql );
  711. //
  712. // Perform the actual decrement of the refernce count. Note that we
  713. // use the intrinsic functions for this, because of their
  714. // performance benefit.
  715. //
  716. result = InterlockedDecrement( &Connection->ReferenceCount );
  717. AfdReleaseSpinLock( &AfdSpinLock, oldIrql );
  718. //
  719. // If the reference count is now 0, free the connection in an
  720. // executive worker thread.
  721. //
  722. if ( result == 0 ) {
  723. AfdQueueWorkItem(
  724. AfdFreeConnection,
  725. &Connection->WorkItem
  726. );
  727. }
  728. } // AfdDereferenceConnection
  729. PAFD_CONNECTION
  730. AfdGetFreeConnection (
  731. IN PAFD_ENDPOINT Endpoint
  732. )
  733. /*++
  734. Routine Description:
  735. Takes a connection off of the endpoint's queue of listening
  736. connections.
  737. Arguments:
  738. Endpoint - a pointer to the endpoint from which to get a connection.
  739. Return Value:
  740. AFD_CONNECTION - a pointer to an AFD connection block.
  741. --*/
  742. {
  743. PAFD_CONNECTION connection;
  744. PLIST_ENTRY listEntry;
  745. ASSERT( Endpoint->Type == AfdBlockTypeVcListening );
  746. //
  747. // Remove the first entry from the list. If the list is empty,
  748. // return NULL.
  749. //
  750. listEntry = ExInterlockedRemoveHeadList(
  751. &Endpoint->Common.VcListening.FreeConnectionListHead,
  752. &AfdSpinLock
  753. );
  754. if ( listEntry == NULL ) {
  755. return NULL;
  756. }
  757. InterlockedDecrement(
  758. &Endpoint->Common.VcListening.FreeConnectionCount
  759. );
  760. //
  761. // Find the connection pointer from the list entry and return a
  762. // pointer to the connection object.
  763. //
  764. connection = CONTAINING_RECORD(
  765. listEntry,
  766. AFD_CONNECTION,
  767. ListEntry
  768. );
  769. return connection;
  770. } // AfdGetFreeConnection
  771. PAFD_CONNECTION
  772. AfdGetReturnedConnection (
  773. IN PAFD_ENDPOINT Endpoint,
  774. IN ULONG Sequence
  775. )
  776. /*++
  777. Routine Description:
  778. Takes a connection off of the endpoint's queue of returned
  779. connections.
  780. Arguments:
  781. Endpoint - a pointer to the endpoint from which to get a connection.
  782. Sequence - the sequence the connection must match. This is actually
  783. a pointer to the connection. If NULL, the first returned
  784. connection is used.
  785. Return Value:
  786. AFD_CONNECTION - a pointer to an AFD connection block.
  787. --*/
  788. {
  789. PAFD_CONNECTION connection;
  790. PLIST_ENTRY listEntry;
  791. KIRQL oldIrql;
  792. ASSERT( Endpoint->Type == AfdBlockTypeVcListening );
  793. AfdAcquireSpinLock( &AfdSpinLock, &oldIrql );
  794. //
  795. // Walk the endpoint's list of returned connections until we reach
  796. // the end or until we find one with a matching sequence.
  797. //
  798. for ( listEntry = Endpoint->Common.VcListening.ReturnedConnectionListHead.Flink;
  799. listEntry != &Endpoint->Common.VcListening.ReturnedConnectionListHead;
  800. listEntry = listEntry->Flink ) {
  801. connection = CONTAINING_RECORD(
  802. listEntry,
  803. AFD_CONNECTION,
  804. ListEntry
  805. );
  806. if ( Sequence == (ULONG)connection || Sequence == 0 ) {
  807. //
  808. // Found the connection we were looking for. Remove
  809. // the connection from the list, release the spin lock,
  810. // and return the connection.
  811. //
  812. RemoveEntryList( listEntry );
  813. AfdReleaseSpinLock( &AfdSpinLock, oldIrql );
  814. return connection;
  815. }
  816. }
  817. AfdReleaseSpinLock( &AfdSpinLock, oldIrql );
  818. return NULL;
  819. } // AfdGetReturnedConnection
  820. PAFD_CONNECTION
  821. AfdGetUnacceptedConnection (
  822. IN PAFD_ENDPOINT Endpoint
  823. )
  824. /*++
  825. Routine Description:
  826. Takes a connection of the endpoint's queue of unaccpted connections.
  827. *** NOTE: This routine must be called with AfdSpinLock held!!
  828. Arguments:
  829. Endpoint - a pointer to the endpoint from which to get a connection.
  830. Return Value:
  831. AFD_CONNECTION - a pointer to an AFD connection block.
  832. --*/
  833. {
  834. PAFD_CONNECTION connection;
  835. PLIST_ENTRY listEntry;
  836. ASSERT( Endpoint->Type == AfdBlockTypeVcListening );
  837. ASSERT( KeGetCurrentIrql( ) == DISPATCH_LEVEL );
  838. if ( IsListEmpty( &Endpoint->Common.VcListening.UnacceptedConnectionListHead ) ) {
  839. return NULL;
  840. }
  841. //
  842. // Dequeue a listening connection and remember its handle.
  843. //
  844. listEntry = RemoveHeadList( &Endpoint->Common.VcListening.UnacceptedConnectionListHead );
  845. connection = CONTAINING_RECORD( listEntry, AFD_CONNECTION, ListEntry );
  846. return connection;
  847. } // AfdGetUnacceptedConnection
  848. #if REFERENCE_DEBUG
  849. VOID
  850. AfdReferenceConnection (
  851. IN PAFD_CONNECTION Connection,
  852. IN PVOID Info1,
  853. IN PVOID Info2
  854. )
  855. {
  856. LONG result;
  857. ASSERT( Connection->Type == AfdBlockTypeConnection );
  858. ASSERT( Connection->ReferenceCount > 0 );
  859. ASSERT( Connection->ReferenceCount != 0xD1000000 );
  860. IF_DEBUG(CONNECTION) {
  861. KdPrint(( "AfdReferenceConnection: connection %lx, new refcnt %ld\n",
  862. Connection, Connection->ReferenceCount+1 ));
  863. }
  864. //
  865. // Do the actual increment of the reference count.
  866. //
  867. result = InterlockedIncrement( &Connection->ReferenceCount );
  868. #if REFERENCE_DEBUG
  869. AfdUpdateConnectionTrack(
  870. Connection,
  871. result,
  872. Info1,
  873. Info2,
  874. 1
  875. );
  876. #endif
  877. } // AfdReferenceConnection
  878. #endif
  879. VOID
  880. AfdAddConnectedReference (
  881. IN PAFD_CONNECTION Connection
  882. )
  883. /*++
  884. Routine Description:
  885. Adds the connected reference to an AFD connection block. The
  886. connected reference is special because it prevents the connection
  887. object from being freed until we receive a disconnect event, or know
  888. through some other means that the virtual circuit is disconnected.
  889. Arguments:
  890. Connection - a pointer to an AFD connection block.
  891. Return Value:
  892. None.
  893. --*/
  894. {
  895. KIRQL oldIrql;
  896. AfdAcquireSpinLock( &Connection->Endpoint->SpinLock, &oldIrql );
  897. IF_DEBUG(CONNECTION) {
  898. KdPrint(( "AfdAddConnectedReference: connection %lx, new refcnt %ld\n",
  899. Connection, Connection->ReferenceCount+1 ));
  900. }
  901. ASSERT( !Connection->ConnectedReferenceAdded );
  902. ASSERT( Connection->Type == AfdBlockTypeConnection );
  903. //
  904. // Increment the reference count and remember that the connected
  905. // reference has been placed on the connection object.
  906. //
  907. Connection->ConnectedReferenceAdded = TRUE;
  908. AfdRecordConnectedReferencesAdded();
  909. AfdReleaseSpinLock( &Connection->Endpoint->SpinLock, oldIrql );
  910. REFERENCE_CONNECTION( Connection );
  911. } // AfdAddConnectedReference
  912. VOID
  913. AfdDeleteConnectedReference (
  914. IN PAFD_CONNECTION Connection,
  915. IN BOOLEAN EndpointLockHeld
  916. )
  917. /*++
  918. Routine Description:
  919. Removes the connected reference to an AFD connection block. If the
  920. connected reference has already been removed, this routine does
  921. nothing. The connected reference should be removed as soon as we
  922. know that it is OK to close the connection object handle, but not
  923. before. Removing this reference too soon could abort a connection
  924. which shouldn't get aborted.
  925. Arguments:
  926. Connection - a pointer to an AFD connection block.
  927. EndpointLockHeld - TRUE if the caller already has the endpoint
  928. spin lock. The lock remains held on exit.
  929. Return Value:
  930. None.
  931. --*/
  932. {
  933. KIRQL oldIrql;
  934. PAFD_ENDPOINT endpoint;
  935. #if REFERENCE_DEBUG
  936. PVOID caller, callersCaller;
  937. RtlGetCallersAddress( &caller, &callersCaller );
  938. #endif
  939. endpoint = Connection->Endpoint;
  940. if ( !EndpointLockHeld ) {
  941. AfdAcquireSpinLock( &endpoint->SpinLock, &oldIrql );
  942. }
  943. //
  944. // Only do a dereference if the connected reference is still active
  945. // on the connectiuon object.
  946. //
  947. if ( Connection->ConnectedReferenceAdded ) {
  948. //
  949. // Three things must be true before we can remove the connected
  950. // reference:
  951. //
  952. // 1) There must be no sends outstanding on the connection if
  953. // the TDI provider does not support bufferring. This is
  954. // because AfdRestartBufferSend() looks at the connection
  955. // object.
  956. //
  957. // 2) Cleanup must have started on the endpoint. Until we get a
  958. // cleanup IRP on the endpoint, we could still get new sends.
  959. //
  960. // 3) We have been indicated with a disconnect on the
  961. // connection. We want to keep the connection object around
  962. // until we get a disconnect indication in order to avoid
  963. // premature closes on the connection object resulting in an
  964. // unintended abort. If the transport does not support
  965. // orderly release, then this condition is not necessary.
  966. //
  967. if ( (Connection->TdiBufferring ||
  968. Connection->VcBufferredSendCount == 0)
  969. &&
  970. Connection->CleanupBegun
  971. &&
  972. (Connection->AbortIndicated || Connection->DisconnectIndicated ||
  973. ( (endpoint->TransportInfo->ProviderInfo.ServiceFlags &
  974. TDI_SERVICE_ORDERLY_RELEASE) == 0)) ) {
  975. IF_DEBUG(CONNECTION) {
  976. KdPrint(( "AfdDeleteConnectedReference: connection %lx, "
  977. "new refcnt %ld\n",
  978. Connection, Connection->ReferenceCount-1 ));
  979. }
  980. //
  981. // Be careful about the order of things here. We must FIRST
  982. // reset the flag, then release the spin lock and call
  983. // AfdDereferenceConnection(). Note that it is illegal to
  984. // call AfdDereferenceConnection() with a spin lock held.
  985. //
  986. Connection->ConnectedReferenceAdded = FALSE;
  987. AfdRecordConnectedReferencesDeleted();
  988. if ( !EndpointLockHeld ) {
  989. AfdReleaseSpinLock( &endpoint->SpinLock, oldIrql );
  990. }
  991. DEREFERENCE_CONNECTION( Connection );
  992. } else {
  993. IF_DEBUG(CONNECTION) {
  994. KdPrint(( "AfdDeleteConnectedReference: connection %lx, "
  995. "%ld sends pending\n",
  996. Connection, Connection->VcBufferredSendCount ));
  997. }
  998. #if REFERENCE_DEBUG
  999. {
  1000. ULONG action;
  1001. action = 0;
  1002. if ( !Connection->TdiBufferring &&
  1003. Connection->VcBufferredSendCount != 0 ) {
  1004. action |= 0xA0000000;
  1005. }
  1006. if ( !Connection->CleanupBegun ) {
  1007. action |= 0x0B000000;
  1008. }
  1009. if ( !Connection->AbortIndicated && !Connection->DisconnectIndicated ) {
  1010. action |= 0x00C00000;
  1011. }
  1012. UPDATE_CONN( Connection, action );
  1013. }
  1014. #endif
  1015. //
  1016. // Remember that the connected reference deletion is still
  1017. // pending, i.e. there is a special condition on the
  1018. // endpoint. This will cause AfdRestartBufferSend() to do
  1019. // the actual dereference when the last send completes.
  1020. //
  1021. Connection->SpecialCondition = TRUE;
  1022. if ( !EndpointLockHeld ) {
  1023. AfdReleaseSpinLock( &endpoint->SpinLock, oldIrql );
  1024. }
  1025. }
  1026. } else {
  1027. IF_DEBUG(CONNECTION) {
  1028. KdPrint(( "AfdDeleteConnectedReference: already removed on "
  1029. " connection %lx, refcnt %ld\n",
  1030. Connection, Connection->ReferenceCount ));
  1031. }
  1032. if ( !EndpointLockHeld ) {
  1033. AfdReleaseSpinLock( &endpoint->SpinLock, oldIrql );
  1034. }
  1035. }
  1036. return;
  1037. } // AfdDeleteConnectedReference
  1038. #if REFERENCE_DEBUG
  1039. VOID
  1040. AfdUpdateConnectionTrack (
  1041. IN PAFD_CONNECTION Connection,
  1042. IN LONG NewReferenceCount,
  1043. IN PVOID Info1,
  1044. IN PVOID Info2,
  1045. IN ULONG Action
  1046. )
  1047. {
  1048. PAFD_REFERENCE_DEBUG slot;
  1049. LONG newSlot;
  1050. newSlot = InterlockedIncrement( &Connection->CurrentReferenceSlot );
  1051. slot = &Connection->ReferenceDebug[newSlot % MAX_REFERENCE];
  1052. slot->Info1 = Info1;
  1053. slot->Info2 = Info2;
  1054. slot->Action = Action;
  1055. slot->NewCount = NewReferenceCount;
  1056. #if GLOBAL_REFERENCE_DEBUG
  1057. {
  1058. PAFD_GLOBAL_REFERENCE_DEBUG globalSlot;
  1059. newSlot = InterlockedIncrement( &AfdGlobalReferenceSlot );
  1060. globalSlot = &AfdGlobalReference[newSlot % MAX_GLOBAL_REFERENCE];
  1061. globalSlot->Info1 = Info1;
  1062. globalSlot->Info2 = Info2;
  1063. globalSlot->Action = Action;
  1064. globalSlot->NewCount = NewReferenceCount;
  1065. globalSlot->Connection = Connection;
  1066. KeQueryTickCount( &globalSlot->TickCounter );
  1067. }
  1068. #endif
  1069. } // AfdUpdateConnectionTrack
  1070. #endif