Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

2286 lines
54 KiB

  1. /*++
  2. Copyright (c) 1998-2001 Microsoft Corporation
  3. Module Name:
  4. httpconn.cxx
  5. Abstract:
  6. This module implements the HTTP_CONNECTION object.
  7. Author:
  8. Keith Moore (keithmo) 08-Jul-1998
  9. Revision History:
  10. --*/
  11. #include "precomp.h"
  12. #include "httpconnp.h"
  13. //
  14. // Private globals.
  15. //
  16. //
  17. // Global connection Limits stuff
  18. //
  19. ULONG g_MaxConnections = HTTP_LIMIT_INFINITE;
  20. ULONG g_CurrentConnections = 0;
  21. BOOLEAN g_InitGlobalConnections = FALSE;
  22. #ifdef ALLOC_PRAGMA
  23. #endif // ALLOC_PRAGMA
  24. #if 0
  25. NOT PAGEABLE -- UlBindConnectionToProcess
  26. NOT PAGEABLE -- UlQueryProcessBinding
  27. NOT PAGEABLE -- UlpCreateProcBinding
  28. NOT PAGEABLE -- UlpFreeProcBinding
  29. NOT PAGEABLE -- UlpFindProcBinding
  30. NOT PAGEABLE -- UlCreateHttpConnection
  31. NOT PAGEABLE -- UlReferenceHttpConnection
  32. NOT PAGEABLE -- UlDereferenceHttpConnection
  33. NOT PAGEABLE -- UlReferenceHttpRequest
  34. NOT PAGEABLE -- UlDereferenceHttpRequest
  35. NOT PAGEABLE -- UlpCreateHttpRequest
  36. NOT PAGEABLE -- UlpFreeHttpRequest
  37. #endif
  38. //
  39. // Public functions.
  40. //
  41. /***************************************************************************++
  42. Routine Description:
  43. Creates a new HTTP_CONNECTION object.
  44. Arguments:
  45. ppHttpConnection - Receives a pointer to the new HTTP_CONNECTION
  46. object if successful.
  47. pConnection - Supplies a pointer to the UL_CONNECTION to associate
  48. with the newly created HTTP_CONNECTION.
  49. Return Value:
  50. NTSTATUS - Completion status.
  51. --***************************************************************************/
  52. NTSTATUS
  53. UlCreateHttpConnection(
  54. OUT PUL_HTTP_CONNECTION *ppHttpConnection,
  55. IN PUL_CONNECTION pConnection
  56. )
  57. {
  58. PUL_HTTP_CONNECTION pHttpConnection;
  59. NTSTATUS Status;
  60. ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL);
  61. pHttpConnection = &pConnection->HttpConnection;
  62. if (pHttpConnection != NULL)
  63. {
  64. pHttpConnection->Signature = UL_HTTP_CONNECTION_POOL_TAG;
  65. pHttpConnection->RefCount = 1;
  66. pHttpConnection->pConnection = pConnection;
  67. REFERENCE_CONNECTION( pConnection );
  68. pHttpConnection->SecureConnection = pConnection->FilterInfo.SecureConnection;
  69. HTTP_SET_NULL_ID(&pHttpConnection->ConnectionId);
  70. pHttpConnection->SendBufferedBytes = 0;
  71. pHttpConnection->NextRecvNumber = 0;
  72. pHttpConnection->NextBufferNumber = 0;
  73. pHttpConnection->NextBufferToParse = 0;
  74. pHttpConnection->pRequest = NULL;
  75. pHttpConnection->pCurrentBuffer = NULL;
  76. pHttpConnection->pConnectionCountEntry = NULL;
  77. pHttpConnection->pPrevSiteCounters = NULL;
  78. //
  79. // Init connection timeout info block; implicitly starts
  80. // ConnectionIdle timer.
  81. //
  82. UlInitializeConnectionTimerInfo( &pHttpConnection->TimeoutInfo );
  83. //
  84. // Initialize the disconnect management fields.
  85. //
  86. pHttpConnection->NeedMoreData = 0;
  87. pHttpConnection->UlconnDestroyed = 0;
  88. pHttpConnection->WaitingForResponse = 0;
  89. pHttpConnection->DisconnectFlag = FALSE;
  90. UlInitializeNotifyHead(
  91. &pHttpConnection->WaitForDisconnectHead,
  92. NULL
  93. );
  94. //
  95. // Init our buffer list
  96. //
  97. InitializeListHead(&(pHttpConnection->BufferHead));
  98. //
  99. // Init QoS parameters on the connection
  100. //
  101. pHttpConnection->BandwidthThrottlingEnabled = 0;
  102. pHttpConnection->pFlow = NULL;
  103. pHttpConnection->pFilter = NULL;
  104. //
  105. // init app pool process binding list
  106. //
  107. InitializeListHead(&(pHttpConnection->BindingHead));
  108. UlInitializeSpinLock(
  109. &pHttpConnection->BindingSpinLock,
  110. "BindingSpinLock"
  111. );
  112. Status = UlInitializeResource(
  113. &(pHttpConnection->Resource),
  114. "UL_HTTP_CONNECTION[%p].Resource",
  115. pHttpConnection,
  116. UL_HTTP_CONNECTION_RESOURCE_TAG
  117. );
  118. if (NT_SUCCESS(Status) == FALSE)
  119. {
  120. RETURN(Status);
  121. }
  122. //
  123. // Initialize BufferingInfo structure.
  124. //
  125. UlInitializeSpinLock(
  126. &pHttpConnection->BufferingInfo.BufferingSpinLock,
  127. "BufferingSpinLock"
  128. );
  129. pHttpConnection->BufferingInfo.BytesBuffered = 0;
  130. pHttpConnection->BufferingInfo.TransportBytesNotTaken = 0;
  131. pHttpConnection->BufferingInfo.DrainAfterDisconnect = FALSE;
  132. pHttpConnection->BufferingInfo.ReadIrpPending = FALSE;
  133. pHttpConnection->pRequestIdContext = NULL;
  134. UlInitializeSpinLock(
  135. &pHttpConnection->RequestIdSpinLock,
  136. "RequestIdSpinLock"
  137. );
  138. UlTrace(
  139. REFCOUNT, (
  140. "ul!UlCreateHttpConnection conn=%p refcount=%d\n",
  141. pHttpConnection,
  142. pHttpConnection->RefCount)
  143. );
  144. *ppHttpConnection = pHttpConnection;
  145. RETURN(STATUS_SUCCESS);
  146. }
  147. RETURN(STATUS_INSUFFICIENT_RESOURCES);
  148. } // UlCreateHttpConnection
  149. NTSTATUS
  150. UlCreateHttpConnectionId(
  151. IN PUL_HTTP_CONNECTION pHttpConnection
  152. )
  153. {
  154. NTSTATUS Status;
  155. //
  156. // Sanity check.
  157. //
  158. PAGED_CODE();
  159. //
  160. // Create an opaque id for the connection
  161. //
  162. Status = UlAllocateOpaqueId(
  163. &pHttpConnection->ConnectionId, // pOpaqueId
  164. UlOpaqueIdTypeHttpConnection, // OpaqueIdType
  165. pHttpConnection // pContext
  166. );
  167. if (NT_SUCCESS(Status))
  168. {
  169. UL_REFERENCE_HTTP_CONNECTION(pHttpConnection);
  170. TRACE_TIME(
  171. pHttpConnection->ConnectionId,
  172. 0,
  173. TIME_ACTION_CREATE_CONNECTION
  174. );
  175. }
  176. RETURN(Status);
  177. } // UlCreateHttpConnectionId
  178. VOID
  179. UlConnectionDestroyedWorker(
  180. IN PUL_WORK_ITEM pWorkItem
  181. )
  182. {
  183. PUL_HTTP_CONNECTION pHttpConnection;
  184. //
  185. // Sanity check.
  186. //
  187. PAGED_CODE();
  188. pHttpConnection = CONTAINING_RECORD(
  189. pWorkItem,
  190. UL_HTTP_CONNECTION,
  191. WorkItem
  192. );
  193. ASSERT(UL_IS_VALID_HTTP_CONNECTION(pHttpConnection));
  194. UlTrace(HTTP_IO, (
  195. "ul!UlConnectionDestroyedWorker: httpconn=%p\n",
  196. pHttpConnection
  197. ));
  198. UlAcquireResourceExclusive( &pHttpConnection->Resource, TRUE );
  199. //
  200. // kill the request if there is one
  201. //
  202. if (pHttpConnection->pRequest) {
  203. ASSERT(UL_IS_VALID_INTERNAL_REQUEST(pHttpConnection->pRequest));
  204. UlUnlinkHttpRequest(pHttpConnection->pRequest);
  205. pHttpConnection->pRequest = NULL;
  206. }
  207. //
  208. // make sure no one adds a new request now that we're done
  209. //
  210. pHttpConnection->UlconnDestroyed = 1;
  211. //
  212. // Decrement the global connection limit. Its safe to decrement for
  213. // global case because http object doesn't even allocated for global
  214. // rejection which happens as tcp refusal early when acepting the
  215. // connection request.
  216. //
  217. UlDecrementConnections( &g_CurrentConnections );
  218. //
  219. // Decrement the site connections and let our ref go away. If the
  220. // pConnectionCountEntry is not null, we have been accepted.
  221. //
  222. if (pHttpConnection->pConnectionCountEntry)
  223. {
  224. UlDecrementConnections(
  225. &pHttpConnection->pConnectionCountEntry->CurConnections );
  226. DEREFERENCE_CONNECTION_COUNT_ENTRY(pHttpConnection->pConnectionCountEntry);
  227. pHttpConnection->pConnectionCountEntry = NULL;
  228. }
  229. //
  230. // and now remove the connection's id
  231. //
  232. if (HTTP_IS_NULL_ID(&pHttpConnection->ConnectionId) == FALSE)
  233. {
  234. UlFreeOpaqueId(
  235. pHttpConnection->ConnectionId,
  236. UlOpaqueIdTypeHttpConnection
  237. );
  238. HTTP_SET_NULL_ID(&pHttpConnection->ConnectionId);
  239. UL_DEREFERENCE_HTTP_CONNECTION(pHttpConnection);
  240. }
  241. UlReleaseResource( &pHttpConnection->Resource );
  242. //
  243. // Complete all WaitForDisconnect IRPs
  244. //
  245. UlCompleteAllWaitForDisconnect(pHttpConnection);
  246. //
  247. // and remove the ULTDI reference from the HTTP_CONNECTION
  248. //
  249. UL_DEREFERENCE_HTTP_CONNECTION(pHttpConnection);
  250. } // UlConnectionDestroyedWorker
  251. /***************************************************************************++
  252. Routine Description:
  253. Tries to establish a binding between a connection and an app pool
  254. process. You can query these bindings with UlQueryProcessBinding.
  255. Arguments:
  256. pHttpConnection - the connection to bind
  257. pAppPool - the app pool that owns the process (key for lookups)
  258. pProcess - the process to bind to
  259. --***************************************************************************/
  260. NTSTATUS
  261. UlBindConnectionToProcess(
  262. IN PUL_HTTP_CONNECTION pHttpConnection,
  263. IN PUL_APP_POOL_OBJECT pAppPool,
  264. IN PUL_APP_POOL_PROCESS pProcess
  265. )
  266. {
  267. NTSTATUS Status = STATUS_SUCCESS;
  268. PUL_APOOL_PROC_BINDING pBinding = NULL;
  269. KIRQL OldIrql;
  270. //
  271. // Sanity check
  272. //
  273. ASSERT( UL_IS_VALID_HTTP_CONNECTION( pHttpConnection ) );
  274. ASSERT( pAppPool->NumberActiveProcesses > 1 || pProcess == NULL );
  275. UlAcquireSpinLock(&pHttpConnection->BindingSpinLock, &OldIrql);
  276. //
  277. // see if there's already a binding object
  278. //
  279. pBinding = UlpFindProcBinding(pHttpConnection, pAppPool);
  280. if (pBinding) {
  281. if (pProcess) {
  282. //
  283. // modify the binding
  284. //
  285. pBinding->pProcess = pProcess;
  286. } else {
  287. //
  288. // we're supposed to kill this binding
  289. //
  290. RemoveEntryList(&pBinding->BindingEntry);
  291. UlpFreeProcBinding(pBinding);
  292. }
  293. } else {
  294. if (pProcess) {
  295. //
  296. // create a new entry
  297. //
  298. pBinding = UlpCreateProcBinding(pAppPool, pProcess);
  299. if (pBinding) {
  300. InsertHeadList(
  301. &pHttpConnection->BindingHead,
  302. &pBinding->BindingEntry
  303. );
  304. } else {
  305. Status = STATUS_INSUFFICIENT_RESOURCES;
  306. }
  307. }
  308. }
  309. UlReleaseSpinLock(&pHttpConnection->BindingSpinLock, OldIrql);
  310. UlTrace(ROUTING, (
  311. "ul!UlBindConnectionToProcess(\n"
  312. " pHttpConnection = %p (%I64x)\n"
  313. " pAppPool = %p\n"
  314. " pProcess = %p )\n"
  315. " Status = 0x%x\n",
  316. pHttpConnection,
  317. pHttpConnection->ConnectionId,
  318. pAppPool,
  319. pProcess,
  320. Status
  321. ));
  322. return Status;
  323. }
  324. /***************************************************************************++
  325. Routine Description:
  326. Removes an HTTP request from all lists and cleans up it's opaque id.
  327. Arguments:
  328. pRequest - the request to be unlinked
  329. --***************************************************************************/
  330. VOID
  331. UlCleanupHttpConnection(
  332. IN PUL_HTTP_CONNECTION pHttpConnection
  333. )
  334. {
  335. PLIST_ENTRY pEntry;
  336. ASSERT( UL_IS_VALID_INTERNAL_REQUEST( pHttpConnection->pRequest ) );
  337. ASSERT( pHttpConnection->WaitingForResponse );
  338. UlUnlinkHttpRequest( pHttpConnection->pRequest );
  339. pHttpConnection->pRequest = NULL;
  340. pHttpConnection->WaitingForResponse = 0;
  341. UlTrace( PARSER, (
  342. "***1 pConnection %p->WaitingForResponse = 0\n",
  343. pHttpConnection
  344. ));
  345. //
  346. // Free the old request's buffers
  347. //
  348. ASSERT( UL_IS_VALID_REQUEST_BUFFER( pHttpConnection->pCurrentBuffer ) );
  349. pEntry = pHttpConnection->BufferHead.Flink;
  350. while (pEntry != &pHttpConnection->BufferHead)
  351. {
  352. PUL_REQUEST_BUFFER pBuffer;
  353. //
  354. // Get the object
  355. //
  356. pBuffer = CONTAINING_RECORD(
  357. pEntry,
  358. UL_REQUEST_BUFFER,
  359. ListEntry
  360. );
  361. //
  362. // did we reach the end?
  363. //
  364. if (pBuffer == pHttpConnection->pCurrentBuffer) {
  365. break;
  366. }
  367. //
  368. // remember the next one
  369. //
  370. pEntry = pEntry->Flink;
  371. //
  372. // unlink it
  373. //
  374. UlFreeRequestBuffer(pBuffer);
  375. }
  376. }
  377. VOID
  378. UlReferenceHttpConnection(
  379. IN PVOID pObject
  380. REFERENCE_DEBUG_FORMAL_PARAMS
  381. )
  382. {
  383. LONG refCount;
  384. PUL_HTTP_CONNECTION pHttpConnection = (PUL_HTTP_CONNECTION) pObject;
  385. refCount = InterlockedIncrement( &pHttpConnection->RefCount );
  386. WRITE_REF_TRACE_LOG2(
  387. g_pHttpConnectionTraceLog,
  388. pHttpConnection->pTraceLog,
  389. REF_ACTION_REFERENCE_HTTP_CONNECTION,
  390. refCount,
  391. pHttpConnection,
  392. pFileName,
  393. LineNumber
  394. );
  395. UlTrace(
  396. REFCOUNT, (
  397. "ul!UlReferenceHttpConnection conn=%p refcount=%d\n",
  398. pHttpConnection,
  399. refCount)
  400. );
  401. } // UlReferenceHttpConnection
  402. VOID
  403. UlDereferenceHttpConnection(
  404. IN PUL_HTTP_CONNECTION pHttpConnection
  405. REFERENCE_DEBUG_FORMAL_PARAMS
  406. )
  407. {
  408. LONG refCount;
  409. ASSERT( pHttpConnection );
  410. ASSERT( pHttpConnection->RefCount > 0 );
  411. WRITE_REF_TRACE_LOG2(
  412. g_pHttpConnectionTraceLog,
  413. pHttpConnection->pTraceLog,
  414. REF_ACTION_DEREFERENCE_HTTP_CONNECTION,
  415. pHttpConnection->RefCount - 1,
  416. pHttpConnection,
  417. pFileName,
  418. LineNumber
  419. );
  420. refCount = InterlockedDecrement( &pHttpConnection->RefCount );
  421. UlTrace(
  422. REFCOUNT, (
  423. "ul!UlDereferenceHttpConnection conn=%p refcount=%d\n",
  424. pHttpConnection,
  425. refCount)
  426. );
  427. if (refCount == 0)
  428. {
  429. //
  430. // now it's time to free the connection, we need to do
  431. // this at lower'd irql, let's check it out
  432. //
  433. UL_CALL_PASSIVE(
  434. &(pHttpConnection->WorkItem),
  435. &UlDeleteHttpConnection
  436. );
  437. }
  438. } // UlDereferenceHttpConnection
  439. /***************************************************************************++
  440. Routine Description:
  441. Frees all resources associated with the specified HTTP_CONNECTION.
  442. Arguments:
  443. pWorkItem - Supplies the HTTP_CONNECTION to free.
  444. --***************************************************************************/
  445. VOID
  446. UlDeleteHttpConnection(
  447. IN PUL_WORK_ITEM pWorkItem
  448. )
  449. {
  450. NTSTATUS Status;
  451. PLIST_ENTRY pEntry;
  452. PUL_HTTP_CONNECTION pHttpConnection;
  453. KIRQL OldIrql;
  454. //
  455. // Sanity check.
  456. //
  457. PAGED_CODE();
  458. pHttpConnection = CONTAINING_RECORD(
  459. pWorkItem,
  460. UL_HTTP_CONNECTION,
  461. WorkItem
  462. );
  463. ASSERT( pHttpConnection != NULL &&
  464. pHttpConnection->Signature == UL_HTTP_CONNECTION_POOL_TAG );
  465. ASSERT(HTTP_IS_NULL_ID(&pHttpConnection->ConnectionId));
  466. ASSERT(pHttpConnection->SendBufferedBytes == 0);
  467. WRITE_REF_TRACE_LOG2(
  468. g_pHttpConnectionTraceLog,
  469. pHttpConnection->pTraceLog,
  470. REF_ACTION_DESTROY_HTTP_CONNECTION,
  471. 0,
  472. pHttpConnection,
  473. __FILE__,
  474. __LINE__
  475. );
  476. //
  477. // The request is gone by now
  478. //
  479. ASSERT(pHttpConnection->pRequest == NULL);
  480. //
  481. // remove from Timeout Timer Wheel(c)
  482. //
  483. UlTimeoutRemoveTimerWheelEntry(
  484. &pHttpConnection->TimeoutInfo
  485. );
  486. //
  487. // delete the buffer list
  488. //
  489. pEntry = pHttpConnection->BufferHead.Flink;
  490. while (pEntry != &pHttpConnection->BufferHead)
  491. {
  492. PUL_REQUEST_BUFFER pBuffer;
  493. //
  494. // Get the object
  495. //
  496. pBuffer = CONTAINING_RECORD(
  497. pEntry,
  498. UL_REQUEST_BUFFER,
  499. ListEntry
  500. );
  501. //
  502. // remember the next one
  503. //
  504. pEntry = pEntry->Flink;
  505. //
  506. // unlink it
  507. //
  508. UlFreeRequestBuffer(pBuffer);
  509. }
  510. ASSERT(IsListEmpty(&pHttpConnection->BufferHead));
  511. //
  512. // get rid of any bindings we're keeping
  513. //
  514. while (!IsListEmpty(&pHttpConnection->BindingHead))
  515. {
  516. PUL_APOOL_PROC_BINDING pBinding;
  517. //
  518. // Get the object
  519. //
  520. pEntry = RemoveHeadList(&pHttpConnection->BindingHead);
  521. pBinding = CONTAINING_RECORD(
  522. pEntry,
  523. UL_APOOL_PROC_BINDING,
  524. BindingEntry
  525. );
  526. ASSERT( IS_VALID_PROC_BINDING(pBinding) );
  527. //
  528. // free it
  529. //
  530. UlpFreeProcBinding(pBinding);
  531. }
  532. //
  533. // get rid of our resource
  534. //
  535. Status = UlDeleteResource(&(pHttpConnection->Resource));
  536. ASSERT(NT_SUCCESS(Status));
  537. //
  538. // Attempt to remove any QoS filter on this connection,
  539. // if BWT is enabled.
  540. //
  541. if (pHttpConnection->BandwidthThrottlingEnabled)
  542. {
  543. UlTcDeleteFilter(pHttpConnection);
  544. }
  545. //
  546. // Remove final (previous) site counter entry reference
  547. // (matches reference in UlSendCachedResponse/UlDeliverHttpRequest)
  548. //
  549. if (pHttpConnection->pPrevSiteCounters)
  550. {
  551. UlDecSiteCounter(
  552. pHttpConnection->pPrevSiteCounters,
  553. HttpSiteCounterCurrentConns
  554. );
  555. DEREFERENCE_SITE_COUNTER_ENTRY(pHttpConnection->pPrevSiteCounters);
  556. pHttpConnection->pPrevSiteCounters = NULL;
  557. }
  558. //
  559. // free the memory
  560. //
  561. pHttpConnection->Signature = MAKE_FREE_SIGNATURE(
  562. UL_HTTP_CONNECTION_POOL_TAG
  563. );
  564. //
  565. // let go the UL_CONNECTION
  566. //
  567. DEREFERENCE_CONNECTION( pHttpConnection->pConnection );
  568. } // UlDeleteHttpConnection
  569. /***************************************************************************++
  570. Routine Description:
  571. Arguments:
  572. Return Value:
  573. NTSTATUS - Completion status.
  574. --***************************************************************************/
  575. NTSTATUS
  576. UlpCreateHttpRequest(
  577. IN PUL_HTTP_CONNECTION pHttpConnection,
  578. OUT PUL_INTERNAL_REQUEST *ppRequest
  579. )
  580. {
  581. PUL_INTERNAL_REQUEST pRequest = NULL;
  582. //
  583. // Sanity check.
  584. //
  585. PAGED_CODE();
  586. pRequest = UlPplAllocateInternalRequest();
  587. if (pRequest == NULL)
  588. {
  589. return STATUS_NO_MEMORY;
  590. }
  591. ASSERT( pRequest->Signature == MAKE_FREE_TAG(UL_INTERNAL_REQUEST_POOL_TAG) );
  592. pRequest->Signature = UL_INTERNAL_REQUEST_POOL_TAG;
  593. pRequest->RefCount = 1;
  594. //
  595. // the verb comes first
  596. //
  597. pRequest->ParseState = ParseVerbState;
  598. //
  599. // keep a reference to the connection.
  600. //
  601. UL_REFERENCE_HTTP_CONNECTION( pHttpConnection );
  602. pRequest->pHttpConn = pHttpConnection;
  603. pRequest->ConnectionId = pHttpConnection->ConnectionId;
  604. pRequest->Secure = pHttpConnection->SecureConnection;
  605. //
  606. // init our LIST_ENTRY's
  607. //
  608. InitializeListHead( &pRequest->UnknownHeaderList );
  609. InitializeListHead( &pRequest->IrpHead );
  610. //
  611. // We start with no header buffers appended nor Irps pending.
  612. //
  613. pRequest->HeadersAppended = FALSE;
  614. pRequest->IrpsPending = FALSE;
  615. //
  616. // Reset the index to our default unknown header table to 0 as well as
  617. // the unknown header count.
  618. //
  619. pRequest->NextUnknownHeaderIndex = 0;
  620. pRequest->UnknownHeaderCount = 0;
  621. //
  622. // Create an opaque id for the request.
  623. //
  624. // We also make a copy of the id in case we need
  625. // to see what the id was after the real one
  626. // is freed and set to null.
  627. //
  628. HTTP_SET_NULL_ID(&pRequest->RequestId);
  629. pRequest->RequestIdCopy = pRequest->RequestId;
  630. //
  631. // Grab the raw connection id off the UL_CONNECTION.
  632. //
  633. pRequest->RawConnectionId = pHttpConnection->pConnection->FilterInfo.ConnectionId;
  634. //
  635. // Initialize the header index table.
  636. //
  637. pRequest->HeaderIndex[0] = HttpHeaderRequestMaximum;
  638. //
  639. // Initialize the referenced buffers arrary.
  640. //
  641. pRequest->AllocRefBuffers = 1;
  642. pRequest->UsedRefBuffers = 0;
  643. pRequest->pRefBuffers = pRequest->pInlineRefBuffers;
  644. //
  645. // Initialize the UL_URL_CONFIG_GROUP_INFO.
  646. //
  647. UlpInitializeUrlInfo(&pRequest->ConfigInfo);
  648. //
  649. // Zero the remaining fields.
  650. //
  651. RtlZeroMemory(
  652. (PUCHAR)pRequest + FIELD_OFFSET(UL_INTERNAL_REQUEST, HeaderValid),
  653. sizeof(*pRequest) - FIELD_OFFSET(UL_INTERNAL_REQUEST, HeaderValid)
  654. );
  655. CREATE_REF_TRACE_LOG( pRequest->pTraceLog, 32 - REF_TRACE_OVERHEAD, 0 );
  656. //
  657. // return it
  658. //
  659. *ppRequest = pRequest;
  660. UlTrace(REFCOUNT, (
  661. "ul!UlpCreateHttpRequest req=%p refcount=%d\n",
  662. pRequest,
  663. pRequest->RefCount
  664. ));
  665. return STATUS_SUCCESS;
  666. } // UlpCreateHttpRequest
  667. VOID
  668. UlReferenceHttpRequest(
  669. IN PVOID pObject
  670. REFERENCE_DEBUG_FORMAL_PARAMS
  671. )
  672. {
  673. LONG refCount;
  674. PUL_INTERNAL_REQUEST pRequest = (PUL_INTERNAL_REQUEST) pObject;
  675. refCount = InterlockedIncrement( &pRequest->RefCount );
  676. WRITE_REF_TRACE_LOG2(
  677. g_pHttpRequestTraceLog,
  678. pRequest->pTraceLog,
  679. REF_ACTION_REFERENCE_HTTP_REQUEST,
  680. refCount,
  681. pRequest,
  682. pFileName,
  683. LineNumber
  684. );
  685. UlTrace(
  686. REFCOUNT, (
  687. "ul!UlReferenceHttpRequest req=%p refcount=%d\n",
  688. pRequest,
  689. refCount)
  690. );
  691. } // UlReferenceHttpRequest
  692. VOID
  693. UlDereferenceHttpRequest(
  694. IN PUL_INTERNAL_REQUEST pRequest
  695. REFERENCE_DEBUG_FORMAL_PARAMS
  696. )
  697. {
  698. LONG refCount;
  699. WRITE_REF_TRACE_LOG2(
  700. g_pHttpRequestTraceLog,
  701. pRequest->pTraceLog,
  702. REF_ACTION_DEREFERENCE_HTTP_REQUEST,
  703. pRequest->RefCount - 1,
  704. pRequest,
  705. pFileName,
  706. LineNumber
  707. );
  708. refCount = InterlockedDecrement( &pRequest->RefCount );
  709. UlTrace(
  710. REFCOUNT, (
  711. "ul!UlDereferenceHttpRequest req=%p refcount=%d\n",
  712. pRequest,
  713. refCount)
  714. );
  715. if (refCount == 0)
  716. {
  717. UL_CALL_PASSIVE(
  718. &pRequest->WorkItem,
  719. &UlpFreeHttpRequest
  720. );
  721. }
  722. } // UlDereferenceHttpRequest
  723. /***************************************************************************++
  724. Routine Description:
  725. Cancels all pending http io.
  726. Arguments:
  727. pRequest - Supplies the HTTP_REQUEST.
  728. --***************************************************************************/
  729. VOID
  730. UlCancelRequestIo(
  731. IN PUL_INTERNAL_REQUEST pRequest
  732. )
  733. {
  734. //
  735. // Sanity check.
  736. //
  737. PAGED_CODE();
  738. ASSERT(UL_IS_VALID_INTERNAL_REQUEST(pRequest));
  739. //
  740. // Mark the request as InCleanup, so additional IRPs
  741. // on the request will not be queued.
  742. //
  743. pRequest->InCleanup = 1;
  744. //
  745. // tank all pending io on this request
  746. //
  747. while (IsListEmpty(&pRequest->IrpHead) == FALSE)
  748. {
  749. PLIST_ENTRY pEntry;
  750. PIRP pIrp;
  751. //
  752. // Pop it off the list.
  753. //
  754. pEntry = RemoveHeadList(&pRequest->IrpHead);
  755. pEntry->Blink = pEntry->Flink = NULL;
  756. pIrp = CONTAINING_RECORD(pEntry, IRP, Tail.Overlay.ListEntry);
  757. ASSERT(IS_VALID_IRP(pIrp));
  758. //
  759. // pop the cancel routine
  760. //
  761. if (IoSetCancelRoutine(pIrp, NULL) == NULL)
  762. {
  763. //
  764. // IoCancelIrp pop'd it first
  765. //
  766. // ok to just ignore this irp, it's been pop'd off the queue
  767. // and will be completed in the cancel routine.
  768. //
  769. // keep looping
  770. //
  771. pIrp = NULL;
  772. }
  773. else
  774. {
  775. PUL_INTERNAL_REQUEST pIrpRequest;
  776. //
  777. // cancel it. even if pIrp->Cancel == TRUE we are supposed to
  778. // complete it, our cancel routine will never run.
  779. //
  780. pIrpRequest = (PUL_INTERNAL_REQUEST)(
  781. IoGetCurrentIrpStackLocation(pIrp)->
  782. Parameters.DeviceIoControl.Type3InputBuffer
  783. );
  784. ASSERT(pIrpRequest == pRequest);
  785. UL_DEREFERENCE_INTERNAL_REQUEST(pIrpRequest);
  786. IoGetCurrentIrpStackLocation(pIrp)->
  787. Parameters.DeviceIoControl.Type3InputBuffer = NULL;
  788. pIrp->IoStatus.Status = STATUS_CANCELLED;
  789. pIrp->IoStatus.Information = 0;
  790. UlCompleteRequest(pIrp, g_UlPriorityBoost);
  791. pIrp = NULL;
  792. }
  793. } // while (IsListEmpty(&pRequest->IrpHead) == FALSE)
  794. } // UlCancelRequestIo
  795. /***************************************************************************++
  796. Routine Description:
  797. Frees all resources associated with the specified UL_INTERNAL_REQUEST.
  798. Arguments:
  799. pRequest - Supplies the UL_INTERNAL_REQUEST to free.
  800. --***************************************************************************/
  801. VOID
  802. UlpFreeHttpRequest(
  803. IN PUL_WORK_ITEM pWorkItem
  804. )
  805. {
  806. PUL_INTERNAL_REQUEST pRequest;
  807. PLIST_ENTRY pEntry;
  808. ULONG i;
  809. NTSTATUS Status;
  810. //
  811. // Sanity check.
  812. //
  813. PAGED_CODE();
  814. pRequest = CONTAINING_RECORD(
  815. pWorkItem,
  816. UL_INTERNAL_REQUEST,
  817. WorkItem
  818. );
  819. //
  820. // our opaque id should already be free'd (UlDeleteOpaqueIds)
  821. //
  822. ASSERT(HTTP_IS_NULL_ID(&pRequest->RequestId));
  823. //
  824. // free any known header buffers allocated
  825. //
  826. if (pRequest->HeadersAppended)
  827. {
  828. for (i = 0; i < HttpHeaderRequestMaximum; i++)
  829. {
  830. HTTP_HEADER_ID HeaderId = (HTTP_HEADER_ID)pRequest->HeaderIndex[i];
  831. if (HeaderId == HttpHeaderRequestMaximum)
  832. {
  833. break;
  834. }
  835. ASSERT( pRequest->HeaderValid[HeaderId] );
  836. if (pRequest->Headers[HeaderId].OurBuffer == 1)
  837. {
  838. UL_FREE_POOL(
  839. pRequest->Headers[HeaderId].pHeader,
  840. HEADER_VALUE_POOL_TAG
  841. );
  842. }
  843. }
  844. //
  845. // and any unknown header buffers allocated
  846. //
  847. while (IsListEmpty(&pRequest->UnknownHeaderList) == FALSE)
  848. {
  849. PUL_HTTP_UNKNOWN_HEADER pUnknownHeader;
  850. pEntry = RemoveHeadList(&pRequest->UnknownHeaderList);
  851. pUnknownHeader = CONTAINING_RECORD(
  852. pEntry,
  853. UL_HTTP_UNKNOWN_HEADER,
  854. List
  855. );
  856. if (pUnknownHeader->HeaderValue.OurBuffer == 1)
  857. {
  858. UL_FREE_POOL(
  859. pUnknownHeader->HeaderValue.pHeader,
  860. HEADER_VALUE_POOL_TAG
  861. );
  862. }
  863. //
  864. // Free the header structure
  865. //
  866. if (pUnknownHeader->HeaderValue.ExternalAllocated == 1)
  867. {
  868. UL_FREE_POOL(
  869. pUnknownHeader,
  870. UL_HTTP_UNKNOWN_HEADER_POOL_TAG
  871. );
  872. }
  873. }
  874. }
  875. //
  876. // there better not be any pending io, it would have been cancelled either
  877. // in UlDeleteHttpConnection or in UlDetachProcessFromAppPool .
  878. //
  879. ASSERT(IsListEmpty(&pRequest->IrpHead));
  880. //
  881. // dereferenc request buffers.
  882. //
  883. for (i = 0; i < pRequest->UsedRefBuffers; i++)
  884. {
  885. ASSERT( UL_IS_VALID_REQUEST_BUFFER(pRequest->pRefBuffers[i]) );
  886. UL_DEREFERENCE_REQUEST_BUFFER(pRequest->pRefBuffers[i]);
  887. }
  888. if (pRequest->AllocRefBuffers > 1)
  889. {
  890. UL_FREE_POOL(
  891. pRequest->pRefBuffers,
  892. UL_REF_REQUEST_BUFFER_POOL_TAG
  893. );
  894. }
  895. //
  896. // free any url that was allocated
  897. //
  898. if (pRequest->CookedUrl.pUrl != NULL)
  899. {
  900. if (pRequest->CookedUrl.pUrl != pRequest->pUrlBuffer)
  901. {
  902. UL_FREE_POOL(pRequest->CookedUrl.pUrl, URL_POOL_TAG);
  903. }
  904. }
  905. //
  906. // free any config group info
  907. //
  908. ASSERT( IS_VALID_URL_CONFIG_GROUP_INFO(&pRequest->ConfigInfo) );
  909. ASSERT( pRequest->pHttpConn );
  910. //
  911. // Perf counters
  912. // NOTE: Assumes cache & non-cache paths both go through here
  913. // NOTE: If connection is refused the pConnectionCountEntry will be NULL
  914. //
  915. if (pRequest->ConfigInfo.pSiteCounters &&
  916. pRequest->pHttpConn->pConnectionCountEntry)
  917. {
  918. PUL_SITE_COUNTER_ENTRY pCtr = pRequest->ConfigInfo.pSiteCounters;
  919. UlAddSiteCounter64(
  920. pCtr,
  921. HttpSiteCounterBytesSent,
  922. pRequest->BytesSent
  923. );
  924. UlAddSiteCounter64(
  925. pCtr,
  926. HttpSiteCounterBytesReceived,
  927. pRequest->BytesReceived
  928. );
  929. UlAddSiteCounter64(
  930. pCtr,
  931. HttpSiteCounterBytesTransfered,
  932. (pRequest->BytesSent + pRequest->BytesReceived)
  933. );
  934. }
  935. //
  936. // Release all the references from the UL_URL_CONFIG_GROUP_INFO.
  937. //
  938. UlpConfigGroupInfoRelease(&pRequest->ConfigInfo);
  939. //
  940. // release our reference to the connection
  941. //
  942. UL_DEREFERENCE_HTTP_CONNECTION( pRequest->pHttpConn );
  943. //
  944. // Free the object buffer
  945. //
  946. ASSERT(pRequest->Signature == UL_INTERNAL_REQUEST_POOL_TAG);
  947. pRequest->Signature = MAKE_FREE_TAG(UL_INTERNAL_REQUEST_POOL_TAG);
  948. DESTROY_REF_TRACE_LOG( pRequest->pTraceLog );
  949. UlPplFreeInternalRequest( pRequest );
  950. }
  951. /***************************************************************************++
  952. Routine Description:
  953. Allocates and initializes a new UL_REQUEST_BUFFER.
  954. Arguments:
  955. BufferSize - size of the new buffer in bytes
  956. --***************************************************************************/
  957. PUL_REQUEST_BUFFER
  958. UlCreateRequestBuffer(
  959. ULONG BufferSize,
  960. ULONG BufferNumber
  961. )
  962. {
  963. PUL_REQUEST_BUFFER pBuffer;
  964. BufferSize = MAX(BufferSize, DEFAULT_MAX_REQUEST_BUFFER_SIZE);
  965. if (BufferSize > DEFAULT_MAX_REQUEST_BUFFER_SIZE)
  966. {
  967. BufferSize = (ULONG) MAX(
  968. BufferSize,
  969. PAGE_SIZE - ALIGN_UP(sizeof(UL_REQUEST_BUFFER),PVOID)
  970. );
  971. pBuffer = UL_ALLOCATE_STRUCT_WITH_SPACE(
  972. NonPagedPool,
  973. UL_REQUEST_BUFFER,
  974. BufferSize,
  975. UL_REQUEST_BUFFER_POOL_TAG
  976. );
  977. }
  978. else
  979. {
  980. pBuffer = UlPplAllocateRequestBuffer();
  981. }
  982. if (pBuffer == NULL)
  983. {
  984. return NULL;
  985. }
  986. RtlZeroMemory(
  987. (PCHAR)pBuffer + sizeof(SINGLE_LIST_ENTRY),
  988. sizeof(UL_REQUEST_BUFFER) - sizeof(SINGLE_LIST_ENTRY)
  989. );
  990. pBuffer->Signature = UL_REQUEST_BUFFER_POOL_TAG;
  991. UlTrace(HTTP_IO, (
  992. "ul!UlCreateRequestBuffer buff=%p num=%d size=%d\n",
  993. pBuffer,
  994. BufferNumber,
  995. BufferSize
  996. ));
  997. pBuffer->RefCount = 1;
  998. pBuffer->AllocBytes = BufferSize;
  999. pBuffer->BufferNumber = BufferNumber;
  1000. return pBuffer;
  1001. }
  1002. /***************************************************************************++
  1003. Routine Description:
  1004. Removes a request buffer from the buffer list and destroys it.
  1005. Arguments:
  1006. pBuffer - the buffer to be deleted
  1007. --***************************************************************************/
  1008. VOID
  1009. UlFreeRequestBuffer(
  1010. PUL_REQUEST_BUFFER pBuffer
  1011. )
  1012. {
  1013. ASSERT( UL_IS_VALID_REQUEST_BUFFER( pBuffer ) );
  1014. UlTrace(HTTP_IO, (
  1015. "ul!UlFreeRequestBuffer(pBuffer = %p, Num = %d)\n",
  1016. pBuffer,
  1017. pBuffer->BufferNumber
  1018. ));
  1019. if (pBuffer->ListEntry.Flink != NULL) {
  1020. RemoveEntryList(&pBuffer->ListEntry);
  1021. pBuffer->ListEntry.Blink = pBuffer->ListEntry.Flink = NULL;
  1022. }
  1023. UL_DEREFERENCE_REQUEST_BUFFER(pBuffer);
  1024. }
  1025. //
  1026. // Private functions.
  1027. //
  1028. /***************************************************************************++
  1029. Routine Description:
  1030. Retrieves a binding set with UlBindConnectionToProcess.
  1031. Arguments:
  1032. pHttpConnection - the connection to query
  1033. pAppPool - the key to use for the lookup
  1034. Return Values:
  1035. A pointer to the bound process if one was found. NULL otherwise.
  1036. --***************************************************************************/
  1037. PUL_APP_POOL_PROCESS
  1038. UlQueryProcessBinding(
  1039. IN PUL_HTTP_CONNECTION pHttpConnection,
  1040. IN PUL_APP_POOL_OBJECT pAppPool
  1041. )
  1042. {
  1043. PUL_APOOL_PROC_BINDING pBinding;
  1044. PUL_APP_POOL_PROCESS pProcess = NULL;
  1045. KIRQL OldIrql;
  1046. //
  1047. // Sanity check
  1048. //
  1049. ASSERT( UL_IS_VALID_HTTP_CONNECTION( pHttpConnection ) );
  1050. UlAcquireSpinLock(&pHttpConnection->BindingSpinLock, &OldIrql);
  1051. pBinding = UlpFindProcBinding(pHttpConnection, pAppPool);
  1052. if (pBinding) {
  1053. pProcess = pBinding->pProcess;
  1054. }
  1055. UlReleaseSpinLock(&pHttpConnection->BindingSpinLock, OldIrql);
  1056. return pProcess;
  1057. }
  1058. /***************************************************************************++
  1059. Routine Description:
  1060. Allocates and builds a UL_APOOL_PROC_BINDING object.
  1061. Arguments:
  1062. pAppPool - the lookup key
  1063. pProcess - the binding
  1064. Return Values:
  1065. a pointer to the allocated object, or NULL on failure
  1066. --***************************************************************************/
  1067. PUL_APOOL_PROC_BINDING
  1068. UlpCreateProcBinding(
  1069. IN PUL_APP_POOL_OBJECT pAppPool,
  1070. IN PUL_APP_POOL_PROCESS pProcess
  1071. )
  1072. {
  1073. PUL_APOOL_PROC_BINDING pBinding;
  1074. ASSERT( pAppPool->NumberActiveProcesses > 1 );
  1075. //
  1076. // CODEWORK: lookaside
  1077. //
  1078. pBinding = UL_ALLOCATE_STRUCT(
  1079. NonPagedPool,
  1080. UL_APOOL_PROC_BINDING,
  1081. UL_APOOL_PROC_BINDING_POOL_TAG
  1082. );
  1083. if (pBinding) {
  1084. pBinding->Signature = UL_APOOL_PROC_BINDING_POOL_TAG;
  1085. pBinding->pAppPool = pAppPool;
  1086. pBinding->pProcess = pProcess;
  1087. UlTrace(ROUTING, (
  1088. "ul!UlpCreateProcBinding(\n"
  1089. " pAppPool = %p\n"
  1090. " pProcess = %p )\n"
  1091. " pBinding = %p\n",
  1092. pAppPool,
  1093. pProcess,
  1094. pBinding
  1095. ));
  1096. }
  1097. return pBinding;
  1098. }
  1099. /***************************************************************************++
  1100. Routine Description:
  1101. Gets rid of a proc binding
  1102. Arguments:
  1103. pBinding - the binding to get rid of
  1104. --***************************************************************************/
  1105. VOID
  1106. UlpFreeProcBinding(
  1107. IN PUL_APOOL_PROC_BINDING pBinding
  1108. )
  1109. {
  1110. UL_FREE_POOL_WITH_SIG(pBinding, UL_APOOL_PROC_BINDING_POOL_TAG);
  1111. }
  1112. /***************************************************************************++
  1113. Routine Description:
  1114. Searches a connection's list of bindings for one that has the right
  1115. app pool key
  1116. Arguments:
  1117. pHttpConnection - the connection to search
  1118. pAppPool - the key
  1119. Return Values:
  1120. The binding if found or NULL if not found.
  1121. --***************************************************************************/
  1122. PUL_APOOL_PROC_BINDING
  1123. UlpFindProcBinding(
  1124. IN PUL_HTTP_CONNECTION pHttpConnection,
  1125. IN PUL_APP_POOL_OBJECT pAppPool
  1126. )
  1127. {
  1128. PLIST_ENTRY pEntry;
  1129. PUL_APOOL_PROC_BINDING pBinding = NULL;
  1130. //
  1131. // Sanity check
  1132. //
  1133. ASSERT( UL_IS_VALID_HTTP_CONNECTION(pHttpConnection) );
  1134. pEntry = pHttpConnection->BindingHead.Flink;
  1135. while (pEntry != &pHttpConnection->BindingHead) {
  1136. pBinding = CONTAINING_RECORD(
  1137. pEntry,
  1138. UL_APOOL_PROC_BINDING,
  1139. BindingEntry
  1140. );
  1141. ASSERT( IS_VALID_PROC_BINDING(pBinding) );
  1142. if (pBinding->pAppPool == pAppPool) {
  1143. //
  1144. // got it!
  1145. //
  1146. break;
  1147. }
  1148. pEntry = pEntry->Flink;
  1149. }
  1150. return pBinding;
  1151. }
  1152. /***************************************************************************++
  1153. Routine Description:
  1154. Removes an HTTP request from all lists and cleans up it's opaque id.
  1155. Arguments:
  1156. pRequest - the request to be unlinked
  1157. --***************************************************************************/
  1158. VOID
  1159. UlUnlinkHttpRequest(
  1160. IN PUL_INTERNAL_REQUEST pRequest
  1161. )
  1162. {
  1163. //
  1164. // if we got far enough to deliver the request then
  1165. // unlink it from the app pool. this needs to happen here because the
  1166. // queue'd IRPs keep references to the UL_INTERNAL_REQUEST objects.
  1167. // this kicks their references off and allows them to delete.
  1168. //
  1169. if (pRequest->ConfigInfo.pAppPool)
  1170. {
  1171. UlUnlinkRequestFromProcess(pRequest->ConfigInfo.pAppPool, pRequest);
  1172. }
  1173. //
  1174. // cancel i/o
  1175. //
  1176. if (pRequest->IrpsPending)
  1177. {
  1178. UlCancelRequestIo(pRequest);
  1179. }
  1180. else
  1181. {
  1182. //
  1183. // Mark the request as InCleanup, so additional IRPs
  1184. // on the request will not be queued.
  1185. //
  1186. // Normally UlCancelRequestIo sets this flag, but we
  1187. // have to do it here since we're optimizing that
  1188. // call away.
  1189. //
  1190. pRequest->InCleanup = 1;
  1191. }
  1192. //
  1193. // delete its opaque id
  1194. //
  1195. if (HTTP_IS_NULL_ID(&pRequest->RequestId) == FALSE)
  1196. {
  1197. UlFreeRequestId(pRequest);
  1198. HTTP_SET_NULL_ID(&pRequest->RequestId);
  1199. //
  1200. // it is still referenced by this connection
  1201. //
  1202. ASSERT(pRequest->RefCount > 1);
  1203. UL_DEREFERENCE_INTERNAL_REQUEST(pRequest);
  1204. }
  1205. //
  1206. // deref it
  1207. //
  1208. UL_DEREFERENCE_INTERNAL_REQUEST(pRequest);
  1209. }
  1210. //
  1211. // Following code has been implemented for Global & Site specific connection
  1212. // limits feature. If enforced, incoming connections get refused when they
  1213. // exceed the existing limit. Control channel & config group (re)sets this
  1214. // values whereas httprcv and sendresponse updates the limits for incoming
  1215. // requests & connections. A seperate connection_count_entry structure keeps
  1216. // track of the limits per site. Global limits are tracked by the global
  1217. // variables g_MaxConnections & g_CurrentConnections same API has been used
  1218. // for both purposes.
  1219. //
  1220. /***************************************************************************++
  1221. Routine Description:
  1222. Allocates a connection count entry which will hold the site specific
  1223. connection count info. Get called by cgroup when Config group is
  1224. attempting to allocate a connection count entry.
  1225. Arguments:
  1226. pConfigGroup - To receive the newly allocated count entry
  1227. MaxConnections - The maximum allowed connections
  1228. --***************************************************************************/
  1229. NTSTATUS
  1230. UlCreateConnectionCountEntry(
  1231. IN OUT PUL_CONFIG_GROUP_OBJECT pConfigGroup,
  1232. IN ULONG MaxConnections
  1233. )
  1234. {
  1235. PUL_CONNECTION_COUNT_ENTRY pEntry;
  1236. // Sanity check.
  1237. PAGED_CODE();
  1238. ASSERT(IS_VALID_CONFIG_GROUP(pConfigGroup));
  1239. // Alloc new struct from Paged Pool
  1240. pEntry = UL_ALLOCATE_STRUCT(
  1241. PagedPool,
  1242. UL_CONNECTION_COUNT_ENTRY,
  1243. UL_CONNECTION_COUNT_ENTRY_POOL_TAG
  1244. );
  1245. if (!pEntry)
  1246. {
  1247. UlTrace(LIMITS,
  1248. ("Http!UlCreateConnectionCountEntry: OutOfMemory pConfigGroup %p\n",
  1249. pConfigGroup
  1250. ));
  1251. return STATUS_NO_MEMORY;
  1252. }
  1253. pEntry->Signature = UL_CONNECTION_COUNT_ENTRY_POOL_TAG;
  1254. pEntry->RefCount = 1;
  1255. pEntry->MaxConnections = MaxConnections;
  1256. pEntry->CurConnections = 0;
  1257. // Update cgroup pointer
  1258. ASSERT( pConfigGroup->pConnectionCountEntry == NULL );
  1259. pConfigGroup->pConnectionCountEntry = pEntry;
  1260. UlTrace(LIMITS,
  1261. ("Http!UlCreateConnectionCountEntry: pNewEntry %p, pConfigGroup %p, Max %d\n",
  1262. pEntry,
  1263. pConfigGroup,
  1264. MaxConnections
  1265. ));
  1266. return STATUS_SUCCESS;
  1267. } // UlCreateConnectionCountEntry
  1268. /***************************************************************************++
  1269. Routine Description:
  1270. increments the refcount for ConnectionCountEntry.
  1271. Arguments:
  1272. pEntry - the object to increment.
  1273. --***************************************************************************/
  1274. VOID
  1275. UlReferenceConnectionCountEntry(
  1276. IN PUL_CONNECTION_COUNT_ENTRY pEntry
  1277. REFERENCE_DEBUG_FORMAL_PARAMS
  1278. )
  1279. {
  1280. LONG refCount;
  1281. //
  1282. // Sanity check.
  1283. //
  1284. PAGED_CODE();
  1285. ASSERT( IS_VALID_CONNECTION_COUNT_ENTRY(pEntry) );
  1286. refCount = InterlockedIncrement( &pEntry->RefCount );
  1287. //
  1288. // Tracing.
  1289. //
  1290. WRITE_REF_TRACE_LOG(
  1291. g_pConnectionCountTraceLog,
  1292. REF_ACTION_REFERENCE_CONNECTION_COUNT_ENTRY,
  1293. refCount,
  1294. pEntry,
  1295. pFileName,
  1296. LineNumber
  1297. );
  1298. UlTrace(
  1299. REFCOUNT,
  1300. ("Http!UlReferenceConnectionCountEntry pEntry=%p refcount=%d\n",
  1301. pEntry,
  1302. refCount
  1303. ));
  1304. } // UlReferenceConnectionCountEntry
  1305. /***************************************************************************++
  1306. Routine Description:
  1307. decrements the refcount. if it hits 0, destruct's ConnectionCountEntry
  1308. Arguments:
  1309. pEntry - the object to decrement.
  1310. --***************************************************************************/
  1311. VOID
  1312. UlDereferenceConnectionCountEntry(
  1313. IN PUL_CONNECTION_COUNT_ENTRY pEntry
  1314. REFERENCE_DEBUG_FORMAL_PARAMS
  1315. )
  1316. {
  1317. LONG refCount;
  1318. NTSTATUS Status;
  1319. //
  1320. // Sanity check.
  1321. //
  1322. PAGED_CODE();
  1323. ASSERT( IS_VALID_CONNECTION_COUNT_ENTRY(pEntry) );
  1324. refCount = InterlockedDecrement( &pEntry->RefCount );
  1325. //
  1326. // Tracing.
  1327. //
  1328. WRITE_REF_TRACE_LOG(
  1329. g_pConnectionCountTraceLog,
  1330. REF_ACTION_DEREFERENCE_CONNECTION_COUNT_ENTRY,
  1331. refCount,
  1332. pEntry,
  1333. pFileName,
  1334. LineNumber
  1335. );
  1336. UlTrace(
  1337. REFCOUNT,
  1338. ("Http!UlDereferenceConnectionCountEntry pEntry=%p refcount=%d\n",
  1339. pEntry,
  1340. refCount
  1341. ));
  1342. //
  1343. // Cleanup the memory and do few checks !
  1344. //
  1345. if ( refCount == 0 )
  1346. {
  1347. // Make sure no connection on the site
  1348. ASSERT( 0 == pEntry->CurConnections );
  1349. UlTrace(
  1350. LIMITS,
  1351. ("Http!UlDereferenceConnectionCountEntry: Removing pEntry=%p\n",
  1352. pEntry
  1353. ));
  1354. // Release memory
  1355. UL_FREE_POOL_WITH_SIG(pEntry,UL_CONNECTION_COUNT_ENTRY_POOL_TAG);
  1356. }
  1357. } // UlDereferenceConnectionCountEntry
  1358. /***************************************************************************++
  1359. Routine Description:
  1360. This
  1361. function set the maximum limit. Maximum allowed number of connections
  1362. at any time by the active control channel.
  1363. Arguments:
  1364. MaxConnections - Maximum allowed number of connections
  1365. Return Value:
  1366. Old Max Connection count
  1367. --***************************************************************************/
  1368. ULONG
  1369. UlSetMaxConnections(
  1370. IN OUT PULONG pCurMaxConnection,
  1371. IN ULONG NewMaxConnection
  1372. )
  1373. {
  1374. ULONG OldMaxConnection;
  1375. UlTrace(LIMITS,
  1376. ("Http!UlSetMaxConnections pCurMaxConnection=%p NewMaxConnection=%d\n",
  1377. pCurMaxConnection,
  1378. NewMaxConnection
  1379. ));
  1380. //
  1381. // By setting this we are not forcing the existing connections to
  1382. // termination but this number will be effective for all newcoming
  1383. // connections, as soon as the atomic operation completed.
  1384. //
  1385. OldMaxConnection = (ULONG) InterlockedExchange((LONG *) pCurMaxConnection,
  1386. (LONG) NewMaxConnection
  1387. );
  1388. return OldMaxConnection;
  1389. } // UlSetMaxConnections
  1390. /***************************************************************************++
  1391. Routine Description:
  1392. Control channel uses this function to set or reset the global connection
  1393. limits.
  1394. --***************************************************************************/
  1395. VOID
  1396. UlSetGlobalConnectionLimit(
  1397. IN ULONG Limit
  1398. )
  1399. {
  1400. UlSetMaxConnections( &g_MaxConnections, Limit );
  1401. UlTrace(LIMITS,("Http!UlSetGlobalConnectionLimit: To %d\n", Limit));
  1402. } // ULSetGlobalConnectionLimit
  1403. /***************************************************************************++
  1404. Routine Description:
  1405. Control channel uses this function to initialize the global connection
  1406. limits. Assuming the existince of one and only one active control channel
  1407. this globals get set only once during init. But could be set again later
  1408. because of a reconfig.
  1409. --***************************************************************************/
  1410. NTSTATUS
  1411. UlInitGlobalConnectionLimits(
  1412. VOID
  1413. )
  1414. {
  1415. ASSERT(!g_InitGlobalConnections);
  1416. if (!g_InitGlobalConnections)
  1417. {
  1418. g_MaxConnections = HTTP_LIMIT_INFINITE;
  1419. g_CurrentConnections = 0;
  1420. UlTrace(LIMITS,
  1421. ("Http!UlInitGlobalConnectionLimits: Init g_MaxConnections %d,"
  1422. "g_CurrentConnections %d\n",
  1423. g_MaxConnections,
  1424. g_CurrentConnections
  1425. ));
  1426. g_InitGlobalConnections = TRUE;
  1427. }
  1428. return STATUS_SUCCESS;
  1429. } // UlInitGlobalConnectionLimits
  1430. /***************************************************************************++
  1431. Routine Description:
  1432. Wrapper around the Accept Connection for global connections
  1433. --***************************************************************************/
  1434. BOOLEAN
  1435. UlAcceptGlobalConnection(
  1436. VOID
  1437. )
  1438. {
  1439. return UlAcceptConnection( &g_MaxConnections, &g_CurrentConnections );
  1440. } // UlAcceptGlobalConnection
  1441. /***************************************************************************++
  1442. Routine Description:
  1443. This function checks if we are allowed to accept the incoming connection
  1444. based on the number enforced by the control channel.
  1445. Return value:
  1446. Decision for the newcoming connection either ACCEPT or REJECT as boolean
  1447. --***************************************************************************/
  1448. BOOLEAN
  1449. UlAcceptConnection(
  1450. IN PULONG pMaxConnection,
  1451. IN OUT PULONG pCurConnection
  1452. )
  1453. {
  1454. ULONG LocalCur;
  1455. ULONG LocalCurPlusOne;
  1456. ULONG LocalMax;
  1457. do
  1458. {
  1459. //
  1460. // Capture the Max & Cur. Do the comparison. If in the limit
  1461. // attempt to increment the connection count by ensuring nobody
  1462. // else did it before us.
  1463. //
  1464. LocalMax = *((volatile ULONG *) pMaxConnection);
  1465. LocalCur = *((volatile ULONG *) pCurConnection);
  1466. //
  1467. // Its greater than or equal because Max may get updated to
  1468. // a smaller number on-the-fly and we end up having current
  1469. // connections greater than the maximum allowed.
  1470. // NOTE: HTTP_LIMIT_INFINITE has been picked as (ULONG)-1 so
  1471. // following comparison won't reject for the infinite case.
  1472. //
  1473. if ( LocalCur >= LocalMax )
  1474. {
  1475. //
  1476. // We are already at the limit refuse it.
  1477. //
  1478. UlTrace(LIMITS,
  1479. ("Http!UlAcceptConnection REFUSE pCurConnection=%p[%d]"
  1480. "pMaxConnection=%p[%d]\n",
  1481. pCurConnection,LocalCur,
  1482. pMaxConnection,LocalMax
  1483. ));
  1484. return FALSE;
  1485. }
  1486. //
  1487. // Either the limit was infinite or conn count was not exceeding
  1488. // the limit. Lets attempt to increment the count and accept the
  1489. // connection in the while statement.
  1490. //
  1491. LocalCurPlusOne = LocalCur + 1;
  1492. }
  1493. while ( LocalCur != (ULONG) InterlockedCompareExchange(
  1494. (LONG *) pCurConnection,
  1495. (LONG) LocalCurPlusOne,
  1496. (LONG) LocalCur
  1497. ) );
  1498. //
  1499. // Successfully incremented the counter. Let it go with success.
  1500. //
  1501. UlTrace(LIMITS,
  1502. ("Http!UlAcceptConnection ACCEPT pCurConnection=%p[%d]"
  1503. "pMaxConnection=%p[%d]\n",
  1504. pCurConnection,LocalCur,
  1505. pMaxConnection,LocalMax
  1506. ));
  1507. return TRUE;
  1508. } // UlAcceptConnection
  1509. /***************************************************************************++
  1510. Routine Description:
  1511. Everytime a disconnection happens we will decrement the count here.
  1512. Return Value:
  1513. The newly decremented value
  1514. --***************************************************************************/
  1515. LONG
  1516. UlDecrementConnections(
  1517. IN OUT PULONG pCurConnection
  1518. )
  1519. {
  1520. LONG NewConnectionCount;
  1521. NewConnectionCount = InterlockedDecrement( (LONG *) pCurConnection );
  1522. ASSERT( NewConnectionCount >= 0 );
  1523. return NewConnectionCount;
  1524. } // UlDecrementConnections
  1525. /***************************************************************************++
  1526. Routine Description:
  1527. For cache & non-cache hits this function get called. Connection resource
  1528. has assumed to be acquired at this time. The function decide to accept or
  1529. reject the request by looking at the corresponding count entries.
  1530. Arguments:
  1531. pConnection - For getting the previous site's connection count entry
  1532. pConfigInfo - Holds a pointer to newly received request's site's
  1533. connection count entry.
  1534. Return Value:
  1535. Shows reject or accept
  1536. --***************************************************************************/
  1537. BOOLEAN
  1538. UlCheckSiteConnectionLimit(
  1539. IN OUT PUL_HTTP_CONNECTION pConnection,
  1540. IN OUT PUL_URL_CONFIG_GROUP_INFO pConfigInfo
  1541. )
  1542. {
  1543. BOOLEAN Accept;
  1544. PUL_CONNECTION_COUNT_ENTRY pConEntry;
  1545. PUL_CONNECTION_COUNT_ENTRY pCIEntry;
  1546. if (pConfigInfo->pMaxConnections == NULL || pConfigInfo->pConnectionCountEntry == NULL)
  1547. {
  1548. //
  1549. // No connection count entry for the new request perhaps WAS never
  1550. // set this before otherwise its a problem.
  1551. //
  1552. UlTrace(LIMITS,
  1553. ("Http!UlCheckSiteConnectionLimit: NO LIMIT pConnection=%p pConfigInfo=%p\n",
  1554. pConnection,
  1555. pConfigInfo
  1556. ));
  1557. return TRUE;
  1558. }
  1559. ASSERT(IS_VALID_CONNECTION_COUNT_ENTRY(pConfigInfo->pConnectionCountEntry));
  1560. pCIEntry = pConfigInfo->pConnectionCountEntry;
  1561. pConEntry = pConnection->pConnectionCountEntry;
  1562. Accept = FALSE;
  1563. //
  1564. // Make a check on the connection limit of the site. Refuse the request
  1565. // if the limit is exceded.
  1566. //
  1567. if (pConEntry)
  1568. {
  1569. ASSERT(IS_VALID_CONNECTION_COUNT_ENTRY(pConEntry));
  1570. //
  1571. // For consecutive requests we decrement the previous site's connection count
  1572. // before proceeding to the decision on the newcoming request,if the two sides
  1573. // are not same.That means we assume this connection on site x until (if ever)
  1574. // a request changes this to site y. Naturally until the first request arrives
  1575. // and successfully parsed, the connection does not count to any specific site
  1576. //
  1577. if (pConEntry != pCIEntry)
  1578. {
  1579. UlDecrementConnections(&pConEntry->CurConnections);
  1580. DEREFERENCE_CONNECTION_COUNT_ENTRY(pConEntry);
  1581. //
  1582. // We do not increment the connection here yet, since the AcceptConnection
  1583. // will decide and do that.
  1584. //
  1585. REFERENCE_CONNECTION_COUNT_ENTRY(pCIEntry);
  1586. pConnection->pConnectionCountEntry = pCIEntry;
  1587. }
  1588. else
  1589. {
  1590. //
  1591. // There was an old entry, that means this connection already got through.
  1592. // And the entry hasn't been changed with this new request.
  1593. // No need to check again, our design is not forcing existing connections
  1594. // to disconnect.
  1595. //
  1596. return TRUE;
  1597. }
  1598. }
  1599. else
  1600. {
  1601. REFERENCE_CONNECTION_COUNT_ENTRY(pCIEntry);
  1602. pConnection->pConnectionCountEntry = pCIEntry;
  1603. }
  1604. Accept = UlAcceptConnection(
  1605. &pConnection->pConnectionCountEntry->MaxConnections,
  1606. &pConnection->pConnectionCountEntry->CurConnections
  1607. );
  1608. if (Accept == FALSE)
  1609. {
  1610. // We are going to refuse. Let our ref & refcount go away
  1611. // on the connection etry to prevent the possible incorrect
  1612. // decrement in the UlConnectionDestroyedWorker. If refused
  1613. // current connection hasn't been incremented in the accept
  1614. // connection. Perf counters also depends on the fact that
  1615. // pConnectionCountEntry will be Null when con got refused
  1616. DEREFERENCE_CONNECTION_COUNT_ENTRY(pConnection->pConnectionCountEntry);
  1617. pConnection->pConnectionCountEntry = NULL;
  1618. }
  1619. return Accept;
  1620. } // UlCheckSiteConnectionLimit
  1621. #ifdef REUSE_CONNECTION_OPAQUE_ID
  1622. /***************************************************************************++
  1623. Routine Description:
  1624. Allocate a request opaque ID.
  1625. Return Value:
  1626. NT_SUCCESS
  1627. --***************************************************************************/
  1628. NTSTATUS
  1629. UlAllocateRequestId(
  1630. IN PUL_INTERNAL_REQUEST pRequest
  1631. )
  1632. {
  1633. PUL_HTTP_CONNECTION pConnection;
  1634. KIRQL OldIrql;
  1635. PAGED_CODE();
  1636. pConnection = pRequest->pHttpConn;
  1637. UlAcquireSpinLock(&pConnection->RequestIdSpinLock, &OldIrql);
  1638. pConnection->pRequestIdContext = pRequest;
  1639. UlReleaseSpinLock(&pConnection->RequestIdSpinLock, OldIrql);
  1640. pRequest->RequestId = pConnection->ConnectionId;
  1641. return STATUS_SUCCESS;
  1642. }
  1643. /***************************************************************************++
  1644. Routine Description:
  1645. Free a request opaque ID.
  1646. Return Value:
  1647. VOID
  1648. --***************************************************************************/
  1649. VOID
  1650. UlFreeRequestId(
  1651. IN PUL_INTERNAL_REQUEST pRequest
  1652. )
  1653. {
  1654. PUL_HTTP_CONNECTION pConnection;
  1655. KIRQL OldIrql;
  1656. PAGED_CODE();
  1657. pConnection = pRequest->pHttpConn;
  1658. UlAcquireSpinLock(&pConnection->RequestIdSpinLock, &OldIrql);
  1659. pConnection->pRequestIdContext = NULL;
  1660. UlReleaseSpinLock(&pConnection->RequestIdSpinLock, OldIrql);
  1661. return;
  1662. }
  1663. /***************************************************************************++
  1664. Routine Description:
  1665. Get a request from the connection opaque ID.
  1666. Return Value:
  1667. PUL_INTERNAL_REQUEST
  1668. --***************************************************************************/
  1669. PUL_INTERNAL_REQUEST
  1670. UlGetRequestFromId(
  1671. IN HTTP_REQUEST_ID RequestId
  1672. )
  1673. {
  1674. PUL_HTTP_CONNECTION pConnection;
  1675. PUL_INTERNAL_REQUEST pRequest;
  1676. KIRQL OldIrql;
  1677. PAGED_CODE();
  1678. pConnection = UlGetConnectionFromId(RequestId);
  1679. if (pConnection != NULL)
  1680. {
  1681. UlAcquireSpinLock(&pConnection->RequestIdSpinLock, &OldIrql);
  1682. pRequest = pConnection->pRequestIdContext;
  1683. if (pRequest != NULL)
  1684. {
  1685. UL_REFERENCE_INTERNAL_REQUEST(pRequest);
  1686. }
  1687. UlReleaseSpinLock(&pConnection->RequestIdSpinLock, OldIrql);
  1688. UL_DEREFERENCE_HTTP_CONNECTION(pConnection);
  1689. return pRequest;
  1690. }
  1691. return NULL;
  1692. }
  1693. #endif