/*++ 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 //