440 lines
7.7 KiB
C
440 lines
7.7 KiB
C
/*++
|
||
|
||
Copyright (c) 2000-2000 Microsoft Corporation
|
||
|
||
Module Name:
|
||
|
||
notify.c
|
||
|
||
Abstract:
|
||
|
||
DNS Resolver Service.
|
||
|
||
Notification thread
|
||
- host file changes
|
||
- registry config changes
|
||
|
||
Author:
|
||
|
||
Jim Gilroy (jamesg) November 2000
|
||
|
||
Revision History:
|
||
|
||
--*/
|
||
|
||
|
||
#include "local.h"
|
||
|
||
//
|
||
// Host file directory
|
||
//
|
||
|
||
#define HOSTS_FILE_DIRECTORY L"\\drivers\\etc"
|
||
|
||
//
|
||
// Notify globals
|
||
//
|
||
|
||
DWORD g_NotifyThreadId = 0;
|
||
HANDLE g_hNotifyThread = NULL;
|
||
|
||
HANDLE g_hHostFileChange = NULL;
|
||
HANDLE g_hRegistryChange = NULL;
|
||
|
||
|
||
|
||
|
||
HANDLE
|
||
CreateHostsFileChangeHandle(
|
||
VOID
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Create hosts file change handle.
|
||
|
||
Arguments:
|
||
|
||
None.
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
{
|
||
HANDLE changeHandle;
|
||
PWSTR psystemDirectory = NULL;
|
||
UINT len;
|
||
WCHAR hostDirectory[ MAX_PATH*2 ];
|
||
|
||
DNSDBG( INIT, ( "CreateHostsFileChangeHandle\n" ));
|
||
|
||
//
|
||
// build host file name
|
||
//
|
||
|
||
len = GetSystemDirectory( hostDirectory, MAX_PATH );
|
||
if ( !len || len>MAX_PATH )
|
||
{
|
||
DNSLOG_F1( "Error: Failed to get system directory" );
|
||
DNSLOG_F1( "NotifyThread exiting." );
|
||
return( NULL );
|
||
}
|
||
|
||
wcscat( hostDirectory, HOSTS_FILE_DIRECTORY );
|
||
|
||
//
|
||
// drop change notify on host file directory
|
||
//
|
||
|
||
changeHandle = FindFirstChangeNotification(
|
||
hostDirectory,
|
||
FALSE,
|
||
FILE_NOTIFY_CHANGE_FILE_NAME |
|
||
FILE_NOTIFY_CHANGE_LAST_WRITE );
|
||
|
||
if ( changeHandle == INVALID_HANDLE_VALUE )
|
||
{
|
||
DNSLOG_F1( "NotifyThread failed to get handle from" );
|
||
DNSLOG_F2(
|
||
"Failed to get hosts file change handle.\n"
|
||
"Error code: <0x%.8X>",
|
||
GetLastError() );
|
||
return( NULL );
|
||
}
|
||
|
||
return( changeHandle );
|
||
}
|
||
|
||
|
||
|
||
|
||
VOID
|
||
ThreadShutdownWait(
|
||
IN HANDLE hThread
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Wait on thread shutdown.
|
||
|
||
Arguments:
|
||
|
||
hThread -- thread handle that is shutting down
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
{
|
||
DWORD waitResult;
|
||
|
||
if ( !hThread )
|
||
{
|
||
return;
|
||
}
|
||
|
||
DNSDBG( ANY, (
|
||
"Waiting on shutdown of thread %d (%p)\n",
|
||
hThread, hThread ));
|
||
|
||
waitResult = WaitForSingleObject(
|
||
hThread,
|
||
10000 );
|
||
|
||
switch( waitResult )
|
||
{
|
||
case WAIT_OBJECT_0:
|
||
|
||
break;
|
||
|
||
default:
|
||
|
||
// thread didn't stop -- need to kill it
|
||
|
||
ASSERT( waitResult == WAIT_TIMEOUT );
|
||
|
||
DNSLOG_F2( "Shutdown: thread %d not stopped, terminating", hThread );
|
||
TerminateThread( hThread, 1 );
|
||
break;
|
||
}
|
||
|
||
// close thread handle
|
||
|
||
CloseHandle( hThread );
|
||
}
|
||
|
||
|
||
|
||
VOID
|
||
NotifyThread(
|
||
VOID
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Main notify thread.
|
||
|
||
Arguments:
|
||
|
||
None.
|
||
|
||
Globals:
|
||
|
||
g_hStopEvent -- waits on shutdown even
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
{
|
||
DWORD handleCount;
|
||
DWORD waitResult;
|
||
HANDLE handleArray[3];
|
||
|
||
DNSDBG( INIT, (
|
||
"\nStart NotifyThread\n" ));
|
||
|
||
//
|
||
// get file change handle
|
||
//
|
||
|
||
g_hHostFileChange = CreateHostsFileChangeHandle();
|
||
|
||
//
|
||
// wait on
|
||
// - host file change => flush+rebuild cache
|
||
// - registry change => reread config info
|
||
// - shutdown => exit
|
||
//
|
||
|
||
handleArray[0] = g_hStopEvent;
|
||
handleCount = 1;
|
||
|
||
if ( g_hHostFileChange )
|
||
{
|
||
handleArray[handleCount++] = g_hHostFileChange;
|
||
}
|
||
if ( g_hRegistryChange )
|
||
{
|
||
handleArray[handleCount++] = g_hRegistryChange;
|
||
}
|
||
|
||
if ( handleCount == 1 )
|
||
{
|
||
DNSDBG( ANY, (
|
||
"No change handles -- exit notify thread.\n" ));
|
||
goto ThreadExit;
|
||
}
|
||
|
||
|
||
while( 1 )
|
||
{
|
||
waitResult = WaitForMultipleObjects(
|
||
handleCount,
|
||
handleArray,
|
||
FALSE,
|
||
INFINITE );
|
||
|
||
switch( waitResult )
|
||
{
|
||
case WAIT_OBJECT_0:
|
||
|
||
// shutdown event
|
||
// - if stopping exit
|
||
// - do garbage collection if required
|
||
// - otherwise short wait to avoid spin if screwup
|
||
// and not get thrashed by failed garbage collection
|
||
|
||
DNSLOG_F1( "NotifyThread: Shutdown Event" );
|
||
if ( g_StopFlag )
|
||
{
|
||
goto ThreadExit;
|
||
}
|
||
else if ( g_GarbageCollectFlag )
|
||
{
|
||
Cache_GarbageCollect( 0 );
|
||
}
|
||
ELSE_ASSERT_FALSE;
|
||
|
||
Sleep( 1000 );
|
||
if ( g_StopFlag )
|
||
{
|
||
goto ThreadExit;
|
||
}
|
||
continue;
|
||
|
||
case WAIT_OBJECT_0 + 1:
|
||
|
||
// host file change -- flush cache
|
||
|
||
DNSLOG_F1( "NotifyThread: Host file change event" );
|
||
|
||
// reset notification -- BEFORE reload
|
||
|
||
if ( !FindNextChangeNotification( g_hHostFileChange ) )
|
||
{
|
||
DNSLOG_F1( "NotifyThread failed to get handle" );
|
||
DNSLOG_F1( "from FindNextChangeNotification." );
|
||
DNSLOG_F2( "Error code: <0x%.8X>", GetLastError() );
|
||
goto ThreadExit;
|
||
}
|
||
|
||
Cache_Flush();
|
||
break;
|
||
|
||
case WAIT_OBJECT_0 + 2:
|
||
|
||
// registry change notification -- flush cache and reload
|
||
|
||
DNSLOG_F1( "NotifyThread: Registry change event" );
|
||
break;
|
||
|
||
|
||
default:
|
||
|
||
ASSERT( g_StopFlag );
|
||
if ( g_StopFlag )
|
||
{
|
||
goto ThreadExit;
|
||
}
|
||
Sleep( 5000 );
|
||
continue;
|
||
}
|
||
}
|
||
|
||
ThreadExit:
|
||
|
||
DNSDBG( INIT, (
|
||
"NotifyThread exit\n" ));
|
||
DNSLOG_F1( "NotifyThread exiting." );
|
||
}
|
||
|
||
|
||
|
||
VOID
|
||
StartNotify(
|
||
VOID
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Start notify thread.
|
||
|
||
Arguments:
|
||
|
||
None.
|
||
|
||
Return Value:
|
||
|
||
ERROR_SUCCESS if successful.
|
||
ErrorCode on failure.
|
||
|
||
--*/
|
||
{
|
||
//
|
||
// clear
|
||
//
|
||
|
||
g_NotifyThreadId = 0;
|
||
g_hNotifyThread = NULL;
|
||
|
||
g_hHostFileChange = NULL;
|
||
g_hRegistryChange = NULL;
|
||
|
||
|
||
//
|
||
// host file write monitor thread
|
||
// keeps cache in sync when write made to host file
|
||
//
|
||
|
||
g_hNotifyThread = CreateThread(
|
||
NULL,
|
||
0,
|
||
(LPTHREAD_START_ROUTINE) NotifyThread,
|
||
NULL,
|
||
0,
|
||
&g_NotifyThreadId );
|
||
if ( !g_hNotifyThread )
|
||
{
|
||
DNS_STATUS status = GetLastError();
|
||
|
||
DNSLOG_F1( "ERROR: InitializeCache function failed to create" );
|
||
DNSLOG_F1( " HOSTS file monitor thread." );
|
||
DNSLOG_F2( " Error code: <0x%.8X>", status );
|
||
DNSLOG_F1( " NOTE: Resolver service will continue to run." );
|
||
|
||
DNSDBG( ANY, (
|
||
"FAILED Notify thread start!\n"
|
||
"\tstatus = %d\n",
|
||
status ));
|
||
}
|
||
}
|
||
|
||
|
||
|
||
VOID
|
||
ShutdownNotify(
|
||
VOID
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Shutdown notify thread.
|
||
|
||
Arguments:
|
||
|
||
None.
|
||
|
||
Return Value:
|
||
|
||
ERROR_SUCCESS if successful.
|
||
ErrorCode on failure.
|
||
|
||
--*/
|
||
{
|
||
DWORD waitResult;
|
||
|
||
DNSDBG( INIT, ( "NotifyShutdown()\n" ));
|
||
|
||
//
|
||
// wait for notify thread to stop
|
||
//
|
||
|
||
ThreadShutdownWait( g_hNotifyThread );
|
||
g_hNotifyThread = NULL;
|
||
|
||
//
|
||
// close notification handles
|
||
//
|
||
|
||
if ( g_hRegistryChange )
|
||
{
|
||
CloseHandle( g_hRegistryChange );
|
||
}
|
||
if ( g_hHostFileChange )
|
||
{
|
||
CloseHandle( g_hHostFileChange );
|
||
}
|
||
|
||
// clear globals
|
||
|
||
g_NotifyThreadId = 0;
|
||
g_hNotifyThread = NULL;
|
||
|
||
g_hHostFileChange = NULL;
|
||
g_hRegistryChange = NULL;
|
||
}
|
||
|
||
//
|
||
// End notify.c
|
||
//
|