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.

2266 lines
44 KiB

  1. /*++
  2. Copyright (c) 1998-2001 Microsoft Corporation
  3. Module Name:
  4. tul.c
  5. Abstract:
  6. Stupid test file for HTTP.SYS (formerly UL.SYS).
  7. Author:
  8. Keith Moore (keithmo) 17-Jun-1998
  9. Revision History:
  10. --*/
  11. #include "precomp.h"
  12. #pragma hdrstop
  13. #include <..\..\drv\config.h>
  14. // this funny business gets me the UL_DEBUG_* flags on free builds
  15. #if !DBG
  16. #undef DBG
  17. #define DBG 1
  18. #define DBG_FLIP
  19. #endif
  20. #include <..\..\drv\debug.h>
  21. #ifdef DBG_FLIP
  22. #undef DBG_FLIP
  23. #undef DBG
  24. #define DBG 0
  25. #endif
  26. //
  27. // Our command table.
  28. //
  29. typedef
  30. INT
  31. (WINAPI * PFN_COMMAND)(
  32. IN HANDLE UlHandle,
  33. IN INT argc,
  34. IN PWSTR argv[]
  35. );
  36. typedef struct _COMMAND_ENTRY
  37. {
  38. PWSTR pCommandName;
  39. PWSTR pUsageHelp;
  40. PFN_COMMAND pCommandHandler;
  41. BOOL AutoStartUl;
  42. } COMMAND_ENTRY, *PCOMMAND_ENTRY;
  43. //
  44. // Performance counters.
  45. //
  46. #if LATER
  47. typedef enum _COUNTER_TYPE
  48. {
  49. Cumulative,
  50. Percentage,
  51. Average
  52. } COUNTER_TYPE, *PCOUNTER_TYPE;
  53. typedef struct _PERF_COUNTER
  54. {
  55. PWSTR pDisplayName;
  56. LONG FieldOffset;
  57. COUNTER_TYPE Type;
  58. } PERF_COUNTER, *PPERF_COUNTER;
  59. #define MAKE_CUMULATIVE( name ) \
  60. { \
  61. (PWSTR)L#name, \
  62. FIELD_OFFSET( UL_PERF_COUNTERS_USER, name ), \
  63. Cumulative \
  64. }
  65. #define MAKE_PERCENTAGE( name ) \
  66. { \
  67. (PWSTR)L#name, \
  68. FIELD_OFFSET( UL_PERF_COUNTERS_USER, name ), \
  69. Percentage \
  70. }
  71. #define MAKE_AVERAGE( name ) \
  72. { \
  73. (PWSTR)L#name, \
  74. FIELD_OFFSET( UL_PERF_COUNTERS_USER, name ), \
  75. Average \
  76. }
  77. PERF_COUNTER UlPerfCounters[] =
  78. {
  79. MAKE_CUMULATIVE( BytesReceived ),
  80. MAKE_CUMULATIVE( BytesSent ),
  81. MAKE_CUMULATIVE( ConnectionsReceived ),
  82. MAKE_CUMULATIVE( FilesSent ),
  83. MAKE_CUMULATIVE( FileCacheAttempts ),
  84. MAKE_PERCENTAGE( FileCacheHits ),
  85. MAKE_CUMULATIVE( FileCacheNegativeHits ),
  86. MAKE_CUMULATIVE( FileCacheEntries ),
  87. MAKE_CUMULATIVE( FastAcceptAttempted ),
  88. MAKE_PERCENTAGE( FastAcceptSucceeded ),
  89. MAKE_CUMULATIVE( FastReceiveAttempted ),
  90. MAKE_PERCENTAGE( FastReceiveSucceeded ),
  91. MAKE_CUMULATIVE( FastSendAttempted ),
  92. MAKE_PERCENTAGE( FastSendSucceeded ),
  93. MAKE_CUMULATIVE( MdlReadAttempted ),
  94. MAKE_PERCENTAGE( MdlReadSucceeded ),
  95. MAKE_CUMULATIVE( DecAvailThreads ),
  96. MAKE_AVERAGE( DecAvailThreadsRetry ),
  97. MAKE_CUMULATIVE( IncAvailThreads ),
  98. MAKE_AVERAGE( IncAvailThreadsRetry ),
  99. MAKE_CUMULATIVE( DecAvailPending ),
  100. MAKE_AVERAGE( DecAvailPendingRetry ),
  101. MAKE_CUMULATIVE( DecNumberOfThreads ),
  102. MAKE_AVERAGE( DecNumberOfThreadsRetry ),
  103. MAKE_CUMULATIVE( IncNumberOfThreads ),
  104. MAKE_AVERAGE( IncNumberOfThreadsRetry ),
  105. MAKE_CUMULATIVE( CreateSession ),
  106. MAKE_AVERAGE( CreateSessionRetry ),
  107. MAKE_CUMULATIVE( DestroySession ),
  108. MAKE_AVERAGE( DestroySessionRetry ),
  109. MAKE_CUMULATIVE( IncAcceptPending ),
  110. MAKE_AVERAGE( IncAcceptPendingRetry ),
  111. MAKE_CUMULATIVE( DecAcceptPending ),
  112. MAKE_AVERAGE( DecAcceptPendingRetry ),
  113. MAKE_CUMULATIVE( PerCpuNetworkDpcCounters[0] ),
  114. MAKE_CUMULATIVE( PerCpuNetworkDpcCounters[1] ),
  115. MAKE_CUMULATIVE( PerCpuNetworkDpcCounters[2] ),
  116. MAKE_CUMULATIVE( PerCpuNetworkDpcCounters[3] ),
  117. MAKE_CUMULATIVE( PerCpuFileSystemDpcCounters[0] ),
  118. MAKE_CUMULATIVE( PerCpuFileSystemDpcCounters[1] ),
  119. MAKE_CUMULATIVE( PerCpuFileSystemDpcCounters[2] ),
  120. MAKE_CUMULATIVE( PerCpuFileSystemDpcCounters[3] ),
  121. MAKE_CUMULATIVE( PerCpuThreadPoolActivity[0] ),
  122. MAKE_CUMULATIVE( PerCpuThreadPoolActivity[1] ),
  123. MAKE_CUMULATIVE( PerCpuThreadPoolActivity[2] ),
  124. MAKE_CUMULATIVE( PerCpuThreadPoolActivity[3] )
  125. };
  126. #define NUM_PERF_COUNTERS (sizeof(UlPerfCounters) / sizeof(UlPerfCounters[0]))
  127. #define GET_LONGLONG( buffer, offset ) \
  128. *(LONGLONG *)(((PCHAR)(buffer)) + (offset))
  129. #endif // LATER
  130. //
  131. // Configuration stuff.
  132. //
  133. typedef struct _CONFIG_ENTRY
  134. {
  135. PWSTR pConfigName;
  136. PWSTR pDisplayFormat;
  137. ULONG Type;
  138. LONGLONG SavedValue;
  139. LONG Status;
  140. } CONFIG_ENTRY, *PCONFIG_ENTRY;
  141. CONFIG_ENTRY ConfigTable[] =
  142. {
  143. {
  144. REGISTRY_IRP_STACK_SIZE,
  145. L"%lu",
  146. REG_DWORD,
  147. DEFAULT_IRP_STACK_SIZE
  148. },
  149. {
  150. REGISTRY_PRIORITY_BOOST,
  151. L"%lu",
  152. REG_DWORD,
  153. DEFAULT_PRIORITY_BOOST
  154. },
  155. {
  156. REGISTRY_DEBUG_FLAGS,
  157. L"%08lx",
  158. REG_DWORD,
  159. DEFAULT_DEBUG_FLAGS
  160. },
  161. {
  162. REGISTRY_BREAK_ON_STARTUP,
  163. L"%lu",
  164. REG_DWORD,
  165. DEFAULT_BREAK_ON_STARTUP
  166. },
  167. {
  168. REGISTRY_BREAK_ON_ERROR,
  169. L"%lu",
  170. REG_DWORD,
  171. DEFAULT_BREAK_ON_ERROR
  172. },
  173. {
  174. REGISTRY_VERBOSE_ERRORS,
  175. L"%lu",
  176. REG_DWORD,
  177. DEFAULT_VERBOSE_ERRORS
  178. },
  179. {
  180. REGISTRY_ENABLE_UNLOAD,
  181. L"%lu",
  182. REG_DWORD,
  183. DEFAULT_ENABLE_UNLOAD
  184. },
  185. {
  186. REGISTRY_ENABLE_SECURITY,
  187. L"%lu",
  188. REG_DWORD,
  189. DEFAULT_ENABLE_SECURITY
  190. },
  191. {
  192. REGISTRY_MIN_IDLE_CONNECTIONS,
  193. L"%lu",
  194. REG_DWORD,
  195. DEFAULT_MIN_IDLE_CONNECTIONS
  196. },
  197. {
  198. REGISTRY_MAX_IDLE_CONNECTIONS,
  199. L"%lu",
  200. REG_DWORD,
  201. DEFAULT_MAX_IDLE_CONNECTIONS
  202. },
  203. {
  204. REGISTRY_IRP_CONTEXT_LOOKASIDE_DEPTH,
  205. L"%lu",
  206. REG_DWORD,
  207. DEFAULT_IRP_CONTEXT_LOOKASIDE_DEPTH
  208. },
  209. {
  210. REGISTRY_RCV_BUFFER_SIZE,
  211. L"%lu",
  212. REG_DWORD,
  213. DEFAULT_RCV_BUFFER_SIZE
  214. },
  215. {
  216. REGISTRY_RCV_BUFFER_LOOKASIDE_DEPTH,
  217. L"%lu",
  218. REG_DWORD,
  219. DEFAULT_RCV_BUFFER_LOOKASIDE_DEPTH
  220. },
  221. {
  222. REGISTRY_RESOURCE_LOOKASIDE_DEPTH,
  223. L"%lu",
  224. REG_DWORD,
  225. DEFAULT_RESOURCE_LOOKASIDE_DEPTH
  226. },
  227. {
  228. REGISTRY_REQ_BUFFER_LOOKASIDE_DEPTH,
  229. L"%lu",
  230. REG_DWORD,
  231. DEFAULT_REQ_BUFFER_LOOKASIDE_DEPTH
  232. },
  233. {
  234. REGISTRY_INT_REQUEST_LOOKASIDE_DEPTH,
  235. L"%lu",
  236. REG_DWORD,
  237. DEFAULT_INT_REQUEST_LOOKASIDE_DEPTH
  238. },
  239. {
  240. REGISTRY_RESP_BUFFER_SIZE,
  241. L"%lu",
  242. REG_DWORD,
  243. DEFAULT_RESP_BUFFER_SIZE
  244. },
  245. {
  246. REGISTRY_RESP_BUFFER_LOOKASIDE_DEPTH,
  247. L"%lu",
  248. REG_DWORD,
  249. DEFAULT_RESP_BUFFER_LOOKASIDE_DEPTH
  250. },
  251. {
  252. REGISTRY_SEND_TRACKER_LOOKASIDE_DEPTH,
  253. L"%lu",
  254. REG_DWORD,
  255. DEFAULT_SEND_TRACKER_LOOKASIDE_DEPTH
  256. },
  257. {
  258. REGISTRY_LOG_BUFFER_LOOKASIDE_DEPTH,
  259. L"%lu",
  260. REG_DWORD,
  261. DEFAULT_LOG_BUFFER_LOOKASIDE_DEPTH
  262. },
  263. {
  264. REGISTRY_MAX_INTERNAL_URL_LENGTH,
  265. L"%lu",
  266. REG_DWORD,
  267. DEFAULT_MAX_INTERNAL_URL_LENGTH
  268. },
  269. {
  270. REGISTRY_MAX_REQUEST_BYTES,
  271. L"%lu",
  272. REG_DWORD,
  273. DEFAULT_MAX_REQUEST_BYTES
  274. },
  275. {
  276. REGISTRY_ENABLE_CONNECTION_REUSE,
  277. L"%lu",
  278. REG_DWORD,
  279. DEFAULT_ENABLE_CONNECTION_REUSE
  280. },
  281. {
  282. REGISTRY_ENABLE_NAGLING,
  283. L"%lu",
  284. REG_DWORD,
  285. DEFAULT_ENABLE_NAGLING
  286. },
  287. {
  288. REGISTRY_ENABLE_THREAD_AFFINITY,
  289. L"%lu",
  290. REG_DWORD,
  291. DEFAULT_ENABLE_THREAD_AFFINITY
  292. },
  293. {
  294. REGISTRY_THREAD_AFFINITY_MASK,
  295. L"%I64x",
  296. REG_QWORD,
  297. 0
  298. },
  299. {
  300. REGISTRY_THREADS_PER_CPU,
  301. L"%lu",
  302. REG_DWORD,
  303. DEFAULT_THREADS_PER_CPU
  304. },
  305. {
  306. REGISTRY_MAX_WORK_QUEUE_DEPTH,
  307. L"%lu",
  308. REG_DWORD,
  309. DEFAULT_MAX_WORK_QUEUE_DEPTH,
  310. },
  311. {
  312. REGISTRY_MIN_WORK_DEQUEUE_DEPTH,
  313. L"%lu",
  314. REG_DWORD,
  315. DEFAULT_MIN_WORK_DEQUEUE_DEPTH,
  316. },
  317. {
  318. REGISTRY_MAX_URL_LENGTH,
  319. L"%lu",
  320. REG_DWORD,
  321. DEFAULT_MAX_URL_LENGTH
  322. },
  323. {
  324. REGISTRY_MAX_FIELD_LENGTH,
  325. L"%lu",
  326. REG_DWORD,
  327. DEFAULT_MAX_FIELD_LENGTH
  328. },
  329. {
  330. REGISTRY_DEBUG_LOGTIMER_CYCLE,
  331. L"%lu",
  332. REG_DWORD,
  333. DEFAULT_DEBUG_LOGTIMER_CYCLE
  334. },
  335. {
  336. REGISTRY_DEBUG_LOG_BUFFER_PERIOD,
  337. L"%lu",
  338. REG_DWORD,
  339. DEFAULT_DEBUG_LOG_BUFFER_PERIOD
  340. },
  341. {
  342. REGISTRY_LOG_BUFFER_SIZE,
  343. L"%lu",
  344. REG_DWORD,
  345. DEFAULT_LOG_BUFFER_SIZE
  346. },
  347. {
  348. REGISTRY_ENABLE_NON_UTF8_URL,
  349. L"%lu",
  350. REG_DWORD,
  351. DEFAULT_ENABLE_NON_UTF8_URL
  352. },
  353. {
  354. REGISTRY_ENABLE_DBCS_URL,
  355. L"%lu",
  356. REG_DWORD,
  357. DEFAULT_ENABLE_DBCS_URL
  358. },
  359. {
  360. REGISTRY_FAVOR_DBCS_URL,
  361. L"%lu",
  362. REG_DWORD,
  363. DEFAULT_FAVOR_DBCS_URL
  364. },
  365. {
  366. REGISTRY_CACHE_ENABLED,
  367. L"%lu",
  368. REG_DWORD,
  369. DEFAULT_CACHE_ENABLED
  370. },
  371. {
  372. REGISTRY_MAX_CACHE_URI_COUNT,
  373. L"%lu",
  374. REG_DWORD,
  375. DEFAULT_MAX_CACHE_URI_COUNT
  376. },
  377. {
  378. REGISTRY_MAX_CACHE_MEGABYTE_COUNT,
  379. L"%lu",
  380. REG_DWORD,
  381. DEFAULT_MAX_CACHE_MEGABYTE_COUNT
  382. },
  383. {
  384. REGISTRY_CACHE_SCAVENGER_PERIOD,
  385. L"%lu",
  386. REG_DWORD,
  387. DEFAULT_CACHE_SCAVENGER_PERIOD
  388. },
  389. {
  390. REGISTRY_MAX_URI_BYTES,
  391. L"%lu",
  392. REG_DWORD,
  393. DEFAULT_MAX_URI_BYTES
  394. },
  395. {
  396. REGISTRY_HASH_TABLE_BITS,
  397. L"%ld",
  398. REG_DWORD,
  399. DEFAULT_HASH_TABLE_BITS
  400. },
  401. {
  402. REGISTRY_LARGE_MEM_MEGABYTES,
  403. L"%ld",
  404. REG_DWORD,
  405. DEFAULT_LARGE_MEM_MEGABYTES
  406. },
  407. {
  408. REGISTRY_OPAQUE_ID_TABLE_SIZE,
  409. L"%lu",
  410. REG_DWORD,
  411. DEFAULT_OPAQUE_ID_TABLE_SIZE
  412. },
  413. };
  414. #define NUM_CONFIG_ENTRIES (sizeof(ConfigTable) / sizeof(ConfigTable[0]))
  415. #define DEFAULT_SUFFIX_SZ L" [default]"
  416. typedef struct _FLAG_ENTRY {
  417. PWSTR pName;
  418. PWSTR pDisplayFormat;
  419. LONG Value;
  420. } FLAG_ENTRY, *PFLAG_ENTRY;
  421. #define MAKE_FLAG( name, display ) \
  422. { \
  423. (PWSTR)L#name, \
  424. (display), \
  425. UL_DEBUG_ ## name \
  426. }
  427. FLAG_ENTRY FlagTable[] =
  428. {
  429. MAKE_FLAG(OPEN_CLOSE, L"file object create/close"),
  430. MAKE_FLAG(SEND_RESPONSE, L"send response ioctl"),
  431. MAKE_FLAG(SEND_BUFFER, L"send buffer"),
  432. MAKE_FLAG(TDI, L"low level network stuff"),
  433. MAKE_FLAG(FILE_CACHE, L"open/close files"),
  434. MAKE_FLAG(CONFIG_GROUP_FNC, L"config group changes"),
  435. MAKE_FLAG(CONFIG_GROUP_TREE, L"cgroup tree operations"),
  436. MAKE_FLAG(REFCOUNT, L"object refcounting"),
  437. MAKE_FLAG(HTTP_IO, L"high level network & buffers"),
  438. MAKE_FLAG(ROUTING, L"request to process routing"),
  439. MAKE_FLAG(URI_CACHE, L"uri content cache"),
  440. MAKE_FLAG(PARSER, L"request parsing"),
  441. MAKE_FLAG(SITE, L"sites and endpoints"),
  442. MAKE_FLAG(WORK_ITEM, L"thread pool work queue"),
  443. MAKE_FLAG(FILTER, L"filters and ssl"),
  444. MAKE_FLAG(LOGGING, L"ul logging"),
  445. MAKE_FLAG(TC, L"traffic control"),
  446. MAKE_FLAG(OPAQUE_ID, L"opaque ids"),
  447. MAKE_FLAG(PERF_COUNTERS, L"perf counters"),
  448. MAKE_FLAG(LKRHASH, L"LKRhash hashtables"),
  449. MAKE_FLAG(TIMEOUTS, L"timeout monitor"),
  450. MAKE_FLAG(LIMITS, L"connection limits"),
  451. MAKE_FLAG(LARGE_MEM, L"large memory"),
  452. MAKE_FLAG(IOCTL, L"ioctl"),
  453. MAKE_FLAG(VERBOSE, L"verbose"),
  454. };
  455. #define NUM_FLAG_ENTRIES (sizeof(FlagTable) / sizeof(FlagTable[0]))
  456. DEFINE_COMMON_GLOBALS();
  457. VOID
  458. Usage(
  459. VOID
  460. );
  461. NTSTATUS
  462. OpenUlDevice(
  463. PHANDLE pHandle
  464. );
  465. BOOL
  466. TryToStartUlDevice(
  467. VOID
  468. );
  469. INT
  470. LongLongToString(
  471. LONGLONG Value,
  472. PWSTR pBuffer
  473. );
  474. LONG
  475. CalcPercentage(
  476. LONGLONG High,
  477. LONGLONG Low
  478. );
  479. PCOMMAND_ENTRY
  480. FindCommandByName(
  481. IN PWSTR pCommand
  482. );
  483. PCONFIG_ENTRY
  484. FindConfigByName(
  485. IN PWSTR pConfig
  486. );
  487. ULONG
  488. FindFlagByName(
  489. IN PWSTR pFlagName
  490. );
  491. INT
  492. ControlHttpServer(
  493. IN HANDLE UlHandle,
  494. IN ULONG Command
  495. );
  496. VOID
  497. DumpConfiguration(
  498. IN HKEY Key
  499. );
  500. VOID
  501. DumpFlags(
  502. IN HKEY Key
  503. );
  504. #if LATER
  505. INT
  506. WINAPI
  507. DoStart(
  508. IN HANDLE UlHandle,
  509. IN INT argc,
  510. IN PWSTR argv[]
  511. );
  512. INT
  513. WINAPI
  514. DoStop(
  515. IN HANDLE UlHandle,
  516. IN INT argc,
  517. IN PWSTR argv[]
  518. );
  519. INT
  520. WINAPI
  521. DoPause(
  522. IN HANDLE UlHandle,
  523. IN INT argc,
  524. IN PWSTR argv[]
  525. );
  526. INT
  527. WINAPI
  528. DoContinue(
  529. IN HANDLE UlHandle,
  530. IN INT argc,
  531. IN PWSTR argv[]
  532. );
  533. INT
  534. WINAPI
  535. DoQuery(
  536. IN HANDLE UlHandle,
  537. IN INT argc,
  538. IN PWSTR argv[]
  539. );
  540. INT
  541. WINAPI
  542. DoPerf(
  543. IN HANDLE UlHandle,
  544. IN INT argc,
  545. IN PWSTR argv[]
  546. );
  547. INT
  548. WINAPI
  549. DoClear(
  550. IN HANDLE UlHandle,
  551. IN INT argc,
  552. IN PWSTR argv[]
  553. );
  554. INT
  555. WINAPI
  556. DoFlush(
  557. IN HANDLE UlHandle,
  558. IN INT argc,
  559. IN PWSTR argv[]
  560. );
  561. #endif // LATER
  562. INT
  563. WINAPI
  564. DoConfig(
  565. IN HANDLE UlHandle,
  566. IN INT argc,
  567. IN PWSTR argv[]
  568. );
  569. INT
  570. WINAPI
  571. DoFlags(
  572. IN HANDLE UlHandle,
  573. IN INT argc,
  574. IN PWSTR argv[]
  575. );
  576. COMMAND_ENTRY CommandTable[] =
  577. {
  578. #if LATER
  579. {
  580. L"start",
  581. L"starts the server",
  582. &DoStart,
  583. TRUE
  584. },
  585. {
  586. L"stop",
  587. L"stops the server",
  588. &DoStop,
  589. TRUE
  590. },
  591. {
  592. L"pause",
  593. L"pauses the server",
  594. &DoPause,
  595. TRUE
  596. },
  597. {
  598. L"continue",
  599. L"continues the server",
  600. &DoContinue,
  601. TRUE
  602. },
  603. {
  604. L"query",
  605. L"queries the current state",
  606. &DoQuery,
  607. TRUE
  608. },
  609. {
  610. L"perf",
  611. L"displays perf counters",
  612. &DoPerf,
  613. TRUE
  614. },
  615. {
  616. L"clear",
  617. L"clears perf counters",
  618. &DoClear,
  619. TRUE
  620. },
  621. {
  622. L"flush",
  623. L"flushes file cache",
  624. &DoFlush,
  625. TRUE
  626. },
  627. #endif // LATER
  628. {
  629. L"config",
  630. L"configures the server",
  631. &DoConfig,
  632. FALSE
  633. },
  634. {
  635. L"flags",
  636. L"configures debug flags",
  637. &DoFlags,
  638. FALSE
  639. }
  640. };
  641. #define NUM_COMMAND_ENTRIES (sizeof(CommandTable) / sizeof(CommandTable[0]))
  642. INT
  643. __cdecl
  644. wmain(
  645. INT argc,
  646. PWSTR argv[]
  647. )
  648. {
  649. NTSTATUS status;
  650. HANDLE handle;
  651. PCOMMAND_ENTRY pEntry;
  652. INT result;
  653. ULONG err;
  654. //
  655. // Initialize.
  656. //
  657. setvbuf( stdin, NULL, _IONBF, 0 );
  658. setvbuf( stdout, NULL, _IONBF, 0 );
  659. //
  660. // Setup locals so we know how to cleanup on exit.
  661. //
  662. handle = NULL;
  663. //
  664. // Find the command handler.
  665. //
  666. if (argc == 1)
  667. {
  668. pEntry = NULL;
  669. }
  670. else
  671. {
  672. pEntry = FindCommandByName( argv[1] );
  673. }
  674. if (pEntry == NULL)
  675. {
  676. Usage();
  677. result = 1;
  678. goto cleanup;
  679. }
  680. //
  681. // Open the UL.SYS device.
  682. //
  683. status = OpenUlDevice( &handle );
  684. if (!NT_SUCCESS(status))
  685. {
  686. if (pEntry->AutoStartUl)
  687. {
  688. if (TryToStartUlDevice())
  689. {
  690. status = OpenUlDevice( &handle );
  691. }
  692. }
  693. else
  694. {
  695. status = STATUS_SUCCESS;
  696. }
  697. }
  698. if (!NT_SUCCESS(status))
  699. {
  700. wprintf(
  701. L"Cannot open %s, error %08lx\n",
  702. HTTP_CONTROL_DEVICE_NAME,
  703. status
  704. );
  705. result = 1;
  706. goto cleanup;
  707. }
  708. //
  709. // Call the handler.
  710. //
  711. argc--;
  712. argv++;
  713. result = (pEntry->pCommandHandler)(
  714. handle,
  715. argc,
  716. argv
  717. );
  718. cleanup:
  719. if (handle != NULL)
  720. {
  721. NtClose( handle );
  722. }
  723. return result;
  724. } // main
  725. PCOMMAND_ENTRY
  726. FindCommandByName(
  727. IN PWSTR pCommand
  728. )
  729. {
  730. PCOMMAND_ENTRY pEntry;
  731. INT i;
  732. for (i = NUM_COMMAND_ENTRIES, pEntry = &CommandTable[0] ;
  733. i > 0 ;
  734. i--, pEntry++)
  735. {
  736. if (_wcsicmp( pCommand, pEntry->pCommandName ) == 0)
  737. {
  738. return pEntry;
  739. }
  740. }
  741. return NULL;
  742. } // FindCommandByName
  743. PCONFIG_ENTRY
  744. FindConfigByName(
  745. IN PWSTR pConfig
  746. )
  747. {
  748. PCONFIG_ENTRY pEntry;
  749. INT i;
  750. INT len;
  751. //
  752. // First off, validate that the incoming configuration name
  753. // is of the form "property=". The trailing '=' is required.
  754. //
  755. len = wcslen( pConfig );
  756. if (pConfig[len - 1] != L'=')
  757. {
  758. return NULL;
  759. }
  760. len--;
  761. for (i = NUM_CONFIG_ENTRIES, pEntry = &ConfigTable[0] ;
  762. i > 0 ;
  763. i--, pEntry++)
  764. {
  765. if ((INT)wcslen( pEntry->pConfigName ) == len &&
  766. _wcsnicmp( pConfig, pEntry->pConfigName, len ) == 0)
  767. {
  768. return pEntry;
  769. }
  770. }
  771. return NULL;
  772. } // FindConfigByName
  773. ULONG
  774. FindFlagByName(
  775. IN PWSTR pFlagName
  776. )
  777. {
  778. INT len;
  779. ULONG flags;
  780. ULONG i;
  781. len = wcslen(pFlagName);
  782. if ((len > 2) && (wcsncmp(pFlagName, L"0x", 2) == 0)) {
  783. // numeric flag
  784. flags = wcstoul(pFlagName, NULL, 16);
  785. } else {
  786. // named flag
  787. flags = 0;
  788. for (i = 0; i < NUM_FLAG_ENTRIES; i++) {
  789. if (_wcsicmp(pFlagName, FlagTable[i].pName) == 0) {
  790. flags = FlagTable[i].Value;
  791. break;
  792. }
  793. }
  794. }
  795. return flags;
  796. }
  797. VOID
  798. Usage(
  799. VOID
  800. )
  801. {
  802. PCOMMAND_ENTRY pEntry;
  803. INT i;
  804. INT maxLength;
  805. INT len;
  806. //
  807. // Scan the command table, searching for the longest command name.
  808. // (This makes the output much prettier...)
  809. //
  810. maxLength = 0;
  811. for (i = NUM_COMMAND_ENTRIES, pEntry = &CommandTable[0] ;
  812. i > 0 ;
  813. i--, pEntry++)
  814. {
  815. len = wcslen( pEntry->pCommandName );
  816. if (len > maxLength)
  817. {
  818. maxLength = len;
  819. }
  820. }
  821. //
  822. // Now display the usage information.
  823. //
  824. wprintf(
  825. L"use: tul action [options]\n"
  826. L"\n"
  827. L"valid actions are:\n"
  828. L"\n"
  829. );
  830. for (i = NUM_COMMAND_ENTRIES, pEntry = &CommandTable[0] ;
  831. i > 0 ;
  832. i--, pEntry++)
  833. {
  834. wprintf(
  835. L" %-*s - %s\n",
  836. maxLength,
  837. pEntry->pCommandName,
  838. pEntry->pUsageHelp
  839. );
  840. }
  841. } // Usage
  842. NTSTATUS
  843. OpenUlDevice(
  844. PHANDLE pHandle
  845. )
  846. {
  847. NTSTATUS status;
  848. OBJECT_ATTRIBUTES objectAttributes;
  849. UNICODE_STRING deviceName;
  850. IO_STATUS_BLOCK ioStatusBlock;
  851. //
  852. // Open the UL device.
  853. //
  854. RtlInitUnicodeString(
  855. &deviceName,
  856. HTTP_CONTROL_DEVICE_NAME
  857. );
  858. InitializeObjectAttributes(
  859. &objectAttributes, // ObjectAttributes
  860. &deviceName, // ObjectName
  861. OBJ_CASE_INSENSITIVE, // Attributes
  862. NULL, // RootDirectory
  863. NULL // SecurityDescriptor
  864. );
  865. status = NtCreateFile(
  866. pHandle, // FileHandle
  867. GENERIC_READ | // DesiredAccess
  868. GENERIC_WRITE |
  869. SYNCHRONIZE,
  870. &objectAttributes, // ObjectAttributes
  871. &ioStatusBlock, // IoStatusBlock
  872. NULL, // AllocationSize
  873. 0, // FileAttributes
  874. FILE_SHARE_READ | // ShareAccess
  875. FILE_SHARE_WRITE,
  876. FILE_OPEN_IF, // CreateDisposition
  877. FILE_SYNCHRONOUS_IO_NONALERT, // CreateOptions
  878. NULL, // EaBuffer
  879. 0 // EaLength
  880. );
  881. if (!NT_SUCCESS(status))
  882. {
  883. *pHandle = NULL;
  884. }
  885. return status;
  886. } // OpenHdhDevice
  887. BOOL
  888. TryToStartUlDevice(
  889. VOID
  890. )
  891. {
  892. BOOL result = FALSE;
  893. SC_HANDLE scHandle = NULL;
  894. SC_HANDLE svcHandle = NULL;
  895. scHandle = OpenSCManager(
  896. NULL,
  897. NULL,
  898. SC_MANAGER_ALL_ACCESS
  899. );
  900. if (scHandle == NULL)
  901. {
  902. goto exit;
  903. }
  904. svcHandle = OpenService(
  905. scHandle,
  906. L"Ul",
  907. SERVICE_ALL_ACCESS
  908. );
  909. if (svcHandle == NULL)
  910. {
  911. goto exit;
  912. }
  913. if (!StartService( svcHandle, 0, NULL ))
  914. {
  915. goto exit;
  916. }
  917. result = TRUE;
  918. exit:
  919. if (svcHandle != NULL)
  920. {
  921. CloseServiceHandle( svcHandle );
  922. }
  923. if (scHandle != NULL)
  924. {
  925. CloseServiceHandle( scHandle );
  926. }
  927. return result;
  928. } // TryToStartHdhDevice
  929. INT
  930. LongLongToString(
  931. LONGLONG Value,
  932. PWSTR pBuffer
  933. )
  934. {
  935. PWSTR p1;
  936. PWSTR p2;
  937. WCHAR ch;
  938. INT digit;
  939. BOOL negative;
  940. INT count;
  941. BOOL needComma;
  942. INT length;
  943. ULONGLONG unsignedValue;
  944. //
  945. // Handling zero specially makes everything else a bit easier.
  946. //
  947. if (Value == 0)
  948. {
  949. wcscpy( pBuffer, L"0" );
  950. return 1;
  951. }
  952. //
  953. // Remember if the value is negative.
  954. //
  955. if (Value < 0)
  956. {
  957. negative = TRUE;
  958. unsignedValue = (ULONGLONG)-Value;
  959. }
  960. else
  961. {
  962. negative = FALSE;
  963. unsignedValue = (ULONGLONG)Value;
  964. }
  965. //
  966. // Pull the least signifigant digits off the value and store them
  967. // into the buffer. Note that this will store the digits in the
  968. // reverse order.
  969. //
  970. p1 = p2 = pBuffer;
  971. count = 3;
  972. needComma = FALSE;
  973. while (unsignedValue != 0)
  974. {
  975. if (needComma)
  976. {
  977. *p1++ = L',';
  978. needComma = FALSE;
  979. }
  980. digit = (INT)( unsignedValue % 10 );
  981. unsignedValue = unsignedValue / 10;
  982. *p1++ = L'0' + digit;
  983. count--;
  984. if (count == 0)
  985. {
  986. count = 3;
  987. needComma = TRUE;
  988. }
  989. }
  990. //
  991. // Tack on a leading L'-' if necessary.
  992. //
  993. if (negative)
  994. {
  995. *p1++ = L'-';
  996. }
  997. length = (INT)( p1 - pBuffer );
  998. //
  999. // Reverse the digits in the buffer.
  1000. //
  1001. *p1-- = L'\0';
  1002. while (p1 > p2)
  1003. {
  1004. ch = *p1;
  1005. *p1 = *p2;
  1006. *p2 = ch;
  1007. p2++;
  1008. p1--;
  1009. }
  1010. return length;
  1011. } // LongLongToString
  1012. LONG
  1013. CalcPercentage(
  1014. LONGLONG High,
  1015. LONGLONG Low
  1016. )
  1017. {
  1018. LONG result;
  1019. if (High == 0 || Low == 0)
  1020. {
  1021. result = 0;
  1022. }
  1023. else
  1024. {
  1025. result = (LONG)( ( Low * 100 ) / High );
  1026. }
  1027. return result;
  1028. } // CalcPercentage
  1029. #if LATER
  1030. INT
  1031. ControlHttpServer(
  1032. IN HANDLE UlHandle,
  1033. IN ULONG Command
  1034. )
  1035. {
  1036. NTSTATUS status;
  1037. IO_STATUS_BLOCK ioStatusBlock;
  1038. UL_CONTROL_HTTP_SERVER_INFO controlInfo;
  1039. controlInfo.Command = Command;
  1040. //
  1041. // Issue the request.
  1042. //
  1043. status = NtDeviceIoControlFile(
  1044. UlHandle, // FileHandle
  1045. NULL, // Event
  1046. NULL, // ApcRoutine
  1047. NULL, // ApcContext
  1048. &ioStatusBlock, // IoStatusBlock
  1049. IOCTL_UL_CONTROL_HTTP_SERVER, // IoControlCode
  1050. &controlInfo, // InputBuffer
  1051. sizeof(controlInfo), // InputBufferLength,
  1052. &controlInfo, // OutputBuffer,
  1053. sizeof(controlInfo) // OutputBufferLength
  1054. );
  1055. if (!NT_SUCCESS(status))
  1056. {
  1057. wprintf(
  1058. L"NtDeviceIoControlFile() failed, error %08lx\n",
  1059. status
  1060. );
  1061. return 1;
  1062. }
  1063. wprintf(
  1064. L"HTTP server state = %lu (%s)\n",
  1065. controlInfo.State,
  1066. UlStateToString( controlInfo.State )
  1067. );
  1068. return 0;
  1069. } // ControlHttpServer
  1070. #endif // LATER
  1071. VOID
  1072. DumpConfiguration(
  1073. IN HKEY Key
  1074. )
  1075. {
  1076. PCONFIG_ENTRY pEntry;
  1077. INT i;
  1078. INT len;
  1079. INT maxNameLength;
  1080. INT maxValueLength;
  1081. LONG err;
  1082. LONG longValue;
  1083. DWORD type;
  1084. DWORD length;
  1085. PWSTR pDefaultSuffix;
  1086. WCHAR stringValue[MAX_PATH];
  1087. //
  1088. // Scan the config table, searching for the longest parameter name.
  1089. // (This makes the output much prettier...)
  1090. //
  1091. maxNameLength = 0;
  1092. maxValueLength = 0;
  1093. for (i = NUM_CONFIG_ENTRIES, pEntry = &ConfigTable[0] ;
  1094. i > 0 ;
  1095. i--, pEntry++)
  1096. {
  1097. len = wcslen( pEntry->pConfigName );
  1098. if (len > maxNameLength)
  1099. {
  1100. maxNameLength = len;
  1101. }
  1102. if (pEntry->Type == REG_DWORD)
  1103. {
  1104. length = sizeof(pEntry->SavedValue);
  1105. pEntry->Status = RegQueryValueEx(
  1106. Key,
  1107. pEntry->pConfigName,
  1108. NULL,
  1109. &type,
  1110. (LPBYTE)&pEntry->SavedValue,
  1111. &length
  1112. );
  1113. len = swprintf(
  1114. stringValue,
  1115. pEntry->pDisplayFormat,
  1116. (LONG) pEntry->SavedValue
  1117. );
  1118. if (len > maxValueLength)
  1119. {
  1120. maxValueLength = len;
  1121. }
  1122. }
  1123. else if (pEntry->Type == REG_QWORD)
  1124. {
  1125. length = sizeof(pEntry->SavedValue);
  1126. pEntry->Status = RegQueryValueEx(
  1127. Key,
  1128. pEntry->pConfigName,
  1129. NULL,
  1130. &type,
  1131. (LPBYTE)&pEntry->SavedValue,
  1132. &length
  1133. );
  1134. len = swprintf(
  1135. stringValue,
  1136. pEntry->pDisplayFormat,
  1137. (LONGLONG) pEntry->SavedValue
  1138. );
  1139. if (len > maxValueLength)
  1140. {
  1141. maxValueLength = len;
  1142. }
  1143. }
  1144. }
  1145. //
  1146. // Now display the parameters.
  1147. //
  1148. wprintf( L"Configuration:\n" );
  1149. for (i = NUM_CONFIG_ENTRIES, pEntry = &ConfigTable[0] ;
  1150. i > 0 ;
  1151. i--, pEntry++)
  1152. {
  1153. len = 0;
  1154. pDefaultSuffix = L"";
  1155. if (pEntry->Type == REG_DWORD)
  1156. {
  1157. swprintf(
  1158. stringValue,
  1159. pEntry->pDisplayFormat,
  1160. (LONG) pEntry->SavedValue
  1161. );
  1162. if (pEntry->Status != NO_ERROR)
  1163. {
  1164. pDefaultSuffix = DEFAULT_SUFFIX_SZ;
  1165. }
  1166. len = maxValueLength;
  1167. }
  1168. else if (pEntry->Type == REG_QWORD)
  1169. {
  1170. swprintf(
  1171. stringValue,
  1172. pEntry->pDisplayFormat,
  1173. (LONGLONG) pEntry->SavedValue
  1174. );
  1175. if (pEntry->Status != NO_ERROR)
  1176. {
  1177. pDefaultSuffix = DEFAULT_SUFFIX_SZ;
  1178. }
  1179. len = maxValueLength;
  1180. }
  1181. else
  1182. {
  1183. length = sizeof(stringValue) / sizeof(stringValue[0]);
  1184. err = RegQueryValueEx(
  1185. Key,
  1186. pEntry->pConfigName,
  1187. NULL,
  1188. &type,
  1189. (LPBYTE)stringValue,
  1190. &length
  1191. );
  1192. if (err != NO_ERROR)
  1193. {
  1194. wcscpy(
  1195. stringValue,
  1196. ( pEntry->SavedValue == 0 )
  1197. ? L"(null)"
  1198. : (PWSTR)pEntry->SavedValue
  1199. );
  1200. pDefaultSuffix = DEFAULT_SUFFIX_SZ;
  1201. }
  1202. }
  1203. wprintf(
  1204. L" %-*s : %*s%s\n",
  1205. maxNameLength,
  1206. pEntry->pConfigName,
  1207. len,
  1208. stringValue,
  1209. pDefaultSuffix
  1210. );
  1211. }
  1212. } // DumpConfiguration
  1213. VOID
  1214. DumpFlags(
  1215. IN HKEY Key
  1216. )
  1217. {
  1218. LONG err;
  1219. DWORD length;
  1220. DWORD flags;
  1221. DWORD flagsDisplayed;
  1222. ULONG i;
  1223. //
  1224. // Read the flags from the registry
  1225. //
  1226. flags = DEFAULT_DEBUG_FLAGS;
  1227. length = sizeof(flags);
  1228. err = RegQueryValueEx(
  1229. Key, // key
  1230. REGISTRY_DEBUG_FLAGS, // name
  1231. NULL, // reserved
  1232. NULL, // type
  1233. (LPBYTE) &flags, // value
  1234. &length // value length
  1235. );
  1236. //
  1237. // Now display the flags
  1238. //
  1239. flagsDisplayed = 0;
  1240. wprintf( L"\n");
  1241. for (i = 0; i < NUM_FLAG_ENTRIES; i++) {
  1242. wprintf(
  1243. L"%-20s",
  1244. FlagTable[i].pName
  1245. );
  1246. if (flags & FlagTable[i].Value) {
  1247. wprintf(L"[on] ");
  1248. flagsDisplayed |= FlagTable[i].Value;
  1249. } else {
  1250. wprintf(L" ");
  1251. }
  1252. wprintf(L"%s\n", FlagTable[i].pDisplayFormat);
  1253. }
  1254. wprintf( L"\n" );
  1255. //
  1256. // dump any set flags that we missed
  1257. //
  1258. flags &= ~flagsDisplayed;
  1259. if (flags) {
  1260. wprintf(L"The following set flags are not in the table 0x%08x\n\n", flags);
  1261. }
  1262. //
  1263. // a handy thing to cut and paste
  1264. //
  1265. wprintf(L"tul flags 0x%08x\n", flags | flagsDisplayed);
  1266. } // DumpFlags
  1267. #if LATER
  1268. INT
  1269. WINAPI
  1270. DoStart(
  1271. IN HANDLE UlHandle,
  1272. IN INT argc,
  1273. IN PWSTR argv[]
  1274. )
  1275. {
  1276. INT result;
  1277. //
  1278. // Validate the arguments.
  1279. //
  1280. if (argc != 1)
  1281. {
  1282. wprintf(
  1283. L"use: tul start\n"
  1284. );
  1285. return 1;
  1286. }
  1287. //
  1288. // Do it.
  1289. //
  1290. result = ControlHttpServer(
  1291. UlHandle,
  1292. UL_HTTP_SERVER_COMMAND_START
  1293. );
  1294. return result;
  1295. } // DoStart
  1296. INT
  1297. WINAPI
  1298. DoStop(
  1299. IN HANDLE UlHandle,
  1300. IN INT argc,
  1301. IN PWSTR argv[]
  1302. )
  1303. {
  1304. INT result;
  1305. //
  1306. // Validate the arguments.
  1307. //
  1308. if (argc != 1)
  1309. {
  1310. wprintf(
  1311. L"use: tul stop\n"
  1312. );
  1313. return 1;
  1314. }
  1315. //
  1316. // Do it.
  1317. //
  1318. result = ControlHttpServer(
  1319. UlHandle,
  1320. UL_HTTP_SERVER_COMMAND_STOP
  1321. );
  1322. return result;
  1323. } // DoStop
  1324. INT
  1325. WINAPI
  1326. DoPause(
  1327. IN HANDLE UlHandle,
  1328. IN INT argc,
  1329. IN PWSTR argv[]
  1330. )
  1331. {
  1332. INT result;
  1333. //
  1334. // Validate the arguments.
  1335. //
  1336. if (argc != 1)
  1337. {
  1338. wprintf(
  1339. L"use: tul pause\n"
  1340. );
  1341. return 1;
  1342. }
  1343. //
  1344. // Do it.
  1345. //
  1346. result = ControlHttpServer(
  1347. UlHandle,
  1348. UL_HTTP_SERVER_COMMAND_PAUSE
  1349. );
  1350. return result;
  1351. } // DoPause
  1352. INT
  1353. WINAPI
  1354. DoContinue(
  1355. IN HANDLE UlHandle,
  1356. IN INT argc,
  1357. IN PWSTR argv[]
  1358. )
  1359. {
  1360. INT result;
  1361. //
  1362. // Validate the arguments.
  1363. //
  1364. if (argc != 1)
  1365. {
  1366. wprintf(
  1367. L"use: tul continue\n"
  1368. );
  1369. return 1;
  1370. }
  1371. //
  1372. // Do it.
  1373. //
  1374. result = ControlHttpServer(
  1375. UlHandle,
  1376. UL_HTTP_SERVER_COMMAND_CONTINUE
  1377. );
  1378. return result;
  1379. } // DoContinue
  1380. INT
  1381. WINAPI
  1382. DoQuery(
  1383. IN HANDLE UlHandle,
  1384. IN INT argc,
  1385. IN PWSTR argv[]
  1386. )
  1387. {
  1388. INT result;
  1389. //
  1390. // Validate the arguments.
  1391. //
  1392. if (argc != 1)
  1393. {
  1394. wprintf(
  1395. L"use: tul query\n"
  1396. );
  1397. return 1;
  1398. }
  1399. //
  1400. // Do it.
  1401. //
  1402. result = ControlHttpServer(
  1403. UlHandle,
  1404. UL_HTTP_SERVER_COMMAND_QUERY
  1405. );
  1406. return result;
  1407. } // DoQuery
  1408. INT
  1409. WINAPI
  1410. DoPerf(
  1411. IN HANDLE UlHandle,
  1412. IN INT argc,
  1413. IN PWSTR argv[]
  1414. )
  1415. {
  1416. UL_PERF_COUNTERS_USER perfCounters;
  1417. IO_STATUS_BLOCK ioStatusBlock;
  1418. NTSTATUS status;
  1419. INT i;
  1420. INT maxNameLength;
  1421. INT maxValueLength;
  1422. INT len;
  1423. PPERF_COUNTER counter;
  1424. WCHAR value[32];
  1425. WCHAR suffix[32];
  1426. //
  1427. // Validate the arguments.
  1428. //
  1429. if (argc != 1)
  1430. {
  1431. wprintf(
  1432. L"use: tul perf\n"
  1433. );
  1434. return 1;
  1435. }
  1436. //
  1437. // Read the perf counters.
  1438. //
  1439. status = NtDeviceIoControlFile(
  1440. UlHandle, // FileHandle
  1441. NULL, // Event
  1442. NULL, // ApcRoutine
  1443. NULL, // ApcContext
  1444. &ioStatusBlock, // IoStatusBlock
  1445. IOCTL_UL_QUERY_PERF_COUNTERS, // IoControlCode
  1446. NULL, // InputBuffer
  1447. 0, // InputBufferLength,
  1448. &perfCounters, // OutputBuffer,
  1449. sizeof(perfCounters) // OutputBufferLength
  1450. );
  1451. if (!NT_SUCCESS(status))
  1452. {
  1453. wprintf(
  1454. L"NtDeviceIoControlFile() failed, error %08lx\n",
  1455. status
  1456. );
  1457. return 1;
  1458. }
  1459. //
  1460. // Pass 1: Calculate the maximum lengths of the display names and
  1461. // the printable values.
  1462. //
  1463. maxNameLength = 0;
  1464. maxValueLength = 0;
  1465. for( i = NUM_PERF_COUNTERS, counter = UlPerfCounters ;
  1466. i > 0 ;
  1467. i--, counter++ ) {
  1468. len = wcslen( counter->DisplayName );
  1469. if (len > maxNameLength)
  1470. {
  1471. maxNameLength = len;
  1472. }
  1473. len = LongLongToString(
  1474. GET_LONGLONG( &perfCounters, counter->FieldOffset ),
  1475. value
  1476. );
  1477. if (len > maxValueLength)
  1478. {
  1479. maxValueLength = len;
  1480. }
  1481. }
  1482. //
  1483. // Pass 2: Display the counters.
  1484. //
  1485. wprintf( L"Performance Counters:\n" );
  1486. for( i = NUM_PERF_COUNTERS, counter = UlPerfCounters ;
  1487. i > 0 ;
  1488. i--, counter++ ) {
  1489. LongLongToString(
  1490. GET_LONGLONG( &perfCounters, counter->FieldOffset ),
  1491. value
  1492. );
  1493. suffix[0] = '\0'; // until proven otherwise...
  1494. if (counter->Type == Percentage)
  1495. {
  1496. LONGLONG high;
  1497. LONGLONG low;
  1498. high = GET_LONGLONG( &perfCounters, counter[-1].FieldOffset );
  1499. low = GET_LONGLONG( &perfCounters, counter->FieldOffset );
  1500. if (high != 0 || low != 0)
  1501. {
  1502. swprintf(
  1503. suffix,
  1504. L" [%ld%%]",
  1505. CalcPercentage(
  1506. high,
  1507. low
  1508. )
  1509. );
  1510. }
  1511. }
  1512. else
  1513. if (counter->Type == Average)
  1514. {
  1515. LONGLONG numerator;
  1516. LONGLONG divisor;
  1517. float average;
  1518. numerator = GET_LONGLONG( &perfCounters, counter->FieldOffset );
  1519. divisor = GET_LONGLONG( &perfCounters, counter[-1].FieldOffset );
  1520. if (divisor != 0)
  1521. {
  1522. average = (float)numerator / (float)divisor;
  1523. swprintf(
  1524. suffix,
  1525. L" [%.3f]",
  1526. average
  1527. );
  1528. }
  1529. }
  1530. wprintf(
  1531. L" %-*s = %*s%s\n",
  1532. maxNameLength,
  1533. counter->DisplayName,
  1534. maxValueLength,
  1535. value,
  1536. suffix
  1537. );
  1538. }
  1539. return 0;
  1540. } // DoPerf
  1541. INT
  1542. WINAPI
  1543. DoClear(
  1544. IN HANDLE UlHandle,
  1545. IN INT argc,
  1546. IN PWSTR argv[]
  1547. )
  1548. {
  1549. NTSTATUS status;
  1550. IO_STATUS_BLOCK ioStatusBlock;
  1551. //
  1552. // Validate the arguments.
  1553. //
  1554. if (argc != 1)
  1555. {
  1556. wprintf(
  1557. L"use: tul clear\n"
  1558. );
  1559. return 1;
  1560. }
  1561. //
  1562. // Issue the request.
  1563. //
  1564. status = NtDeviceIoControlFile(
  1565. UlHandle, // FileHandle
  1566. NULL, // Event
  1567. NULL, // ApcRoutine
  1568. NULL, // ApcContext
  1569. &ioStatusBlock, // IoStatusBlock
  1570. IOCTL_UL_CLEAR_PERF_COUNTERS, // IoControlCode
  1571. NULL, // InputBuffer
  1572. 0, // InputBufferLength,
  1573. NULL, // OutputBuffer,
  1574. 0 // OutputBufferLength
  1575. );
  1576. if (!NT_SUCCESS(status))
  1577. {
  1578. wprintf(
  1579. L"NtDeviceIoControlFile() failed, error %08lx\n",
  1580. status
  1581. );
  1582. return 1;
  1583. }
  1584. wprintf(
  1585. L"Performance counters cleared\n"
  1586. );
  1587. return 0;
  1588. } // DoClear
  1589. INT
  1590. WINAPI
  1591. DoFlush(
  1592. IN HANDLE UlHandle,
  1593. IN INT argc,
  1594. IN PWSTR argv[]
  1595. )
  1596. {
  1597. NTSTATUS status;
  1598. IO_STATUS_BLOCK ioStatusBlock;
  1599. //
  1600. // Validate the arguments.
  1601. //
  1602. if (argc != 1)
  1603. {
  1604. wprintf(
  1605. L"use: tul flush\n"
  1606. );
  1607. return 1;
  1608. }
  1609. //
  1610. // Issue the request.
  1611. //
  1612. status = NtDeviceIoControlFile(
  1613. UlHandle, // FileHandle
  1614. NULL, // Event
  1615. NULL, // ApcRoutine
  1616. NULL, // ApcContext
  1617. &ioStatusBlock, // IoStatusBlock
  1618. IOCTL_UL_FLUSH_FILE_CACHE, // IoControlCode
  1619. NULL, // InputBuffer
  1620. 0, // InputBufferLength,
  1621. NULL, // OutputBuffer,
  1622. 0 // OutputBufferLength
  1623. );
  1624. if (!NT_SUCCESS(status))
  1625. {
  1626. wprintf(
  1627. L"NtDeviceIoControlFile() failed, error %08lx\n",
  1628. status
  1629. );
  1630. return 1;
  1631. }
  1632. wprintf(
  1633. L"File cache flushed\n"
  1634. );
  1635. return 0;
  1636. } // DoFlush
  1637. #endif // LATER
  1638. INT
  1639. WINAPI
  1640. DoConfig(
  1641. IN HANDLE UlHandle,
  1642. IN INT argc,
  1643. IN PWSTR argv[]
  1644. )
  1645. {
  1646. PCONFIG_ENTRY pEntry;
  1647. LONG longValue;
  1648. LONGLONG longlongValue;
  1649. HKEY key;
  1650. INT result;
  1651. LONG err;
  1652. CONST BYTE * pNewValue;
  1653. DWORD newValueLength;
  1654. //
  1655. // Setup locals so we know how to cleanup on exit.
  1656. //
  1657. key = NULL;
  1658. //
  1659. // Try to open the registry.
  1660. //
  1661. err = RegOpenKeyEx(
  1662. HKEY_LOCAL_MACHINE,
  1663. L"System\\CurrentControlSet\\Services\\Http\\Parameters",
  1664. 0,
  1665. KEY_ALL_ACCESS,
  1666. &key
  1667. );
  1668. if (err != NO_ERROR)
  1669. {
  1670. wprintf(
  1671. L"tul: cannot open registry, error %ld\n",
  1672. err
  1673. );
  1674. result = 1;
  1675. goto cleanup;
  1676. }
  1677. //
  1678. // Validate the arguments.
  1679. //
  1680. if (argc == 1)
  1681. {
  1682. DumpConfiguration( key );
  1683. result = 0;
  1684. goto cleanup;
  1685. }
  1686. else
  1687. if (argc != 3)
  1688. {
  1689. wprintf(
  1690. L"use: tul config [property= value]\n"
  1691. );
  1692. result = 1;
  1693. goto cleanup;
  1694. }
  1695. //
  1696. // Find the entry.
  1697. //
  1698. pEntry = FindConfigByName( argv[1] );
  1699. if (pEntry == NULL)
  1700. {
  1701. wprintf(
  1702. L"tul: invalid property %s\n",
  1703. argv[1]
  1704. );
  1705. result = 1;
  1706. goto cleanup;
  1707. }
  1708. //
  1709. // Interpret it.
  1710. //
  1711. if (pEntry->Type == REG_DWORD)
  1712. {
  1713. if (argv[2][0] == L'-')
  1714. longValue = wcstol( argv[2], NULL, 0 );
  1715. else
  1716. longValue = (LONG) wcstoul( argv[2], NULL, 0 );
  1717. pNewValue = (CONST BYTE *)&longValue;
  1718. newValueLength = sizeof(longValue);
  1719. }
  1720. else if (pEntry->Type == REG_QWORD)
  1721. {
  1722. // Hack: because link fails for Win32 and we don't need top 32 bits on Win32
  1723. #ifndef _WIN64
  1724. # define _wcstoi64(nptr, endptr, base) \
  1725. (__int64) wcstol((nptr), (endptr), (base))
  1726. # define _wcstoui64(nptr, endptr, base) \
  1727. (unsigned __int64) wcstoul((nptr), (endptr), (base))
  1728. #endif
  1729. if (argv[2][0] == L'-')
  1730. longlongValue = _wcstoi64( argv[2], NULL, 0 );
  1731. else
  1732. longlongValue = (LONGLONG) _wcstoui64( argv[2], NULL, 0 );
  1733. pNewValue = (CONST BYTE *)&longlongValue;
  1734. newValueLength = sizeof(longlongValue);
  1735. }
  1736. else
  1737. {
  1738. pNewValue = (CONST BYTE *)argv[2];
  1739. newValueLength = (DWORD)( wcslen( argv[2] ) + 1 ) * sizeof(argv[0][0]);
  1740. }
  1741. if (_wcsicmp( argv[2], L"/delete" ) == 0)
  1742. {
  1743. err = RegDeleteValue(
  1744. key,
  1745. pEntry->pConfigName
  1746. );
  1747. }
  1748. else
  1749. {
  1750. err = RegSetValueEx(
  1751. key,
  1752. pEntry->pConfigName,
  1753. 0,
  1754. pEntry->Type,
  1755. pNewValue,
  1756. newValueLength
  1757. );
  1758. }
  1759. if (err != NO_ERROR)
  1760. {
  1761. wprintf(
  1762. L"tul: cannot write to registry, error %ld\n",
  1763. err
  1764. );
  1765. result = 1;
  1766. goto cleanup;
  1767. }
  1768. //
  1769. // Success!
  1770. //
  1771. DumpConfiguration( key );
  1772. result = 0;
  1773. cleanup:
  1774. if (key != NULL)
  1775. {
  1776. RegCloseKey( key );
  1777. }
  1778. return result;
  1779. } // DoConfig
  1780. INT
  1781. WINAPI
  1782. DoFlags(
  1783. IN HANDLE UlHandle,
  1784. IN INT argc,
  1785. IN PWSTR argv[]
  1786. )
  1787. {
  1788. HKEY key;
  1789. INT result;
  1790. LONG err;
  1791. LONG i;
  1792. ULONG flags;
  1793. //
  1794. // Setup locals so we know how to cleanup on exit.
  1795. //
  1796. key = NULL;
  1797. //
  1798. // Try to open the registry.
  1799. //
  1800. err = RegOpenKeyEx(
  1801. HKEY_LOCAL_MACHINE,
  1802. L"System\\CurrentControlSet\\Services\\Http\\Parameters",
  1803. 0,
  1804. KEY_ALL_ACCESS,
  1805. &key
  1806. );
  1807. if (err != NO_ERROR)
  1808. {
  1809. wprintf(
  1810. L"tul: cannot open registry, error %ld\n",
  1811. err
  1812. );
  1813. result = 1;
  1814. goto cleanup;
  1815. }
  1816. //
  1817. // Validate the arguments.
  1818. //
  1819. if (argc == 1)
  1820. {
  1821. DumpFlags( key );
  1822. result = 0;
  1823. goto cleanup;
  1824. }
  1825. //
  1826. // read each flag on the command line and set it
  1827. //
  1828. flags = 0;
  1829. for (i = 1; i < argc; i++) {
  1830. flags |= FindFlagByName(argv[i]);
  1831. }
  1832. err = RegSetValueEx(
  1833. key,
  1834. REGISTRY_DEBUG_FLAGS,
  1835. 0,
  1836. REG_DWORD,
  1837. (LPBYTE)&flags,
  1838. sizeof(flags)
  1839. );
  1840. //
  1841. // Success!
  1842. //
  1843. DumpFlags( key );
  1844. result = 0;
  1845. cleanup:
  1846. if (key != NULL)
  1847. {
  1848. RegCloseKey( key );
  1849. }
  1850. return result;
  1851. } // DoFlags