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.
2814 lines
78 KiB
2814 lines
78 KiB
/*++
|
|
|
|
Copyright (c) 1998-2002 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
init.c
|
|
|
|
Abstract:
|
|
|
|
This module performs initialization for the UL device driver.
|
|
|
|
Author:
|
|
|
|
Keith Moore (keithmo) 10-Jun-1998
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
|
|
#include "precomp.h"
|
|
|
|
|
|
PDRIVER_OBJECT g_UlDriverObject = NULL;
|
|
|
|
//
|
|
// Private constants.
|
|
//
|
|
|
|
#define DEFAULT_THREAD_AFFINITY_MASK ((1ui64 << KeNumberProcessors) - 1)
|
|
|
|
|
|
|
|
//
|
|
// Private types.
|
|
//
|
|
|
|
|
|
//
|
|
// Private prototypes.
|
|
//
|
|
|
|
|
|
NTSTATUS
|
|
UlpApplySecurityToDeviceObjects(
|
|
VOID
|
|
);
|
|
|
|
NTSTATUS
|
|
UlpSetDeviceObjectSecurity(
|
|
IN PDEVICE_OBJECT pDeviceObject,
|
|
IN SECURITY_INFORMATION SecurityInformation,
|
|
IN PSECURITY_DESCRIPTOR pSecurityDescriptor
|
|
);
|
|
|
|
ULONG
|
|
UlpReadUrlC14nConfig(
|
|
HANDLE parametersHandle
|
|
);
|
|
|
|
VOID
|
|
UlpReadErrorLogConfig(
|
|
HANDLE parametersHandle
|
|
);
|
|
|
|
VOID
|
|
UlpReadRegistry (
|
|
IN PUL_CONFIG pConfig
|
|
);
|
|
|
|
VOID
|
|
UlpTerminateModules(
|
|
VOID
|
|
);
|
|
|
|
VOID
|
|
UlpUnload (
|
|
IN PDRIVER_OBJECT DriverObject
|
|
);
|
|
|
|
|
|
//
|
|
// Private globals.
|
|
//
|
|
|
|
#if DBG
|
|
ULONG g_UlpForceInitFailure = 0;
|
|
#endif // DBG
|
|
|
|
|
|
#ifdef ALLOC_PRAGMA
|
|
#pragma alloc_text( INIT, DriverEntry )
|
|
#pragma alloc_text( INIT, UlpApplySecurityToDeviceObjects )
|
|
#pragma alloc_text( INIT, UlpSetDeviceObjectSecurity )
|
|
#pragma alloc_text( INIT, UlpReadUrlC14nConfig )
|
|
#pragma alloc_text( INIT, UlpReadRegistry )
|
|
#pragma alloc_text( INIT, UlpReadErrorLogConfig )
|
|
#pragma alloc_text( PAGE, UlpUnload )
|
|
#pragma alloc_text( PAGE, UlpTerminateModules )
|
|
|
|
//
|
|
// Note that UlpTerminateModules() must be "page" if driver unloading
|
|
// is enabled (it's called from UlpUnload), but can be "init" otherwise
|
|
// (it's only called after initialization failure).
|
|
//
|
|
#pragma alloc_text( PAGE, UlpTerminateModules )
|
|
#endif // ALLOC_PRAGMA
|
|
|
|
|
|
//
|
|
// Public functions.
|
|
//
|
|
|
|
/***************************************************************************++
|
|
|
|
Routine Description:
|
|
|
|
This is the initialization routine for the UL device driver.
|
|
|
|
Arguments:
|
|
|
|
DriverObject - Supplies a pointer to driver object created by the
|
|
system.
|
|
|
|
RegistryPath - Supplies the name of the driver's configuration
|
|
registry tree.
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS - Completion status.
|
|
|
|
--***************************************************************************/
|
|
NTSTATUS
|
|
DriverEntry(
|
|
IN PDRIVER_OBJECT DriverObject,
|
|
IN PUNICODE_STRING RegistryPath
|
|
)
|
|
{
|
|
NTSTATUS status;
|
|
UNICODE_STRING deviceName;
|
|
OBJECT_ATTRIBUTES objectAttributes;
|
|
UL_CONFIG config;
|
|
SYSTEM_BASIC_INFORMATION sbi;
|
|
|
|
UNREFERENCED_PARAMETER(RegistryPath);
|
|
|
|
//
|
|
// Sanity check.
|
|
//
|
|
|
|
PAGED_CODE();
|
|
|
|
g_UlDriverObject = DriverObject;
|
|
|
|
//
|
|
// Grab the number of processors in the system.
|
|
//
|
|
|
|
g_UlNumberOfProcessors = KeNumberProcessors;
|
|
g_UlThreadAffinityMask = DEFAULT_THREAD_AFFINITY_MASK;
|
|
|
|
//
|
|
// Grab the largest cache line size in the system
|
|
//
|
|
|
|
g_UlCacheLineSize = KeGetRecommendedSharedDataAlignment();
|
|
|
|
for (g_UlCacheLineBits = 0;
|
|
(1U << g_UlCacheLineBits) < g_UlCacheLineSize;
|
|
++g_UlCacheLineBits)
|
|
{}
|
|
|
|
ASSERT(g_UlCacheLineSize <= (1U << g_UlCacheLineBits));
|
|
|
|
status = NtQuerySystemInformation(
|
|
SystemBasicInformation,
|
|
&sbi,
|
|
sizeof(sbi),
|
|
NULL);
|
|
ASSERT(NT_SUCCESS(status));
|
|
|
|
//
|
|
// Capture total physical memory, in terms of megabytes.
|
|
//
|
|
|
|
g_UlTotalPhysicalMemMB = PAGES_TO_MEGABYTES(sbi.NumberOfPhysicalPages);
|
|
|
|
//
|
|
// Estimate the total number of NPP available in bytes since Landy
|
|
// doesn't want to export MmSizeOfNonPagedPoolInBytes.
|
|
//
|
|
// CODEWORK: Whenever we have a mechanism for discovering the
|
|
// NonPagedPool size, use that instead of the total physical
|
|
// RAM on the system.
|
|
//
|
|
|
|
#if defined(_WIN64)
|
|
//
|
|
// On IA64, assume NPP can be 50% of total physical memory.
|
|
//
|
|
|
|
g_UlTotalNonPagedPoolBytes = MEGABYTES_TO_BYTES(g_UlTotalPhysicalMemMB/2);
|
|
#else
|
|
//
|
|
// On X86, assume NPP is either 50% of total physical memory or 256MB,
|
|
// whichever is less.
|
|
//
|
|
|
|
g_UlTotalNonPagedPoolBytes = MEGABYTES_TO_BYTES(
|
|
MIN(256, g_UlTotalPhysicalMemMB/2)
|
|
);
|
|
#endif
|
|
|
|
//
|
|
// Snag a pointer to the system process.
|
|
//
|
|
|
|
g_pUlSystemProcess = (PKPROCESS)IoGetCurrentProcess();
|
|
|
|
//
|
|
// Temporarily initialize the IS_HTTP_*() macros.
|
|
// Will be initialized properly by InitializeHttpUtil() later.
|
|
//
|
|
|
|
HttpCmnInitializeHttpCharsTable(FALSE);
|
|
|
|
//
|
|
// Read registry information.
|
|
//
|
|
|
|
UlpReadRegistry( &config );
|
|
|
|
#if DBG
|
|
//
|
|
// Give anyone using the kernel debugger a chance to abort
|
|
// initialization.
|
|
//
|
|
|
|
if (g_UlpForceInitFailure != 0)
|
|
{
|
|
status = STATUS_UNSUCCESSFUL;
|
|
goto fatal;
|
|
}
|
|
#endif // DBG
|
|
|
|
//
|
|
// Initialize the global trace logs.
|
|
//
|
|
|
|
CREATE_REF_TRACE_LOG( g_pMondoGlobalTraceLog,
|
|
16384 - REF_TRACE_OVERHEAD,
|
|
0, TRACELOG_HIGH_PRIORITY,
|
|
UL_REF_TRACE_LOG_POOL_TAG );
|
|
|
|
CREATE_REF_TRACE_LOG( g_pPoolAllocTraceLog,
|
|
16384 - REF_TRACE_OVERHEAD,
|
|
0, TRACELOG_HIGH_PRIORITY,
|
|
UL_REF_TRACE_LOG_POOL_TAG );
|
|
|
|
CREATE_REF_TRACE_LOG( g_pUriTraceLog,
|
|
2048 - REF_TRACE_OVERHEAD,
|
|
0, TRACELOG_HIGH_PRIORITY,
|
|
UL_REF_TRACE_LOG_POOL_TAG );
|
|
|
|
CREATE_REF_TRACE_LOG( g_pTdiTraceLog,
|
|
32768 - REF_TRACE_OVERHEAD,
|
|
0, TRACELOG_HIGH_PRIORITY,
|
|
UL_REF_TRACE_LOG_POOL_TAG );
|
|
|
|
CREATE_REF_TRACE_LOG( g_pHttpRequestTraceLog,
|
|
2048 - REF_TRACE_OVERHEAD,
|
|
0, TRACELOG_HIGH_PRIORITY,
|
|
UL_REF_TRACE_LOG_POOL_TAG );
|
|
|
|
CREATE_REF_TRACE_LOG( g_pHttpConnectionTraceLog,
|
|
2048 - REF_TRACE_OVERHEAD,
|
|
0, TRACELOG_HIGH_PRIORITY,
|
|
UL_REF_TRACE_LOG_POOL_TAG );
|
|
|
|
CREATE_REF_TRACE_LOG( g_pHttpResponseTraceLog,
|
|
2048 - REF_TRACE_OVERHEAD,
|
|
0, TRACELOG_HIGH_PRIORITY,
|
|
UL_REF_TRACE_LOG_POOL_TAG );
|
|
|
|
CREATE_REF_TRACE_LOG( g_pAppPoolTraceLog,
|
|
2048 - REF_TRACE_OVERHEAD,
|
|
0, TRACELOG_HIGH_PRIORITY,
|
|
UL_REF_TRACE_LOG_POOL_TAG );
|
|
|
|
CREATE_REF_TRACE_LOG( g_pAppPoolProcessTraceLog,
|
|
2048 - REF_TRACE_OVERHEAD,
|
|
0, TRACELOG_HIGH_PRIORITY,
|
|
UL_REF_TRACE_LOG_POOL_TAG );
|
|
|
|
CREATE_REF_TRACE_LOG( g_pConfigGroupTraceLog,
|
|
2048 - REF_TRACE_OVERHEAD,
|
|
0, TRACELOG_HIGH_PRIORITY,
|
|
UL_REF_TRACE_LOG_POOL_TAG );
|
|
|
|
CREATE_REF_TRACE_LOG( g_pControlChannelTraceLog,
|
|
2048 - REF_TRACE_OVERHEAD,
|
|
0, TRACELOG_HIGH_PRIORITY,
|
|
UL_REF_TRACE_LOG_POOL_TAG );
|
|
|
|
CREATE_REF_TRACE_LOG( g_pThreadTraceLog,
|
|
16384 - REF_TRACE_OVERHEAD,
|
|
0, TRACELOG_HIGH_PRIORITY,
|
|
UL_REF_TRACE_LOG_POOL_TAG );
|
|
|
|
CREATE_REF_TRACE_LOG( g_pMdlTraceLog,
|
|
2048 - REF_TRACE_OVERHEAD,
|
|
0, TRACELOG_HIGH_PRIORITY,
|
|
UL_REF_TRACE_LOG_POOL_TAG );
|
|
|
|
CREATE_REF_TRACE_LOG( g_pFilterTraceLog,
|
|
2048 - REF_TRACE_OVERHEAD,
|
|
0, TRACELOG_HIGH_PRIORITY,
|
|
UL_REF_TRACE_LOG_POOL_TAG );
|
|
|
|
CREATE_REF_TRACE_LOG( g_pSiteCounterTraceLog,
|
|
2048 - REF_TRACE_OVERHEAD,
|
|
0, TRACELOG_HIGH_PRIORITY,
|
|
UL_REF_TRACE_LOG_POOL_TAG );
|
|
|
|
CREATE_REF_TRACE_LOG( g_pConnectionCountTraceLog,
|
|
2048 - REF_TRACE_OVERHEAD,
|
|
0, TRACELOG_HIGH_PRIORITY,
|
|
UL_REF_TRACE_LOG_POOL_TAG );
|
|
|
|
CREATE_REF_TRACE_LOG( g_pConfigGroupInfoTraceLog,
|
|
2048 - REF_TRACE_OVERHEAD,
|
|
0, TRACELOG_HIGH_PRIORITY,
|
|
UL_REF_TRACE_LOG_POOL_TAG );
|
|
|
|
CREATE_REF_TRACE_LOG( g_pChunkTrackerTraceLog,
|
|
2048 - REF_TRACE_OVERHEAD,
|
|
0, TRACELOG_HIGH_PRIORITY,
|
|
UL_REF_TRACE_LOG_POOL_TAG );
|
|
|
|
CREATE_REF_TRACE_LOG( g_pWorkItemTraceLog,
|
|
32768 - REF_TRACE_OVERHEAD,
|
|
0, TRACELOG_HIGH_PRIORITY,
|
|
UL_REF_TRACE_LOG_POOL_TAG );
|
|
|
|
CREATE_REF_TRACE_LOG( g_pEndpointUsageTraceLog,
|
|
16384 - REF_TRACE_OVERHEAD,
|
|
0, TRACELOG_HIGH_PRIORITY,
|
|
UL_REF_TRACE_LOG_POOL_TAG );
|
|
|
|
CREATE_IRP_TRACE_LOG( g_pIrpTraceLog,
|
|
32768 - REF_TRACE_OVERHEAD, 0 );
|
|
CREATE_TIME_TRACE_LOG( g_pTimeTraceLog,
|
|
32768 - REF_TRACE_OVERHEAD, 0 );
|
|
CREATE_APP_POOL_TIME_TRACE_LOG( g_pAppPoolTimeTraceLog,
|
|
32768 - REF_TRACE_OVERHEAD, 0 );
|
|
|
|
CREATE_STRING_LOG( g_pGlobalStringLog, 5 * 1024 * 1024, 0, FALSE );
|
|
|
|
CREATE_UC_TRACE_LOG( g_pUcTraceLog,
|
|
16384 - REF_TRACE_OVERHEAD, 0 );
|
|
|
|
//
|
|
// Create an object directory to contain our device objects.
|
|
//
|
|
|
|
status = UlInitUnicodeStringEx( &deviceName, HTTP_DIRECTORY_NAME );
|
|
|
|
if (!NT_SUCCESS(status))
|
|
{
|
|
goto fatal;
|
|
}
|
|
|
|
InitializeObjectAttributes(
|
|
&objectAttributes, // ObjectAttributes
|
|
&deviceName, // ObjectName
|
|
OBJ_CASE_INSENSITIVE | // Attributes
|
|
OBJ_KERNEL_HANDLE,
|
|
NULL, // RootDirectory
|
|
NULL // SecurityDescriptor
|
|
);
|
|
|
|
status = ZwCreateDirectoryObject(
|
|
&g_UlDirectoryObject, // DirectoryHandle
|
|
DIRECTORY_ALL_ACCESS, // AccessMask
|
|
&objectAttributes // ObjectAttributes
|
|
);
|
|
|
|
if (!NT_SUCCESS(status))
|
|
{
|
|
goto fatal;
|
|
}
|
|
|
|
//
|
|
// Create the control channel device object.
|
|
//
|
|
|
|
status = UlInitUnicodeStringEx( &deviceName, HTTP_CONTROL_DEVICE_NAME );
|
|
|
|
if (!NT_SUCCESS(status))
|
|
{
|
|
goto fatal;
|
|
}
|
|
|
|
status = IoCreateDevice(
|
|
DriverObject, // DriverObject
|
|
0, // DeviceExtension
|
|
&deviceName, // DeviceName
|
|
FILE_DEVICE_NETWORK, // DeviceType
|
|
0, // DeviceCharacteristics
|
|
FALSE, // Exclusive
|
|
&g_pUlControlDeviceObject // DeviceObject
|
|
);
|
|
|
|
if (!NT_SUCCESS(status))
|
|
{
|
|
goto fatal;
|
|
}
|
|
|
|
//
|
|
// Create the filter device object.
|
|
//
|
|
|
|
status = UlInitUnicodeStringEx( &deviceName, HTTP_FILTER_DEVICE_NAME );
|
|
|
|
if (!NT_SUCCESS(status))
|
|
{
|
|
goto fatal;
|
|
}
|
|
|
|
status = IoCreateDevice(
|
|
DriverObject, // DriverObject
|
|
0, // DeviceExtension
|
|
&deviceName, // DeviceName
|
|
FILE_DEVICE_NETWORK, // DeviceType
|
|
0, // DeviceCharacteristics
|
|
FALSE, // Exclusive
|
|
&g_pUlFilterDeviceObject // DeviceObject
|
|
);
|
|
|
|
if (!NT_SUCCESS(status))
|
|
{
|
|
goto fatal;
|
|
}
|
|
|
|
g_pUlFilterDeviceObject->StackSize = DEFAULT_IRP_STACK_SIZE;
|
|
|
|
//
|
|
// Create the app pool device object.
|
|
//
|
|
|
|
status = UlInitUnicodeStringEx( &deviceName, HTTP_APP_POOL_DEVICE_NAME );
|
|
|
|
if (!NT_SUCCESS(status))
|
|
{
|
|
goto fatal;
|
|
}
|
|
|
|
status = IoCreateDevice(
|
|
DriverObject, // DriverObject
|
|
0, // DeviceExtension
|
|
&deviceName, // DeviceName
|
|
FILE_DEVICE_NETWORK, // DeviceType
|
|
0, // DeviceCharacteristics
|
|
FALSE, // Exclusive
|
|
&g_pUlAppPoolDeviceObject // DeviceObject
|
|
);
|
|
|
|
if (!NT_SUCCESS(status))
|
|
{
|
|
goto fatal;
|
|
}
|
|
|
|
g_pUlAppPoolDeviceObject->StackSize = DEFAULT_IRP_STACK_SIZE;
|
|
|
|
|
|
//
|
|
// Initialize the driver object with this driver's entrypoints.
|
|
//
|
|
|
|
DriverObject->MajorFunction[IRP_MJ_CREATE] = &UlCreate;
|
|
DriverObject->MajorFunction[IRP_MJ_CLOSE] = &UlClose;
|
|
DriverObject->MajorFunction[IRP_MJ_CLEANUP] = &UlCleanup;
|
|
DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = &UlDeviceControl;
|
|
DriverObject->MajorFunction[IRP_MJ_QUERY_SECURITY] = &UlQuerySecurityDispatch;
|
|
DriverObject->MajorFunction[IRP_MJ_SET_SECURITY] = &UlSetSecurityDispatch;
|
|
DriverObject->MajorFunction[IRP_MJ_SYSTEM_CONTROL] = &UlEtwDispatch;
|
|
DriverObject->FastIoDispatch = &UlFastIoDispatch;
|
|
DriverObject->DriverUnload = NULL;
|
|
|
|
//
|
|
// Initialize global data.
|
|
//
|
|
|
|
status = UlInitializeData(&config);
|
|
|
|
if (!NT_SUCCESS(status))
|
|
{
|
|
goto fatal;
|
|
}
|
|
|
|
//
|
|
// Create the thread pool.
|
|
//
|
|
|
|
status = UlInitializeThreadPool(config.ThreadsPerCpu);
|
|
|
|
if (!NT_SUCCESS(status))
|
|
{
|
|
goto fatal;
|
|
}
|
|
|
|
//
|
|
// Initialize common TDI code.
|
|
//
|
|
|
|
status = UxInitializeTdi();
|
|
|
|
if (!NT_SUCCESS(status))
|
|
{
|
|
goto fatal;
|
|
}
|
|
|
|
//
|
|
// Initialize server connection code.
|
|
//
|
|
|
|
status = UlInitializeTdi();
|
|
|
|
if (!NT_SUCCESS(status))
|
|
{
|
|
goto fatal;
|
|
}
|
|
|
|
//
|
|
// Initialize George.
|
|
//
|
|
|
|
status = UlLargeMemInitialize();
|
|
if (!NT_SUCCESS(status))
|
|
{
|
|
goto fatal;
|
|
}
|
|
|
|
//
|
|
// Initialize Keith.
|
|
//
|
|
|
|
status = UlInitializeControlChannel();
|
|
if (!NT_SUCCESS(status))
|
|
{
|
|
goto fatal;
|
|
}
|
|
|
|
//
|
|
// Initialize Henry.
|
|
//
|
|
|
|
status = InitializeHttpUtil();
|
|
if (!NT_SUCCESS(status))
|
|
{
|
|
goto fatal;
|
|
}
|
|
|
|
status = InitializeParser();
|
|
if (!NT_SUCCESS(status))
|
|
{
|
|
goto fatal;
|
|
}
|
|
|
|
status = UlInitializeOpaqueIdTable();
|
|
if (!NT_SUCCESS(status))
|
|
{
|
|
goto fatal;
|
|
}
|
|
|
|
status = InitializeFileCache();
|
|
if (!NT_SUCCESS(status))
|
|
{
|
|
goto fatal;
|
|
}
|
|
|
|
//
|
|
// Initialize Michael.
|
|
//
|
|
status = UlInitializeFilterChannel(&config);
|
|
if (!NT_SUCCESS(status))
|
|
{
|
|
goto fatal;
|
|
}
|
|
|
|
//
|
|
// Initialize Alex.
|
|
//
|
|
status = UlInitializeUriCache(&config);
|
|
if (!NT_SUCCESS(status))
|
|
{
|
|
goto fatal;
|
|
}
|
|
|
|
status = UlInitializeDateCache();
|
|
if (!NT_SUCCESS(status))
|
|
{
|
|
goto fatal;
|
|
}
|
|
|
|
//
|
|
// Initialize Paul.
|
|
//
|
|
|
|
status = UlInitializeCG();
|
|
if (!NT_SUCCESS(status))
|
|
{
|
|
goto fatal;
|
|
}
|
|
|
|
status = UlInitializeAP();
|
|
if (!NT_SUCCESS(status))
|
|
{
|
|
goto fatal;
|
|
}
|
|
|
|
//
|
|
// Initialize Ali
|
|
//
|
|
status = UlInitializeLogUtil();
|
|
if (!NT_SUCCESS(status))
|
|
{
|
|
goto fatal;
|
|
}
|
|
|
|
status = UlInitializeLogs();
|
|
if (!NT_SUCCESS(status))
|
|
{
|
|
goto fatal;
|
|
}
|
|
|
|
status = UlInitializeBinaryLog();
|
|
if (!NT_SUCCESS(status))
|
|
{
|
|
goto fatal;
|
|
}
|
|
|
|
status = UlInitializeErrorLog();
|
|
if (!NT_SUCCESS(status))
|
|
{
|
|
goto fatal;
|
|
}
|
|
|
|
status = UlTcInitialize();
|
|
if (!NT_SUCCESS(status))
|
|
{
|
|
goto fatal;
|
|
}
|
|
|
|
status = UlInitGlobalConnectionLimits();
|
|
if (!NT_SUCCESS(status))
|
|
{
|
|
goto fatal;
|
|
}
|
|
|
|
status = UlInitializeHttpConnection();
|
|
if (!NT_SUCCESS(status))
|
|
{
|
|
goto fatal;
|
|
}
|
|
|
|
//
|
|
// Initialize Eric.
|
|
//
|
|
|
|
status = UlInitializeCounters();
|
|
if (!NT_SUCCESS(status))
|
|
{
|
|
goto fatal;
|
|
}
|
|
|
|
UlInitializeTimeoutMonitor();
|
|
//
|
|
// Initialize ETW Tracing
|
|
//
|
|
UlEtwInitLog( g_pUlControlDeviceObject );
|
|
|
|
//
|
|
// Initialize HTTP client
|
|
//
|
|
|
|
if(config.EnableHttpClient)
|
|
{
|
|
//
|
|
// All of the client code live under a "section" called PAGEUC. This
|
|
// section is paged by default & gets locked down when there is an app
|
|
// that uses the client APIs (specifically, opens a handle to a server).
|
|
//
|
|
// There are two ways of demand locking this section. We can either use
|
|
// MmLockPagableCodeSection or MmLockPagableSectionByHandle. It's a lot
|
|
// cheaper to use MmLockPagableSectionByHandle.
|
|
//
|
|
// So, during our DriverEntry, we first lock the entire PAGEUC section
|
|
// to obtain the handle. We then immediately unlock it, but remember
|
|
// the handle. This allows us to use MmLockPagableSectionByHandle for
|
|
// subsequent locks, which is much faster.
|
|
//
|
|
// In order to use MmLockPagableCodeSection, we'll pick one function
|
|
// that lives under this section --> UcpTdiReceiveHandler
|
|
//
|
|
|
|
g_ClientImageHandle =
|
|
MmLockPagableCodeSection((PVOID)((ULONG_PTR)UcpTdiReceiveHandler));
|
|
MmUnlockPagableImageSection(g_ClientImageHandle);
|
|
|
|
|
|
//
|
|
// Create the server device object
|
|
//
|
|
status = UlInitUnicodeStringEx(&deviceName, HTTP_SERVER_DEVICE_NAME);
|
|
|
|
if(!NT_SUCCESS(status))
|
|
{
|
|
goto fatal;
|
|
}
|
|
|
|
status = IoCreateDevice(DriverObject,
|
|
0,
|
|
&deviceName,
|
|
FILE_DEVICE_NETWORK,
|
|
0,
|
|
FALSE,
|
|
&g_pUcServerDeviceObject
|
|
);
|
|
|
|
if(!NT_SUCCESS(status))
|
|
{
|
|
goto fatal;
|
|
}
|
|
g_pUcServerDeviceObject->StackSize ++;
|
|
|
|
//
|
|
// Initialize the client connection code.
|
|
//
|
|
|
|
status = UcInitializeServerInformation();
|
|
if(!NT_SUCCESS(status))
|
|
{
|
|
goto fatal;
|
|
}
|
|
|
|
status = UcInitializeClientConnections();
|
|
if(!NT_SUCCESS(status))
|
|
{
|
|
goto fatal;
|
|
}
|
|
|
|
status = UcInitializeSSPI();
|
|
if(!NT_SUCCESS(status))
|
|
{
|
|
goto fatal;
|
|
}
|
|
|
|
status = UcInitializeHttpRequests();
|
|
if (!NT_SUCCESS(status))
|
|
{
|
|
goto fatal;
|
|
}
|
|
|
|
}
|
|
else
|
|
{
|
|
// Disable all the client IOCTLs.
|
|
|
|
UlSetDummyIoctls();
|
|
}
|
|
|
|
//
|
|
// Apply security to the device objects.
|
|
//
|
|
|
|
status = UlpApplySecurityToDeviceObjects();
|
|
|
|
if (!NT_SUCCESS(status))
|
|
{
|
|
goto fatal;
|
|
}
|
|
|
|
//
|
|
// Initialize Namespace.
|
|
// Note: This initialization must be done after
|
|
// UlpApplySecurityToDeviceObjects() has been called.
|
|
// Otherwise, g_pAdminAllSystemAll will not be initialzied.
|
|
// UlInitializeNamespace() uses that global security descriptor.
|
|
//
|
|
|
|
status = UlInitializeNamespace();
|
|
|
|
if (!NT_SUCCESS(status))
|
|
{
|
|
goto fatal;
|
|
}
|
|
|
|
#if DBG
|
|
//
|
|
// Give anyone using the kernel debugger one final chance to abort
|
|
// initialization.
|
|
//
|
|
|
|
if (g_UlpForceInitFailure != 0)
|
|
{
|
|
status = STATUS_UNSUCCESSFUL;
|
|
goto fatal;
|
|
}
|
|
#endif // DBG
|
|
|
|
//
|
|
// Set DriverUnload only after everything has succeeded to synchronize
|
|
// DriverEntry and DriverUnload. In theory however, the DriverUnload
|
|
// routine can still be called once we set it, but that can't be fixed
|
|
// by the drivers, it needs to be fixed by IO or SCM.
|
|
//
|
|
|
|
DriverObject->DriverUnload = &UlpUnload;
|
|
|
|
return STATUS_SUCCESS;
|
|
|
|
//
|
|
// Fatal error handlers.
|
|
//
|
|
|
|
fatal:
|
|
|
|
ASSERT( !NT_SUCCESS(status) );
|
|
|
|
UlpTerminateModules();
|
|
|
|
return status;
|
|
|
|
} // DriverEntry
|
|
|
|
|
|
//
|
|
// Private functions.
|
|
//
|
|
|
|
/***************************************************************************++
|
|
|
|
Routine Description:
|
|
|
|
Applies the appropriate security descriptors to the global device
|
|
objects created at initialization time.
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS - Completion status.
|
|
|
|
--***************************************************************************/
|
|
NTSTATUS
|
|
UlpApplySecurityToDeviceObjects(
|
|
VOID
|
|
)
|
|
{
|
|
NTSTATUS status;
|
|
SECURITY_DESCRIPTOR securityDescriptor;
|
|
PGENERIC_MAPPING pFileObjectGenericMapping;
|
|
ACCESS_MASK fileReadWrite;
|
|
ACCESS_MASK fileAll;
|
|
SID_MASK_PAIR sidMaskPairs[4];
|
|
|
|
//
|
|
// Sanity check.
|
|
//
|
|
|
|
PAGED_CODE();
|
|
|
|
ASSERT( IS_VALID_DEVICE_OBJECT( g_pUlControlDeviceObject ) );
|
|
ASSERT( IS_VALID_DEVICE_OBJECT( g_pUlFilterDeviceObject ) );
|
|
ASSERT( IS_VALID_DEVICE_OBJECT( g_pUlAppPoolDeviceObject ) );
|
|
|
|
//
|
|
// Gain access to the predefined SIDs and other security-related
|
|
// goodies exported by the kernel.
|
|
//
|
|
|
|
//SeEnableAccessToExports();
|
|
|
|
//
|
|
// Map a couple of generic file access types to their corresponding
|
|
// object-specific rights.
|
|
//
|
|
|
|
|
|
pFileObjectGenericMapping = IoGetFileObjectGenericMapping();
|
|
ASSERT( pFileObjectGenericMapping != NULL );
|
|
|
|
//
|
|
// FILE_READ & FILE_WRITE
|
|
//
|
|
|
|
fileReadWrite = GENERIC_READ | GENERIC_WRITE;
|
|
|
|
RtlMapGenericMask(
|
|
&fileReadWrite,
|
|
pFileObjectGenericMapping
|
|
);
|
|
|
|
//
|
|
// FILE_ALL
|
|
//
|
|
|
|
fileAll = GENERIC_ALL;
|
|
|
|
RtlMapGenericMask(
|
|
&fileAll,
|
|
pFileObjectGenericMapping
|
|
);
|
|
|
|
//
|
|
// Build a restrictive security descriptor for the filter device
|
|
// object:
|
|
//
|
|
// Full access for NT AUTHORITY\SYSTEM
|
|
// Full access for BUILTIN\Administrators
|
|
//
|
|
|
|
sidMaskPairs[0].pSid = SeExports->SeLocalSystemSid;
|
|
sidMaskPairs[0].AccessMask = fileAll;
|
|
sidMaskPairs[0].AceFlags = 0;
|
|
|
|
sidMaskPairs[1].pSid = SeExports->SeAliasAdminsSid;
|
|
sidMaskPairs[1].AccessMask = fileAll;
|
|
sidMaskPairs[1].AceFlags = 0;
|
|
|
|
status = UlCreateSecurityDescriptor(
|
|
&securityDescriptor, // pSecurityDescriptor
|
|
&sidMaskPairs[0], // pSidMaskPairs
|
|
2 // NumSidMaskPairs
|
|
);
|
|
|
|
if (!NT_SUCCESS(status))
|
|
{
|
|
return status;
|
|
}
|
|
|
|
//
|
|
// Filter object
|
|
//
|
|
|
|
status = UlpSetDeviceObjectSecurity(
|
|
g_pUlFilterDeviceObject,
|
|
DACL_SECURITY_INFORMATION,
|
|
&securityDescriptor
|
|
);
|
|
|
|
UlCleanupSecurityDescriptor(&securityDescriptor);
|
|
|
|
if (!NT_SUCCESS(status))
|
|
{
|
|
return status;
|
|
}
|
|
|
|
//
|
|
// We want a global security descriptor that allows fileAll to
|
|
// System and Administrators and nothing else for world. Incidently,
|
|
// the filter device object provides this exact feature. We'll save
|
|
// a pointer to this security descriptor.
|
|
//
|
|
// WARNING: If we ever change the ACL on the Filter Device Object, we'll
|
|
// have to create a new security descriptor for this.
|
|
//
|
|
//
|
|
|
|
g_pAdminAllSystemAll = g_pUlFilterDeviceObject->SecurityDescriptor;
|
|
|
|
//
|
|
// Build a slightly less restrictive security descriptor for the
|
|
// other device objects.
|
|
//
|
|
// Full access for NT AUTHORITY\SYSTEM
|
|
// Full access for BUILTIN\Administrators
|
|
// Read/Write access for Authenticated users
|
|
// Read/Write access for Guest.
|
|
//
|
|
|
|
sidMaskPairs[2].pSid = SeExports->SeAuthenticatedUsersSid;
|
|
sidMaskPairs[2].AccessMask = fileReadWrite;
|
|
sidMaskPairs[2].AceFlags = 0;
|
|
|
|
|
|
sidMaskPairs[3].pSid = SeExports->SeAliasGuestsSid;
|
|
sidMaskPairs[3].AccessMask = fileReadWrite;
|
|
sidMaskPairs[3].AceFlags = 0;
|
|
|
|
|
|
status = UlCreateSecurityDescriptor(
|
|
&securityDescriptor,
|
|
&sidMaskPairs[0], // pSidMaskPairs
|
|
4 // NumSidMaskPairs
|
|
);
|
|
|
|
if (!NT_SUCCESS(status))
|
|
{
|
|
return status;
|
|
}
|
|
|
|
for(;;)
|
|
{
|
|
|
|
//
|
|
// App Pool
|
|
//
|
|
status = UlpSetDeviceObjectSecurity(
|
|
g_pUlAppPoolDeviceObject,
|
|
DACL_SECURITY_INFORMATION,
|
|
&securityDescriptor
|
|
);
|
|
|
|
if (!NT_SUCCESS(status))
|
|
{
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Control Channel
|
|
//
|
|
status = UlpSetDeviceObjectSecurity(
|
|
g_pUlControlDeviceObject,
|
|
DACL_SECURITY_INFORMATION,
|
|
&securityDescriptor
|
|
);
|
|
|
|
if (!NT_SUCCESS(status))
|
|
{
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Server
|
|
//
|
|
|
|
if(g_pUcServerDeviceObject)
|
|
{
|
|
status = UlpSetDeviceObjectSecurity(
|
|
g_pUcServerDeviceObject,
|
|
DACL_SECURITY_INFORMATION,
|
|
&securityDescriptor
|
|
);
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
UlCleanupSecurityDescriptor(&securityDescriptor);
|
|
|
|
return status;
|
|
|
|
} // UlpApplySecurityToDeviceObjects
|
|
|
|
/***************************************************************************++
|
|
|
|
Routine Description:
|
|
|
|
Applies the specified security descriptor to the specified device
|
|
object.
|
|
|
|
Arguments:
|
|
|
|
pDeviceObject - Supplies the device object to manipulate.
|
|
|
|
SecurityInformation - Supplies the level of information to change.
|
|
|
|
pSecurityDescriptor - Supplies the new security descriptor for the
|
|
device object.
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS - Completion status.
|
|
|
|
--***************************************************************************/
|
|
NTSTATUS
|
|
UlpSetDeviceObjectSecurity(
|
|
IN PDEVICE_OBJECT pDeviceObject,
|
|
IN SECURITY_INFORMATION SecurityInformation,
|
|
IN PSECURITY_DESCRIPTOR pSecurityDescriptor
|
|
)
|
|
{
|
|
NTSTATUS status;
|
|
HANDLE handle;
|
|
|
|
//
|
|
// Sanity check.
|
|
//
|
|
|
|
PAGED_CODE();
|
|
|
|
ASSERT( IS_VALID_DEVICE_OBJECT( pDeviceObject ) );
|
|
ASSERT( RtlValidSecurityDescriptor( pSecurityDescriptor ) );
|
|
|
|
//
|
|
// Open a handle to the device object.
|
|
//
|
|
|
|
status = ObOpenObjectByPointer(
|
|
pDeviceObject, // Object
|
|
OBJ_CASE_INSENSITIVE | // HandleAttributes
|
|
OBJ_KERNEL_HANDLE,
|
|
NULL, // PassedAccessState
|
|
MAXIMUM_ALLOWED, // DesiredAccess
|
|
NULL, // ObjectType
|
|
KernelMode, // AccessMode
|
|
&handle // Handle
|
|
);
|
|
|
|
if (NT_SUCCESS(status))
|
|
{
|
|
status = NtSetSecurityObject(
|
|
handle, // Handle
|
|
SecurityInformation, // SecurityInformation
|
|
pSecurityDescriptor // SecurityDescriptor
|
|
);
|
|
|
|
ZwClose( handle );
|
|
}
|
|
|
|
return status;
|
|
|
|
} // UlpSetDeviceObjectSecurity
|
|
|
|
|
|
//
|
|
// Read URL processing parameters.
|
|
//
|
|
|
|
ULONG
|
|
UlpReadUrlC14nConfig(
|
|
HANDLE parametersHandle
|
|
)
|
|
{
|
|
LONG tmp;
|
|
LONG DefaultBoolRegValue = -123; // sane values are 0 and 1
|
|
LONG EnableDbcs;
|
|
LONG FavorUtf8;
|
|
LONG EnableNonUtf8 ;
|
|
LONG PercentUAllowed ;
|
|
LONG AllowRestrictedChars ;
|
|
LONG UrlSegmentMaxLength;
|
|
LONG UrlSegmentMaxCount;
|
|
NTSTATUS status;
|
|
UNICODE_STRING registryPathNLS;
|
|
HANDLE codePageHandle;
|
|
UNICODE_STRING ACPCodeString;
|
|
ULONG ACPCode = 0;
|
|
PKEY_VALUE_PARTIAL_INFORMATION pInfo;
|
|
|
|
//
|
|
// Tune defaults based on whether we are running on a DBCS system.
|
|
// Since we do not have a convenient API to do so, use this algorithm:
|
|
//
|
|
// 1- Get ACP from the registry at:
|
|
// HKLM\System\CurrentControlSet\Control\NLS\CodePage
|
|
// 2- check against the list of DBCS in:
|
|
// http://www.microsoft.com/globaldev/reference/WinCP.asp
|
|
//
|
|
// TODO - use kernel mode API when provided.
|
|
//
|
|
|
|
EnableDbcs = FALSE;
|
|
|
|
status = UlInitUnicodeStringEx(®istryPathNLS, REGISTRY_NLS_PATH);
|
|
|
|
if(NT_SUCCESS(status))
|
|
{
|
|
status = UlOpenRegistry(
|
|
®istryPathNLS,
|
|
&codePageHandle,
|
|
REGISTRY_NLS_CODEPAGE_KEY
|
|
);
|
|
|
|
if (NT_SUCCESS(status))
|
|
{
|
|
pInfo = NULL;
|
|
|
|
status = UlReadGenericParameter(
|
|
codePageHandle,
|
|
REGISTRY_ACP_NAME,
|
|
&pInfo
|
|
);
|
|
|
|
if (NT_SUCCESS(status))
|
|
{
|
|
ASSERT(pInfo);
|
|
|
|
if (pInfo->Type == REG_SZ)
|
|
{
|
|
status = UlInitUnicodeStringEx(
|
|
&ACPCodeString,
|
|
(PWSTR)pInfo->Data
|
|
);
|
|
|
|
if (NT_SUCCESS(status))
|
|
{
|
|
status = HttpWideStringToULong(
|
|
ACPCodeString.Buffer,
|
|
ACPCodeString.Length / sizeof(WCHAR),
|
|
FALSE,
|
|
10,
|
|
NULL,
|
|
&ACPCode
|
|
);
|
|
|
|
if (NT_SUCCESS(status))
|
|
{
|
|
//
|
|
// Check if this is one of the known DBCS codes:
|
|
//
|
|
if ((ACPCode == CP_JAPANESE_SHIFT_JIS) ||
|
|
(ACPCode == CP_SIMPLIFIED_CHINESE_GBK) ||
|
|
(ACPCode == CP_KOREAN) ||
|
|
(ACPCode == CP_TRADITIONAL_CHINESE_BIG5))
|
|
{
|
|
EnableDbcs = TRUE;
|
|
}
|
|
else
|
|
{
|
|
EnableDbcs = FALSE;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Free up the returned value.
|
|
//
|
|
UL_FREE_POOL( pInfo, UL_REGISTRY_DATA_POOL_TAG );
|
|
}
|
|
|
|
ZwClose( codePageHandle );
|
|
}
|
|
}
|
|
|
|
//
|
|
// Now check if we have registry overrides for each of these.
|
|
//
|
|
EnableNonUtf8 = UlReadLongParameter(
|
|
parametersHandle,
|
|
REGISTRY_ENABLE_NON_UTF8_URL,
|
|
DefaultBoolRegValue);
|
|
|
|
if (EnableNonUtf8 != DefaultBoolRegValue)
|
|
{
|
|
//
|
|
// A registry setting is present; use it.
|
|
//
|
|
EnableNonUtf8 = (BOOLEAN) (EnableNonUtf8 != 0);
|
|
}
|
|
else
|
|
{
|
|
EnableNonUtf8 = DEFAULT_ENABLE_NON_UTF8_URL;
|
|
}
|
|
|
|
if (EnableNonUtf8)
|
|
{
|
|
FavorUtf8 = UlReadLongParameter(
|
|
parametersHandle,
|
|
REGISTRY_FAVOR_UTF8_URL,
|
|
DefaultBoolRegValue
|
|
);
|
|
|
|
if (FavorUtf8 != DefaultBoolRegValue)
|
|
{
|
|
//
|
|
// A registry setting is present; use it.
|
|
//
|
|
FavorUtf8 = (BOOLEAN) (FavorUtf8 != 0);
|
|
}
|
|
else
|
|
{
|
|
FavorUtf8 = DEFAULT_FAVOR_UTF8_URL;
|
|
}
|
|
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// We can't do DBCS or favor UTF-8 if we accept UTF-8 only.
|
|
//
|
|
EnableDbcs = FALSE;
|
|
FavorUtf8 = FALSE;
|
|
}
|
|
|
|
PercentUAllowed = UlReadLongParameter(
|
|
parametersHandle,
|
|
REGISTRY_PERCENT_U_ALLOWED,
|
|
DefaultBoolRegValue);
|
|
|
|
if (PercentUAllowed != DefaultBoolRegValue)
|
|
{
|
|
//
|
|
// A registry setting is present; use it.
|
|
//
|
|
PercentUAllowed = (BOOLEAN) (PercentUAllowed != 0);
|
|
}
|
|
else
|
|
{
|
|
PercentUAllowed = DEFAULT_PERCENT_U_ALLOWED;
|
|
}
|
|
|
|
AllowRestrictedChars = UlReadLongParameter(
|
|
parametersHandle,
|
|
REGISTRY_ALLOW_RESTRICTED_CHARS,
|
|
DefaultBoolRegValue);
|
|
|
|
if (AllowRestrictedChars != DefaultBoolRegValue)
|
|
{
|
|
//
|
|
// A registry setting is present; use it.
|
|
//
|
|
AllowRestrictedChars = (BOOLEAN) (AllowRestrictedChars != 0);
|
|
}
|
|
else
|
|
{
|
|
AllowRestrictedChars = DEFAULT_ALLOW_RESTRICTED_CHARS;
|
|
}
|
|
|
|
tmp = UlReadLongParameter(
|
|
parametersHandle,
|
|
REGISTRY_URL_SEGMENT_MAX_LENGTH,
|
|
DEFAULT_URL_SEGMENT_MAX_LENGTH
|
|
);
|
|
|
|
if (tmp == 0)
|
|
{
|
|
// 0 in the registry turns this feature off
|
|
UrlSegmentMaxLength = C14N_URL_SEGMENT_UNLIMITED_LENGTH;
|
|
}
|
|
else if (tmp < WCSLEN_LIT(L"/x") || tmp > UNICODE_STRING_MAX_WCHAR_LEN)
|
|
{
|
|
UrlSegmentMaxLength = DEFAULT_URL_SEGMENT_MAX_LENGTH;
|
|
}
|
|
else
|
|
{
|
|
UrlSegmentMaxLength = tmp;
|
|
}
|
|
|
|
tmp = UlReadLongParameter(
|
|
parametersHandle,
|
|
REGISTRY_URL_SEGMENT_MAX_COUNT,
|
|
DEFAULT_URL_SEGMENT_MAX_COUNT
|
|
);
|
|
|
|
if (tmp == 0)
|
|
{
|
|
// 0 in the registry turns this feature off
|
|
UrlSegmentMaxCount = C14N_URL_SEGMENT_UNLIMITED_COUNT;
|
|
}
|
|
else if (tmp < 2 || tmp > UNICODE_STRING_MAX_WCHAR_LEN / WCSLEN_LIT(L"/x"))
|
|
{
|
|
UrlSegmentMaxCount = DEFAULT_URL_SEGMENT_MAX_COUNT;
|
|
}
|
|
else
|
|
{
|
|
UrlSegmentMaxCount = tmp;
|
|
}
|
|
|
|
//
|
|
// Initialize the default Url Canonicalization settings
|
|
//
|
|
|
|
HttpInitializeDefaultUrlC14nConfigEncoding(
|
|
&g_UrlC14nConfig,
|
|
(BOOLEAN) EnableNonUtf8,
|
|
(BOOLEAN) FavorUtf8,
|
|
(BOOLEAN) EnableDbcs
|
|
);
|
|
|
|
g_UrlC14nConfig.PercentUAllowed = (BOOLEAN) PercentUAllowed;
|
|
g_UrlC14nConfig.AllowRestrictedChars = (BOOLEAN) AllowRestrictedChars;
|
|
g_UrlC14nConfig.CodePage = ACPCode;
|
|
g_UrlC14nConfig.UrlSegmentMaxLength = UrlSegmentMaxLength;
|
|
g_UrlC14nConfig.UrlSegmentMaxCount = UrlSegmentMaxCount;
|
|
|
|
return ACPCode;
|
|
|
|
} // UlpReadUrlC14nConfig
|
|
|
|
/***************************************************************************++
|
|
|
|
Routine Description:
|
|
|
|
Reads the error logging config from registry and initializes the
|
|
global config structure.
|
|
|
|
Arguments:
|
|
|
|
parametersHandle - Supplies the reg handle to the http param folder.
|
|
|
|
--***************************************************************************/
|
|
|
|
VOID
|
|
UlpReadErrorLogConfig(
|
|
HANDLE parametersHandle
|
|
)
|
|
{
|
|
LONG tmp;
|
|
NTSTATUS Status;
|
|
PKEY_VALUE_PARTIAL_INFORMATION pInfo;
|
|
|
|
PAGED_CODE();
|
|
|
|
//
|
|
// First see whether it's enabled or not.
|
|
//
|
|
|
|
tmp = UlReadLongParameter(
|
|
parametersHandle,
|
|
REGISTRY_ERROR_LOGGING_ENABLED,
|
|
DEFAULT_ENABLE_ERROR_LOGGING
|
|
);
|
|
if (tmp == 0)
|
|
{
|
|
g_UlErrLoggingConfig.Enabled = FALSE;
|
|
}
|
|
else if (tmp == 1)
|
|
{
|
|
g_UlErrLoggingConfig.Enabled = TRUE;
|
|
}
|
|
else
|
|
{
|
|
g_UlErrLoggingConfig.Enabled = DEFAULT_ENABLE_ERROR_LOGGING;
|
|
}
|
|
|
|
//
|
|
// Now try to read the whole config if it is enabled.
|
|
//
|
|
|
|
if (g_UlErrLoggingConfig.Enabled == TRUE)
|
|
{
|
|
//
|
|
// Rollover size.
|
|
//
|
|
|
|
tmp = UlReadLongParameter(
|
|
parametersHandle,
|
|
REGISTRY_ERROR_LOGGING_TRUNCATION_SIZE,
|
|
0
|
|
);
|
|
if (tmp < 0)
|
|
{
|
|
//
|
|
// Interpret the neg values as infinite.
|
|
//
|
|
|
|
g_UlErrLoggingConfig.TruncateSize = HTTP_LIMIT_INFINITE;
|
|
|
|
}
|
|
else if (tmp < DEFAULT_MIN_ERROR_FILE_TRUNCATION_SIZE)
|
|
{
|
|
//
|
|
// If the it is invalid, set it to default.
|
|
//
|
|
|
|
g_UlErrLoggingConfig.TruncateSize = DEFAULT_ERROR_FILE_TRUNCATION_SIZE;
|
|
|
|
}
|
|
else
|
|
{
|
|
g_UlErrLoggingConfig.TruncateSize = (ULONG) tmp;
|
|
}
|
|
|
|
//
|
|
// Error logging directory.
|
|
//
|
|
|
|
g_UlErrLoggingConfig.Dir.Buffer = g_UlErrLoggingConfig._DirBuffer;
|
|
g_UlErrLoggingConfig.Dir.Length = 0;
|
|
g_UlErrLoggingConfig.Dir.MaximumLength =
|
|
(USHORT) sizeof(g_UlErrLoggingConfig._DirBuffer);
|
|
|
|
//
|
|
// Lets make sure the buffer is big enough to hold.
|
|
//
|
|
|
|
ASSERT(sizeof(g_UlErrLoggingConfig._DirBuffer)
|
|
>= (( MAX_PATH // From reg
|
|
+ UL_ERROR_LOG_SUB_DIR_LENGTH // SubDir
|
|
+ 1 // UnicodeNull
|
|
) * sizeof(WCHAR))
|
|
);
|
|
|
|
pInfo = NULL;
|
|
Status = UlReadGenericParameter(
|
|
parametersHandle,
|
|
REGISTRY_ERROR_LOGGING_DIRECTORY,
|
|
&pInfo
|
|
);
|
|
|
|
if (NT_SUCCESS(Status))
|
|
{
|
|
ASSERT(pInfo);
|
|
|
|
if (pInfo->Type == REG_EXPAND_SZ || pInfo->Type == REG_SZ)
|
|
{
|
|
USHORT RegDirLength = (USHORT) wcslen((PWCHAR) pInfo->Data);
|
|
|
|
if (RegDirLength <= MAX_PATH)
|
|
{
|
|
//
|
|
// Copy the beginning portion from the registry.
|
|
//
|
|
|
|
Status = UlBuildErrorLoggingDirStr(
|
|
(PCWSTR) pInfo->Data,
|
|
&g_UlErrLoggingConfig.Dir
|
|
);
|
|
|
|
ASSERT(NT_SUCCESS(Status));
|
|
|
|
//
|
|
// Check the user's directory.
|
|
//
|
|
|
|
Status = UlCheckErrorLogConfig(&g_UlErrLoggingConfig);
|
|
if (NT_SUCCESS(Status))
|
|
{
|
|
//
|
|
// Good to go.
|
|
//
|
|
|
|
UL_FREE_POOL( pInfo, UL_REGISTRY_DATA_POOL_TAG );
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Free up the returned value.
|
|
//
|
|
|
|
UL_FREE_POOL( pInfo, UL_REGISTRY_DATA_POOL_TAG );
|
|
}
|
|
|
|
//
|
|
// Fall back to the default directory.
|
|
//
|
|
|
|
ASSERT(wcslen(DEFAULT_ERROR_LOGGING_DIR) <= MAX_PATH);
|
|
|
|
Status = UlBuildErrorLoggingDirStr(
|
|
DEFAULT_ERROR_LOGGING_DIR,
|
|
&g_UlErrLoggingConfig.Dir
|
|
);
|
|
|
|
ASSERT(NT_SUCCESS(Status));
|
|
|
|
Status = UlCheckErrorLogConfig(&g_UlErrLoggingConfig);
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
//
|
|
// This call should not fail.
|
|
//
|
|
|
|
ASSERT(!"Invalid default error logging config !");
|
|
g_UlErrLoggingConfig.Enabled = FALSE;
|
|
}
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
/***************************************************************************++
|
|
|
|
Routine Description:
|
|
|
|
Reads the UL section of the registry. Any values contained in the
|
|
registry override defaults.
|
|
|
|
BUGBUG: the limits on many of these settings seem particularly arbitrary,
|
|
not to mention undocumented.
|
|
|
|
Arguments:
|
|
|
|
pConfig - Supplies a pointer to a UL_CONFIG structure that receives
|
|
init-time configuration parameters. These are basically
|
|
parameters that do not need to persist in the driver once
|
|
initialization is complete.
|
|
|
|
--***************************************************************************/
|
|
VOID
|
|
UlpReadRegistry(
|
|
IN PUL_CONFIG pConfig
|
|
)
|
|
{
|
|
HANDLE parametersHandle;
|
|
NTSTATUS status;
|
|
LONG tmp;
|
|
LONGLONG tmp64;
|
|
UNICODE_STRING registryPath;
|
|
UNICODE_STRING registryPathComputerName;
|
|
PKEY_VALUE_PARTIAL_INFORMATION pInfo;
|
|
PKEY_VALUE_PARTIAL_INFORMATION pValue;
|
|
HANDLE computerNameHandle;
|
|
ULONG ACPCode;
|
|
|
|
|
|
//
|
|
// Sanity check.
|
|
//
|
|
|
|
PAGED_CODE();
|
|
|
|
//
|
|
// Establish defaults.
|
|
//
|
|
|
|
pConfig->ThreadsPerCpu = DEFAULT_THREADS_PER_CPU;
|
|
pConfig->IrpContextLookasideDepth = DEFAULT_IRP_CONTEXT_LOOKASIDE_DEPTH;
|
|
pConfig->ReceiveBufferLookasideDepth = DEFAULT_RCV_BUFFER_LOOKASIDE_DEPTH;
|
|
pConfig->ResourceLookasideDepth = DEFAULT_RESOURCE_LOOKASIDE_DEPTH;
|
|
pConfig->RequestBufferLookasideDepth = DEFAULT_REQ_BUFFER_LOOKASIDE_DEPTH;
|
|
pConfig->InternalRequestLookasideDepth = DEFAULT_INT_REQUEST_LOOKASIDE_DEPTH;
|
|
pConfig->ResponseBufferLookasideDepth = DEFAULT_RESP_BUFFER_LOOKASIDE_DEPTH;
|
|
pConfig->SendTrackerLookasideDepth = DEFAULT_SEND_TRACKER_LOOKASIDE_DEPTH;
|
|
pConfig->LogFileBufferLookasideDepth = DEFAULT_LOG_BUFFER_LOOKASIDE_DEPTH;
|
|
pConfig->LogDataBufferLookasideDepth = DEFAULT_LOG_DATA_BUFFER_LOOKASIDE_DEPTH;
|
|
pConfig->ErrorLogBufferLookasideDepth = DEFAULT_ERROR_LOG_BUFFER_LOOKASIDE_DEPTH;
|
|
pConfig->FilterWriteTrackerLookasideDepth = DEFAULT_LOOKASIDE_DEPTH;
|
|
|
|
pConfig->UriConfig.EnableCache = DEFAULT_CACHE_ENABLED;
|
|
pConfig->UriConfig.MaxCacheUriCount = DEFAULT_MAX_CACHE_URI_COUNT;
|
|
pConfig->UriConfig.MaxCacheMegabyteCount = DEFAULT_MAX_CACHE_MEGABYTE_COUNT;
|
|
pConfig->UriConfig.MaxUriBytes = DEFAULT_MAX_URI_BYTES;
|
|
pConfig->UriConfig.ScavengerPeriod = DEFAULT_CACHE_SCAVENGER_PERIOD;
|
|
pConfig->EnableHttpClient = DEFAULT_HTTP_CLIENT_ENABLED;
|
|
|
|
//
|
|
// Open the registry.
|
|
//
|
|
|
|
status = UlInitUnicodeStringEx( ®istryPath, REGISTRY_UL_INFORMATION );
|
|
|
|
if(!NT_SUCCESS(status))
|
|
{
|
|
return;
|
|
}
|
|
|
|
status = UlOpenRegistry( ®istryPath, ¶metersHandle, NULL );
|
|
|
|
if(!NT_SUCCESS(status))
|
|
{
|
|
return;
|
|
}
|
|
|
|
#if DBG
|
|
//
|
|
// Read the debug flags.
|
|
//
|
|
|
|
g_UlDebug = (ULONGLONG)
|
|
UlReadLongLongParameter(
|
|
parametersHandle,
|
|
REGISTRY_DEBUG_FLAGS,
|
|
(LONGLONG)g_UlDebug
|
|
);
|
|
|
|
//
|
|
// Force a breakpoint if so requested.
|
|
//
|
|
|
|
if (UlReadLongParameter(
|
|
parametersHandle,
|
|
REGISTRY_BREAK_ON_STARTUP,
|
|
DEFAULT_BREAK_ON_STARTUP) != 0 )
|
|
{
|
|
DbgBreakPoint();
|
|
}
|
|
|
|
//
|
|
// Read the break-on-error flags.
|
|
//
|
|
|
|
g_UlBreakOnError = (BOOLEAN) UlReadLongParameter(
|
|
parametersHandle,
|
|
REGISTRY_BREAK_ON_ERROR,
|
|
g_UlBreakOnError
|
|
) != 0;
|
|
|
|
g_UlVerboseErrors = (BOOLEAN) UlReadLongParameter(
|
|
parametersHandle,
|
|
REGISTRY_VERBOSE_ERRORS,
|
|
g_UlVerboseErrors
|
|
) != 0;
|
|
|
|
//
|
|
// Break-on-error implies verbose-errors.
|
|
//
|
|
|
|
if (g_UlBreakOnError)
|
|
{
|
|
g_UlVerboseErrors = TRUE;
|
|
}
|
|
#endif // DBG
|
|
|
|
//
|
|
// Read the thread pool parameters.
|
|
//
|
|
|
|
tmp = UlReadLongParameter(
|
|
parametersHandle,
|
|
REGISTRY_THREADS_PER_CPU,
|
|
(LONG)pConfig->ThreadsPerCpu
|
|
);
|
|
|
|
if (tmp > MAX_THREADS_PER_CPU || tmp <= 0)
|
|
{
|
|
tmp = DEFAULT_THREADS_PER_CPU;
|
|
}
|
|
|
|
pConfig->ThreadsPerCpu = (USHORT)tmp;
|
|
|
|
//
|
|
// Other configuration parameters. (Lookaside depths are USHORTs)
|
|
//
|
|
|
|
tmp = UlReadLongParameter(
|
|
parametersHandle,
|
|
REGISTRY_IDLE_CONNECTIONS_LOW_MARK,
|
|
(LONG)g_UlIdleConnectionsLowMark
|
|
);
|
|
|
|
if (tmp > UL_MAX_SLIST_DEPTH || tmp < 1)
|
|
{
|
|
//
|
|
// If the low mark is bad, don't even try to read the high mark.
|
|
//
|
|
g_UlIdleConnectionsLowMark = DEFAULT_IDLE_CONNECTIONS_LOW_MARK;
|
|
g_UlIdleConnectionsHighMark = DEFAULT_IDLE_CONNECTIONS_HIGH_MARK;
|
|
}
|
|
else
|
|
{
|
|
g_UlIdleConnectionsLowMark = (USHORT)tmp;
|
|
|
|
//
|
|
// Now read the high mark, again if it is bad, discard the low mark
|
|
// as well.
|
|
//
|
|
tmp = UlReadLongParameter(
|
|
parametersHandle,
|
|
REGISTRY_IDLE_CONNECTIONS_HIGH_MARK,
|
|
(LONG)g_UlIdleConnectionsHighMark
|
|
);
|
|
|
|
if (tmp < g_UlIdleConnectionsLowMark ||
|
|
tmp > UL_MAX_SLIST_DEPTH
|
|
)
|
|
{
|
|
g_UlIdleConnectionsLowMark = DEFAULT_IDLE_CONNECTIONS_LOW_MARK;
|
|
g_UlIdleConnectionsHighMark = DEFAULT_IDLE_CONNECTIONS_HIGH_MARK;
|
|
}
|
|
else
|
|
{
|
|
g_UlIdleConnectionsHighMark = (USHORT)tmp;
|
|
}
|
|
}
|
|
|
|
tmp = UlReadLongParameter(
|
|
parametersHandle,
|
|
REGISTRY_IDLE_LIST_TRIMMER_PERIOD,
|
|
(LONG)g_UlIdleListTrimmerPeriod
|
|
);
|
|
|
|
if (tmp > (24 * 60 * 60) || tmp < 5)
|
|
{
|
|
tmp = DEFAULT_IDLE_LIST_TRIMMER_PERIOD;
|
|
}
|
|
|
|
g_UlIdleListTrimmerPeriod = (ULONG)tmp;
|
|
|
|
tmp = UlReadLongParameter(
|
|
parametersHandle,
|
|
REGISTRY_MAX_ENDPOINTS,
|
|
(LONG)g_UlMaxEndpoints
|
|
);
|
|
|
|
if (tmp > 1024 || tmp < 0)
|
|
{
|
|
tmp = DEFAULT_MAX_ENDPOINTS;
|
|
}
|
|
|
|
g_UlMaxEndpoints = (USHORT)tmp;
|
|
|
|
tmp = UlReadLongParameter(
|
|
parametersHandle,
|
|
REGISTRY_IRP_CONTEXT_LOOKASIDE_DEPTH,
|
|
(LONG)pConfig->IrpContextLookasideDepth
|
|
);
|
|
|
|
if (tmp > UL_MAX_SLIST_DEPTH || tmp < 0)
|
|
{
|
|
tmp = DEFAULT_IRP_CONTEXT_LOOKASIDE_DEPTH;
|
|
}
|
|
|
|
pConfig->IrpContextLookasideDepth = (USHORT)tmp;
|
|
|
|
tmp = UlReadLongParameter(
|
|
parametersHandle,
|
|
REGISTRY_RCV_BUFFER_LOOKASIDE_DEPTH,
|
|
(LONG)pConfig->ReceiveBufferLookasideDepth
|
|
);
|
|
|
|
if (tmp > UL_MAX_SLIST_DEPTH || tmp < 0)
|
|
{
|
|
tmp = DEFAULT_RCV_BUFFER_LOOKASIDE_DEPTH;
|
|
}
|
|
|
|
pConfig->ReceiveBufferLookasideDepth = (USHORT)tmp;
|
|
|
|
tmp = UlReadLongParameter(
|
|
parametersHandle,
|
|
REGISTRY_REQ_BUFFER_LOOKASIDE_DEPTH,
|
|
(LONG)pConfig->RequestBufferLookasideDepth
|
|
);
|
|
|
|
if (tmp > UL_MAX_SLIST_DEPTH || tmp < 0)
|
|
{
|
|
tmp = DEFAULT_REQ_BUFFER_LOOKASIDE_DEPTH;
|
|
}
|
|
|
|
pConfig->RequestBufferLookasideDepth = (USHORT)tmp;
|
|
|
|
tmp = UlReadLongParameter(
|
|
parametersHandle,
|
|
REGISTRY_INT_REQUEST_LOOKASIDE_DEPTH,
|
|
(LONG)pConfig->InternalRequestLookasideDepth
|
|
);
|
|
|
|
if (tmp > UL_MAX_SLIST_DEPTH || tmp < 0)
|
|
{
|
|
tmp = DEFAULT_INT_REQUEST_LOOKASIDE_DEPTH;
|
|
}
|
|
|
|
pConfig->InternalRequestLookasideDepth = (USHORT)tmp;
|
|
|
|
tmp = UlReadLongParameter(
|
|
parametersHandle,
|
|
REGISTRY_RESP_BUFFER_LOOKASIDE_DEPTH,
|
|
(LONG)pConfig->ResponseBufferLookasideDepth
|
|
);
|
|
|
|
if (tmp > UL_MAX_SLIST_DEPTH || tmp < 0)
|
|
{
|
|
tmp = DEFAULT_RESP_BUFFER_LOOKASIDE_DEPTH;
|
|
}
|
|
|
|
pConfig->ResponseBufferLookasideDepth = (USHORT)tmp;
|
|
|
|
tmp = UlReadLongParameter(
|
|
parametersHandle,
|
|
REGISTRY_SEND_TRACKER_LOOKASIDE_DEPTH,
|
|
(LONG)pConfig->SendTrackerLookasideDepth
|
|
);
|
|
|
|
if (tmp > UL_MAX_SLIST_DEPTH || tmp < 0)
|
|
{
|
|
tmp = DEFAULT_SEND_TRACKER_LOOKASIDE_DEPTH;
|
|
}
|
|
|
|
pConfig->SendTrackerLookasideDepth = (USHORT)tmp;
|
|
|
|
tmp = UlReadLongParameter(
|
|
parametersHandle,
|
|
REGISTRY_LOG_BUFFER_LOOKASIDE_DEPTH,
|
|
(LONG)pConfig->LogFileBufferLookasideDepth
|
|
);
|
|
|
|
if (tmp > UL_MAX_SLIST_DEPTH || tmp < 0)
|
|
{
|
|
tmp = DEFAULT_LOG_BUFFER_LOOKASIDE_DEPTH;
|
|
}
|
|
|
|
pConfig->LogFileBufferLookasideDepth = (USHORT)tmp;
|
|
|
|
tmp = UlReadLongParameter(
|
|
parametersHandle,
|
|
REGISTRY_LOG_DATA_BUFFER_LOOKASIDE_DEPTH,
|
|
(LONG)pConfig->LogDataBufferLookasideDepth
|
|
);
|
|
|
|
if (tmp > UL_MAX_SLIST_DEPTH || tmp < 0)
|
|
{
|
|
tmp = DEFAULT_LOG_DATA_BUFFER_LOOKASIDE_DEPTH;
|
|
}
|
|
|
|
pConfig->LogDataBufferLookasideDepth = (USHORT)tmp;
|
|
|
|
g_UlOptForIntrMod = (BOOLEAN) UlReadLongParameter(
|
|
parametersHandle,
|
|
REGISTRY_OPT_FOR_INTR_MOD,
|
|
(LONG)g_UlOptForIntrMod
|
|
) != 0;
|
|
|
|
g_UlEnableNagling = (BOOLEAN) UlReadLongParameter(
|
|
parametersHandle,
|
|
REGISTRY_ENABLE_NAGLING,
|
|
(LONG)g_UlEnableNagling
|
|
) != 0;
|
|
|
|
g_UlEnableThreadAffinity = (BOOLEAN) UlReadLongParameter(
|
|
parametersHandle,
|
|
REGISTRY_ENABLE_THREAD_AFFINITY,
|
|
(LONG)g_UlEnableThreadAffinity
|
|
) != 0;
|
|
|
|
tmp64 = UlReadLongLongParameter(
|
|
parametersHandle,
|
|
REGISTRY_THREAD_AFFINITY_MASK,
|
|
g_UlThreadAffinityMask
|
|
);
|
|
|
|
if ((ULONGLONG)tmp64 > DEFAULT_THREAD_AFFINITY_MASK
|
|
|| (ULONGLONG)tmp64 == 0)
|
|
{
|
|
tmp64 = DEFAULT_THREAD_AFFINITY_MASK;
|
|
}
|
|
|
|
g_UlThreadAffinityMask = (ULONGLONG)tmp64;
|
|
|
|
tmp = UlReadLongParameter(
|
|
parametersHandle,
|
|
REGISTRY_MAX_WORK_QUEUE_DEPTH,
|
|
(LONG)g_UlMaxWorkQueueDepth
|
|
);
|
|
|
|
if (tmp > UL_MAX_SLIST_DEPTH || tmp < 0)
|
|
{
|
|
tmp = DEFAULT_MAX_WORK_QUEUE_DEPTH;
|
|
}
|
|
|
|
g_UlMaxWorkQueueDepth = (USHORT)tmp;
|
|
|
|
tmp = UlReadLongParameter(
|
|
parametersHandle,
|
|
REGISTRY_MIN_WORK_DEQUEUE_DEPTH,
|
|
(LONG)g_UlMinWorkDequeueDepth
|
|
);
|
|
|
|
if (tmp > UL_MAX_SLIST_DEPTH || tmp < 0)
|
|
{
|
|
tmp = DEFAULT_MIN_WORK_DEQUEUE_DEPTH;
|
|
}
|
|
|
|
g_UlMinWorkDequeueDepth = (USHORT)tmp;
|
|
|
|
tmp = UlReadLongParameter(
|
|
parametersHandle,
|
|
REGISTRY_MAX_COPY_THRESHOLD,
|
|
(LONG)g_UlMaxCopyThreshold
|
|
);
|
|
|
|
if (tmp > (128 * 1024) || tmp < 0)
|
|
{
|
|
tmp = DEFAULT_MAX_COPY_THRESHOLD;
|
|
}
|
|
|
|
g_UlMaxCopyThreshold = tmp;
|
|
|
|
tmp = UlReadLongParameter(
|
|
parametersHandle,
|
|
REGISTRY_MAX_BUFFERED_SENDS,
|
|
(LONG)g_UlMaxBufferedSends
|
|
);
|
|
|
|
if (tmp > 64 || tmp < 0)
|
|
{
|
|
tmp = DEFAULT_MAX_BUFFERED_SENDS;
|
|
}
|
|
|
|
g_UlMaxBufferedSends = tmp;
|
|
|
|
tmp = UlReadLongParameter(
|
|
parametersHandle,
|
|
REGISTRY_MAX_BYTES_PER_SEND,
|
|
(LONG)g_UlMaxBytesPerSend
|
|
);
|
|
|
|
if (tmp > 0xFFFFF || tmp < 0)
|
|
{
|
|
tmp = DEFAULT_MAX_BYTES_PER_SEND;
|
|
}
|
|
|
|
g_UlMaxBytesPerSend = tmp;
|
|
|
|
tmp = UlReadLongParameter(
|
|
parametersHandle,
|
|
REGISTRY_MAX_BYTES_PER_READ,
|
|
(LONG)g_UlMaxBytesPerRead
|
|
);
|
|
|
|
if (tmp > 0xFFFFF || tmp < 0)
|
|
{
|
|
tmp = DEFAULT_MAX_BYTES_PER_READ;
|
|
}
|
|
|
|
g_UlMaxBytesPerRead = tmp;
|
|
|
|
tmp = UlReadLongParameter(
|
|
parametersHandle,
|
|
REGISTRY_MAX_PIPELINED_REQUESTS,
|
|
(LONG)g_UlMaxPipelinedRequests
|
|
);
|
|
|
|
if (tmp > 1024 || tmp < 0)
|
|
{
|
|
tmp = DEFAULT_MAX_PIPELINED_REQUESTS;
|
|
}
|
|
|
|
g_UlMaxPipelinedRequests = tmp;
|
|
|
|
g_UlEnableCopySend = (BOOLEAN) UlReadLongParameter(
|
|
parametersHandle,
|
|
REGISTRY_ENABLE_COPY_SEND,
|
|
DEFAULT_ENABLE_COPY_SEND
|
|
) != 0;
|
|
|
|
tmp = UlReadLongParameter(
|
|
parametersHandle,
|
|
REGISTRY_CONNECTION_SEND_LIMIT,
|
|
(LONG)g_UlConnectionSendLimit
|
|
);
|
|
|
|
if (tmp > (1024 * 1024) || tmp < 0)
|
|
{
|
|
tmp = DEFAULT_CONNECTION_SEND_LIMIT;
|
|
}
|
|
|
|
g_UlConnectionSendLimit = tmp;
|
|
|
|
tmp64 = UlReadLongLongParameter(
|
|
parametersHandle,
|
|
REGISTRY_GLOBAL_SEND_LIMIT,
|
|
g_UlGlobalSendLimit
|
|
);
|
|
|
|
if (tmp64 > (LONGLONG)g_UlTotalNonPagedPoolBytes / 2 ||
|
|
tmp64 < (LONGLONG)g_UlConnectionSendLimit)
|
|
{
|
|
tmp64 = DEFAULT_GLOBAL_SEND_LIMIT;
|
|
}
|
|
|
|
g_UlGlobalSendLimit = tmp64;
|
|
|
|
tmp = UlReadLongParameter(
|
|
parametersHandle,
|
|
REGISTRY_OPAQUE_ID_TABLE_SIZE,
|
|
(LONG)g_UlOpaqueIdTableSize
|
|
);
|
|
|
|
if (tmp > 0xFFFF || tmp <= 0)
|
|
{
|
|
tmp = DEFAULT_OPAQUE_ID_TABLE_SIZE;
|
|
}
|
|
|
|
g_UlOpaqueIdTableSize = tmp;
|
|
|
|
//
|
|
// MaxInternalUrlLength is a hint for allocating the inline buffer
|
|
// of WCHARs to hold the URL at the end of a UL_INTERNAL_REQUEST.
|
|
// Note: This is not the maximum possible length of a URL received off
|
|
// the wire; that's MaxFieldLength.
|
|
//
|
|
|
|
tmp = UlReadLongParameter(
|
|
parametersHandle,
|
|
REGISTRY_MAX_INTERNAL_URL_LENGTH,
|
|
g_UlMaxInternalUrlLength
|
|
);
|
|
|
|
//
|
|
// Round up to an even number, as it measures the size in bytes
|
|
// of a WCHAR array
|
|
//
|
|
tmp = (tmp + 1) & ~1;
|
|
|
|
#define MIN_MAX_INTERNAL_URL_LENGTH (64 * sizeof(WCHAR))
|
|
#define MAX_MAX_INTERNAL_URL_LENGTH (MAX_PATH * sizeof(WCHAR))
|
|
|
|
tmp = min(tmp, MAX_MAX_INTERNAL_URL_LENGTH);
|
|
tmp = max(tmp, MIN_MAX_INTERNAL_URL_LENGTH);
|
|
|
|
ASSERT(MIN_MAX_INTERNAL_URL_LENGTH <= tmp
|
|
&& tmp <= MAX_MAX_INTERNAL_URL_LENGTH);
|
|
|
|
g_UlMaxInternalUrlLength = tmp;
|
|
|
|
//
|
|
// MAX allowed field length in HTTP requests, in bytes
|
|
//
|
|
|
|
tmp = UlReadLongParameter(
|
|
parametersHandle,
|
|
REGISTRY_MAX_FIELD_LENGTH,
|
|
(LONG)g_UlMaxFieldLength
|
|
);
|
|
|
|
// Set a 64KB-2 hard upper limit for each individual header.
|
|
// Note: the length fields in HTTP_KNOWN_HEADER and HTTP_UNKNOWN_HEADER
|
|
// are USHORTs. We have to allow a terminating '\0' in the data
|
|
// we pass up, hence -2.
|
|
|
|
tmp = min(tmp, ANSI_STRING_MAX_CHAR_LEN);
|
|
tmp = max(tmp, 64);
|
|
|
|
ASSERT(64 <= tmp && tmp <= ANSI_STRING_MAX_CHAR_LEN);
|
|
|
|
g_UlMaxFieldLength = tmp;
|
|
|
|
//
|
|
// MaxRequestBytes is the total size of all the headers, including
|
|
// the initial verb/URL/version line.
|
|
//
|
|
|
|
tmp = UlReadLongParameter(
|
|
parametersHandle,
|
|
REGISTRY_MAX_REQUEST_BYTES,
|
|
g_UlMaxRequestBytes
|
|
);
|
|
|
|
// Set a 16MB hard upper limit for all the headers. Don't want to
|
|
// set it bigger than this to minimize Denial of Service attacks.
|
|
// If you really want to send a lot of data, send it in the entity body.
|
|
|
|
tmp = min(tmp, (16 * 1024 * 1024));
|
|
tmp = max(tmp, 256);
|
|
|
|
ASSERT(256 <= tmp && tmp <= (16 * 1024 * 1024));
|
|
|
|
g_UlMaxRequestBytes = tmp;
|
|
|
|
// An individual field can't be bigger than the aggregated fields
|
|
|
|
if (g_UlMaxRequestBytes < g_UlMaxFieldLength)
|
|
{
|
|
g_UlMaxFieldLength = g_UlMaxRequestBytes;
|
|
}
|
|
|
|
tmp = UlReadLongParameter(
|
|
parametersHandle,
|
|
REGISTRY_DISABLE_LOG_BUFFERING,
|
|
(LONG)g_UlDisableLogBuffering
|
|
);
|
|
|
|
g_UlDisableLogBuffering = (BOOLEAN) (tmp != 0);
|
|
|
|
tmp = UlReadLongParameter(
|
|
parametersHandle,
|
|
REGISTRY_LOG_BUFFER_SIZE,
|
|
(LONG)g_UlLogBufferSize
|
|
);
|
|
|
|
if (tmp > MAXIMUM_ALLOWED_LOG_BUFFER_SIZE
|
|
|| tmp < MINIMUM_ALLOWED_LOG_BUFFER_SIZE )
|
|
{
|
|
// Basically this value will be discarted by the logging code
|
|
// instead systems granularity size (64K) will be used.
|
|
tmp = DEFAULT_LOG_BUFFER_SIZE;
|
|
}
|
|
|
|
tmp -= tmp % 4096; // Align down to 4k
|
|
|
|
g_UlLogBufferSize = (ULONG) tmp;
|
|
|
|
//
|
|
// read the resource lookaside config
|
|
//
|
|
|
|
tmp = UlReadLongParameter(
|
|
parametersHandle,
|
|
REGISTRY_RESOURCE_LOOKASIDE_DEPTH,
|
|
(LONG)pConfig->ResourceLookasideDepth
|
|
);
|
|
|
|
if (tmp > UL_MAX_SLIST_DEPTH || tmp < 0)
|
|
{
|
|
tmp = DEFAULT_RESOURCE_LOOKASIDE_DEPTH;
|
|
}
|
|
|
|
pConfig->ResourceLookasideDepth = (USHORT)tmp;
|
|
|
|
|
|
tmp = UlReadLongParameter(
|
|
parametersHandle,
|
|
REGISTRY_MAX_REQUESTS_QUEUED,
|
|
g_UlMaxRequestsQueued
|
|
);
|
|
|
|
if (tmp > UL_MAX_REQUESTS_QUEUED || tmp < UL_MIN_REQUESTS_QUEUED)
|
|
{
|
|
tmp = DEFAULT_MAX_REQUESTS_QUEUED;
|
|
}
|
|
|
|
g_UlMaxRequestsQueued = tmp;
|
|
|
|
tmp = UlReadLongParameter(
|
|
parametersHandle,
|
|
REGISTRY_MAX_ZOMBIE_HTTP_CONN_COUNT,
|
|
g_UlMaxZombieHttpConnectionCount
|
|
);
|
|
|
|
if (tmp > 0xFFFF || tmp < 0)
|
|
{
|
|
tmp = DEFAULT_MAX_ZOMBIE_HTTP_CONN_COUNT;
|
|
}
|
|
|
|
g_UlMaxZombieHttpConnectionCount = tmp;
|
|
|
|
//
|
|
// Max UL_CONNECTION override
|
|
//
|
|
|
|
tmp = UlReadLongParameter(
|
|
parametersHandle,
|
|
REGISTRY_MAX_CONNECTIONS,
|
|
g_MaxConnections
|
|
);
|
|
|
|
// Restrict from 1K min to 2M max
|
|
if (tmp > 0x1F0000 || tmp < 0x400 )
|
|
{
|
|
tmp = HTTP_LIMIT_INFINITE;
|
|
}
|
|
|
|
g_MaxConnections = tmp;
|
|
|
|
tmp = UlReadLongParameter(
|
|
parametersHandle,
|
|
REGISTRY_RCV_BUFFER_SIZE,
|
|
g_UlReceiveBufferSize
|
|
);
|
|
|
|
if (tmp > 0xFFFF || tmp < 128)
|
|
{
|
|
tmp = DEFAULT_RCV_BUFFER_SIZE;
|
|
}
|
|
|
|
g_UlReceiveBufferSize = ALIGN_UP( tmp, PVOID );
|
|
|
|
tmp = UlReadLongParameter(
|
|
parametersHandle,
|
|
REGISTRY_RESP_BUFFER_SIZE,
|
|
g_UlResponseBufferSize
|
|
);
|
|
|
|
if (tmp > 0xFFFF || tmp < 128)
|
|
{
|
|
tmp = DEFAULT_RESP_BUFFER_SIZE;
|
|
}
|
|
|
|
g_UlResponseBufferSize = tmp;
|
|
|
|
ACPCode = UlpReadUrlC14nConfig(parametersHandle);
|
|
|
|
//
|
|
// Should we disable the Server: response header?
|
|
//
|
|
|
|
tmp = UlReadLongParameter(
|
|
parametersHandle,
|
|
REGISTRY_DISABLE_SERVER_HEADER,
|
|
(LONG)g_UlDisableServerHeader
|
|
);
|
|
|
|
if (tmp >= 0 && tmp <= 2)
|
|
{
|
|
g_UlDisableServerHeader = (ULONG) tmp;
|
|
}
|
|
|
|
|
|
//
|
|
// Read error logging config.
|
|
//
|
|
|
|
UlpReadErrorLogConfig(parametersHandle);
|
|
|
|
//
|
|
// Read the ComputerName from the Registry.
|
|
//
|
|
|
|
wcsncpy(g_UlComputerName, L"<server>", MAX_COMPUTER_NAME_LEN);
|
|
|
|
status = UlInitUnicodeStringEx( ®istryPathComputerName,
|
|
REGISTRY_COMPUTER_NAME_PATH );
|
|
|
|
if (NT_SUCCESS(status))
|
|
{
|
|
status = UlOpenRegistry(
|
|
®istryPathComputerName,
|
|
&computerNameHandle,
|
|
REGISTRY_COMPUTER_NAME
|
|
);
|
|
|
|
if (NT_SUCCESS(status))
|
|
{
|
|
pInfo = NULL;
|
|
|
|
status = UlReadGenericParameter(
|
|
computerNameHandle,
|
|
REGISTRY_COMPUTER_NAME,
|
|
&pInfo
|
|
);
|
|
|
|
if (NT_SUCCESS(status))
|
|
{
|
|
ASSERT(pInfo);
|
|
|
|
if (pInfo->Type == REG_SZ)
|
|
{
|
|
wcsncpy(g_UlComputerName,
|
|
(PWCHAR)pInfo->Data,
|
|
MAX_COMPUTER_NAME_LEN
|
|
);
|
|
//
|
|
// Make sure we're NULL terminated. This will truncate
|
|
// the name from the registry.
|
|
//
|
|
|
|
g_UlComputerName[MAX_COMPUTER_NAME_LEN] = L'\0';
|
|
}
|
|
|
|
//
|
|
// Free up the returned value.
|
|
//
|
|
|
|
UL_FREE_POOL( pInfo, UL_REGISTRY_DATA_POOL_TAG );
|
|
}
|
|
|
|
ZwClose( computerNameHandle );
|
|
}
|
|
}
|
|
|
|
//
|
|
// Read URI Cache parameters
|
|
//
|
|
|
|
pConfig->UriConfig.EnableCache = (BOOLEAN) UlReadLongParameter(
|
|
parametersHandle,
|
|
REGISTRY_CACHE_ENABLED,
|
|
DEFAULT_CACHE_ENABLED
|
|
) != 0;
|
|
|
|
pConfig->UriConfig.MaxCacheUriCount = UlReadLongParameter(
|
|
parametersHandle,
|
|
REGISTRY_MAX_CACHE_URI_COUNT,
|
|
DEFAULT_MAX_CACHE_URI_COUNT
|
|
);
|
|
|
|
pConfig->UriConfig.MaxCacheMegabyteCount = UlReadLongParameter(
|
|
parametersHandle,
|
|
REGISTRY_MAX_CACHE_MEGABYTE_COUNT,
|
|
DEFAULT_MAX_CACHE_MEGABYTE_COUNT
|
|
);
|
|
|
|
tmp = UlReadLongParameter(
|
|
parametersHandle,
|
|
REGISTRY_MAX_URI_BYTES,
|
|
DEFAULT_MAX_URI_BYTES
|
|
);
|
|
|
|
if (tmp < (4 * 1024) || tmp > (16 * 1024 * 1024))
|
|
{
|
|
tmp = DEFAULT_MAX_URI_BYTES;
|
|
}
|
|
|
|
pConfig->UriConfig.MaxUriBytes = tmp;
|
|
|
|
pConfig->UriConfig.ScavengerPeriod = UlReadLongParameter(
|
|
parametersHandle,
|
|
REGISTRY_CACHE_SCAVENGER_PERIOD,
|
|
DEFAULT_CACHE_SCAVENGER_PERIOD
|
|
);
|
|
|
|
pConfig->UriConfig.HashTableBits = UlReadLongParameter(
|
|
parametersHandle,
|
|
REGISTRY_HASH_TABLE_BITS,
|
|
DEFAULT_HASH_TABLE_BITS
|
|
);
|
|
|
|
#if 0
|
|
pConfig->EnableHttpClient = (BOOLEAN) UlReadLongParameter(
|
|
parametersHandle,
|
|
REGISTRY_HTTP_CLIENT_ENABLED,
|
|
DEFAULT_HTTP_CLIENT_ENABLED
|
|
) != 0;
|
|
#endif
|
|
|
|
g_HttpClientEnabled = pConfig->EnableHttpClient;
|
|
|
|
//
|
|
// Read list of IP addresses for ListenOnlyList
|
|
//
|
|
pValue = NULL;
|
|
status = UlReadGenericParameter(
|
|
parametersHandle,
|
|
REGISTRY_LISTEN_ONLY_LIST,
|
|
&pValue
|
|
);
|
|
|
|
if (NT_SUCCESS(status) && REG_MULTI_SZ == pValue->Type)
|
|
{
|
|
// If UlRegMultiSzToUlAddrArray fails then we simply use
|
|
// the default.
|
|
|
|
status = UlRegMultiSzToUlAddrArray(
|
|
(PWSTR)pValue->Data,
|
|
&g_pTdiListenAddresses,
|
|
&g_TdiListenAddrCount
|
|
);
|
|
|
|
if ( STATUS_INVALID_PARAMETER == status )
|
|
{
|
|
//
|
|
// Write event log message that ListenOnlyList was found, but
|
|
// no entries could be converted.
|
|
//
|
|
|
|
UlWriteEventLogEntry(
|
|
EVENT_HTTP_LISTEN_ONLY_ALL_CONVERT_FAILED,
|
|
0,
|
|
0,
|
|
NULL,
|
|
0,
|
|
NULL
|
|
);
|
|
}
|
|
}
|
|
|
|
if ( pValue )
|
|
{
|
|
UL_FREE_POOL( pValue, UL_REGISTRY_DATA_POOL_TAG );
|
|
pValue = NULL;
|
|
}
|
|
|
|
//
|
|
// Make sure we can always buffer enough bytes for an entire request
|
|
// header.
|
|
//
|
|
|
|
g_UlMaxBufferedBytes = MAX(g_UlMaxBufferedBytes, g_UlMaxRequestBytes);
|
|
|
|
//
|
|
// Scavenger Config - MB to reclaim each time
|
|
//
|
|
|
|
g_UlScavengerTrimMB = UlReadLongParameter(
|
|
parametersHandle,
|
|
REGISTRY_SCAVENGER_TRIM_MB,
|
|
DEFAULT_SCAVENGER_TRIM_MB
|
|
);
|
|
|
|
//
|
|
// Dump configuration on checked builds.
|
|
//
|
|
|
|
#if DBG
|
|
DbgPrint( "Http.sys Configuration:\n" );
|
|
|
|
// These settings are only present on checked builds
|
|
DbgPrint( " g_UlDebug = 0x%016I64x\n", g_UlDebug );
|
|
DbgPrint( " g_UlBreakOnError = %lu\n", g_UlBreakOnError );
|
|
DbgPrint( " g_UlVerboseErrors = %lu\n", g_UlVerboseErrors );
|
|
|
|
// These settings are present on all builds
|
|
DbgPrint( " g_UlComputerName = %ls\n", g_UlComputerName );
|
|
DbgPrint( " g_UlIdleConnectionsHighMark = %lu\n", g_UlIdleConnectionsHighMark );
|
|
DbgPrint( " g_UlIdleConnectionsLowMark = %lu\n", g_UlIdleConnectionsLowMark );
|
|
DbgPrint( " g_UlIdleListTrimmerPeriod = %lu\n", g_UlIdleListTrimmerPeriod );
|
|
DbgPrint( " g_UlMaxEndpoints = %lu\n", g_UlMaxEndpoints );
|
|
DbgPrint( " g_UlOptForIntrMod = %lu\n", g_UlOptForIntrMod );
|
|
DbgPrint( " g_UlEnableNagling = %lu\n", g_UlEnableNagling );
|
|
DbgPrint( " g_UlEnableThreadAffinity = %lu\n", g_UlEnableThreadAffinity );
|
|
DbgPrint( " g_UlThreadAffinityMask = 0x%I64x\n", g_UlThreadAffinityMask );
|
|
DbgPrint( " g_UlMaxCopyThreshold = %lu\n", g_UlMaxCopyThreshold );
|
|
DbgPrint( " g_UlMaxBufferedSends = %lu\n", g_UlMaxBufferedSends );
|
|
DbgPrint( " g_UlMaxBytesPerSend = %lu\n", g_UlMaxBytesPerSend );
|
|
DbgPrint( " g_UlMaxBytesPerRead = %lu\n", g_UlMaxBytesPerRead );
|
|
DbgPrint( " g_UlMaxPipelinedRequests = %lu\n", g_UlMaxPipelinedRequests );
|
|
DbgPrint( " g_UlEnableCopySend = %lu\n", g_UlEnableCopySend );
|
|
DbgPrint( " g_UlConnectionSendLimit = %lu\n", g_UlConnectionSendLimit );
|
|
DbgPrint( " g_UlGlobalSendLimit = %I64u\n", g_UlGlobalSendLimit );
|
|
DbgPrint( " g_UlOpaqueIdTableSize = %lu\n", g_UlOpaqueIdTableSize );
|
|
DbgPrint( " g_UlMaxRequestsQueued = %lu\n", g_UlMaxRequestsQueued );
|
|
DbgPrint( " g_UlMaxRequestBytes = %lu\n", g_UlMaxRequestBytes );
|
|
DbgPrint( " g_UlReceiveBufferSize = %lu\n", g_UlReceiveBufferSize );
|
|
DbgPrint( " g_UlResponseBufferSize = %lu\n", g_UlResponseBufferSize );
|
|
DbgPrint( " g_UlMaxFieldLength = %lu\n", g_UlMaxFieldLength );
|
|
DbgPrint( " g_MaxConnections = 0x%lx\n", g_MaxConnections );
|
|
DbgPrint( " g_UlDisableLogBuffering = %lu\n", g_UlDisableLogBuffering );
|
|
DbgPrint( " g_UlLogBufferSize = %lu\n", g_UlLogBufferSize );
|
|
|
|
DbgPrint( " CodePage = %lu\n", ACPCode );
|
|
DbgPrint( " EnableNonUtf8 = %lu\n", g_UrlC14nConfig.EnableNonUtf8 );
|
|
DbgPrint( " FavorUtf8 = %lu\n", g_UrlC14nConfig.FavorUtf8 );
|
|
DbgPrint( " EnableDbcs = %lu\n", g_UrlC14nConfig.EnableDbcs );
|
|
DbgPrint( " PercentUAllowed = %lu\n", g_UrlC14nConfig.PercentUAllowed );
|
|
DbgPrint( " AllowRestrictedChars = %lu\n", g_UrlC14nConfig.AllowRestrictedChars );
|
|
DbgPrint( " HostnameDecodeOrder = 0x%lx\n", g_UrlC14nConfig.HostnameDecodeOrder );
|
|
DbgPrint( " AbsPathDecodeOrder = 0x%lx\n", g_UrlC14nConfig.AbsPathDecodeOrder );
|
|
DbgPrint( " UrlSegmentMaxLength = %lu\n", g_UrlC14nConfig.UrlSegmentMaxLength );
|
|
DbgPrint( " UrlSegmentMaxCount = %lu\n", g_UrlC14nConfig.UrlSegmentMaxCount );
|
|
|
|
DbgPrint( " g_UlMaxInternalUrlLength = %lu\n", g_UlMaxInternalUrlLength );
|
|
DbgPrint( " g_UlMaxZombieHttpConnCount = %lu\n", g_UlMaxZombieHttpConnectionCount );
|
|
DbgPrint( " g_UlDisableServerHeader = %lu\n", g_UlDisableServerHeader );
|
|
|
|
DbgPrint( " ThreadsPerCpu = %lu\n", pConfig->ThreadsPerCpu );
|
|
DbgPrint( " IrpContextLookasideDepth = %lu\n", pConfig->IrpContextLookasideDepth );
|
|
DbgPrint( " ReceiveBufferLookasideDepth = %lu\n", pConfig->ReceiveBufferLookasideDepth );
|
|
DbgPrint( " ResourceLookasideDepth = %lu\n", pConfig->ResourceLookasideDepth );
|
|
DbgPrint( " RequestBufferLookasideDepth = %lu\n", pConfig->RequestBufferLookasideDepth );
|
|
DbgPrint( " IntlRequestLookasideDepth = %lu\n", pConfig->InternalRequestLookasideDepth );
|
|
DbgPrint( " ResponseBufferLookasideDepth = %lu\n", pConfig->ResponseBufferLookasideDepth );
|
|
DbgPrint( " SendTrackerLookasideDepth = %lu\n", pConfig->SendTrackerLookasideDepth );
|
|
DbgPrint( " LogFileBufferLookasideDepth = %lu\n", pConfig->LogFileBufferLookasideDepth );
|
|
DbgPrint( " LogDataBufferLookasideDepth = %lu\n", pConfig->LogDataBufferLookasideDepth );
|
|
DbgPrint( " WriteTrackerLookasideDepth = %lu\n", pConfig->FilterWriteTrackerLookasideDepth );
|
|
DbgPrint( " EnableCache = %lu\n", pConfig->UriConfig.EnableCache );
|
|
DbgPrint( " MaxCacheUriCount = %lu\n", pConfig->UriConfig.MaxCacheUriCount );
|
|
DbgPrint( " MaxCacheMegabyteCount = %lu\n", pConfig->UriConfig.MaxCacheMegabyteCount );
|
|
DbgPrint( " ScavengerPeriod = %lu\n", pConfig->UriConfig.ScavengerPeriod );
|
|
DbgPrint( " HashTableBits = %ld\n", pConfig->UriConfig.HashTableBits);
|
|
DbgPrint( " MaxUriBytes = %lu\n", pConfig->UriConfig.MaxUriBytes );
|
|
DbgPrint( " ScavengerTrimMB = %ld\n", g_UlScavengerTrimMB);
|
|
#endif // DBG
|
|
|
|
//
|
|
// Cleanup.
|
|
//
|
|
|
|
ZwClose( parametersHandle );
|
|
|
|
} // UlpReadRegistry
|
|
|
|
|
|
/***************************************************************************++
|
|
|
|
Routine Description:
|
|
|
|
Unload routine called by the IO subsystem when UL is getting
|
|
unloaded.
|
|
|
|
--***************************************************************************/
|
|
VOID
|
|
UlpUnload(
|
|
IN PDRIVER_OBJECT DriverObject
|
|
)
|
|
{
|
|
UNREFERENCED_PARAMETER(DriverObject);
|
|
|
|
//
|
|
// Sanity check.
|
|
//
|
|
|
|
PAGED_CODE();
|
|
UL_ENTER_DRIVER("http!UlpUnload", NULL);
|
|
|
|
#if DBG
|
|
KdPrint(( "UlpUnload called.\n" ));
|
|
#endif // DBG
|
|
|
|
//
|
|
// Terminate the UL modules.
|
|
//
|
|
|
|
UlpTerminateModules();
|
|
|
|
//
|
|
// Flush all kernel DPCs to ensure our periodic timer DPCs cannot
|
|
// get called after we unload.
|
|
//
|
|
|
|
KeFlushQueuedDpcs();
|
|
|
|
UL_LEAVE_DRIVER("UlpUnload");
|
|
|
|
#if DBG
|
|
//
|
|
// Terminate any debug-specific data after UL_LEAVE_DRIVER
|
|
//
|
|
|
|
UlDbgTerminateDebugData( );
|
|
#endif // DBG
|
|
|
|
#if DBG
|
|
KdPrint(( "\n"
|
|
"------\n"
|
|
"http!UlpUnload finished.\n"
|
|
"------\n" ));
|
|
#endif // DBG
|
|
|
|
} // UlpUnload
|
|
|
|
|
|
/***************************************************************************++
|
|
|
|
Routine Description:
|
|
|
|
Terminates the various UL modules in the correct order.
|
|
|
|
--***************************************************************************/
|
|
VOID
|
|
UlpTerminateModules(
|
|
VOID
|
|
)
|
|
{
|
|
//
|
|
// Sanity check.
|
|
//
|
|
|
|
PAGED_CODE();
|
|
|
|
//
|
|
// Wait for endpoints to go away, so we're sure all I/O is done.
|
|
//
|
|
|
|
UlWaitForEndpointDrain();
|
|
|
|
//
|
|
// Kill Michael.
|
|
//
|
|
|
|
UlTerminateDateCache();
|
|
UlTerminateUriCache();
|
|
UlTerminateFilterChannel();
|
|
|
|
//
|
|
// Kill Henry.
|
|
//
|
|
|
|
TerminateFileCache();
|
|
|
|
//
|
|
// Kill Paul.
|
|
//
|
|
|
|
UlTerminateCG();
|
|
UlTerminateAP();
|
|
|
|
//
|
|
// Kill Keith.
|
|
//
|
|
|
|
UlTerminateControlChannel();
|
|
|
|
//
|
|
// TerminateLogs Blocks until all Io To Be Complete
|
|
//
|
|
// Note:CG should be terminated before Logs.
|
|
// Otherwise we won't stop issuing the buffer writes.
|
|
// ThreadPool should be terminated after Logs.
|
|
// Otherwise our Completion APCs won't be completed back.
|
|
//
|
|
|
|
//
|
|
// Kill ETW Logging
|
|
//
|
|
UlEtwUnRegisterLog( g_pUlControlDeviceObject );
|
|
|
|
//
|
|
// Kill Ali
|
|
//
|
|
|
|
UlTerminateLogs();
|
|
UlTerminateBinaryLog();
|
|
UlTerminateErrorLog();
|
|
UlTerminateLogUtil();
|
|
UlTcTerminate();
|
|
UlTerminateHttpConnection();
|
|
|
|
//
|
|
// Kill Eric.
|
|
//
|
|
|
|
UlTerminateCounters();
|
|
UlTerminateTimeoutMonitor();
|
|
|
|
//
|
|
// Kill George.
|
|
//
|
|
|
|
UlLargeMemTerminate();
|
|
|
|
//
|
|
// Kill TDI.
|
|
//
|
|
|
|
UxTerminateTdi();
|
|
UlTerminateTdi();
|
|
|
|
//
|
|
// Kill the thread pool.
|
|
//
|
|
|
|
UlTerminateThreadPool();
|
|
|
|
|
|
//
|
|
// Kill the opaque Ids
|
|
//
|
|
|
|
UlTerminateOpaqueIdTable();
|
|
|
|
|
|
//
|
|
// Kill any global data.
|
|
//
|
|
|
|
UlTerminateData();
|
|
|
|
//
|
|
// Kill Listen-Only address list
|
|
//
|
|
|
|
if ( g_pTdiListenAddresses )
|
|
{
|
|
ASSERT( 0 != g_TdiListenAddrCount );
|
|
UlFreeUlAddr( g_pTdiListenAddresses );
|
|
}
|
|
|
|
//
|
|
// Kill namespace.
|
|
//
|
|
|
|
UlTerminateNamespace();
|
|
|
|
//
|
|
// Kill Client.
|
|
//
|
|
|
|
if (g_ClientImageHandle)
|
|
{
|
|
//
|
|
// g_ClientImageHandle != NULL <=> client code was initialized.
|
|
// Call client terminate functions now.
|
|
//
|
|
|
|
g_ClientImageHandle = NULL;
|
|
|
|
UcTerminateServerInformation();
|
|
UcTerminateClientConnections();
|
|
|
|
UcTerminateHttpRequests();
|
|
}
|
|
|
|
//
|
|
// Delete our device objects.
|
|
//
|
|
|
|
if (g_pUlAppPoolDeviceObject != NULL)
|
|
{
|
|
IoDeleteDevice( g_pUlAppPoolDeviceObject );
|
|
}
|
|
|
|
if (g_pUlFilterDeviceObject != NULL)
|
|
{
|
|
IoDeleteDevice( g_pUlFilterDeviceObject );
|
|
}
|
|
|
|
if (g_pUlControlDeviceObject != NULL)
|
|
{
|
|
IoDeleteDevice( g_pUlControlDeviceObject );
|
|
}
|
|
|
|
if (g_pUcServerDeviceObject != NULL)
|
|
{
|
|
IoDeleteDevice( g_pUcServerDeviceObject );
|
|
}
|
|
|
|
//
|
|
// Delete the directory container.
|
|
//
|
|
|
|
if (g_UlDirectoryObject != NULL)
|
|
{
|
|
ZwClose( g_UlDirectoryObject );
|
|
}
|
|
|
|
//
|
|
// Delete the global trace logs.
|
|
//
|
|
|
|
DESTROY_REF_TRACE_LOG( g_pEndpointUsageTraceLog, UL_REF_TRACE_LOG_POOL_TAG );
|
|
DESTROY_REF_TRACE_LOG( g_pTdiTraceLog, UL_REF_TRACE_LOG_POOL_TAG );
|
|
DESTROY_REF_TRACE_LOG( g_pHttpRequestTraceLog, UL_REF_TRACE_LOG_POOL_TAG );
|
|
DESTROY_REF_TRACE_LOG( g_pHttpConnectionTraceLog, UL_REF_TRACE_LOG_POOL_TAG );
|
|
DESTROY_REF_TRACE_LOG( g_pHttpResponseTraceLog, UL_REF_TRACE_LOG_POOL_TAG );
|
|
DESTROY_REF_TRACE_LOG( g_pAppPoolTraceLog, UL_REF_TRACE_LOG_POOL_TAG );
|
|
DESTROY_REF_TRACE_LOG( g_pAppPoolProcessTraceLog, UL_REF_TRACE_LOG_POOL_TAG );
|
|
DESTROY_REF_TRACE_LOG( g_pConfigGroupTraceLog, UL_REF_TRACE_LOG_POOL_TAG );
|
|
DESTROY_REF_TRACE_LOG( g_pControlChannelTraceLog, UL_REF_TRACE_LOG_POOL_TAG );
|
|
DESTROY_REF_TRACE_LOG( g_pThreadTraceLog, UL_REF_TRACE_LOG_POOL_TAG );
|
|
DESTROY_REF_TRACE_LOG( g_pMdlTraceLog, UL_REF_TRACE_LOG_POOL_TAG );
|
|
DESTROY_REF_TRACE_LOG( g_pFilterTraceLog, UL_REF_TRACE_LOG_POOL_TAG );
|
|
DESTROY_REF_TRACE_LOG( g_pUriTraceLog, UL_REF_TRACE_LOG_POOL_TAG );
|
|
DESTROY_IRP_TRACE_LOG( g_pIrpTraceLog );
|
|
DESTROY_TIME_TRACE_LOG( g_pTimeTraceLog );
|
|
DESTROY_APP_POOL_TIME_TRACE_LOG( g_pAppPoolTimeTraceLog );
|
|
DESTROY_REF_TRACE_LOG( g_pSiteCounterTraceLog, UL_REF_TRACE_LOG_POOL_TAG );
|
|
DESTROY_REF_TRACE_LOG( g_pConnectionCountTraceLog, UL_REF_TRACE_LOG_POOL_TAG );
|
|
DESTROY_REF_TRACE_LOG( g_pConfigGroupInfoTraceLog, UL_REF_TRACE_LOG_POOL_TAG );
|
|
DESTROY_REF_TRACE_LOG( g_pChunkTrackerTraceLog, UL_REF_TRACE_LOG_POOL_TAG );
|
|
DESTROY_REF_TRACE_LOG( g_pWorkItemTraceLog, UL_REF_TRACE_LOG_POOL_TAG );
|
|
DESTROY_REF_TRACE_LOG( g_pPoolAllocTraceLog, UL_REF_TRACE_LOG_POOL_TAG );
|
|
DESTROY_REF_TRACE_LOG( g_pMondoGlobalTraceLog, UL_REF_TRACE_LOG_POOL_TAG );
|
|
|
|
DESTROY_STRING_LOG( g_pGlobalStringLog );
|
|
|
|
DESTROY_UC_TRACE_LOG( g_pUcTraceLog);
|
|
|
|
} // UlpTerminateModules
|