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.

1181 lines
31 KiB

  1. /*++
  2. Copyright (c) 1999-2002 Microsoft Corporation
  3. Module Name:
  4. control.c
  5. Abstract:
  6. This module implements the UL control channel.
  7. Author:
  8. Keith Moore (keithmo) 09-Feb-1999
  9. Revision History:
  10. --*/
  11. #include "precomp.h"
  12. #include "controlp.h"
  13. //
  14. // Private constants.
  15. //
  16. //
  17. // Private globals.
  18. //
  19. LIST_ENTRY g_ControlChannelListHead = {NULL,NULL};
  20. LONG g_ControlChannelCount = 0;
  21. BOOLEAN g_InitControlChannelCalled = FALSE;
  22. #ifdef ALLOC_PRAGMA
  23. #pragma alloc_text( INIT, UlInitializeControlChannel )
  24. #pragma alloc_text( PAGE, UlTerminateControlChannel )
  25. #pragma alloc_text( PAGE, UlCreateControlChannel )
  26. #pragma alloc_text( PAGE, UlCloseControlChannel )
  27. #endif // ALLOC_PRAGMA
  28. #if 0
  29. NOT PAGEABLE -- UlQueryFilterChannel
  30. #endif
  31. //
  32. // Public functions.
  33. //
  34. /***************************************************************************++
  35. Routine Description:
  36. Performs global initialization of this module.
  37. Return Value:
  38. NTSTATUS - Completion status.
  39. --***************************************************************************/
  40. NTSTATUS
  41. UlInitializeControlChannel(
  42. VOID
  43. )
  44. {
  45. if (!g_InitControlChannelCalled)
  46. {
  47. InitializeListHead(&g_ControlChannelListHead);
  48. UlInitializePushLock(
  49. &g_pUlNonpagedData->ControlChannelPushLock,
  50. "ControlChannelPushLock",
  51. 0,
  52. UL_CONTROL_CHANNEL_PUSHLOCK_TAG
  53. );
  54. g_InitControlChannelCalled = TRUE;
  55. }
  56. return STATUS_SUCCESS;
  57. } // UlInitializeControlChannel
  58. /***************************************************************************++
  59. Routine Description:
  60. Performs global termination of this module.
  61. --***************************************************************************/
  62. VOID
  63. UlTerminateControlChannel(
  64. VOID
  65. )
  66. {
  67. if (g_InitControlChannelCalled)
  68. {
  69. ASSERT( IsListEmpty( &g_ControlChannelListHead )) ;
  70. ASSERT( 0 == g_ControlChannelCount );
  71. UlDeletePushLock(
  72. &g_pUlNonpagedData->ControlChannelPushLock
  73. );
  74. g_InitControlChannelCalled = FALSE;
  75. }
  76. } // UlTerminateControlChannel
  77. /***************************************************************************++
  78. Routine Description:
  79. Opens a control channel.
  80. Arguments:
  81. pControlChannel - Receives a pointer to the newly created control
  82. channel if successful.
  83. Return Value:
  84. NTSTATUS - Completion status.
  85. --***************************************************************************/
  86. NTSTATUS
  87. UlCreateControlChannel(
  88. OUT PUL_CONTROL_CHANNEL *ppControlChannel
  89. )
  90. {
  91. PUL_CONTROL_CHANNEL pControlChannel;
  92. //
  93. // Sanity check.
  94. //
  95. PAGED_CODE();
  96. pControlChannel = UL_ALLOCATE_STRUCT(
  97. NonPagedPool,
  98. UL_CONTROL_CHANNEL,
  99. UL_CONTROL_CHANNEL_POOL_TAG
  100. );
  101. if (pControlChannel == NULL)
  102. return STATUS_NO_MEMORY;
  103. RtlZeroMemory(pControlChannel, sizeof(*pControlChannel));
  104. pControlChannel->Signature = UL_CONTROL_CHANNEL_POOL_TAG;
  105. pControlChannel->State = HttpEnabledStateInactive;
  106. pControlChannel->RefCount = 1;
  107. // Init Site Counter List info
  108. InitializeListHead( &pControlChannel->SiteCounterHead );
  109. pControlChannel->SiteCounterCount = 0;
  110. UlInitializeNotifyHead(
  111. &pControlChannel->ConfigGroupHead,
  112. &g_pUlNonpagedData->ConfigGroupResource
  113. );
  114. // No Qos limit as default
  115. pControlChannel->MaxBandwidth = HTTP_LIMIT_INFINITE;
  116. InitializeListHead( &pControlChannel->FlowListHead );
  117. // No binary logging yet.
  118. pControlChannel->BinaryLoggingConfig.LoggingEnabled = FALSE;
  119. // TODO: Pick up default Connection Timeout Limits
  120. // Init process count & demand start default
  121. pControlChannel->DemandStartThreshold = DEFAULT_DEMAND_START_THRESHOLD;
  122. pControlChannel->AppPoolProcessCount = 0;
  123. // This will be set when the CleanUp Irp called on the associated
  124. // file object.
  125. pControlChannel->InCleanUp = 0;
  126. // Add this to the global list of channels
  127. UlAcquirePushLockExclusive(
  128. &g_pUlNonpagedData->ControlChannelPushLock
  129. );
  130. InsertHeadList(
  131. &g_ControlChannelListHead,
  132. &pControlChannel->ControlChannelListEntry
  133. );
  134. g_ControlChannelCount++;
  135. ASSERT(g_ControlChannelCount >= 1);
  136. UlReleasePushLockExclusive(
  137. &g_pUlNonpagedData->ControlChannelPushLock
  138. );
  139. WRITE_REF_TRACE_LOG(
  140. g_pControlChannelTraceLog,
  141. REF_ACTION_CREATE_CONTROL_CHANNEL,
  142. pControlChannel->RefCount,
  143. pControlChannel,
  144. __FILE__,
  145. __LINE__
  146. );
  147. // Set the callers variable
  148. *ppControlChannel = pControlChannel;
  149. return STATUS_SUCCESS;
  150. } // UlCreateControlChannel
  151. /***************************************************************************++
  152. Routine Description:
  153. When the last handle on the associated file object is closed, IoManager
  154. sends the CleanUp Irp and we come here and;
  155. Mark the control channel in clean-up.
  156. An extra refcount on the control channel still stays intact until close.
  157. The marked control channel stays on the list of control channels.
  158. After this point on, it is impossible for a server app to add a cgroup
  159. to this control channel.
  160. Arguments:
  161. pControlChannel - Supplies the control channel.
  162. Return Value:
  163. NTSTATUS - Completion status.
  164. --***************************************************************************/
  165. VOID
  166. UlCleanUpControlChannel(
  167. IN PUL_CONTROL_CHANNEL pControlChannel
  168. )
  169. {
  170. //
  171. // Sanity check.
  172. //
  173. PAGED_CODE();
  174. ASSERT(pControlChannel);
  175. //
  176. // Acquire the lock and find the cchannel.
  177. //
  178. VERIFY_CONTROL_CHANNEL(pControlChannel);
  179. //
  180. // Mark this control channel being cleaned-up so that we
  181. // won't be adding new cgroups to this channel anymore.
  182. //
  183. pControlChannel->InCleanUp = TRUE;
  184. WRITE_REF_TRACE_LOG(
  185. g_pControlChannelTraceLog,
  186. REF_ACTION_CLEANUP_CONTROL_CHANNEL,
  187. pControlChannel->RefCount,
  188. pControlChannel,
  189. __FILE__,
  190. __LINE__
  191. );
  192. //
  193. // NOTE: We will hold on to the last ref on control channel
  194. // NOTE: a little bit more, until the close iotcl is called
  195. //
  196. } // UlCleanUpControlChannel
  197. /***************************************************************************++
  198. Routine Description:
  199. Closes a control channel.
  200. When the total refcount on the associated file object hits zero.
  201. IoManager sends the close Irp and we come here and .
  202. Orphan the cgroups belong to this control channel.
  203. Remove the possibly existings global flow for the bandwidth throttling.
  204. Drop the last ref on the control channel and free it up.
  205. Arguments:
  206. pControlChannel - Supplies the control channel to be closed.
  207. --***************************************************************************/
  208. VOID
  209. UlCloseControlChannel(
  210. IN PUL_CONTROL_CHANNEL pControlChannel
  211. )
  212. {
  213. //
  214. // Sanity check.
  215. //
  216. PAGED_CODE();
  217. ASSERT(pControlChannel);
  218. //
  219. // Acquire the lock and find the cchannel.
  220. //
  221. VERIFY_CONTROL_CHANNEL(pControlChannel);
  222. ASSERT(TRUE == pControlChannel->InCleanUp);
  223. //
  224. // Free all the orphaned config groups.
  225. //
  226. UlNotifyAllEntries(
  227. &UlNotifyOrphanedConfigGroup,
  228. &pControlChannel->ConfigGroupHead,
  229. NULL
  230. );
  231. //
  232. // Remove QoS flows if they exist.
  233. //
  234. if (!IsListEmpty(&pControlChannel->FlowListHead))
  235. {
  236. UlTcRemoveFlows(pControlChannel, TRUE);
  237. }
  238. //
  239. // Remove from the list of control channels.
  240. //
  241. UlAcquirePushLockExclusive(
  242. &g_pUlNonpagedData->ControlChannelPushLock
  243. );
  244. RemoveEntryList(&pControlChannel->ControlChannelListEntry);
  245. pControlChannel->ControlChannelListEntry.Flink = NULL;
  246. ASSERT(g_ControlChannelCount >= 1);
  247. g_ControlChannelCount--;
  248. UlReleasePushLockExclusive(
  249. &g_pUlNonpagedData->ControlChannelPushLock
  250. );
  251. WRITE_REF_TRACE_LOG(
  252. g_pControlChannelTraceLog,
  253. REF_ACTION_CLOSE_CONTROL_CHANNEL,
  254. pControlChannel->RefCount,
  255. pControlChannel,
  256. __FILE__,
  257. __LINE__
  258. );
  259. //
  260. // Close control channel does not wait on individual cgroups
  261. // to go away. While an already parsed and routed request
  262. // holding a pointer to control channel we cannot go away.
  263. // We should wait until all the cgroups releases its
  264. // references to us. Remove the final reference so that we
  265. // can get cleaned up.
  266. // Because requests may still be in flight, the site counter
  267. // entries may still be around and on the control channel.
  268. //
  269. DEREFERENCE_CONTROL_CHANNEL(pControlChannel);
  270. } // UlCloseControlChannel
  271. /***************************************************************************++
  272. Routine Description:
  273. Sets control channel information.
  274. Arguments:
  275. Return Value:
  276. NTSTATUS - Completion status.
  277. --***************************************************************************/
  278. NTSTATUS
  279. UlSetControlChannelInformation(
  280. IN PUL_CONTROL_CHANNEL pControlChannel,
  281. IN HTTP_CONTROL_CHANNEL_INFORMATION_CLASS InformationClass,
  282. IN PVOID pControlChannelInformation,
  283. IN ULONG Length,
  284. IN KPROCESSOR_MODE RequestorMode
  285. )
  286. {
  287. NTSTATUS Status = STATUS_SUCCESS;
  288. HTTP_BANDWIDTH_LIMIT NewMaxBandwidth;
  289. HTTP_CONTROL_CHANNEL_BINARY_LOGGING LoggingInfo;
  290. HTTP_CONTROL_CHANNEL_TIMEOUT_LIMIT TimeoutInfo;
  291. HTTP_ENABLED_STATE NewControlChannelState;
  292. UNREFERENCED_PARAMETER(Length);
  293. //
  294. // Sanity check.
  295. //
  296. PAGED_CODE();
  297. //
  298. // no buffer?
  299. //
  300. ASSERT(IS_VALID_CONTROL_CHANNEL(pControlChannel));
  301. ASSERT(NULL != pControlChannelInformation);
  302. CG_LOCK_WRITE();
  303. //
  304. // What are we being asked to do?
  305. //
  306. switch (InformationClass)
  307. {
  308. case HttpControlChannelStateInformation:
  309. NewControlChannelState =
  310. *((PHTTP_ENABLED_STATE)pControlChannelInformation);
  311. if(NewControlChannelState == HttpEnabledStateActive ||
  312. NewControlChannelState == HttpEnabledStateInactive)
  313. {
  314. pControlChannel->State = NewControlChannelState;
  315. //
  316. // flush the URI cache.
  317. // CODEWORK: if we were smarter we might not need to flush
  318. //
  319. UlFlushCache(pControlChannel);
  320. }
  321. else
  322. {
  323. Status = STATUS_INVALID_PARAMETER;
  324. goto end;
  325. }
  326. break;
  327. case HttpControlChannelFilterInformation:
  328. {
  329. PHTTP_CONTROL_CHANNEL_FILTER pFiltInfo;
  330. //
  331. // This property is for admins only.
  332. //
  333. Status = UlThreadAdminCheck(
  334. FILE_WRITE_DATA,
  335. RequestorMode,
  336. HTTP_CONTROL_DEVICE_NAME
  337. );
  338. if(!NT_SUCCESS(Status))
  339. {
  340. goto end;
  341. }
  342. pFiltInfo = (PHTTP_CONTROL_CHANNEL_FILTER) pControlChannelInformation;
  343. //
  344. // Record the new information.
  345. //
  346. if (pFiltInfo->Flags.Present)
  347. {
  348. if(pFiltInfo->FilterHandle != NULL)
  349. {
  350. Status = STATUS_INVALID_PARAMETER;
  351. goto end;
  352. }
  353. UxSetFilterOnlySsl(pFiltInfo->FilterOnlySsl);
  354. }
  355. else
  356. {
  357. UxSetFilterOnlySsl(FALSE);
  358. }
  359. }
  360. break;
  361. case HttpControlChannelBandwidthInformation:
  362. {
  363. //
  364. // This property is for admins only.
  365. //
  366. Status = UlThreadAdminCheck(
  367. FILE_WRITE_DATA,
  368. RequestorMode,
  369. HTTP_CONTROL_DEVICE_NAME
  370. );
  371. if(!NT_SUCCESS(Status))
  372. {
  373. goto end;
  374. }
  375. NewMaxBandwidth = *((PHTTP_BANDWIDTH_LIMIT) pControlChannelInformation);
  376. //
  377. // Rate can not be lower than the min allowed.
  378. //
  379. if (NewMaxBandwidth < HTTP_MIN_ALLOWED_BANDWIDTH_THROTTLING_RATE)
  380. {
  381. Status = STATUS_INVALID_PARAMETER;
  382. goto end;
  383. }
  384. //
  385. // But check to see if PSched is installed or not before proceeding.
  386. // By returning an error here, WAS will raise an event warning but
  387. // proceed w/o terminating the web server
  388. //
  389. if (!UlTcPSchedInstalled())
  390. {
  391. NTSTATUS TempStatus;
  392. if (NewMaxBandwidth == HTTP_LIMIT_INFINITE)
  393. {
  394. //
  395. // By default Config Store has HTTP_LIMIT_INFINITE. Therefore
  396. // return success for non-actions to prevent unnecessary event
  397. // warnings.
  398. //
  399. Status = STATUS_SUCCESS;
  400. goto end;
  401. }
  402. //
  403. // Try to wake up psched state.
  404. //
  405. TempStatus = UlTcInitPSched();
  406. if (!NT_SUCCESS(TempStatus))
  407. {
  408. //
  409. // There's a BWT limit coming down but PSched is not installed
  410. //
  411. Status = STATUS_INVALID_DEVICE_REQUEST;
  412. goto end;
  413. }
  414. }
  415. //
  416. // Take a look at the similar "set cgroup ioctl" for
  417. // detailed comments.
  418. //
  419. if (pControlChannel->MaxBandwidth != HTTP_LIMIT_INFINITE)
  420. {
  421. //
  422. // See if there is really a change.
  423. //
  424. if (NewMaxBandwidth != pControlChannel->MaxBandwidth)
  425. {
  426. if (NewMaxBandwidth != HTTP_LIMIT_INFINITE)
  427. {
  428. Status = UlTcModifyFlows(
  429. (PVOID) pControlChannel,
  430. NewMaxBandwidth,
  431. TRUE
  432. );
  433. if (!NT_SUCCESS(Status))
  434. goto end;
  435. }
  436. else
  437. {
  438. UlTcRemoveFlows(
  439. (PVOID) pControlChannel,
  440. TRUE
  441. );
  442. }
  443. //
  444. // Don't forget to update the control channel
  445. // if it was a success.
  446. //
  447. pControlChannel->MaxBandwidth = NewMaxBandwidth;
  448. }
  449. }
  450. else
  451. {
  452. //
  453. // Create the global flows on all interfaces.
  454. //
  455. if (NewMaxBandwidth != HTTP_LIMIT_INFINITE)
  456. {
  457. Status = UlTcAddFlows(
  458. (PVOID) pControlChannel,
  459. NewMaxBandwidth,
  460. TRUE
  461. );
  462. if (NT_SUCCESS(Status))
  463. {
  464. //
  465. // Success! Remember the global bandwidth limit
  466. // in control channel.
  467. //
  468. pControlChannel->MaxBandwidth = NewMaxBandwidth;
  469. }
  470. }
  471. //
  472. // When UlCloseControlChannel is called, the global flows on
  473. // all interfaces are also going to be removed.Alternatively
  474. // the flows might be removed by explicitly setting the limit
  475. // to infinite
  476. //
  477. }
  478. }
  479. break;
  480. case HttpControlChannelTimeoutInformation:
  481. // CODEWORK: scope timeout monitor info to Control Channel
  482. //
  483. // This property is for admins only.
  484. //
  485. Status = UlThreadAdminCheck(
  486. FILE_WRITE_DATA,
  487. RequestorMode,
  488. HTTP_CONTROL_DEVICE_NAME
  489. );
  490. if( !NT_SUCCESS(Status) )
  491. {
  492. goto end;
  493. }
  494. //
  495. // Validate before setting
  496. //
  497. TimeoutInfo = *((PHTTP_CONTROL_CHANNEL_TIMEOUT_LIMIT)
  498. pControlChannelInformation);
  499. // NOTE: 64K seconds ~= 18.2 hours
  500. if (TimeoutInfo.ConnectionTimeout > 0xFFFF ||
  501. TimeoutInfo.HeaderWaitTimeout > 0xFFFF )
  502. {
  503. Status = STATUS_INVALID_PARAMETER;
  504. goto end;
  505. }
  506. UlSetTimeoutMonitorInformation(
  507. &TimeoutInfo
  508. );
  509. Status = STATUS_SUCCESS;
  510. break;
  511. case HttpControlChannelUTF8Logging:
  512. //
  513. // This property is for admins only.
  514. //
  515. Status = UlThreadAdminCheck(
  516. FILE_WRITE_DATA,
  517. RequestorMode,
  518. HTTP_CONTROL_DEVICE_NAME
  519. );
  520. if( NT_SUCCESS(Status) )
  521. {
  522. BOOLEAN bDoUTF8Logging;
  523. bDoUTF8Logging =
  524. (0 == *((PHTTP_CONTROL_CHANNEL_UTF8_LOGGING)pControlChannelInformation) ?
  525. FALSE : TRUE );
  526. pControlChannel->UTF8Logging = bDoUTF8Logging;
  527. UlSetUTF8Logging( bDoUTF8Logging );
  528. }
  529. break;
  530. case HttpControlChannelBinaryLogging:
  531. {
  532. UNICODE_STRING LogFileDir;
  533. //
  534. // This property is for admins only.
  535. //
  536. Status = UlThreadAdminCheck(
  537. FILE_WRITE_DATA,
  538. RequestorMode,
  539. HTTP_CONTROL_DEVICE_NAME
  540. );
  541. if(!NT_SUCCESS(Status))
  542. {
  543. goto end;
  544. }
  545. RtlInitEmptyUnicodeString(&LogFileDir, NULL, 0);
  546. RtlZeroMemory(&LoggingInfo, sizeof(LoggingInfo));
  547. __try
  548. {
  549. // Copy the input buffer into a local variable, we may
  550. // overwrite some of the fields
  551. LoggingInfo =
  552. (*((PHTTP_CONTROL_CHANNEL_BINARY_LOGGING)
  553. pControlChannelInformation));
  554. //
  555. // Do the range check for the configuration params.
  556. //
  557. Status = UlCheckLoggingConfig(&LoggingInfo, NULL);
  558. if (!NT_SUCCESS(Status))
  559. {
  560. goto end;
  561. }
  562. //
  563. // If the logging is -being- turned off. Fields other than the
  564. // LoggingEnabled are discarded. And the directory string might
  565. // be null, therefore we should only probe it if the logging is
  566. // enabled.
  567. //
  568. if (LoggingInfo.LoggingEnabled)
  569. {
  570. Status =
  571. UlProbeAndCaptureUnicodeString(
  572. &LoggingInfo.LogFileDir,
  573. RequestorMode,
  574. &LogFileDir,
  575. MAX_PATH
  576. );
  577. if (NT_SUCCESS(Status))
  578. {
  579. //
  580. // Validity check for the logging directory.
  581. //
  582. if (!UlIsValidLogDirectory(
  583. &LogFileDir,
  584. TRUE, // UncSupport
  585. FALSE // SystemRootSupport
  586. ))
  587. {
  588. Status = STATUS_INVALID_PARAMETER;
  589. UlFreeCapturedUnicodeString(&LogFileDir);
  590. }
  591. }
  592. }
  593. }
  594. __except( UL_EXCEPTION_FILTER() )
  595. {
  596. Status = UL_CONVERT_EXCEPTION_CODE(GetExceptionCode());
  597. }
  598. if (!NT_SUCCESS(Status))
  599. {
  600. goto end;
  601. }
  602. // Now reinit the unicode_string in LoggingInfo struct
  603. // to point to the captured one.
  604. LoggingInfo.LogFileDir = LogFileDir;
  605. if (pControlChannel->BinaryLoggingConfig.Flags.Present)
  606. {
  607. Status =
  608. UlReConfigureBinaryLogEntry(
  609. pControlChannel,
  610. &pControlChannel->BinaryLoggingConfig, // The old
  611. &LoggingInfo // The new
  612. );
  613. }
  614. else
  615. {
  616. //
  617. // Delay the creation until it becomes enabled.
  618. //
  619. if (LoggingInfo.LoggingEnabled)
  620. {
  621. Status =
  622. UlCreateBinaryLogEntry(
  623. pControlChannel,
  624. &LoggingInfo
  625. );
  626. }
  627. }
  628. // Cleanup the captured LogFileDir now.
  629. UlFreeCapturedUnicodeString(&LogFileDir);
  630. }
  631. break;
  632. case HttpControlChannelDemandStartThreshold:
  633. {
  634. PHTTP_CONTROL_CHANNEL_DEMAND_START_THRESHOLD pDST;
  635. if ( Length < sizeof(HTTP_CONTROL_CHANNEL_DEMAND_START_THRESHOLD) )
  636. {
  637. Status = STATUS_BUFFER_TOO_SMALL;
  638. }
  639. else
  640. {
  641. pDST = (PHTTP_CONTROL_CHANNEL_DEMAND_START_THRESHOLD)
  642. pControlChannelInformation;
  643. if (pDST->Flags.Present)
  644. {
  645. InterlockedExchange(
  646. (PLONG)&pControlChannel->DemandStartThreshold,
  647. pDST->DemandStartThreshold
  648. );
  649. }
  650. Status = STATUS_SUCCESS;
  651. }
  652. }
  653. break;
  654. default:
  655. //
  656. // Should have been caught in UlSetControlChannelIoctl.
  657. //
  658. ASSERT(FALSE);
  659. Status = STATUS_INVALID_PARAMETER;
  660. break;
  661. }
  662. end:
  663. CG_UNLOCK_WRITE();
  664. return Status;
  665. } // UlSetControlChannelInformation
  666. /***************************************************************************++
  667. Routine Description:
  668. Gets control channel information. For each element of the control channel
  669. if the supplied buffer is NULL, then we return the required length in the
  670. optional length field.
  671. Arguments:
  672. Return Value:
  673. NTSTATUS - Completion status.
  674. --***************************************************************************/
  675. NTSTATUS
  676. UlGetControlChannelInformation(
  677. IN KPROCESSOR_MODE RequestorMode,
  678. IN PUL_CONTROL_CHANNEL pControlChannel,
  679. IN HTTP_CONTROL_CHANNEL_INFORMATION_CLASS InformationClass,
  680. IN PVOID pControlChannelInformation,
  681. IN ULONG Length,
  682. OUT PULONG pReturnLength
  683. )
  684. {
  685. NTSTATUS Status = STATUS_SUCCESS;
  686. UNREFERENCED_PARAMETER(Length);
  687. //
  688. // Sanity check.
  689. //
  690. PAGED_CODE();
  691. ASSERT(IS_VALID_CONTROL_CHANNEL(pControlChannel));
  692. ASSERT(NULL != pControlChannelInformation);
  693. ASSERT(pReturnLength);
  694. CG_LOCK_READ();
  695. //
  696. // What are we being asked to do?
  697. //
  698. switch (InformationClass)
  699. {
  700. case HttpControlChannelStateInformation:
  701. *((PHTTP_ENABLED_STATE)pControlChannelInformation)
  702. = pControlChannel->State;
  703. *pReturnLength = sizeof(HTTP_ENABLED_STATE);
  704. break;
  705. case HttpControlChannelBandwidthInformation:
  706. //
  707. // This property is for admins only.
  708. //
  709. Status = UlThreadAdminCheck(
  710. FILE_READ_DATA,
  711. RequestorMode,
  712. HTTP_CONTROL_DEVICE_NAME
  713. );
  714. if(NT_SUCCESS(Status))
  715. {
  716. *((PHTTP_BANDWIDTH_LIMIT)pControlChannelInformation) =
  717. pControlChannel->MaxBandwidth;
  718. *pReturnLength = sizeof(HTTP_BANDWIDTH_LIMIT);
  719. }
  720. break;
  721. case HttpControlChannelConnectionInformation:
  722. *((PHTTP_CONNECTION_LIMIT)pControlChannelInformation) =
  723. UlGetGlobalConnectionLimit();
  724. *pReturnLength = sizeof(HTTP_CONNECTION_LIMIT);
  725. break;
  726. default:
  727. //
  728. // Should have been caught in UlQueryControlChannelIoctl.
  729. //
  730. ASSERT(FALSE);
  731. Status = STATUS_INVALID_PARAMETER;
  732. }
  733. CG_UNLOCK_READ();
  734. return Status;
  735. } // UlGetControlChannelInformation
  736. //
  737. // Private functions.
  738. //
  739. /***************************************************************************++
  740. Routine Description:
  741. Addref's the control channel object
  742. Arguments:
  743. PUL_CONTROL_CHANNEL pControlChannel
  744. Return Value:
  745. NTSTATUS - Completion status.
  746. --***************************************************************************/
  747. VOID
  748. UlReferenceControlChannel(
  749. IN PUL_CONTROL_CHANNEL pControlChannel
  750. REFERENCE_DEBUG_FORMAL_PARAMS
  751. )
  752. {
  753. LONG refCount;
  754. //
  755. // Sanity check.
  756. //
  757. ASSERT(IS_VALID_CONTROL_CHANNEL(pControlChannel));
  758. refCount = InterlockedIncrement(&pControlChannel->RefCount);
  759. WRITE_REF_TRACE_LOG(
  760. g_pControlChannelTraceLog,
  761. REF_ACTION_REFERENCE_CONTROL_CHANNEL,
  762. refCount,
  763. pControlChannel,
  764. pFileName,
  765. LineNumber
  766. );
  767. UlTrace(REFCOUNT,(
  768. "Http!UlReferenceControlChannel pControlChannel=%p refcount=%d\n",
  769. pControlChannel,
  770. refCount)
  771. );
  772. } // UlReferenceControlChannel
  773. /***************************************************************************++
  774. Routine Description:
  775. Releases the control channel object.
  776. Arguments:
  777. PUL_CONTROL_CHANNEL pControlChannel
  778. --***************************************************************************/
  779. VOID
  780. UlDereferenceControlChannel(
  781. IN PUL_CONTROL_CHANNEL pControlChannel
  782. REFERENCE_DEBUG_FORMAL_PARAMS
  783. )
  784. {
  785. LONG refCount;
  786. //
  787. // Sanity check.
  788. //
  789. ASSERT(IS_VALID_CONTROL_CHANNEL(pControlChannel));
  790. refCount = InterlockedDecrement( &pControlChannel->RefCount );
  791. WRITE_REF_TRACE_LOG(
  792. g_pControlChannelTraceLog,
  793. REF_ACTION_DEREFERENCE_CONTROL_CHANNEL,
  794. refCount,
  795. pControlChannel,
  796. pFileName,
  797. LineNumber
  798. );
  799. UlTrace(REFCOUNT, (
  800. "http!UlDereferenceControlChannel pControlChannel=%p refcount=%d\n",
  801. pControlChannel,
  802. refCount)
  803. );
  804. if (refCount == 0)
  805. {
  806. //
  807. // Now it's time to free the object
  808. //
  809. if (pControlChannel->BinaryLoggingConfig.Flags.Present &&
  810. pControlChannel->BinaryLoggingConfig.LogFileDir.Buffer != NULL)
  811. {
  812. UlRemoveBinaryLogEntry(pControlChannel);
  813. pControlChannel->pBinaryLogEntry = NULL;
  814. }
  815. else
  816. {
  817. ASSERT( NULL == pControlChannel->pBinaryLogEntry );
  818. }
  819. //
  820. // Flow list must also be empty here.
  821. //
  822. ASSERT(IsListEmpty(&pControlChannel->FlowListHead));
  823. //
  824. // Check Site Counter List: should be empty by this point
  825. //
  826. ASSERT(IsListEmpty(&pControlChannel->SiteCounterHead));
  827. UL_FREE_POOL(pControlChannel, UL_CONTROL_CHANNEL_POOL_TAG);
  828. }
  829. } // UlDereferenceControlChannel
  830. /******************************************************************************
  831. Routine Description:
  832. This will return the control channel object reference by this handle, bumping
  833. the refcount on the control channel.
  834. This is called by UlSetAppPoolInformation when user mode wants to
  835. associate a control channel to an app pool by handle.
  836. The app pool keeps a pointer to the control channel.
  837. Arguments:
  838. ControlChannel - the handle of the control channel
  839. AccessMode - KernelMode or UserMode
  840. ppControlChannel - returns the control channel object the handle represented.
  841. Return Value:
  842. NTSTATUS - Completion status.
  843. ******************************************************************************/
  844. NTSTATUS
  845. UlGetControlChannelFromHandle(
  846. IN HANDLE ControlChannel,
  847. IN KPROCESSOR_MODE AccessMode,
  848. OUT PUL_CONTROL_CHANNEL * ppControlChannel
  849. )
  850. {
  851. NTSTATUS Status;
  852. PFILE_OBJECT pFileObject = NULL;
  853. //
  854. // Sanity check.
  855. //
  856. PAGED_CODE();
  857. ASSERT(ppControlChannel != NULL);
  858. Status = ObReferenceObjectByHandle(
  859. ControlChannel, // Handle
  860. FILE_READ_ACCESS, // DesiredAccess
  861. *IoFileObjectType, // ObjectType
  862. AccessMode, // AccessMode
  863. (PVOID *) &pFileObject, // Object
  864. NULL // HandleInformation
  865. );
  866. if (NT_SUCCESS(Status) == FALSE)
  867. {
  868. goto end;
  869. }
  870. if (IS_CONTROL_CHANNEL(pFileObject) == FALSE ||
  871. IS_VALID_CONTROL_CHANNEL(GET_CONTROL_CHANNEL(pFileObject)) == FALSE)
  872. {
  873. Status = STATUS_INVALID_HANDLE;
  874. goto end;
  875. }
  876. *ppControlChannel = GET_CONTROL_CHANNEL(pFileObject);
  877. REFERENCE_CONTROL_CHANNEL(*ppControlChannel);
  878. end:
  879. if (pFileObject != NULL)
  880. {
  881. ObDereferenceObject(pFileObject);
  882. }
  883. return Status;
  884. } // UlGetControlChannelFromHandle