|
|
/*++
Copyright (c) 1998-2001 Microsoft Corporation
Module Name:
tul.c
Abstract:
Stupid test file for HTTP.SYS (formerly UL.SYS).
Author:
Keith Moore (keithmo) 17-Jun-1998
Revision History:
--*/
#include "precomp.h"
#pragma hdrstop
#include <..\..\drv\config.h>
// this funny business gets me the UL_DEBUG_* flags on free builds
#if !DBG
#undef DBG
#define DBG 1
#define DBG_FLIP
#endif
#include <..\..\drv\debug.h>
#ifdef DBG_FLIP
#undef DBG_FLIP
#undef DBG
#define DBG 0
#endif
//
// Our command table.
//
typedef INT (WINAPI * PFN_COMMAND)( IN HANDLE UlHandle, IN INT argc, IN PWSTR argv[] );
typedef struct _COMMAND_ENTRY { PWSTR pCommandName; PWSTR pUsageHelp; PFN_COMMAND pCommandHandler; BOOL AutoStartUl; } COMMAND_ENTRY, *PCOMMAND_ENTRY;
//
// Performance counters.
//
#if LATER
typedef enum _COUNTER_TYPE { Cumulative, Percentage, Average
} COUNTER_TYPE, *PCOUNTER_TYPE;
typedef struct _PERF_COUNTER { PWSTR pDisplayName; LONG FieldOffset; COUNTER_TYPE Type;
} PERF_COUNTER, *PPERF_COUNTER;
#define MAKE_CUMULATIVE( name ) \
{ \ (PWSTR)L#name, \ FIELD_OFFSET( UL_PERF_COUNTERS_USER, name ), \ Cumulative \ }
#define MAKE_PERCENTAGE( name ) \
{ \ (PWSTR)L#name, \ FIELD_OFFSET( UL_PERF_COUNTERS_USER, name ), \ Percentage \ }
#define MAKE_AVERAGE( name ) \
{ \ (PWSTR)L#name, \ FIELD_OFFSET( UL_PERF_COUNTERS_USER, name ), \ Average \ }
PERF_COUNTER UlPerfCounters[] = { MAKE_CUMULATIVE( BytesReceived ), MAKE_CUMULATIVE( BytesSent ), MAKE_CUMULATIVE( ConnectionsReceived ), MAKE_CUMULATIVE( FilesSent ), MAKE_CUMULATIVE( FileCacheAttempts ), MAKE_PERCENTAGE( FileCacheHits ), MAKE_CUMULATIVE( FileCacheNegativeHits ), MAKE_CUMULATIVE( FileCacheEntries ), MAKE_CUMULATIVE( FastAcceptAttempted ), MAKE_PERCENTAGE( FastAcceptSucceeded ), MAKE_CUMULATIVE( FastReceiveAttempted ), MAKE_PERCENTAGE( FastReceiveSucceeded ), MAKE_CUMULATIVE( FastSendAttempted ), MAKE_PERCENTAGE( FastSendSucceeded ), MAKE_CUMULATIVE( MdlReadAttempted ), MAKE_PERCENTAGE( MdlReadSucceeded ), MAKE_CUMULATIVE( DecAvailThreads ), MAKE_AVERAGE( DecAvailThreadsRetry ), MAKE_CUMULATIVE( IncAvailThreads ), MAKE_AVERAGE( IncAvailThreadsRetry ), MAKE_CUMULATIVE( DecAvailPending ), MAKE_AVERAGE( DecAvailPendingRetry ), MAKE_CUMULATIVE( DecNumberOfThreads ), MAKE_AVERAGE( DecNumberOfThreadsRetry ), MAKE_CUMULATIVE( IncNumberOfThreads ), MAKE_AVERAGE( IncNumberOfThreadsRetry ), MAKE_CUMULATIVE( CreateSession ), MAKE_AVERAGE( CreateSessionRetry ), MAKE_CUMULATIVE( DestroySession ), MAKE_AVERAGE( DestroySessionRetry ), MAKE_CUMULATIVE( IncAcceptPending ), MAKE_AVERAGE( IncAcceptPendingRetry ), MAKE_CUMULATIVE( DecAcceptPending ), MAKE_AVERAGE( DecAcceptPendingRetry ), MAKE_CUMULATIVE( PerCpuNetworkDpcCounters[0] ), MAKE_CUMULATIVE( PerCpuNetworkDpcCounters[1] ), MAKE_CUMULATIVE( PerCpuNetworkDpcCounters[2] ), MAKE_CUMULATIVE( PerCpuNetworkDpcCounters[3] ), MAKE_CUMULATIVE( PerCpuFileSystemDpcCounters[0] ), MAKE_CUMULATIVE( PerCpuFileSystemDpcCounters[1] ), MAKE_CUMULATIVE( PerCpuFileSystemDpcCounters[2] ), MAKE_CUMULATIVE( PerCpuFileSystemDpcCounters[3] ), MAKE_CUMULATIVE( PerCpuThreadPoolActivity[0] ), MAKE_CUMULATIVE( PerCpuThreadPoolActivity[1] ), MAKE_CUMULATIVE( PerCpuThreadPoolActivity[2] ), MAKE_CUMULATIVE( PerCpuThreadPoolActivity[3] ) };
#define NUM_PERF_COUNTERS (sizeof(UlPerfCounters) / sizeof(UlPerfCounters[0]))
#define GET_LONGLONG( buffer, offset ) \
*(LONGLONG *)(((PCHAR)(buffer)) + (offset)) #endif // LATER
//
// Configuration stuff.
//
typedef struct _CONFIG_ENTRY { PWSTR pConfigName; PWSTR pDisplayFormat; ULONG Type; LONGLONG SavedValue; LONG Status;
} CONFIG_ENTRY, *PCONFIG_ENTRY;
CONFIG_ENTRY ConfigTable[] = { { REGISTRY_IRP_STACK_SIZE, L"%lu", REG_DWORD, DEFAULT_IRP_STACK_SIZE },
{ REGISTRY_PRIORITY_BOOST, L"%lu", REG_DWORD, DEFAULT_PRIORITY_BOOST },
{ REGISTRY_DEBUG_FLAGS, L"%08lx", REG_DWORD, DEFAULT_DEBUG_FLAGS },
{ REGISTRY_BREAK_ON_STARTUP, L"%lu", REG_DWORD, DEFAULT_BREAK_ON_STARTUP },
{ REGISTRY_BREAK_ON_ERROR, L"%lu", REG_DWORD, DEFAULT_BREAK_ON_ERROR },
{ REGISTRY_VERBOSE_ERRORS, L"%lu", REG_DWORD, DEFAULT_VERBOSE_ERRORS },
{ REGISTRY_ENABLE_UNLOAD, L"%lu", REG_DWORD, DEFAULT_ENABLE_UNLOAD },
{ REGISTRY_ENABLE_SECURITY, L"%lu", REG_DWORD, DEFAULT_ENABLE_SECURITY },
{ REGISTRY_MIN_IDLE_CONNECTIONS, L"%lu", REG_DWORD, DEFAULT_MIN_IDLE_CONNECTIONS },
{ REGISTRY_MAX_IDLE_CONNECTIONS, L"%lu", REG_DWORD, DEFAULT_MAX_IDLE_CONNECTIONS },
{ REGISTRY_IRP_CONTEXT_LOOKASIDE_DEPTH, L"%lu", REG_DWORD, DEFAULT_IRP_CONTEXT_LOOKASIDE_DEPTH },
{ REGISTRY_RCV_BUFFER_SIZE, L"%lu", REG_DWORD, DEFAULT_RCV_BUFFER_SIZE },
{ REGISTRY_RCV_BUFFER_LOOKASIDE_DEPTH, L"%lu", REG_DWORD, DEFAULT_RCV_BUFFER_LOOKASIDE_DEPTH },
{ REGISTRY_RESOURCE_LOOKASIDE_DEPTH, L"%lu", REG_DWORD, DEFAULT_RESOURCE_LOOKASIDE_DEPTH },
{ REGISTRY_REQ_BUFFER_LOOKASIDE_DEPTH, L"%lu", REG_DWORD, DEFAULT_REQ_BUFFER_LOOKASIDE_DEPTH },
{ REGISTRY_INT_REQUEST_LOOKASIDE_DEPTH, L"%lu", REG_DWORD, DEFAULT_INT_REQUEST_LOOKASIDE_DEPTH },
{ REGISTRY_RESP_BUFFER_SIZE, L"%lu", REG_DWORD, DEFAULT_RESP_BUFFER_SIZE },
{ REGISTRY_RESP_BUFFER_LOOKASIDE_DEPTH, L"%lu", REG_DWORD, DEFAULT_RESP_BUFFER_LOOKASIDE_DEPTH },
{ REGISTRY_SEND_TRACKER_LOOKASIDE_DEPTH, L"%lu", REG_DWORD, DEFAULT_SEND_TRACKER_LOOKASIDE_DEPTH },
{ REGISTRY_LOG_BUFFER_LOOKASIDE_DEPTH, L"%lu", REG_DWORD, DEFAULT_LOG_BUFFER_LOOKASIDE_DEPTH },
{ REGISTRY_MAX_INTERNAL_URL_LENGTH, L"%lu", REG_DWORD, DEFAULT_MAX_INTERNAL_URL_LENGTH },
{ REGISTRY_MAX_REQUEST_BYTES, L"%lu", REG_DWORD, DEFAULT_MAX_REQUEST_BYTES },
{ REGISTRY_ENABLE_CONNECTION_REUSE, L"%lu", REG_DWORD, DEFAULT_ENABLE_CONNECTION_REUSE },
{ REGISTRY_ENABLE_NAGLING, L"%lu", REG_DWORD, DEFAULT_ENABLE_NAGLING },
{ REGISTRY_ENABLE_THREAD_AFFINITY, L"%lu", REG_DWORD, DEFAULT_ENABLE_THREAD_AFFINITY },
{ REGISTRY_THREAD_AFFINITY_MASK, L"%I64x", REG_QWORD, 0 },
{ REGISTRY_THREADS_PER_CPU, L"%lu", REG_DWORD, DEFAULT_THREADS_PER_CPU },
{ REGISTRY_MAX_WORK_QUEUE_DEPTH, L"%lu", REG_DWORD, DEFAULT_MAX_WORK_QUEUE_DEPTH, },
{ REGISTRY_MIN_WORK_DEQUEUE_DEPTH, L"%lu", REG_DWORD, DEFAULT_MIN_WORK_DEQUEUE_DEPTH, },
{ REGISTRY_MAX_URL_LENGTH, L"%lu", REG_DWORD, DEFAULT_MAX_URL_LENGTH },
{ REGISTRY_MAX_FIELD_LENGTH, L"%lu", REG_DWORD, DEFAULT_MAX_FIELD_LENGTH },
{ REGISTRY_DEBUG_LOGTIMER_CYCLE, L"%lu", REG_DWORD, DEFAULT_DEBUG_LOGTIMER_CYCLE },
{ REGISTRY_DEBUG_LOG_BUFFER_PERIOD, L"%lu", REG_DWORD, DEFAULT_DEBUG_LOG_BUFFER_PERIOD },
{ REGISTRY_LOG_BUFFER_SIZE, L"%lu", REG_DWORD, DEFAULT_LOG_BUFFER_SIZE },
{ REGISTRY_ENABLE_NON_UTF8_URL, L"%lu", REG_DWORD, DEFAULT_ENABLE_NON_UTF8_URL },
{ REGISTRY_ENABLE_DBCS_URL, L"%lu", REG_DWORD, DEFAULT_ENABLE_DBCS_URL },
{ REGISTRY_FAVOR_DBCS_URL, L"%lu", REG_DWORD, DEFAULT_FAVOR_DBCS_URL },
{ REGISTRY_CACHE_ENABLED, L"%lu", REG_DWORD, DEFAULT_CACHE_ENABLED },
{ REGISTRY_MAX_CACHE_URI_COUNT, L"%lu", REG_DWORD, DEFAULT_MAX_CACHE_URI_COUNT },
{ REGISTRY_MAX_CACHE_MEGABYTE_COUNT, L"%lu", REG_DWORD, DEFAULT_MAX_CACHE_MEGABYTE_COUNT },
{ REGISTRY_CACHE_SCAVENGER_PERIOD, L"%lu", REG_DWORD, DEFAULT_CACHE_SCAVENGER_PERIOD },
{ REGISTRY_MAX_URI_BYTES, L"%lu", REG_DWORD, DEFAULT_MAX_URI_BYTES },
{ REGISTRY_HASH_TABLE_BITS, L"%ld", REG_DWORD, DEFAULT_HASH_TABLE_BITS },
{ REGISTRY_LARGE_MEM_MEGABYTES, L"%ld", REG_DWORD, DEFAULT_LARGE_MEM_MEGABYTES },
{ REGISTRY_OPAQUE_ID_TABLE_SIZE, L"%lu", REG_DWORD, DEFAULT_OPAQUE_ID_TABLE_SIZE },
};
#define NUM_CONFIG_ENTRIES (sizeof(ConfigTable) / sizeof(ConfigTable[0]))
#define DEFAULT_SUFFIX_SZ L" [default]"
typedef struct _FLAG_ENTRY { PWSTR pName; PWSTR pDisplayFormat; LONG Value; } FLAG_ENTRY, *PFLAG_ENTRY;
#define MAKE_FLAG( name, display ) \
{ \ (PWSTR)L#name, \ (display), \ UL_DEBUG_ ## name \ }
FLAG_ENTRY FlagTable[] = { MAKE_FLAG(OPEN_CLOSE, L"file object create/close"), MAKE_FLAG(SEND_RESPONSE, L"send response ioctl"), MAKE_FLAG(SEND_BUFFER, L"send buffer"), MAKE_FLAG(TDI, L"low level network stuff"),
MAKE_FLAG(FILE_CACHE, L"open/close files"), MAKE_FLAG(CONFIG_GROUP_FNC, L"config group changes"), MAKE_FLAG(CONFIG_GROUP_TREE, L"cgroup tree operations"), MAKE_FLAG(REFCOUNT, L"object refcounting"),
MAKE_FLAG(HTTP_IO, L"high level network & buffers"), MAKE_FLAG(ROUTING, L"request to process routing"), MAKE_FLAG(URI_CACHE, L"uri content cache"), MAKE_FLAG(PARSER, L"request parsing"),
MAKE_FLAG(SITE, L"sites and endpoints"), MAKE_FLAG(WORK_ITEM, L"thread pool work queue"), MAKE_FLAG(FILTER, L"filters and ssl"), MAKE_FLAG(LOGGING, L"ul logging"),
MAKE_FLAG(TC, L"traffic control"), MAKE_FLAG(OPAQUE_ID, L"opaque ids"), MAKE_FLAG(PERF_COUNTERS, L"perf counters"), MAKE_FLAG(LKRHASH, L"LKRhash hashtables"),
MAKE_FLAG(TIMEOUTS, L"timeout monitor"), MAKE_FLAG(LIMITS, L"connection limits"), MAKE_FLAG(LARGE_MEM, L"large memory"), MAKE_FLAG(IOCTL, L"ioctl"),
MAKE_FLAG(VERBOSE, L"verbose"), };
#define NUM_FLAG_ENTRIES (sizeof(FlagTable) / sizeof(FlagTable[0]))
DEFINE_COMMON_GLOBALS();
VOID Usage( VOID );
NTSTATUS OpenUlDevice( PHANDLE pHandle );
BOOL TryToStartUlDevice( VOID );
INT LongLongToString( LONGLONG Value, PWSTR pBuffer );
LONG CalcPercentage( LONGLONG High, LONGLONG Low );
PCOMMAND_ENTRY FindCommandByName( IN PWSTR pCommand );
PCONFIG_ENTRY FindConfigByName( IN PWSTR pConfig );
ULONG FindFlagByName( IN PWSTR pFlagName );
INT ControlHttpServer( IN HANDLE UlHandle, IN ULONG Command );
VOID DumpConfiguration( IN HKEY Key );
VOID DumpFlags( IN HKEY Key );
#if LATER
INT WINAPI DoStart( IN HANDLE UlHandle, IN INT argc, IN PWSTR argv[] );
INT WINAPI DoStop( IN HANDLE UlHandle, IN INT argc, IN PWSTR argv[] );
INT WINAPI DoPause( IN HANDLE UlHandle, IN INT argc, IN PWSTR argv[] );
INT WINAPI DoContinue( IN HANDLE UlHandle, IN INT argc, IN PWSTR argv[] );
INT WINAPI DoQuery( IN HANDLE UlHandle, IN INT argc, IN PWSTR argv[] );
INT WINAPI DoPerf( IN HANDLE UlHandle, IN INT argc, IN PWSTR argv[] );
INT WINAPI DoClear( IN HANDLE UlHandle, IN INT argc, IN PWSTR argv[] );
INT WINAPI DoFlush( IN HANDLE UlHandle, IN INT argc, IN PWSTR argv[] ); #endif // LATER
INT WINAPI DoConfig( IN HANDLE UlHandle, IN INT argc, IN PWSTR argv[] );
INT WINAPI DoFlags( IN HANDLE UlHandle, IN INT argc, IN PWSTR argv[] );
COMMAND_ENTRY CommandTable[] = { #if LATER
{ L"start", L"starts the server", &DoStart, TRUE },
{ L"stop", L"stops the server", &DoStop, TRUE },
{ L"pause", L"pauses the server", &DoPause, TRUE },
{ L"continue", L"continues the server", &DoContinue, TRUE },
{ L"query", L"queries the current state", &DoQuery, TRUE },
{ L"perf", L"displays perf counters", &DoPerf, TRUE },
{ L"clear", L"clears perf counters", &DoClear, TRUE },
{ L"flush", L"flushes file cache", &DoFlush, TRUE }, #endif // LATER
{ L"config", L"configures the server", &DoConfig, FALSE },
{ L"flags", L"configures debug flags", &DoFlags, FALSE }
};
#define NUM_COMMAND_ENTRIES (sizeof(CommandTable) / sizeof(CommandTable[0]))
INT __cdecl wmain( INT argc, PWSTR argv[] ) { NTSTATUS status; HANDLE handle; PCOMMAND_ENTRY pEntry; INT result; ULONG err;
//
// Initialize.
//
setvbuf( stdin, NULL, _IONBF, 0 ); setvbuf( stdout, NULL, _IONBF, 0 );
//
// Setup locals so we know how to cleanup on exit.
//
handle = NULL;
//
// Find the command handler.
//
if (argc == 1) { pEntry = NULL; } else { pEntry = FindCommandByName( argv[1] ); }
if (pEntry == NULL) { Usage(); result = 1; goto cleanup; }
//
// Open the UL.SYS device.
//
status = OpenUlDevice( &handle );
if (!NT_SUCCESS(status)) { if (pEntry->AutoStartUl) { if (TryToStartUlDevice()) { status = OpenUlDevice( &handle ); } } else { status = STATUS_SUCCESS; } }
if (!NT_SUCCESS(status)) { wprintf( L"Cannot open %s, error %08lx\n", HTTP_CONTROL_DEVICE_NAME, status );
result = 1; goto cleanup; }
//
// Call the handler.
//
argc--; argv++;
result = (pEntry->pCommandHandler)( handle, argc, argv );
cleanup:
if (handle != NULL) { NtClose( handle ); }
return result;
} // main
PCOMMAND_ENTRY FindCommandByName( IN PWSTR pCommand ) { PCOMMAND_ENTRY pEntry; INT i;
for (i = NUM_COMMAND_ENTRIES, pEntry = &CommandTable[0] ; i > 0 ; i--, pEntry++) { if (_wcsicmp( pCommand, pEntry->pCommandName ) == 0) { return pEntry; } }
return NULL;
} // FindCommandByName
PCONFIG_ENTRY FindConfigByName( IN PWSTR pConfig ) { PCONFIG_ENTRY pEntry; INT i; INT len;
//
// First off, validate that the incoming configuration name
// is of the form "property=". The trailing '=' is required.
//
len = wcslen( pConfig );
if (pConfig[len - 1] != L'=') { return NULL; }
len--;
for (i = NUM_CONFIG_ENTRIES, pEntry = &ConfigTable[0] ; i > 0 ; i--, pEntry++) { if ((INT)wcslen( pEntry->pConfigName ) == len && _wcsnicmp( pConfig, pEntry->pConfigName, len ) == 0) { return pEntry; } }
return NULL;
} // FindConfigByName
ULONG FindFlagByName( IN PWSTR pFlagName ) { INT len; ULONG flags; ULONG i;
len = wcslen(pFlagName); if ((len > 2) && (wcsncmp(pFlagName, L"0x", 2) == 0)) { // numeric flag
flags = wcstoul(pFlagName, NULL, 16); } else { // named flag
flags = 0; for (i = 0; i < NUM_FLAG_ENTRIES; i++) { if (_wcsicmp(pFlagName, FlagTable[i].pName) == 0) { flags = FlagTable[i].Value; break; } } }
return flags; }
VOID Usage( VOID ) { PCOMMAND_ENTRY pEntry; INT i; INT maxLength; INT len;
//
// Scan the command table, searching for the longest command name.
// (This makes the output much prettier...)
//
maxLength = 0;
for (i = NUM_COMMAND_ENTRIES, pEntry = &CommandTable[0] ; i > 0 ; i--, pEntry++) { len = wcslen( pEntry->pCommandName );
if (len > maxLength) { maxLength = len; } }
//
// Now display the usage information.
//
wprintf( L"use: tul action [options]\n" L"\n" L"valid actions are:\n" L"\n" );
for (i = NUM_COMMAND_ENTRIES, pEntry = &CommandTable[0] ; i > 0 ; i--, pEntry++) { wprintf( L" %-*s - %s\n", maxLength, pEntry->pCommandName, pEntry->pUsageHelp ); }
} // Usage
NTSTATUS OpenUlDevice( PHANDLE pHandle ) { NTSTATUS status; OBJECT_ATTRIBUTES objectAttributes; UNICODE_STRING deviceName; IO_STATUS_BLOCK ioStatusBlock;
//
// Open the UL device.
//
RtlInitUnicodeString( &deviceName, HTTP_CONTROL_DEVICE_NAME );
InitializeObjectAttributes( &objectAttributes, // ObjectAttributes
&deviceName, // ObjectName
OBJ_CASE_INSENSITIVE, // Attributes
NULL, // RootDirectory
NULL // SecurityDescriptor
);
status = NtCreateFile( pHandle, // FileHandle
GENERIC_READ | // DesiredAccess
GENERIC_WRITE | SYNCHRONIZE, &objectAttributes, // ObjectAttributes
&ioStatusBlock, // IoStatusBlock
NULL, // AllocationSize
0, // FileAttributes
FILE_SHARE_READ | // ShareAccess
FILE_SHARE_WRITE, FILE_OPEN_IF, // CreateDisposition
FILE_SYNCHRONOUS_IO_NONALERT, // CreateOptions
NULL, // EaBuffer
0 // EaLength
);
if (!NT_SUCCESS(status)) { *pHandle = NULL; }
return status;
} // OpenHdhDevice
BOOL TryToStartUlDevice( VOID ) { BOOL result = FALSE; SC_HANDLE scHandle = NULL; SC_HANDLE svcHandle = NULL;
scHandle = OpenSCManager( NULL, NULL, SC_MANAGER_ALL_ACCESS );
if (scHandle == NULL) { goto exit; }
svcHandle = OpenService( scHandle, L"Ul", SERVICE_ALL_ACCESS );
if (svcHandle == NULL) { goto exit; }
if (!StartService( svcHandle, 0, NULL )) { goto exit; }
result = TRUE;
exit:
if (svcHandle != NULL) { CloseServiceHandle( svcHandle ); }
if (scHandle != NULL) { CloseServiceHandle( scHandle ); }
return result;
} // TryToStartHdhDevice
INT LongLongToString( LONGLONG Value, PWSTR pBuffer ) { PWSTR p1; PWSTR p2; WCHAR ch; INT digit; BOOL negative; INT count; BOOL needComma; INT length; ULONGLONG unsignedValue;
//
// Handling zero specially makes everything else a bit easier.
//
if (Value == 0) { wcscpy( pBuffer, L"0" ); return 1; }
//
// Remember if the value is negative.
//
if (Value < 0) { negative = TRUE; unsignedValue = (ULONGLONG)-Value; } else { negative = FALSE; unsignedValue = (ULONGLONG)Value; }
//
// Pull the least signifigant digits off the value and store them
// into the buffer. Note that this will store the digits in the
// reverse order.
//
p1 = p2 = pBuffer; count = 3; needComma = FALSE;
while (unsignedValue != 0) { if (needComma) { *p1++ = L','; needComma = FALSE; }
digit = (INT)( unsignedValue % 10 ); unsignedValue = unsignedValue / 10;
*p1++ = L'0' + digit;
count--; if (count == 0) { count = 3; needComma = TRUE; } }
//
// Tack on a leading L'-' if necessary.
//
if (negative) { *p1++ = L'-'; }
length = (INT)( p1 - pBuffer );
//
// Reverse the digits in the buffer.
//
*p1-- = L'\0';
while (p1 > p2) { ch = *p1; *p1 = *p2; *p2 = ch;
p2++; p1--; }
return length;
} // LongLongToString
LONG CalcPercentage( LONGLONG High, LONGLONG Low ) {
LONG result;
if (High == 0 || Low == 0) { result = 0; } else { result = (LONG)( ( Low * 100 ) / High ); }
return result;
} // CalcPercentage
#if LATER
INT ControlHttpServer( IN HANDLE UlHandle, IN ULONG Command ) {
NTSTATUS status; IO_STATUS_BLOCK ioStatusBlock; UL_CONTROL_HTTP_SERVER_INFO controlInfo;
controlInfo.Command = Command;
//
// Issue the request.
//
status = NtDeviceIoControlFile( UlHandle, // FileHandle
NULL, // Event
NULL, // ApcRoutine
NULL, // ApcContext
&ioStatusBlock, // IoStatusBlock
IOCTL_UL_CONTROL_HTTP_SERVER, // IoControlCode
&controlInfo, // InputBuffer
sizeof(controlInfo), // InputBufferLength,
&controlInfo, // OutputBuffer,
sizeof(controlInfo) // OutputBufferLength
);
if (!NT_SUCCESS(status)) { wprintf( L"NtDeviceIoControlFile() failed, error %08lx\n", status ); return 1; }
wprintf( L"HTTP server state = %lu (%s)\n", controlInfo.State, UlStateToString( controlInfo.State ) );
return 0;
} // ControlHttpServer
#endif // LATER
VOID DumpConfiguration( IN HKEY Key ) { PCONFIG_ENTRY pEntry; INT i; INT len; INT maxNameLength; INT maxValueLength; LONG err; LONG longValue; DWORD type; DWORD length; PWSTR pDefaultSuffix; WCHAR stringValue[MAX_PATH];
//
// Scan the config table, searching for the longest parameter name.
// (This makes the output much prettier...)
//
maxNameLength = 0; maxValueLength = 0;
for (i = NUM_CONFIG_ENTRIES, pEntry = &ConfigTable[0] ; i > 0 ; i--, pEntry++) { len = wcslen( pEntry->pConfigName );
if (len > maxNameLength) { maxNameLength = len; }
if (pEntry->Type == REG_DWORD) { length = sizeof(pEntry->SavedValue);
pEntry->Status = RegQueryValueEx( Key, pEntry->pConfigName, NULL, &type, (LPBYTE)&pEntry->SavedValue, &length );
len = swprintf( stringValue, pEntry->pDisplayFormat, (LONG) pEntry->SavedValue );
if (len > maxValueLength) { maxValueLength = len; } } else if (pEntry->Type == REG_QWORD) { length = sizeof(pEntry->SavedValue);
pEntry->Status = RegQueryValueEx( Key, pEntry->pConfigName, NULL, &type, (LPBYTE)&pEntry->SavedValue, &length );
len = swprintf( stringValue, pEntry->pDisplayFormat, (LONGLONG) pEntry->SavedValue );
if (len > maxValueLength) { maxValueLength = len; } } }
//
// Now display the parameters.
//
wprintf( L"Configuration:\n" );
for (i = NUM_CONFIG_ENTRIES, pEntry = &ConfigTable[0] ; i > 0 ; i--, pEntry++) { len = 0; pDefaultSuffix = L"";
if (pEntry->Type == REG_DWORD) { swprintf( stringValue, pEntry->pDisplayFormat, (LONG) pEntry->SavedValue );
if (pEntry->Status != NO_ERROR) { pDefaultSuffix = DEFAULT_SUFFIX_SZ; }
len = maxValueLength; } else if (pEntry->Type == REG_QWORD) { swprintf( stringValue, pEntry->pDisplayFormat, (LONGLONG) pEntry->SavedValue );
if (pEntry->Status != NO_ERROR) { pDefaultSuffix = DEFAULT_SUFFIX_SZ; }
len = maxValueLength; } else { length = sizeof(stringValue) / sizeof(stringValue[0]);
err = RegQueryValueEx( Key, pEntry->pConfigName, NULL, &type, (LPBYTE)stringValue, &length );
if (err != NO_ERROR) { wcscpy( stringValue, ( pEntry->SavedValue == 0 ) ? L"(null)" : (PWSTR)pEntry->SavedValue );
pDefaultSuffix = DEFAULT_SUFFIX_SZ; } }
wprintf( L" %-*s : %*s%s\n", maxNameLength, pEntry->pConfigName, len, stringValue, pDefaultSuffix ); }
} // DumpConfiguration
VOID DumpFlags( IN HKEY Key ) { LONG err; DWORD length; DWORD flags; DWORD flagsDisplayed; ULONG i;
//
// Read the flags from the registry
//
flags = DEFAULT_DEBUG_FLAGS; length = sizeof(flags);
err = RegQueryValueEx( Key, // key
REGISTRY_DEBUG_FLAGS, // name
NULL, // reserved
NULL, // type
(LPBYTE) &flags, // value
&length // value length
);
//
// Now display the flags
//
flagsDisplayed = 0;
wprintf( L"\n"); for (i = 0; i < NUM_FLAG_ENTRIES; i++) { wprintf( L"%-20s", FlagTable[i].pName );
if (flags & FlagTable[i].Value) { wprintf(L"[on] "); flagsDisplayed |= FlagTable[i].Value; } else { wprintf(L" "); }
wprintf(L"%s\n", FlagTable[i].pDisplayFormat); } wprintf( L"\n" );
//
// dump any set flags that we missed
//
flags &= ~flagsDisplayed; if (flags) { wprintf(L"The following set flags are not in the table 0x%08x\n\n", flags); }
//
// a handy thing to cut and paste
//
wprintf(L"tul flags 0x%08x\n", flags | flagsDisplayed);
} // DumpFlags
#if LATER
INT WINAPI DoStart( IN HANDLE UlHandle, IN INT argc, IN PWSTR argv[] ) {
INT result;
//
// Validate the arguments.
//
if (argc != 1) { wprintf( L"use: tul start\n" ); return 1; }
//
// Do it.
//
result = ControlHttpServer( UlHandle, UL_HTTP_SERVER_COMMAND_START );
return result;
} // DoStart
INT WINAPI DoStop( IN HANDLE UlHandle, IN INT argc, IN PWSTR argv[] ) {
INT result;
//
// Validate the arguments.
//
if (argc != 1) { wprintf( L"use: tul stop\n" ); return 1; }
//
// Do it.
//
result = ControlHttpServer( UlHandle, UL_HTTP_SERVER_COMMAND_STOP );
return result;
} // DoStop
INT WINAPI DoPause( IN HANDLE UlHandle, IN INT argc, IN PWSTR argv[] ) {
INT result;
//
// Validate the arguments.
//
if (argc != 1) { wprintf( L"use: tul pause\n" ); return 1; }
//
// Do it.
//
result = ControlHttpServer( UlHandle, UL_HTTP_SERVER_COMMAND_PAUSE );
return result;
} // DoPause
INT WINAPI DoContinue( IN HANDLE UlHandle, IN INT argc, IN PWSTR argv[] ) {
INT result;
//
// Validate the arguments.
//
if (argc != 1) { wprintf( L"use: tul continue\n" ); return 1; }
//
// Do it.
//
result = ControlHttpServer( UlHandle, UL_HTTP_SERVER_COMMAND_CONTINUE );
return result;
} // DoContinue
INT WINAPI DoQuery( IN HANDLE UlHandle, IN INT argc, IN PWSTR argv[] ) {
INT result;
//
// Validate the arguments.
//
if (argc != 1) { wprintf( L"use: tul query\n" ); return 1; }
//
// Do it.
//
result = ControlHttpServer( UlHandle, UL_HTTP_SERVER_COMMAND_QUERY );
return result;
} // DoQuery
INT WINAPI DoPerf( IN HANDLE UlHandle, IN INT argc, IN PWSTR argv[] ) {
UL_PERF_COUNTERS_USER perfCounters; IO_STATUS_BLOCK ioStatusBlock; NTSTATUS status; INT i; INT maxNameLength; INT maxValueLength; INT len; PPERF_COUNTER counter; WCHAR value[32]; WCHAR suffix[32];
//
// Validate the arguments.
//
if (argc != 1) { wprintf( L"use: tul perf\n" ); return 1; }
//
// Read the perf counters.
//
status = NtDeviceIoControlFile( UlHandle, // FileHandle
NULL, // Event
NULL, // ApcRoutine
NULL, // ApcContext
&ioStatusBlock, // IoStatusBlock
IOCTL_UL_QUERY_PERF_COUNTERS, // IoControlCode
NULL, // InputBuffer
0, // InputBufferLength,
&perfCounters, // OutputBuffer,
sizeof(perfCounters) // OutputBufferLength
);
if (!NT_SUCCESS(status)) { wprintf( L"NtDeviceIoControlFile() failed, error %08lx\n", status ); return 1; }
//
// Pass 1: Calculate the maximum lengths of the display names and
// the printable values.
//
maxNameLength = 0; maxValueLength = 0;
for( i = NUM_PERF_COUNTERS, counter = UlPerfCounters ; i > 0 ; i--, counter++ ) {
len = wcslen( counter->DisplayName ); if (len > maxNameLength) { maxNameLength = len; }
len = LongLongToString( GET_LONGLONG( &perfCounters, counter->FieldOffset ), value ); if (len > maxValueLength) { maxValueLength = len; }
}
//
// Pass 2: Display the counters.
//
wprintf( L"Performance Counters:\n" );
for( i = NUM_PERF_COUNTERS, counter = UlPerfCounters ; i > 0 ; i--, counter++ ) {
LongLongToString( GET_LONGLONG( &perfCounters, counter->FieldOffset ), value );
suffix[0] = '\0'; // until proven otherwise...
if (counter->Type == Percentage) { LONGLONG high; LONGLONG low;
high = GET_LONGLONG( &perfCounters, counter[-1].FieldOffset ); low = GET_LONGLONG( &perfCounters, counter->FieldOffset );
if (high != 0 || low != 0) { swprintf( suffix, L" [%ld%%]", CalcPercentage( high, low ) ); } } else if (counter->Type == Average) { LONGLONG numerator; LONGLONG divisor; float average;
numerator = GET_LONGLONG( &perfCounters, counter->FieldOffset ); divisor = GET_LONGLONG( &perfCounters, counter[-1].FieldOffset );
if (divisor != 0) { average = (float)numerator / (float)divisor;
swprintf( suffix, L" [%.3f]", average ); } }
wprintf( L" %-*s = %*s%s\n", maxNameLength, counter->DisplayName, maxValueLength, value, suffix );
}
return 0;
} // DoPerf
INT WINAPI DoClear( IN HANDLE UlHandle, IN INT argc, IN PWSTR argv[] ) {
NTSTATUS status; IO_STATUS_BLOCK ioStatusBlock;
//
// Validate the arguments.
//
if (argc != 1) { wprintf( L"use: tul clear\n" ); return 1; }
//
// Issue the request.
//
status = NtDeviceIoControlFile( UlHandle, // FileHandle
NULL, // Event
NULL, // ApcRoutine
NULL, // ApcContext
&ioStatusBlock, // IoStatusBlock
IOCTL_UL_CLEAR_PERF_COUNTERS, // IoControlCode
NULL, // InputBuffer
0, // InputBufferLength,
NULL, // OutputBuffer,
0 // OutputBufferLength
);
if (!NT_SUCCESS(status)) { wprintf( L"NtDeviceIoControlFile() failed, error %08lx\n", status ); return 1; }
wprintf( L"Performance counters cleared\n" );
return 0;
} // DoClear
INT WINAPI DoFlush( IN HANDLE UlHandle, IN INT argc, IN PWSTR argv[] ) {
NTSTATUS status; IO_STATUS_BLOCK ioStatusBlock;
//
// Validate the arguments.
//
if (argc != 1) { wprintf( L"use: tul flush\n" ); return 1; }
//
// Issue the request.
//
status = NtDeviceIoControlFile( UlHandle, // FileHandle
NULL, // Event
NULL, // ApcRoutine
NULL, // ApcContext
&ioStatusBlock, // IoStatusBlock
IOCTL_UL_FLUSH_FILE_CACHE, // IoControlCode
NULL, // InputBuffer
0, // InputBufferLength,
NULL, // OutputBuffer,
0 // OutputBufferLength
);
if (!NT_SUCCESS(status)) { wprintf( L"NtDeviceIoControlFile() failed, error %08lx\n", status ); return 1; }
wprintf( L"File cache flushed\n" );
return 0;
} // DoFlush
#endif // LATER
INT WINAPI DoConfig( IN HANDLE UlHandle, IN INT argc, IN PWSTR argv[] ) { PCONFIG_ENTRY pEntry; LONG longValue; LONGLONG longlongValue; HKEY key; INT result; LONG err; CONST BYTE * pNewValue; DWORD newValueLength;
//
// Setup locals so we know how to cleanup on exit.
//
key = NULL;
//
// Try to open the registry.
//
err = RegOpenKeyEx( HKEY_LOCAL_MACHINE, L"System\\CurrentControlSet\\Services\\Http\\Parameters", 0, KEY_ALL_ACCESS, &key );
if (err != NO_ERROR) { wprintf( L"tul: cannot open registry, error %ld\n", err ); result = 1; goto cleanup; }
//
// Validate the arguments.
//
if (argc == 1) { DumpConfiguration( key ); result = 0; goto cleanup; } else if (argc != 3) { wprintf( L"use: tul config [property= value]\n" ); result = 1; goto cleanup; }
//
// Find the entry.
//
pEntry = FindConfigByName( argv[1] );
if (pEntry == NULL) { wprintf( L"tul: invalid property %s\n", argv[1] ); result = 1; goto cleanup; }
//
// Interpret it.
//
if (pEntry->Type == REG_DWORD) { if (argv[2][0] == L'-') longValue = wcstol( argv[2], NULL, 0 ); else longValue = (LONG) wcstoul( argv[2], NULL, 0 ); pNewValue = (CONST BYTE *)&longValue; newValueLength = sizeof(longValue); } else if (pEntry->Type == REG_QWORD) { // Hack: because link fails for Win32 and we don't need top 32 bits on Win32
#ifndef _WIN64
# define _wcstoi64(nptr, endptr, base) \
(__int64) wcstol((nptr), (endptr), (base)) # define _wcstoui64(nptr, endptr, base) \
(unsigned __int64) wcstoul((nptr), (endptr), (base)) #endif
if (argv[2][0] == L'-') longlongValue = _wcstoi64( argv[2], NULL, 0 ); else longlongValue = (LONGLONG) _wcstoui64( argv[2], NULL, 0 ); pNewValue = (CONST BYTE *)&longlongValue; newValueLength = sizeof(longlongValue); } else { pNewValue = (CONST BYTE *)argv[2]; newValueLength = (DWORD)( wcslen( argv[2] ) + 1 ) * sizeof(argv[0][0]); }
if (_wcsicmp( argv[2], L"/delete" ) == 0) { err = RegDeleteValue( key, pEntry->pConfigName ); } else { err = RegSetValueEx( key, pEntry->pConfigName, 0, pEntry->Type, pNewValue, newValueLength ); }
if (err != NO_ERROR) { wprintf( L"tul: cannot write to registry, error %ld\n", err ); result = 1; goto cleanup; }
//
// Success!
//
DumpConfiguration( key ); result = 0;
cleanup:
if (key != NULL) { RegCloseKey( key ); }
return result;
} // DoConfig
INT WINAPI DoFlags( IN HANDLE UlHandle, IN INT argc, IN PWSTR argv[] ) { HKEY key; INT result; LONG err; LONG i; ULONG flags;
//
// Setup locals so we know how to cleanup on exit.
//
key = NULL;
//
// Try to open the registry.
//
err = RegOpenKeyEx( HKEY_LOCAL_MACHINE, L"System\\CurrentControlSet\\Services\\Http\\Parameters", 0, KEY_ALL_ACCESS, &key );
if (err != NO_ERROR) { wprintf( L"tul: cannot open registry, error %ld\n", err ); result = 1; goto cleanup; }
//
// Validate the arguments.
//
if (argc == 1) { DumpFlags( key ); result = 0; goto cleanup; }
//
// read each flag on the command line and set it
//
flags = 0; for (i = 1; i < argc; i++) { flags |= FindFlagByName(argv[i]); }
err = RegSetValueEx( key, REGISTRY_DEBUG_FLAGS, 0, REG_DWORD, (LPBYTE)&flags, sizeof(flags) );
//
// Success!
//
DumpFlags( key ); result = 0;
cleanup:
if (key != NULL) { RegCloseKey( key ); }
return result;
} // DoFlags
|