1209 lines
24 KiB
C
1209 lines
24 KiB
C
/*++
|
||
|
||
Copyright (c) 1997-2001 Microsoft Corporation
|
||
|
||
Module Name:
|
||
|
||
dnsrslvr.c
|
||
|
||
Abstract:
|
||
|
||
DNS Resolver Service
|
||
|
||
Main service module.
|
||
|
||
Author:
|
||
|
||
Glenn Curtis (glennc) 25-Feb-1997
|
||
|
||
Revision History:
|
||
|
||
Jim Gilroy (jamesg) March 2000 cleanup
|
||
Jim Gilroy (jamesg) Nov 2000 rewrite
|
||
|
||
--*/
|
||
|
||
|
||
#include "local.h"
|
||
|
||
#ifdef BUILD_W2K
|
||
#include <services.h>
|
||
#else
|
||
#include <svcs.h>
|
||
#endif
|
||
|
||
|
||
//
|
||
// Service control
|
||
//
|
||
|
||
SERVICE_STATUS ServiceStatus;
|
||
SERVICE_STATUS_HANDLE ServiceStatusHandle = (SERVICE_STATUS_HANDLE) 0;
|
||
|
||
#ifdef BUILD_W2K
|
||
PSVCS_GLOBAL_DATA g_pSvchostData;
|
||
#else
|
||
PSVCHOST_GLOBAL_DATA g_pSvchostData;
|
||
#endif
|
||
|
||
|
||
HANDLE g_hStopEvent;
|
||
BOOL g_StopFlag;
|
||
|
||
BOOL g_fServiceControlHandled;
|
||
|
||
//
|
||
// Service state
|
||
//
|
||
|
||
#define RES_STATUS_BEGIN 0x0cc00000
|
||
#define RES_STATUS_ZERO_INIT 0x0cc00001
|
||
#define RES_STATUS_CREATED_CS 0x0cc00002
|
||
#define RES_STATUS_CREATED_EVENT 0x0cc00003
|
||
#define RES_STATUS_READ_REGISTRY 0x0cc00004
|
||
#define RES_STATUS_ALLOC_CACHE 0x0cc00005
|
||
#define RES_STATUS_START_NOTIFY 0x0cc00006
|
||
#define RES_STATUS_START_IP_LIST 0x0cc00007
|
||
#define RES_STATUS_START_RPC 0x0cc00008
|
||
#define RES_STATUS_REG_CONTROL 0x0cc00009
|
||
#define RES_STATUS_RUNNING 0x0cc00100
|
||
|
||
#define RES_STATUS_STOPPING 0x0cc00300
|
||
#define RES_STATUS_SIGNALED_STOP 0x0cc00301
|
||
#define RES_STATUS_STOP_RPC 0x0cc00302
|
||
#define RES_STATUS_STOP_NOTIFY 0x0cc00303
|
||
#define RES_STATUS_STOP_IP_LIST 0x0cc00304
|
||
#define RES_STATUS_FREE_CACHE 0x0cc00305
|
||
#define RES_STATUS_FREE_NET_INFO 0x0cc00306
|
||
#define RES_STATUS_FREE_IP_LIST 0x0cc00307
|
||
#define RES_STATUS_FREE_SERVICE_NOTIFY 0x0cc00308
|
||
#define RES_STATUS_DEL_EVENT 0x0cc00309
|
||
#define RES_STATUS_DEL_CS 0x0cc00310
|
||
#define RES_STATUS_END 0x0cc00400
|
||
|
||
DWORD g_ResolverStatus = RES_STATUS_BEGIN;
|
||
|
||
//
|
||
// Initialization cleanup\state
|
||
//
|
||
// Track what we intialized for safer\faster cleanup
|
||
//
|
||
|
||
#define INITFLAG_CS_CREATED 0x00000001
|
||
#define INITFLAG_WINSOCK 0x00000002
|
||
#define INITFLAG_EVENTS_CREATED 0x00000004
|
||
#define INITFLAG_CACHE_CREATED 0x00000008
|
||
#define INITFLAG_NOTIFY_STARTED 0x00000010
|
||
#define INITFLAG_IP_LIST_CREATED 0x00000020
|
||
#define INITFLAG_RPC_SERVER_STARTED 0x00000100
|
||
|
||
DWORD g_InitState;
|
||
|
||
|
||
//
|
||
// Critical sections used
|
||
//
|
||
|
||
CRITICAL_SECTION CacheCritSec;
|
||
CRITICAL_SECTION NetworkListCritSec;
|
||
CRITICAL_SECTION NetworkFailureCritSec;
|
||
|
||
|
||
//
|
||
// Logging control
|
||
//
|
||
|
||
BOOL g_LogTraceInfo = TRUE;
|
||
|
||
|
||
//
|
||
// Private protos
|
||
//
|
||
|
||
DWORD
|
||
ResolverInitialize(
|
||
VOID
|
||
);
|
||
|
||
VOID
|
||
ResolverShutdown(
|
||
IN DWORD ErrorCode
|
||
);
|
||
|
||
VOID
|
||
ResolverControlHandler(
|
||
IN DWORD Opcode
|
||
);
|
||
|
||
DWORD
|
||
ResolverUpdateStatus(
|
||
VOID
|
||
);
|
||
|
||
|
||
//
|
||
// Service routines
|
||
//
|
||
|
||
//
|
||
// NT5 version -- inside services.exe
|
||
//
|
||
|
||
#ifdef BUILD_W2K
|
||
|
||
VOID
|
||
SVCS_ENTRY_POINT(
|
||
DWORD NumArgs,
|
||
LPTSTR * ArgsArray,
|
||
PSVCS_GLOBAL_DATA pSvcsGlobalData,
|
||
HANDLE SvcRefHandle
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Main main entry point of resolver service
|
||
|
||
Arguments:
|
||
|
||
NumArgs - number of arguments to service start call
|
||
|
||
ArgsArray - array of ptrs to arguments in service start call
|
||
|
||
Return Value:
|
||
|
||
None
|
||
|
||
--*/
|
||
{
|
||
//
|
||
// save pointer to service data block
|
||
//
|
||
|
||
g_pSvchostData = pSvcsGlobalData;
|
||
|
||
ResolverInitialize();
|
||
}
|
||
|
||
|
||
#else
|
||
//
|
||
// Whistler+ version -- in svchost.exe process
|
||
//
|
||
|
||
VOID
|
||
SvchostPushServiceGlobals(
|
||
PSVCHOST_GLOBAL_DATA pGlobals
|
||
)
|
||
{
|
||
g_pSvchostData = pGlobals;
|
||
}
|
||
|
||
|
||
VOID
|
||
ServiceMain(
|
||
IN DWORD NumArgs,
|
||
IN LPTSTR * ArgsArray
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Main entry point of resolver service.
|
||
|
||
Arguments:
|
||
|
||
NumArgs - number of strings specified in ArgsArray.
|
||
|
||
ArgsArray - array of ptrs to arguments in service start call
|
||
|
||
Return Value:
|
||
|
||
None
|
||
|
||
--*/
|
||
{
|
||
//
|
||
// Make sure svchost.exe gave us global data
|
||
//
|
||
|
||
ASSERT( g_pSvchostData != NULL );
|
||
|
||
//
|
||
// Startup service, then exit
|
||
//
|
||
|
||
ResolverInitialize();
|
||
}
|
||
|
||
#endif // NT4 \ Whistler+ switch
|
||
|
||
|
||
|
||
VOID
|
||
ResolverInitFailure(
|
||
IN DNS_STATUS Status,
|
||
IN DWORD EventId,
|
||
IN DWORD MemEventId,
|
||
IN PSTR pszDebugString
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Handle resolver init failure.
|
||
|
||
Function exists to avoid duplicate code.
|
||
|
||
Arguments:
|
||
|
||
Return Value:
|
||
|
||
None
|
||
|
||
--*/
|
||
{
|
||
WCHAR numberString[16];
|
||
PWSTR eventStrings[1];
|
||
|
||
DNSLOG_TIME();
|
||
DNSLOG_F1( "Resolver Init Failure" );
|
||
DNSLOG_F2( " Failure = %s", pszDebugString );
|
||
DNSLOG_F2( " Status = %d", Status );
|
||
DNSLOG_F1( "" );
|
||
|
||
DNSDBG( ANY, (
|
||
"Resolver Init FAILED!\n"
|
||
"\tname = %s\n"
|
||
"\tstatus = %d\n"
|
||
"\tevent id = %d\n"
|
||
"\tmem event = %08x\n",
|
||
pszDebugString,
|
||
Status,
|
||
EventId,
|
||
MemEventId ));
|
||
|
||
DnsDbg_PrintfToDebugger(
|
||
"ResolverInitialize - Returning status %d 0x%08x\n"
|
||
"\tname = %s\n",
|
||
Status, Status,
|
||
pszDebugString );
|
||
|
||
//
|
||
// log in memory event
|
||
//
|
||
|
||
LogEventInMemory( MemEventId, Status );
|
||
|
||
//
|
||
// log event
|
||
// - convert status to string
|
||
//
|
||
|
||
wsprintfW( numberString, L"0x%.8X", Status );
|
||
eventStrings[0] = numberString;
|
||
|
||
ResolverLogEvent(
|
||
EventId,
|
||
EVENTLOG_ERROR_TYPE,
|
||
1,
|
||
eventStrings,
|
||
Status );
|
||
|
||
// clean up
|
||
|
||
ResolverShutdown( Status );
|
||
}
|
||
|
||
|
||
|
||
DWORD
|
||
ResolverInitialize(
|
||
VOID
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This function initializes the DNS Caching Resolver service.
|
||
|
||
Arguments:
|
||
|
||
InitState - Returns a flag to indicate how far we got with
|
||
initializing the service before an error occurred.
|
||
|
||
Return Value:
|
||
|
||
ERROR_SUCCESS if successful.
|
||
ErrorCode on failure.
|
||
|
||
--*/
|
||
{
|
||
DNS_STATUS status = NO_ERROR;
|
||
|
||
//
|
||
// init service state
|
||
//
|
||
|
||
g_ResolverStatus = RES_STATUS_BEGIN;
|
||
g_InitState = 0;
|
||
g_StopFlag = FALSE;
|
||
g_hStopEvent = NULL;
|
||
g_fServiceControlHandled = FALSE;
|
||
|
||
//
|
||
// initialize logging
|
||
//
|
||
|
||
DNSLOG_INIT();
|
||
DNSLOG_F1( "DNS Caching Resolver Service - ResolverInitialize" );
|
||
|
||
#if DBG
|
||
#if 0
|
||
Dns_StartDebug(
|
||
0,
|
||
"dnsres.flag",
|
||
NULL,
|
||
"dnsres.log",
|
||
0 );
|
||
#endif
|
||
Dns_StartDebugEx(
|
||
0, // no flag value
|
||
"dnsres.flag",
|
||
NULL, // no external flag
|
||
"dnsres.log",
|
||
0, // no wrap limit
|
||
FALSE, // don't use existing global
|
||
FALSE,
|
||
TRUE // make this file global
|
||
);
|
||
#endif
|
||
|
||
DNSDBG( INIT, ( "DNS resolver startup.\n" ));
|
||
IF_DNSDBG( START_BREAK )
|
||
{
|
||
// since resolver moved to NetworkServices permissions do
|
||
// not properly bring up ntsd; instead just give time
|
||
// to attach debugger
|
||
|
||
Sleep( 20000 );
|
||
}
|
||
|
||
//
|
||
// initialize service status block
|
||
//
|
||
|
||
ServiceStatusHandle = (SERVICE_STATUS_HANDLE) 0;
|
||
|
||
ServiceStatus.dwServiceType = SERVICE_WIN32_SHARE_PROCESS;
|
||
ServiceStatus.dwCurrentState = SERVICE_START_PENDING;
|
||
ServiceStatus.dwControlsAccepted = 0;
|
||
ServiceStatus.dwCheckPoint = 0;
|
||
ServiceStatus.dwWaitHint = 5000;
|
||
ServiceStatus.dwWin32ExitCode = NO_ERROR;
|
||
ServiceStatus.dwServiceSpecificExitCode = 0;
|
||
|
||
ResolverUpdateStatus();
|
||
|
||
//
|
||
// init globals to zero
|
||
//
|
||
|
||
ZeroInitIpListGlobals();
|
||
ZeroNetworkConfigGlobals();
|
||
g_ResolverStatus = RES_STATUS_ZERO_INIT;
|
||
|
||
//
|
||
// initialize all our critical sections as soon as we can
|
||
//
|
||
|
||
LogEventInMemory( RES_EVENT_INITCRIT_START, 0 );
|
||
InitializeCriticalSection( & CacheCritSec );
|
||
InitializeCriticalSection( & NetworkListCritSec );
|
||
InitializeCriticalSection( & NetworkFailureCritSec );
|
||
LogEventInMemory( RES_EVENT_INITCRIT_END,0 );
|
||
|
||
//
|
||
// init our dnslib heap to use dnsapi heap
|
||
//
|
||
// this is important because we currently mix and match records
|
||
// created inside dnsapi (hosts file and query) with a few that
|
||
// we roll on our own; need this to be common
|
||
//
|
||
|
||
Dns_LibHeapReset( DnsApiAlloc, DnsApiRealloc, DnsApiFree );
|
||
|
||
//
|
||
// init winsock
|
||
//
|
||
|
||
Dns_InitializeWinsock();
|
||
g_InitState |= INITFLAG_WINSOCK;
|
||
|
||
//
|
||
// shutdown event
|
||
//
|
||
|
||
g_hStopEvent = CreateEvent(
|
||
NULL, // no security descriptor
|
||
TRUE, // do not use automatic reset
|
||
FALSE, // initial state: not signalled
|
||
NULL // no name
|
||
);
|
||
if ( !g_hStopEvent )
|
||
{
|
||
status = GetLastError();
|
||
|
||
ResolverInitFailure(
|
||
status,
|
||
0,
|
||
0,
|
||
"CreateEvent() failed" );
|
||
return status;
|
||
}
|
||
g_InitState |= INITFLAG_EVENTS_CREATED;
|
||
g_ResolverStatus = RES_STATUS_CREATED_EVENT;
|
||
|
||
ResolverUpdateStatus();
|
||
|
||
//
|
||
// initialize our global registry values
|
||
// - force this just once on startup so we have the
|
||
// relevant cache params; after that read only on
|
||
// demand when building netinfo blobs
|
||
|
||
ReadRegistryConfig();
|
||
|
||
//
|
||
// Set the query timeouts to be used from defaults or registry
|
||
//
|
||
|
||
Dns_InitQueryTimeouts();
|
||
|
||
//
|
||
// init socket caching
|
||
// - improves perf and prevents socket DOS attack
|
||
// - default cache to 10 sockets
|
||
//
|
||
// DCR: create global for socket caching
|
||
//
|
||
|
||
Dns_CacheSocketInit( 10 );
|
||
|
||
#if 0
|
||
//
|
||
// start cache on demand now
|
||
//
|
||
|
||
//
|
||
// initialize cache
|
||
//
|
||
|
||
status = Cache_Initialize();
|
||
|
||
LogEventInMemory( RES_EVENT_INITCACHE, status );
|
||
|
||
if ( status != NO_ERROR )
|
||
{
|
||
ResolverInitFailure(
|
||
status,
|
||
EVENT_DNS_CACHE_START_FAILURE_NO_CONTROL,
|
||
0,
|
||
"Cache_Initialize() failed" );
|
||
return status;
|
||
}
|
||
g_InitState |= INITFLAG_CACHE_CREATED;
|
||
g_ResolverStatus = RES_STATUS_ALLOC_CACHE;
|
||
ResolverUpdateStatus();
|
||
#endif
|
||
|
||
//
|
||
// notification thread (host file and registry)
|
||
//
|
||
|
||
StartNotify();
|
||
g_InitState |= INITFLAG_NOTIFY_STARTED;
|
||
g_ResolverStatus = RES_STATUS_START_NOTIFY;
|
||
ResolverUpdateStatus();
|
||
|
||
//
|
||
// IP notification thread
|
||
//
|
||
|
||
status = InitIpListAndNotification();
|
||
if ( status != ERROR_SUCCESS )
|
||
{
|
||
ResolverInitFailure(
|
||
status,
|
||
0,
|
||
0,
|
||
"IP list init failed" );
|
||
return status;
|
||
}
|
||
g_InitState |= INITFLAG_IP_LIST_CREATED;
|
||
g_ResolverStatus = RES_STATUS_START_IP_LIST;
|
||
ResolverUpdateStatus();
|
||
|
||
//
|
||
// register control handler
|
||
// allows us to receive service requests
|
||
//
|
||
|
||
ServiceStatusHandle = RegisterServiceCtrlHandlerW(
|
||
DNS_RESOLVER_SERVICE,
|
||
ResolverControlHandler
|
||
);
|
||
if ( !ServiceStatusHandle )
|
||
{
|
||
status = GetLastError();
|
||
ResolverInitFailure(
|
||
status,
|
||
EVENT_DNS_CACHE_START_FAILURE_LOW_MEMORY,
|
||
RES_EVENT_REGISTER_SCH,
|
||
"Call to RegisterServiceCtrlHandlerW failed!"
|
||
);
|
||
return status;
|
||
}
|
||
g_ResolverStatus = RES_STATUS_REG_CONTROL;
|
||
ResolverUpdateStatus();
|
||
|
||
//
|
||
// initialize RPC interfaces
|
||
// - bump our requested stack size up to 8K
|
||
// (RPC uses 1800 bytes before we get the stack,
|
||
// the new() operator followed by the heap code uses
|
||
// another 1200 -- leaving only about a 1000 for
|
||
// DNS)
|
||
//
|
||
|
||
LogEventInMemory( RES_EVENT_STARTRPC, 0 );
|
||
|
||
#if 0
|
||
// should not be necessary
|
||
// default for all svchost instances has been increased
|
||
if ( status != NO_ERROR )
|
||
{
|
||
DNSDBG( ANY, (
|
||
"RpcMgmtSetServerStackSize( 2000 ) = %d\n",
|
||
status ));
|
||
}
|
||
#endif
|
||
|
||
status = Rpc_Initialize();
|
||
#if 0
|
||
status = g_pSvchostData->StartRpcServer(
|
||
SERVER_INTERFACE_NAME_W,
|
||
DnsResolver_ServerIfHandle );
|
||
#endif
|
||
if ( status != NO_ERROR )
|
||
{
|
||
LogEventInMemory( RES_EVENT_STATUS, status );
|
||
|
||
if ( status == RPC_S_TYPE_ALREADY_REGISTERED ||
|
||
status == RPC_NT_TYPE_ALREADY_REGISTERED )
|
||
{
|
||
DNSLOG_TIME();
|
||
DNSLOG_F1( " Call to StartRpcServer returned warning that" );
|
||
DNSLOG_F1( " the service is already running!" );
|
||
DNSLOG_F2( " RpcPipeName : %S", RESOLVER_INTERFACE_NAME_W );
|
||
DNSLOG_F1( " Going to just continue running . . ." );
|
||
DNSLOG_F1( "" );
|
||
|
||
DnsDbg_PrintfToDebugger(
|
||
"DNS Client (dnsrslvr.dll) - Call to StartRpcServer\n"
|
||
"returned warning that the service is already running!\n"
|
||
"RpcPipeName : %S"
|
||
"Going to just continue running . . .\n",
|
||
RESOLVER_INTERFACE_NAME_W );
|
||
|
||
status = NO_ERROR;
|
||
}
|
||
else
|
||
{
|
||
DNSDBG( ANY, (
|
||
"RPC init FAILED! status = %d\n"
|
||
"\tpipe name = %s\n",
|
||
status,
|
||
RESOLVER_INTERFACE_NAME_W ));
|
||
|
||
ResolverInitFailure(
|
||
status,
|
||
EVENT_DNS_CACHE_START_FAILURE_NO_RPC,
|
||
0,
|
||
"Call to StartRpcServer failed!"
|
||
);
|
||
return status;
|
||
}
|
||
}
|
||
|
||
g_ResolverStatus = RES_STATUS_START_RPC;
|
||
g_InitState |= INITFLAG_RPC_SERVER_STARTED;
|
||
|
||
//
|
||
// successful startup
|
||
// - indicate running
|
||
// - indicate what service control messages we want to get
|
||
//
|
||
|
||
ServiceStatus.dwCurrentState = SERVICE_RUNNING;
|
||
ServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP |
|
||
SERVICE_ACCEPT_PARAMCHANGE |
|
||
SERVICE_ACCEPT_NETBINDCHANGE;
|
||
ServiceStatus.dwWaitHint = 0;
|
||
ServiceStatus.dwWin32ExitCode = NO_ERROR;
|
||
|
||
ResolverUpdateStatus();
|
||
|
||
g_ResolverStatus = RES_STATUS_RUNNING;
|
||
|
||
DNSLOG_F1( "ResolverInitialize - Successful" );
|
||
DNSLOG_F1( "" );
|
||
return NO_ERROR;
|
||
}
|
||
|
||
|
||
|
||
VOID
|
||
ResolverShutdown(
|
||
IN DWORD ErrorCode
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This function shuts down the DNS cache service.
|
||
|
||
Arguments:
|
||
|
||
ErrorCode - Supplies the error code of the failure
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
{
|
||
DWORD status = NO_ERROR;
|
||
LONG existingStopFlag;
|
||
|
||
DNSLOG_TIME();
|
||
DNSLOG_F1( "DNS Caching Resolver Service - ResolverShutdown" );
|
||
DnsDbg_PrintfToDebugger( "DNS Client - ResolverShutdown!\n" );
|
||
|
||
//
|
||
// indicate shutdown
|
||
// - but interlock to avoid dual shutdown
|
||
//
|
||
|
||
existingStopFlag = InterlockedExchange(
|
||
&g_StopFlag,
|
||
(LONG) TRUE );
|
||
if ( existingStopFlag )
|
||
{
|
||
DNS_ASSERT( FALSE );
|
||
return;
|
||
}
|
||
DNS_ASSERT( g_StopFlag );
|
||
|
||
//
|
||
// indicate stop in progress
|
||
//
|
||
|
||
ServiceStatus.dwCurrentState = SERVICE_STOP_PENDING;
|
||
ServiceStatus.dwCheckPoint = 1;
|
||
ServiceStatus.dwWaitHint = 60000;
|
||
ResolverUpdateStatus();
|
||
|
||
g_ResolverStatus = RES_STATUS_STOPPING;
|
||
|
||
//
|
||
// wakeup threads to shut down
|
||
//
|
||
|
||
g_StopFlag = TRUE;
|
||
if ( g_hStopEvent )
|
||
{
|
||
if ( !SetEvent(g_hStopEvent) )
|
||
{
|
||
DnsDbg_PrintfToDebugger(
|
||
"DNSCACHE: Error setting g_hStopEvent %lu\n",
|
||
GetLastError());
|
||
DNS_ASSERT( FALSE );
|
||
}
|
||
}
|
||
g_ResolverStatus = RES_STATUS_SIGNALED_STOP;
|
||
|
||
//
|
||
// cleanup RPC
|
||
//
|
||
|
||
if ( g_InitState & INITFLAG_RPC_SERVER_STARTED )
|
||
{
|
||
LogEventInMemory( RES_EVENT_STOPRPC, 0 );
|
||
|
||
Rpc_Shutdown();
|
||
#if 0
|
||
//status = g_pSvchostData->StopRpcServer( DnsResolver_ServerIfHandle );
|
||
#endif
|
||
LogEventInMemory( RES_EVENT_STATUS, status );
|
||
}
|
||
g_ResolverStatus = RES_STATUS_STOP_RPC;
|
||
|
||
//
|
||
// re-signal stop within lock
|
||
//
|
||
|
||
LOCK_CACHE_NO_START();
|
||
g_StopFlag = TRUE;
|
||
if ( g_hStopEvent )
|
||
{
|
||
if ( !SetEvent(g_hStopEvent) )
|
||
{
|
||
DnsDbg_PrintfToDebugger(
|
||
"DNSCACHE: Error setting g_hStopEvent %lu\n",
|
||
GetLastError());
|
||
DNS_ASSERT( FALSE );
|
||
}
|
||
}
|
||
UNLOCK_CACHE();
|
||
|
||
//
|
||
// stop notify thread
|
||
//
|
||
|
||
if ( g_InitState & INITFLAG_NOTIFY_STARTED )
|
||
{
|
||
ShutdownNotify();
|
||
}
|
||
g_ResolverStatus = RES_STATUS_STOP_NOTIFY;
|
||
|
||
//
|
||
// stop IP notify thread
|
||
//
|
||
|
||
if ( g_InitState & INITFLAG_IP_LIST_CREATED )
|
||
{
|
||
ShutdownIpListAndNotify();
|
||
}
|
||
g_ResolverStatus = RES_STATUS_STOP_IP_LIST;
|
||
|
||
//
|
||
// cleanup cache
|
||
//
|
||
|
||
Cache_Shutdown();
|
||
g_ResolverStatus = RES_STATUS_FREE_CACHE;
|
||
|
||
//
|
||
// cleanup service notification list
|
||
//
|
||
|
||
//CleanupServiceNotification();
|
||
//g_ResolverStatus = RES_STATUS_FREE_SERVICE_NOTIFY;
|
||
|
||
//
|
||
// cleanup network info globals
|
||
//
|
||
|
||
CleanupNetworkInfo();
|
||
g_ResolverStatus = RES_STATUS_FREE_NET_INFO;
|
||
|
||
//
|
||
// cleanup winsock
|
||
// cleanup socket caching also
|
||
// - this is irrelevant for other services running in
|
||
// our process so we shouldn't leave the handles open
|
||
//
|
||
|
||
if ( g_InitState & INITFLAG_WINSOCK )
|
||
{
|
||
Dns_CacheSocketCleanup();
|
||
Dns_CleanupWinsock();
|
||
}
|
||
|
||
//
|
||
// cleanup main shutdown event
|
||
//
|
||
|
||
if ( g_InitState & INITFLAG_EVENTS_CREATED )
|
||
{
|
||
if ( g_hStopEvent )
|
||
{
|
||
CloseHandle(g_hStopEvent);
|
||
g_hStopEvent = NULL;
|
||
}
|
||
}
|
||
g_ResolverStatus = RES_STATUS_DEL_EVENT;
|
||
|
||
//
|
||
// delete critical sections
|
||
//
|
||
|
||
if ( g_InitState & INITFLAG_CS_CREATED )
|
||
{
|
||
LogEventInMemory( RES_EVENT_DELCRIT_START, 0 );
|
||
DeleteCriticalSection( &CacheCritSec );
|
||
DeleteCriticalSection( &NetworkListCritSec );
|
||
DeleteCriticalSection( &NetworkFailureCritSec );
|
||
LogEventInMemory( RES_EVENT_DELCRIT_END, 0 );
|
||
}
|
||
g_ResolverStatus = RES_STATUS_DEL_CS;
|
||
|
||
//
|
||
// cleanup complete
|
||
// tell Service Controller that we are stopped
|
||
//
|
||
|
||
ServiceStatus.dwCurrentState = SERVICE_STOPPED;
|
||
ServiceStatus.dwControlsAccepted = 0;
|
||
ServiceStatus.dwWin32ExitCode = ErrorCode;
|
||
ServiceStatus.dwServiceSpecificExitCode = 0;
|
||
ServiceStatus.dwCheckPoint = 0;
|
||
ServiceStatus.dwWaitHint = 0;
|
||
|
||
ResolverUpdateStatus();
|
||
|
||
g_ResolverStatus = RES_STATUS_END;
|
||
|
||
DNSLOG_F1( "ResolverShutdown - Finished" );
|
||
DNSLOG_F1( "" );
|
||
}
|
||
|
||
|
||
|
||
BOOL
|
||
GetServiceControlLock(
|
||
VOID
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Get exclusive access handling service control message.
|
||
|
||
Arguments:
|
||
|
||
None
|
||
|
||
Return Value:
|
||
|
||
TRUE -- have exclusive access to handle SCM, other threads locked out
|
||
FALSE -- another thread still handling SCM
|
||
|
||
--*/
|
||
{
|
||
BOOL fresult;
|
||
|
||
//
|
||
// set handled flag, if not previously set
|
||
// if not previous set -> we have exclusive access
|
||
//
|
||
|
||
fresult = InterlockedCompareExchange(
|
||
&g_fServiceControlHandled,
|
||
(LONG) TRUE, // new value
|
||
(LONG) 0 // previous value to do exchange
|
||
);
|
||
|
||
return !fresult;
|
||
}
|
||
|
||
|
||
VOID
|
||
ReleaseServiceControlLock(
|
||
VOID
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Release service control exclusive access.
|
||
|
||
Arguments:
|
||
|
||
None
|
||
|
||
Return Value:
|
||
|
||
None
|
||
|
||
--*/
|
||
{
|
||
//
|
||
// clear handled flag
|
||
// - since GetServiceControlLock() uses CompareExchange
|
||
// we can just clear without interlock
|
||
//
|
||
|
||
DNS_ASSERT( g_fServiceControlHandled );
|
||
g_fServiceControlHandled = FALSE;
|
||
}
|
||
|
||
|
||
|
||
|
||
VOID
|
||
ResolverControlHandler(
|
||
IN DWORD Opcode
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Service control handler for DNS cache service.
|
||
|
||
Arguments:
|
||
|
||
Opcode - specifies service action
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
{
|
||
LogEventInMemory( RES_EVENT_SCH, Opcode );
|
||
|
||
DNSLOG_TIME();
|
||
DNSLOG_F2( "ResolverControlHandler - Recieved opcode %d", Opcode );
|
||
|
||
DNSDBG( ANY, (
|
||
"\n\n"
|
||
"ResolverControlHandler() Opcode = %d\n",
|
||
Opcode ));
|
||
|
||
//
|
||
// handle various service control codes
|
||
//
|
||
|
||
switch( Opcode )
|
||
{
|
||
|
||
case SERVICE_CONTROL_STOP:
|
||
|
||
ResolverShutdown( NO_ERROR );
|
||
break;
|
||
|
||
case SERVICE_CONTROL_PARAMCHANGE :
|
||
|
||
DNSLOG_F1( " Handle Paramchange" );
|
||
DNSLOG_F1( "" );
|
||
|
||
if ( !GetServiceControlLock() )
|
||
{
|
||
return;
|
||
}
|
||
|
||
//
|
||
// rebuild -- with cache flush
|
||
//
|
||
|
||
HandleConfigChange(
|
||
"SC -- ParamChange",
|
||
TRUE // flush cache
|
||
);
|
||
|
||
//
|
||
// signal other services about PnP
|
||
//
|
||
// SendServiceNotifications();
|
||
|
||
ReleaseServiceControlLock();
|
||
break;
|
||
|
||
case SERVICE_CONTROL_NETBINDENABLE:
|
||
case SERVICE_CONTROL_NETBINDDISABLE:
|
||
|
||
DNSLOG_F1( " Handle NetBindEnable\\Disable" );
|
||
DNSLOG_F1( "" );
|
||
|
||
if ( !GetServiceControlLock() )
|
||
{
|
||
return;
|
||
}
|
||
|
||
//
|
||
// rebuild -- with cache flush
|
||
//
|
||
|
||
HandleConfigChange(
|
||
"SC -- NetBind",
|
||
TRUE // flush cache
|
||
);
|
||
|
||
ReleaseServiceControlLock();
|
||
break;
|
||
|
||
case SERVICE_CONTROL_INTERROGATE:
|
||
case SERVICE_CONTROL_NETBINDADD:
|
||
case SERVICE_CONTROL_NETBINDREMOVE:
|
||
default:
|
||
|
||
DNSLOG_F1( " This is an unknown opcode, ignoring ..." );
|
||
DNSLOG_F1( "" );
|
||
break;
|
||
}
|
||
|
||
//
|
||
// update service status
|
||
//
|
||
|
||
ResolverUpdateStatus();
|
||
|
||
DNSLOG_F2( "Resolver Controll Handler (opcode = %d) -- returning", Opcode );
|
||
|
||
DNSDBG( ANY, (
|
||
"Leaving ResolverControlHandler( %d )\n\n\n",
|
||
Opcode ));
|
||
}
|
||
|
||
|
||
|
||
DWORD
|
||
ResolverUpdateStatus(
|
||
VOID
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Update service controller with current service status.
|
||
|
||
Arguments:
|
||
|
||
None.
|
||
|
||
Return Value:
|
||
|
||
Return code from SetServiceStatus.
|
||
|
||
--*/
|
||
{
|
||
DWORD status = NO_ERROR;
|
||
|
||
DNSDBG( TRACE, ( "ResolverUpdateStatus()\n" ));
|
||
|
||
//
|
||
// bump the checkpoint
|
||
// if status, set it
|
||
|
||
ServiceStatus.dwCheckPoint++;
|
||
#if 0
|
||
if ( Status )
|
||
{
|
||
ServiceStatus.dwWin32ExitCode = Status;
|
||
}
|
||
#endif
|
||
|
||
//
|
||
// DCR_FIX: this doesn't do much
|
||
// usually people write something like this that sets the service
|
||
// state AND does the update
|
||
//
|
||
// QUESTION: what's up with the LogEventInMemory?
|
||
//
|
||
|
||
if ( ServiceStatusHandle == (SERVICE_STATUS_HANDLE) 0 )
|
||
{
|
||
LogEventInMemory( RES_EVENT_UPDATE_STATUS, ERROR_INVALID_HANDLE );
|
||
return ERROR_INVALID_HANDLE;
|
||
}
|
||
|
||
LogEventInMemory( RES_EVENT_UPDATE_STATUS, ServiceStatus.dwWin32ExitCode );
|
||
|
||
if ( ! SetServiceStatus( ServiceStatusHandle, &ServiceStatus ) )
|
||
{
|
||
status = GetLastError();
|
||
}
|
||
|
||
LogEventInMemory( RES_EVENT_UPDATE_STATUS, status );
|
||
|
||
return status;
|
||
}
|
||
|
||
|
||
|
||
//
|
||
// Event logging
|
||
//
|
||
|
||
VOID
|
||
ResolverLogEvent(
|
||
IN DWORD MessageId,
|
||
IN WORD EventType,
|
||
IN DWORD StringCount,
|
||
IN PWSTR * StringArray,
|
||
IN DWORD ErrorCode
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Log to eventlog.
|
||
|
||
Arguments:
|
||
|
||
MessageId -- event message id
|
||
|
||
EventType -- event type (error, warning, info, etc.)
|
||
|
||
StringCount -- string arg count
|
||
|
||
StringArray -- imbedded strings
|
||
|
||
ErrorCode -- error code for data section of event
|
||
|
||
Return Value:
|
||
|
||
None
|
||
|
||
--*/
|
||
{
|
||
HANDLE hlog;
|
||
PVOID pdata = NULL;
|
||
|
||
//
|
||
// open resolver as event source
|
||
//
|
||
// note: we don't keep log open because events are few
|
||
//
|
||
|
||
hlog = RegisterEventSourceW(
|
||
NULL,
|
||
DNS_RESOLVER_SERVICE );
|
||
|
||
if ( hlog == NULL )
|
||
{
|
||
return;
|
||
}
|
||
|
||
if ( ErrorCode != NO_ERROR )
|
||
{
|
||
pdata = &ErrorCode;
|
||
}
|
||
|
||
//
|
||
// Write to event log
|
||
//
|
||
// DCR: should get suppression technology here
|
||
//
|
||
|
||
ReportEventW(
|
||
hlog,
|
||
EventType,
|
||
0, // event category
|
||
MessageId,
|
||
(PSID) NULL,
|
||
(WORD) StringCount,
|
||
sizeof(DWORD),
|
||
StringArray,
|
||
(PVOID) pdata );
|
||
|
||
DeregisterEventSource( hlog );
|
||
}
|
||
|
||
|
||
//
|
||
// End dnsrslvr.c
|
||
//
|