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.

9315 lines
250 KiB

  1. /*++
  2. Copyright (c) 1998-2002 Microsoft Corporation
  3. Module Name:
  4. ultdi.c
  5. Abstract:
  6. This module implements the TDI component.
  7. Author:
  8. Keith Moore (keithmo) 15-Jun-1998
  9. Revision History:
  10. --*/
  11. #include "precomp.h"
  12. //
  13. // Private globals.
  14. //
  15. //
  16. // Global lists of all active and all waiting-to-be-deleted endpoints.
  17. //
  18. LIST_ENTRY g_TdiEndpointListHead;
  19. LIST_ENTRY g_TdiDeletedEndpointListHead; // for debugging
  20. ULONG g_TdiEndpointCount; // #elements in active endpoint list
  21. //
  22. // Global lists of all connections, active, idle, or retiring
  23. //
  24. LIST_ENTRY g_TdiConnectionListHead;
  25. ULONG g_TdiConnectionCount; // #elements in connection list
  26. //
  27. // Global list of all addresses to use when creating a listening
  28. // endpoint object
  29. //
  30. ULONG g_TdiListenAddrCount = 0;
  31. PUL_TRANSPORT_ADDRESS g_pTdiListenAddresses = NULL;
  32. //
  33. // Spinlock protecting the above lists.
  34. //
  35. UL_SPIN_LOCK g_TdiSpinLock;
  36. //
  37. // Global initialization flag.
  38. //
  39. BOOLEAN g_TdiInitialized = FALSE;
  40. //
  41. // Used to wait for endpoints and connections to close on shutdown
  42. //
  43. BOOLEAN g_TdiWaitingForEndpointDrain;
  44. KEVENT g_TdiEndpointDrainEvent;
  45. KEVENT g_TdiConnectionDrainEvent;
  46. //
  47. // TDI Send routine if Fast Send is possible.
  48. //
  49. PUL_TCPSEND_DISPATCH g_TcpFastSendIPv4 = NULL;
  50. PUL_TCPSEND_DISPATCH g_TcpFastSendIPv6 = NULL;
  51. //
  52. // Connection statistics.
  53. //
  54. UL_CONNECTION_STATS g_UlConnectionStats;
  55. //
  56. // The idle list trim timer.
  57. //
  58. UL_TRIM_TIMER g_UlTrimTimer;
  59. #ifdef ALLOC_PRAGMA
  60. #pragma alloc_text( INIT, UlInitializeTdi )
  61. #pragma alloc_text( PAGE, UlCloseListeningEndpoint )
  62. #pragma alloc_text( PAGE, UlpEndpointCleanupWorker )
  63. #pragma alloc_text( PAGE, UlpDestroyConnectionWorker )
  64. #pragma alloc_text( PAGE, UlpAssociateConnection )
  65. #pragma alloc_text( PAGE, UlpDisassociateConnection )
  66. #pragma alloc_text( PAGE, UlpInitializeAddrIdleList )
  67. #pragma alloc_text( PAGE, UlpCleanupAddrIdleList )
  68. #pragma alloc_text( PAGE, UlpReplenishAddrIdleList )
  69. #pragma alloc_text( PAGE, UlpOptimizeForInterruptModeration )
  70. #pragma alloc_text( PAGE, UlpSetNagling )
  71. #pragma alloc_text( PAGE, UlpPopulateIdleList )
  72. #pragma alloc_text( PAGE, UlpIdleListTrimTimerWorker )
  73. #endif // ALLOC_PRAGMA
  74. #if 0
  75. NOT PAGEABLE -- UlWaitForEndpointDrain
  76. NOT PAGEABLE -- UlCreateListeningEndpoint
  77. NOT PAGEABLE -- UlCloseConnection
  78. NOT PAGEABLE -- UlReceiveData
  79. NOT PAGEABLE -- UlSendData
  80. NOT PAGEABLE -- UlAddSiteToEndpointList
  81. NOT PAGEABLE -- UlRemoveSiteFromEndpointList
  82. NOT PAGEABLE -- UlpReplenishAddrIdleListWorker
  83. NOT PAGEABLE -- UlpDestroyEndpoint
  84. NOT PAGEABLE -- UlpDestroyConnection
  85. NOT PAGEABLE -- UlpDequeueIdleConnectionToDrain
  86. NOT PAGEABLE -- UlpDequeueIdleConnection
  87. NOT PAGEABLE -- UlpEnqueueActiveConnection
  88. NOT PAGEABLE -- UlpConnectHandler
  89. NOT PAGEABLE -- UlpDisconnectHandler
  90. NOT PAGEABLE -- UlpDoDisconnectNotification
  91. NOT PAGEABLE -- UlpCloseRawConnection
  92. NOT PAGEABLE -- UlpQueryTcpFastSend
  93. NOT PAGEABLE -- UlpSendRawData
  94. NOT PAGEABLE -- UlpReceiveRawData
  95. NOT PAGEABLE -- UlpReceiveHandler
  96. NOT PAGEABLE -- UlpDummyReceiveHandler
  97. NOT PAGEABLE -- UlpReceiveExpeditedHandler
  98. NOT PAGEABLE -- UlpRestartAccept
  99. NOT PAGEABLE -- UlpRestartSendData
  100. NOT PAGEABLE -- UlpReferenceEndpoint
  101. NOT PAGEABLE -- UlpDereferenceEndpoint
  102. NOT PAGEABLE -- UlReferenceConnection
  103. NOT PAGEABLE -- UlDereferenceConnection
  104. NOT PAGEABLE -- UlpCleanupConnectionId
  105. NOT PAGEABLE -- UlpCleanupEarlyConnection
  106. NOT PAGEABLE -- UlpConnectionCleanupWorker
  107. NOT PAGEABLE -- UlpCreateConnection
  108. NOT PAGEABLE -- UlpInitializeConnection
  109. NOT PAGEABLE -- UlpBeginDisconnect
  110. NOT PAGEABLE -- UlpRestartDisconnect
  111. NOT PAGEABLE -- UlpBeginAbort
  112. NOT PAGEABLE -- UlpRestartAbort
  113. NOT PAGEABLE -- UlpRemoveFinalReference
  114. NOT PAGEABLE -- UlpRestartReceive
  115. NOT PAGEABLE -- UlpRestartClientReceive
  116. NOT PAGEABLE -- UlpDisconnectAllActiveConnections
  117. NOT PAGEABLE -- UlpUnbindConnectionFromEndpoint
  118. NOT PAGEABLE -- UlpSynchronousIoComplete
  119. NOT PAGEABLE -- UlpFindEndpointForPort
  120. NOT PAGEABLE -- UlpRestartQueryAddress
  121. NOT PAGEABLE -- UlpIdleListTrimTimerDpcRoutine
  122. NOT PAGEABLE -- UlpSetIdleListTrimTimer
  123. NOT PAGEABLE -- UlCheckListeningEndpointState
  124. NOT PAGEABLE -- UlpIsUrlRouteableInListenScope
  125. #endif
  126. //
  127. // Public functions.
  128. //
  129. /***************************************************************************++
  130. Routine Description:
  131. Performs global initialization of this module.
  132. Return Value:
  133. NTSTATUS - Completion status.
  134. --***************************************************************************/
  135. NTSTATUS
  136. UlInitializeTdi(
  137. VOID
  138. )
  139. {
  140. NTSTATUS status;
  141. //
  142. // Sanity check.
  143. //
  144. PAGED_CODE();
  145. ASSERT( !g_TdiInitialized );
  146. //
  147. // Initialize global data.
  148. //
  149. InitializeListHead( &g_TdiEndpointListHead );
  150. InitializeListHead( &g_TdiDeletedEndpointListHead );
  151. InitializeListHead( &g_TdiConnectionListHead );
  152. UlInitializeSpinLock( &g_TdiSpinLock, "g_TdiSpinLock" );
  153. g_TdiEndpointCount = 0;
  154. g_TdiConnectionCount = 0;
  155. RtlZeroMemory(&g_UlConnectionStats, sizeof(g_UlConnectionStats));
  156. KeInitializeEvent(
  157. &g_TdiEndpointDrainEvent,
  158. NotificationEvent,
  159. FALSE
  160. );
  161. KeInitializeEvent(
  162. &g_TdiConnectionDrainEvent,
  163. NotificationEvent,
  164. FALSE
  165. );
  166. if (g_UlIdleConnectionsHighMark == DEFAULT_IDLE_CONNECTIONS_HIGH_MARK)
  167. {
  168. //
  169. // Let's start with one connection per 2 MB and enforce a 64-512 range.
  170. //
  171. g_UlIdleConnectionsHighMark = (USHORT) g_UlTotalPhysicalMemMB / 2;
  172. g_UlIdleConnectionsHighMark = MAX(64, g_UlIdleConnectionsHighMark);
  173. g_UlIdleConnectionsHighMark = MIN(512, g_UlIdleConnectionsHighMark);
  174. }
  175. if (g_UlIdleConnectionsLowMark == DEFAULT_IDLE_CONNECTIONS_LOW_MARK)
  176. {
  177. //
  178. // To reduce the NPP usage on inactive endpoints. Pick the low mark
  179. // as small as possible, however not too small to surface a connection
  180. // drop problem. If we pick 1/4 of high, this would give us a range
  181. // of (16 .. 128).
  182. //
  183. g_UlIdleConnectionsLowMark = g_UlIdleConnectionsHighMark / 8;
  184. }
  185. UlTrace(TDI_STATS, (
  186. "UlInitializeTdi ...\n"
  187. "\tg_UlTotalPhysicalMemMB : %d\n"
  188. "\tg_UlIdleConnectionsLowMark : %d\n"
  189. "\tg_UlIdleConnectionsHighMark: %d\n",
  190. g_UlTotalPhysicalMemMB,
  191. g_UlIdleConnectionsLowMark,
  192. g_UlIdleConnectionsHighMark
  193. ));
  194. if (g_UlMaxEndpoints == DEFAULT_MAX_ENDPOINTS)
  195. {
  196. //
  197. // Compute a default based on physical memory. This starts at 16
  198. // for a 64MB machine and it is capped at 64 for a 256MB+ machine.
  199. //
  200. g_UlMaxEndpoints = (USHORT) g_UlTotalPhysicalMemMB / 4;
  201. g_UlMaxEndpoints = MIN(64, g_UlMaxEndpoints);
  202. }
  203. //
  204. // Init the idle list trim timer.
  205. //
  206. g_UlTrimTimer.Initialized = TRUE;
  207. g_UlTrimTimer.Started = FALSE;
  208. UlInitializeSpinLock(&g_UlTrimTimer.SpinLock,"IdleListTrimTimerSpinLock");
  209. KeInitializeDpc(&g_UlTrimTimer.DpcObject,
  210. &UlpIdleListTrimTimerDpcRoutine,
  211. NULL
  212. );
  213. KeInitializeTimer(&g_UlTrimTimer.Timer);
  214. UlInitializeWorkItem(&g_UlTrimTimer.WorkItem);
  215. g_UlTrimTimer.WorkItemScheduled = FALSE;
  216. InitializeListHead(&g_UlTrimTimer.ZombieConnectionListHead);
  217. //
  218. // Init list of addresses to listen on if it hasn't been done already
  219. //
  220. if ( !g_pTdiListenAddresses )
  221. {
  222. PUL_TRANSPORT_ADDRESS pTa, pTaCurrent;
  223. USHORT ip6addr_any[8] = { 0 };
  224. //
  225. // Allocate for two addresses, INADDR_ANY and in6addr_any.
  226. //
  227. // CODEWORK: check if IPv6 is enabled to see if we should add IPv6
  228. // address.
  229. pTa = UL_ALLOCATE_ARRAY(
  230. NonPagedPool,
  231. UL_TRANSPORT_ADDRESS,
  232. 2,
  233. UL_TRANSPORT_ADDRESS_POOL_TAG
  234. );
  235. if (pTa == NULL)
  236. {
  237. return STATUS_INSUFFICIENT_RESOURCES;
  238. }
  239. g_TdiListenAddrCount = 2;
  240. g_pTdiListenAddresses = pTa;
  241. RtlZeroMemory( pTa, g_TdiListenAddrCount * sizeof(UL_TRANSPORT_ADDRESS) );
  242. pTaCurrent = &pTa[0];
  243. UlInitializeIpTransportAddress( &(pTa[0].TaIp), 0L, 0 );
  244. UlInitializeIp6TransportAddress( &(pTa[1].TaIp6), ip6addr_any, 0, 0 );
  245. }
  246. // NOTE: we always want to be dual stack (IPv4/IPv6).
  247. status = UlpQueryTcpFastSend(DD_TCP_DEVICE_NAME, &g_TcpFastSendIPv4);
  248. if (NT_SUCCESS(status))
  249. {
  250. NTSTATUS status6;
  251. status6 = UlpQueryTcpFastSend(DD_TCPV6_DEVICE_NAME, &g_TcpFastSendIPv6);
  252. }
  253. if (NT_SUCCESS(status))
  254. {
  255. g_TdiInitialized = TRUE;
  256. }
  257. return status;
  258. } // UlInitializeTdi
  259. /***************************************************************************++
  260. Routine Description:
  261. Performs global termination of this module.
  262. --***************************************************************************/
  263. VOID
  264. UlTerminateTdi(
  265. VOID
  266. )
  267. {
  268. KIRQL OldIrql;
  269. //
  270. // Sanity check.
  271. //
  272. if (g_TdiInitialized)
  273. {
  274. UlTrace(TDI,
  275. ("UlTerminateTdi: connections refused:\n"
  276. "\tTotalConnections=%lu\n"
  277. "\tGlobalLimit=%lu\n"
  278. "\tEndpointDying=%lu\n"
  279. "\tNoIdleConn=%lu\n",
  280. g_UlConnectionStats.TotalConnections,
  281. g_UlConnectionStats.GlobalLimit,
  282. g_UlConnectionStats.EndpointDying,
  283. g_UlConnectionStats.NoIdleConn
  284. ));
  285. ASSERT( IsListEmpty( &g_TdiEndpointListHead )) ;
  286. ASSERT( IsListEmpty( &g_TdiDeletedEndpointListHead )) ;
  287. ASSERT( IsListEmpty( &g_TdiConnectionListHead )) ;
  288. ASSERT( g_TdiEndpointCount == 0 );
  289. ASSERT( g_TdiConnectionCount == 0 );
  290. UlAcquireSpinLock(&g_UlTrimTimer.SpinLock, &OldIrql);
  291. g_UlTrimTimer.Initialized = FALSE;
  292. KeCancelTimer(&g_UlTrimTimer.Timer);
  293. UlReleaseSpinLock(&g_UlTrimTimer.SpinLock, OldIrql);
  294. g_TdiInitialized = FALSE;
  295. }
  296. } // UlTerminateTdi
  297. /***************************************************************************++
  298. Routine Description:
  299. One minute idle timer for trimming the idle list of each endpoint.
  300. Arguments:
  301. None
  302. --***************************************************************************/
  303. VOID
  304. UlpSetIdleListTrimTimer(
  305. VOID
  306. )
  307. {
  308. LONGLONG BufferPeriodTime100Ns;
  309. LONG BufferPeriodTimeMs;
  310. LARGE_INTEGER BufferPeriodTime;
  311. //
  312. // Remaining time to next tick. Default value is in seconds.
  313. //
  314. BufferPeriodTimeMs = g_UlIdleListTrimmerPeriod * 1000;
  315. BufferPeriodTime100Ns = (LONGLONG) BufferPeriodTimeMs * 10 * 1000;
  316. //
  317. // Negative time for relative value.
  318. //
  319. BufferPeriodTime.QuadPart = -BufferPeriodTime100Ns;
  320. KeSetTimerEx(
  321. &g_UlTrimTimer.Timer,
  322. BufferPeriodTime, // Must be in nanosec
  323. BufferPeriodTimeMs, // Must be in millisec
  324. &g_UlTrimTimer.DpcObject
  325. );
  326. }
  327. /***************************************************************************++
  328. Routine Description:
  329. This function blocks until the endpoint list is empty. It also prevents
  330. new endpoints from being created.
  331. Arguments:
  332. None.
  333. --***************************************************************************/
  334. VOID
  335. UlWaitForEndpointDrain(
  336. VOID
  337. )
  338. {
  339. KIRQL oldIrql;
  340. BOOLEAN WaitConnection = FALSE;
  341. BOOLEAN WaitEndpoint = FALSE;
  342. ULONG WaitCount = 0;
  343. if (g_TdiInitialized)
  344. {
  345. UlAcquireSpinLock( &g_TdiSpinLock, &oldIrql );
  346. if (!g_TdiWaitingForEndpointDrain)
  347. {
  348. g_TdiWaitingForEndpointDrain = TRUE;
  349. }
  350. if (g_TdiEndpointCount > 0)
  351. {
  352. WaitEndpoint = TRUE;
  353. }
  354. if (g_TdiConnectionCount > 0)
  355. {
  356. WaitConnection = TRUE;
  357. }
  358. UlReleaseSpinLock( &g_TdiSpinLock, oldIrql );
  359. if (WaitConnection || WaitEndpoint)
  360. {
  361. PVOID Events[2];
  362. if (WaitEndpoint && WaitConnection)
  363. {
  364. Events[0] = &g_TdiEndpointDrainEvent;
  365. Events[1] = &g_TdiConnectionDrainEvent;
  366. WaitCount = 2;
  367. }
  368. else
  369. {
  370. if (WaitEndpoint)
  371. {
  372. Events[0] = &g_TdiEndpointDrainEvent;
  373. }
  374. else
  375. {
  376. Events[0] = &g_TdiConnectionDrainEvent;
  377. }
  378. Events[1] = NULL;
  379. WaitCount = 1;
  380. }
  381. KeWaitForMultipleObjects(
  382. WaitCount,
  383. Events,
  384. WaitAll,
  385. UserRequest,
  386. KernelMode,
  387. FALSE,
  388. NULL,
  389. NULL
  390. );
  391. }
  392. }
  393. } // UlWaitForEndpointDrain
  394. /***************************************************************************++
  395. Routine Description:
  396. Creates a new listening endpoint bound to the specified port on
  397. all available TDI addresses (see: g_TdiListenAddresses and
  398. g_TdiListenAddressCount).
  399. Arguments:
  400. Port - TCP Port for this endpoint.
  401. InitialBacklog - Supplies the initial number of idle connections
  402. to add to the endpoint.
  403. pConnectionRequestHandler - Supplies a pointer to an indication
  404. handler to invoke when incoming connections arrive.
  405. pConnectionCompleteHandler - Supplies a pointer to an indication
  406. handler to invoke when either a) the incoming connection is
  407. fully accepted, or b) the incoming connection could not be
  408. accepted due to a fatal error.
  409. pConnectionDisconnectHandler - Supplies a pointer to an indication
  410. handler to invoke when connections are disconnected by the
  411. remote (client) side.
  412. pConnectionDestroyedHandler - Supplies a pointer to an indication
  413. handle to invoke after a connection has been fully destroyed.
  414. This is typically the TDI client's opportunity to cleanup
  415. any allocated resources.
  416. pDataReceiveHandler - Supplies a pointer to an indication handler to
  417. invoke when incoming data arrives.
  418. pListeningContext - Supplies an uninterpreted context value to
  419. associate with the new listening endpoint.
  420. ppListeningEndpoint - Receives a pointer to the new listening
  421. endpoint if successful.
  422. Return Value:
  423. NTSTATUS - Completion status.
  424. --***************************************************************************/
  425. NTSTATUS
  426. UlCreateListeningEndpoint(
  427. IN PHTTP_PARSED_URL pParsedUrl,
  428. IN PUL_CONNECTION_REQUEST pConnectionRequestHandler,
  429. IN PUL_CONNECTION_COMPLETE pConnectionCompleteHandler,
  430. IN PUL_CONNECTION_DISCONNECT pConnectionDisconnectHandler,
  431. IN PUL_CONNECTION_DISCONNECT_COMPLETE pConnectionDisconnectCompleteHandler,
  432. IN PUL_CONNECTION_DESTROYED pConnectionDestroyedHandler,
  433. IN PUL_DATA_RECEIVE pDataReceiveHandler,
  434. OUT PUL_ENDPOINT *ppListeningEndpoint
  435. )
  436. {
  437. NTSTATUS status;
  438. PUL_ENDPOINT pEndpoint;
  439. ULONG i;
  440. ULONG AddrIdleListSize;
  441. ULONG FailedAddrIdleList;
  442. KIRQL OldIrql;
  443. WCHAR IpAddressString[MAX_IP_ADDR_AND_PORT_STRING_LEN + 1];
  444. USHORT BytesWritten;
  445. USHORT Port;
  446. //
  447. // Sanity check.
  448. //
  449. ASSERT( pParsedUrl );
  450. Port = SWAP_SHORT(pParsedUrl->PortNumber);
  451. ASSERT( Port > 0 );
  452. //
  453. // Setup locals so we know how to cleanup on a fatal exit.
  454. //
  455. pEndpoint = NULL;
  456. if (!g_pTdiListenAddresses || (0 == g_TdiListenAddrCount))
  457. {
  458. // Fail. We have failed to initialize properly.
  459. // REVIEW: is there a better return code in this case?
  460. status = STATUS_INSUFFICIENT_RESOURCES;
  461. goto fatal;
  462. }
  463. //
  464. // Allocate enough pool for the endpoint structure and the
  465. // array of UL_ADDR_IDLE_LISTs.
  466. //
  467. AddrIdleListSize = g_TdiListenAddrCount * sizeof(UL_ADDR_IDLE_LIST);
  468. pEndpoint = UL_ALLOCATE_STRUCT_WITH_SPACE(
  469. NonPagedPool,
  470. UL_ENDPOINT,
  471. AddrIdleListSize,
  472. UL_ENDPOINT_POOL_TAG
  473. );
  474. if (pEndpoint == NULL)
  475. {
  476. status = STATUS_INSUFFICIENT_RESOURCES;
  477. goto fatal;
  478. }
  479. //
  480. // Initialize the easy parts.
  481. //
  482. pEndpoint->Signature = UL_ENDPOINT_SIGNATURE;
  483. pEndpoint->ReferenceCount = 0;
  484. pEndpoint->UsageCount = 1;
  485. WRITE_REF_TRACE_LOG(
  486. g_pEndpointUsageTraceLog,
  487. REF_ACTION_REFERENCE_ENDPOINT_USAGE,
  488. pEndpoint->UsageCount,
  489. pEndpoint,
  490. __FILE__,
  491. __LINE__
  492. );
  493. UlInitializeWorkItem(&pEndpoint->WorkItem);
  494. pEndpoint->WorkItemScheduled = FALSE;
  495. REFERENCE_ENDPOINT(pEndpoint, REF_ACTION_INIT);
  496. REFERENCE_ENDPOINT(pEndpoint, REF_ACTION_ENDPOINT_USAGE_REFERENCE);
  497. REFERENCE_ENDPOINT(pEndpoint, REF_ACTION_ENDPOINT_EVENT_REFERENCE);
  498. pEndpoint->pConnectionRequestHandler = pConnectionRequestHandler;
  499. pEndpoint->pConnectionCompleteHandler = pConnectionCompleteHandler;
  500. pEndpoint->pConnectionDisconnectHandler = pConnectionDisconnectHandler;
  501. pEndpoint->pConnectionDisconnectCompleteHandler = pConnectionDisconnectCompleteHandler;
  502. pEndpoint->pConnectionDestroyedHandler = pConnectionDestroyedHandler;
  503. pEndpoint->pDataReceiveHandler = pDataReceiveHandler;
  504. pEndpoint->pListeningContext = (PVOID)pEndpoint;
  505. pEndpoint->LocalPort = Port;
  506. pEndpoint->Secure = pParsedUrl->Secure;
  507. pEndpoint->Counted = FALSE;
  508. pEndpoint->Deleted = FALSE;
  509. pEndpoint->GlobalEndpointListEntry.Flink = NULL;
  510. RtlZeroMemory(
  511. &pEndpoint->CleanupIrpContext,
  512. sizeof(UL_IRP_CONTEXT)
  513. );
  514. pEndpoint->CleanupIrpContext.Signature = UL_IRP_CONTEXT_SIGNATURE;
  515. //
  516. // build array of Listening Address Objects
  517. //
  518. ASSERT( g_TdiListenAddrCount > 0 );
  519. pEndpoint->AddrIdleListCount = g_TdiListenAddrCount;
  520. // Address Idle Lists immediately follow the UL_ENDPOINT object
  521. pEndpoint->aAddrIdleLists = (PUL_ADDR_IDLE_LIST)(&pEndpoint[1]);
  522. RtlZeroMemory(
  523. pEndpoint->aAddrIdleLists,
  524. AddrIdleListSize
  525. );
  526. FailedAddrIdleList = 0;
  527. for ( i = 0; i < pEndpoint->AddrIdleListCount; i++ )
  528. {
  529. status = UlpInitializeAddrIdleList(
  530. pEndpoint,
  531. Port,
  532. &g_pTdiListenAddresses[i],
  533. &pEndpoint->aAddrIdleLists[i]
  534. );
  535. if (!NT_SUCCESS(status))
  536. {
  537. //
  538. // NOTE: STATUS_OBJECT_NOT_FOUND is returned if the underlying
  539. // transport is not present on the system (e.g. IPv6).
  540. //
  541. if(status != STATUS_OBJECT_NAME_NOT_FOUND)
  542. {
  543. PUL_TRANSPORT_ADDRESS pTa;
  544. pTa = &pEndpoint->aAddrIdleLists[i].LocalAddress;
  545. BytesWritten =
  546. HostAddressAndPortToStringW(
  547. IpAddressString,
  548. pTa->Ta.Address->Address,
  549. pTa->Ta.Address->AddressType
  550. );
  551. ASSERT(BytesWritten <=
  552. (MAX_IP_ADDR_AND_PORT_STRING_LEN * sizeof(WCHAR)));
  553. UlEventLogOneStringEntry(
  554. EVENT_HTTP_CREATE_ENDPOINT_FAILED,
  555. IpAddressString,
  556. TRUE,
  557. status
  558. );
  559. goto fatal;
  560. }
  561. FailedAddrIdleList++;
  562. continue; // ignore; makes cleanup easier.
  563. }
  564. //
  565. // Replenish the idle connection pool.
  566. //
  567. status = UlpReplenishAddrIdleList(
  568. &pEndpoint->aAddrIdleLists[i],
  569. TRUE
  570. );
  571. if (!NT_SUCCESS(status))
  572. {
  573. goto fatal;
  574. }
  575. }
  576. //
  577. // see if we got at least one valid AO
  578. //
  579. if ( FailedAddrIdleList == pEndpoint->AddrIdleListCount )
  580. {
  581. // No valid AO's created; fail the endpoint creation!
  582. status = STATUS_INVALID_ADDRESS;
  583. goto fatal;
  584. }
  585. //
  586. // Put the endpoint onto the global list.
  587. //
  588. UlAcquireSpinLock( &g_TdiSpinLock, &OldIrql );
  589. //
  590. // Check if we have exceeded the g_UlMaxEndpoints limit.
  591. //
  592. if (g_TdiEndpointCount >= g_UlMaxEndpoints)
  593. {
  594. status = STATUS_ALLOTTED_SPACE_EXCEEDED;
  595. UlReleaseSpinLock( &g_TdiSpinLock, OldIrql );
  596. goto fatal;
  597. }
  598. InsertTailList(
  599. &g_TdiEndpointListHead,
  600. &pEndpoint->GlobalEndpointListEntry
  601. );
  602. g_TdiEndpointCount++;
  603. pEndpoint->Counted = TRUE;
  604. UlReleaseSpinLock( &g_TdiSpinLock, OldIrql );
  605. //
  606. // Now we have at least one endpoint, kick the idle timer to action.
  607. //
  608. UlAcquireSpinLock(&g_UlTrimTimer.SpinLock, &OldIrql);
  609. if (g_UlTrimTimer.Started == FALSE)
  610. {
  611. UlpSetIdleListTrimTimer();
  612. g_UlTrimTimer.Started = TRUE;
  613. }
  614. UlReleaseSpinLock(&g_UlTrimTimer.SpinLock, OldIrql);
  615. //
  616. // Success!
  617. //
  618. UlTrace(TDI, (
  619. "UlCreateListeningEndpoint: endpoint %p, port %d\n",
  620. pEndpoint,
  621. SWAP_SHORT(Port)
  622. ));
  623. *ppListeningEndpoint = pEndpoint;
  624. return STATUS_SUCCESS;
  625. fatal:
  626. ASSERT( !NT_SUCCESS(status) );
  627. if (pEndpoint != NULL)
  628. {
  629. PUL_ADDR_IDLE_LIST pAddrIdleList = pEndpoint->aAddrIdleLists;
  630. //
  631. // Remove connect event handler so we won't get any more
  632. // indications that could add a reference.
  633. //
  634. // These calls could fail, but there's basically nothing
  635. // we can do about it if they do.
  636. //
  637. for ( i = 0; i < pEndpoint->AddrIdleListCount; i++ )
  638. {
  639. if (pAddrIdleList->AddressObject.pDeviceObject)
  640. {
  641. //
  642. // Close the TDI object.
  643. //
  644. UxCloseTdiObject( &pAddrIdleList->AddressObject );
  645. }
  646. pAddrIdleList++;
  647. }
  648. //
  649. // Release the three references on the endpoint, which
  650. // will cause it to destroy itself.
  651. //
  652. ASSERT( 3 == pEndpoint->ReferenceCount );
  653. pEndpoint->UsageCount = 0; // to prevent assertions
  654. WRITE_REF_TRACE_LOG(
  655. g_pEndpointUsageTraceLog,
  656. REF_ACTION_DEREFERENCE_ENDPOINT_USAGE,
  657. pEndpoint->UsageCount,
  658. pEndpoint,
  659. __FILE__,
  660. __LINE__
  661. );
  662. DEREFERENCE_ENDPOINT_SELF(
  663. pEndpoint,
  664. REF_ACTION_ENDPOINT_EVENT_DEREFERENCE
  665. );
  666. DEREFERENCE_ENDPOINT_SELF(
  667. pEndpoint, REF_ACTION_ENDPOINT_USAGE_DEREFERENCE
  668. );
  669. DEREFERENCE_ENDPOINT_SELF(
  670. pEndpoint, REF_ACTION_FINAL_DEREF
  671. );
  672. }
  673. return status;
  674. } // UlCreateListeningEndpoint
  675. /***************************************************************************++
  676. Routine Description:
  677. Closes an existing listening endpoint.
  678. Arguments:
  679. pListeningEndpoint - Supplies a pointer to a listening endpoint
  680. previously created with UlCreateListeningEndpoint().
  681. pCompletionRoutine - Supplies a pointer to a completion routine to
  682. invoke after the listening endpoint is fully closed.
  683. pCompletionContext - Supplies an uninterpreted context value for the
  684. completion routine.
  685. Return Value:
  686. NTSTATUS - Completion status.
  687. --***************************************************************************/
  688. NTSTATUS
  689. UlCloseListeningEndpoint(
  690. IN PUL_ENDPOINT pListeningEndpoint,
  691. IN PUL_COMPLETION_ROUTINE pCompletionRoutine,
  692. IN PVOID pCompletionContext
  693. )
  694. {
  695. PUL_IRP_CONTEXT pIrpContext;
  696. NTSTATUS status;
  697. PUL_ADDR_IDLE_LIST pAddrIdleList;
  698. PUL_CONNECTION pConnection;
  699. ULONG i;
  700. //
  701. // Sanity check.
  702. //
  703. PAGED_CODE();
  704. ASSERT( IS_VALID_ENDPOINT( pListeningEndpoint ) );
  705. ASSERT( pCompletionRoutine != NULL );
  706. UlTrace(TDI, (
  707. "UlCloseListeningEndpoint: endpoint %p, completion %p, ctx %p\n",
  708. pListeningEndpoint,
  709. pCompletionRoutine,
  710. pCompletionContext
  711. ));
  712. //
  713. // Remember completion information to be used when
  714. // we're done cleaning up.
  715. //
  716. pIrpContext = &pListeningEndpoint->CleanupIrpContext;
  717. pIrpContext->pCompletionRoutine = pCompletionRoutine;
  718. pIrpContext->pCompletionContext = pCompletionContext;
  719. pIrpContext->pOwnIrp = NULL;
  720. pIrpContext->OwnIrpContext = TRUE;
  721. //
  722. // Remove connect event handler so we won't get any more
  723. // indications that could add a reference.
  724. //
  725. // These calls could fail, but there's basically nothing
  726. // we can do about it if they do.
  727. //
  728. // Once we're done we remove the reference we held
  729. // on the endpoint for the handlers.
  730. //
  731. pAddrIdleList = pListeningEndpoint->aAddrIdleLists;
  732. for ( i = 0; i < pListeningEndpoint->AddrIdleListCount; i++ )
  733. {
  734. if ( pAddrIdleList->AddressObject.pDeviceObject )
  735. {
  736. //
  737. // Close the TDI Address Object to flush all outstanding
  738. // completions.
  739. //
  740. UxCloseTdiObject( &pAddrIdleList->AddressObject );
  741. //
  742. // Destroy as many idle connections as possible.
  743. //
  744. while ( NULL != ( pConnection = UlpDequeueIdleConnectionToDrain(
  745. pAddrIdleList
  746. ) ) )
  747. {
  748. ASSERT( IS_VALID_CONNECTION( pConnection ) );
  749. UlpDestroyConnection( pConnection );
  750. }
  751. }
  752. pAddrIdleList++;
  753. }
  754. DEREFERENCE_ENDPOINT_SELF(
  755. pListeningEndpoint,
  756. REF_ACTION_ENDPOINT_EVENT_DEREFERENCE
  757. );
  758. //
  759. // Let UlpDisconnectAllActiveConnections do the dirty work.
  760. //
  761. status = UlpDisconnectAllActiveConnections( pListeningEndpoint );
  762. return status;
  763. } // UlCloseListeningEndpoint
  764. /***************************************************************************++
  765. Routine Description:
  766. Closes a previously accepted connection.
  767. Arguments:
  768. pConnection - Supplies a pointer to a connection as previously
  769. indicated to the PUL_CONNECTION_REQUEST handler.
  770. AbortiveDisconnect - Supplies TRUE if the connection is to be abortively
  771. disconnected, FALSE if it should be gracefully disconnected.
  772. pCompletionRoutine - Supplies a pointer to a completion routine to
  773. invoke after the connection is fully closed.
  774. pCompletionContext - Supplies an uninterpreted context value for the
  775. completion routine.
  776. Return Value:
  777. NTSTATUS - Completion status.
  778. --***************************************************************************/
  779. NTSTATUS
  780. UlCloseConnection(
  781. IN PUL_CONNECTION pConnection,
  782. IN BOOLEAN AbortiveDisconnect,
  783. IN PUL_COMPLETION_ROUTINE pCompletionRoutine,
  784. IN PVOID pCompletionContext
  785. )
  786. {
  787. NTSTATUS status;
  788. //
  789. // Sanity check.
  790. //
  791. ASSERT( IS_VALID_CONNECTION( pConnection ) );
  792. UlTrace(TDI, (
  793. "UlCloseConnection: connection %p, abort %lu\n",
  794. pConnection,
  795. (ULONG)AbortiveDisconnect
  796. ));
  797. WRITE_REF_TRACE_LOG2(
  798. g_pTdiTraceLog,
  799. pConnection->pTraceLog,
  800. (USHORT) (AbortiveDisconnect
  801. ? REF_ACTION_CLOSE_UL_CONN_ABORTIVE
  802. : REF_ACTION_CLOSE_UL_CONN_GRACEFUL),
  803. pConnection->ReferenceCount,
  804. pConnection,
  805. __FILE__,
  806. __LINE__
  807. );
  808. //
  809. // We only send graceful disconnects through the filter
  810. // process. There's also no point in going through the
  811. // filter if the connection is already being closed or
  812. // aborted.
  813. //
  814. if (pConnection->FilterInfo.pFilterChannel &&
  815. !pConnection->ConnectionFlags.CleanupBegun &&
  816. !pConnection->ConnectionFlags.AbortIndicated &&
  817. !AbortiveDisconnect)
  818. {
  819. //
  820. // Send graceful disconnect through the filter process.
  821. //
  822. status = UlFilterCloseHandler(
  823. &pConnection->FilterInfo,
  824. pCompletionRoutine,
  825. pCompletionContext
  826. );
  827. }
  828. else
  829. {
  830. //
  831. // Really close the connection.
  832. //
  833. status = UlpCloseRawConnection(
  834. pConnection,
  835. AbortiveDisconnect,
  836. pCompletionRoutine,
  837. pCompletionContext
  838. );
  839. }
  840. return status;
  841. } // UlCloseConnection
  842. /***************************************************************************++
  843. Routine Description:
  844. Sends a block of data on the specified connection. If the connection
  845. is filtered, the data will be sent to the filter first.
  846. Arguments:
  847. pConnection - Supplies a pointer to a connection as previously
  848. indicated to the PUL_CONNECTION_REQUEST handler.
  849. pMdlChain - Supplies a pointer to a MDL chain describing the
  850. data buffers to send.
  851. Length - Supplies the length of the data referenced by the MDL
  852. chain.
  853. pCompletionRoutine - Supplies a pointer to a completion routine to
  854. invoke after the data is sent.
  855. pCompletionContext - Supplies an uninterpreted context value for the
  856. completion routine.
  857. InitiateDisconnect - Supplies TRUE if a graceful disconnect should
  858. be initiated immediately after initiating the send (i.e. before
  859. the send actually completes).
  860. Return Value:
  861. NTSTATUS - Completion status.
  862. --***************************************************************************/
  863. NTSTATUS
  864. UlSendData(
  865. IN PUL_CONNECTION pConnection,
  866. IN PMDL pMdlChain,
  867. IN ULONG Length,
  868. IN PUL_COMPLETION_ROUTINE pCompletionRoutine,
  869. IN PVOID pCompletionContext,
  870. IN PIRP pOwnIrp,
  871. IN PUL_IRP_CONTEXT pOwnIrpContext,
  872. IN BOOLEAN InitiateDisconnect,
  873. IN BOOLEAN RequestComplete
  874. )
  875. {
  876. NTSTATUS Status;
  877. PUL_IRP_CONTEXT pIrpContext;
  878. //
  879. // Sanity check.
  880. //
  881. ASSERT( IS_VALID_CONNECTION( pConnection ) );
  882. ASSERT( pMdlChain != NULL );
  883. ASSERT( Length > 0 );
  884. ASSERT( pCompletionRoutine != NULL );
  885. UlTrace(TDI, (
  886. "UlSendData: connection %p, mdl %p, length %lu\n",
  887. pConnection,
  888. pMdlChain,
  889. Length
  890. ));
  891. //
  892. // Connection should be around until we make a call to close connection.
  893. // Otherwise if the send completes inline, it may free
  894. // up the connection reference when we enter this function, causing
  895. // us to reference a stale connection pointer when calling disconnect.
  896. //
  897. REFERENCE_CONNECTION( pConnection );
  898. //
  899. // Allocate & initialize a context structure if necessary.
  900. //
  901. if (pOwnIrpContext == NULL)
  902. {
  903. pIrpContext = UlPplAllocateIrpContext();
  904. }
  905. else
  906. {
  907. ASSERT( pOwnIrp != NULL );
  908. pIrpContext = pOwnIrpContext;
  909. }
  910. if (pIrpContext == NULL)
  911. {
  912. Status = STATUS_INSUFFICIENT_RESOURCES;
  913. goto fatal;
  914. }
  915. ASSERT( IS_VALID_IRP_CONTEXT( pIrpContext ) );
  916. pIrpContext->pConnectionContext = (PVOID) pConnection;
  917. pIrpContext->pCompletionRoutine = pCompletionRoutine;
  918. pIrpContext->pCompletionContext = pCompletionContext;
  919. pIrpContext->pOwnIrp = pOwnIrp;
  920. pIrpContext->OwnIrpContext = (BOOLEAN) (pOwnIrpContext != NULL);
  921. //
  922. // Try to send the data. This send operation may complete inline
  923. // fast, if the connection has already been aborted by the client
  924. // In that case connection may gone away. To prevent this we
  925. // keep additional refcount until we make a call to close connection
  926. // below.
  927. //
  928. if (pConnection->FilterInfo.pFilterChannel)
  929. {
  930. //
  931. // First go through the filter.
  932. //
  933. Status = UlFilterSendHandler(
  934. &pConnection->FilterInfo,
  935. pMdlChain,
  936. Length,
  937. pIrpContext
  938. );
  939. UlTrace(TDI, (
  940. "UlSendData: sent filtered data, status = 0x%x\n",
  941. Status
  942. ));
  943. ASSERT( Status == STATUS_PENDING );
  944. }
  945. else
  946. {
  947. if (RequestComplete &&
  948. pConnection->AddressType == TDI_ADDRESS_TYPE_IP)
  949. {
  950. //
  951. // Just send it directly to the network.
  952. //
  953. Status = UlpSendRawData(
  954. pConnection,
  955. pMdlChain,
  956. Length,
  957. pIrpContext,
  958. InitiateDisconnect
  959. );
  960. UlTrace(TDI, (
  961. "UlSendData: sent raw data with disconnect, status = 0x%x\n",
  962. Status
  963. ));
  964. InitiateDisconnect = FALSE;
  965. }
  966. else
  967. {
  968. //
  969. // Just send it directly to the network.
  970. //
  971. Status = UlpSendRawData(
  972. pConnection,
  973. pMdlChain,
  974. Length,
  975. pIrpContext,
  976. FALSE
  977. );
  978. UlTrace(TDI, (
  979. "UlSendData: sent raw data, status = 0x%x\n",
  980. Status
  981. ));
  982. }
  983. }
  984. if (!NT_SUCCESS(Status))
  985. {
  986. goto fatal;
  987. }
  988. //
  989. // Now that the send is "in flight", initiate a disconnect if
  990. // so requested.
  991. //
  992. if (InitiateDisconnect)
  993. {
  994. WRITE_REF_TRACE_LOG2(
  995. g_pTdiTraceLog,
  996. pConnection->pTraceLog,
  997. REF_ACTION_CLOSE_UL_CONN_GRACEFUL,
  998. pConnection->ReferenceCount,
  999. pConnection,
  1000. __FILE__,
  1001. __LINE__
  1002. );
  1003. (VOID) UlCloseConnection(
  1004. pConnection,
  1005. FALSE, // AbortiveDisconnect
  1006. NULL, // pCompletionRoutine
  1007. NULL // pCompletionContext
  1008. );
  1009. UlTrace(TDI, (
  1010. "UlSendData: closed conn\n"
  1011. ));
  1012. }
  1013. DEREFERENCE_CONNECTION( pConnection );
  1014. return STATUS_PENDING;
  1015. fatal:
  1016. ASSERT( !NT_SUCCESS(Status) );
  1017. if (pIrpContext != NULL && pIrpContext != pOwnIrpContext)
  1018. {
  1019. UlPplFreeIrpContext( pIrpContext );
  1020. }
  1021. (VOID) UlpCloseRawConnection(
  1022. pConnection,
  1023. TRUE, // AbortiveDisconnect
  1024. NULL, // pCompletionRoutine
  1025. NULL // pCompletionContext
  1026. );
  1027. UlTrace(TDI, (
  1028. "UlSendData: error occurred; closed raw conn\n"
  1029. ));
  1030. Status = UlInvokeCompletionRoutine(
  1031. Status,
  1032. 0,
  1033. pCompletionRoutine,
  1034. pCompletionContext
  1035. );
  1036. UlTrace(TDI, (
  1037. "UlSendData: finished completion routine: status = 0x%x\n",
  1038. Status
  1039. ));
  1040. DEREFERENCE_CONNECTION( pConnection );
  1041. return Status;
  1042. } // UlSendData
  1043. /***************************************************************************++
  1044. Routine Description:
  1045. Receives data from the specified connection. This function is
  1046. typically used after a receive indication handler has failed to
  1047. consume all of the indicated data.
  1048. If the connection is filtered the data will be read from the
  1049. filter channel.
  1050. Arguments:
  1051. pConnection - Supplies a pointer to a connection as previously
  1052. indicated to the PUL_CONNECTION_REQUEST handler.
  1053. pBuffer - Supplies a pointer to the target buffer for the received
  1054. data.
  1055. BufferLength - Supplies the length of pBuffer.
  1056. pCompletionRoutine - Supplies a pointer to a completion routine to
  1057. invoke after the listening endpoint is fully closed.
  1058. pCompletionContext - Supplies an uninterpreted context value for the
  1059. completion routine.
  1060. Return Value:
  1061. NTSTATUS - Completion status.
  1062. --***************************************************************************/
  1063. NTSTATUS
  1064. UlReceiveData(
  1065. IN PVOID pConnectionContext,
  1066. IN PVOID pBuffer,
  1067. IN ULONG BufferLength,
  1068. IN PUL_COMPLETION_ROUTINE pCompletionRoutine,
  1069. IN PVOID pCompletionContext
  1070. )
  1071. {
  1072. NTSTATUS status;
  1073. PUL_CONNECTION pConnection = (PUL_CONNECTION)pConnectionContext;
  1074. //
  1075. // Sanity check.
  1076. //
  1077. ASSERT(IS_VALID_CONNECTION(pConnection));
  1078. if (pConnection->FilterInfo.pFilterChannel)
  1079. {
  1080. //
  1081. // This is a filtered connection, get the data from the filter.
  1082. //
  1083. status = UlFilterReadHandler(
  1084. &pConnection->FilterInfo,
  1085. (PBYTE)pBuffer,
  1086. BufferLength,
  1087. pCompletionRoutine,
  1088. pCompletionContext
  1089. );
  1090. }
  1091. else
  1092. {
  1093. //
  1094. // This is not a filtered connection. Get the data from TDI.
  1095. //
  1096. status = UlpReceiveRawData(
  1097. pConnectionContext,
  1098. pBuffer,
  1099. BufferLength,
  1100. pCompletionRoutine,
  1101. pCompletionContext
  1102. );
  1103. }
  1104. return status;
  1105. } // UlReceiveData
  1106. /***************************************************************************++
  1107. Routine Description:
  1108. Either create a new endpoint for the specified URL or, if one
  1109. already exists, reference it.
  1110. We do not allow mixing protocols on the same endpoint (e.g. HTTP
  1111. and HTTPS).
  1112. Arguments:
  1113. pParsedUrl - fully decomposed and parsed URL.
  1114. Return Value:
  1115. NTSTATUS - Completion status.
  1116. --***************************************************************************/
  1117. NTSTATUS
  1118. UlAddSiteToEndpointList(
  1119. PHTTP_PARSED_URL pParsedUrl
  1120. )
  1121. {
  1122. NTSTATUS status;
  1123. PUL_ENDPOINT pEndpoint;
  1124. KIRQL oldIrql;
  1125. USHORT Port;
  1126. BOOLEAN Secure;
  1127. //
  1128. // Even though this routine cannot be pageable
  1129. // (due to the spinlock aquisition), it must be called at
  1130. // low IRQL.
  1131. //
  1132. ASSERT( pParsedUrl );
  1133. ASSERT( KeGetCurrentIrql() == PASSIVE_LEVEL );
  1134. //
  1135. // convert port to network byte order
  1136. //
  1137. Port = SWAP_SHORT(pParsedUrl->PortNumber);
  1138. Secure = pParsedUrl->Secure;
  1139. UlTrace(SITE, (
  1140. "UlAddSiteToEndpointList:"
  1141. " Scheme = '%s' Port = %d SiteType = %d FullUrl = %S\n",
  1142. Secure ? "https" : "http",
  1143. SWAP_SHORT(Port),
  1144. pParsedUrl->SiteType,
  1145. pParsedUrl->pFullUrl
  1146. ));
  1147. UlAcquireSpinLock( &g_TdiSpinLock, &oldIrql );
  1148. //
  1149. // make sure we're not shutting down
  1150. //
  1151. if (g_TdiWaitingForEndpointDrain)
  1152. {
  1153. UlReleaseSpinLock( &g_TdiSpinLock, oldIrql );
  1154. status = STATUS_INVALID_DEVICE_STATE;
  1155. goto cleanup;
  1156. }
  1157. //
  1158. // Check whether this url is routable according to our
  1159. // listen scope - global listen address list - or not.
  1160. // If not fail the request. We do not need the create
  1161. // an endpoint and walk its idle list, endpoint's
  1162. // list is always the duplicate of the global one.
  1163. //
  1164. if (!UlpIsUrlRouteableInListenScope(pParsedUrl))
  1165. {
  1166. //
  1167. // ParsedUrl is allocated from stack, individual
  1168. // string pointers are allocated from paged pool
  1169. // do not touch them.
  1170. //
  1171. UlReleaseSpinLock( &g_TdiSpinLock, oldIrql );
  1172. status = STATUS_HOST_UNREACHABLE;
  1173. goto cleanup;
  1174. }
  1175. //
  1176. // Find an existing endpoint for this address.
  1177. //
  1178. pEndpoint = UlpFindEndpointForPort( Port );
  1179. //
  1180. // Did we find one?
  1181. //
  1182. if (pEndpoint == NULL)
  1183. {
  1184. //
  1185. // Didn't find it. Try to create one. Since we must release
  1186. // the TDI spinlock before we can create a new listening endpoint,
  1187. // there is the opportunity for a race condition with other
  1188. // threads creating endpoints.
  1189. //
  1190. UlReleaseSpinLock( &g_TdiSpinLock, oldIrql );
  1191. UlTrace(SITE, (
  1192. "UlAddSiteToEndpointList: no endpoint for scheme '%s'"
  1193. " (port %d), creating\n",
  1194. Secure ? "https" : "http",
  1195. SWAP_SHORT(Port)
  1196. ));
  1197. status = UlCreateListeningEndpoint(
  1198. pParsedUrl, // Port & Scheme (& opt Address)
  1199. &UlConnectionRequest, // callback functions
  1200. &UlConnectionComplete,
  1201. &UlConnectionDisconnect,
  1202. &UlConnectionDisconnectComplete,
  1203. &UlConnectionDestroyed,
  1204. &UlHttpReceive,
  1205. &pEndpoint
  1206. );
  1207. if (!NT_SUCCESS(status))
  1208. {
  1209. //
  1210. // Maybe another thread has already created it?
  1211. //
  1212. UlAcquireSpinLock( &g_TdiSpinLock, &oldIrql );
  1213. //
  1214. // make sure we're not shutting down
  1215. //
  1216. if (g_TdiWaitingForEndpointDrain)
  1217. {
  1218. UlReleaseSpinLock( &g_TdiSpinLock, oldIrql );
  1219. status = STATUS_INVALID_DEVICE_STATE;
  1220. goto cleanup;
  1221. }
  1222. //
  1223. // Find an existing endpoint for this address.
  1224. //
  1225. pEndpoint = UlpFindEndpointForPort( Port );
  1226. if (pEndpoint != NULL)
  1227. {
  1228. //
  1229. // Check if the endpoint's protocol matches the protocol of the new url
  1230. //
  1231. if (Secure != pEndpoint->Secure)
  1232. {
  1233. status = STATUS_OBJECT_NAME_COLLISION;
  1234. }
  1235. else
  1236. {
  1237. //
  1238. // Adjust the usage count.
  1239. //
  1240. pEndpoint->UsageCount++;
  1241. ASSERT( pEndpoint->UsageCount > 0 );
  1242. WRITE_REF_TRACE_LOG(
  1243. g_pEndpointUsageTraceLog,
  1244. REF_ACTION_REFERENCE_ENDPOINT_USAGE,
  1245. pEndpoint->UsageCount,
  1246. pEndpoint,
  1247. __FILE__,
  1248. __LINE__
  1249. );
  1250. status = STATUS_SUCCESS;
  1251. }
  1252. }
  1253. //
  1254. // The endpoint doesn't exist. This is a "real" failure.
  1255. //
  1256. UlReleaseSpinLock( &g_TdiSpinLock, oldIrql );
  1257. }
  1258. }
  1259. else
  1260. {
  1261. //
  1262. // Check if the endpoint's protocol matches the protocol of the new url
  1263. //
  1264. if (Secure != pEndpoint->Secure)
  1265. {
  1266. status = STATUS_OBJECT_NAME_COLLISION;
  1267. }
  1268. else
  1269. {
  1270. //
  1271. // Adjust the usage count.
  1272. //
  1273. pEndpoint->UsageCount++;
  1274. ASSERT( pEndpoint->UsageCount > 0 );
  1275. WRITE_REF_TRACE_LOG(
  1276. g_pEndpointUsageTraceLog,
  1277. REF_ACTION_REFERENCE_ENDPOINT_USAGE,
  1278. pEndpoint->UsageCount,
  1279. pEndpoint,
  1280. __FILE__,
  1281. __LINE__
  1282. );
  1283. status = STATUS_SUCCESS;
  1284. }
  1285. UlReleaseSpinLock( &g_TdiSpinLock, oldIrql );
  1286. }
  1287. UlTrace(SITE, (
  1288. "UlAddSiteToEndpointList: using endpoint %p for scheme '%s' port %d\n",
  1289. pEndpoint,
  1290. SWAP_SHORT(Port)
  1291. ));
  1292. cleanup:
  1293. RETURN(status);
  1294. } // UlAddSiteToEndpointList
  1295. /***************************************************************************++
  1296. Routine Description:
  1297. Dereference the endpoint corresponding to the specified address.
  1298. Arguments:
  1299. pSiteUrl - Supplies the URL specifying the site to remove.
  1300. UseIp6Wildcard - Indicates wildcard sites should be mapped to IPv6.
  1301. Return Value:
  1302. NTSTATUS - Completion status.
  1303. --***************************************************************************/
  1304. NTSTATUS
  1305. UlRemoveSiteFromEndpointList(
  1306. IN BOOLEAN secure,
  1307. IN USHORT port
  1308. )
  1309. {
  1310. NTSTATUS status = STATUS_SUCCESS;
  1311. PUL_ENDPOINT pEndpoint;
  1312. KIRQL oldIrql = PASSIVE_LEVEL;
  1313. BOOLEAN spinlockHeld = FALSE;
  1314. UL_STATUS_BLOCK ulStatus;
  1315. UNREFERENCED_PARAMETER(secure);
  1316. //
  1317. // N.B. pSiteUrl is paged and cannot be manipulated with the
  1318. // spinlock held. Even though this routine cannot be pageable
  1319. // (due to the spinlock aquisition), it must be called at
  1320. // low IRQL.
  1321. //
  1322. ASSERT( KeGetCurrentIrql() == PASSIVE_LEVEL );
  1323. //
  1324. // convert port to network byte order
  1325. //
  1326. port = SWAP_SHORT(port);
  1327. UlTrace(SITE, (
  1328. "UlRemoveSiteFromEndpointList: Scheme = '%s', Port = %d\n",
  1329. secure ? "https" : "http",
  1330. SWAP_SHORT(port)
  1331. ));
  1332. //
  1333. // Find an existing endpoint for this address.
  1334. //
  1335. UlAcquireSpinLock( &g_TdiSpinLock, &oldIrql );
  1336. spinlockHeld = TRUE;
  1337. pEndpoint = UlpFindEndpointForPort( port );
  1338. //
  1339. // Did we find one?
  1340. //
  1341. if (pEndpoint == NULL)
  1342. {
  1343. //
  1344. // Ideally, this should never happen.
  1345. //
  1346. ASSERT(FALSE);
  1347. status = STATUS_NOT_FOUND;
  1348. goto cleanup;
  1349. }
  1350. //
  1351. // Adjust the usage count. If it drops to zero, blow away the
  1352. // endpoint.
  1353. //
  1354. ASSERT( pEndpoint->UsageCount > 0 );
  1355. pEndpoint->UsageCount--;
  1356. WRITE_REF_TRACE_LOG(
  1357. g_pEndpointUsageTraceLog,
  1358. REF_ACTION_REFERENCE_ENDPOINT_USAGE,
  1359. pEndpoint->UsageCount,
  1360. pEndpoint,
  1361. __FILE__,
  1362. __LINE__
  1363. );
  1364. if (pEndpoint->UsageCount == 0)
  1365. {
  1366. //
  1367. // We can't call UlCloseListeningEndpoint() with the TDI spinlock
  1368. // held. If the endpoint is still on the global list, then go
  1369. // ahead and remove it now, release the TDI spinlock, and then
  1370. // close the endpoint.
  1371. //
  1372. if (! pEndpoint->Deleted)
  1373. {
  1374. ASSERT(NULL != pEndpoint->GlobalEndpointListEntry.Flink);
  1375. RemoveEntryList( &pEndpoint->GlobalEndpointListEntry );
  1376. InsertTailList(
  1377. &g_TdiDeletedEndpointListHead,
  1378. &pEndpoint->GlobalEndpointListEntry
  1379. );
  1380. pEndpoint->Deleted = TRUE;
  1381. }
  1382. UlReleaseSpinLock( &g_TdiSpinLock, oldIrql );
  1383. spinlockHeld = FALSE;
  1384. DEREFERENCE_ENDPOINT_SELF(
  1385. pEndpoint,
  1386. REF_ACTION_ENDPOINT_USAGE_DEREFERENCE
  1387. );
  1388. UlTrace(SITE, (
  1389. "UlRemoveSiteFromEndpointList: closing endpoint %p for "
  1390. "scheme '%s' port %d\n",
  1391. pEndpoint,
  1392. secure ? "https" : "http",
  1393. port
  1394. ));
  1395. //
  1396. // Initialize a status block. We'll pass a pointer to this as
  1397. // the completion context to UlCloseListeningEndpoint(). The
  1398. // completion routine will update the status block and signal
  1399. // the event.
  1400. //
  1401. UlInitializeStatusBlock( &ulStatus );
  1402. status = UlCloseListeningEndpoint(
  1403. pEndpoint,
  1404. &UlpSynchronousIoComplete,
  1405. &ulStatus
  1406. );
  1407. if (status == STATUS_PENDING)
  1408. {
  1409. //
  1410. // Wait for it to finish.
  1411. //
  1412. UlWaitForStatusBlockEvent( &ulStatus );
  1413. //
  1414. // Retrieve the updated status.
  1415. //
  1416. status = ulStatus.IoStatus.Status;
  1417. }
  1418. }
  1419. cleanup:
  1420. if (spinlockHeld)
  1421. {
  1422. UlReleaseSpinLock( &g_TdiSpinLock, oldIrql );
  1423. }
  1424. #if DBG
  1425. if (status == STATUS_NOT_FOUND)
  1426. {
  1427. UlTrace(SITE, (
  1428. "UlRemoveSiteFromEndpointList: cannot find endpoint for "
  1429. "scheme '%s' port %d\n",
  1430. secure ? "https" : "http",
  1431. port
  1432. ));
  1433. }
  1434. #endif
  1435. RETURN(status);
  1436. } // UlRemoveSiteFromEndpointList
  1437. //
  1438. // Private functions.
  1439. //
  1440. /***************************************************************************++
  1441. Routine Description:
  1442. Destroys all resources allocated to an endpoint, including the
  1443. endpoint structure itself.
  1444. Arguments:
  1445. pEndpoint - Supplies the endpoint to destroy.
  1446. --***************************************************************************/
  1447. VOID
  1448. UlpDestroyEndpoint(
  1449. IN PUL_ENDPOINT pEndpoint
  1450. )
  1451. {
  1452. PUL_IRP_CONTEXT pIrpContext;
  1453. ULONG EndpointCount = ULONG_MAX;
  1454. KIRQL oldIrql;
  1455. ULONG i;
  1456. //
  1457. // Sanity check.
  1458. //
  1459. ASSERT( IS_VALID_ENDPOINT( pEndpoint ) );
  1460. ASSERT(0 == pEndpoint->ReferenceCount);
  1461. ASSERT(0 == pEndpoint->UsageCount);
  1462. UlTrace(TDI, (
  1463. "UlpDestroyEndpoint: endpoint %p\n",
  1464. pEndpoint
  1465. ));
  1466. //
  1467. // Purge the idle lists.
  1468. //
  1469. for ( i = 0; i < pEndpoint->AddrIdleListCount ; i++ )
  1470. {
  1471. UlpCleanupAddrIdleList( &pEndpoint->aAddrIdleLists[i] );
  1472. }
  1473. //
  1474. // Invoke the completion routine in the IRP context if specified.
  1475. //
  1476. pIrpContext = &pEndpoint->CleanupIrpContext;
  1477. ASSERT( IS_VALID_IRP_CONTEXT( pIrpContext ) );
  1478. (VOID) UlInvokeCompletionRoutine(
  1479. STATUS_SUCCESS,
  1480. 0,
  1481. pIrpContext->pCompletionRoutine,
  1482. pIrpContext->pCompletionContext
  1483. );
  1484. //
  1485. // Remove the endpoint from g_TdiDeletedEndpointListHead
  1486. //
  1487. ASSERT( pEndpoint->Deleted );
  1488. ASSERT( NULL != pEndpoint->GlobalEndpointListEntry.Flink );
  1489. UlAcquireSpinLock( &g_TdiSpinLock, &oldIrql );
  1490. RemoveEntryList( &pEndpoint->GlobalEndpointListEntry );
  1491. if (pEndpoint->Counted)
  1492. {
  1493. g_TdiEndpointCount--;
  1494. EndpointCount = g_TdiEndpointCount;
  1495. }
  1496. UlReleaseSpinLock( &g_TdiSpinLock, oldIrql );
  1497. //
  1498. // Free the endpoint structure.
  1499. //
  1500. pEndpoint->Signature = UL_ENDPOINT_SIGNATURE_X;
  1501. UL_FREE_POOL( pEndpoint, UL_ENDPOINT_POOL_TAG );
  1502. //
  1503. // Decrement the global endpoint count.
  1504. //
  1505. if (g_TdiWaitingForEndpointDrain && EndpointCount == 0)
  1506. {
  1507. KeSetEvent(&g_TdiEndpointDrainEvent, 0, FALSE);
  1508. }
  1509. } // UlpDestroyEndpoint
  1510. /***************************************************************************++
  1511. Routine Description:
  1512. Deferred cleanup routine for dead connections.
  1513. Arguments:
  1514. pWorkItem - Supplies a pointer to the work item queued. This should
  1515. point to the WORK_ITEM structure embedded in a UL_CONNECTION.
  1516. --***************************************************************************/
  1517. VOID
  1518. UlpDestroyConnectionWorker(
  1519. IN PUL_WORK_ITEM pWorkItem
  1520. )
  1521. {
  1522. PUL_CONNECTION pConnection;
  1523. //
  1524. // Sanity check.
  1525. //
  1526. PAGED_CODE();
  1527. //
  1528. // Initialize locals.
  1529. //
  1530. pConnection = CONTAINING_RECORD(
  1531. pWorkItem,
  1532. UL_CONNECTION,
  1533. WorkItem
  1534. );
  1535. ASSERT( IS_VALID_CONNECTION( pConnection ) );
  1536. UlpDestroyConnection(pConnection);
  1537. } // UlpDestroyConnectionWorker
  1538. /***************************************************************************++
  1539. Routine Description:
  1540. Destroys all resources allocated to an connection, including the
  1541. connection structure itself.
  1542. Arguments:
  1543. pConnection - Supplies the connection to destroy.
  1544. --***************************************************************************/
  1545. VOID
  1546. UlpDestroyConnection(
  1547. IN PUL_CONNECTION pConnection
  1548. )
  1549. {
  1550. ULONG ConnectionCount;
  1551. KIRQL OldIrql;
  1552. //
  1553. // Sanity check.
  1554. //
  1555. PAGED_CODE();
  1556. ASSERT( IS_VALID_CONNECTION( pConnection ) );
  1557. ASSERT(pConnection->ConnListState == NoConnList);
  1558. ASSERT(UlpConnectionIsOnValidList(pConnection));
  1559. UlTraceVerbose(TDI, (
  1560. "UlpDestroyConnection: connection %p\n",
  1561. pConnection
  1562. ));
  1563. //
  1564. // Close the TDI object. Do this first so we would not receive any
  1565. // TDI indications beyond this point. Otherwise, our UlpDisconnectHandler
  1566. // may get called later and it may try to clean up a stale pFilterChannel
  1567. // under race conditions.
  1568. //
  1569. UxCloseTdiObject( &pConnection->ConnectionObject );
  1570. if (pConnection->FilterInfo.pFilterChannel)
  1571. {
  1572. //
  1573. // Release the RawConnection ID if we have allocated one.
  1574. //
  1575. UlpCleanupConnectionId(pConnection);
  1576. DEREFERENCE_FILTER_CHANNEL(pConnection->FilterInfo.pFilterChannel);
  1577. pConnection->FilterInfo.pFilterChannel = NULL;
  1578. }
  1579. // If OpaqueId is non-zero, then refCount should not be zero
  1580. ASSERT(HTTP_IS_NULL_ID(&pConnection->FilterInfo.ConnectionId));
  1581. //
  1582. // Free the accept IRP.
  1583. //
  1584. if (pConnection->pIrp != NULL)
  1585. {
  1586. UlFreeIrp( pConnection->pIrp );
  1587. }
  1588. //
  1589. // Remove from global list of connections
  1590. //
  1591. UlAcquireSpinLock( &g_TdiSpinLock, &OldIrql );
  1592. RemoveEntryList( &pConnection->GlobalConnectionListEntry );
  1593. g_TdiConnectionCount--;
  1594. ConnectionCount = g_TdiConnectionCount;
  1595. UlReleaseSpinLock( &g_TdiSpinLock, OldIrql );
  1596. //
  1597. // Free the connection structure.
  1598. //
  1599. DESTROY_REF_TRACE_LOG( pConnection->pTraceLog,
  1600. UL_CONNECTION_REF_TRACE_LOG_POOL_TAG );
  1601. DESTROY_REF_TRACE_LOG( pConnection->pHttpTraceLog,
  1602. UL_HTTP_CONNECTION_REF_TRACE_LOG_POOL_TAG );
  1603. WRITE_REF_TRACE_LOG(
  1604. g_pTdiTraceLog,
  1605. REF_ACTION_FREE_UL_CONNECTION,
  1606. 0,
  1607. pConnection,
  1608. __FILE__,
  1609. __LINE__
  1610. );
  1611. pConnection->Signature = UL_CONNECTION_SIGNATURE_X;
  1612. UL_FREE_POOL( pConnection, UL_CONNECTION_POOL_TAG );
  1613. // allow us to shut down
  1614. if (g_TdiWaitingForEndpointDrain && ConnectionCount == 0)
  1615. {
  1616. KeSetEvent(&g_TdiConnectionDrainEvent, 0, FALSE);
  1617. }
  1618. } // UlpDestroyConnection
  1619. /***************************************************************************++
  1620. Routine Description:
  1621. Dequeues any idle connection from the specified endpoint.
  1622. Arguments:
  1623. pAddrIdleList - Supplies the idle list to dequeue from.
  1624. Return Value:
  1625. PUL_CONNECTION - Pointer to an idle connection is successful,
  1626. NULL otherwise.
  1627. --***************************************************************************/
  1628. PUL_CONNECTION
  1629. UlpDequeueIdleConnectionToDrain(
  1630. IN PUL_ADDR_IDLE_LIST pAddrIdleList
  1631. )
  1632. {
  1633. PSLIST_ENTRY pSListEntry;
  1634. PUL_CONNECTION pConnection;
  1635. //
  1636. // Sanity check.
  1637. //
  1638. ASSERT( IS_VALID_ADDR_IDLE_LIST( pAddrIdleList ) );
  1639. pConnection = NULL;
  1640. //
  1641. // Pop an entry off the list.
  1642. //
  1643. pSListEntry = PpslAllocateToDrain( pAddrIdleList->IdleConnectionSListsHandle );
  1644. if (pSListEntry != NULL)
  1645. {
  1646. pConnection = CONTAINING_RECORD(
  1647. pSListEntry,
  1648. UL_CONNECTION,
  1649. IdleSListEntry
  1650. );
  1651. pConnection->IdleSListEntry.Next = NULL;
  1652. pConnection->ConnListState = NoConnList;
  1653. ASSERT( IS_VALID_CONNECTION( pConnection ) );
  1654. ASSERT(pConnection->ConnectionFlags.Value == 0);
  1655. if ( pConnection->FilterInfo.pFilterChannel )
  1656. {
  1657. //
  1658. // If the idle connection has filter attached on it, it will have
  1659. // an additional refcount because of the opaque id assigned to the
  1660. // ul_connection, filter API uses this id to communicate with the
  1661. // filter app through various IOCTLs.
  1662. //
  1663. ASSERT( 2 == pConnection->ReferenceCount );
  1664. }
  1665. else
  1666. {
  1667. //
  1668. // As long as the connection doesn't get destroyed, it will sit
  1669. // in the idle list with one refcount on it.
  1670. //
  1671. ASSERT( 1 == pConnection->ReferenceCount );
  1672. }
  1673. ASSERT( IS_VALID_ENDPOINT( pAddrIdleList->pOwningEndpoint ) );
  1674. }
  1675. return pConnection;
  1676. } // UlpDequeueIdleConnectionToDrain
  1677. /***************************************************************************++
  1678. Routine Description:
  1679. Dequeues an idle connection from the specified endpoint.
  1680. Arguments:
  1681. pEndpoint - Supplies the endpoint to dequeue from.
  1682. Return Value:
  1683. PUL_CONNECTION - Pointer to an idle connection is successful,
  1684. NULL otherwise.
  1685. --***************************************************************************/
  1686. PUL_CONNECTION
  1687. UlpDequeueIdleConnection(
  1688. IN PUL_ADDR_IDLE_LIST pAddrIdleList
  1689. )
  1690. {
  1691. PSLIST_ENTRY pSListEntry;
  1692. PUL_CONNECTION pConnection;
  1693. BOOLEAN PerProcListReplenishNeeded = FALSE;
  1694. BOOLEAN BackingListReplenishNeeded = FALSE; // Replenish backing list only
  1695. USHORT Depth = 0;
  1696. USHORT MinDepth = 0;
  1697. //
  1698. // Sanity check.
  1699. //
  1700. ASSERT( IS_VALID_ADDR_IDLE_LIST( pAddrIdleList ) );
  1701. //
  1702. // Pop an entry off the list.
  1703. //
  1704. pSListEntry = PpslAllocate( pAddrIdleList->IdleConnectionSListsHandle );
  1705. if (pSListEntry != NULL)
  1706. {
  1707. pConnection = CONTAINING_RECORD(
  1708. pSListEntry,
  1709. UL_CONNECTION,
  1710. IdleSListEntry
  1711. );
  1712. pConnection->IdleSListEntry.Next = NULL;
  1713. pConnection->ConnListState = NoConnList;
  1714. pConnection->OriginProcessor = KeGetCurrentProcessorNumber();
  1715. ASSERT( IS_VALID_CONNECTION( pConnection ) );
  1716. ASSERT( pConnection->ConnectionFlags.Value == 0 );
  1717. if (pConnection->FilterInfo.pFilterChannel)
  1718. {
  1719. //
  1720. // If the idle connection has filter attached on it, it will have
  1721. // an additional refcount because of the opaque id assigned to the
  1722. // ul_connection, filter API uses this id to communicate with the
  1723. // filter app through various IOCTLs.
  1724. //
  1725. ASSERT( 2 == pConnection->ReferenceCount );
  1726. }
  1727. else
  1728. {
  1729. //
  1730. // As long as the connection doesn't get destroyed, it will sit
  1731. // in the idle list with one refcount on it.
  1732. //
  1733. ASSERT( 1 == pConnection->ReferenceCount );
  1734. }
  1735. //
  1736. // Generate more connections if necessary. At the beginning
  1737. // there will be nothing in the back list, so we will do the
  1738. // initial populate when the first conn served from the idle
  1739. // list. Later we will populate only when we hit to low mark.
  1740. //
  1741. Depth = PpslQueryDepth(
  1742. pAddrIdleList->IdleConnectionSListsHandle,
  1743. KeGetCurrentProcessorNumber()
  1744. );
  1745. if (Depth == 0)
  1746. {
  1747. //
  1748. // This will replenish a block of connections to the
  1749. // per-proc list.
  1750. //
  1751. PerProcListReplenishNeeded = TRUE;
  1752. }
  1753. Depth = PpslQueryBackingListDepth(
  1754. pAddrIdleList->IdleConnectionSListsHandle
  1755. );
  1756. MinDepth = PpslQueryBackingListMinDepth(
  1757. pAddrIdleList->IdleConnectionSListsHandle
  1758. );
  1759. if (Depth < MinDepth)
  1760. {
  1761. //
  1762. // This will replenish a block of connections to the
  1763. // backing list.
  1764. //
  1765. BackingListReplenishNeeded = TRUE;
  1766. }
  1767. }
  1768. else
  1769. {
  1770. //
  1771. // The idle list is empty. However, we need to schedule
  1772. // a replenish at this time. Actually, we're desperate
  1773. // since we have already scheduled one.
  1774. //
  1775. PerProcListReplenishNeeded = TRUE;
  1776. BackingListReplenishNeeded = TRUE;
  1777. pConnection = NULL;
  1778. }
  1779. WRITE_REF_TRACE_LOG(
  1780. g_pTdiTraceLog,
  1781. REF_ACTION_DEQUEUE_UL_CONNECTION,
  1782. PerProcListReplenishNeeded || BackingListReplenishNeeded,
  1783. pConnection,
  1784. __FILE__,
  1785. __LINE__
  1786. );
  1787. //
  1788. // Schedule a replenish if necessary.
  1789. //
  1790. if (PerProcListReplenishNeeded || BackingListReplenishNeeded)
  1791. {
  1792. //
  1793. // Add a reference to the endpoint to ensure that it doesn't
  1794. // disappear from under us. UlpReplenishAddrIdleListWorker will
  1795. // remove the reference once it's finished.
  1796. //
  1797. if (FALSE == InterlockedExchange(
  1798. &pAddrIdleList->WorkItemScheduled,
  1799. TRUE
  1800. ))
  1801. {
  1802. REFERENCE_ENDPOINT(
  1803. pAddrIdleList->pOwningEndpoint,
  1804. REF_ACTION_REPLENISH
  1805. );
  1806. //
  1807. // Remember the proc on the adrlist.
  1808. //
  1809. if (PerProcListReplenishNeeded)
  1810. {
  1811. //
  1812. // Replenish per-proc list, and backing list
  1813. // if necessary
  1814. //
  1815. pAddrIdleList->CpuToReplenish =
  1816. (USHORT) KeGetCurrentProcessorNumber();
  1817. }
  1818. else
  1819. {
  1820. //
  1821. // Replenish backing list only
  1822. //
  1823. pAddrIdleList->CpuToReplenish =
  1824. (USHORT) g_UlNumberOfProcessors;
  1825. }
  1826. UL_QUEUE_HIGH_PRIORITY_ITEM(
  1827. &pAddrIdleList->WorkItem,
  1828. &UlpReplenishAddrIdleListWorker
  1829. );
  1830. }
  1831. }
  1832. return pConnection;
  1833. } // UlpDequeueIdleConnection
  1834. /***************************************************************************++
  1835. Routine Description:
  1836. Enqueues an active connection onto the specified endpoint.
  1837. Arguments:
  1838. pConnection - Supplies the connection to enqueue.
  1839. --***************************************************************************/
  1840. VOID
  1841. UlpEnqueueActiveConnection(
  1842. IN PUL_CONNECTION pConnection
  1843. )
  1844. {
  1845. PUL_ENDPOINT pEndpoint;
  1846. //
  1847. // Sanity check.
  1848. //
  1849. ASSERT( IS_VALID_CONNECTION( pConnection ) );
  1850. ASSERT(pConnection->ConnListState == NoConnList);
  1851. ASSERT(UlpConnectionIsOnValidList(pConnection));
  1852. pEndpoint = pConnection->pOwningEndpoint;
  1853. ASSERT( IS_VALID_ENDPOINT( pEndpoint ) );
  1854. ASSERT(UlDbgSpinLockOwned(&pConnection->ConnectionStateSpinLock));
  1855. REFERENCE_CONNECTION(pConnection);
  1856. pConnection->ConnListState = ActiveNoConnList;
  1857. ASSERT(UlpConnectionIsOnValidList(pConnection));
  1858. } // UlpEnqueueActiveConnection
  1859. /***************************************************************************++
  1860. Routine Description:
  1861. Handler for incoming connections.
  1862. Arguments:
  1863. pTdiEventContext - Supplies the context associated with the address
  1864. object. This should be a PUL_ADDR_IDLE_LIST, which can
  1865. traverse back to a PUL_ENDPOINT.
  1866. RemoteAddressLength - Supplies the length of the remote (client-
  1867. side) address.
  1868. pRemoteAddress - Supplies a pointer to the remote address as
  1869. stored in a TRANSPORT_ADDRESS structure.
  1870. UserDataLength - Optionally supplies the length of any connect
  1871. data associated with the connection request.
  1872. pUserData - Optionally supplies a pointer to any connect data
  1873. associated with the connection request.
  1874. OptionsLength - Optionally supplies the length of any connect
  1875. options associated with the connection request.
  1876. pOptions - Optionally supplies a pointer to any connect options
  1877. associated with the connection request.
  1878. pConnectionContext - Receives the context to associate with this
  1879. connection. We'll always use a PUL_CONNECTION as the context.
  1880. pAcceptIrp - Receives an IRP that will be completed by the transport
  1881. when the incoming connection is fully accepted.
  1882. Return Value:
  1883. NTSTATUS - Completion status.
  1884. --***************************************************************************/
  1885. NTSTATUS
  1886. UlpConnectHandler(
  1887. IN PVOID pTdiEventContext,
  1888. IN LONG RemoteAddressLength,
  1889. IN PVOID pRemoteAddress,
  1890. IN LONG UserDataLength,
  1891. IN PVOID pUserData,
  1892. IN LONG OptionsLength,
  1893. IN PVOID pOptions,
  1894. OUT CONNECTION_CONTEXT *pConnectionContext,
  1895. OUT PIRP *pAcceptIrp
  1896. )
  1897. {
  1898. NTSTATUS status;
  1899. BOOLEAN result;
  1900. PUL_ADDR_IDLE_LIST pAddrIdleList;
  1901. PUL_ENDPOINT pEndpoint;
  1902. PUL_CONNECTION pConnection;
  1903. PUX_TDI_OBJECT pTdiObject;
  1904. BOOLEAN handlerCalled;
  1905. TRANSPORT_ADDRESS UNALIGNED *TAList;
  1906. PTA_ADDRESS TA;
  1907. UL_ENTER_DRIVER("UlpConnectHandler", NULL);
  1908. UL_INC_CONNECTION_STATS( TotalConnections );
  1909. UNREFERENCED_PARAMETER(UserDataLength);
  1910. UNREFERENCED_PARAMETER(pUserData);
  1911. UNREFERENCED_PARAMETER(OptionsLength);
  1912. UNREFERENCED_PARAMETER(pOptions);
  1913. //
  1914. // Sanity check.
  1915. //
  1916. pAddrIdleList = (PUL_ADDR_IDLE_LIST)pTdiEventContext;
  1917. ASSERT( IS_VALID_ADDR_IDLE_LIST(pAddrIdleList));
  1918. pEndpoint = pAddrIdleList->pOwningEndpoint;
  1919. ASSERT( IS_VALID_ENDPOINT( pEndpoint ) );
  1920. UlTrace(TDI,("UlpConnectHandler: AddrIdleList %p, endpoint %p\n",
  1921. pAddrIdleList,
  1922. pEndpoint));
  1923. //
  1924. // If the endpoint has been has been added to the global list, then
  1925. // pEndpoint->Counted will be set. If the endpoint has not been added
  1926. // to the global list, then fail this call.
  1927. //
  1928. if (!pEndpoint->Counted)
  1929. {
  1930. return STATUS_INVALID_DEVICE_STATE;
  1931. }
  1932. //
  1933. // Setup locals so we know how to cleanup on fatal exit.
  1934. //
  1935. pConnection = NULL;
  1936. handlerCalled = FALSE;
  1937. //
  1938. // make sure that we are not in the process of destroying this
  1939. // endpoint. UlRemoveSiteFromEndpointList will do that and
  1940. // start the cleanup process when UsageCount hits 0.
  1941. //
  1942. if (pEndpoint->UsageCount == 0)
  1943. {
  1944. UL_INC_CONNECTION_STATS( EndpointDying );
  1945. status = STATUS_CONNECTION_REFUSED;
  1946. goto fatal;
  1947. }
  1948. //
  1949. // Try to pull an idle connection from the endpoint.
  1950. //
  1951. for (;;)
  1952. {
  1953. pConnection = UlpDequeueIdleConnection( pAddrIdleList );
  1954. if (pConnection == NULL )
  1955. {
  1956. UL_INC_CONNECTION_STATS( NoIdleConn );
  1957. status = STATUS_INSUFFICIENT_RESOURCES;
  1958. goto fatal;
  1959. }
  1960. ASSERT( IS_VALID_CONNECTION( pConnection ) );
  1961. //
  1962. // Establish a referenced pointer from the connection back
  1963. // to the endpoint.
  1964. //
  1965. ASSERT( pConnection->pOwningEndpoint == pEndpoint );
  1966. ASSERT( pConnection->pOwningAddrIdleList == pAddrIdleList );
  1967. REFERENCE_ENDPOINT( pEndpoint, REF_ACTION_CONNECT );
  1968. //
  1969. // Make sure the filter settings are up to date.
  1970. //
  1971. if (UlValidateFilterChannel(
  1972. pConnection->FilterInfo.pFilterChannel,
  1973. pConnection->FilterInfo.SecureConnection
  1974. ))
  1975. {
  1976. //
  1977. // We found a good connection.
  1978. // Break out of the loop and go on.
  1979. //
  1980. break;
  1981. }
  1982. //
  1983. // This connection doesn't have up to date filter
  1984. // settings. Destroy it and get a new connection.
  1985. //
  1986. UlpCleanupEarlyConnection(pConnection);
  1987. }
  1988. //
  1989. // We should have a good connection now.
  1990. //
  1991. ASSERT(IS_VALID_CONNECTION(pConnection));
  1992. pTdiObject = &pConnection->ConnectionObject;
  1993. //
  1994. // Store the remote address in the connection.
  1995. //
  1996. TAList = (TRANSPORT_ADDRESS UNALIGNED *) pRemoteAddress;
  1997. TA = (PTA_ADDRESS) TAList->Address;
  1998. ASSERT(TA->AddressType == pConnection->AddressType);
  1999. RtlCopyMemory(pConnection->RemoteAddress, TA->Address, TA->AddressLength);
  2000. //
  2001. // Invoke the client's handler to see if they can accept
  2002. // this connection. If they refuse it, bail.
  2003. //
  2004. result = (pEndpoint->pConnectionRequestHandler)(
  2005. pEndpoint->pListeningContext,
  2006. pConnection,
  2007. (PTRANSPORT_ADDRESS)(pRemoteAddress),
  2008. RemoteAddressLength,
  2009. &pConnection->pConnectionContext
  2010. );
  2011. if (!result)
  2012. {
  2013. //
  2014. // We expect UlConnectionRequest to call UL_INC_CONNECTION_STATS().
  2015. //
  2016. status = STATUS_CONNECTION_REFUSED;
  2017. goto fatal;
  2018. }
  2019. //
  2020. // Remember that we've called the handler. If we hit a fatal
  2021. // condition (say, out of memory) after this point, we'll
  2022. // fake a "failed connection complete" indication to the client
  2023. // so they can cleanup their state.
  2024. //
  2025. handlerCalled = TRUE;
  2026. pConnection->pIrp->Tail.Overlay.Thread = PsGetCurrentThread();
  2027. pConnection->pIrp->Tail.Overlay.OriginalFileObject = pTdiObject->pFileObject;
  2028. TdiBuildAccept(
  2029. pConnection->pIrp, // Irp
  2030. pTdiObject->pDeviceObject, // DeviceObject
  2031. pTdiObject->pFileObject, // FileObject
  2032. &UlpRestartAccept, // CompletionRoutine
  2033. pConnection, // Context
  2034. &(pConnection->TdiConnectionInformation), // RequestConnectionInfo
  2035. NULL // ReturnConnectionInfo
  2036. );
  2037. //
  2038. // We must trace the IRP before we set the next stack location
  2039. // so the trace code can pull goodies from the IRP correctly.
  2040. //
  2041. TRACE_IRP( IRP_ACTION_CALL_DRIVER, pConnection->pIrp );
  2042. //
  2043. // Make the next stack location current. Normally, UlCallDriver would
  2044. // do this for us, but since we're bypassing UlCallDriver, we must do
  2045. // it ourselves.
  2046. //
  2047. IoSetNextIrpStackLocation( pConnection->pIrp );
  2048. //
  2049. // Return the IRP to the transport.
  2050. //
  2051. *pAcceptIrp = pConnection->pIrp;
  2052. //
  2053. // Establish the connection context.
  2054. //
  2055. *pConnectionContext = (CONNECTION_CONTEXT)pConnection;
  2056. UlpSetConnectionFlag( pConnection, MakeAcceptPendingFlag() );
  2057. //
  2058. // NOTE: As far as the cleanup connection state is concerned,
  2059. // we are still UlConnectStateConnectIdle until we've fully
  2060. // accepted the connection (Half-Open connection doesn't matter).
  2061. //
  2062. ASSERT( UlConnectStateConnectIdle == pConnection->ConnectionState );
  2063. //
  2064. // Reference the connection so it doesn't go away before
  2065. // the accept IRP completes.
  2066. //
  2067. REFERENCE_CONNECTION( pConnection );
  2068. UL_LEAVE_DRIVER("UlpConnectHandler");
  2069. //
  2070. // Tell TDI that we gave it an IRP to complete.
  2071. //
  2072. return STATUS_MORE_PROCESSING_REQUIRED;
  2073. //
  2074. // Cleanup for fatal error conditions.
  2075. //
  2076. fatal:
  2077. UlTrace(TDI, (
  2078. "UlpConnectHandler: endpoint %p, failure 0x%x\n",
  2079. pTdiEventContext,
  2080. status
  2081. ));
  2082. if (handlerCalled)
  2083. {
  2084. //
  2085. // Fake a "failed connection complete" indication.
  2086. //
  2087. (pEndpoint->pConnectionCompleteHandler)(
  2088. pEndpoint->pListeningContext,
  2089. pConnection->pConnectionContext,
  2090. status
  2091. );
  2092. }
  2093. //
  2094. // If we managed to pull a connection off the idle list, then
  2095. // put it back and remove the endpoint reference we added.
  2096. //
  2097. if (pConnection != NULL)
  2098. {
  2099. UlpCleanupEarlyConnection(pConnection);
  2100. }
  2101. UL_LEAVE_DRIVER("UlpConnectHandler");
  2102. return status;
  2103. } // UlpConnectHandler
  2104. /***************************************************************************++
  2105. Routine Description:
  2106. Handler for disconnect requests.
  2107. Arguments:
  2108. pTdiEventContext - Supplies the context associated with the address
  2109. object. This should be a PUL_ENDPOINT.
  2110. ConnectionContext - Supplies the context associated with the
  2111. connection object. This should be a PUL_CONNECTION.
  2112. DisconnectDataLength - Optionally supplies the length of any
  2113. disconnect data associated with the disconnect request.
  2114. pDisconnectData - Optionally supplies a pointer to any disconnect
  2115. data associated with the disconnect request.
  2116. DisconnectInformationLength - Optionally supplies the length of any
  2117. disconnect information associated with the disconnect request.
  2118. pDisconnectInformation - Optionally supplies a pointer to any
  2119. disconnect information associated with the disconnect request.
  2120. DisconnectFlags - Supplies the disconnect flags. This will be zero
  2121. or more TDI_DISCONNECT_* flags.
  2122. Return Value:
  2123. NTSTATUS - Completion status.
  2124. --***************************************************************************/
  2125. NTSTATUS
  2126. UlpDisconnectHandler(
  2127. IN PVOID pTdiEventContext,
  2128. IN CONNECTION_CONTEXT ConnectionContext,
  2129. IN LONG DisconnectDataLength,
  2130. IN PVOID pDisconnectData,
  2131. IN LONG DisconnectInformationLength,
  2132. IN PVOID pDisconnectInformation,
  2133. IN ULONG DisconnectFlags
  2134. )
  2135. {
  2136. PUL_ENDPOINT pEndpoint;
  2137. PUL_CONNECTION pConnection;
  2138. LONG OldReference;
  2139. LONG NewReference;
  2140. UL_ENTER_DRIVER("UlpDisconnectHandler", NULL);
  2141. UNREFERENCED_PARAMETER(DisconnectDataLength);
  2142. UNREFERENCED_PARAMETER(pDisconnectData);
  2143. UNREFERENCED_PARAMETER(DisconnectInformationLength);
  2144. UNREFERENCED_PARAMETER(pDisconnectInformation);
  2145. //
  2146. // Sanity check.
  2147. //
  2148. pEndpoint = (PUL_ENDPOINT)pTdiEventContext;
  2149. ASSERT( IS_VALID_ENDPOINT( pEndpoint ) );
  2150. pConnection = (PUL_CONNECTION)ConnectionContext;
  2151. ASSERT( IS_VALID_CONNECTION( pConnection ) );
  2152. ASSERT( pConnection->pOwningEndpoint == pEndpoint );
  2153. UlTrace(TDI, (
  2154. "UlpDisconnectHandler: endpoint %p, connection %p, flags 0x%08lx, %s\n",
  2155. pTdiEventContext,
  2156. (PVOID)ConnectionContext,
  2157. DisconnectFlags,
  2158. (DisconnectFlags & TDI_DISCONNECT_ABORT) ? "abort" : "graceful"
  2159. ));
  2160. //
  2161. // Add an extra reference to pConnection before we proceed to protect
  2162. // ourselves from having connection reference drops to 0 in the middle
  2163. // of this routine, unless the reference is already at 0 when we enter
  2164. // this routine, in which case we simply bail out.
  2165. //
  2166. WRITE_REF_TRACE_LOG2(
  2167. g_pTdiTraceLog,
  2168. pConnection->pTraceLog,
  2169. REF_ACTION_DISCONNECT_HANDLER,
  2170. pConnection->ReferenceCount,
  2171. pConnection,
  2172. __FILE__,
  2173. __LINE__
  2174. );
  2175. for (;;)
  2176. {
  2177. OldReference = *((volatile LONG *) &pConnection->ReferenceCount);
  2178. if (0 == OldReference)
  2179. {
  2180. ASSERT( UlConnectStateConnectCleanup == pConnection->ConnectionState );
  2181. ASSERT( pConnection->ConnectionFlags.TdiConnectionInvalid );
  2182. return STATUS_SUCCESS;
  2183. }
  2184. NewReference = OldReference + 1;
  2185. if (InterlockedCompareExchange(
  2186. &pConnection->ReferenceCount,
  2187. NewReference,
  2188. OldReference
  2189. ) == OldReference)
  2190. {
  2191. break;
  2192. }
  2193. }
  2194. //
  2195. // Update the connection state based on the type of disconnect.
  2196. //
  2197. if (DisconnectFlags & TDI_DISCONNECT_ABORT)
  2198. {
  2199. //
  2200. // If it's a filtered connection, make sure we stop passing
  2201. // on AppWrite data.
  2202. //
  2203. if (pConnection->FilterInfo.pFilterChannel)
  2204. {
  2205. UlDestroyFilterConnection(&pConnection->FilterInfo);
  2206. }
  2207. UlpSetConnectionFlag( pConnection, MakeAbortIndicatedFlag() );
  2208. WRITE_REF_TRACE_LOG2(
  2209. g_pTdiTraceLog,
  2210. pConnection->pTraceLog,
  2211. REF_ACTION_ABORT_INDICATED,
  2212. pConnection->ReferenceCount,
  2213. pConnection,
  2214. __FILE__,
  2215. __LINE__
  2216. );
  2217. //
  2218. // Since the client aborted the connection we
  2219. // can clean up our own state immediately.
  2220. // This will also change our state for us.
  2221. // REVIEW: is it okay to init a graceful disconnect when we receive a
  2222. // graceful disconnect?
  2223. //
  2224. UlpCloseRawConnection(
  2225. pConnection,
  2226. TRUE, // AbortiveDisconnect
  2227. NULL, // pCompletionRoutine
  2228. NULL // pCompletionContext
  2229. );
  2230. }
  2231. else
  2232. {
  2233. UlpSetConnectionFlag( pConnection, MakeDisconnectIndicatedFlag() );
  2234. WRITE_REF_TRACE_LOG2(
  2235. g_pTdiTraceLog,
  2236. pConnection->pTraceLog,
  2237. REF_ACTION_DISCONNECT_INDICATED,
  2238. pConnection->ReferenceCount,
  2239. pConnection,
  2240. __FILE__,
  2241. __LINE__
  2242. );
  2243. if (UlConnectStateConnectReady == pConnection->ConnectionState)
  2244. {
  2245. if (pConnection->FilterInfo.pFilterChannel)
  2246. {
  2247. UlFilterDisconnectHandler(&pConnection->FilterInfo);
  2248. }
  2249. else
  2250. {
  2251. UlpDoDisconnectNotification(pConnection);
  2252. }
  2253. }
  2254. else
  2255. {
  2256. UlTrace( TDI, (
  2257. "UlpDisconnectHandler: connection %p, NOT UlConnectStateConnectReady (%d)!\n",
  2258. (PVOID)ConnectionContext,
  2259. pConnection->ConnectionState
  2260. ));
  2261. //
  2262. // If it's a filtered connection, make sure we stop passing
  2263. // on AppWrite data.
  2264. //
  2265. if (pConnection->FilterInfo.pFilterChannel)
  2266. {
  2267. UlDestroyFilterConnection(&pConnection->FilterInfo);
  2268. }
  2269. UlpCloseRawConnection(
  2270. pConnection,
  2271. TRUE, // AbortiveDisconnect
  2272. NULL, // pCompletionRoutine
  2273. NULL // pCompletionContext
  2274. );
  2275. }
  2276. }
  2277. //
  2278. // If cleanup has begun on the connection, remove the final reference.
  2279. //
  2280. UlpRemoveFinalReference( pConnection );
  2281. //
  2282. // Drop the extra reference we added when we enter this function.
  2283. //
  2284. DEREFERENCE_CONNECTION( pConnection );
  2285. UL_LEAVE_DRIVER("UlpDisconnectHandler");
  2286. return STATUS_SUCCESS;
  2287. } // UlpDisconnectHandler
  2288. /***************************************************************************++
  2289. Routine Description:
  2290. Tells the ultdi client of a disconnect. The client is only
  2291. notified of graceful disconnects and then only if the client
  2292. has not itself attempted to disconnect the connection. If the
  2293. connection is filtered, the filter process will be notified
  2294. instead of the client directly.
  2295. Arguments:
  2296. pConnection - a pointer to the connection
  2297. --***************************************************************************/
  2298. VOID
  2299. UlpDoDisconnectNotification(
  2300. IN PVOID pConnectionContext
  2301. )
  2302. {
  2303. PUL_CONNECTION pConnection = (PUL_CONNECTION) pConnectionContext;
  2304. PUL_ENDPOINT pEndpoint;
  2305. KIRQL OldIrql;
  2306. ASSERT(IS_VALID_CONNECTION(pConnection));
  2307. pEndpoint = pConnection->pOwningEndpoint;
  2308. ASSERT(IS_VALID_ENDPOINT(pEndpoint));
  2309. UlAcquireSpinLock(&pConnection->ConnectionStateSpinLock, &OldIrql);
  2310. ASSERT(pConnection->ConnectionFlags.AcceptComplete);
  2311. if (UlConnectStateConnectReady == pConnection->ConnectionState)
  2312. {
  2313. (pEndpoint->pConnectionDisconnectHandler)(
  2314. pEndpoint->pListeningContext,
  2315. pConnection->pConnectionContext
  2316. );
  2317. }
  2318. UlReleaseSpinLock(&pConnection->ConnectionStateSpinLock, OldIrql);
  2319. } // UlpDoDisconnectNotification
  2320. /***************************************************************************++
  2321. Routine Description:
  2322. Closes a previously accepted connection.
  2323. Arguments:
  2324. pConnection - Supplies a pointer to a connection as previously
  2325. indicated to the PUL_CONNECTION_REQUEST handler.
  2326. AbortiveDisconnect - Supplies TRUE if the connection is to be abortively
  2327. disconnected, FALSE if it should be gracefully disconnected.
  2328. pCompletionRoutine - Supplies a pointer to a completion routine to
  2329. invoke after the connection is fully closed.
  2330. pCompletionContext - Supplies an uninterpreted context value for the
  2331. completion routine.
  2332. Return Value:
  2333. NTSTATUS - Completion status.
  2334. --***************************************************************************/
  2335. NTSTATUS
  2336. UlpCloseRawConnection(
  2337. IN PVOID pConnectionContext,
  2338. IN BOOLEAN AbortiveDisconnect,
  2339. IN PUL_COMPLETION_ROUTINE pCompletionRoutine,
  2340. IN PVOID pCompletionContext
  2341. )
  2342. {
  2343. NTSTATUS status;
  2344. PUL_CONNECTION pConnection = (PUL_CONNECTION) pConnectionContext;
  2345. KIRQL OldIrql;
  2346. PIRP pIrp = NULL;
  2347. PUL_IRP_CONTEXT pIrpContext = NULL;
  2348. PUX_TDI_OBJECT pTdiObject;
  2349. //
  2350. // Sanity check.
  2351. //
  2352. ASSERT( IS_VALID_CONNECTION( pConnection ) );
  2353. ASSERT( KeGetCurrentIrql() <= DISPATCH_LEVEL );
  2354. UlTrace(TDI, (
  2355. "UlpCloseRawConnection: connection %p, %s disconnect\n",
  2356. pConnection,
  2357. (AbortiveDisconnect ? "Abortive" : "Graceful" )
  2358. ));
  2359. //
  2360. // This is the final close handler for all types of connections
  2361. // filter, non filter. We will go through this multiple times,
  2362. // but we need to guard against re-using the Disconnect IRP and
  2363. // ensure one-time close actions done a maximum of once.
  2364. //
  2365. UlAcquireSpinLock(
  2366. &pConnection->ConnectionStateSpinLock,
  2367. &OldIrql
  2368. );
  2369. switch (pConnection->ConnectionState)
  2370. {
  2371. //
  2372. // First attempt to terminate connection
  2373. //
  2374. case UlConnectStateConnectReady:
  2375. {
  2376. BOOLEAN Ignore = FALSE;
  2377. if (pConnection->ConnectionFlags.AbortIndicated)
  2378. {
  2379. // Client aborted. Go directly to clean up state.
  2380. pConnection->ConnectionState = UlConnectStateConnectCleanup;
  2381. Ignore = TRUE;
  2382. }
  2383. else
  2384. {
  2385. if (!AbortiveDisconnect)
  2386. {
  2387. //
  2388. // Allocate the disconnect IRP and IRP context for the
  2389. // graceful disconnect. If this fails, we will abort.
  2390. //
  2391. pIrpContext = UlPplAllocateIrpContext();
  2392. pTdiObject = &pConnection->ConnectionObject;
  2393. pIrp = UlAllocateIrp(
  2394. pTdiObject->pDeviceObject->StackSize,
  2395. FALSE
  2396. );
  2397. if (!pIrpContext || !pIrp)
  2398. {
  2399. if (pIrp)
  2400. {
  2401. UlFreeIrp( pIrp );
  2402. }
  2403. if (pIrpContext)
  2404. {
  2405. UlPplFreeIrpContext( pIrpContext );
  2406. }
  2407. AbortiveDisconnect = TRUE;
  2408. }
  2409. }
  2410. if (AbortiveDisconnect)
  2411. {
  2412. // Change State
  2413. pConnection->ConnectionState = UlConnectStateAbortPending;
  2414. //
  2415. // Set the flag indicating that an abort is pending &
  2416. // we're cleaning up.
  2417. //
  2418. UlpSetConnectionFlag( pConnection, MakeAbortPendingFlag() );
  2419. UlpSetConnectionFlag( pConnection, MakeCleanupBegunFlag() );
  2420. }
  2421. else
  2422. {
  2423. // Change State
  2424. pConnection->ConnectionState = UlConnectStateDisconnectPending;
  2425. //
  2426. // Set the flag indicating that a disconnect is pending &
  2427. // we're cleaning up.
  2428. //
  2429. UlpSetConnectionFlag( pConnection, MakeDisconnectPendingFlag() );
  2430. UlpSetConnectionFlag( pConnection, MakeCleanupBegunFlag() );
  2431. }
  2432. }
  2433. UlReleaseSpinLock(
  2434. &pConnection->ConnectionStateSpinLock,
  2435. OldIrql
  2436. );
  2437. WRITE_REF_TRACE_LOG2(
  2438. g_pTdiTraceLog,
  2439. pConnection->pTraceLog,
  2440. REF_ACTION_CLOSE_UL_CONN_RAW_CLOSE,
  2441. pConnection->ReferenceCount,
  2442. pConnection,
  2443. __FILE__,
  2444. __LINE__
  2445. );
  2446. //
  2447. // Do one-time only cleanup tasks
  2448. //
  2449. //
  2450. // Get rid of our opaque id if we're a filtered connection.
  2451. // Also make sure we stop delivering AppWrite data to the parser.
  2452. //
  2453. if (pConnection->FilterInfo.pFilterChannel)
  2454. {
  2455. UlpCleanupConnectionId( pConnection );
  2456. UlDestroyFilterConnection(&pConnection->FilterInfo);
  2457. }
  2458. //
  2459. // Let the completion routines do the dirty work
  2460. //
  2461. if (Ignore)
  2462. {
  2463. //
  2464. // Client aborted. No need to send RST or FIN.
  2465. //
  2466. status = UlInvokeCompletionRoutine(
  2467. STATUS_SUCCESS,
  2468. 0,
  2469. pCompletionRoutine,
  2470. pCompletionContext
  2471. );
  2472. }
  2473. else
  2474. {
  2475. if (AbortiveDisconnect)
  2476. {
  2477. //
  2478. // Send RST
  2479. //
  2480. status = UlpBeginAbort(
  2481. pConnection,
  2482. pCompletionRoutine,
  2483. pCompletionContext
  2484. );
  2485. }
  2486. else
  2487. {
  2488. //
  2489. // Send FIN
  2490. //
  2491. status = UlpBeginDisconnect(
  2492. pIrp,
  2493. pIrpContext,
  2494. pConnection,
  2495. pCompletionRoutine,
  2496. pCompletionContext
  2497. );
  2498. }
  2499. }
  2500. }
  2501. break;
  2502. // END case UlConnectStateConnectReady
  2503. //
  2504. // Waiting for disconnect indication
  2505. //
  2506. case UlConnectStateDisconnectComplete:
  2507. if ( pConnection->ConnectionFlags.AbortIndicated ||
  2508. pConnection->ConnectionFlags.DisconnectIndicated )
  2509. {
  2510. // Change State
  2511. pConnection->ConnectionState = UlConnectStateConnectCleanup;
  2512. }
  2513. else
  2514. {
  2515. if (AbortiveDisconnect)
  2516. {
  2517. // Change State
  2518. pConnection->ConnectionState = UlConnectStateAbortPending;
  2519. ASSERT( pConnection->ConnectionFlags.CleanupBegun );
  2520. UlpSetConnectionFlag( pConnection, MakeAbortPendingFlag() );
  2521. UlReleaseSpinLock(
  2522. &pConnection->ConnectionStateSpinLock,
  2523. OldIrql
  2524. );
  2525. UlTraceVerbose( TDI, (
  2526. "UlpCloseRawConnection: connection %p, Abort after Disconnect\n",
  2527. pConnection
  2528. ));
  2529. WRITE_REF_TRACE_LOG2(
  2530. g_pTdiTraceLog,
  2531. pConnection->pTraceLog,
  2532. REF_ACTION_CLOSE_UL_CONN_FORCE_ABORT,
  2533. pConnection->ReferenceCount,
  2534. pConnection,
  2535. __FILE__,
  2536. __LINE__
  2537. );
  2538. status = UlpBeginAbort(
  2539. pConnection,
  2540. pCompletionRoutine,
  2541. pCompletionContext
  2542. );
  2543. return status;
  2544. }
  2545. }
  2546. goto UnlockAndIgnore;
  2547. // END: case UlConnectStateDisconnectComplete
  2548. //
  2549. // Graceful disconnect already occured
  2550. //
  2551. case UlConnectStateDisconnectPending:
  2552. ASSERT( !pConnection->ConnectionFlags.DisconnectComplete );
  2553. if (pConnection->ConnectionFlags.AbortIndicated)
  2554. {
  2555. pConnection->ConnectionState = UlConnectStateConnectCleanup;
  2556. }
  2557. else
  2558. if (AbortiveDisconnect)
  2559. {
  2560. //
  2561. // Flag the connection as aborting a disconnect and set the state
  2562. // to UlConnectStateAbortPending.
  2563. //
  2564. UlpSetConnectionFlag( pConnection, MakeAbortDisconnectFlag() );
  2565. UlpSetConnectionFlag( pConnection, MakeAbortPendingFlag() );
  2566. pConnection->ConnectionState = UlConnectStateAbortPending;
  2567. UlReleaseSpinLock(
  2568. &pConnection->ConnectionStateSpinLock,
  2569. OldIrql
  2570. );
  2571. WRITE_REF_TRACE_LOG2(
  2572. g_pTdiTraceLog,
  2573. pConnection->pTraceLog,
  2574. REF_ACTION_CLOSE_UL_CONN_ABORT_DISCONNECT,
  2575. pConnection->ReferenceCount,
  2576. pConnection,
  2577. __FILE__,
  2578. __LINE__
  2579. );
  2580. status = UlpBeginAbort(
  2581. pConnection,
  2582. pCompletionRoutine,
  2583. pCompletionContext
  2584. );
  2585. return status;
  2586. }
  2587. goto UnlockAndIgnore;
  2588. // END case UlConnectStateDisconnectPending
  2589. //
  2590. // Invalid States
  2591. //
  2592. case UlConnectStateInvalid:
  2593. default:
  2594. //
  2595. // BUGBUG: Should never get here!
  2596. //
  2597. ASSERT( !"UlpCloseRawConnection: Invalid State!" );
  2598. //
  2599. // ...and then fall through to...
  2600. //
  2601. //
  2602. // Ignore any Aborts or Disconnects when in these states
  2603. //
  2604. case UlConnectStateConnectIdle: // Init'd
  2605. case UlConnectStateAbortPending: // Send RST
  2606. case UlConnectStateConnectCleanup: // Cleanup
  2607. UnlockAndIgnore:
  2608. //
  2609. // we've already done it. don't do it twice.
  2610. //
  2611. UlReleaseSpinLock(
  2612. &pConnection->ConnectionStateSpinLock,
  2613. OldIrql);
  2614. status = UlInvokeCompletionRoutine(
  2615. STATUS_SUCCESS,
  2616. 0,
  2617. pCompletionRoutine,
  2618. pCompletionContext
  2619. );
  2620. }
  2621. return status;
  2622. } // UlpCloseRawConnection
  2623. /***************************************************************************++
  2624. Routine Description:
  2625. Sends a block of data on the specified connection.
  2626. Arguments:
  2627. pConnection - Supplies a pointer to a connection as previously
  2628. indicated to the PUL_CONNECTION_REQUEST handler.
  2629. pMdlChain - Supplies a pointer to a MDL chain describing the
  2630. data buffers to send.
  2631. Length - Supplies the length of the data referenced by the MDL
  2632. chain.
  2633. pIrpContext - used to indicate completion to the caller.
  2634. InitiateDisconnect - Supplies TRUE if a graceful disconnect should
  2635. be initiated immediately after initiating the send (i.e. before
  2636. the send actually completes).
  2637. --***************************************************************************/
  2638. NTSTATUS
  2639. UlpSendRawData(
  2640. IN PVOID pConnectionContext,
  2641. IN PMDL pMdlChain,
  2642. IN ULONG Length,
  2643. IN PUL_IRP_CONTEXT pIrpContext,
  2644. IN BOOLEAN InitiateDisconnect
  2645. )
  2646. {
  2647. NTSTATUS status = STATUS_SUCCESS;
  2648. PIRP pIrp = NULL;
  2649. PUX_TDI_OBJECT pTdiObject;
  2650. PUL_CONNECTION pConnection = (PUL_CONNECTION) pConnectionContext;
  2651. PIRP pOwnIrp = pIrpContext->pOwnIrp;
  2652. PUL_TCPSEND_DISPATCH pDispatchRoutine;
  2653. KIRQL OldIrql;
  2654. //
  2655. // Sanity check.
  2656. //
  2657. ASSERT( IS_VALID_CONNECTION( pConnection ) );
  2658. //
  2659. // Apply the disconnect state transitions if InitiateDisconnect is
  2660. // requested.
  2661. //
  2662. if (InitiateDisconnect)
  2663. {
  2664. UlAcquireSpinLock( &pConnection->ConnectionStateSpinLock, &OldIrql );
  2665. if (UlConnectStateConnectReady == pConnection->ConnectionState)
  2666. {
  2667. //
  2668. // No SendAndDisconnect if client has aborted already and
  2669. // transition directly to the clean up state.
  2670. //
  2671. if (pConnection->ConnectionFlags.AbortIndicated)
  2672. {
  2673. pConnection->ConnectionState = UlConnectStateConnectCleanup;
  2674. status = STATUS_CONNECTION_INVALID;
  2675. }
  2676. else
  2677. {
  2678. pConnection->ConnectionState = UlConnectStateDisconnectPending;
  2679. //
  2680. // Set the flag indicating that a disconnect is pending &
  2681. // we're cleaning up.
  2682. //
  2683. UlpSetConnectionFlag( pConnection, MakeDisconnectPendingFlag() );
  2684. UlpSetConnectionFlag( pConnection, MakeCleanupBegunFlag() );
  2685. }
  2686. }
  2687. else
  2688. {
  2689. status = STATUS_CONNECTION_INVALID;
  2690. }
  2691. UlReleaseSpinLock( &pConnection->ConnectionStateSpinLock, OldIrql );
  2692. WRITE_REF_TRACE_LOG2(
  2693. g_pTdiTraceLog,
  2694. pConnection->pTraceLog,
  2695. REF_ACTION_SEND_AND_DISCONNECT,
  2696. pConnection->ReferenceCount,
  2697. pConnection,
  2698. __FILE__,
  2699. __LINE__
  2700. );
  2701. //
  2702. // Get rid of our opaque id if we're a filtered connection.
  2703. // Also make sure we stop delivering AppWrite data to the parser.
  2704. //
  2705. if (pConnection->FilterInfo.pFilterChannel)
  2706. {
  2707. UlpCleanupConnectionId( pConnection );
  2708. UlDestroyFilterConnection( &pConnection->FilterInfo );
  2709. }
  2710. if (!NT_SUCCESS(status))
  2711. {
  2712. goto fatal;
  2713. }
  2714. }
  2715. pTdiObject = &pConnection->ConnectionObject;
  2716. ASSERT( IS_VALID_TDI_OBJECT( pTdiObject ) );
  2717. ASSERT( pMdlChain != NULL );
  2718. ASSERT( Length > 0 );
  2719. ASSERT( pIrpContext != NULL );
  2720. //
  2721. // Allocate an IRP.
  2722. //
  2723. if (pOwnIrp)
  2724. {
  2725. pIrp = pOwnIrp;
  2726. }
  2727. else
  2728. {
  2729. pIrp = UlAllocateIrp(
  2730. pTdiObject->pDeviceObject->StackSize, // StackSize
  2731. FALSE // ChargeQuota
  2732. );
  2733. if (pIrp == NULL)
  2734. {
  2735. status = STATUS_INSUFFICIENT_RESOURCES;
  2736. goto fatal;
  2737. }
  2738. }
  2739. //
  2740. // Build the send IRP, call the transport.
  2741. //
  2742. pIrp->RequestorMode = KernelMode;
  2743. pIrp->Tail.Overlay.Thread = PsGetCurrentThread();
  2744. pIrp->Tail.Overlay.OriginalFileObject = pTdiObject->pFileObject;
  2745. pIrpContext->TdiSendFlag = InitiateDisconnect? TDI_SEND_AND_DISCONNECT: 0;
  2746. pIrpContext->SendLength = Length;
  2747. TdiBuildSend(
  2748. pIrp, // Irp
  2749. pTdiObject->pDeviceObject, // DeviceObject
  2750. pTdiObject->pFileObject, // FileObject
  2751. &UlpRestartSendData, // CompletionRoutine
  2752. pIrpContext, // Context
  2753. pMdlChain, // MdlAddress
  2754. pIrpContext->TdiSendFlag, // Flags
  2755. Length // SendLength
  2756. );
  2757. UlTrace(TDI, (
  2758. "UlpSendRawData: allocated irp %p for connection %p\n",
  2759. pIrp,
  2760. pConnection
  2761. ));
  2762. WRITE_REF_TRACE_LOG(
  2763. g_pMdlTraceLog,
  2764. REF_ACTION_SEND_MDL,
  2765. PtrToLong(pMdlChain->Next), // bugbug64
  2766. pMdlChain,
  2767. __FILE__,
  2768. __LINE__
  2769. );
  2770. #ifdef SPECIAL_MDL_FLAG
  2771. {
  2772. PMDL scan = pMdlChain;
  2773. while (scan != NULL)
  2774. {
  2775. ASSERT( (scan->MdlFlags & SPECIAL_MDL_FLAG) == 0 );
  2776. scan->MdlFlags |= SPECIAL_MDL_FLAG;
  2777. scan = scan->Next;
  2778. }
  2779. }
  2780. #endif
  2781. IF_DEBUG2BOTH(TDI, VERBOSE)
  2782. {
  2783. PMDL pMdl;
  2784. ULONG i, NumMdls = 0;
  2785. for (pMdl = pMdlChain; pMdl != NULL; pMdl = pMdl->Next)
  2786. {
  2787. ++NumMdls;
  2788. }
  2789. UlTrace(TDI, (
  2790. "UlpSendRawData: irp %p, %lu MDLs, %lu bytes, [[[[.\n",
  2791. pIrp, NumMdls, Length
  2792. ));
  2793. for (pMdl = pMdlChain, i = 1; pMdl != NULL; pMdl = pMdl->Next, ++i)
  2794. {
  2795. PVOID pBuffer;
  2796. UlTrace(TDI, (
  2797. "UlpSendRawData: irp %p, MDL[%lu of %lu], %lu bytes.\n",
  2798. pIrp, i, NumMdls, pMdl->ByteCount
  2799. ));
  2800. pBuffer = MmGetSystemAddressForMdlSafe(pMdl, NormalPagePriority);
  2801. if (pBuffer != NULL)
  2802. UlDbgPrettyPrintBuffer((UCHAR*) pBuffer, pMdl->ByteCount);
  2803. }
  2804. UlTrace(TDI, (
  2805. "UlpSendRawData: irp %p ]]]].\n",
  2806. pIrp
  2807. ));
  2808. }
  2809. if (pConnection->AddressType == TDI_ADDRESS_TYPE_IP)
  2810. {
  2811. ASSERT( NULL != g_TcpFastSendIPv4 );
  2812. pDispatchRoutine = g_TcpFastSendIPv4;
  2813. }
  2814. else
  2815. {
  2816. ASSERT( TDI_ADDRESS_TYPE_IP6 == pConnection->AddressType );
  2817. pDispatchRoutine = g_TcpFastSendIPv6;
  2818. //
  2819. // It's possible that g_TcpFastSendIPv6 wasn't initialized; e.g., if
  2820. // someone does an 'ipv6 install' and an 'iisreset', then http.sys is
  2821. // not restarted and so UlInitializeTdi() is not called and the
  2822. // function pointer doesn't get initialized.
  2823. //
  2824. if (NULL == pDispatchRoutine)
  2825. {
  2826. status = UlpQueryTcpFastSend(
  2827. DD_TCPV6_DEVICE_NAME,
  2828. &g_TcpFastSendIPv6
  2829. );
  2830. if (!NT_SUCCESS(status))
  2831. goto fatal;
  2832. pDispatchRoutine = g_TcpFastSendIPv6;
  2833. }
  2834. }
  2835. ASSERT( NULL != pDispatchRoutine );
  2836. //
  2837. // Add a reference to the connection, then call the driver to initiate
  2838. // the send.
  2839. //
  2840. REFERENCE_CONNECTION( pConnection );
  2841. IoSetNextIrpStackLocation(pIrp);
  2842. (*pDispatchRoutine)(
  2843. pIrp,
  2844. IoGetCurrentIrpStackLocation(pIrp)
  2845. );
  2846. UlTrace(TDI, (
  2847. "UlpSendRawData: called driver for irp %p; "
  2848. "returning STATUS_PENDING\n",
  2849. pIrp
  2850. ));
  2851. //
  2852. // We don't return the status from calling Tcp's fast dispatch routine
  2853. // since the completion for Irp is guaranteed and will have the
  2854. // appropriate status.
  2855. //
  2856. return STATUS_PENDING;
  2857. fatal:
  2858. ASSERT( !NT_SUCCESS(status) );
  2859. if (pIrp != NULL && pIrp != pOwnIrp)
  2860. {
  2861. UlFreeIrp( pIrp );
  2862. }
  2863. (VOID) UlpCloseRawConnection(
  2864. pConnection,
  2865. TRUE,
  2866. NULL,
  2867. NULL
  2868. );
  2869. return status;
  2870. } // UlpSendRawData
  2871. /***************************************************************************++
  2872. Routine Description:
  2873. Receives data from the specified connection. This function is
  2874. typically used after a receive indication handler has failed to
  2875. consume all of the indicated data.
  2876. Arguments:
  2877. pConnection - Supplies a pointer to a connection as previously
  2878. indicated to the PUL_CONNECTION_REQUEST handler.
  2879. pBuffer - Supplies a pointer to the target buffer for the received
  2880. data.
  2881. BufferLength - Supplies the length of pBuffer.
  2882. pCompletionRoutine - Supplies a pointer to a completion routine to
  2883. invoke after the listening endpoint is fully closed.
  2884. pCompletionContext - Supplies an uninterpreted context value for the
  2885. completion routine.
  2886. Return Value:
  2887. NTSTATUS - Completion status.
  2888. --***************************************************************************/
  2889. NTSTATUS
  2890. UlpReceiveRawData(
  2891. IN PVOID pConnectionContext,
  2892. IN PVOID pBuffer,
  2893. IN ULONG BufferLength,
  2894. IN PUL_COMPLETION_ROUTINE pCompletionRoutine,
  2895. IN PVOID pCompletionContext
  2896. )
  2897. {
  2898. NTSTATUS status;
  2899. PUX_TDI_OBJECT pTdiObject;
  2900. PUL_IRP_CONTEXT pIrpContext;
  2901. PIRP pIrp;
  2902. PMDL pMdl;
  2903. PUL_CONNECTION pConnection = (PUL_CONNECTION) pConnectionContext;
  2904. //
  2905. // Sanity check.
  2906. //
  2907. ASSERT( IS_VALID_CONNECTION( pConnection ) );
  2908. pTdiObject = &pConnection->ConnectionObject;
  2909. ASSERT( IS_VALID_TDI_OBJECT( pTdiObject ) );
  2910. ASSERT( pCompletionRoutine != NULL );
  2911. UlTrace(TDI, (
  2912. "UlpReceiveRawData: connection %p, buffer %p, length %lu\n",
  2913. pConnection,
  2914. pBuffer,
  2915. BufferLength
  2916. ));
  2917. //
  2918. // Setup locals so we know how to cleanup on failure.
  2919. //
  2920. pIrpContext = NULL;
  2921. pIrp = NULL;
  2922. pMdl = NULL;
  2923. //
  2924. // Create & initialize a receive IRP.
  2925. //
  2926. pIrp = UlAllocateIrp(
  2927. pTdiObject->pDeviceObject->StackSize, // StackSize
  2928. FALSE // ChargeQuota
  2929. );
  2930. if (pIrp != NULL)
  2931. {
  2932. //
  2933. // Snag an IRP context.
  2934. //
  2935. pIrpContext = UlPplAllocateIrpContext();
  2936. if (pIrpContext != NULL)
  2937. {
  2938. ASSERT( IS_VALID_IRP_CONTEXT( pIrpContext ) );
  2939. pIrpContext->pConnectionContext = (PVOID)pConnection;
  2940. pIrpContext->pCompletionRoutine = pCompletionRoutine;
  2941. pIrpContext->pCompletionContext = pCompletionContext;
  2942. pIrpContext->pOwnIrp = NULL;
  2943. pIrpContext->OwnIrpContext = FALSE;
  2944. //
  2945. // Create an MDL describing the client's buffer.
  2946. //
  2947. pMdl = UlAllocateMdl(
  2948. pBuffer, // VirtualAddress
  2949. BufferLength, // Length
  2950. FALSE, // SecondaryBuffer
  2951. FALSE, // ChargeQuota
  2952. NULL // Irp
  2953. );
  2954. if (pMdl != NULL)
  2955. {
  2956. //
  2957. // Adjust the MDL for our non-paged buffer.
  2958. //
  2959. MmBuildMdlForNonPagedPool( pMdl );
  2960. //
  2961. // Reference the connection, finish building the IRP.
  2962. //
  2963. REFERENCE_CONNECTION( pConnection );
  2964. TdiBuildReceive(
  2965. pIrp, // Irp
  2966. pTdiObject->pDeviceObject, // DeviceObject
  2967. pTdiObject->pFileObject, // FileObject
  2968. &UlpRestartClientReceive, // CompletionRoutine
  2969. pIrpContext, // CompletionContext
  2970. pMdl, // Mdl
  2971. TDI_RECEIVE_NORMAL, // Flags
  2972. BufferLength // Length
  2973. );
  2974. UlTrace(TDI, (
  2975. "UlpReceiveRawData: allocated irp %p for connection %p\n",
  2976. pIrp,
  2977. pConnection
  2978. ));
  2979. //
  2980. // Let the transport do the rest.
  2981. //
  2982. UlCallDriver( pTdiObject->pDeviceObject, pIrp );
  2983. return STATUS_PENDING;
  2984. }
  2985. }
  2986. }
  2987. //
  2988. // We only make it this point if we hit an allocation failure.
  2989. //
  2990. if (pMdl != NULL)
  2991. {
  2992. UlFreeMdl( pMdl );
  2993. }
  2994. if (pIrpContext != NULL)
  2995. {
  2996. UlPplFreeIrpContext( pIrpContext );
  2997. }
  2998. if (pIrp != NULL)
  2999. {
  3000. UlFreeIrp( pIrp );
  3001. }
  3002. status = UlInvokeCompletionRoutine(
  3003. STATUS_INSUFFICIENT_RESOURCES,
  3004. 0,
  3005. pCompletionRoutine,
  3006. pCompletionContext
  3007. );
  3008. return status;
  3009. } // UlpReceiveRawData
  3010. /***************************************************************************++
  3011. Routine Description:
  3012. A Dummy handler that is called by the filter code. This just calls
  3013. back into UlHttpReceive.
  3014. Arguments:
  3015. Return Value:
  3016. NTSTATUS - Completion status.
  3017. --***************************************************************************/
  3018. NTSTATUS
  3019. UlpDummyReceiveHandler(
  3020. IN PVOID pTdiEventContext,
  3021. IN PVOID ConnectionContext,
  3022. IN PVOID pTsdu,
  3023. IN ULONG BytesIndicated,
  3024. IN ULONG BytesUnreceived,
  3025. OUT ULONG *pBytesTaken
  3026. )
  3027. {
  3028. PUL_ENDPOINT pEndpoint;
  3029. PUL_CONNECTION pConnection;
  3030. //
  3031. // Sanity check.
  3032. //
  3033. ASSERT(pTdiEventContext == NULL);
  3034. ASSERT(BytesUnreceived == 0);
  3035. UNREFERENCED_PARAMETER(pTdiEventContext);
  3036. pConnection = (PUL_CONNECTION)ConnectionContext;
  3037. ASSERT( IS_VALID_CONNECTION( pConnection ) );
  3038. pEndpoint = pConnection->pOwningEndpoint;
  3039. ASSERT( IS_VALID_ENDPOINT( pEndpoint ) );
  3040. return (pEndpoint->pDataReceiveHandler)(
  3041. pEndpoint->pListeningContext,
  3042. pConnection->pConnectionContext,
  3043. pTsdu,
  3044. BytesIndicated,
  3045. BytesUnreceived,
  3046. pBytesTaken
  3047. );
  3048. } // UlpDummyReceiveHandler
  3049. /***************************************************************************++
  3050. Routine Description:
  3051. Handler for normal receive data.
  3052. Arguments:
  3053. pTdiEventContext - Supplies the context associated with the address
  3054. object. This should be a PUL_ENDPOINT.
  3055. ConnectionContext - Supplies the context associated with the
  3056. connection object. This should be a PUL_CONNECTION.
  3057. ReceiveFlags - Supplies the receive flags. This will be zero or more
  3058. TDI_RECEIVE_* flags.
  3059. BytesIndicated - Supplies the number of bytes indicated in pTsdu.
  3060. BytesAvailable - Supplies the number of bytes available in this
  3061. TSDU.
  3062. pBytesTaken - Receives the number of bytes consumed by this handler.
  3063. pTsdu - Supplies a pointer to the indicated data.
  3064. pIrp - Receives an IRP if the handler needs more data than indicated.
  3065. Return Value:
  3066. NTSTATUS - Completion status.
  3067. --***************************************************************************/
  3068. NTSTATUS
  3069. UlpReceiveHandler(
  3070. IN PVOID pTdiEventContext,
  3071. IN CONNECTION_CONTEXT ConnectionContext,
  3072. IN ULONG ReceiveFlags,
  3073. IN ULONG BytesIndicated,
  3074. IN ULONG BytesAvailable,
  3075. OUT ULONG *pBytesTaken,
  3076. IN PVOID pTsdu,
  3077. OUT PIRP *pIrp
  3078. )
  3079. {
  3080. NTSTATUS status;
  3081. PUL_ENDPOINT pEndpoint;
  3082. PUL_CONNECTION pConnection;
  3083. PUX_TDI_OBJECT pTdiObject;
  3084. KIRQL OldIrql;
  3085. UL_ENTER_DRIVER("UlpReceiveHandler", NULL);
  3086. UNREFERENCED_PARAMETER(ReceiveFlags);
  3087. //
  3088. // Sanity check.
  3089. //
  3090. pEndpoint = (PUL_ENDPOINT)pTdiEventContext;
  3091. ASSERT( IS_VALID_ENDPOINT( pEndpoint ) );
  3092. pConnection = (PUL_CONNECTION)ConnectionContext;
  3093. ASSERT( IS_VALID_CONNECTION( pConnection ) );
  3094. ASSERT( pConnection->pOwningEndpoint == pEndpoint );
  3095. pTdiObject = &pConnection->ConnectionObject;
  3096. ASSERT( IS_VALID_TDI_OBJECT( pTdiObject ) );
  3097. UlTrace(TDI, (
  3098. "UlpReceiveHandler: endpoint %p, connection %p, length %lu,%lu\n",
  3099. pTdiEventContext,
  3100. (PVOID)ConnectionContext,
  3101. BytesIndicated,
  3102. BytesAvailable
  3103. ));
  3104. //
  3105. // Clear the bytes taken output var
  3106. //
  3107. *pBytesTaken = 0;
  3108. //
  3109. // Bail out if this is an idle connection. On a checked build, we should
  3110. // assert because TCP should not indicate data after the disconnect.
  3111. // Bug related is 449527 which is fixed in build 3557.main.
  3112. //
  3113. if (0 == pConnection->ConnectionFlags.Value)
  3114. {
  3115. ASSERT( FALSE );
  3116. status = STATUS_DATA_NOT_ACCEPTED;
  3117. goto end;
  3118. }
  3119. //
  3120. // Wait for the local address to be set just in case the receive happens
  3121. // before accept. This is possible (but rare) on MP machines even when
  3122. // using DIRECT_ACCEPT. We set the ReceivePending flag and reject
  3123. // the data if this ever happens. When accept is completed, we will build
  3124. // a receive IRP to flush the data if ReceivePending is set.
  3125. //
  3126. if (0 == pConnection->ConnectionFlags.LocalAddressValid)
  3127. {
  3128. UlAcquireSpinLock(
  3129. &pConnection->ConnectionStateSpinLock,
  3130. &OldIrql
  3131. );
  3132. if (0 == pConnection->ConnectionFlags.LocalAddressValid)
  3133. {
  3134. UlpSetConnectionFlag( pConnection, MakeReceivePendingFlag() );
  3135. UlReleaseSpinLock(
  3136. &pConnection->ConnectionStateSpinLock,
  3137. OldIrql
  3138. );
  3139. status = STATUS_DATA_NOT_ACCEPTED;
  3140. goto end;
  3141. }
  3142. UlReleaseSpinLock(
  3143. &pConnection->ConnectionStateSpinLock,
  3144. OldIrql
  3145. );
  3146. }
  3147. //
  3148. // Give the client a crack at the data.
  3149. //
  3150. if (pConnection->FilterInfo.pFilterChannel)
  3151. {
  3152. //
  3153. // Needs to go through a filter.
  3154. //
  3155. status = UlFilterReceiveHandler(
  3156. &pConnection->FilterInfo,
  3157. pTsdu,
  3158. BytesIndicated,
  3159. BytesAvailable - BytesIndicated,
  3160. pBytesTaken
  3161. );
  3162. }
  3163. else
  3164. {
  3165. //
  3166. // Go directly to client (UlHttpReceive).
  3167. //
  3168. status = (pEndpoint->pDataReceiveHandler)(
  3169. pEndpoint->pListeningContext,
  3170. pConnection->pConnectionContext,
  3171. pTsdu,
  3172. BytesIndicated,
  3173. BytesAvailable - BytesIndicated,
  3174. pBytesTaken
  3175. );
  3176. }
  3177. ASSERT( *pBytesTaken <= BytesIndicated );
  3178. if (status == STATUS_SUCCESS)
  3179. {
  3180. goto end;
  3181. }
  3182. else if (status == STATUS_MORE_PROCESSING_REQUIRED)
  3183. {
  3184. ASSERT(!"How could this ever happen?");
  3185. //
  3186. // The client consumed part of the indicated data.
  3187. //
  3188. // A subsequent receive indication will be made to the client when
  3189. // additional data is available. This subsequent indication will
  3190. // include the unconsumed data from the current indication plus
  3191. // any additional data received.
  3192. //
  3193. // We need to allocate a receive buffer so we can pass an IRP back
  3194. // to the transport.
  3195. //
  3196. status = UlpBuildTdiReceiveBuffer(pTdiObject, pConnection, pIrp);
  3197. if (status == STATUS_MORE_PROCESSING_REQUIRED)
  3198. {
  3199. //
  3200. // Make the next stack location current. Normally, UlCallDriver
  3201. // would do this for us, but since we're bypassing UlCallDriver,
  3202. // we must do it ourselves.
  3203. //
  3204. IoSetNextIrpStackLocation( *pIrp );
  3205. goto end;
  3206. }
  3207. }
  3208. //
  3209. // If we made it this far, then we've hit a fatal condition. Either the
  3210. // client returned a status code other than STATUS_SUCCESS or
  3211. // STATUS_MORE_PROCESSING_REQUIRED, or we failed to allocation the
  3212. // receive IRP to pass back to the transport. In either case, we need
  3213. // to abort the connection.
  3214. //
  3215. UlpCloseRawConnection(
  3216. pConnection,
  3217. TRUE, // AbortiveDisconnect
  3218. NULL, // pCompletionRoutine
  3219. NULL // pCompletionContext
  3220. );
  3221. end:
  3222. UlTrace(TDI, (
  3223. "UlpReceiveHandler: endpoint %p, connection %p, length %lu,%lu, "
  3224. "taken %lu, status 0x%x\n",
  3225. pTdiEventContext,
  3226. (PVOID)ConnectionContext,
  3227. BytesIndicated,
  3228. BytesAvailable,
  3229. *pBytesTaken,
  3230. status
  3231. ));
  3232. UL_LEAVE_DRIVER("UlpReceiveHandler");
  3233. return status;
  3234. } // UlpReceiveHandler
  3235. /***************************************************************************++
  3236. Routine Description:
  3237. Handler for expedited receive data.
  3238. Arguments:
  3239. pTdiEventContext - Supplies the context associated with the address
  3240. object. This should be a PUL_ENDPOINT.
  3241. ConnectionContext - Supplies the context associated with the
  3242. connection object. This should be a PUL_CONNECTION.
  3243. ReceiveFlags - Supplies the receive flags. This will be zero or more
  3244. TDI_RECEIVE_* flags.
  3245. BytesIndiated - Supplies the number of bytes indicated in pTsdu.
  3246. BytesAvailable - Supplies the number of bytes available in this
  3247. TSDU.
  3248. pBytesTaken - Receives the number of bytes consumed by this handler.
  3249. pTsdu - Supplies a pointer to the indicated data.
  3250. ppIrp - Receives an IRP if the handler needs more data than indicated.
  3251. Return Value:
  3252. NTSTATUS - Completion status.
  3253. --***************************************************************************/
  3254. NTSTATUS
  3255. UlpReceiveExpeditedHandler(
  3256. IN PVOID pTdiEventContext,
  3257. IN CONNECTION_CONTEXT ConnectionContext,
  3258. IN ULONG ReceiveFlags,
  3259. IN ULONG BytesIndicated,
  3260. IN ULONG BytesAvailable,
  3261. OUT ULONG *pBytesTaken,
  3262. IN PVOID pTsdu,
  3263. OUT PIRP *ppIrp
  3264. )
  3265. {
  3266. PUL_ENDPOINT pEndpoint;
  3267. PUL_CONNECTION pConnection;
  3268. PUX_TDI_OBJECT pTdiObject;
  3269. UL_ENTER_DRIVER("UlpReceiveExpeditedHandler", NULL);
  3270. UNREFERENCED_PARAMETER(ReceiveFlags);
  3271. UNREFERENCED_PARAMETER(BytesIndicated);
  3272. UNREFERENCED_PARAMETER(pTsdu);
  3273. UNREFERENCED_PARAMETER(ppIrp);
  3274. //
  3275. // Sanity check.
  3276. //
  3277. pEndpoint = (PUL_ENDPOINT)pTdiEventContext;
  3278. ASSERT( IS_VALID_ENDPOINT( pEndpoint ) );
  3279. pConnection = (PUL_CONNECTION)ConnectionContext;
  3280. ASSERT( IS_VALID_CONNECTION( pConnection ) );
  3281. ASSERT( pConnection->pOwningEndpoint == pEndpoint );
  3282. pTdiObject = &pConnection->ConnectionObject;
  3283. ASSERT( IS_VALID_TDI_OBJECT( pTdiObject ) );
  3284. UlTrace(TDI, (
  3285. "UlpReceiveExpeditedHandler: endpoint %p, connection %p, length %lu,%lu\n",
  3286. pTdiEventContext,
  3287. (PVOID)ConnectionContext,
  3288. BytesIndicated,
  3289. BytesAvailable
  3290. ));
  3291. //
  3292. // We don't support expedited data, so just consume it all.
  3293. //
  3294. *pBytesTaken = BytesAvailable;
  3295. UL_LEAVE_DRIVER("UlpReceiveExpeditedHandler");
  3296. return STATUS_SUCCESS;
  3297. } // UlpReceiveExpeditedHandler
  3298. /***************************************************************************++
  3299. Routine Description:
  3300. Completion handler for accept IRPs.
  3301. Arguments:
  3302. pDeviceObject - Supplies the device object for the IRP being
  3303. completed.
  3304. pIrp - Supplies the IRP being completed.
  3305. pContext - Supplies the context associated with this request.
  3306. This is actually a PUL_CONNECTION.
  3307. Return Value:
  3308. NTSTATUS - STATUS_SUCCESS if IO should continue processing this
  3309. IRP, STATUS_MORE_PROCESSING_REQUIRED if IO should stop processing
  3310. this IRP.
  3311. --***************************************************************************/
  3312. NTSTATUS
  3313. UlpRestartAccept(
  3314. IN PDEVICE_OBJECT pDeviceObject,
  3315. IN PIRP pIrp,
  3316. IN PVOID pContext
  3317. )
  3318. {
  3319. PUL_CONNECTION pConnection;
  3320. PUL_ENDPOINT pEndpoint;
  3321. BOOLEAN NeedDisconnect = FALSE;
  3322. BOOLEAN NeedAbort = FALSE;
  3323. BOOLEAN ReceivePending = FALSE;
  3324. NTSTATUS IrpStatus;
  3325. NTSTATUS Status;
  3326. PIRP pReceiveIrp;
  3327. PTRANSPORT_ADDRESS pAddress;
  3328. KIRQL OldIrql;
  3329. UNREFERENCED_PARAMETER( pDeviceObject );
  3330. //
  3331. // Sanity check.
  3332. //
  3333. pConnection = (PUL_CONNECTION) pContext;
  3334. ASSERT( IS_VALID_CONNECTION( pConnection ) );
  3335. ASSERT( pConnection->ConnectionFlags.AcceptPending );
  3336. pEndpoint = pConnection->pOwningEndpoint;
  3337. ASSERT( IS_VALID_ENDPOINT( pEndpoint ) );
  3338. UlTrace(TDI, (
  3339. "UlpRestartAccept: irp %p, endpoint %p, connection %p, status 0x%x\n",
  3340. pIrp,
  3341. pEndpoint,
  3342. pConnection,
  3343. pIrp->IoStatus.Status
  3344. ));
  3345. //
  3346. // Capture the status from the IRP then free it.
  3347. //
  3348. IrpStatus = pIrp->IoStatus.Status;
  3349. //
  3350. // Assert for TCP bug 477465.
  3351. //
  3352. ASSERT( STATUS_CONNECTION_ACTIVE != IrpStatus );
  3353. //
  3354. // If the connection was fully accepted (successfully), then
  3355. // move it to the endpoint's active list.
  3356. //
  3357. if (NT_SUCCESS(IrpStatus))
  3358. {
  3359. //
  3360. // Get the Local Address Info.
  3361. //
  3362. pAddress = &(pConnection->Ta.Ta);
  3363. ASSERT( pAddress->Address[0].AddressType == pConnection->AddressType );
  3364. RtlCopyMemory(
  3365. pConnection->LocalAddress,
  3366. pAddress->Address[0].Address,
  3367. pAddress->Address[0].AddressLength
  3368. );
  3369. //
  3370. // Set the AcceptComplete flag. If a disconnect has
  3371. // already been indicated, then remember this fact so we can
  3372. // fake a call to the client's connection disconnect handler
  3373. // after we invoke the connection complete handler.
  3374. //
  3375. UlAcquireSpinLock(
  3376. &pConnection->ConnectionStateSpinLock,
  3377. &OldIrql
  3378. );
  3379. UlpEnqueueActiveConnection( pConnection );
  3380. //
  3381. // Mark we are done with the accept & change state.
  3382. //
  3383. ASSERT( UlConnectStateConnectIdle == pConnection->ConnectionState );
  3384. UlpSetConnectionFlag( pConnection, MakeLocalAddressValidFlag() );
  3385. UlpSetConnectionFlag( pConnection, MakeAcceptCompleteFlag() );
  3386. if (pConnection->ConnectionFlags.AbortIndicated)
  3387. {
  3388. //
  3389. // We got reset before we are up, transition directly to
  3390. // UlConnectStateConnectCleanup since UlpDisconnectHandler
  3391. // does nothing when it got the abort indication as the
  3392. // connection was still idle at that point.
  3393. //
  3394. pConnection->ConnectionState = UlConnectStateConnectCleanup;
  3395. NeedAbort = TRUE;
  3396. }
  3397. else
  3398. {
  3399. pConnection->ConnectionState = UlConnectStateConnectReady;
  3400. }
  3401. if (pConnection->ConnectionFlags.DisconnectIndicated)
  3402. {
  3403. NeedDisconnect = TRUE;
  3404. }
  3405. if (pConnection->ConnectionFlags.ReceivePending)
  3406. {
  3407. ReceivePending = TRUE;
  3408. }
  3409. UlReleaseSpinLock(
  3410. &pConnection->ConnectionStateSpinLock,
  3411. OldIrql
  3412. );
  3413. }
  3414. //
  3415. // Tell the client that the connection is complete.
  3416. //
  3417. (pEndpoint->pConnectionCompleteHandler)(
  3418. pEndpoint->pListeningContext,
  3419. pConnection->pConnectionContext,
  3420. IrpStatus
  3421. );
  3422. //
  3423. // If the accept failed, then mark the connection so we know there is
  3424. // no longer an accept pending, enqueue the connection back onto the
  3425. // endpoint's idle list.
  3426. if (!NT_SUCCESS(IrpStatus))
  3427. {
  3428. //
  3429. // Need to get rid of our opaque id if we're a filtered connection.
  3430. //
  3431. pConnection->ConnectionFlags.AcceptPending = 0;
  3432. UlpCleanupEarlyConnection( pConnection );
  3433. }
  3434. else
  3435. {
  3436. if (ReceivePending && !NeedDisconnect && !NeedAbort)
  3437. {
  3438. //
  3439. // We may have pending receives that we rejected early on
  3440. // inside the receive handler. Build an IRP to flush the
  3441. // data now. Do this only after we have completed the connect.
  3442. // Otherwise we can either process receives without timer being
  3443. // properly initialized or we can initilize timer on a free/idle
  3444. // connection.
  3445. //
  3446. Status = UlpBuildTdiReceiveBuffer(
  3447. &pConnection->ConnectionObject,
  3448. pConnection,
  3449. &pReceiveIrp
  3450. );
  3451. if (Status != STATUS_MORE_PROCESSING_REQUIRED)
  3452. {
  3453. UlpCloseRawConnection(
  3454. pConnection,
  3455. TRUE,
  3456. NULL,
  3457. NULL
  3458. );
  3459. }
  3460. else
  3461. {
  3462. UlCallDriver(
  3463. pConnection->ConnectionObject.pDeviceObject,
  3464. pReceiveIrp
  3465. );
  3466. }
  3467. }
  3468. //
  3469. // Tell the client that the connection was disconnected.
  3470. //
  3471. if (NeedDisconnect)
  3472. {
  3473. ASSERT( !NeedAbort );
  3474. UlpDoDisconnectNotification( pConnection );
  3475. }
  3476. if (NeedAbort)
  3477. {
  3478. ASSERT( !NeedDisconnect );
  3479. //
  3480. // We now may be able to remove the final reference since
  3481. // we have now set the AcceptComplete flag.
  3482. //
  3483. UlpRemoveFinalReference( pConnection );
  3484. }
  3485. }
  3486. //
  3487. // Drop the reference added in UlpConnectHandler.
  3488. //
  3489. DEREFERENCE_CONNECTION( pConnection );
  3490. return STATUS_MORE_PROCESSING_REQUIRED;
  3491. } // UlpRestartAccept
  3492. /***************************************************************************++
  3493. Routine Description:
  3494. Completion handler for send IRPs.
  3495. Arguments:
  3496. pDeviceObject - Supplies the device object for the IRP being
  3497. completed.
  3498. pIrp - Supplies the IRP being completed.
  3499. pContext - Supplies the context associated with this request.
  3500. This is actually a PUL_IRP_CONTEXT.
  3501. Return Value:
  3502. NTSTATUS - STATUS_SUCCESS if IO should continue processing this
  3503. IRP, STATUS_MORE_PROCESSING_REQUIRED if IO should stop processing
  3504. this IRP.
  3505. --***************************************************************************/
  3506. NTSTATUS
  3507. UlpRestartSendData(
  3508. IN PDEVICE_OBJECT pDeviceObject,
  3509. IN PIRP pIrp,
  3510. IN PVOID pContext
  3511. )
  3512. {
  3513. PUL_CONNECTION pConnection;
  3514. PUL_IRP_CONTEXT pIrpContext;
  3515. BOOLEAN OwnIrpContext;
  3516. PIRP pOwnIrp;
  3517. PUL_COMPLETION_ROUTINE pCompletionRoutine;
  3518. PVOID pCompletionContext;
  3519. NTSTATUS SendStatus = pIrp->IoStatus.Status;
  3520. UNREFERENCED_PARAMETER(pDeviceObject);
  3521. //
  3522. // Sanity check.
  3523. //
  3524. pIrpContext = (PUL_IRP_CONTEXT)pContext;
  3525. ASSERT( IS_VALID_IRP_CONTEXT( pIrpContext ) );
  3526. ASSERT( pIrpContext->pCompletionRoutine != NULL );
  3527. OwnIrpContext = pIrpContext->OwnIrpContext;
  3528. pOwnIrp = pIrpContext->pOwnIrp;
  3529. pCompletionRoutine = pIrpContext->pCompletionRoutine;
  3530. pCompletionContext = pIrpContext->pCompletionContext;
  3531. pConnection = (PUL_CONNECTION)pIrpContext->pConnectionContext;
  3532. ASSERT( IS_VALID_CONNECTION( pConnection ) );
  3533. ASSERT( IS_VALID_ENDPOINT( pConnection->pOwningEndpoint ) );
  3534. UlTrace(TDI, (
  3535. "UlpRestartSendData: irp %p, connection %p, status 0x%x, info %Iu\n",
  3536. pIrp,
  3537. pConnection,
  3538. pIrp->IoStatus.Status,
  3539. pIrp->IoStatus.Information
  3540. ));
  3541. WRITE_REF_TRACE_LOG(
  3542. g_pMdlTraceLog,
  3543. REF_ACTION_SEND_MDL_COMPLETE,
  3544. PtrToLong(pIrp->MdlAddress->Next), // bugbug64
  3545. pIrp->MdlAddress,
  3546. __FILE__,
  3547. __LINE__
  3548. );
  3549. #ifdef SPECIAL_MDL_FLAG
  3550. {
  3551. PMDL scan = pIrp->MdlAddress;
  3552. while (scan != NULL)
  3553. {
  3554. ASSERT( (scan->MdlFlags & SPECIAL_MDL_FLAG) != 0 );
  3555. scan->MdlFlags &= ~SPECIAL_MDL_FLAG;
  3556. scan = scan->Next;
  3557. }
  3558. }
  3559. #endif
  3560. //
  3561. // As needed, fake a disconnect indication and a disconnect completion
  3562. // if this comes from SEND_AND_DISCONNECT.
  3563. //
  3564. if (TDI_SEND_AND_DISCONNECT == pIrpContext->TdiSendFlag)
  3565. {
  3566. //
  3567. // SendStatus needs to be adjusted to STATUS_SUCCESS if we have sent
  3568. // all bytes asked for. This is because SEND_AND_DISCONNECT completes
  3569. // with the status of *both* send and disconnect.
  3570. //
  3571. if (pIrp->IoStatus.Information == pIrpContext->SendLength)
  3572. {
  3573. SendStatus = STATUS_SUCCESS;
  3574. }
  3575. //
  3576. // This is the last action on the connectio since send
  3577. // and disconnect completion means the connection has been
  3578. // closed by both local and remote sides.
  3579. //
  3580. if (!pConnection->ConnectionFlags.AbortIndicated &&
  3581. !pConnection->ConnectionFlags.DisconnectIndicated &&
  3582. !pConnection->ConnectionFlags.TdiConnectionInvalid)
  3583. {
  3584. //
  3585. // Fake a gracefull disconnect since it didn't happen.
  3586. //
  3587. // No need to sync with the disconnect handler since it
  3588. // will not run during or after the calling of this
  3589. // completion routine.
  3590. //
  3591. UlpDisconnectHandler(
  3592. pConnection->pOwningEndpoint,
  3593. pConnection,
  3594. 0,
  3595. NULL,
  3596. 0,
  3597. NULL,
  3598. TDI_DISCONNECT_RELEASE
  3599. );
  3600. }
  3601. pIrpContext->pConnectionContext = (PVOID)pConnection;
  3602. pIrpContext->pCompletionRoutine = NULL;
  3603. pIrpContext->pCompletionContext = NULL;
  3604. pIrpContext->pOwnIrp = pIrp;
  3605. pIrpContext->OwnIrpContext = TRUE;
  3606. (VOID) UlpRestartDisconnect(
  3607. pDeviceObject,
  3608. pIrp,
  3609. pIrpContext
  3610. );
  3611. //
  3612. // UlpRestartDisconnect drops the reference we added in UlSendData().
  3613. //
  3614. }
  3615. else
  3616. {
  3617. //
  3618. // Remove the reference we added in UlSendData().
  3619. //
  3620. DEREFERENCE_CONNECTION( pConnection );
  3621. }
  3622. //
  3623. // Tell the client that the send is complete.
  3624. //
  3625. (VOID) UlInvokeCompletionRoutine(
  3626. SendStatus,
  3627. pIrp->IoStatus.Information,
  3628. pCompletionRoutine,
  3629. pCompletionContext
  3630. );
  3631. //
  3632. // Free the context & the IRP since we're done with them, then
  3633. // tell IO to stop processing the IRP.
  3634. //
  3635. if (!OwnIrpContext)
  3636. {
  3637. UlPplFreeIrpContext( pIrpContext );
  3638. }
  3639. if (!pOwnIrp)
  3640. {
  3641. UlFreeIrp( pIrp );
  3642. }
  3643. return STATUS_MORE_PROCESSING_REQUIRED;
  3644. } // UlpRestartSendData
  3645. /***************************************************************************++
  3646. Routine Description:
  3647. Increments the reference count on the specified endpoint.
  3648. Arguments:
  3649. pEndpoint - Supplies the endpoint to reference.
  3650. pFileName (REFERENCE_DEBUG only) - Supplies the name of the file
  3651. containing the calling function.
  3652. LineNumber (REFERENCE_DEBUG only) - Supplies the line number of
  3653. the calling function.
  3654. --***************************************************************************/
  3655. VOID
  3656. UlpReferenceEndpoint(
  3657. IN PUL_ENDPOINT pEndpoint,
  3658. IN REFTRACE_ACTION Action
  3659. REFERENCE_DEBUG_FORMAL_PARAMS
  3660. )
  3661. {
  3662. LONG RefCount;
  3663. UNREFERENCED_PARAMETER( Action );
  3664. //
  3665. // Sanity check.
  3666. //
  3667. ASSERT( IS_VALID_ENDPOINT( pEndpoint ) );
  3668. //
  3669. // Reference it.
  3670. //
  3671. RefCount = InterlockedIncrement( &pEndpoint->ReferenceCount );
  3672. ASSERT( RefCount > 0 );
  3673. WRITE_REF_TRACE_LOG(
  3674. g_pTdiTraceLog,
  3675. Action,
  3676. RefCount,
  3677. pEndpoint,
  3678. pFileName,
  3679. LineNumber
  3680. );
  3681. UlTrace2Both(TDI, REFCOUNT, (
  3682. "UlpReferenceEndpoint: endpoint %p, refcount %ld\n",
  3683. pEndpoint,
  3684. RefCount
  3685. ));
  3686. } // UlpReferenceEndpoint
  3687. /***************************************************************************++
  3688. Routine Description:
  3689. Decrements the reference count on the specified endpoint.
  3690. Arguments:
  3691. pEndpoint - Supplies the endpoint to dereference.
  3692. pConnToEnqueue - if non-NULL, this routine will enqueue to the idle list.
  3693. pFileName (REFERENCE_DEBUG only) - Supplies the name of the file
  3694. containing the calling function.
  3695. LineNumber (REFERENCE_DEBUG only) - Supplies the line number of
  3696. the calling function.
  3697. --***************************************************************************/
  3698. VOID
  3699. UlpDereferenceEndpoint(
  3700. IN PUL_ENDPOINT pEndpoint,
  3701. IN PUL_CONNECTION pConnToEnqueue,
  3702. IN REFTRACE_ACTION Action
  3703. REFERENCE_DEBUG_FORMAL_PARAMS
  3704. )
  3705. {
  3706. PUL_ADDR_IDLE_LIST pAddrIdleList;
  3707. LONG RefCount;
  3708. KIRQL OldIrql;
  3709. UNREFERENCED_PARAMETER( Action );
  3710. //
  3711. // Sanity check.
  3712. //
  3713. ASSERT( IS_VALID_ENDPOINT( pEndpoint ) );
  3714. //
  3715. // Enqueue the connection to the idle list if pConnToEnqueue is not NULL.
  3716. //
  3717. if (NULL != pConnToEnqueue)
  3718. {
  3719. ASSERT( IS_VALID_CONNECTION( pConnToEnqueue ) );
  3720. pAddrIdleList = pConnToEnqueue->pOwningAddrIdleList;
  3721. ASSERT( IS_VALID_ADDR_IDLE_LIST( pAddrIdleList ) );
  3722. ASSERT( pAddrIdleList->pOwningEndpoint == pEndpoint );
  3723. ASSERT( pConnToEnqueue->ConnectionFlags.Value == 0 );
  3724. ASSERT( UlpConnectionIsOnValidList( pConnToEnqueue ) );
  3725. ASSERT( pConnToEnqueue->OriginProcessor < g_UlNumberOfProcessors );
  3726. //
  3727. // The idle list holds a reference; the filter channel (if it exists)
  3728. // holds another reference.
  3729. //
  3730. ASSERT( pConnToEnqueue->ReferenceCount ==
  3731. 1 + (pConnToEnqueue->FilterInfo.pFilterChannel != NULL) );
  3732. pConnToEnqueue->ConnListState = IdleConnList;
  3733. //
  3734. // CODEWORK: We should monitor the connection serving rate
  3735. // and start destroying freed connections if the rate is too
  3736. // small. We used to call PpslFree here which does some basic
  3737. // form of that test. (Delta check) however it wasn't good
  3738. // enough so we have disabled it for the time being.
  3739. //
  3740. if (FALSE == PpslFreeSpecifyList(
  3741. pAddrIdleList->IdleConnectionSListsHandle,
  3742. &pConnToEnqueue->IdleSListEntry,
  3743. pConnToEnqueue->OriginProcessor
  3744. ))
  3745. {
  3746. //
  3747. // We failed to free it to the per-processor list
  3748. // We definetely need to destroy this connection.
  3749. // Schedule a cleanup.
  3750. //
  3751. pConnToEnqueue->IdleSListEntry.Next = NULL;
  3752. pConnToEnqueue->ConnListState = NoConnList;
  3753. UL_QUEUE_WORK_ITEM(
  3754. &pConnToEnqueue->WorkItem,
  3755. &UlpDestroyConnectionWorker
  3756. );
  3757. }
  3758. }
  3759. //
  3760. // Dereference the endpoint.
  3761. //
  3762. RefCount = InterlockedDecrement( &pEndpoint->ReferenceCount );
  3763. ASSERT( RefCount >= 0 );
  3764. WRITE_REF_TRACE_LOG(
  3765. g_pTdiTraceLog,
  3766. Action,
  3767. RefCount,
  3768. pEndpoint,
  3769. pFileName,
  3770. LineNumber
  3771. );
  3772. UlTrace2Both(TDI, REFCOUNT, (
  3773. "UlpDereferenceEndpoint: endpoint %p, refcount %ld\n",
  3774. pEndpoint,
  3775. RefCount
  3776. ));
  3777. //
  3778. // Has the last external reference to the endpoint been removed?
  3779. //
  3780. if (RefCount == 0)
  3781. {
  3782. //
  3783. // The final references to the endpoint have been removed, so it's
  3784. // time to destroy the endpoint. We'll remove the endpoint from the
  3785. // global list and move it to the deleted list (if necessary),
  3786. // release the TDI spinlock, then destroy the endpoint.
  3787. //
  3788. UlAcquireSpinLock( &g_TdiSpinLock, &OldIrql );
  3789. if (!pEndpoint->Deleted)
  3790. {
  3791. //
  3792. // If this routine was called by the `fatal' section of
  3793. // UlCreateListeningEndpoint, then the endpoint was never
  3794. // added to g_TdiEndpointListHead.
  3795. //
  3796. if (NULL != pEndpoint->GlobalEndpointListEntry.Flink)
  3797. {
  3798. RemoveEntryList( &pEndpoint->GlobalEndpointListEntry );
  3799. }
  3800. InsertTailList(
  3801. &g_TdiDeletedEndpointListHead,
  3802. &pEndpoint->GlobalEndpointListEntry
  3803. );
  3804. pEndpoint->Deleted = TRUE;
  3805. }
  3806. else
  3807. {
  3808. ASSERT( NULL != pEndpoint->GlobalEndpointListEntry.Flink );
  3809. }
  3810. UlReleaseSpinLock( &g_TdiSpinLock, OldIrql );
  3811. //
  3812. // The endpoint is going away. Do final cleanup & resource
  3813. // release at passive IRQL.
  3814. //
  3815. // There is no chance that a replenish could be
  3816. // currently scheduled on pEndpoint->WorkItem, because
  3817. // we add a reference to the endpoint before scheduling the
  3818. // replenish, so we can't be here too.
  3819. //
  3820. // We need to schedule a worker item for the cleanup because
  3821. // this can be called within the context of a TDI indication
  3822. // (such as accept completion) in which case UlpDestroyEndpoint
  3823. // can close the same connection we have just pushed to the
  3824. // idle list in UlpRestartAccept, causing a deadlock.
  3825. //
  3826. UL_QUEUE_WORK_ITEM(
  3827. &pEndpoint->WorkItem,
  3828. &UlpEndpointCleanupWorker
  3829. );
  3830. }
  3831. } // UlpDereferenceEndpoint
  3832. /***************************************************************************++
  3833. Routine Description:
  3834. Increments the reference count on the specified connection.
  3835. Arguments:
  3836. pConnection - Supplies the connection to reference.
  3837. pFileName (REFERENCE_DEBUG only) - Supplies the name of the file
  3838. containing the calling function.
  3839. LineNumber (REFERENCE_DEBUG only) - Supplies the line number of
  3840. the calling function.
  3841. --***************************************************************************/
  3842. VOID
  3843. UlReferenceConnection(
  3844. IN PVOID pConnectionContext
  3845. REFERENCE_DEBUG_FORMAL_PARAMS
  3846. )
  3847. {
  3848. PUL_ENDPOINT pEndpoint;
  3849. LONG RefCount;
  3850. PUL_CONNECTION pConnection = (PUL_CONNECTION) pConnectionContext;
  3851. //
  3852. // Sanity check.
  3853. //
  3854. ASSERT( IS_VALID_CONNECTION( pConnection ) );
  3855. pEndpoint = pConnection->pOwningEndpoint;
  3856. ASSERT( IS_VALID_ENDPOINT( pEndpoint ) );
  3857. //
  3858. // Reference it.
  3859. //
  3860. RefCount = InterlockedIncrement( &pConnection->ReferenceCount );
  3861. ASSERT( RefCount > 1 );
  3862. WRITE_REF_TRACE_LOG2(
  3863. g_pTdiTraceLog,
  3864. pConnection->pTraceLog,
  3865. REF_ACTION_REFERENCE_UL_CONNECTION,
  3866. RefCount,
  3867. pConnection,
  3868. pFileName,
  3869. LineNumber
  3870. );
  3871. UlTrace2Both(TDI, REFCOUNT, (
  3872. "UlReferenceConnection: connection %p, refcount %ld\n",
  3873. pConnection,
  3874. RefCount
  3875. ));
  3876. } // UlReferenceConnection
  3877. /***************************************************************************++
  3878. Routine Description:
  3879. Decrements the reference count on the specified connection.
  3880. Arguments:
  3881. pConnection - Supplies the connection to dereference.
  3882. pFileName (REFERENCE_DEBUG only) - Supplies the name of the file
  3883. containing the calling function.
  3884. LineNumber (REFERENCE_DEBUG only) - Supplies the line number of
  3885. the calling function.
  3886. --***************************************************************************/
  3887. VOID
  3888. UlDereferenceConnection(
  3889. IN PVOID pConnectionContext
  3890. REFERENCE_DEBUG_FORMAL_PARAMS
  3891. )
  3892. {
  3893. PUL_ENDPOINT pEndpoint;
  3894. LONG RefCount;
  3895. PUL_CONNECTION pConnection = (PUL_CONNECTION) pConnectionContext;
  3896. //
  3897. // Sanity check.
  3898. //
  3899. ASSERT( IS_VALID_CONNECTION( pConnection ) );
  3900. pEndpoint = pConnection->pOwningEndpoint;
  3901. ASSERT( IS_VALID_ENDPOINT( pEndpoint ) );
  3902. //
  3903. // Must postpone the actual InterlockedDecrement until after the
  3904. // WRITE_REF_TRACE_LOG2 to prevent a race condition, where the
  3905. // pConnection->TraceLog is destroyed by another thread on the last
  3906. // dereference before the WRITE_REF_TRACE_LOG2 completes. This means
  3907. // that there's a slight race condition in what gets written to the
  3908. // tracelog, but we can live with that.
  3909. //
  3910. WRITE_REF_TRACE_LOG2(
  3911. g_pTdiTraceLog,
  3912. pConnection->pTraceLog,
  3913. REF_ACTION_DEREFERENCE_UL_CONNECTION,
  3914. pConnection->ReferenceCount - 1,
  3915. pConnection,
  3916. pFileName,
  3917. LineNumber
  3918. );
  3919. RefCount = InterlockedDecrement( &pConnection->ReferenceCount );
  3920. ASSERT( RefCount >= 0 );
  3921. UlTrace2Both(TDI, REFCOUNT, (
  3922. "UlDereferenceConnection: connection %p, refcount %ld\n",
  3923. pConnection,
  3924. RefCount
  3925. ));
  3926. if (RefCount == 0)
  3927. {
  3928. //
  3929. // The final reference to the connection has been removed, so
  3930. // it's time to destroy the connection.
  3931. //
  3932. ASSERT( UlpConnectionIsOnValidList( pConnection ) );
  3933. //
  3934. // If there's a filter token associated with the connection,
  3935. // cleanup must run under the system process at passive level
  3936. // (i.e., on one of our worker threads). Otherwise, we can
  3937. // clean it up directly.
  3938. //
  3939. if (pConnection->FilterInfo.SslInfo.Token != NULL)
  3940. {
  3941. UL_QUEUE_WORK_ITEM(
  3942. &pConnection->WorkItem,
  3943. &UlpConnectionCleanupWorker
  3944. );
  3945. }
  3946. else
  3947. {
  3948. UlpConnectionCleanupWorker( &pConnection->WorkItem );
  3949. }
  3950. }
  3951. } // UlDereferenceConnection
  3952. /***************************************************************************++
  3953. Routine Description:
  3954. Deferred cleanup routine for dead endpoints.
  3955. Arguments:
  3956. pWorkItem - Supplies a pointer to the work item queued. This should
  3957. point to the WORK_ITEM structure embedded in a UL_ENDPOINT.
  3958. --***************************************************************************/
  3959. VOID
  3960. UlpEndpointCleanupWorker(
  3961. IN PUL_WORK_ITEM pWorkItem
  3962. )
  3963. {
  3964. PUL_ENDPOINT pEndpoint;
  3965. //
  3966. // Sanity check.
  3967. //
  3968. PAGED_CODE();
  3969. pEndpoint = CONTAINING_RECORD(
  3970. pWorkItem,
  3971. UL_ENDPOINT,
  3972. WorkItem
  3973. );
  3974. ASSERT( IS_VALID_ENDPOINT( pEndpoint ) );
  3975. //
  3976. // Nuke it.
  3977. //
  3978. UlpDestroyEndpoint( pEndpoint );
  3979. } // UlpEndpointCleanupWorker
  3980. /***************************************************************************++
  3981. Routine Description:
  3982. Removes the opaque id from a connection.
  3983. Arguments:
  3984. pConnection
  3985. --***************************************************************************/
  3986. VOID
  3987. UlpCleanupConnectionId(
  3988. IN PUL_CONNECTION pConnection
  3989. )
  3990. {
  3991. HTTP_RAW_CONNECTION_ID ConnectionId;
  3992. ASSERT( IS_VALID_CONNECTION( pConnection ) );
  3993. //
  3994. // Pull the ID off the connection and set the connection's ID to 0.
  3995. //
  3996. ConnectionId = UlInterlockedExchange64(
  3997. (PLONGLONG) &pConnection->FilterInfo.ConnectionId,
  3998. HTTP_NULL_ID
  3999. );
  4000. if (!HTTP_IS_NULL_ID(&ConnectionId))
  4001. {
  4002. UlTrace(TDI, (
  4003. "UlpCleanupConnectionId: conn=%p id=%I64x\n",
  4004. pConnection, ConnectionId
  4005. ));
  4006. UlFreeOpaqueId( ConnectionId, UlOpaqueIdTypeRawConnection );
  4007. DEREFERENCE_CONNECTION( pConnection );
  4008. }
  4009. } // UlpCleanupConnectionId
  4010. /***************************************************************************++
  4011. Routine Description:
  4012. This function gets called if RestartAccept fails and we cannot establish
  4013. a connection on a secure endpoint, or if something goes wrong in
  4014. UlpConnectHandler.
  4015. The connections over secure endpoints keep an extra refcount to
  4016. the UL_CONNECTION because of their opaqueid. They normally
  4017. get removed after the CloseRawConnection happens but in the above case
  4018. close won't happen and we have to explicitly cleanup the id.
  4019. Arguments:
  4020. pConnection
  4021. --***************************************************************************/
  4022. VOID
  4023. UlpCleanupEarlyConnection(
  4024. IN PUL_CONNECTION pConnection
  4025. )
  4026. {
  4027. UL_CONNECTION_FLAGS Flags;
  4028. ASSERT( IS_VALID_CONNECTION( pConnection ) );
  4029. //
  4030. // If we are failing early we should never have been to
  4031. // FinalReferenceRemoved in the first place.
  4032. //
  4033. Flags.Value = *((volatile LONG *) &pConnection->ConnectionFlags.Value);
  4034. ASSERT( !Flags.FinalReferenceRemoved );
  4035. if (pConnection->FilterInfo.pFilterChannel)
  4036. {
  4037. //
  4038. // Cleanup opaque id. And release the final refcount
  4039. //
  4040. UlpCleanupConnectionId( pConnection );
  4041. }
  4042. //
  4043. // Remove the final reference.
  4044. //
  4045. DEREFERENCE_CONNECTION( pConnection );
  4046. } // UlpCleanupEarlyConnection
  4047. /***************************************************************************++
  4048. Routine Description:
  4049. Deferred cleanup routine for dead connections. We have to be queued as a
  4050. work item and should be running on the passive IRQL. See below comment.
  4051. Arguments:
  4052. pWorkItem - Supplies a pointer to the work item queued. This should
  4053. point to the WORK_ITEM structure embedded in a UL_CONNECTION.
  4054. --***************************************************************************/
  4055. VOID
  4056. UlpConnectionCleanupWorker(
  4057. IN PUL_WORK_ITEM pWorkItem
  4058. )
  4059. {
  4060. PUL_CONNECTION pConnection;
  4061. PUL_CONNECTION pConnToEnqueue = NULL; // don't reuse
  4062. PUL_ENDPOINT pEndpoint;
  4063. NTSTATUS status;
  4064. //
  4065. // Initialize locals.
  4066. //
  4067. status = STATUS_SUCCESS;
  4068. pConnection = CONTAINING_RECORD(
  4069. pWorkItem,
  4070. UL_CONNECTION,
  4071. WorkItem
  4072. );
  4073. ASSERT( IS_VALID_CONNECTION( pConnection ) );
  4074. ASSERT( IS_VALID_ENDPOINT( pConnection->pOwningEndpoint ) );
  4075. ASSERT( IS_VALID_ADDR_IDLE_LIST( pConnection->pOwningAddrIdleList ) );
  4076. ASSERT( pConnection->ReferenceCount == 0 );
  4077. ASSERT( pConnection->HttpConnection.RefCount == 0 );
  4078. //
  4079. // Grab the endpoint.
  4080. //
  4081. pEndpoint = pConnection->pOwningEndpoint;
  4082. //
  4083. // Now remove the connection from the active list
  4084. //
  4085. ASSERT( UlpConnectionIsOnValidList( pConnection ) );
  4086. pConnection->ConnListState = NoConnList;
  4087. ASSERT( UlpConnectionIsOnValidList( pConnection ) );
  4088. if (pConnection->FilterInfo.pFilterChannel)
  4089. {
  4090. //
  4091. // Get rid of any buffers we allocated for
  4092. // certificate information.
  4093. //
  4094. if (pConnection->FilterInfo.SslInfo.pServerCertData)
  4095. {
  4096. UL_FREE_POOL(
  4097. pConnection->FilterInfo.SslInfo.pServerCertData,
  4098. UL_SSL_CERT_DATA_POOL_TAG
  4099. );
  4100. pConnection->FilterInfo.SslInfo.pServerCertData = NULL;
  4101. }
  4102. if (pConnection->FilterInfo.SslInfo.pCertEncoded)
  4103. {
  4104. UL_FREE_POOL(
  4105. pConnection->FilterInfo.SslInfo.pCertEncoded,
  4106. UL_SSL_CERT_DATA_POOL_TAG
  4107. );
  4108. pConnection->FilterInfo.SslInfo.pCertEncoded = NULL;
  4109. }
  4110. if (pConnection->FilterInfo.SslInfo.Token)
  4111. {
  4112. HANDLE Token = (HANDLE) pConnection->FilterInfo.SslInfo.Token;
  4113. pConnection->FilterInfo.SslInfo.Token = NULL;
  4114. //
  4115. // If we are not running under the system process. And if the
  4116. // thread we are running under has some APCs queued currently
  4117. // KeAttachProcess won't allow us to attach to another process
  4118. // and will bugcheck 5. We have to be queued as a work item and
  4119. // should be running on the passive IRQL.
  4120. //
  4121. ASSERT( PsGetCurrentProcess() == (PEPROCESS) g_pUlSystemProcess );
  4122. ZwClose(Token);
  4123. }
  4124. }
  4125. //
  4126. // Check if the disconnect/abort completed with an error.
  4127. //
  4128. if (pConnection->ConnectionFlags.TdiConnectionInvalid)
  4129. {
  4130. status = STATUS_CONNECTION_INVALID;
  4131. }
  4132. //
  4133. // If the connection is still ok and we're reusing
  4134. // connection objects, throw it back on the idle list.
  4135. //
  4136. if (NT_SUCCESS(status))
  4137. {
  4138. //
  4139. // Release the filter channel.
  4140. //
  4141. if (pConnection->FilterInfo.pFilterChannel)
  4142. {
  4143. if (!HTTP_IS_NULL_ID(&pConnection->FilterInfo.ConnectionId))
  4144. {
  4145. UlpCleanupConnectionId( pConnection );
  4146. }
  4147. DEREFERENCE_FILTER_CHANNEL( pConnection->FilterInfo.pFilterChannel );
  4148. pConnection->FilterInfo.pFilterChannel = NULL;
  4149. }
  4150. //
  4151. // Initialize the connection for reuse.
  4152. //
  4153. status = UlpInitializeConnection( pConnection );
  4154. if (NT_SUCCESS(status))
  4155. {
  4156. //
  4157. // Stick the connection back on the idle list for reuse.
  4158. //
  4159. pConnToEnqueue = pConnection;
  4160. }
  4161. }
  4162. //
  4163. // Active connections hold a reference to the ENDPOINT. Release
  4164. // that reference. See the comment on UlpCreateConnection.
  4165. //
  4166. DEREFERENCE_ENDPOINT_CONNECTION(
  4167. pEndpoint,
  4168. pConnToEnqueue,
  4169. REF_ACTION_CONN_CLEANUP
  4170. );
  4171. //
  4172. // If anything went amiss, blow away the connection.
  4173. //
  4174. if (!NT_SUCCESS(status))
  4175. {
  4176. UL_QUEUE_WORK_ITEM(
  4177. &pConnection->WorkItem,
  4178. &UlpDestroyConnectionWorker
  4179. );
  4180. }
  4181. } // UlpConnectionCleanupWorker
  4182. /***************************************************************************++
  4183. Routine Description:
  4184. Associates the TDI connection object contained in the specified
  4185. connection to the TDI address object contained in the specified
  4186. endpoint.
  4187. Arguments:
  4188. pConnection - Supplies the connection to associate with the endpoint.
  4189. pEndpoint - Supplies the endpoint to associated with the connection.
  4190. pAddrIdleList - Supplies the address idle list owned by the endpoint
  4191. to associate with the connection.
  4192. Return Value:
  4193. NTSTATUS - Completion status.
  4194. --***************************************************************************/
  4195. NTSTATUS
  4196. UlpAssociateConnection(
  4197. IN PUL_CONNECTION pConnection,
  4198. IN PUL_ADDR_IDLE_LIST pAddrIdleList
  4199. )
  4200. {
  4201. NTSTATUS status;
  4202. IO_STATUS_BLOCK ioStatusBlock;
  4203. HANDLE handle;
  4204. TDI_REQUEST_USER_ASSOCIATE associateInfo;
  4205. //
  4206. // Sanity check.
  4207. //
  4208. PAGED_CODE();
  4209. ASSERT( IS_VALID_CONNECTION( pConnection ) );
  4210. ASSERT( IS_VALID_ADDR_IDLE_LIST( pAddrIdleList ) );
  4211. ASSERT( IS_VALID_ENDPOINT( pAddrIdleList->pOwningEndpoint ) );
  4212. ASSERT( pConnection->pOwningEndpoint == NULL );
  4213. //
  4214. // Associate the connection with the address object.
  4215. //
  4216. associateInfo.AddressHandle = pAddrIdleList->AddressObject.Handle;
  4217. ASSERT( associateInfo.AddressHandle != NULL );
  4218. handle = pConnection->ConnectionObject.Handle;
  4219. ASSERT( handle != NULL );
  4220. status = ZwDeviceIoControlFile(
  4221. handle, // FileHandle
  4222. NULL, // Event
  4223. NULL, // ApcRoutine
  4224. NULL, // ApcContext
  4225. &ioStatusBlock, // IoStatusBlock
  4226. IOCTL_TDI_ASSOCIATE_ADDRESS, // IoControlCode
  4227. &associateInfo, // InputBuffer
  4228. sizeof(associateInfo), // InputBufferLength
  4229. NULL, // OutputBuffer
  4230. 0 // OutputBufferLength
  4231. );
  4232. if (status == STATUS_PENDING)
  4233. {
  4234. status = ZwWaitForSingleObject(
  4235. handle, // Handle
  4236. TRUE, // Alertable
  4237. NULL // Timeout
  4238. );
  4239. ASSERT( NT_SUCCESS(status) );
  4240. status = ioStatusBlock.Status;
  4241. }
  4242. if (NT_SUCCESS(status))
  4243. {
  4244. pConnection->pOwningEndpoint = pAddrIdleList->pOwningEndpoint;
  4245. pConnection->pOwningAddrIdleList = pAddrIdleList;
  4246. pConnection->pConnectionDestroyedHandler = pAddrIdleList->pOwningEndpoint->pConnectionDestroyedHandler;
  4247. pConnection->pListeningContext = pAddrIdleList->pOwningEndpoint->pListeningContext;
  4248. }
  4249. else
  4250. {
  4251. UlTrace(TDI, (
  4252. "UlpAssociateConnection conn=%p, endp=%p, addr idle list=%p, status = 0x%x\n",
  4253. pConnection,
  4254. pAddrIdleList->pOwningEndpoint,
  4255. pAddrIdleList,
  4256. status
  4257. ));
  4258. }
  4259. return status;
  4260. } // UlpAssociateConnection
  4261. /***************************************************************************++
  4262. Routine Description:
  4263. Disassociates the TDI connection object contained in the specified
  4264. connection from its TDI address object.
  4265. Arguments:
  4266. pConnection - Supplies the connection to disassociate.
  4267. Return Value:
  4268. NTSTATUS - Completion status.
  4269. --***************************************************************************/
  4270. NTSTATUS
  4271. UlpDisassociateConnection(
  4272. IN PUL_CONNECTION pConnection
  4273. )
  4274. {
  4275. NTSTATUS status;
  4276. IO_STATUS_BLOCK ioStatusBlock;
  4277. HANDLE handle;
  4278. //
  4279. // Sanity check.
  4280. //
  4281. PAGED_CODE();
  4282. ASSERT( IS_VALID_CONNECTION( pConnection ) );
  4283. ASSERT( IS_VALID_ENDPOINT( pConnection->pOwningEndpoint ) );
  4284. ASSERT( IS_VALID_ADDR_IDLE_LIST( pConnection->pOwningAddrIdleList ) );
  4285. //
  4286. // Disassociate the connection from the address object.
  4287. //
  4288. handle = pConnection->ConnectionObject.Handle;
  4289. status = ZwDeviceIoControlFile(
  4290. handle, // FileHandle
  4291. NULL, // Event
  4292. NULL, // ApcRoutine
  4293. NULL, // ApcContext
  4294. &ioStatusBlock, // IoStatusBlock
  4295. IOCTL_TDI_DISASSOCIATE_ADDRESS, // IoControlCode
  4296. NULL, // InputBuffer
  4297. 0, // InputBufferLength
  4298. NULL, // OutputBuffer
  4299. 0 // OutputBufferLength
  4300. );
  4301. if (status == STATUS_PENDING)
  4302. {
  4303. status = ZwWaitForSingleObject(
  4304. handle, // Handle
  4305. TRUE, // Alertable
  4306. NULL // Timeout
  4307. );
  4308. ASSERT( NT_SUCCESS(status) );
  4309. status = ioStatusBlock.Status;
  4310. }
  4311. //
  4312. // Proceed with the disassociate even if the IOCTL failed.
  4313. //
  4314. pConnection->pOwningEndpoint = NULL;
  4315. pConnection->pOwningAddrIdleList = NULL;
  4316. return status;
  4317. } // UlpDisassociateConnection
  4318. /***************************************************************************++
  4319. Routine Description:
  4320. Initalized a UL_ADDR_IDLE_LIST and opens TDI handles/file objects
  4321. Arguments:
  4322. pEndpoint - Endpoint to be associated with this UL_ADDR_IDLE_LIST
  4323. Port - port number in network order
  4324. pTA - Transport Address to use when creating UX_TDI_OBJECT
  4325. pAddrIdleList- Caller allocated structure to be initalized.
  4326. Returns:
  4327. STATUS_INVALID_PARAMETER - failed due to bad transport address or
  4328. bad parameter.
  4329. --***************************************************************************/
  4330. NTSTATUS
  4331. UlpInitializeAddrIdleList(
  4332. IN PUL_ENDPOINT pEndpoint,
  4333. IN USHORT Port,
  4334. IN PUL_TRANSPORT_ADDRESS pTa,
  4335. IN OUT PUL_ADDR_IDLE_LIST pAddrIdleList
  4336. )
  4337. {
  4338. NTSTATUS status;
  4339. ULONG TASize;
  4340. #if DBG
  4341. USHORT PortHostOrder = SWAP_SHORT(Port);
  4342. UCHAR IpType = (pTa->Ta.Address[0].AddressType == TDI_ADDRESS_TYPE_IP6)
  4343. ? '6' : '4';
  4344. #endif // DBG
  4345. ASSERT( IS_VALID_ENDPOINT( pEndpoint ) );
  4346. ASSERT( pTa );
  4347. ASSERT( pTa->Ta.Address[0].AddressType == TDI_ADDRESS_TYPE_IP ||
  4348. pTa->Ta.Address[0].AddressType == TDI_ADDRESS_TYPE_IP6);
  4349. ASSERT( pAddrIdleList );
  4350. ASSERT( NULL == pAddrIdleList->AddressObject.pFileObject );
  4351. UlTrace(TDI, (
  4352. "UlpInitializeAddrIdleList: "
  4353. "pEndpoint %p, pAddrIdleList %p, Port %hu, IPv%c\n.",
  4354. pEndpoint,
  4355. pAddrIdleList,
  4356. PortHostOrder,
  4357. IpType
  4358. ));
  4359. pAddrIdleList->Signature = UL_ADDR_IDLE_LIST_SIGNATURE;
  4360. pAddrIdleList->pOwningEndpoint = pEndpoint;
  4361. UlInitializeWorkItem( &pAddrIdleList->WorkItem );
  4362. pAddrIdleList->WorkItemScheduled = FALSE;
  4363. //
  4364. // Set up the local transport address w/port
  4365. //
  4366. // This has to be done before we return from this routine -
  4367. // the caller expects the address to be initialized (even for failures).
  4368. RtlCopyMemory(
  4369. &pAddrIdleList->LocalAddress,
  4370. pTa,
  4371. sizeof(UL_TRANSPORT_ADDRESS)
  4372. );
  4373. if ( TDI_ADDRESS_TYPE_IP == pTa->Ta.Address[0].AddressType )
  4374. {
  4375. TASize = sizeof(TA_IP_ADDRESS);
  4376. pAddrIdleList->LocalAddress.TaIp.Address[0].Address[0].sin_port = Port;
  4377. }
  4378. else if ( TDI_ADDRESS_TYPE_IP6 == pTa->Ta.Address[0].AddressType )
  4379. {
  4380. TASize = sizeof(TA_IP6_ADDRESS);
  4381. pAddrIdleList->LocalAddress.TaIp6.Address[0].Address[0].sin6_port = Port;
  4382. }
  4383. else
  4384. {
  4385. // Bad Address!
  4386. ASSERT( !"UlpInitializeAddrIdleList: Bad TDI AddressType!" );
  4387. status = STATUS_INVALID_PARAMETER;
  4388. goto fatal;
  4389. }
  4390. pAddrIdleList->LocalAddressLength = TASize;
  4391. // Create idle connection list
  4392. pAddrIdleList->IdleConnectionSListsHandle =
  4393. PpslCreatePool(
  4394. UL_NONPAGED_DATA_POOL_TAG,
  4395. g_UlIdleConnectionsHighMark,
  4396. g_UlIdleConnectionsLowMark
  4397. );
  4398. if (pAddrIdleList->IdleConnectionSListsHandle == NULL)
  4399. {
  4400. status = STATUS_INSUFFICIENT_RESOURCES;
  4401. goto fatal;
  4402. }
  4403. //
  4404. // Open the TDI address object for this endpoint.
  4405. //
  4406. status = UxOpenTdiAddressObject(
  4407. &pAddrIdleList->LocalAddress.Ta,
  4408. TASize,
  4409. &pAddrIdleList->AddressObject
  4410. );
  4411. if (!NT_SUCCESS(status))
  4412. {
  4413. UlTraceError(TDI, (
  4414. "UlpInitializeAddrIdleList(%hu, IPv%c): "
  4415. "UxOpenTdiAddressObject failed, %s\n",
  4416. PortHostOrder, IpType, HttpStatusToString(status)
  4417. ));
  4418. goto fatal;
  4419. }
  4420. //
  4421. // Set the TDI event handlers.
  4422. //
  4423. status = UxSetEventHandler(
  4424. &pAddrIdleList->AddressObject,
  4425. TDI_EVENT_CONNECT,
  4426. (ULONG_PTR) &UlpConnectHandler,
  4427. pAddrIdleList
  4428. );
  4429. if (!NT_SUCCESS(status))
  4430. {
  4431. UlTraceError(TDI, (
  4432. "UlpInitializeAddrIdleList(%hu, IPv%c): "
  4433. "UxSetEventHandler(CONNECT) failed, %s\n",
  4434. PortHostOrder, IpType, HttpStatusToString(status)
  4435. ));
  4436. goto fatal;
  4437. }
  4438. status = UxSetEventHandler(
  4439. &pAddrIdleList->AddressObject,
  4440. TDI_EVENT_DISCONNECT,
  4441. (ULONG_PTR) &UlpDisconnectHandler,
  4442. pEndpoint
  4443. );
  4444. if (!NT_SUCCESS(status))
  4445. {
  4446. UlTraceError(TDI, (
  4447. "UlpInitializeAddrIdleList(%hu, IPv%c): "
  4448. "UxSetEventHandler(DISCONNECT) failed, %s\n",
  4449. PortHostOrder, IpType, HttpStatusToString(status)
  4450. ));
  4451. goto fatal;
  4452. }
  4453. status = UxSetEventHandler(
  4454. &pAddrIdleList->AddressObject,
  4455. TDI_EVENT_RECEIVE,
  4456. (ULONG_PTR) &UlpReceiveHandler,
  4457. pEndpoint
  4458. );
  4459. if (!NT_SUCCESS(status))
  4460. {
  4461. UlTraceError(TDI, (
  4462. "UlpInitializeAddrIdleList(%hu, IPv%c): "
  4463. "UxSetEventHandler(RECEIVE) failed, %s\n",
  4464. PortHostOrder, IpType, HttpStatusToString(status)
  4465. ));
  4466. goto fatal;
  4467. }
  4468. status = UxSetEventHandler(
  4469. &pAddrIdleList->AddressObject,
  4470. TDI_EVENT_RECEIVE_EXPEDITED,
  4471. (ULONG_PTR) &UlpReceiveExpeditedHandler,
  4472. pEndpoint
  4473. );
  4474. if (!NT_SUCCESS(status))
  4475. {
  4476. UlTraceError(TDI, (
  4477. "UlpInitializeAddrIdleList(%hu, IPv%c): "
  4478. "UxSetEventHandler(RECEIVE_EXPEDITED) failed, "
  4479. "%s\n",
  4480. PortHostOrder, IpType, HttpStatusToString(status)
  4481. ));
  4482. goto fatal;
  4483. }
  4484. return status;
  4485. fatal:
  4486. //
  4487. // Disable connect events if we failed for any reason
  4488. //
  4489. if (pAddrIdleList && pAddrIdleList->AddressObject.pFileObject)
  4490. {
  4491. UxSetEventHandler(
  4492. &pAddrIdleList->AddressObject,
  4493. TDI_EVENT_CONNECT,
  4494. (ULONG_PTR) NULL,
  4495. NULL
  4496. );
  4497. }
  4498. return status;
  4499. } // UlpInitializeEndpointTdiObject
  4500. /***************************************************************************++
  4501. Routine Description:
  4502. Cleans up a UL_ADDR_IDLE_LIST and closes TDI handles/file objects
  4503. Arguments:
  4504. pAddrIdleList - Caller allocated structure to be cleaned up.
  4505. Returns:
  4506. STATUS_INVALID_PARAMETER - failed due to bad parameter
  4507. --***************************************************************************/
  4508. VOID
  4509. UlpCleanupAddrIdleList(
  4510. PUL_ADDR_IDLE_LIST pAddrIdleList
  4511. )
  4512. {
  4513. PUL_CONNECTION pConnection;
  4514. ASSERT( pAddrIdleList );
  4515. UlTrace(TDI, (
  4516. "UlpCleanupAddrIdleList: pAddrIdleList %p\n",
  4517. pAddrIdleList
  4518. ));
  4519. //
  4520. // Clean up idle list
  4521. //
  4522. if ( pAddrIdleList->IdleConnectionSListsHandle )
  4523. {
  4524. ASSERT( IS_VALID_ADDR_IDLE_LIST(pAddrIdleList) );
  4525. do
  4526. {
  4527. pConnection = UlpDequeueIdleConnectionToDrain( pAddrIdleList );
  4528. if (pConnection)
  4529. {
  4530. ASSERT( IS_VALID_CONNECTION( pConnection ) );
  4531. UlpDestroyConnection( pConnection );
  4532. }
  4533. } while ( pConnection );
  4534. PpslDestroyPool(
  4535. pAddrIdleList->IdleConnectionSListsHandle,
  4536. UL_NONPAGED_DATA_POOL_TAG
  4537. );
  4538. pAddrIdleList->IdleConnectionSListsHandle = NULL;
  4539. }
  4540. //
  4541. // Mark as cleaned up
  4542. //
  4543. pAddrIdleList->Signature = UL_ADDR_IDLE_LIST_SIGNATURE_X;
  4544. }// UlpCleanupAddrIdleList
  4545. /***************************************************************************++
  4546. Routine Description:
  4547. Creates a block of idle connections on a specified proc or current proc.
  4548. Arguments:
  4549. pAddrIdleList - Supplies the idle list to replenish.
  4550. Proc - Only for this per-proc list
  4551. --***************************************************************************/
  4552. NTSTATUS
  4553. UlpPopulateIdleList(
  4554. IN OUT PUL_ADDR_IDLE_LIST pAddrIdleList,
  4555. IN ULONG Proc
  4556. )
  4557. {
  4558. NTSTATUS Status = STATUS_SUCCESS;
  4559. PUL_CONNECTION pConnection;
  4560. ULONG i;
  4561. USHORT BlockSize;
  4562. PAGED_CODE();
  4563. //
  4564. // Create a block of connections.
  4565. //
  4566. BlockSize = PpslQueryMinDepth(
  4567. pAddrIdleList->IdleConnectionSListsHandle,
  4568. Proc
  4569. );
  4570. ASSERT(BlockSize);
  4571. for (i = 0; i < BlockSize; i++)
  4572. {
  4573. Status = UlpCreateConnection(
  4574. pAddrIdleList,
  4575. &pConnection
  4576. );
  4577. if (!NT_SUCCESS(Status))
  4578. {
  4579. break;
  4580. }
  4581. Status = UlpInitializeConnection(pConnection);
  4582. if (!NT_SUCCESS(Status))
  4583. {
  4584. UlpDestroyConnection(pConnection);
  4585. break;
  4586. }
  4587. //
  4588. // Free the connection back to the idle list. But do not
  4589. // overflow the backing list.
  4590. //
  4591. pConnection->ConnListState = IdleConnList;
  4592. if ( FALSE ==
  4593. PpslFreeSpecifyList(
  4594. pAddrIdleList->IdleConnectionSListsHandle,
  4595. &pConnection->IdleSListEntry,
  4596. Proc
  4597. ) )
  4598. {
  4599. pConnection->ConnListState = NoConnList;
  4600. UlpDestroyConnection(pConnection);
  4601. break;
  4602. }
  4603. }
  4604. return Status;
  4605. }
  4606. /***************************************************************************++
  4607. Routine Description:
  4608. Replenishes the idle connection pool in the specified endpoint.
  4609. Arguments:
  4610. pAddrIdleList - Supplies the idle list to replenish.
  4611. PopulateAll - Whether or not to replenish all per-proc idle connection
  4612. lists or just the current processor's idle connection list.
  4613. --***************************************************************************/
  4614. NTSTATUS
  4615. UlpReplenishAddrIdleList(
  4616. IN PUL_ADDR_IDLE_LIST pAddrIdleList,
  4617. IN BOOLEAN PopulateAll
  4618. )
  4619. {
  4620. NTSTATUS Status;
  4621. //
  4622. // Sanity check.
  4623. //
  4624. PAGED_CODE();
  4625. ASSERT(IS_VALID_ADDR_IDLE_LIST(pAddrIdleList));
  4626. ASSERT(IS_VALID_ENDPOINT(pAddrIdleList->pOwningEndpoint));
  4627. if (PopulateAll)
  4628. {
  4629. //
  4630. // We are initializing the idle list for the very first time.
  4631. // Populate the backing list to its LowDepth.
  4632. //
  4633. Status = UlpPopulateIdleList(pAddrIdleList, g_UlNumberOfProcessors);
  4634. SHOW_LIST_INFO(
  4635. "REPLENISH",
  4636. "INIT ",
  4637. pAddrIdleList,
  4638. g_UlNumberOfProcessors
  4639. );
  4640. }
  4641. else
  4642. {
  4643. SHOW_LIST_INFO(
  4644. "REPLENISH",
  4645. "BEFORE",
  4646. pAddrIdleList,
  4647. pAddrIdleList->CpuToReplenish
  4648. );
  4649. //
  4650. // Add a "block" of Idle connections to per-proc list/backing list
  4651. // if possible.
  4652. //
  4653. Status = UlpPopulateIdleList(
  4654. pAddrIdleList,
  4655. pAddrIdleList->CpuToReplenish
  4656. );
  4657. SHOW_LIST_INFO(
  4658. "REPLENISH",
  4659. "AFTER ",
  4660. pAddrIdleList,
  4661. pAddrIdleList->CpuToReplenish
  4662. );
  4663. //
  4664. // If a per-proc list replenishment was requested, also
  4665. // check backing list and replenish it if necessary.
  4666. //
  4667. if(pAddrIdleList->CpuToReplenish < g_UlNumberOfProcessors)
  4668. {
  4669. ULONG Depth, MinDepth;
  4670. Depth =
  4671. PpslQueryBackingListDepth(
  4672. pAddrIdleList->IdleConnectionSListsHandle
  4673. );
  4674. MinDepth =
  4675. PpslQueryBackingListMinDepth(
  4676. pAddrIdleList->IdleConnectionSListsHandle
  4677. );
  4678. if(Depth < MinDepth)
  4679. {
  4680. SHOW_LIST_INFO(
  4681. "REPLENISH",
  4682. "BEFORE",
  4683. pAddrIdleList,
  4684. g_UlNumberOfProcessors
  4685. );
  4686. Status = UlpPopulateIdleList(
  4687. pAddrIdleList,
  4688. g_UlNumberOfProcessors
  4689. );
  4690. SHOW_LIST_INFO(
  4691. "REPLENISH",
  4692. "AFTER ",
  4693. pAddrIdleList,
  4694. g_UlNumberOfProcessors
  4695. );
  4696. }
  4697. }
  4698. } // !PopulateAll
  4699. return Status;
  4700. } // UlpReplenishAddrIdleList
  4701. /***************************************************************************++
  4702. Routine Description:
  4703. Deferred endpoint replenish routine.
  4704. Arguments:
  4705. pWorkItem - Supplies a pointer to the work item queued. This should
  4706. point to the WORK_ITEM structure embedded in a UL_ADDR_IDLE_LIST.
  4707. --***************************************************************************/
  4708. VOID
  4709. UlpReplenishAddrIdleListWorker(
  4710. IN PUL_WORK_ITEM pWorkItem
  4711. )
  4712. {
  4713. PUL_ADDR_IDLE_LIST pAddrIdleList;
  4714. PUL_ENDPOINT pEndpoint;
  4715. KIRQL OldIrql;
  4716. PUL_DEFERRED_REMOVE_ITEM pRemoveItem;
  4717. //
  4718. // Sanity check.
  4719. //
  4720. PAGED_CODE();
  4721. pAddrIdleList = CONTAINING_RECORD(
  4722. pWorkItem,
  4723. UL_ADDR_IDLE_LIST,
  4724. WorkItem
  4725. );
  4726. UlTrace(TDI_STATS, (
  4727. "UlpReplenishAddrIdleListWorker: Address Idle List %p\n",
  4728. pAddrIdleList
  4729. ));
  4730. ASSERT( IS_VALID_ADDR_IDLE_LIST( pAddrIdleList ) );
  4731. pEndpoint = pAddrIdleList->pOwningEndpoint;
  4732. ASSERT( IS_VALID_ENDPOINT( pEndpoint ) );
  4733. //
  4734. // Allocate a UL_DEFERRED_REMOVE_ITEM to be used later to drop the usage
  4735. // count we will be adding.
  4736. //
  4737. pRemoveItem = UL_ALLOCATE_STRUCT(
  4738. PagedPool,
  4739. UL_DEFERRED_REMOVE_ITEM,
  4740. UL_DEFERRED_REMOVE_ITEM_POOL_TAG
  4741. );
  4742. if (NULL == pRemoveItem)
  4743. {
  4744. //
  4745. // Can't replenish this time.
  4746. //
  4747. goto end;
  4748. }
  4749. //
  4750. // Initialize the structure.
  4751. //
  4752. pRemoveItem->Signature = UL_DEFERRED_REMOVE_ITEM_POOL_TAG;
  4753. pRemoveItem->UrlSecure = pEndpoint->Secure;
  4754. pRemoveItem->UrlPort = SWAP_SHORT(pEndpoint->LocalPort);
  4755. //
  4756. // Make sure pAddrIdleList is valid by testing and adding a temporary
  4757. // usage count to the endpoint we are replenishing.
  4758. //
  4759. UlAcquireSpinLock( &g_TdiSpinLock, &OldIrql );
  4760. if (pEndpoint->UsageCount == 0 || g_TdiWaitingForEndpointDrain)
  4761. {
  4762. UlReleaseSpinLock( &g_TdiSpinLock, OldIrql );
  4763. goto end;
  4764. }
  4765. pEndpoint->UsageCount++;
  4766. WRITE_REF_TRACE_LOG(
  4767. g_pEndpointUsageTraceLog,
  4768. REF_ACTION_REFERENCE_ENDPOINT_USAGE,
  4769. pEndpoint->UsageCount,
  4770. pEndpoint,
  4771. __FILE__,
  4772. __LINE__
  4773. );
  4774. UlReleaseSpinLock( &g_TdiSpinLock, OldIrql );
  4775. //
  4776. // Let UlpReplenishAddrIdleList() do the dirty work.
  4777. //
  4778. UlpReplenishAddrIdleList( pAddrIdleList, FALSE );
  4779. //
  4780. // Drop the temporary usage count through UlRemoveSite. This is
  4781. // arranged this way because UlRemoveSiteFromEndpointList has to
  4782. // happen on a special wait thread pool. Or it is possible to have
  4783. // another replenish worker scheduled for another address list on the
  4784. // same endpoint which takes an endpoint reference. This means
  4785. // UlRemoveSiteFromEndpointList will wait indefinitely if we call it
  4786. // directly from this routine.
  4787. //
  4788. UlRemoveSite( pRemoveItem );
  4789. //
  4790. // Set pRemoveItem to NULL so we won't double-free.
  4791. //
  4792. pRemoveItem = NULL;
  4793. end:
  4794. if (pRemoveItem)
  4795. {
  4796. UL_FREE_POOL_WITH_SIG( pRemoveItem, UL_DEFERRED_REMOVE_ITEM_POOL_TAG );
  4797. }
  4798. InterlockedExchange( &pAddrIdleList->WorkItemScheduled, FALSE );
  4799. //
  4800. // Remove the reference that UlpDequeueIdleConnection added for
  4801. // this call.
  4802. //
  4803. DEREFERENCE_ENDPOINT_SELF(
  4804. pAddrIdleList->pOwningEndpoint,
  4805. REF_ACTION_REPLENISH
  4806. );
  4807. } // UlpReplenishAddrIdleListWorker
  4808. /***************************************************************************++
  4809. Routine Description:
  4810. Queues a passive worker for the lowered irql.
  4811. Arguments:
  4812. Ignored
  4813. --***************************************************************************/
  4814. VOID
  4815. UlpIdleListTrimTimerDpcRoutine(
  4816. PKDPC Dpc,
  4817. PVOID DeferredContext,
  4818. PVOID SystemArgument1,
  4819. PVOID SystemArgument2
  4820. )
  4821. {
  4822. ULONG Index;
  4823. PLIST_ENTRY pLink;
  4824. PUL_ENDPOINT pEndpoint;
  4825. PUL_ADDR_IDLE_LIST pAddrIdleList;
  4826. //
  4827. // Parameters are ignored.
  4828. //
  4829. UNREFERENCED_PARAMETER(Dpc);
  4830. UNREFERENCED_PARAMETER(DeferredContext);
  4831. UNREFERENCED_PARAMETER(SystemArgument1);
  4832. UNREFERENCED_PARAMETER(SystemArgument2);
  4833. //
  4834. // Drop trimming the idle lists of endpoints if there is another
  4835. // one still running.
  4836. //
  4837. if (FALSE != InterlockedExchange(
  4838. &g_UlTrimTimer.WorkItemScheduled,
  4839. TRUE
  4840. ))
  4841. {
  4842. return;
  4843. }
  4844. //
  4845. // Since there are no trim workers running around, the zombie list
  4846. // must be empty.
  4847. //
  4848. ASSERT(IsListEmpty(&g_UlTrimTimer.ZombieConnectionListHead));
  4849. UlAcquireSpinLockAtDpcLevel(&g_UlTrimTimer.SpinLock);
  4850. if (g_UlTrimTimer.Initialized == TRUE)
  4851. {
  4852. UlAcquireSpinLockAtDpcLevel(&g_TdiSpinLock);
  4853. for (pLink = g_TdiEndpointListHead.Flink;
  4854. pLink != &g_TdiEndpointListHead;
  4855. pLink = pLink->Flink
  4856. )
  4857. {
  4858. pEndpoint = CONTAINING_RECORD(
  4859. pLink,
  4860. UL_ENDPOINT,
  4861. GlobalEndpointListEntry
  4862. );
  4863. ASSERT(IS_VALID_ENDPOINT(pEndpoint));
  4864. for (Index = 0; Index < pEndpoint->AddrIdleListCount; Index++)
  4865. {
  4866. pAddrIdleList = &pEndpoint->aAddrIdleLists[Index];
  4867. //
  4868. // Trim the idle list if there was no replenish running at
  4869. // this time. We can certainly drop the trim if a replenish
  4870. // is running on the adr-list.
  4871. //
  4872. if (FALSE == InterlockedExchange(
  4873. &pAddrIdleList->WorkItemScheduled,
  4874. TRUE
  4875. ))
  4876. {
  4877. UlpTrimAddrIdleList(
  4878. pAddrIdleList,
  4879. &g_UlTrimTimer.ZombieConnectionListHead
  4880. );
  4881. }
  4882. }
  4883. }
  4884. UlReleaseSpinLockFromDpcLevel(&g_TdiSpinLock);
  4885. //
  4886. // Destroy the zombie list at high priority to release the memory asap.
  4887. // We cannot cleanup this list here, since the UlpDestroyConnection
  4888. // must work at passive level because of UxCloseTdiObject call. That's
  4889. // why we are having the zombie list here to pass it to the passive
  4890. // worker.
  4891. //
  4892. if (!IsListEmpty(&g_UlTrimTimer.ZombieConnectionListHead))
  4893. {
  4894. UL_QUEUE_HIGH_PRIORITY_ITEM(
  4895. &g_UlTrimTimer.WorkItem,
  4896. &UlpIdleListTrimTimerWorker
  4897. );
  4898. }
  4899. else
  4900. {
  4901. //
  4902. // Worker won't get called. Reset the workitem scheduled field.
  4903. //
  4904. InterlockedExchange(&g_UlTrimTimer.WorkItemScheduled, FALSE);
  4905. }
  4906. }
  4907. UlReleaseSpinLockFromDpcLevel(&g_UlTrimTimer.SpinLock);
  4908. }
  4909. /***************************************************************************++
  4910. Routine Description:
  4911. Destroys the zombie idle connection list at passive level.
  4912. Arguments:
  4913. Work Item.
  4914. --***************************************************************************/
  4915. VOID
  4916. UlpIdleListTrimTimerWorker(
  4917. IN PUL_WORK_ITEM pWorkItem
  4918. )
  4919. {
  4920. PUL_TRIM_TIMER pTimer;
  4921. PLIST_ENTRY pListEntry;
  4922. PUL_CONNECTION pConnection;
  4923. PAGED_CODE();
  4924. pTimer = CONTAINING_RECORD(
  4925. pWorkItem,
  4926. UL_TRIM_TIMER,
  4927. WorkItem
  4928. );
  4929. UlTrace(TDI_STATS,("UlpIdleListTrimTimerWorker: destroying [%d] connections ...\n",
  4930. UlpZombieListDepth(&g_UlTrimTimer.ZombieConnectionListHead)
  4931. ));
  4932. //
  4933. // We shouldn't be called if the list was empty.
  4934. //
  4935. ASSERT(!IsListEmpty(&g_UlTrimTimer.ZombieConnectionListHead));
  4936. //
  4937. // Drain the list, and close all of the idle connections.
  4938. //
  4939. while (!IsListEmpty(&g_UlTrimTimer.ZombieConnectionListHead))
  4940. {
  4941. //
  4942. // Remove the connection from the zombie connection list.
  4943. //
  4944. pListEntry = RemoveHeadList(
  4945. &g_UlTrimTimer.ZombieConnectionListHead
  4946. );
  4947. //
  4948. // Validate the connection.
  4949. //
  4950. pConnection = CONTAINING_RECORD(
  4951. pListEntry,
  4952. UL_CONNECTION,
  4953. GlobalConnectionListEntry
  4954. );
  4955. ASSERT(IS_VALID_CONNECTION(pConnection));
  4956. ASSERT(pConnection->IdleSListEntry.Next == NULL);
  4957. ASSERT(pConnection->ConnListState == NoConnList);
  4958. UlpDestroyConnection(pConnection);
  4959. }
  4960. //
  4961. // Now we are done we can let other trim timers to work.
  4962. //
  4963. InterlockedExchange(&g_UlTrimTimer.WorkItemScheduled, FALSE);
  4964. TRACE_IDLE_CONNECTIONS();
  4965. }
  4966. /***************************************************************************++
  4967. Routine Description:
  4968. Simple function to move an idle connection to the zombie list
  4969. Arguments:
  4970. pSListEntry - the idle connection to be moved.
  4971. pZombieList - the trimmed connection to be moved to this zombie list.
  4972. --***************************************************************************/
  4973. __inline
  4974. VOID
  4975. UlpZombifyIdleConnection(
  4976. PSLIST_ENTRY pSListEntry,
  4977. PLIST_ENTRY pZombieList
  4978. )
  4979. {
  4980. PUL_CONNECTION pConnection;
  4981. ASSERT(pSListEntry);
  4982. ASSERT(pZombieList);
  4983. ASSERT(UlDbgSpinLockOwned(&g_TdiSpinLock));
  4984. pConnection = CONTAINING_RECORD(
  4985. pSListEntry,
  4986. UL_CONNECTION,
  4987. IdleSListEntry
  4988. );
  4989. ASSERT(IS_VALID_CONNECTION(pConnection));
  4990. pConnection->IdleSListEntry.Next = NULL;
  4991. pConnection->ConnListState = NoConnList;
  4992. //
  4993. // Move it from global connection list to the zombie list.
  4994. //
  4995. RemoveEntryList(
  4996. &pConnection->GlobalConnectionListEntry
  4997. );
  4998. InsertTailList(
  4999. pZombieList,
  5000. &pConnection->GlobalConnectionListEntry
  5001. );
  5002. //
  5003. // Once the zombie list is ready, a passive worker will call
  5004. // UlpDestroyConnection(pConnection); for the whole zombie list.
  5005. //
  5006. }
  5007. /***************************************************************************++
  5008. Routine Description:
  5009. This function will decide on cleaning up the idle connections on the adr-
  5010. list.
  5011. Arguments:
  5012. pAddrIdleList - the list to be trimmed
  5013. pZombieList - the trimmed connection to be moved to this zombie list.
  5014. --***************************************************************************/
  5015. VOID
  5016. UlpTrimAddrIdleList(
  5017. IN OUT PUL_ADDR_IDLE_LIST pAddrIdleList,
  5018. OUT PLIST_ENTRY pZombieList
  5019. )
  5020. {
  5021. PUL_ENDPOINT pEndpoint;
  5022. PSLIST_ENTRY pSListEntry;
  5023. LONG i;
  5024. ULONG Proc;
  5025. //
  5026. // We are messing with the GlobalConnectionListEntry of the connection.
  5027. // You better hold the tdi spinlock while calling this.
  5028. //
  5029. ASSERT(UlDbgSpinLockOwned(&g_TdiSpinLock));
  5030. ASSERT(IS_VALID_ADDR_IDLE_LIST(pAddrIdleList));
  5031. pEndpoint = pAddrIdleList->pOwningEndpoint;
  5032. ASSERT(IS_VALID_ENDPOINT(pEndpoint));
  5033. //
  5034. // Visit each per-proc list as well as the backing list to update
  5035. // connection serv rate. Also if we have a slowing delta, trim the
  5036. // list.
  5037. //
  5038. for (Proc = 0; Proc <= g_UlNumberOfProcessors; Proc++)
  5039. {
  5040. USHORT LowMark;
  5041. LONG BlockSize;
  5042. LONG Delta, PrevServed;
  5043. PrevServed = PpslQueryPrevServed(
  5044. pAddrIdleList->IdleConnectionSListsHandle,
  5045. Proc
  5046. );
  5047. Delta = PpslAdjustActivityStats(
  5048. pAddrIdleList->IdleConnectionSListsHandle,
  5049. Proc
  5050. );
  5051. ASSERT((Delta > 0) || (-Delta <= PrevServed));
  5052. //
  5053. // If the connection serving rate has dropped more than 10% since
  5054. // the last time we woke up. Trim upto half of the distance to low
  5055. // water mark.
  5056. //
  5057. if (Delta <= 0 && -Delta >= PrevServed/10)
  5058. {
  5059. LowMark = (Proc == g_UlNumberOfProcessors) ?
  5060. PpslQueryBackingListMinDepth(
  5061. pAddrIdleList->IdleConnectionSListsHandle
  5062. ) :
  5063. 0;
  5064. BlockSize = PpslQueryDepth(
  5065. pAddrIdleList->IdleConnectionSListsHandle,
  5066. Proc
  5067. )
  5068. -
  5069. LowMark;
  5070. //
  5071. // Some funky logic to decide on trim size.
  5072. //
  5073. BlockSize = MAX(0, BlockSize);
  5074. if(PrevServed == 0)
  5075. {
  5076. ASSERT(Delta == 0);
  5077. BlockSize /= 2;
  5078. }
  5079. else
  5080. {
  5081. LONG Temp = (LONG)(((LONGLONG)BlockSize)*(-Delta)/PrevServed);
  5082. ASSERT(Temp <= BlockSize);
  5083. BlockSize = MIN(Temp, BlockSize/2);
  5084. }
  5085. for (i = 0; i < BlockSize; i++)
  5086. {
  5087. pSListEntry =
  5088. PpslAllocateToTrim(
  5089. pAddrIdleList->IdleConnectionSListsHandle,
  5090. Proc
  5091. );
  5092. if (pSListEntry != NULL)
  5093. {
  5094. UlpZombifyIdleConnection(pSListEntry,pZombieList);
  5095. }
  5096. else
  5097. {
  5098. break;
  5099. }
  5100. }
  5101. }
  5102. }
  5103. //
  5104. // Let the replenish to do its work.
  5105. //
  5106. InterlockedExchange(&pAddrIdleList->WorkItemScheduled, FALSE);
  5107. }
  5108. /***************************************************************************++
  5109. Routine Description:
  5110. Creates a new UL_CONNECTION object and opens the corresponding
  5111. TDI connection object.
  5112. Note: The connection returned from this function will contain
  5113. an unreferenced pointer to the owning endpoint. Only active
  5114. connections have references to the endpoint because the refcount
  5115. is used to decide when to clean up the list of idle connections.
  5116. Arguments:
  5117. pAddrIdleList - Supplies the Endpoint's idle connection list for
  5118. a particular TDI address.
  5119. ppConnection - Receives the pointer to a new UL_CONNECTION if
  5120. successful.
  5121. Return Value:
  5122. NTSTATUS - Completion status. *ppConnection is undefined if the
  5123. return value is not STATUS_SUCCESS.
  5124. --***************************************************************************/
  5125. NTSTATUS
  5126. UlpCreateConnection(
  5127. IN PUL_ADDR_IDLE_LIST pAddrIdleList,
  5128. OUT PUL_CONNECTION *ppConnection
  5129. )
  5130. {
  5131. NTSTATUS status;
  5132. PUL_CONNECTION pConnection;
  5133. PUX_TDI_OBJECT pTdiObject;
  5134. KIRQL OldIrql;
  5135. ASSERT( IS_VALID_ADDR_IDLE_LIST( pAddrIdleList ) );
  5136. ASSERT(NULL != ppConnection);
  5137. //
  5138. // Allocate the pool for the connection structure.
  5139. //
  5140. pConnection = UL_ALLOCATE_STRUCT(
  5141. NonPagedPool,
  5142. UL_CONNECTION,
  5143. UL_CONNECTION_POOL_TAG
  5144. );
  5145. if (pConnection == NULL)
  5146. {
  5147. status = STATUS_INSUFFICIENT_RESOURCES;
  5148. goto fatal;
  5149. }
  5150. WRITE_REF_TRACE_LOG(
  5151. g_pTdiTraceLog,
  5152. REF_ACTION_ALLOC_UL_CONNECTION,
  5153. 0,
  5154. pConnection,
  5155. __FILE__,
  5156. __LINE__
  5157. );
  5158. //
  5159. // One time field initialization.
  5160. //
  5161. pConnection->Signature = UL_CONNECTION_SIGNATURE;
  5162. pConnection->pConnectionContext = NULL;
  5163. pConnection->pOwningEndpoint = NULL;
  5164. pConnection->FilterInfo.pFilterChannel = NULL;
  5165. HTTP_SET_NULL_ID( &pConnection->FilterInfo.ConnectionId );
  5166. pConnection->pIrp = NULL;
  5167. UlInitializeWorkItem(&pConnection->WorkItem);
  5168. pConnection->IdleSListEntry.Next = NULL;
  5169. pConnection->ConnListState = NoConnList;
  5170. ASSERT(UlpConnectionIsOnValidList(pConnection));
  5171. //
  5172. // Init the Connection State spin lock
  5173. //
  5174. UlInitializeSpinLock(
  5175. &pConnection->ConnectionStateSpinLock,
  5176. "ConnectionState"
  5177. );
  5178. UlAcquireSpinLock( &g_TdiSpinLock, &OldIrql );
  5179. InsertTailList(
  5180. &g_TdiConnectionListHead,
  5181. &pConnection->GlobalConnectionListEntry
  5182. );
  5183. g_TdiConnectionCount++;
  5184. UlReleaseSpinLock( &g_TdiSpinLock, OldIrql );
  5185. //
  5186. // Initialize a private trace log.
  5187. //
  5188. CREATE_REF_TRACE_LOG( pConnection->pTraceLog,
  5189. 96 - REF_TRACE_OVERHEAD, 0, TRACELOG_LOW_PRIORITY,
  5190. UL_CONNECTION_REF_TRACE_LOG_POOL_TAG );
  5191. CREATE_REF_TRACE_LOG( pConnection->pHttpTraceLog,
  5192. 32 - REF_TRACE_OVERHEAD, 0, TRACELOG_LOW_PRIORITY,
  5193. UL_HTTP_CONNECTION_REF_TRACE_LOG_POOL_TAG );
  5194. //
  5195. // Open the TDI connection object for this connection.
  5196. //
  5197. status = UxOpenTdiConnectionObject(
  5198. pAddrIdleList->LocalAddress.Ta.Address[0].AddressType,
  5199. (CONNECTION_CONTEXT)pConnection,
  5200. &pConnection->ConnectionObject
  5201. );
  5202. if (!NT_SUCCESS(status))
  5203. {
  5204. goto fatal;
  5205. }
  5206. ASSERT( IS_VALID_TDI_OBJECT( &pConnection->ConnectionObject ) );
  5207. //
  5208. // Associate the connection with the endpoint.
  5209. //
  5210. status = UlpAssociateConnection( pConnection, pAddrIdleList );
  5211. if (!NT_SUCCESS(status))
  5212. {
  5213. goto fatal;
  5214. }
  5215. pTdiObject = &pConnection->ConnectionObject;
  5216. pConnection->pIrp = UlAllocateIrp(
  5217. pTdiObject->pDeviceObject->StackSize, // StackSize
  5218. FALSE // ChargeQuota
  5219. );
  5220. if (pConnection->pIrp == NULL)
  5221. {
  5222. status = STATUS_INSUFFICIENT_RESOURCES;
  5223. goto fatal;
  5224. }
  5225. pConnection->pIrp->RequestorMode = KernelMode;
  5226. //
  5227. // Success!
  5228. //
  5229. UlTraceVerbose(TDI, (
  5230. "UlpCreateConnection: created %p\n",
  5231. pConnection
  5232. ));
  5233. *ppConnection = pConnection;
  5234. return STATUS_SUCCESS;
  5235. fatal:
  5236. UlTrace(TDI, (
  5237. "UlpCreateConnection: failure 0x%x\n",
  5238. status
  5239. ));
  5240. ASSERT( !NT_SUCCESS(status) );
  5241. if (pConnection != NULL)
  5242. {
  5243. UlpDestroyConnection( pConnection );
  5244. }
  5245. *ppConnection = NULL;
  5246. return status;
  5247. } // UlpCreateConnection
  5248. /***************************************************************************++
  5249. Routine Description:
  5250. Initializes a UL_CONNECTION for use.
  5251. Note: inactive connections do not have a reference to the endpoint,
  5252. so the caller to this function *must* have a reference.
  5253. Arguments:
  5254. pConnection - Pointer to the UL_CONNECTION to initialize.
  5255. SecureConnection - TRUE if this connection is for a secure endpoint.
  5256. --***************************************************************************/
  5257. NTSTATUS
  5258. UlpInitializeConnection(
  5259. IN PUL_CONNECTION pConnection
  5260. )
  5261. {
  5262. NTSTATUS status;
  5263. BOOLEAN SecureConnection;
  5264. PUL_FILTER_CHANNEL pChannel;
  5265. //
  5266. // Sanity check.
  5267. //
  5268. ASSERT(pConnection);
  5269. ASSERT(IS_VALID_ENDPOINT(pConnection->pOwningEndpoint));
  5270. ASSERT(IS_VALID_ADDR_IDLE_LIST(pConnection->pOwningAddrIdleList));
  5271. //
  5272. // Initialize locals.
  5273. //
  5274. status = STATUS_SUCCESS;
  5275. SecureConnection = pConnection->pOwningEndpoint->Secure;
  5276. //
  5277. // Initialize the easy parts.
  5278. //
  5279. pConnection->ReferenceCount = 1;
  5280. pConnection->ConnectionFlags.Value = 0;
  5281. pConnection->ConnectionState = UlConnectStateConnectIdle;
  5282. pConnection->IdleSListEntry.Next = NULL;
  5283. pConnection->ConnListState = NoConnList;
  5284. ASSERT(UlpConnectionIsOnValidList(pConnection));
  5285. pConnection->AddressType =
  5286. pConnection->pOwningAddrIdleList->LocalAddress.Ta.Address[0].AddressType;
  5287. pConnection->AddressLength =
  5288. pConnection->pOwningAddrIdleList->LocalAddress.Ta.Address[0].AddressLength;
  5289. //
  5290. // Setup the Tdi Connection Information space to be filled with
  5291. // Local Address Information at the completion of the Accept Irp.
  5292. //
  5293. pConnection->TdiConnectionInformation.UserDataLength = 0;
  5294. pConnection->TdiConnectionInformation.UserData = NULL;
  5295. pConnection->TdiConnectionInformation.OptionsLength = 0;
  5296. pConnection->TdiConnectionInformation.Options = NULL;
  5297. pConnection->TdiConnectionInformation.RemoteAddressLength =
  5298. pConnection->pOwningAddrIdleList->LocalAddressLength;
  5299. pConnection->TdiConnectionInformation.RemoteAddress =
  5300. &(pConnection->Ta);
  5301. //
  5302. // Init the Inteface/Link IDs.
  5303. //
  5304. pConnection->bRoutingLookupDone = FALSE;
  5305. //
  5306. // Init the IrpContext.
  5307. //
  5308. pConnection->IrpContext.Signature = UL_IRP_CONTEXT_SIGNATURE;
  5309. //
  5310. // Init the HTTP_CONNECTION.
  5311. //
  5312. pConnection->HttpConnection.RefCount = 0;
  5313. pChannel = UxRetrieveServerFilterChannel(SecureConnection);
  5314. //
  5315. // pChannel will be non NULL if HTTPFilter is running and the user has
  5316. // asked for a SecureConnection or if they have enabled RAW ISAPI filtering.
  5317. //
  5318. //
  5319. // If pChannel is NULL and it's a secure connection, we should fail it.
  5320. // SSL will not work if HTTPFilter is not running.
  5321. //
  5322. if(SecureConnection && pChannel == NULL)
  5323. {
  5324. return STATUS_NO_TRACKING_SERVICE;
  5325. }
  5326. if (pChannel)
  5327. {
  5328. status = UxInitializeFilterConnection(
  5329. &pConnection->FilterInfo,
  5330. pChannel,
  5331. SecureConnection,
  5332. &UlReferenceConnection,
  5333. &UlDereferenceConnection,
  5334. &UlpCloseRawConnection,
  5335. &UlpSendRawData,
  5336. &UlpReceiveRawData,
  5337. &UlpDummyReceiveHandler,
  5338. &UlpComputeHttpRawConnectionLength,
  5339. &UlpGenerateHttpRawConnectionInfo,
  5340. NULL,
  5341. &UlpDoDisconnectNotification,
  5342. pConnection->pOwningEndpoint,
  5343. pConnection
  5344. );
  5345. }
  5346. else
  5347. {
  5348. pConnection->FilterInfo.pFilterChannel = NULL;
  5349. pConnection->FilterInfo.SecureConnection = FALSE;
  5350. }
  5351. return status;
  5352. } // UlpInitializeConnection
  5353. /***************************************************************************++
  5354. Routine Description:
  5355. Initiates a graceful disconnect on the specified connection.
  5356. Uses the UL_CONNECTION's pre-alloc'd Disconnect Irp, which may be used
  5357. for only one driver call at a time. Caller guarantees exclusive control
  5358. before calling. See UlpCloseRawConnection.
  5359. Arguments:
  5360. pConnection - Supplies the connection to disconnect.
  5361. pCompletionRoutine - Supplies a pointer to a completion routine to
  5362. invoke after the connection is disconnected.
  5363. pCompletionContext - Supplies an uninterpreted context value for the
  5364. completion routine.
  5365. CleaningUp - TRUE if we're cleaning up the connection.
  5366. Return Value:
  5367. NTSTATUS - Completion status.
  5368. --***************************************************************************/
  5369. NTSTATUS
  5370. UlpBeginDisconnect(
  5371. IN PIRP pIrp,
  5372. IN PUL_IRP_CONTEXT pIrpContext,
  5373. IN PUL_CONNECTION pConnection,
  5374. IN PUL_COMPLETION_ROUTINE pCompletionRoutine,
  5375. IN PVOID pCompletionContext
  5376. )
  5377. {
  5378. //
  5379. // Sanity check.
  5380. //
  5381. UlTrace(TDI, (
  5382. "UlpBeginDisconnect: connection %p\n",
  5383. pConnection
  5384. ));
  5385. ASSERT( pIrp );
  5386. ASSERT( IS_VALID_IRP_CONTEXT( pIrpContext ) );
  5387. ASSERT( IS_VALID_CONNECTION( pConnection ) );
  5388. ASSERT( KeGetCurrentIrql() <= DISPATCH_LEVEL );
  5389. ASSERT( pConnection->ConnectionFlags.DisconnectPending );
  5390. //
  5391. // Initialize the IRP context for this request. Set pOwnIrp to NULL
  5392. // and OwnIrpContext to FALSE so they will be freed in the completion
  5393. // routine UlpRestartDisconnect().
  5394. //
  5395. pIrpContext->pConnectionContext = (PVOID)pConnection;
  5396. pIrpContext->pCompletionRoutine = pCompletionRoutine;
  5397. pIrpContext->pCompletionContext = pCompletionContext;
  5398. pIrpContext->pOwnIrp = NULL;
  5399. pIrpContext->OwnIrpContext = FALSE;
  5400. //
  5401. // Initialize the disconnect IRP.
  5402. //
  5403. UxInitializeDisconnectIrp(
  5404. pIrp,
  5405. &pConnection->ConnectionObject,
  5406. TDI_DISCONNECT_RELEASE,
  5407. &UlpRestartDisconnect,
  5408. pIrpContext
  5409. );
  5410. //
  5411. // Add a reference to the connection
  5412. //
  5413. REFERENCE_CONNECTION( pConnection );
  5414. //
  5415. // Then call the driver to initiate the disconnect.
  5416. //
  5417. UlCallDriver( pConnection->ConnectionObject.pDeviceObject, pIrp );
  5418. return STATUS_PENDING;
  5419. } // UlpBeginDisconnect
  5420. /***************************************************************************++
  5421. Routine Description:
  5422. Completion handler for graceful disconnect IRPs.
  5423. Arguments:
  5424. pDeviceObject - Supplies the device object for the IRP being
  5425. completed.
  5426. pIrp - Supplies the IRP being completed.
  5427. pContext - Supplies the context associated with this request.
  5428. This is actually a PUL_IRP_CONTEXT.
  5429. Return Value:
  5430. NTSTATUS - STATUS_SUCCESS if IO should continue processing this
  5431. IRP, STATUS_MORE_PROCESSING_REQUIRED if IO should stop processing
  5432. this IRP.
  5433. --***************************************************************************/
  5434. NTSTATUS
  5435. UlpRestartDisconnect(
  5436. IN PDEVICE_OBJECT pDeviceObject,
  5437. IN PIRP pIrp,
  5438. IN PVOID pContext
  5439. )
  5440. {
  5441. IO_STATUS_BLOCK IoStatus;
  5442. PUL_IRP_CONTEXT pIrpContext;
  5443. PUL_CONNECTION pConnection;
  5444. UL_CONNECTION_FLAGS Flags;
  5445. PUL_ENDPOINT pEndpoint;
  5446. KIRQL OldIrql;
  5447. UNREFERENCED_PARAMETER(pDeviceObject);
  5448. //
  5449. // Sanity check.
  5450. //
  5451. pIrpContext = (PUL_IRP_CONTEXT)pContext;
  5452. ASSERT( IS_VALID_IRP_CONTEXT( pIrpContext ) );
  5453. IoStatus = pIrp->IoStatus;
  5454. pConnection = pIrpContext->pConnectionContext;
  5455. ASSERT( IS_VALID_CONNECTION( pConnection ) );
  5456. ASSERT( pConnection->ConnectionFlags.DisconnectPending );
  5457. UlTrace(TDI, (
  5458. "UlpRestartDisconnect: connection %p, IoStatus %d\n",
  5459. pConnection,
  5460. IoStatus.Status
  5461. ));
  5462. pEndpoint = pConnection->pOwningEndpoint;
  5463. Flags.Value = *((volatile LONG *)&pConnection->ConnectionFlags.Value);
  5464. if (!Flags.DisconnectIndicated && !Flags.AbortIndicated)
  5465. {
  5466. //
  5467. // Only try to drain if it is not already aborted or disconnect
  5468. // indication is not already happened.
  5469. //
  5470. if (pConnection->FilterInfo.pFilterChannel)
  5471. {
  5472. //
  5473. // Put a reference on filter connection until the drain
  5474. // is done.
  5475. //
  5476. REFERENCE_FILTER_CONNECTION(&pConnection->FilterInfo);
  5477. UL_QUEUE_WORK_ITEM(
  5478. &pConnection->FilterInfo.WorkItem,
  5479. &UlFilterDrainIndicatedData
  5480. );
  5481. }
  5482. else
  5483. {
  5484. (pEndpoint->pConnectionDisconnectCompleteHandler)(
  5485. pEndpoint->pListeningContext,
  5486. pConnection->pConnectionContext
  5487. );
  5488. }
  5489. }
  5490. //
  5491. // Set the flag indicating that a disconnect has completed.
  5492. //
  5493. ASSERT( KeGetCurrentIrql() <= DISPATCH_LEVEL );
  5494. UlAcquireSpinLock(
  5495. &pConnection->ConnectionStateSpinLock,
  5496. &OldIrql
  5497. );
  5498. ASSERT( pConnection->ConnectionFlags.CleanupBegun );
  5499. //
  5500. // Mark Disconnect completed.
  5501. //
  5502. UlpSetConnectionFlag( pConnection, MakeDisconnectCompleteFlag() );
  5503. if (pConnection->ConnectionFlags.AbortIndicated ||
  5504. pConnection->ConnectionFlags.DisconnectIndicated ||
  5505. pConnection->ConnectionFlags.AbortDisconnect)
  5506. {
  5507. //
  5508. // Move directly to state UlConnectStateConnectCleanup.
  5509. //
  5510. pConnection->ConnectionState = UlConnectStateConnectCleanup;
  5511. }
  5512. else
  5513. {
  5514. //
  5515. // Change state to UlConnectStateDisconnectComplete.
  5516. //
  5517. pConnection->ConnectionState = UlConnectStateDisconnectComplete;
  5518. }
  5519. if (!NT_SUCCESS(IoStatus.Status) &&
  5520. IoStatus.Status != STATUS_CONNECTION_RESET)
  5521. {
  5522. UlpSetConnectionFlag( pConnection, MakeTdiConnectionInvalidFlag() );
  5523. }
  5524. UlReleaseSpinLock(
  5525. &pConnection->ConnectionStateSpinLock,
  5526. OldIrql
  5527. );
  5528. //
  5529. // Check to see if we're ready to clean up
  5530. //
  5531. UlpRemoveFinalReference( pConnection );
  5532. //
  5533. // Invoke the user's completion routine
  5534. //
  5535. (VOID) UlInvokeCompletionRoutine(
  5536. IoStatus.Status,
  5537. IoStatus.Information,
  5538. pIrpContext->pCompletionRoutine,
  5539. pIrpContext->pCompletionContext
  5540. );
  5541. //
  5542. // Free the IRP and IRP_CONTEXT if pOwnIrp is set to NULL or OwnIrpContext
  5543. // is set to FALSE, which means they were not pre-built as part of the
  5544. // connection object.
  5545. //
  5546. if (!pIrpContext->pOwnIrp)
  5547. {
  5548. UlFreeIrp( pIrp );
  5549. }
  5550. if (!pIrpContext->OwnIrpContext)
  5551. {
  5552. UlPplFreeIrpContext( pIrpContext );
  5553. }
  5554. DEREFERENCE_CONNECTION( pConnection );
  5555. //
  5556. // There is no need to free the IRP context, since it's part
  5557. // of the UL_CONNECTION object.
  5558. //
  5559. return STATUS_MORE_PROCESSING_REQUIRED;
  5560. } // UlpRestartDisconnect
  5561. /***************************************************************************++
  5562. Routine Description:
  5563. Initiates an abortive disconnect on the specified connection.
  5564. Uses the UL_CONNECTION's pre-alloc'd Disconnect Irp, which may be used
  5565. for only one driver call at a time. Caller guarantees exclusive control
  5566. before calling. See UlpCloseRawConnection.
  5567. Arguments:
  5568. pConnection - Supplies the connection to disconnect.
  5569. pCompletionRoutine - Supplies a pointer to a completion routine to
  5570. invoke after the connection is disconnected.
  5571. pCompletionContext - Supplies an uninterpreted context value for the
  5572. completion routine.
  5573. Return Value:
  5574. NTSTATUS - Completion status.
  5575. --***************************************************************************/
  5576. NTSTATUS
  5577. UlpBeginAbort(
  5578. IN PUL_CONNECTION pConnection,
  5579. IN PUL_COMPLETION_ROUTINE pCompletionRoutine,
  5580. IN PVOID pCompletionContext
  5581. )
  5582. {
  5583. PIRP pIrp;
  5584. PUL_IRP_CONTEXT pIrpContext;
  5585. //
  5586. // Sanity check.
  5587. //
  5588. ASSERT( IS_VALID_CONNECTION( pConnection ) );
  5589. UlTrace(TDI, (
  5590. "UlpBeginAbort: connection %p\n",
  5591. pConnection
  5592. ));
  5593. ASSERT( KeGetCurrentIrql() <= DISPATCH_LEVEL );
  5594. ASSERT( pConnection->ConnectionFlags.AbortPending );
  5595. //
  5596. // Use pre-alloc'd IRP context for this request.
  5597. //
  5598. pIrpContext = &pConnection->IrpContext;
  5599. ASSERT( IS_VALID_IRP_CONTEXT( pIrpContext ) );
  5600. pIrpContext->pConnectionContext = (PVOID)pConnection;
  5601. pIrpContext->pCompletionRoutine = pCompletionRoutine;
  5602. pIrpContext->pCompletionContext = pCompletionContext;
  5603. //
  5604. // Initialize pre-alloc'd IRP for the disconnect.
  5605. //
  5606. pIrp = pConnection->pIrp;
  5607. UxInitializeDisconnectIrp(
  5608. pIrp,
  5609. &pConnection->ConnectionObject,
  5610. TDI_DISCONNECT_ABORT,
  5611. &UlpRestartAbort,
  5612. pIrpContext
  5613. );
  5614. //
  5615. // Add a reference to the connection,
  5616. //
  5617. REFERENCE_CONNECTION( pConnection );
  5618. //
  5619. // Then call the driver to initiate the disconnect.
  5620. //
  5621. UlCallDriver( pConnection->ConnectionObject.pDeviceObject, pIrp );
  5622. return STATUS_PENDING;
  5623. } // UlpBeginAbort
  5624. /***************************************************************************++
  5625. Routine Description:
  5626. Completion handler for abortive disconnect IRPs.
  5627. Arguments:
  5628. pDeviceObject - Supplies the device object for the IRP being
  5629. completed.
  5630. pIrp - Supplies the IRP being completed.
  5631. pContext - Supplies the context associated with this request.
  5632. This is actually a PUL_IRP_CONTEXT.
  5633. Return Value:
  5634. NTSTATUS - STATUS_SUCCESS if IO should continue processing this
  5635. IRP, STATUS_MORE_PROCESSING_REQUIRED if IO should stop processing
  5636. this IRP.
  5637. --***************************************************************************/
  5638. NTSTATUS
  5639. UlpRestartAbort(
  5640. IN PDEVICE_OBJECT pDeviceObject,
  5641. IN PIRP pIrp,
  5642. IN PVOID pContext
  5643. )
  5644. {
  5645. PUL_IRP_CONTEXT pIrpContext;
  5646. PUL_CONNECTION pConnection;
  5647. KIRQL OldIrql;
  5648. UNREFERENCED_PARAMETER(pDeviceObject);
  5649. //
  5650. // Sanity check.
  5651. //
  5652. pIrpContext = (PUL_IRP_CONTEXT)pContext;
  5653. ASSERT( IS_VALID_IRP_CONTEXT( pIrpContext ) );
  5654. pConnection = (PUL_CONNECTION)pIrpContext->pConnectionContext;
  5655. ASSERT( IS_VALID_CONNECTION( pConnection ) );
  5656. ASSERT( pConnection->ConnectionFlags.AbortPending );
  5657. UlTrace(TDI, (
  5658. "UlpRestartAbort: connection %p\n",
  5659. pConnection
  5660. ));
  5661. //
  5662. // Set the flag indicating that an abort has completed. If we're in the
  5663. // midst of cleaning up this endpoint and we've already received a
  5664. // disconnect (graceful or abortive) from the client, then remove the
  5665. // final reference to the connection.
  5666. //
  5667. ASSERT( KeGetCurrentIrql() <= DISPATCH_LEVEL );
  5668. UlAcquireSpinLock(
  5669. &pConnection->ConnectionStateSpinLock,
  5670. &OldIrql
  5671. );
  5672. ASSERT( pConnection->ConnectionFlags.CleanupBegun );
  5673. pConnection->ConnectionState = UlConnectStateConnectCleanup;
  5674. UlpSetConnectionFlag( pConnection, MakeAbortCompleteFlag() );
  5675. if (!NT_SUCCESS(pIrp->IoStatus.Status))
  5676. {
  5677. UlpSetConnectionFlag( pConnection, MakeTdiConnectionInvalidFlag() );
  5678. }
  5679. UlReleaseSpinLock(
  5680. &pConnection->ConnectionStateSpinLock,
  5681. OldIrql
  5682. );
  5683. UlpRemoveFinalReference( pConnection );
  5684. //
  5685. // Invoke the user's completion routine, then free the IRP context.
  5686. //
  5687. (VOID) UlInvokeCompletionRoutine(
  5688. pIrp->IoStatus.Status,
  5689. pIrp->IoStatus.Information,
  5690. pIrpContext->pCompletionRoutine,
  5691. pIrpContext->pCompletionContext
  5692. );
  5693. DEREFERENCE_CONNECTION( pConnection );
  5694. return STATUS_MORE_PROCESSING_REQUIRED;
  5695. } // UlpRestartAbort
  5696. /***************************************************************************++
  5697. Routine Description:
  5698. Removes the final reference from a connection if the conditions are
  5699. right. See comments within this function for details on the conditions
  5700. required.
  5701. Arguments:
  5702. pConnection - Supplies the connection to dereference.
  5703. Flags - Supplies the connection flags from the most recent update.
  5704. Note:
  5705. It is very important that the caller of this routine has established
  5706. its own reference to the connection. If necessary, this reference
  5707. can be immediately removed after calling this routine, but not before.
  5708. --***************************************************************************/
  5709. VOID
  5710. UlpRemoveFinalReference(
  5711. IN PUL_CONNECTION pConnection
  5712. )
  5713. {
  5714. KIRQL OldIrql;
  5715. //
  5716. // Sanity check.
  5717. //
  5718. ASSERT( IS_VALID_CONNECTION( pConnection ) );
  5719. UlAcquireSpinLock(
  5720. &pConnection->ConnectionStateSpinLock,
  5721. &OldIrql
  5722. );
  5723. //
  5724. // We can only remove the final reference if:
  5725. //
  5726. // We've begun connection cleanup.
  5727. //
  5728. // We've completed an accept.
  5729. //
  5730. // We've received a disconnect or abort indication or we've
  5731. // issued & completed an abort.
  5732. //
  5733. // We don't have a disconnect or abort pending.
  5734. //
  5735. // We haven't already removed it.
  5736. //
  5737. if ( UlConnectStateConnectCleanup == pConnection->ConnectionState )
  5738. {
  5739. if (!pConnection->ConnectionFlags.FinalReferenceRemoved)
  5740. {
  5741. UlTrace(TDI, (
  5742. "UlpRemoveFinalReference: connection %p\n",
  5743. pConnection
  5744. ));
  5745. //
  5746. // We're it. Set the flag.
  5747. //
  5748. UlpSetConnectionFlag( pConnection, MakeFinalReferenceRemovedFlag() );
  5749. //
  5750. // Unbind from the endpoint if we're still attached.
  5751. // This allows it to release any refs it has on the connection.
  5752. //
  5753. UlpUnbindConnectionFromEndpoint(pConnection);
  5754. UlReleaseSpinLock(
  5755. &pConnection->ConnectionStateSpinLock,
  5756. OldIrql
  5757. );
  5758. //
  5759. // Tell the client that the connection is now fully destroyed.
  5760. //
  5761. (pConnection->pConnectionDestroyedHandler)(
  5762. pConnection->pListeningContext,
  5763. pConnection->pConnectionContext
  5764. );
  5765. //
  5766. // Release the filter channel.
  5767. // This allows it to release any refs it has on the connection.
  5768. //
  5769. if (pConnection->FilterInfo.pFilterChannel)
  5770. {
  5771. UlUnbindConnectionFromFilter(&pConnection->FilterInfo);
  5772. }
  5773. //
  5774. // Remove the final reference.
  5775. //
  5776. DEREFERENCE_CONNECTION( pConnection );
  5777. return;
  5778. }
  5779. }
  5780. else
  5781. {
  5782. UlTrace(TDI, (
  5783. "UlpRemoveFinalReference: cannot remove %p\n",
  5784. pConnection
  5785. ));
  5786. }
  5787. UlReleaseSpinLock(
  5788. &pConnection->ConnectionStateSpinLock,
  5789. OldIrql
  5790. );
  5791. } // UlpRemoveFinalReference
  5792. /***************************************************************************++
  5793. Routine Description:
  5794. Completion handler for receive IRPs passed back to the transport from
  5795. our receive indication handler.
  5796. Arguments:
  5797. pDeviceObject - Supplies the device object for the IRP being
  5798. completed.
  5799. pIrp - Supplies the IRP being completed.
  5800. pContext - Supplies the context associated with this request.
  5801. This is actually a PUL_RECEIVE_BUFFER.
  5802. Return Value:
  5803. NTSTATUS - STATUS_SUCCESS if IO should continue processing this
  5804. IRP, STATUS_MORE_PROCESSING_REQUIRED if IO should stop processing
  5805. this IRP.
  5806. --***************************************************************************/
  5807. NTSTATUS
  5808. UlpRestartReceive(
  5809. IN PDEVICE_OBJECT pDeviceObject,
  5810. IN PIRP pIrp,
  5811. IN PVOID pContext
  5812. )
  5813. {
  5814. NTSTATUS status;
  5815. PUL_RECEIVE_BUFFER pBuffer;
  5816. PUL_CONNECTION pConnection;
  5817. PUL_ENDPOINT pEndpoint;
  5818. PUX_TDI_OBJECT pTdiObject;
  5819. ULONG bytesTaken = 0;
  5820. ULONG bytesRemaining;
  5821. UNREFERENCED_PARAMETER(pDeviceObject);
  5822. //
  5823. // Sanity check.
  5824. //
  5825. pBuffer = (PUL_RECEIVE_BUFFER) pContext;
  5826. ASSERT( IS_VALID_RECEIVE_BUFFER( pBuffer ) );
  5827. pConnection = (PUL_CONNECTION) pBuffer->pConnectionContext;
  5828. ASSERT( IS_VALID_CONNECTION( pConnection ) );
  5829. pTdiObject = &pConnection->ConnectionObject;
  5830. ASSERT( IS_VALID_TDI_OBJECT( pTdiObject ) );
  5831. pEndpoint = pConnection->pOwningEndpoint;
  5832. ASSERT( IS_VALID_ENDPOINT( pEndpoint ) );
  5833. //
  5834. // The connection could be destroyed before we get a chance to
  5835. // receive the completion for the receive IRP. In that case the
  5836. // irp status won't be success but STATUS_CONNECTION_RESET or similar.
  5837. // We should not attempt to pass this case to the client.
  5838. //
  5839. status = pBuffer->pIrp->IoStatus.Status;
  5840. if (status != STATUS_SUCCESS)
  5841. {
  5842. //
  5843. // The HttpConnection has already been destroyed
  5844. // or receive completion failed for some reason.
  5845. // No need to go to client.
  5846. //
  5847. goto end;
  5848. }
  5849. //
  5850. // Fake a receive indication to the client.
  5851. //
  5852. pBuffer->UnreadDataLength += (ULONG)pBuffer->pIrp->IoStatus.Information;
  5853. UlTrace(TDI, (
  5854. "UlpRestartReceive: endpoint %p, connection %p, length %lu\n",
  5855. pEndpoint,
  5856. pConnection,
  5857. pBuffer->UnreadDataLength
  5858. ));
  5859. //
  5860. // Pass the data on.
  5861. //
  5862. if (pConnection->FilterInfo.pFilterChannel)
  5863. {
  5864. //
  5865. // Needs to go through a filter.
  5866. //
  5867. status = UlFilterReceiveHandler(
  5868. &pConnection->FilterInfo,
  5869. pBuffer->pDataArea,
  5870. pBuffer->UnreadDataLength,
  5871. 0,
  5872. &bytesTaken
  5873. );
  5874. }
  5875. else
  5876. {
  5877. //
  5878. // Go directly to client.
  5879. //
  5880. status = (pEndpoint->pDataReceiveHandler)(
  5881. pEndpoint->pListeningContext,
  5882. pConnection->pConnectionContext,
  5883. pBuffer->pDataArea,
  5884. pBuffer->UnreadDataLength,
  5885. 0,
  5886. &bytesTaken
  5887. );
  5888. }
  5889. ASSERT( bytesTaken <= pBuffer->UnreadDataLength );
  5890. //
  5891. // Note that this basically duplicates the logic that's currently in
  5892. // UlpReceiveHandler.
  5893. //
  5894. if (status == STATUS_MORE_PROCESSING_REQUIRED)
  5895. {
  5896. //
  5897. // The client consumed part of the indicated data.
  5898. //
  5899. // We'll need to copy the untaken data forward within the receive
  5900. // buffer, build an MDL describing the remaining part of the buffer,
  5901. // then repost the receive IRP.
  5902. //
  5903. bytesRemaining = pBuffer->UnreadDataLength - bytesTaken;
  5904. //
  5905. // Do we have enough buffer space for more?
  5906. //
  5907. if (bytesRemaining < g_UlReceiveBufferSize)
  5908. {
  5909. //
  5910. // Move the unread portion of the buffer to the beginning.
  5911. //
  5912. RtlMoveMemory(
  5913. pBuffer->pDataArea,
  5914. (PUCHAR)pBuffer->pDataArea + bytesTaken,
  5915. bytesRemaining
  5916. );
  5917. pBuffer->UnreadDataLength = bytesRemaining;
  5918. //
  5919. // Build a partial mdl representing the remainder of the
  5920. // buffer.
  5921. //
  5922. IoBuildPartialMdl(
  5923. pBuffer->pMdl, // SourceMdl
  5924. pBuffer->pPartialMdl, // TargetMdl
  5925. (PUCHAR)pBuffer->pDataArea + bytesRemaining,// VirtualAddress
  5926. g_UlReceiveBufferSize - bytesRemaining // Length
  5927. );
  5928. //
  5929. // Finish initializing the IRP.
  5930. //
  5931. TdiBuildReceive(
  5932. pBuffer->pIrp, // Irp
  5933. pTdiObject->pDeviceObject, // DeviceObject
  5934. pTdiObject->pFileObject, // FileObject
  5935. &UlpRestartReceive, // CompletionRoutine
  5936. pBuffer, // CompletionContext
  5937. pBuffer->pPartialMdl, // MdlAddress
  5938. TDI_RECEIVE_NORMAL, // Flags
  5939. g_UlReceiveBufferSize - bytesRemaining // Length
  5940. );
  5941. UlTrace(TDI, (
  5942. "UlpRestartReceive: connection %p, reusing irp %p to grab more data\n",
  5943. pConnection,
  5944. pBuffer->pIrp
  5945. ));
  5946. //
  5947. // Call the driver.
  5948. //
  5949. UlCallDriver( pTdiObject->pDeviceObject, pIrp );
  5950. //
  5951. // Tell IO to stop processing this request.
  5952. //
  5953. return STATUS_MORE_PROCESSING_REQUIRED;
  5954. }
  5955. status = STATUS_BUFFER_OVERFLOW;
  5956. }
  5957. end:
  5958. if (status != STATUS_SUCCESS)
  5959. {
  5960. //
  5961. // The client failed the indication. Abort the connection.
  5962. //
  5963. //
  5964. // BUGBUG need to add code to return a response
  5965. //
  5966. UlpCloseRawConnection(
  5967. pConnection,
  5968. TRUE, // AbortiveDisconnect
  5969. NULL, // pCompletionRoutine
  5970. NULL // pCompletionContext
  5971. );
  5972. }
  5973. if (pTdiObject->pDeviceObject->StackSize > DEFAULT_IRP_STACK_SIZE)
  5974. {
  5975. UlFreeReceiveBufferPool( pBuffer );
  5976. }
  5977. else
  5978. {
  5979. UlPplFreeReceiveBuffer( pBuffer );
  5980. }
  5981. //
  5982. // Remove the connection we added in the receive indication handler,
  5983. // free the receive buffer, then tell IO to stop processing the IRP.
  5984. //
  5985. DEREFERENCE_CONNECTION( pConnection );
  5986. UlTrace(TDI, (
  5987. "UlpRestartReceive: endpoint %p, connection %p, length %lu, "
  5988. "taken %lu, status 0x%x\n",
  5989. pEndpoint,
  5990. pConnection,
  5991. pBuffer->UnreadDataLength,
  5992. bytesTaken,
  5993. status
  5994. ));
  5995. return STATUS_MORE_PROCESSING_REQUIRED;
  5996. } // UlpRestartReceive
  5997. /***************************************************************************++
  5998. Routine Description:
  5999. Completion handler for receive IRPs initiated from UlReceiveData().
  6000. Arguments:
  6001. pDeviceObject - Supplies the device object for the IRP being
  6002. completed.
  6003. pIrp - Supplies the IRP being completed.
  6004. pContext - Supplies the context associated with this request.
  6005. This is actually a PUL_IRP_CONTEXT.
  6006. Return Value:
  6007. NTSTATUS - STATUS_SUCCESS if IO should continue processing this
  6008. IRP, STATUS_MORE_PROCESSING_REQUIRED if IO should stop processing
  6009. this IRP.
  6010. --***************************************************************************/
  6011. NTSTATUS
  6012. UlpRestartClientReceive(
  6013. IN PDEVICE_OBJECT pDeviceObject,
  6014. IN PIRP pIrp,
  6015. IN PVOID pContext
  6016. )
  6017. {
  6018. PUL_IRP_CONTEXT pIrpContext;
  6019. PUL_CONNECTION pConnection;
  6020. UNREFERENCED_PARAMETER(pDeviceObject);
  6021. //
  6022. // Sanity check.
  6023. //
  6024. pIrpContext= (PUL_IRP_CONTEXT)pContext;
  6025. ASSERT( IS_VALID_IRP_CONTEXT( pIrpContext ) );
  6026. pConnection = (PUL_CONNECTION)pIrpContext->pConnectionContext;
  6027. ASSERT( IS_VALID_CONNECTION( pConnection ) );
  6028. UlTrace(TDI, (
  6029. "UlpRestartClientReceive: irp %p, connection %p, status 0x%x\n",
  6030. pIrp,
  6031. pConnection,
  6032. pIrp->IoStatus.Status
  6033. ));
  6034. //
  6035. // Invoke the client's completion handler.
  6036. //
  6037. (VOID) UlInvokeCompletionRoutine(
  6038. pIrp->IoStatus.Status,
  6039. pIrp->IoStatus.Information,
  6040. pIrpContext->pCompletionRoutine,
  6041. pIrpContext->pCompletionContext
  6042. );
  6043. //
  6044. // Free the IRP context we allocated.
  6045. //
  6046. UlPplFreeIrpContext(pIrpContext);
  6047. //
  6048. // IO can't handle completing an IRP with a non-paged MDL attached
  6049. // to it, so we'll free the MDL here.
  6050. //
  6051. ASSERT( pIrp->MdlAddress != NULL );
  6052. UlFreeMdl( pIrp->MdlAddress );
  6053. pIrp->MdlAddress = NULL;
  6054. //
  6055. // Remove the connection we added in UlReceiveData()
  6056. //
  6057. DEREFERENCE_CONNECTION( pConnection );
  6058. //
  6059. // Free the IRP since we're done with it, then tell IO to
  6060. // stop processing the IRP.
  6061. //
  6062. UlFreeIrp(pIrp);
  6063. return STATUS_MORE_PROCESSING_REQUIRED;
  6064. } // UlpRestartClientReceive
  6065. /***************************************************************************++
  6066. Routine Description:
  6067. Removes all active connections from the specified endpoint and initiates
  6068. abortive disconnects.
  6069. Arguments:
  6070. pEndpoint - Supplies the endpoint to purge.
  6071. Return Value:
  6072. NTSTATUS - completion status
  6073. --***************************************************************************/
  6074. NTSTATUS
  6075. UlpDisconnectAllActiveConnections(
  6076. IN PUL_ENDPOINT pEndpoint
  6077. )
  6078. {
  6079. LIST_ENTRY RetiringList;
  6080. PLIST_ENTRY pListEntry;
  6081. PUL_CONNECTION pConnection;
  6082. PUL_IRP_CONTEXT pIrpContext = &pEndpoint->CleanupIrpContext;
  6083. NTSTATUS Status;
  6084. UL_STATUS_BLOCK StatusBlock;
  6085. KIRQL OldIrql;
  6086. //
  6087. // Sanity check.
  6088. //
  6089. ASSERT( IS_VALID_ENDPOINT( pEndpoint ) );
  6090. ASSERT( IS_VALID_IRP_CONTEXT( pIrpContext ) );
  6091. UlTrace(TDI, (
  6092. "UlpDisconnectAllActiveConnections: endpoint %p\n",
  6093. pEndpoint
  6094. ));
  6095. //
  6096. // This routine is not pageable because it must acquire a spinlock.
  6097. // However, it must be called at passive IRQL because it must
  6098. // block on an event object.
  6099. //
  6100. ASSERT( KeGetCurrentIrql() == PASSIVE_LEVEL );
  6101. //
  6102. // Initialize a status block. We'll pass a pointer to this as
  6103. // the completion context to UlpCloseRawConnection(). The
  6104. // completion routine will update the status block and signal
  6105. // the event.
  6106. //
  6107. UlInitializeStatusBlock( &StatusBlock );
  6108. //
  6109. // Loop through all of the active connections.
  6110. //
  6111. InitializeListHead( &RetiringList );
  6112. UlAcquireSpinLock( &g_TdiSpinLock, &OldIrql );
  6113. for (pListEntry = g_TdiConnectionListHead.Flink;
  6114. pListEntry != &g_TdiConnectionListHead;
  6115. pListEntry = pListEntry->Flink)
  6116. {
  6117. pConnection = CONTAINING_RECORD(
  6118. pListEntry,
  6119. UL_CONNECTION,
  6120. GlobalConnectionListEntry
  6121. );
  6122. ASSERT( IS_VALID_CONNECTION( pConnection ) );
  6123. if (pConnection->ConnListState == ActiveNoConnList &&
  6124. pConnection->pOwningEndpoint == pEndpoint)
  6125. {
  6126. UlAcquireSpinLockAtDpcLevel(
  6127. &pConnection->ConnectionStateSpinLock
  6128. );
  6129. if (pConnection->ConnListState == ActiveNoConnList)
  6130. {
  6131. pConnection->ConnListState = NoConnList;
  6132. InsertTailList(
  6133. &RetiringList,
  6134. &pConnection->RetiringListEntry
  6135. );
  6136. }
  6137. UlReleaseSpinLockFromDpcLevel(
  6138. &pConnection->ConnectionStateSpinLock
  6139. );
  6140. }
  6141. }
  6142. UlReleaseSpinLock( &g_TdiSpinLock, OldIrql );
  6143. while (!IsListEmpty(&RetiringList))
  6144. {
  6145. //
  6146. // Remove the connection from the retiring connection list.
  6147. //
  6148. pListEntry = RemoveHeadList( &RetiringList );
  6149. //
  6150. // Validate the connection.
  6151. //
  6152. pConnection = CONTAINING_RECORD(
  6153. pListEntry,
  6154. UL_CONNECTION,
  6155. RetiringListEntry
  6156. );
  6157. ASSERT( IS_VALID_CONNECTION( pConnection ) );
  6158. ASSERT( pConnection->pOwningEndpoint == pEndpoint );
  6159. //
  6160. // Abort it.
  6161. //
  6162. UlResetStatusBlockEvent( &StatusBlock );
  6163. Status = UlpCloseRawConnection(
  6164. pConnection,
  6165. TRUE,
  6166. &UlpSynchronousIoComplete,
  6167. &StatusBlock
  6168. );
  6169. ASSERT( Status == STATUS_PENDING );
  6170. //
  6171. // Wait for it to complete.
  6172. //
  6173. UlWaitForStatusBlockEvent( &StatusBlock );
  6174. //
  6175. // Remove the connection reference for ActiveNoConnList.
  6176. //
  6177. DEREFERENCE_CONNECTION( pConnection );
  6178. }
  6179. //
  6180. // Purge all zombie connections that belong to this endpoint.
  6181. //
  6182. UlPurgeZombieConnections(
  6183. &UlPurgeListeningEndpoint,
  6184. (PVOID) pEndpoint
  6185. );
  6186. //
  6187. // No active connections, nuke the endpoint.
  6188. //
  6189. // We must set the IRP context in the endpoint so that the
  6190. // completion will be invoked when the endpoint's reference
  6191. // count drops to zero. Since the completion routine may be
  6192. // invoked at a later time, we always return STATUS_PENDING.
  6193. //
  6194. pIrpContext->pConnectionContext = (PVOID)pEndpoint;
  6195. DEREFERENCE_ENDPOINT_SELF( pEndpoint, REF_ACTION_DISCONN_ACTIVE );
  6196. return STATUS_PENDING;
  6197. } // UlpDisconnectAllActiveConnections
  6198. /***************************************************************************++
  6199. Routine Description:
  6200. Unbinds an active connection from the endpoint. If the connection
  6201. is on the active list this routine removes it and drops the
  6202. list's reference to the connection.
  6203. Arguments:
  6204. pConnection - the connection to unbind
  6205. --***************************************************************************/
  6206. VOID
  6207. UlpUnbindConnectionFromEndpoint(
  6208. IN PUL_CONNECTION pConnection
  6209. )
  6210. {
  6211. PUL_ENDPOINT pEndpoint;
  6212. //
  6213. // Sanity check.
  6214. //
  6215. ASSERT(IS_VALID_CONNECTION(pConnection));
  6216. ASSERT(pConnection->IdleSListEntry.Next == NULL);
  6217. pEndpoint = pConnection->pOwningEndpoint;
  6218. ASSERT(IS_VALID_ENDPOINT(pEndpoint));
  6219. ASSERT(UlDbgSpinLockOwned(&pConnection->ConnectionStateSpinLock));
  6220. if (pConnection->ConnListState == ActiveNoConnList)
  6221. {
  6222. pConnection->ConnListState = RetiringNoConnList;
  6223. DEREFERENCE_CONNECTION(pConnection);
  6224. }
  6225. ASSERT(UlpConnectionIsOnValidList(pConnection));
  6226. } // UlpUnbindConnectionFromEndpoint
  6227. /***************************************************************************++
  6228. Routine Description:
  6229. Scan the endpoint list looking for one corresponding to the supplied
  6230. address.
  6231. Note: This routine assumes the TDI spinlock is held.
  6232. Arguments:
  6233. pAddress - Supplies the address to search for.
  6234. Return Value:
  6235. PUL_ENDPOINT - The corresponding endpoint if successful, NULL otherwise.
  6236. --***************************************************************************/
  6237. PUL_ENDPOINT
  6238. UlpFindEndpointForPort(
  6239. IN USHORT Port
  6240. )
  6241. {
  6242. PUL_ENDPOINT pEndpoint;
  6243. PLIST_ENTRY pListEntry;
  6244. //
  6245. // Sanity check.
  6246. //
  6247. ASSERT( UlDbgSpinLockOwned( &g_TdiSpinLock ) );
  6248. ASSERT( Port > 0 );
  6249. //
  6250. // Scan the endpoint list.
  6251. //
  6252. // CODEWORK: linear searches are BAD, if the list grows long.
  6253. // May need to augment this with a hash table or something.
  6254. //
  6255. for (pListEntry = g_TdiEndpointListHead.Flink ;
  6256. pListEntry != &g_TdiEndpointListHead ;
  6257. pListEntry = pListEntry->Flink)
  6258. {
  6259. pEndpoint = CONTAINING_RECORD(
  6260. pListEntry,
  6261. UL_ENDPOINT,
  6262. GlobalEndpointListEntry
  6263. );
  6264. if (pEndpoint->LocalPort == Port)
  6265. {
  6266. //
  6267. // Found the address; return it.
  6268. //
  6269. UlTrace(TDI,(
  6270. "UlpFindEndpointForPort: found endpoint %p for port %d\n",
  6271. pEndpoint,
  6272. SWAP_SHORT(Port)
  6273. ));
  6274. return pEndpoint;
  6275. }
  6276. }
  6277. //
  6278. // If we made it this far, then we did not find the address.
  6279. //
  6280. UlTrace(TDI,(
  6281. "UlpFindEndpointForPort: DID NOT find endpoint for port %d\n",
  6282. SWAP_SHORT(Port)
  6283. ));
  6284. return NULL;
  6285. } // UlpFindEndpointForAddress
  6286. /***************************************************************************++
  6287. Routine Description:
  6288. Completion handler for synthetic synchronous IRPs.
  6289. Arguments:
  6290. pCompletionContext - Supplies an uninterpreted context value
  6291. as passed to the asynchronous API. In this case, this is
  6292. a pointer to a UL_STATUS_BLOCK structure.
  6293. Status - Supplies the final completion status of the
  6294. asynchronous API.
  6295. Information - Optionally supplies additional information about
  6296. the completed operation, such as the number of bytes
  6297. transferred. This field is unused for UlCloseListeningEndpoint().
  6298. --***************************************************************************/
  6299. VOID
  6300. UlpSynchronousIoComplete(
  6301. IN PVOID pCompletionContext,
  6302. IN NTSTATUS Status,
  6303. IN ULONG_PTR Information
  6304. )
  6305. {
  6306. PUL_STATUS_BLOCK pStatus;
  6307. //
  6308. // Snag the status block pointer.
  6309. //
  6310. pStatus = (PUL_STATUS_BLOCK)pCompletionContext;
  6311. //
  6312. // Update the completion status and signal the event.
  6313. //
  6314. UlSignalStatusBlock( pStatus, Status, Information );
  6315. } // UlpSynchronousIoComplete
  6316. /***************************************************************************++
  6317. Routine Description:
  6318. Enable optimization for interrpt moderation on a Address Object (Listening
  6319. Endpoint)
  6320. Arguments:
  6321. pTdiObject - Supplies the TDI address object to manipulate.
  6322. Flag - Supplies TRUE to enable Optimization, FALSE to disable it.
  6323. Return Value:
  6324. NTSTATUS - Completion status.
  6325. --***************************************************************************/
  6326. NTSTATUS
  6327. UlpOptimizeForInterruptModeration(
  6328. IN PUX_TDI_OBJECT pTdiObject,
  6329. IN BOOLEAN Flag
  6330. )
  6331. {
  6332. NTSTATUS status;
  6333. IO_STATUS_BLOCK ioStatusBlock;
  6334. PTCP_REQUEST_SET_INFORMATION_EX pSetInfoEx;
  6335. ULONG value;
  6336. UCHAR buffer[sizeof(*pSetInfoEx) - sizeof(pSetInfoEx->Buffer) + sizeof(value)];
  6337. //
  6338. // Sanity check.
  6339. //
  6340. PAGED_CODE();
  6341. ASSERT( IS_VALID_TDI_OBJECT( pTdiObject ) );
  6342. value = (ULONG) Flag;
  6343. //
  6344. // Setup the buffer.
  6345. //
  6346. pSetInfoEx = (PTCP_REQUEST_SET_INFORMATION_EX)buffer;
  6347. pSetInfoEx->ID.toi_entity.tei_entity = CO_TL_ENTITY;
  6348. pSetInfoEx->ID.toi_entity.tei_instance = TL_INSTANCE;
  6349. pSetInfoEx->ID.toi_class = INFO_CLASS_PROTOCOL;
  6350. pSetInfoEx->ID.toi_type = INFO_TYPE_ADDRESS_OBJECT;
  6351. pSetInfoEx->ID.toi_id = AO_OPTION_SCALE_CWIN;
  6352. pSetInfoEx->BufferSize = sizeof(value);
  6353. RtlCopyMemory( pSetInfoEx->Buffer, &value, sizeof(value) );
  6354. status = ZwDeviceIoControlFile(
  6355. pTdiObject->Handle, // FileHandle
  6356. NULL, // Event
  6357. NULL, // ApcRoutine
  6358. NULL, // ApcContext
  6359. &ioStatusBlock, // IoStatusBlock
  6360. IOCTL_TCP_SET_INFORMATION_EX, // IoControlCode
  6361. pSetInfoEx, // InputBuffer
  6362. sizeof(buffer), // InputBufferLength
  6363. NULL, // OutputBuffer
  6364. 0 // OutputBufferLength
  6365. );
  6366. if (status == STATUS_PENDING)
  6367. {
  6368. status = ZwWaitForSingleObject(
  6369. pTdiObject->Handle, // Handle
  6370. TRUE, // Alertable
  6371. NULL // Timeout
  6372. );
  6373. ASSERT( NT_SUCCESS(status) );
  6374. status = ioStatusBlock.Status;
  6375. }
  6376. return status;
  6377. } // UlpOptimizeForInterruptModeration
  6378. /***************************************************************************++
  6379. Routine Description:
  6380. Enable/disable Nagle's Algorithm on the specified TDI connection object.
  6381. Arguments:
  6382. pTdiObject - Supplies the TDI connection object to manipulate.
  6383. Flag - Supplies TRUE to enable Nagling, FALSE to disable it.
  6384. Return Value:
  6385. NTSTATUS - Completion status.
  6386. --***************************************************************************/
  6387. NTSTATUS
  6388. UlpSetNagling(
  6389. IN PUX_TDI_OBJECT pTdiObject,
  6390. IN BOOLEAN Flag
  6391. )
  6392. {
  6393. NTSTATUS status;
  6394. IO_STATUS_BLOCK ioStatusBlock;
  6395. PTCP_REQUEST_SET_INFORMATION_EX pSetInfoEx;
  6396. ULONG value;
  6397. UCHAR buffer[sizeof(*pSetInfoEx) - sizeof(pSetInfoEx->Buffer) + sizeof(value)];
  6398. //
  6399. // Sanity check.
  6400. //
  6401. PAGED_CODE();
  6402. ASSERT( IS_VALID_TDI_OBJECT( pTdiObject ) );
  6403. //
  6404. // Note: NODELAY semantics are inverted from the usual enable/disable
  6405. // semantics.
  6406. //
  6407. value = (ULONG)!Flag;
  6408. //
  6409. // Setup the buffer.
  6410. //
  6411. pSetInfoEx = (PTCP_REQUEST_SET_INFORMATION_EX)buffer;
  6412. pSetInfoEx->ID.toi_entity.tei_entity = CO_TL_ENTITY;
  6413. pSetInfoEx->ID.toi_entity.tei_instance = TL_INSTANCE;
  6414. pSetInfoEx->ID.toi_class = INFO_CLASS_PROTOCOL;
  6415. pSetInfoEx->ID.toi_type = INFO_TYPE_CONNECTION;
  6416. pSetInfoEx->ID.toi_id = TCP_SOCKET_NODELAY;
  6417. pSetInfoEx->BufferSize = sizeof(value);
  6418. RtlCopyMemory( pSetInfoEx->Buffer, &value, sizeof(value) );
  6419. status = ZwDeviceIoControlFile(
  6420. pTdiObject->Handle, // FileHandle
  6421. NULL, // Event
  6422. NULL, // ApcRoutine
  6423. NULL, // ApcContext
  6424. &ioStatusBlock, // IoStatusBlock
  6425. IOCTL_TCP_SET_INFORMATION_EX, // IoControlCode
  6426. pSetInfoEx, // InputBuffer
  6427. sizeof(buffer), // InputBufferLength
  6428. NULL, // OutputBuffer
  6429. 0 // OutputBufferLength
  6430. );
  6431. if (status == STATUS_PENDING)
  6432. {
  6433. status = ZwWaitForSingleObject(
  6434. pTdiObject->Handle, // Handle
  6435. TRUE, // Alertable
  6436. NULL // Timeout
  6437. );
  6438. ASSERT( NT_SUCCESS(status) );
  6439. status = ioStatusBlock.Status;
  6440. }
  6441. return status;
  6442. } // UlpSetNagling
  6443. /***************************************************************************++
  6444. Routine Description:
  6445. Query the TDI fast send routine to see if fast send is possible.
  6446. Arguments:
  6447. DeviceName - DD_TCP_DEVICE_NAME or DD_TCPV6_DEVICE_NAME
  6448. pDispatchRoutine - where the function pointer is deposited
  6449. Return Value:
  6450. --***************************************************************************/
  6451. NTSTATUS
  6452. UlpQueryTcpFastSend(
  6453. PWSTR DeviceName,
  6454. OUT PUL_TCPSEND_DISPATCH* pDispatchRoutine
  6455. )
  6456. {
  6457. UNICODE_STRING TCPDeviceName;
  6458. PFILE_OBJECT pTCPFileObject;
  6459. PDEVICE_OBJECT pTCPDeviceObject;
  6460. PIRP Irp;
  6461. IO_STATUS_BLOCK StatusBlock;
  6462. KEVENT Event;
  6463. NTSTATUS status;
  6464. status = UlInitUnicodeStringEx(&TCPDeviceName, DeviceName);
  6465. if (!NT_SUCCESS(status))
  6466. {
  6467. return status;
  6468. }
  6469. status = IoGetDeviceObjectPointer(
  6470. &TCPDeviceName,
  6471. FILE_ALL_ACCESS,
  6472. &pTCPFileObject,
  6473. &pTCPDeviceObject
  6474. );
  6475. if (!NT_SUCCESS(status))
  6476. {
  6477. return status;
  6478. }
  6479. KeInitializeEvent(&Event, SynchronizationEvent, FALSE);
  6480. Irp = IoBuildDeviceIoControlRequest(
  6481. IOCTL_TDI_QUERY_DIRECT_SEND_HANDLER,
  6482. pTCPDeviceObject,
  6483. pDispatchRoutine,
  6484. sizeof(*pDispatchRoutine),
  6485. NULL,
  6486. 0,
  6487. FALSE,
  6488. &Event,
  6489. &StatusBlock
  6490. );
  6491. if (Irp)
  6492. {
  6493. status = UlCallDriver(pTCPDeviceObject, Irp);
  6494. if (status == STATUS_PENDING)
  6495. {
  6496. KeWaitForSingleObject(
  6497. &Event,
  6498. Executive,
  6499. KernelMode,
  6500. FALSE,
  6501. NULL
  6502. );
  6503. status = StatusBlock.Status;
  6504. }
  6505. }
  6506. else
  6507. {
  6508. status = STATUS_NO_MEMORY;
  6509. }
  6510. ObDereferenceObject(pTCPFileObject);
  6511. return status;
  6512. } // UlpQueryTcpFastSend
  6513. /***************************************************************************++
  6514. Routine Description:
  6515. Build a receive buffer and IRP to TDI to get any pending data.
  6516. Arguments:
  6517. pTdiObject - Supplies the TDI connection object to manipulate.
  6518. pConnection - Supplies the UL_CONNECTION object.
  6519. Return Value:
  6520. NTSTATUS - Completion status.
  6521. --***************************************************************************/
  6522. NTSTATUS
  6523. UlpBuildTdiReceiveBuffer(
  6524. IN PUX_TDI_OBJECT pTdiObject,
  6525. IN PUL_CONNECTION pConnection,
  6526. OUT PIRP *pIrp
  6527. )
  6528. {
  6529. PUL_RECEIVE_BUFFER pBuffer;
  6530. if (pTdiObject->pDeviceObject->StackSize > DEFAULT_IRP_STACK_SIZE)
  6531. {
  6532. pBuffer = UlAllocateReceiveBuffer(
  6533. pTdiObject->pDeviceObject->StackSize
  6534. );
  6535. }
  6536. else
  6537. {
  6538. pBuffer = UlPplAllocateReceiveBuffer();
  6539. }
  6540. if (pBuffer != NULL)
  6541. {
  6542. //
  6543. // Finish initializing the buffer and the IRP.
  6544. //
  6545. REFERENCE_CONNECTION( pConnection );
  6546. pBuffer->pConnectionContext = pConnection;
  6547. pBuffer->UnreadDataLength = 0;
  6548. TdiBuildReceive(
  6549. pBuffer->pIrp, // Irp
  6550. pTdiObject->pDeviceObject, // DeviceObject
  6551. pTdiObject->pFileObject, // FileObject
  6552. &UlpRestartReceive, // CompletionRoutine
  6553. pBuffer, // CompletionContext
  6554. pBuffer->pMdl, // MdlAddress
  6555. TDI_RECEIVE_NORMAL, // Flags
  6556. g_UlReceiveBufferSize // Length
  6557. );
  6558. UlTrace(TDI, (
  6559. "UlpBuildTdiReceiveBuffer: connection %p, "
  6560. "allocated irp %p to grab more data\n",
  6561. pConnection,
  6562. pBuffer->pIrp
  6563. ));
  6564. //
  6565. // We must trace the IRP before we set the next stack
  6566. // location so the trace code can pull goodies from the
  6567. // IRP correctly.
  6568. //
  6569. TRACE_IRP( IRP_ACTION_CALL_DRIVER, pBuffer->pIrp );
  6570. //
  6571. // Pass the IRP back to the transport.
  6572. //
  6573. *pIrp = pBuffer->pIrp;
  6574. return STATUS_MORE_PROCESSING_REQUIRED;
  6575. }
  6576. return STATUS_INSUFFICIENT_RESOURCES;
  6577. } // UlpBuildTdiReceiveBuffer
  6578. /***************************************************************************++
  6579. Routine Description:
  6580. Returns the length required for HTTP_RAW_CONNECTION
  6581. Arguments:
  6582. pConnectionContext - Pointer to the UL_CONNECTION
  6583. --***************************************************************************/
  6584. ULONG
  6585. UlpComputeHttpRawConnectionLength(
  6586. IN PVOID pConnectionContext
  6587. )
  6588. {
  6589. C_ASSERT(SOCKADDR_ADDRESS_LENGTH_IP6 >= SOCKADDR_ADDRESS_LENGTH_IP);
  6590. UNREFERENCED_PARAMETER(pConnectionContext);
  6591. return (sizeof(HTTP_RAW_CONNECTION_INFO) +
  6592. 2 * ALIGN_UP(SOCKADDR_ADDRESS_LENGTH_IP6, PVOID));
  6593. }
  6594. /***************************************************************************++
  6595. Routine Description:
  6596. Builds the HTTP_RAW_CONNECTION structure
  6597. Arguments:
  6598. pContext - Pointer to the UL_CONNECTION
  6599. pKernelBuffer - Pointer to kernel buffer
  6600. pUserBuffer - Pointer to user buffer
  6601. OutputBufferLength - Length of output buffer
  6602. pBuffer - Buffer for holding any data
  6603. InitialLength - Size of input data.
  6604. --***************************************************************************/
  6605. ULONG
  6606. UlpGenerateHttpRawConnectionInfo(
  6607. IN PVOID pContext,
  6608. IN PUCHAR pKernelBuffer,
  6609. IN PVOID pUserBuffer,
  6610. IN ULONG OutputBufferLength,
  6611. IN PUCHAR pBuffer,
  6612. IN ULONG InitialLength
  6613. )
  6614. {
  6615. PHTTP_RAW_CONNECTION_INFO pConnInfo;
  6616. PUCHAR pLocalAddress;
  6617. PUCHAR pRemoteAddress;
  6618. PHTTP_TRANSPORT_ADDRESS pAddress;
  6619. ULONG BytesCopied = 0;
  6620. PUCHAR pInitialData;
  6621. PUL_CONNECTION pConnection = (PUL_CONNECTION) pContext;
  6622. USHORT AlignedAddressLength;
  6623. ASSERT( IS_VALID_CONNECTION( pConnection ) );
  6624. pConnInfo = (PHTTP_RAW_CONNECTION_INFO) pKernelBuffer;
  6625. // We've allocated enough space for two SOCKADDR_IN6s, so use that
  6626. AlignedAddressLength = (USHORT) ALIGN_UP(SOCKADDR_ADDRESS_LENGTH_IP6, PVOID);
  6627. pLocalAddress = (PUCHAR)( pConnInfo + 1 );
  6628. pRemoteAddress = pLocalAddress + AlignedAddressLength;
  6629. pInitialData = pRemoteAddress + AlignedAddressLength;
  6630. //
  6631. // Now fill in the raw connection data structure.
  6632. //
  6633. pConnInfo->ConnectionId = pConnection->FilterInfo.ConnectionId;
  6634. pAddress = &pConnInfo->Address;
  6635. pAddress->pRemoteAddress = FIXUP_PTR(
  6636. PVOID,
  6637. pUserBuffer,
  6638. pKernelBuffer,
  6639. pRemoteAddress,
  6640. OutputBufferLength
  6641. );
  6642. CopyTdiAddrToSockAddr(
  6643. pConnection->AddressType,
  6644. pConnection->RemoteAddress,
  6645. (struct sockaddr*) pRemoteAddress
  6646. );
  6647. pAddress->pLocalAddress = FIXUP_PTR(
  6648. PVOID,
  6649. pUserBuffer,
  6650. pKernelBuffer,
  6651. pLocalAddress,
  6652. OutputBufferLength
  6653. );
  6654. CopyTdiAddrToSockAddr(
  6655. pConnection->AddressType,
  6656. pConnection->LocalAddress,
  6657. (struct sockaddr*) pLocalAddress
  6658. );
  6659. //
  6660. // Copy any initial data.
  6661. //
  6662. if (InitialLength)
  6663. {
  6664. ASSERT(pBuffer);
  6665. pConnInfo->InitialDataSize = InitialLength;
  6666. pConnInfo->pInitialData = FIXUP_PTR(
  6667. PVOID, // Type
  6668. pUserBuffer, // pUserPtr
  6669. pKernelBuffer, // pKernelPtr
  6670. pInitialData, // pOffsetPtr
  6671. OutputBufferLength // BufferLength
  6672. );
  6673. RtlCopyMemory(pInitialData, pBuffer, InitialLength);
  6674. BytesCopied += InitialLength;
  6675. }
  6676. else
  6677. {
  6678. pConnInfo->InitialDataSize = 0;
  6679. pConnInfo->pInitialData = NULL;
  6680. }
  6681. return BytesCopied;
  6682. } // UlpGenerateHttpRawConnectionInfo
  6683. BOOLEAN
  6684. UlpConnectionIsOnValidList(
  6685. IN PUL_CONNECTION pConnection
  6686. )
  6687. {
  6688. BOOLEAN Valid = TRUE;
  6689. ASSERT( IS_VALID_CONNECTION( pConnection ) );
  6690. switch (pConnection->ConnListState)
  6691. {
  6692. case NoConnList:
  6693. case RetiringNoConnList:
  6694. case ActiveNoConnList:
  6695. ASSERT( pConnection->IdleSListEntry.Next == NULL );
  6696. break;
  6697. case IdleConnList:
  6698. // If this is the last connection in the idle list, then
  6699. // IdleSListEntry.Next==NULL. There's no easy way to tell.
  6700. break;
  6701. default:
  6702. ASSERT(!"Invalid ConnListState");
  6703. Valid = FALSE;
  6704. break;
  6705. }
  6706. return Valid;
  6707. } // UlpConnectionIsOnValidList
  6708. /***************************************************************************++
  6709. Routine Description:
  6710. Converts a RegMultiSz value to an array of UL_TRANSPORT_ADDRESS's.
  6711. If successful, caller must free with UlFreeUlAddrArray( *ppTa ).
  6712. The list of string address may contain both IPv4 and IPv6 addresses.
  6713. The IPv6 addresses should be bracketed. e.g.:
  6714. 1.1.1.1
  6715. [FE80::1]
  6716. [::]
  6717. 2.2.2.2
  6718. Arguments:
  6719. MultiSz - RegMultiSz returned from UlReadGenericParameter
  6720. ppTa - pointer to location to receive pointer to newly alloc'd array of
  6721. UL_TRANSPORT_ADDRESS structs
  6722. pAddrCount - pointer to location to receive the count of valid elements
  6723. in *ppTa.
  6724. Return Value:
  6725. STATUS_SUCCESS if we were able to allocate the TRANSPORT_ADDRESS struct
  6726. and fill in at least one address from the MultiSz list.
  6727. --***************************************************************************/
  6728. NTSTATUS
  6729. UlRegMultiSzToUlAddrArray(
  6730. IN PWSTR MultiSz,
  6731. OUT PUL_TRANSPORT_ADDRESS *ppTa,
  6732. OUT ULONG *pAddrCount
  6733. )
  6734. {
  6735. NTSTATUS status;
  6736. ULONG count, i;
  6737. PWSTR wszCurrent;
  6738. PWSTR wszTerm;
  6739. PWSTR wszSave;
  6740. ULONG dataLength;
  6741. PUL_TRANSPORT_ADDRESS pTa, pTaCurrent;
  6742. struct in_addr IPv4Addr;
  6743. BOOLEAN BracketSeen;
  6744. //
  6745. // Sanity check
  6746. //
  6747. if ( !MultiSz || !wcslen(MultiSz) || !ppTa || !pAddrCount )
  6748. {
  6749. return STATUS_INVALID_PARAMETER;
  6750. }
  6751. *ppTa = NULL;
  6752. *pAddrCount = 0;
  6753. // first pass: count number of entries in list
  6754. count = 0;
  6755. wszCurrent = MultiSz;
  6756. while ( *wszCurrent )
  6757. {
  6758. // step over current string
  6759. wszCurrent += (wcslen( wszCurrent ) + 1);
  6760. count++;
  6761. }
  6762. ASSERT( count );
  6763. if ( 0 >= count )
  6764. {
  6765. // We have yet to allocate any resources.
  6766. return STATUS_INVALID_PARAMETER;
  6767. }
  6768. //
  6769. // Alloc space for all converted addresses, even if some fail.
  6770. //
  6771. pTa = UL_ALLOCATE_ARRAY(
  6772. NonPagedPool,
  6773. UL_TRANSPORT_ADDRESS,
  6774. count,
  6775. UL_TRANSPORT_ADDRESS_POOL_TAG
  6776. );
  6777. if (pTa == NULL)
  6778. {
  6779. return STATUS_INSUFFICIENT_RESOURCES;
  6780. }
  6781. dataLength = count * sizeof(UL_TRANSPORT_ADDRESS);
  6782. RtlZeroMemory( pTa, dataLength );
  6783. // second pass: convert and shove into TA.
  6784. wszCurrent = MultiSz;
  6785. i = 0;
  6786. pTaCurrent = pTa;
  6787. while ( *wszCurrent )
  6788. {
  6789. // Preserve for event log message.
  6790. wszSave = wszCurrent;
  6791. // First try IPv4
  6792. pTaCurrent->TaIp.TAAddressCount = 1;
  6793. pTaCurrent->TaIp.Address[0].AddressLength = TDI_ADDRESS_LENGTH_IP;
  6794. pTaCurrent->TaIp.Address[0].AddressType = TDI_ADDRESS_TYPE_IP;
  6795. status = RtlIpv4StringToAddressW(
  6796. wszCurrent,
  6797. FALSE, // Strict
  6798. &wszTerm, // Terminator
  6799. &IPv4Addr // IPv4Addr
  6800. );
  6801. if (NT_SUCCESS(status))
  6802. {
  6803. // Left hand side in_addr is unaligned, since it is a field
  6804. // in a packed structure and it is coming after an USHORT.
  6805. // Need to be careful here.
  6806. * (struct in_addr UNALIGNED *)
  6807. &pTaCurrent->TaIp.Address[0].Address[0].in_addr
  6808. = IPv4Addr;
  6809. }
  6810. else
  6811. {
  6812. // Now try IPv6
  6813. pTaCurrent->TaIp6.TAAddressCount = 1;
  6814. pTaCurrent->TaIp6.Address[0].AddressLength = TDI_ADDRESS_LENGTH_IP6;
  6815. pTaCurrent->TaIp6.Address[0].AddressType = TDI_ADDRESS_TYPE_IP6;
  6816. // Step over leading L'['
  6817. if (L'[' == *wszCurrent)
  6818. {
  6819. BracketSeen = TRUE;
  6820. wszCurrent++;
  6821. }
  6822. else
  6823. {
  6824. BracketSeen = FALSE;
  6825. }
  6826. // CODEWORK: replace with full-blown IPv6 w/Scope-ID conversion
  6827. // function when it becomes available.
  6828. status = RtlIpv6StringToAddressW(
  6829. wszCurrent,
  6830. &wszTerm, // Terminator
  6831. (struct in6_addr *)
  6832. &pTaCurrent->TaIp6.Address[0].Address[0].sin6_addr
  6833. );
  6834. if ( NT_SUCCESS(status) && L'%' == *wszTerm )
  6835. {
  6836. ULONG scope_id;
  6837. // step past '%'
  6838. wszTerm++;
  6839. status = HttpWideStringToULong(
  6840. wszTerm, // string
  6841. 0, // string is NULL terminated
  6842. FALSE,
  6843. 10,
  6844. NULL,
  6845. &scope_id
  6846. );
  6847. if ( NT_SUCCESS(status) )
  6848. {
  6849. // TDI_ADDRESS_IP6 is a packed struct. sin6_scope_id
  6850. // may be unaligned.
  6851. // Scope ID does not get swapped to Network Byte Order
  6852. *(UNALIGNED64 ULONG *)&
  6853. pTaCurrent->TaIp6.Address[0].Address[0].sin6_scope_id =
  6854. scope_id;
  6855. }
  6856. // step past digits
  6857. while ((*wszTerm) >= L'0' && (*wszTerm) <= L'9')
  6858. {
  6859. wszTerm++;
  6860. }
  6861. }
  6862. // check for L']'
  6863. if ( BracketSeen && L']' != *wszTerm )
  6864. {
  6865. // Invalid IPv6 Address Format, skip this one
  6866. status = STATUS_INVALID_ADDRESS;
  6867. }
  6868. }
  6869. // only move on to the next slot if we successfuly
  6870. // converted the address
  6871. if ( NT_SUCCESS(status) )
  6872. {
  6873. i++;
  6874. pTaCurrent++;
  6875. }
  6876. else
  6877. {
  6878. //
  6879. // Write Event log message that wszSave could not
  6880. // be converted.
  6881. //
  6882. UlEventLogOneStringEntry(
  6883. EVENT_HTTP_LISTEN_ONLY_CONVERT_FAILED,
  6884. wszSave,
  6885. TRUE,
  6886. status
  6887. );
  6888. }
  6889. wszCurrent += (wcslen( wszCurrent ) + 1);
  6890. }
  6891. if ( 0 == i )
  6892. {
  6893. // nothing converted successfully.
  6894. status = STATUS_INVALID_PARAMETER;
  6895. if ( pTa )
  6896. {
  6897. UlFreeUlAddr( pTa );
  6898. }
  6899. }
  6900. else
  6901. {
  6902. // CODEWORK: When we do dynamic adding/removing of addresses, we'll
  6903. // need to sort the list (to make it easier to insert & remove).
  6904. status = STATUS_SUCCESS;
  6905. *pAddrCount = i;
  6906. *ppTa = pTa;
  6907. }
  6908. return status;
  6909. }// UlRegMultiSzToUlAddrArray
  6910. /***************************************************************************++
  6911. Routine Description:
  6912. Checks if pConnection->pOwningEndpoint has any active addresses.
  6913. Arguments:
  6914. pConnection - Supplies the connection object to check.
  6915. Return Value:
  6916. FALSE if there is no AO or TRUE otherwise.
  6917. --***************************************************************************/
  6918. BOOLEAN
  6919. UlCheckListeningEndpointState(
  6920. IN PUL_CONNECTION pConnection
  6921. )
  6922. {
  6923. if (pConnection->pOwningEndpoint->UsageCount)
  6924. {
  6925. return TRUE;
  6926. }
  6927. else
  6928. {
  6929. return FALSE;
  6930. }
  6931. } // UlCheckListeningEndpointState
  6932. /***************************************************************************++
  6933. Routine Description:
  6934. Does a routing lookup & returns the Interface ID & Link ID.
  6935. Arguments:
  6936. pConnection - The connection object.
  6937. Return Value:
  6938. FALSE if there is no AO or TRUE otherwise.
  6939. --***************************************************************************/
  6940. NTSTATUS
  6941. UlGetConnectionRoutingInfo(
  6942. IN PUL_CONNECTION pConnection,
  6943. OUT PULONG pInterfaceId,
  6944. OUT PULONG pLinkId
  6945. )
  6946. {
  6947. PTDI_ROUTING_INFO pTdiRoutingInfo;
  6948. ULONG TdiRoutingInfoSize;
  6949. TDI_REQUEST_KERNEL_QUERY_INFORMATION TdiRequestQueryInformation;
  6950. NTSTATUS Status;
  6951. if(pConnection->bRoutingLookupDone)
  6952. {
  6953. *pInterfaceId = pConnection->InterfaceId;
  6954. *pLinkId = pConnection->LinkId;
  6955. return STATUS_SUCCESS;
  6956. }
  6957. else
  6958. {
  6959. *pInterfaceId = 0;
  6960. *pLinkId = 0;
  6961. }
  6962. //
  6963. // Do a routing lookup to get the interface that we are going to send
  6964. // the packet out on. The flow has to be installed on that interface.
  6965. //
  6966. TdiRequestQueryInformation.QueryType = TDI_QUERY_ROUTING_INFO;
  6967. TdiRequestQueryInformation.RequestConnectionInformation = NULL;
  6968. TdiRoutingInfoSize = sizeof(TDI_ROUTING_INFO) + 2 * sizeof(TDI_ADDRESS_IP);
  6969. pTdiRoutingInfo = UL_ALLOCATE_POOL(
  6970. PagedPool,
  6971. TdiRoutingInfoSize,
  6972. UL_TCI_GENERIC_POOL_TAG
  6973. );
  6974. if(NULL == pTdiRoutingInfo)
  6975. {
  6976. return STATUS_INSUFFICIENT_RESOURCES;
  6977. }
  6978. Status = UlIssueDeviceControl(
  6979. &pConnection->ConnectionObject,
  6980. &TdiRequestQueryInformation,
  6981. sizeof(TdiRequestQueryInformation),
  6982. pTdiRoutingInfo,
  6983. TdiRoutingInfoSize,
  6984. TDI_QUERY_INFORMATION
  6985. );
  6986. if(NT_SUCCESS(Status))
  6987. {
  6988. *pInterfaceId = pTdiRoutingInfo->InterfaceId;
  6989. *pLinkId = pTdiRoutingInfo->LinkId;
  6990. //
  6991. // Cache it on the connection for subsequent lookups.
  6992. //
  6993. pConnection->InterfaceId = pTdiRoutingInfo->InterfaceId;
  6994. pConnection->LinkId = pTdiRoutingInfo->LinkId;
  6995. pConnection->bRoutingLookupDone = TRUE;
  6996. }
  6997. UL_FREE_POOL(pTdiRoutingInfo, UL_TCI_GENERIC_POOL_TAG);
  6998. return Status;
  6999. }
  7000. /*++
  7001. Routine Description:
  7002. If pParsedUrl is an IP constrained site, AND the g_pTdiListenAddresses list
  7003. doesn't contain either a matching ADDR_ANY/in6addr_any or an exact IP match
  7004. then return FALSE.
  7005. Otherwise, return TRUE.
  7006. Arguments:
  7007. pParsedUrl -- fully cooked down url from UlAddUrl*
  7008. Return Value:
  7009. TRUE if routeable, FALSE if NOT routeable.
  7010. --*/
  7011. BOOLEAN
  7012. UlpIsUrlRouteableInListenScope(
  7013. IN PHTTP_PARSED_URL pParsedUrl
  7014. )
  7015. {
  7016. PUL_TRANSPORT_ADDRESS pListenTa;
  7017. USHORT Family;
  7018. PUCHAR pAddr;
  7019. USHORT AddrLen;
  7020. BOOLEAN Routeable = FALSE;
  7021. PSOCKADDR pAddrAny;
  7022. SOCKADDR_IN6 DummyAddr;
  7023. ULONG i;
  7024. //
  7025. // Sanity Check
  7026. //
  7027. ASSERT( pParsedUrl );
  7028. //
  7029. // Check if routing is even an issue for this URL
  7030. //
  7031. if ( HttpUrlSite_IP != pParsedUrl->SiteType &&
  7032. HttpUrlSite_NamePlusIP != pParsedUrl->SiteType )
  7033. {
  7034. // no IP routing issues
  7035. return TRUE;
  7036. }
  7037. //
  7038. // Fail the call if the listen addr list is not present.
  7039. //
  7040. if (!g_pTdiListenAddresses || (0 == g_TdiListenAddrCount))
  7041. {
  7042. return FALSE;
  7043. }
  7044. //
  7045. // Grab relevant address pointers & lengths
  7046. //
  7047. if ( HttpUrlSite_IP == pParsedUrl->SiteType )
  7048. {
  7049. // Grab address & family info from SockAddr
  7050. Family = pParsedUrl->SockAddr.sa_family;
  7051. if (TDI_ADDRESS_TYPE_IP == Family)
  7052. {
  7053. pAddr = (PUCHAR) &pParsedUrl->SockAddr4.sin_addr;
  7054. AddrLen = sizeof(ULONG);
  7055. }
  7056. else
  7057. {
  7058. ASSERT(TDI_ADDRESS_TYPE_IP6 == Family);
  7059. pAddr = (PUCHAR) &pParsedUrl->SockAddr6.sin6_addr;
  7060. AddrLen = sizeof(IN6_ADDR);
  7061. }
  7062. }
  7063. else
  7064. {
  7065. ASSERT( HttpUrlSite_NamePlusIP == pParsedUrl->SiteType );
  7066. // Grab address & family info from RoutingAddr
  7067. Family = pParsedUrl->RoutingAddr.sa_family;
  7068. if (TDI_ADDRESS_TYPE_IP == Family)
  7069. {
  7070. pAddr = (PUCHAR) &pParsedUrl->RoutingAddr4.sin_addr;
  7071. AddrLen = sizeof(ULONG);
  7072. }
  7073. else
  7074. {
  7075. ASSERT(TDI_ADDRESS_TYPE_IP6 == Family);
  7076. pAddr = (PUCHAR) &pParsedUrl->RoutingAddr6.sin6_addr;
  7077. AddrLen = sizeof(IN6_ADDR);
  7078. }
  7079. }
  7080. //
  7081. // set up INADDR_ANY/ip6addr_any
  7082. //
  7083. pAddrAny = (PSOCKADDR)&DummyAddr;
  7084. RtlZeroMemory((PVOID) pAddrAny, sizeof(SOCKADDR_IN6));
  7085. //
  7086. // Walk the list of global listen address entries
  7087. //
  7088. #define TDI_ADDR_FROM_FAMILY( f, a ) ((TDI_ADDRESS_TYPE_IP == (f) ? \
  7089. (PUCHAR)&((a)->TaIp.Address[0].Address[0].in_addr) : \
  7090. (PUCHAR)((a)->TaIp6.Address[0].Address[0].sin6_addr)))
  7091. pListenTa = g_pTdiListenAddresses;
  7092. for ( i = 0; i < g_TdiListenAddrCount; i++ )
  7093. {
  7094. if (pListenTa->Ta.Address[0].AddressType == Family)
  7095. {
  7096. // see if this entry is INADDR_ANY/ip6addr_any
  7097. if (AddrLen == RtlCompareMemory(
  7098. TDI_ADDR_FROM_FAMILY(Family, pListenTa),
  7099. pAddrAny->sa_data,
  7100. AddrLen
  7101. ))
  7102. {
  7103. Routeable = TRUE;
  7104. goto Done;
  7105. }
  7106. // see if we have an exact match
  7107. if (AddrLen == RtlCompareMemory(
  7108. TDI_ADDR_FROM_FAMILY(Family, pListenTa),
  7109. pAddr,
  7110. AddrLen
  7111. ))
  7112. {
  7113. // CODEWORK: If IPv6, check sin6_scope_id too...
  7114. Routeable = TRUE;
  7115. goto Done;
  7116. }
  7117. }
  7118. pListenTa++;
  7119. }
  7120. Done:
  7121. return Routeable;
  7122. }