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.

881 lines
21 KiB

  1. /*++
  2. Copyright (c) 1999-2001 Microsoft Corporation
  3. Module Name:
  4. control.cxx
  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. #define FAKE_CONTROL_CHANNEL ((PUL_CONTROL_CHANNEL)1)
  17. //
  18. // Private globals.
  19. //
  20. PUL_FILTER_CHANNEL g_pFilterChannel = NULL;
  21. BOOLEAN g_FilterOnlySsl = FALSE;
  22. #ifdef ALLOC_PRAGMA
  23. #pragma alloc_text( INIT, UlInitializeControlChannel )
  24. #pragma alloc_text( PAGE, UlTerminateControlChannel )
  25. #pragma alloc_text( PAGE, UlOpenControlChannel )
  26. #pragma alloc_text( PAGE, UlCloseControlChannel )
  27. #pragma alloc_text( PAGE, UlQueryFilterChannel )
  28. #pragma alloc_text( PAGE, UlpSetFilterChannel )
  29. #endif // ALLOC_PRAGMA
  30. #if 0
  31. #endif
  32. //
  33. // Public functions.
  34. //
  35. /***************************************************************************++
  36. Routine Description:
  37. Performs global initialization of this module.
  38. Return Value:
  39. NTSTATUS - Completion status.
  40. --***************************************************************************/
  41. NTSTATUS
  42. UlInitializeControlChannel(
  43. VOID
  44. )
  45. {
  46. return STATUS_SUCCESS;
  47. } // UlInitializeControlChannel
  48. /***************************************************************************++
  49. Routine Description:
  50. Performs global termination of this module.
  51. --***************************************************************************/
  52. VOID
  53. UlTerminateControlChannel(
  54. VOID
  55. )
  56. {
  57. } // UlTerminateControlChannel
  58. /***************************************************************************++
  59. Routine Description:
  60. Opens a control channel.
  61. Arguments:
  62. pControlChannel - Receives a pointer to the newly created control
  63. channel if successful.
  64. Return Value:
  65. NTSTATUS - Completion status.
  66. --***************************************************************************/
  67. NTSTATUS
  68. UlOpenControlChannel(
  69. OUT PUL_CONTROL_CHANNEL *ppControlChannel
  70. )
  71. {
  72. PUL_CONTROL_CHANNEL pControlChannel;
  73. //
  74. // Sanity check.
  75. //
  76. PAGED_CODE();
  77. pControlChannel = UL_ALLOCATE_STRUCT(
  78. PagedPool,
  79. UL_CONTROL_CHANNEL,
  80. UL_CONTROL_CHANNEL_POOL_TAG
  81. );
  82. if (pControlChannel == NULL)
  83. return STATUS_NO_MEMORY;
  84. RtlZeroMemory(pControlChannel, sizeof(*pControlChannel));
  85. pControlChannel->Signature = UL_CONTROL_CHANNEL_POOL_TAG;
  86. pControlChannel->State = HttpEnabledStateInactive;
  87. UlInitializeNotifyHead(
  88. &pControlChannel->ConfigGroupHead,
  89. &g_pUlNonpagedData->ConfigGroupResource
  90. );
  91. // No Qos limit as default
  92. pControlChannel->MaxBandwidth = HTTP_LIMIT_INFINITE;
  93. pControlChannel->MaxConnections = HTTP_LIMIT_INFINITE;
  94. *ppControlChannel = pControlChannel;
  95. return STATUS_SUCCESS;
  96. } // UlOpenControlChannel
  97. /***************************************************************************++
  98. Routine Description:
  99. Closes a control channel.
  100. Arguments:
  101. pControlChannel - Supplies the control channel to close.
  102. Return Value:
  103. NTSTATUS - Completion status.
  104. --***************************************************************************/
  105. NTSTATUS
  106. UlCloseControlChannel(
  107. IN PUL_CONTROL_CHANNEL pControlChannel
  108. )
  109. {
  110. NTSTATUS Status;
  111. //
  112. // Sanity check.
  113. //
  114. PAGED_CODE();
  115. // a good pointer?
  116. //
  117. if (pControlChannel != NULL)
  118. {
  119. PLIST_ENTRY pEntry;
  120. // check the signature
  121. //
  122. if (pControlChannel->Signature != UL_CONTROL_CHANNEL_POOL_TAG)
  123. return RPC_NT_INVALID_TAG;
  124. // Free all the orphaned config groups
  125. //
  126. UlNotifyAllEntries(
  127. &UlNotifyOrphanedConfigGroup,
  128. &pControlChannel->ConfigGroupHead,
  129. NULL
  130. );
  131. //
  132. // release the auto-response
  133. //
  134. if (pControlChannel->pAutoResponse != NULL)
  135. {
  136. UL_DEREFERENCE_INTERNAL_RESPONSE(pControlChannel->pAutoResponse);
  137. pControlChannel->pAutoResponse = NULL;
  138. }
  139. //
  140. // release the filter channel
  141. //
  142. UlpSetFilterChannel(NULL, FALSE);
  143. //
  144. // remove QoS flows if they exist
  145. //
  146. if (pControlChannel->MaxBandwidth != HTTP_LIMIT_INFINITE)
  147. {
  148. UlTcRemoveGlobalFlows();
  149. }
  150. // free the memory
  151. //
  152. UL_FREE_POOL(pControlChannel, UL_CONTROL_CHANNEL_POOL_TAG);
  153. }
  154. return STATUS_SUCCESS;
  155. } // UlCloseControlChannel
  156. /***************************************************************************++
  157. Routine Description:
  158. Sets control channel information.
  159. Arguments:
  160. Return Value:
  161. NTSTATUS - Completion status.
  162. --***************************************************************************/
  163. NTSTATUS
  164. UlSetControlChannelInformation(
  165. IN PUL_CONTROL_CHANNEL pControlChannel,
  166. IN HTTP_CONTROL_CHANNEL_INFORMATION_CLASS InformationClass,
  167. IN PVOID pControlChannelInformation,
  168. IN ULONG Length
  169. )
  170. {
  171. NTSTATUS Status;
  172. HTTP_BANDWIDTH_LIMIT NewMaxBandwidth;
  173. //
  174. // Sanity check.
  175. //
  176. PAGED_CODE();
  177. ASSERT(IS_VALID_CONTROL_CHANNEL(pControlChannel));
  178. //
  179. // no buffer?
  180. //
  181. if (pControlChannelInformation == NULL)
  182. return STATUS_INVALID_PARAMETER;
  183. CG_LOCK_WRITE();
  184. //
  185. // What are we being asked to do?
  186. //
  187. switch (InformationClass)
  188. {
  189. case HttpControlChannelStateInformation:
  190. if (Length < sizeof(HTTP_ENABLED_STATE))
  191. {
  192. Status = STATUS_BUFFER_TOO_SMALL;
  193. goto end;
  194. }
  195. pControlChannel->State = *((PHTTP_ENABLED_STATE)pControlChannelInformation);
  196. //
  197. // flush the URI cache.
  198. // CODEWORK: if we were smarter we might not need to flush
  199. //
  200. UlFlushCache();
  201. break;
  202. case HttpControlChannelAutoResponseInformation:
  203. {
  204. PHTTP_AUTO_RESPONSE pAutoResponse;
  205. pAutoResponse = (PHTTP_AUTO_RESPONSE)pControlChannelInformation;
  206. //
  207. // double check the buffer is big enough
  208. //
  209. if (Length < sizeof(HTTP_AUTO_RESPONSE))
  210. {
  211. Status = STATUS_BUFFER_TOO_SMALL;
  212. goto end;
  213. }
  214. //
  215. // Is there an auto-response?
  216. //
  217. // BUGBUG: temp optional
  218. // if (pAutoResponse->Flags.Present == 1 && pAutoResponse->pResponse != NULL)
  219. if (pAutoResponse->Flags.Present == 1)
  220. {
  221. HTTP_VERSION HttpVersion11 = {1,1};
  222. //
  223. // Are we replacing one already there?
  224. //
  225. if (pControlChannel->pAutoResponse != NULL)
  226. {
  227. UL_DEREFERENCE_INTERNAL_RESPONSE(pControlChannel->pAutoResponse);
  228. pControlChannel->pAutoResponse = NULL;
  229. }
  230. //
  231. // Convert it to kernel mode
  232. //
  233. Status = UlCaptureHttpResponse(
  234. pAutoResponse->pResponse,
  235. NULL,
  236. HttpVersion11,
  237. HttpVerbUnknown,
  238. pAutoResponse->EntityChunkCount,
  239. pAutoResponse->pEntityChunks,
  240. UlCaptureCopyData,
  241. FALSE,
  242. NULL,
  243. &(pControlChannel->pAutoResponse)
  244. );
  245. if (NT_SUCCESS(Status) == FALSE)
  246. {
  247. pControlChannel->pAutoResponse = NULL;
  248. goto end;
  249. }
  250. Status = UlPrepareHttpResponse(
  251. HttpVersion11,
  252. pAutoResponse->pResponse,
  253. pControlChannel->pAutoResponse
  254. );
  255. if (NT_SUCCESS(Status) == FALSE)
  256. {
  257. UL_DEREFERENCE_INTERNAL_RESPONSE(pControlChannel->pAutoResponse);
  258. pControlChannel->pAutoResponse = NULL;
  259. goto end;
  260. }
  261. }
  262. else
  263. {
  264. //
  265. // Remove ours?
  266. //
  267. if (pControlChannel->pAutoResponse != NULL)
  268. {
  269. UL_DEREFERENCE_INTERNAL_RESPONSE(pControlChannel->pAutoResponse);
  270. }
  271. pControlChannel->pAutoResponse = NULL;
  272. }
  273. }
  274. break;
  275. case HttpControlChannelFilterInformation:
  276. {
  277. PHTTP_CONTROL_CHANNEL_FILTER pFiltInfo;
  278. PUL_FILTER_CHANNEL pFilterChannel = NULL;
  279. //
  280. // Check the parameters.
  281. //
  282. if (Length < sizeof(HTTP_CONTROL_CHANNEL_FILTER))
  283. {
  284. Status = STATUS_BUFFER_TOO_SMALL;
  285. goto end;
  286. }
  287. pFiltInfo = (PHTTP_CONTROL_CHANNEL_FILTER) pControlChannelInformation;
  288. //
  289. // Record the new information.
  290. //
  291. if (pFiltInfo->Flags.Present)
  292. {
  293. Status = UlGetFilterFromHandle(
  294. pFiltInfo->FilterHandle,
  295. &pFilterChannel
  296. );
  297. if (NT_SUCCESS(Status))
  298. {
  299. UlpSetFilterChannel(pFilterChannel, pFiltInfo->FilterOnlySsl);
  300. }
  301. else
  302. {
  303. goto end;
  304. }
  305. }
  306. else
  307. {
  308. UlpSetFilterChannel(NULL, FALSE);
  309. }
  310. }
  311. break;
  312. case HttpControlChannelBandwidthInformation:
  313. {
  314. //
  315. // Sanity Check first
  316. //
  317. if (Length < sizeof(HTTP_BANDWIDTH_LIMIT))
  318. {
  319. Status = STATUS_BUFFER_TOO_SMALL;
  320. goto end;
  321. }
  322. NewMaxBandwidth = *((PHTTP_BANDWIDTH_LIMIT) pControlChannelInformation);
  323. //
  324. // Interpret the ZERO as HTTP_LIMIT_INFINITE
  325. //
  326. if (NewMaxBandwidth == 0)
  327. {
  328. NewMaxBandwidth = HTTP_LIMIT_INFINITE;
  329. }
  330. //
  331. // But check to see if PSched is installed or not before proceeding.
  332. // By returning an error here, WAS will raise an event warning but
  333. // proceed w/o terminating the web server
  334. //
  335. if (!UlTcPSchedInstalled())
  336. {
  337. Status = STATUS_SUCCESS;
  338. goto end;
  339. #if 0
  340. // Enable when WAS start expecting this error
  341. if (NewMaxBandwidth != HTTP_LIMIT_INFINITE)
  342. {
  343. // There's a BWT limit coming down but PSched is not installed
  344. Status = STATUS_INVALID_DEVICE_REQUEST;
  345. goto end;
  346. }
  347. else
  348. {
  349. // By default Config Store has HTTP_LIMIT_INFINITE. Therefore
  350. // return success for non-actions to prevent unnecessary event
  351. // warnings.
  352. Status = STATUS_SUCCESS;
  353. goto end;
  354. }
  355. #endif
  356. }
  357. //
  358. // Take a look at the similar "set cgroup ioctl" for detailed comments
  359. //
  360. if (pControlChannel->MaxBandwidth != HTTP_LIMIT_INFINITE)
  361. {
  362. // To see if there is a real change
  363. if (NewMaxBandwidth != pControlChannel->MaxBandwidth)
  364. {
  365. if (NewMaxBandwidth != HTTP_LIMIT_INFINITE)
  366. {
  367. // This will modify global flows on all interfaces
  368. Status = UlTcModifyGlobalFlows(NewMaxBandwidth);
  369. if (!NT_SUCCESS(Status))
  370. goto end;
  371. }
  372. else
  373. {
  374. // Handle BTW disabling by removing the global flows
  375. Status = UlTcRemoveGlobalFlows();
  376. if (!NT_SUCCESS(Status))
  377. goto end;
  378. }
  379. // Don't forget to update the control channel if it was a success
  380. pControlChannel->MaxBandwidth = NewMaxBandwidth;
  381. }
  382. }
  383. else
  384. {
  385. // Create global flows on all interfaces
  386. if (NewMaxBandwidth != HTTP_LIMIT_INFINITE)
  387. {
  388. Status = UlTcAddGlobalFlows(NewMaxBandwidth);
  389. if (!NT_SUCCESS(Status))
  390. goto end;
  391. // Success! Remember the global bandwidth limit in control channel
  392. pControlChannel->MaxBandwidth = NewMaxBandwidth;
  393. }
  394. //
  395. // When UlCloseControlChannel is called, the global flows on all interfaces
  396. // are also going to be removed. Alternatively flows might be removed by
  397. // explicitly setting the bandwidth throttling limit to infinite or reseting
  398. // the flags.present. The latter cases are handled by the reconfiguration
  399. // function UlTcModifyGlobalFlows.
  400. //
  401. }
  402. }
  403. break;
  404. case HttpControlChannelConnectionInformation:
  405. {
  406. if (Length < sizeof(HTTP_CONNECTION_LIMIT))
  407. {
  408. Status = STATUS_BUFFER_TOO_SMALL;
  409. }
  410. else
  411. {
  412. pControlChannel->MaxConnections =
  413. *((PHTTP_CONNECTION_LIMIT)pControlChannelInformation);
  414. UlSetGlobalConnectionLimit( (ULONG) pControlChannel->MaxConnections );
  415. }
  416. }
  417. break;
  418. case HttpControlChannelTimeoutInformation:
  419. {
  420. if ( Length < sizeof(HTTP_CONTROL_CHANNEL_TIMEOUT_LIMIT) )
  421. {
  422. Status = STATUS_BUFFER_TOO_SMALL;
  423. }
  424. else
  425. {
  426. UlSetTimeoutMonitorInformation(
  427. (PHTTP_CONTROL_CHANNEL_TIMEOUT_LIMIT) pControlChannelInformation
  428. );
  429. }
  430. }
  431. break;
  432. case HttpControlChannelUTF8Logging:
  433. {
  434. if ( Length < sizeof(HTTP_CONTROL_CHANNEL_UTF8_LOGGING) )
  435. {
  436. Status = STATUS_BUFFER_TOO_SMALL;
  437. }
  438. else
  439. {
  440. pControlChannel->UTF8Logging =
  441. *((PHTTP_CONTROL_CHANNEL_UTF8_LOGGING)pControlChannelInformation);
  442. UlSetUTF8Logging( pControlChannel->UTF8Logging );
  443. }
  444. }
  445. break;
  446. default:
  447. Status = STATUS_INVALID_PARAMETER;
  448. break;
  449. }
  450. Status = STATUS_SUCCESS;
  451. end:
  452. CG_UNLOCK_WRITE();
  453. return Status;
  454. } // UlSetControlChannelInformation
  455. /***************************************************************************++
  456. Routine Description:
  457. Gets control channel information. For each element of the control channel
  458. if the supplied buffer is NULL, then we return the required length in the
  459. optional length field.
  460. Arguments:
  461. Return Value:
  462. NTSTATUS - Completion status.
  463. --***************************************************************************/
  464. NTSTATUS
  465. UlGetControlChannelInformation(
  466. IN PUL_CONTROL_CHANNEL pControlChannel,
  467. IN HTTP_CONTROL_CHANNEL_INFORMATION_CLASS InformationClass,
  468. IN PVOID pControlChannelInformation,
  469. IN ULONG Length,
  470. OUT PULONG pReturnLength OPTIONAL
  471. )
  472. {
  473. NTSTATUS Status;
  474. //
  475. // Sanity check.
  476. //
  477. PAGED_CODE();
  478. ASSERT(IS_VALID_CONTROL_CHANNEL(pControlChannel));
  479. CG_LOCK_READ();
  480. //
  481. // What are we being asked to do?
  482. //
  483. switch (InformationClass)
  484. {
  485. case HttpControlChannelStateInformation:
  486. {
  487. if (pControlChannelInformation==NULL)
  488. {
  489. //
  490. // Return the necessary size
  491. //
  492. *pReturnLength = sizeof(HTTP_ENABLED_STATE);
  493. }
  494. else
  495. {
  496. if (Length < sizeof(HTTP_ENABLED_STATE))
  497. {
  498. Status = STATUS_BUFFER_TOO_SMALL;
  499. goto end;
  500. }
  501. *((PHTTP_ENABLED_STATE)pControlChannelInformation) = pControlChannel->State;
  502. *pReturnLength = sizeof(HTTP_ENABLED_STATE);
  503. }
  504. }
  505. break;
  506. case HttpControlChannelBandwidthInformation:
  507. {
  508. if (pControlChannelInformation == NULL)
  509. {
  510. *pReturnLength = sizeof(HTTP_BANDWIDTH_LIMIT);
  511. }
  512. else
  513. {
  514. if (Length < sizeof(HTTP_BANDWIDTH_LIMIT))
  515. {
  516. Status = STATUS_BUFFER_TOO_SMALL;
  517. goto end;
  518. }
  519. *((PHTTP_BANDWIDTH_LIMIT)pControlChannelInformation) =
  520. pControlChannel->MaxBandwidth;
  521. *pReturnLength = sizeof(HTTP_BANDWIDTH_LIMIT);
  522. }
  523. }
  524. break;
  525. case HttpControlChannelConnectionInformation:
  526. {
  527. if (pControlChannelInformation == NULL)
  528. {
  529. *pReturnLength = sizeof(HTTP_CONNECTION_LIMIT);
  530. }
  531. else
  532. {
  533. if (Length < sizeof(HTTP_CONNECTION_LIMIT))
  534. {
  535. Status = STATUS_BUFFER_TOO_SMALL;
  536. goto end;
  537. }
  538. *((PHTTP_CONNECTION_LIMIT)pControlChannelInformation) =
  539. pControlChannel->MaxConnections;
  540. *pReturnLength = sizeof(HTTP_CONNECTION_LIMIT);
  541. }
  542. }
  543. break;
  544. case HttpControlChannelAutoResponseInformation: // Cannot be querried ...
  545. default:
  546. Status = STATUS_INVALID_PARAMETER;
  547. goto end;
  548. }
  549. Status = STATUS_SUCCESS;
  550. end:
  551. CG_UNLOCK_READ();
  552. return Status;
  553. } // UlGetControlChannelInformation
  554. /***************************************************************************++
  555. Routine Description:
  556. Queries the filter channel information. Gives the caller a reference
  557. if the channel exists and the caller is supposed to be filtered.
  558. Secure (SSL) connections are always filtered. If g_FilterOnlySsl is
  559. FALSE then everything gets filtered.
  560. Arguments:
  561. SecureConnection - tells us if the caller is on a secure endpoint.
  562. Return values:
  563. A reference to the filter channel if the connection is filtered.
  564. NULL if it is not.
  565. --***************************************************************************/
  566. PUL_FILTER_CHANNEL
  567. UlQueryFilterChannel(
  568. IN BOOLEAN SecureConnection
  569. )
  570. {
  571. PUL_FILTER_CHANNEL pChannel;
  572. //
  573. // Sanity check.
  574. //
  575. PAGED_CODE();
  576. CG_LOCK_READ();
  577. if (g_pFilterChannel && (SecureConnection || !g_FilterOnlySsl))
  578. {
  579. REFERENCE_FILTER_CHANNEL(g_pFilterChannel);
  580. pChannel = g_pFilterChannel;
  581. }
  582. else
  583. {
  584. pChannel = NULL;
  585. }
  586. CG_UNLOCK_READ();
  587. UlTrace(FILTER, (
  588. "ul!UlQueryFilterChannel(secure = %s) returning %p\n",
  589. SecureConnection ? "TRUE" : "FALSE",
  590. pChannel
  591. ));
  592. return pChannel;
  593. }
  594. /***************************************************************************++
  595. Routine Description:
  596. Checks to see if the callers filter channel matches the filter
  597. channel that would be returned by UlQueryFilterChannel.
  598. Note, this function intentionally does not acquire the config
  599. group read lock, because it doesn't really matter if we get
  600. a consistent view of the channel settings.
  601. Arguments:
  602. pChannel - the callers current filter channel setting
  603. SecureConnection - tells us if the caller is on a secure endpoint.
  604. Return values:
  605. Returns TRUE if the filter channel settings are up to date.
  606. --***************************************************************************/
  607. BOOLEAN
  608. UlValidateFilterChannel(
  609. IN PUL_FILTER_CHANNEL pChannel,
  610. IN BOOLEAN SecureConnection
  611. )
  612. {
  613. BOOLEAN UpToDate;
  614. //
  615. // Sanity check.
  616. //
  617. ASSERT(!pChannel || IS_VALID_FILTER_CHANNEL(pChannel));
  618. if (g_pFilterChannel && (SecureConnection || !g_FilterOnlySsl))
  619. {
  620. //
  621. // The connection should be filtered, so its channel
  622. // should match g_pFilterChannel.
  623. //
  624. UpToDate = (pChannel == g_pFilterChannel);
  625. }
  626. else
  627. {
  628. //
  629. // The connection is not filtered, so its channel
  630. // should be NULL.
  631. //
  632. UpToDate = (pChannel == NULL);
  633. }
  634. return UpToDate;
  635. }
  636. //
  637. // Private functions.
  638. //
  639. /***************************************************************************++
  640. Routine Description:
  641. Saves the global filter channel object, which is attached to new
  642. endpoints as they are created.
  643. The global data is protected by the config group lock, which we
  644. assume is held by the caller.
  645. Arguments:
  646. pFilterChannel - the filter channel object
  647. FilterOnlySsl - filter only ssl data, or all data
  648. --***************************************************************************/
  649. VOID
  650. UlpSetFilterChannel(
  651. IN PUL_FILTER_CHANNEL pFilterChannel,
  652. IN BOOLEAN FilterOnlySsl
  653. )
  654. {
  655. //
  656. // Sanity check.
  657. //
  658. PAGED_CODE();
  659. //
  660. // Dump the old channel if there was one.
  661. //
  662. if (g_pFilterChannel)
  663. {
  664. DEREFERENCE_FILTER_CHANNEL(g_pFilterChannel);
  665. }
  666. //
  667. // Save the new values.
  668. //
  669. g_pFilterChannel = pFilterChannel;
  670. g_FilterOnlySsl = FilterOnlySsl;
  671. } // UlSetFilterChannel