windows-nt/Source/XPSP1/NT/inetsrv/iis/iisrearc/ul/util/tul.c

2267 lines
44 KiB
C
Raw Normal View History

2020-09-26 03:20:57 -05:00
/*++
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