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.

1366 lines
39 KiB

  1. /*++
  2. Copyright (c) 1989 Microsoft Corporation
  3. Module Name:
  4. blkconn.c
  5. Abstract:
  6. This module implements routines for managing connection blocks.
  7. Author:
  8. Chuck Lenzmeier (chuckl) 4-Oct-1989
  9. Revision History:
  10. --*/
  11. #include "precomp.h"
  12. #include "blkconn.tmh"
  13. #pragma hdrstop
  14. #define BugCheckFileId SRV_FILE_BLKCONN
  15. #ifdef ALLOC_PRAGMA
  16. #pragma alloc_text( PAGE, SrvAllocateConnection )
  17. #pragma alloc_text( PAGE, SrvCloseConnectionsFromClient )
  18. #if !defined(DBG) || DBG == 0
  19. #pragma alloc_text( PAGE, SrvFreeConnection )
  20. #endif
  21. #endif
  22. #if 0
  23. NOT PAGEABLE -- SrvCloseConnection
  24. NOT PAGEABLE -- SrvCloseFreeConnection
  25. NOT PAGEABLE -- SrvDereferenceConnection
  26. NOT PAGEABLE -- SrvQueryConnections
  27. #endif
  28. CHAR DisconnectReasonText[((USHORT)DisconnectReasons)+1][32] = {
  29. "Idle Connection",
  30. "Endpoint Closing",
  31. "2nd Sess Setup on Conn",
  32. "Transport Issued Disconnect",
  33. "Session Deleted",
  34. "Bad SMB Packet",
  35. "Suspected DOS",
  36. "Cancelled/Failed Receive",
  37. "Stale IPX Conn",
  38. "Unknown"
  39. };
  40. VOID
  41. SrvAllocateConnection (
  42. OUT PCONNECTION *Connection
  43. )
  44. /*++
  45. Routine Description:
  46. This function allocates a Connection Block from the system nonpaged
  47. pool.
  48. Arguments:
  49. Connection - Returns a pointer to the connection block, or NULL if
  50. no pool was available.
  51. Return Value:
  52. None.
  53. --*/
  54. {
  55. PCONNECTION connection;
  56. ULONG i;
  57. PPAGED_CONNECTION pagedConnection;
  58. PAGED_CODE( );
  59. //
  60. // Attempt to allocate from nonpaged pool.
  61. //
  62. connection = ALLOCATE_NONPAGED_POOL( sizeof(CONNECTION), BlockTypeConnection );
  63. *Connection = connection;
  64. if ( connection == NULL ) {
  65. INTERNAL_ERROR(
  66. ERROR_LEVEL_EXPECTED,
  67. "SrvAllocateConnection: Unable to allocate %d bytes from"
  68. "nonpaged pool",
  69. sizeof( CONNECTION ),
  70. NULL
  71. );
  72. return;
  73. }
  74. RtlZeroMemory( connection, sizeof(CONNECTION) );
  75. pagedConnection = ALLOCATE_HEAP_COLD(
  76. sizeof(PAGED_CONNECTION),
  77. BlockTypePagedConnection );
  78. if ( pagedConnection == NULL ) {
  79. INTERNAL_ERROR(
  80. ERROR_LEVEL_EXPECTED,
  81. "SrvAllocateConnection: Unable to allocate %d bytes from"
  82. "paged pool",
  83. sizeof( PAGED_CONNECTION ),
  84. NULL
  85. );
  86. goto error_exit;
  87. }
  88. IF_DEBUG(HEAP) {
  89. KdPrint(( "SrvAllocateConnection: Allocated connection at %p\n",
  90. connection ));
  91. }
  92. RtlZeroMemory( pagedConnection, sizeof(PAGED_CONNECTION) );
  93. SET_BLOCK_TYPE_STATE_SIZE( connection, BlockTypeConnection, BlockStateInitializing, sizeof( CONNECTION ) );
  94. connection->PagedConnection = pagedConnection;
  95. pagedConnection->PagedHeader.NonPagedBlock = connection;
  96. pagedConnection->PagedHeader.Type = BlockTypePagedConnection;
  97. connection->BlockHeader.ReferenceCount = 2; // allow for Active status
  98. // and caller's pointer
  99. InitializeListHead( &pagedConnection->TransactionList );
  100. connection->SmbDialect = SmbDialectIllegal;
  101. connection->CachedFid = (ULONG)-1;
  102. //
  103. // Allocate session table.
  104. //
  105. SrvAllocateTable(
  106. &pagedConnection->SessionTable,
  107. SrvInitialSessionTableSize,
  108. FALSE
  109. );
  110. if ( pagedConnection->SessionTable.Table == NULL ) {
  111. goto error_exit;
  112. }
  113. //
  114. // Allocate tree connect table.
  115. //
  116. SrvAllocateTable(
  117. &pagedConnection->TreeConnectTable,
  118. SrvInitialTreeTableSize,
  119. FALSE
  120. );
  121. if ( pagedConnection->TreeConnectTable.Table == NULL ) {
  122. goto error_exit;
  123. }
  124. //
  125. // Allocate file table.
  126. //
  127. SrvAllocateTable(
  128. &connection->FileTable,
  129. SrvInitialFileTableSize,
  130. TRUE
  131. );
  132. if ( connection->FileTable.Table == NULL ) {
  133. goto error_exit;
  134. }
  135. //
  136. // Allocate search table.
  137. //
  138. SrvAllocateTable(
  139. &pagedConnection->SearchTable,
  140. SrvInitialSearchTableSize,
  141. FALSE
  142. );
  143. if ( pagedConnection->SearchTable.Table == NULL ) {
  144. goto error_exit;
  145. }
  146. //
  147. // Initialize core search list heads
  148. //
  149. InitializeListHead( &pagedConnection->CoreSearchList );
  150. //
  151. // Initialize the locks that protect the connection and its data.
  152. //
  153. INITIALIZE_SPIN_LOCK( &connection->SpinLock );
  154. INITIALIZE_SPIN_LOCK( &connection->Interlock );
  155. INITIALIZE_LOCK( &connection->Lock, CONNECTION_LOCK_LEVEL, "ConnectionLock" );
  156. INITIALIZE_LOCK( &connection->LicenseLock, LICENSE_LOCK_LEVEL, "LicenseLock" );
  157. //
  158. // Initialize the client machine name string.
  159. //
  160. connection->ClientMachineNameString.Buffer =
  161. connection->LeadingSlashes;
  162. connection->ClientMachineNameString.Length = 0;
  163. connection->ClientMachineNameString.MaximumLength =
  164. (USHORT)((2 + COMPUTER_NAME_LENGTH + 1) * sizeof(WCHAR));
  165. connection->LeadingSlashes[0] = '\\';
  166. connection->LeadingSlashes[1] = '\\';
  167. //
  168. // Initialize the oem client machine name string
  169. //
  170. connection->OemClientMachineNameString.Buffer =
  171. connection->OemClientMachineName;
  172. connection->OemClientMachineNameString.MaximumLength =
  173. (USHORT)(COMPUTER_NAME_LENGTH + 1);
  174. //
  175. // Initialize count of sessions.
  176. //
  177. // *** Already done by RtlZeroMemory.
  178. //pagedConnection->CurrentNumberOfSessions = 0;
  179. //
  180. // Initialize the in-progress work item list, the outstanding
  181. // oplock breaks list, and the cached-after-close lists.
  182. //
  183. InitializeListHead( &connection->InProgressWorkItemList );
  184. InitializeListHead( &connection->OplockWorkList );
  185. InitializeListHead( &connection->CachedOpenList );
  186. InitializeListHead( &connection->CachedDirectoryList );
  187. // Initialize the CachedTransactionList
  188. ExInitializeSListHead( &connection->CachedTransactionList );
  189. SET_INVALID_CONTEXT_HANDLE(connection->NegotiateHandle);
  190. //
  191. // Indicate that security signatures are not active
  192. //
  193. connection->SmbSecuritySignatureActive = FALSE;
  194. //
  195. // Indicate that no IPX saved response buffer has been allocated.
  196. //
  197. connection->LastResponse = connection->BuiltinSavedResponse;
  198. //
  199. // Initialize the search hash table list.
  200. //
  201. for ( i = 0; i < SEARCH_HASH_TABLE_SIZE ; i++ ) {
  202. InitializeListHead( &pagedConnection->SearchHashTable[i].ListHead );
  203. }
  204. INITIALIZE_REFERENCE_HISTORY( connection );
  205. INCREMENT_DEBUG_STAT2( SrvDbgStatistics.ConnectionInfo.Allocations );
  206. return;
  207. error_exit:
  208. if ( pagedConnection != NULL ) {
  209. if ( pagedConnection->SessionTable.Table != NULL ) {
  210. SrvFreeTable( &pagedConnection->SessionTable );
  211. }
  212. if ( pagedConnection->TreeConnectTable.Table != NULL ) {
  213. SrvFreeTable( &pagedConnection->TreeConnectTable );
  214. }
  215. if ( pagedConnection->SearchTable.Table != NULL ) {
  216. SrvFreeTable( &pagedConnection->SearchTable );
  217. }
  218. FREE_HEAP( pagedConnection );
  219. }
  220. if ( connection != NULL ) {
  221. if ( connection->FileTable.Table != NULL ) {
  222. SrvFreeTable( &connection->FileTable );
  223. }
  224. DEALLOCATE_NONPAGED_POOL( connection );
  225. *Connection = NULL;
  226. }
  227. return;
  228. } // SrvAllocateConnection
  229. VOID
  230. SrvCloseConnection (
  231. IN PCONNECTION Connection,
  232. IN BOOLEAN RemoteDisconnect
  233. )
  234. /*++
  235. Routine Description:
  236. This function closes a connection (virtual circuit).
  237. *** This routine must NOT be entered with the connection lock held!
  238. It may be entered with the endpoint lock held.
  239. Arguments:
  240. Connection - Supplies a pointer to a Connection Block
  241. RemoteDisconnect - Indicates whether this call is being made in
  242. response to a notification by the transport provider.
  243. Return Value:
  244. None.
  245. --*/
  246. {
  247. PTABLE_HEADER tableHeader;
  248. PLIST_ENTRY listEntry;
  249. USHORT i;
  250. KIRQL oldIrql;
  251. PRFCB rfcb;
  252. ASSERT( !ExIsResourceAcquiredExclusiveLite(&RESOURCE_OF(Connection->Lock)) );
  253. ACQUIRE_LOCK( &Connection->Lock );
  254. //
  255. // If the connection hasn't already been closed, do so now.
  256. //
  257. if ( GET_BLOCK_STATE(Connection) == BlockStateActive ) {
  258. #if SRVDBG29
  259. {
  260. ULONG conn = (ULONG)Connection;
  261. if (RemoteDisconnect) conn |= 1;
  262. if (Connection->DisconnectPending) conn |= 2;
  263. UpdateConnectionHistory( "CLOS", Connection->Endpoint, Connection );
  264. }
  265. #endif
  266. IF_DEBUG(TDI) KdPrint(( "Closing connection (%s) at %p for %z\n",
  267. DisconnectReasonText[(USHORT)Connection->DisconnectReason], Connection, (PCSTRING)&Connection->OemClientMachineNameString ));
  268. IF_DEBUG( ERRORS ) {
  269. if( RemoteDisconnect == FALSE ) {
  270. KdPrint(( "SrvCloseConnection: forcibly closing connection %p (%s)\n", Connection, DisconnectReasonText[(USHORT)Connection->DisconnectReason] ));
  271. }
  272. }
  273. SET_BLOCK_STATE( Connection, BlockStateClosing );
  274. RELEASE_LOCK( &Connection->Lock );
  275. //
  276. // If the connection is on the need-resource queue (waiting for
  277. // a work item) or the disconnect queue (a Disconnect having
  278. // been indicated by the transport), remove it now, and
  279. // dereference it. (Note that the connection can't go away yet,
  280. // because the initial reference is still there.)
  281. //
  282. ACQUIRE_GLOBAL_SPIN_LOCK( Fsd, &oldIrql );
  283. //
  284. // Invalidate the cached connection
  285. //
  286. if ( Connection->OnNeedResourceQueue ) {
  287. SrvRemoveEntryList(
  288. &SrvNeedResourceQueue,
  289. &Connection->ListEntry
  290. );
  291. Connection->OnNeedResourceQueue = FALSE;
  292. DEBUG Connection->ReceivePending = FALSE;
  293. RELEASE_GLOBAL_SPIN_LOCK( Fsd, oldIrql );
  294. SrvDereferenceConnection( Connection );
  295. } else if ( Connection->DisconnectPending ) {
  296. SrvRemoveEntryList(
  297. &SrvDisconnectQueue,
  298. &Connection->ListEntry
  299. );
  300. DEBUG Connection->DisconnectPending = FALSE;
  301. RELEASE_GLOBAL_SPIN_LOCK( Fsd, oldIrql );
  302. SrvDereferenceConnection( Connection );
  303. //
  304. // If there's a disconnect pending, then don't try to shut
  305. // down the connection later.
  306. //
  307. RemoteDisconnect = TRUE;
  308. } else {
  309. RELEASE_GLOBAL_SPIN_LOCK( Fsd, oldIrql );
  310. }
  311. //
  312. // If this is not a remote disconnect, issue a TdiDisconnect
  313. // request now.
  314. //
  315. // *** This is currently done as a synchronous request. It may
  316. // be better to do this asynchronously.
  317. //
  318. if ( !RemoteDisconnect && !Connection->Endpoint->IsConnectionless ) {
  319. SrvDoDisconnect( Connection );
  320. }
  321. //
  322. // Close all active sessions. (This also causes all open files
  323. // and pending transactions to be closed.)
  324. //
  325. SrvCloseSessionsOnConnection( Connection, NULL );
  326. //
  327. // Close all active tree connects.
  328. //
  329. // *** Reference the tree connect for the same reasons as we
  330. // referenced the session; see above.
  331. tableHeader = &Connection->PagedConnection->TreeConnectTable;
  332. ACQUIRE_LOCK( &Connection->Lock );
  333. for ( i = 0; i < tableHeader->TableSize; i++ ) {
  334. PTREE_CONNECT treeConnect =
  335. (PTREE_CONNECT)tableHeader->Table[i].Owner;
  336. if ( treeConnect != NULL &&
  337. GET_BLOCK_STATE( treeConnect ) == BlockStateActive ) {
  338. SrvReferenceTreeConnect( treeConnect );
  339. RELEASE_LOCK( &Connection->Lock );
  340. SrvCloseTreeConnect( treeConnect );
  341. SrvDereferenceTreeConnect( treeConnect );
  342. ACQUIRE_LOCK( &Connection->Lock );
  343. }
  344. }
  345. //
  346. // If there is state associated with a extended security negotiate,
  347. // free it up.
  348. //
  349. if (IS_VALID_CONTEXT_HANDLE(Connection->NegotiateHandle)) {
  350. DeleteSecurityContext( &Connection->NegotiateHandle );
  351. }
  352. SET_INVALID_CONTEXT_HANDLE( Connection->NegotiateHandle );
  353. RELEASE_LOCK( &Connection->Lock );
  354. //
  355. // Cancel all outstanding oplock break requests.
  356. //
  357. while ( (listEntry = ExInterlockedRemoveHeadList(
  358. &Connection->OplockWorkList,
  359. Connection->EndpointSpinLock
  360. )) != NULL ) {
  361. //
  362. // Remove this work item from the connection queue and
  363. // return it to the free queue.
  364. //
  365. rfcb = CONTAINING_RECORD( listEntry, RFCB, ListEntry );
  366. #if DBG
  367. rfcb->ListEntry.Flink = rfcb->ListEntry.Blink = NULL;
  368. #endif
  369. SrvDereferenceRfcb( rfcb );
  370. }
  371. //
  372. // Close RFCBs that are cached after having been closed by the
  373. // client.
  374. //
  375. SrvCloseCachedRfcbsOnConnection( Connection );
  376. //
  377. // Dereference the connection (to indicate that it's no longer
  378. // open). This may cause the connection block to be deleted.
  379. //
  380. SrvDereferenceConnection( Connection );
  381. INCREMENT_DEBUG_STAT2( SrvDbgStatistics.ConnectionInfo.Closes );
  382. } else {
  383. RELEASE_LOCK( &Connection->Lock );
  384. }
  385. return;
  386. } // SrvCloseConnection
  387. VOID
  388. SrvCloseConnectionsFromClient (
  389. IN PCONNECTION Connection,
  390. IN BOOLEAN OnlyIfNoSessions
  391. )
  392. /*++
  393. Routine Description:
  394. This routine closes all connections from a given remote machine name
  395. except the connection passed in. This is used in the Session Setup
  396. SMB when the client indicates that he believes that he has exactly
  397. one connection to this server; if there are others, we know that
  398. they are not valid.
  399. Arguments:
  400. Connection - Address of connection to keep around. This is used
  401. for the machine name.
  402. OnlyIfNoSessions - Kill off the duplicate connections only if they do
  403. not have any established sessions.
  404. Return Value:
  405. None.
  406. --*/
  407. {
  408. USHORT index;
  409. PENDPOINT endpoint;
  410. PLIST_ENTRY listEntry;
  411. PCONNECTION testConnection;
  412. BOOLEAN Connectionless = Connection->Endpoint->IsConnectionless == 1;
  413. BOOLEAN IsIPAddress = (Connection->ClientIPAddress != 0);
  414. PAGED_CODE( );
  415. //
  416. // We need to look at the name of every client for which the server
  417. // has a connection. Connection lists are stored off endpoints, so
  418. // walk the global endpoint list and the list of connections on each
  419. // endpoint.
  420. //
  421. IF_DEBUG(TDI) {
  422. KdPrint(( "SrvCloseConnectionsFromClient entered for connection "
  423. "%p, OemName %z, looking for %wZ\n", Connection,
  424. (PCSTRING)&Connection->OemClientMachineNameString,
  425. &Connection->ClientMachineNameString));
  426. }
  427. if( IsIPAddress )
  428. {
  429. UNICODE_STRING strippedName;
  430. strippedName = Connection->ClientMachineNameString;
  431. strippedName.Buffer += 2;
  432. strippedName.Length -= 2*sizeof(WCHAR);
  433. IsIPAddress = SrvIsDottedQuadAddress( &strippedName );
  434. }
  435. ACQUIRE_LOCK( &SrvEndpointLock );
  436. listEntry = SrvEndpointList.ListHead.Flink;
  437. while ( listEntry != &SrvEndpointList.ListHead ) {
  438. endpoint = CONTAINING_RECORD(
  439. listEntry,
  440. ENDPOINT,
  441. GlobalEndpointListEntry
  442. );
  443. //
  444. // If this endpoint is closing, or if the types don't match,
  445. // skip to the next one.
  446. // Otherwise, reference the endpoint so that it can't go away.
  447. //
  448. if ( GET_BLOCK_STATE(endpoint) != BlockStateActive ||
  449. endpoint->IsConnectionless != Connectionless ) {
  450. listEntry = listEntry->Flink;
  451. continue;
  452. }
  453. //
  454. // If this endpoint doesn't have the same netbios name as the
  455. // endpoint of the passed-in connection then skip it. This is
  456. // to allow servers to have more than one name on the network.
  457. //
  458. if( Connection->Endpoint->TransportAddress.Length !=
  459. endpoint->TransportAddress.Length ||
  460. !RtlEqualMemory( Connection->Endpoint->TransportAddress.Buffer,
  461. endpoint->TransportAddress.Buffer,
  462. endpoint->TransportAddress.Length ) ) {
  463. //
  464. // This connection is for an endpoint having a different network
  465. // name than does this endpoint. Skip this endpoint.
  466. //
  467. listEntry = listEntry->Flink;
  468. continue;
  469. }
  470. #if 0
  471. //
  472. // If this endpoint doesn't have the same transport name as the one
  473. // on which the client is connecting, then skip it. This is for
  474. // multihomed servers.
  475. //
  476. if( Connection->Endpoint->TransportName.Length !=
  477. endpoint->TransportName.Length ||
  478. !RtlEqualMemory( Connection->Endpoint->TransportName.Buffer,
  479. endpoint->TransportName.Buffer,
  480. endpoint->TransportName.Length ) ) {
  481. //
  482. // This connection is for an endpoint coming in over a different
  483. // stack instance.
  484. //
  485. listEntry = listEntry->Flink;
  486. continue;
  487. }
  488. #endif
  489. SrvReferenceEndpoint( endpoint );
  490. //
  491. // Walk the endpoint's connection table.
  492. //
  493. index = (USHORT)-1;
  494. while ( TRUE ) {
  495. //
  496. // Get the next active connection in the table. If no more
  497. // are available, WalkConnectionTable returns NULL.
  498. // Otherwise, it returns a referenced pointer to a
  499. // connection.
  500. //
  501. testConnection = WalkConnectionTable( endpoint, &index );
  502. if ( testConnection == NULL ) {
  503. break;
  504. }
  505. if( testConnection == Connection ) {
  506. //
  507. // Skip ourselves!
  508. //
  509. SrvDereferenceConnection( testConnection );
  510. continue;
  511. }
  512. if( OnlyIfNoSessions == TRUE &&
  513. testConnection->CurrentNumberOfSessions != 0 ) {
  514. //
  515. // This connection has sessions. Skip it.
  516. //
  517. SrvDereferenceConnection( testConnection );
  518. continue;
  519. }
  520. else if( OnlyIfNoSessions == FALSE &&
  521. testConnection->CurrentNumberOfSessions == 0 ) {
  522. //
  523. // This connection has no sessions. Skip it. (It could be a session established from the
  524. // same machine that has not had its session setup reach yet. Thus, the client may know about
  525. // this session, but SRV doesn't)
  526. //
  527. SrvDereferenceConnection( testConnection );
  528. continue;
  529. }
  530. if( Connectionless ) {
  531. //
  532. // Connectionless clients match on IPX address...
  533. //
  534. if( !RtlEqualMemory( &Connection->IpxAddress,
  535. &testConnection->IpxAddress,
  536. sizeof(Connection->IpxAddress) ) ) {
  537. SrvDereferenceConnection( testConnection );
  538. continue;
  539. }
  540. } else {
  541. //
  542. // If the IP address matches, then nuke this client
  543. //
  544. if( IsIPAddress &&
  545. Connection->ClientIPAddress == testConnection->ClientIPAddress ) {
  546. goto nuke_it;
  547. }
  548. //
  549. // If the computer name matches, then nuke this client
  550. //
  551. if ( RtlCompareUnicodeString(
  552. &testConnection->ClientMachineNameString,
  553. &Connection->ClientMachineNameString,
  554. TRUE
  555. ) == 0 ) {
  556. goto nuke_it;
  557. }
  558. //
  559. // Neither the IP address nor the name match -- skip this client
  560. //
  561. SrvDereferenceConnection( testConnection );
  562. continue;
  563. }
  564. nuke_it:
  565. //
  566. // We found a connection that we need to kill. We
  567. // have to release the lock in order to close it.
  568. //
  569. RELEASE_LOCK( &SrvEndpointLock );
  570. IF_DEBUG(TDI) {
  571. KdPrint(( "SrvCloseConnectionsFromClient closing "
  572. "connection %p, MachineNameString %Z\n",
  573. testConnection,
  574. &testConnection->ClientMachineNameString ));
  575. }
  576. #if SRVDBG29
  577. UpdateConnectionHistory( "CFC1", testConnection->Endpoint, testConnection );
  578. UpdateConnectionHistory( "CFC2", testConnection->Endpoint, Connection );
  579. #endif
  580. testConnection->DisconnectReason = DisconnectNewSessionSetupOnConnection;
  581. SrvCloseConnection( testConnection, FALSE );
  582. ACQUIRE_LOCK( &SrvEndpointLock );
  583. //
  584. // Dereference the connection to account for the reference
  585. // from WalkConnectionTable.
  586. //
  587. SrvDereferenceConnection( testConnection );
  588. } // walk connection table
  589. //
  590. // Capture a pointer to the next endpoint in the list (that one
  591. // can't go away because we hold the endpoint list), then
  592. // dereference the current endpoint.
  593. //
  594. listEntry = listEntry->Flink;
  595. SrvDereferenceEndpoint( endpoint );
  596. } // walk endpoint list
  597. RELEASE_LOCK( &SrvEndpointLock );
  598. } // SrvCloseConnectionsFromClient
  599. VOID
  600. SrvCloseFreeConnection (
  601. IN PCONNECTION Connection
  602. )
  603. /*++
  604. Routine Description:
  605. This function closes a free connection. This is a connection that
  606. is not active -- has already been closed via SrvCloseConnection --
  607. and is no longer needed.
  608. *** WARNING! This routine frees the storage occupied by Connection!
  609. Arguments:
  610. Connection - Supplies a pointer to a Connection Block
  611. Return Value:
  612. None.
  613. --*/
  614. {
  615. PENDPOINT endpoint;
  616. PPAGED_CONNECTION pagedConnection = Connection->PagedConnection;
  617. KIRQL oldIrql;
  618. ASSERT( Connection->BlockHeader.ReferenceCount == 0 );
  619. endpoint = Connection->Endpoint;
  620. ACQUIRE_LOCK( &SrvEndpointLock );
  621. //
  622. // Remove the connection from the endpoint's connection table.
  623. //
  624. if ( Connection->Sid != 0 ) {
  625. ACQUIRE_SPIN_LOCK( Connection->EndpointSpinLock, &oldIrql );
  626. SrvRemoveEntryTable(
  627. &endpoint->ConnectionTable,
  628. Connection->SidIndex
  629. );
  630. RELEASE_SPIN_LOCK( Connection->EndpointSpinLock, oldIrql );
  631. Connection->Sid = 0;
  632. }
  633. //
  634. // Decrement the count of connections for the endpoint.
  635. //
  636. ExInterlockedAddUlong(
  637. &endpoint->TotalConnectionCount,
  638. (ULONG)-1,
  639. &GLOBAL_SPIN_LOCK(Fsd)
  640. );
  641. RELEASE_LOCK( &SrvEndpointLock );
  642. //
  643. // Close the connection file object. Remove the additional
  644. // reference.
  645. //
  646. if ( !endpoint->IsConnectionless ) {
  647. SRVDBG_RELEASE_HANDLE( pagedConnection->ConnectionHandle, "CON", 1, Connection );
  648. SrvNtClose( pagedConnection->ConnectionHandle, FALSE );
  649. ObDereferenceObject( Connection->FileObject );
  650. }
  651. //
  652. // Dereference the endpoint.
  653. //
  654. SrvDereferenceEndpoint( endpoint );
  655. //
  656. // Free the storage occupied by the connection.
  657. //
  658. SrvFreeConnection( Connection );
  659. return;
  660. } // SrvCloseFreeConnection
  661. VOID
  662. SrvDereferenceConnection (
  663. IN PCONNECTION Connection
  664. )
  665. /*++
  666. Routine Description:
  667. This function decrements the reference count on a connection. If the
  668. reference count goes to zero, the connection block is deleted.
  669. The connection lock must not be held when this routine is called,
  670. because the global endpoint lock, which has a lower level, must be
  671. acquired.
  672. Arguments:
  673. Connection - Address of connection
  674. Return Value:
  675. None.
  676. --*/
  677. {
  678. ULONG oldCount;
  679. PENDPOINT endpoint;
  680. KIRQL oldIrql;
  681. PPAGED_CONNECTION pagedConnection = Connection->PagedConnection;
  682. ASSERT( GET_BLOCK_TYPE( Connection ) == BlockTypeConnection );
  683. ASSERT( (LONG)Connection->BlockHeader.ReferenceCount > 0 );
  684. UPDATE_REFERENCE_HISTORY( Connection, TRUE );
  685. //
  686. // Perform an interlocked decrement of the connection block's
  687. // reference count.
  688. //
  689. // *** Note that we don't hold a lock between the time we decrement
  690. // the reference count and the time we delete the connection
  691. // block. Normally this would imply that the FSD could
  692. // reference the block in between. However, the transport
  693. // provider guarantees that it won't deliver any more events
  694. // after a remote Disconnect event or after a local
  695. // TdiDisconnect request, and one of those two things has to
  696. // happen before the reference count can go to 0 (see
  697. // SrvCloseConnection).
  698. //
  699. oldCount = ExInterlockedAddUlong(
  700. &Connection->BlockHeader.ReferenceCount,
  701. (ULONG)-1,
  702. Connection->EndpointSpinLock
  703. );
  704. IF_DEBUG(REFCNT) {
  705. KdPrint(( "Dereferencing connection %p; old refcnt %lx\n",
  706. Connection, oldCount ));
  707. }
  708. if ( oldCount == 1 ) {
  709. //
  710. // The new reference count is 0, meaning that it's time to
  711. // delete this block.
  712. //
  713. ASSERT( GET_BLOCK_STATE(Connection) != BlockStateActive );
  714. #if SRVDBG29
  715. if ( GET_BLOCK_STATE(Connection) != BlockStateClosing ) {
  716. KdPrint(( "SRV: Connection is not CLOSING with refcnt 0!\n" ));
  717. DbgBreakPoint( );
  718. }
  719. #endif
  720. //
  721. // Free the space allocated for client Domain, OS Name, and
  722. // LAN type.
  723. //
  724. if ( Connection->ClientOSType.Buffer != NULL ) {
  725. DEALLOCATE_NONPAGED_POOL( Connection->ClientOSType.Buffer );
  726. Connection->ClientOSType.Buffer = NULL;
  727. }
  728. //
  729. // Keep the WORK_QUEUE statistic correct
  730. //
  731. if( Connection->CurrentWorkQueue )
  732. InterlockedDecrement( &Connection->CurrentWorkQueue->CurrentClients );
  733. // (Always TRUE) ASSERT( Connection->CurrentWorkQueue->CurrentClients >= 0 );
  734. endpoint = Connection->Endpoint;
  735. ACQUIRE_LOCK( &SrvEndpointLock );
  736. //
  737. // If the connection hasn't been marked as not reusable (e.g.,
  738. // because a disconnect failed), and the endpoint isn't closing,
  739. // and it isn't already "full" of free connections, put this
  740. // connection on the endpoint's free connection list.
  741. // Otherwise, close the connection file object and free the
  742. // connection block.
  743. //
  744. if ( !Connection->NotReusable &&
  745. (GET_BLOCK_STATE(endpoint) == BlockStateActive) &&
  746. (endpoint->FreeConnectionCount < SrvFreeConnectionMaximum) ) {
  747. //
  748. // Reinitialize the connection state.
  749. //
  750. // !!! Should probably reset the connection's table sizes,
  751. // if they've grown.
  752. //
  753. SET_BLOCK_STATE( Connection, BlockStateInitializing );
  754. pagedConnection->LinkInfoValidTime.QuadPart = 0;
  755. pagedConnection->Throughput.QuadPart = 0;
  756. pagedConnection->Delay.QuadPart = 0;
  757. Connection->CurrentNumberOfSessions = 0;
  758. Connection->ClientMachineNameString.Length = 0;
  759. Connection->ClientCapabilities = 0;
  760. Connection->SmbDialect = SmbDialectIllegal;
  761. Connection->DisconnectPending = FALSE;
  762. Connection->ReceivePending = FALSE;
  763. Connection->OplocksAlwaysDisabled = FALSE;
  764. Connection->CachedFid = (ULONG)-1;
  765. Connection->InProgressWorkContextCount = 0;
  766. Connection->IsConnectionSuspect = FALSE;
  767. Connection->DisconnectReason = DisconnectReasons;
  768. Connection->OperationsPendingOnTransport = 0;
  769. //
  770. // Put the connection on the free list.
  771. //
  772. ACQUIRE_GLOBAL_SPIN_LOCK( Fsd, &oldIrql );
  773. #if SRVDBG29
  774. UpdateConnectionHistory( "KEEP", endpoint, Connection );
  775. #endif
  776. SrvInsertTailList(
  777. &endpoint->FreeConnectionList,
  778. &Connection->EndpointFreeListEntry
  779. );
  780. endpoint->FreeConnectionCount++;
  781. RELEASE_GLOBAL_SPIN_LOCK( Fsd, oldIrql );
  782. RELEASE_LOCK( &SrvEndpointLock );
  783. } else {
  784. RELEASE_LOCK( &SrvEndpointLock );
  785. SrvCloseFreeConnection( Connection );
  786. }
  787. }
  788. return;
  789. } // SrvDereferenceConnection
  790. VOID
  791. SrvFreeConnection (
  792. IN PCONNECTION Connection
  793. )
  794. /*++
  795. Routine Description:
  796. This function returns a Connection Block to the system nonpaged
  797. pool.
  798. Arguments:
  799. Connection - Address of connection
  800. Return Value:
  801. None.
  802. --*/
  803. {
  804. PSLIST_ENTRY listEntry;
  805. PNONPAGED_HEADER header;
  806. PTRANSACTION transaction;
  807. PPAGED_CONNECTION pagedConnection = Connection->PagedConnection;
  808. #if 0
  809. //
  810. // ENSURE WE ARE NOT STILL IN THE CONNECTION TABLE FOR THE ENDPOINT!
  811. //
  812. if( Connection->Endpoint ) {
  813. PTABLE_HEADER tableHeader = &Connection->Endpoint->ConnectionTable;
  814. USHORT i;
  815. KIRQL oldIrql;
  816. ACQUIRE_SPIN_LOCK( &ENDPOINT_SPIN_LOCK(0), &oldIrql );
  817. for ( i = 1; i < ENDPOINT_LOCK_COUNT ; i++ ) {
  818. ACQUIRE_DPC_SPIN_LOCK( &ENDPOINT_SPIN_LOCK(i) );
  819. }
  820. for( i = 0; i < tableHeader->TableSize; i++ ) {
  821. if( (PCONNECTION)tableHeader->Table[i].Owner == Connection ) {
  822. DbgPrint( "SRV: SrvFreeConnection(%p), but connection still in endpoint %p ConnectionTable\n",
  823. Connection, Connection->Endpoint );
  824. DbgPrint( " Entry number %d, addr %p\n", i, &tableHeader->Table[i] );
  825. DbgPrint( " Connection->Sid %X, IPXSID %d\n", Connection->Sid, IPXSID_INDEX(Connection->Sid));
  826. DbgBreakPoint();
  827. break;
  828. }
  829. }
  830. for ( i = ENDPOINT_LOCK_COUNT-1 ; i > 0 ; i-- ) {
  831. RELEASE_DPC_SPIN_LOCK( &ENDPOINT_SPIN_LOCK(i) );
  832. }
  833. RELEASE_SPIN_LOCK( &ENDPOINT_SPIN_LOCK(0), oldIrql );
  834. }
  835. #endif
  836. //
  837. // Free cached transactions.
  838. //
  839. listEntry = ExInterlockedPopEntrySList( &Connection->CachedTransactionList,
  840. &Connection->SpinLock );
  841. while ( listEntry != NULL ) {
  842. header = CONTAINING_RECORD( listEntry, NONPAGED_HEADER, ListEntry );
  843. transaction = header->PagedBlock;
  844. DEALLOCATE_NONPAGED_POOL( header );
  845. FREE_HEAP( transaction );
  846. INCREMENT_DEBUG_STAT( SrvDbgStatistics.TransactionInfo.Frees );
  847. listEntry = ExInterlockedPopEntrySList(
  848. &Connection->CachedTransactionList,
  849. &Connection->SpinLock );
  850. }
  851. //
  852. // Free the search, session, tree, and file tables.
  853. //
  854. SrvFreeTable( &pagedConnection->SearchTable );
  855. SrvFreeTable( &Connection->FileTable );
  856. SrvFreeTable( &pagedConnection->TreeConnectTable );
  857. SrvFreeTable( &pagedConnection->SessionTable );
  858. //
  859. // Free the IPX saved response buffer, if there is one.
  860. //
  861. if ( Connection->DirectHostIpx == TRUE &&
  862. Connection->LastResponse != Connection->BuiltinSavedResponse ) {
  863. DEALLOCATE_NONPAGED_POOL( Connection->LastResponse );
  864. }
  865. //
  866. // Delete the lock on the connection.
  867. //
  868. DELETE_LOCK( &Connection->Lock );
  869. //
  870. // Delete the license server lock
  871. //
  872. DELETE_LOCK( &Connection->LicenseLock );
  873. //
  874. // Free the connection block.
  875. //
  876. DEBUG SET_BLOCK_TYPE_STATE_SIZE( Connection, BlockTypeGarbage, BlockStateDead, -1 );
  877. DEBUG Connection->BlockHeader.ReferenceCount = (ULONG)-1;
  878. TERMINATE_REFERENCE_HISTORY( Connection );
  879. FREE_HEAP( pagedConnection );
  880. DEALLOCATE_NONPAGED_POOL( Connection );
  881. IF_DEBUG(HEAP) {
  882. KdPrint(( "SrvFreeConnection: Freed connection block at %p\n",
  883. Connection ));
  884. }
  885. INCREMENT_DEBUG_STAT2( SrvDbgStatistics.ConnectionInfo.Frees );
  886. return;
  887. } // SrvFreeConnection
  888. #if DBG
  889. NTSTATUS
  890. SrvQueryConnections (
  891. OUT PVOID Buffer,
  892. IN ULONG BufferLength,
  893. OUT PULONG BytesWritten
  894. )
  895. {
  896. USHORT index;
  897. PLIST_ENTRY listEntry;
  898. PLIST_ENTRY connectionListEntry;
  899. PBLOCK_INFORMATION blockInfo = Buffer;
  900. PENDPOINT endpoint;
  901. PCONNECTION connection;
  902. KIRQL oldIrql;
  903. *BytesWritten = 0;
  904. //
  905. // We need to look at the name of every client for which the server
  906. // has a connection. Connection lists are stored off endpoints, so
  907. // walk the global endpoint list and the list of connections on each
  908. // endpoint.
  909. //
  910. ACQUIRE_LOCK( &SrvEndpointLock );
  911. listEntry = SrvEndpointList.ListHead.Flink;
  912. while ( listEntry != &SrvEndpointList.ListHead ) {
  913. endpoint = CONTAINING_RECORD(
  914. listEntry,
  915. ENDPOINT,
  916. GlobalEndpointListEntry
  917. );
  918. //
  919. // If this endpoint is closing, skip to the next one.
  920. // Otherwise, reference the endpoint so that it can't go away.
  921. //
  922. if ( GET_BLOCK_STATE(endpoint) != BlockStateActive ) {
  923. listEntry = listEntry->Flink;
  924. continue;
  925. }
  926. SrvReferenceEndpoint( endpoint );
  927. //
  928. // Put information about the endpoint into the output buffer.
  929. //
  930. if ( (PCHAR)(blockInfo + 1) <= (PCHAR)Buffer + BufferLength ) {
  931. blockInfo->Block = endpoint;
  932. blockInfo->BlockType = (ULONG)BlockTypeEndpoint;
  933. blockInfo->BlockState = (ULONG)endpoint->BlockHeader.State;
  934. blockInfo->ReferenceCount = endpoint->BlockHeader.ReferenceCount;
  935. blockInfo++;
  936. } else {
  937. SrvDereferenceEndpoint( endpoint );
  938. RELEASE_LOCK( &SrvEndpointLock );
  939. return STATUS_BUFFER_OVERFLOW;
  940. }
  941. //
  942. // Walk the connection table, writing information about each
  943. // connection to the output buffer.
  944. //
  945. index = (USHORT)-1;
  946. while ( TRUE ) {
  947. //
  948. // Get the next active connection in the table. If no more
  949. // are available, WalkConnectionTable returns NULL.
  950. // Otherwise, it returns a referenced pointer to a
  951. // connection.
  952. //
  953. connection = WalkConnectionTable( endpoint, &index );
  954. if ( connection == NULL ) {
  955. break;
  956. }
  957. if ( (PCHAR)(blockInfo + 1) <= (PCHAR)Buffer + BufferLength ) {
  958. blockInfo->Block = connection;
  959. blockInfo->BlockType = (ULONG)BlockTypeConnection;
  960. blockInfo->BlockState = (ULONG)connection->BlockHeader.State;
  961. blockInfo->ReferenceCount =
  962. connection->BlockHeader.ReferenceCount;
  963. blockInfo++;
  964. SrvDereferenceConnection( connection );
  965. } else {
  966. SrvDereferenceConnection( connection );
  967. SrvDereferenceEndpoint( endpoint );
  968. RELEASE_LOCK( &SrvEndpointLock );
  969. return STATUS_BUFFER_OVERFLOW;
  970. }
  971. } // walk connection list
  972. //
  973. // Walk the free connection list, writing information about each
  974. // connection to the output buffer.
  975. //
  976. ACQUIRE_GLOBAL_SPIN_LOCK( Fsd, &oldIrql );
  977. for ( connectionListEntry = endpoint->FreeConnectionList.Flink;
  978. connectionListEntry != &endpoint->FreeConnectionList;
  979. connectionListEntry = connectionListEntry->Flink ) {
  980. connection = CONTAINING_RECORD(
  981. connectionListEntry,
  982. CONNECTION,
  983. EndpointFreeListEntry
  984. );
  985. if ( (PCHAR)(blockInfo + 1) <= (PCHAR)Buffer + BufferLength ) {
  986. blockInfo->Block = connection;
  987. blockInfo->BlockType = (ULONG)BlockTypeConnection;
  988. blockInfo->BlockState = (ULONG)connection->BlockHeader.State;
  989. blockInfo->ReferenceCount =
  990. connection->BlockHeader.ReferenceCount;
  991. blockInfo++;
  992. } else {
  993. RELEASE_GLOBAL_SPIN_LOCK( Fsd, oldIrql );
  994. RELEASE_LOCK( &SrvEndpointLock );
  995. return STATUS_BUFFER_OVERFLOW;
  996. }
  997. } // walk free connection list
  998. RELEASE_GLOBAL_SPIN_LOCK( Fsd, oldIrql );
  999. //
  1000. // Capture a pointer to the next endpoint in the list (that one
  1001. // can't go away because we hold the endpoint list), then
  1002. // dereference the current endpoint.
  1003. //
  1004. listEntry = listEntry->Flink;
  1005. SrvDereferenceEndpoint( endpoint );
  1006. } // walk endpoint list
  1007. RELEASE_LOCK( &SrvEndpointLock );
  1008. *BytesWritten = (ULONG)((PCHAR)blockInfo - (PCHAR)Buffer);
  1009. return STATUS_SUCCESS;
  1010. } // SrvQueryConnections
  1011. #endif // if DBG