Source code of Windows XP (NT5)
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.

439 lines
7.7 KiB

  1. /*++
  2. Copyright (c) 2000-2000 Microsoft Corporation
  3. Module Name:
  4. notify.c
  5. Abstract:
  6. DNS Resolver Service.
  7. Notification thread
  8. - host file changes
  9. - registry config changes
  10. Author:
  11. Jim Gilroy (jamesg) November 2000
  12. Revision History:
  13. --*/
  14. #include "local.h"
  15. //
  16. // Host file directory
  17. //
  18. #define HOSTS_FILE_DIRECTORY L"\\drivers\\etc"
  19. //
  20. // Notify globals
  21. //
  22. DWORD g_NotifyThreadId = 0;
  23. HANDLE g_hNotifyThread = NULL;
  24. HANDLE g_hHostFileChange = NULL;
  25. HANDLE g_hRegistryChange = NULL;
  26. HANDLE
  27. CreateHostsFileChangeHandle(
  28. VOID
  29. )
  30. /*++
  31. Routine Description:
  32. Create hosts file change handle.
  33. Arguments:
  34. None.
  35. Return Value:
  36. None.
  37. --*/
  38. {
  39. HANDLE changeHandle;
  40. PWSTR psystemDirectory = NULL;
  41. UINT len;
  42. WCHAR hostDirectory[ MAX_PATH*2 ];
  43. DNSDBG( INIT, ( "CreateHostsFileChangeHandle\n" ));
  44. //
  45. // build host file name
  46. //
  47. len = GetSystemDirectory( hostDirectory, MAX_PATH );
  48. if ( !len || len>MAX_PATH )
  49. {
  50. DNSLOG_F1( "Error: Failed to get system directory" );
  51. DNSLOG_F1( "NotifyThread exiting." );
  52. return( NULL );
  53. }
  54. wcscat( hostDirectory, HOSTS_FILE_DIRECTORY );
  55. //
  56. // drop change notify on host file directory
  57. //
  58. changeHandle = FindFirstChangeNotification(
  59. hostDirectory,
  60. FALSE,
  61. FILE_NOTIFY_CHANGE_FILE_NAME |
  62. FILE_NOTIFY_CHANGE_LAST_WRITE );
  63. if ( changeHandle == INVALID_HANDLE_VALUE )
  64. {
  65. DNSLOG_F1( "NotifyThread failed to get handle from" );
  66. DNSLOG_F2(
  67. "Failed to get hosts file change handle.\n"
  68. "Error code: <0x%.8X>",
  69. GetLastError() );
  70. return( NULL );
  71. }
  72. return( changeHandle );
  73. }
  74. VOID
  75. ThreadShutdownWait(
  76. IN HANDLE hThread
  77. )
  78. /*++
  79. Routine Description:
  80. Wait on thread shutdown.
  81. Arguments:
  82. hThread -- thread handle that is shutting down
  83. Return Value:
  84. None.
  85. --*/
  86. {
  87. DWORD waitResult;
  88. if ( !hThread )
  89. {
  90. return;
  91. }
  92. DNSDBG( ANY, (
  93. "Waiting on shutdown of thread %d (%p)\n",
  94. hThread, hThread ));
  95. waitResult = WaitForSingleObject(
  96. hThread,
  97. 10000 );
  98. switch( waitResult )
  99. {
  100. case WAIT_OBJECT_0:
  101. break;
  102. default:
  103. // thread didn't stop -- need to kill it
  104. ASSERT( waitResult == WAIT_TIMEOUT );
  105. DNSLOG_F2( "Shutdown: thread %d not stopped, terminating", hThread );
  106. TerminateThread( hThread, 1 );
  107. break;
  108. }
  109. // close thread handle
  110. CloseHandle( hThread );
  111. }
  112. VOID
  113. NotifyThread(
  114. VOID
  115. )
  116. /*++
  117. Routine Description:
  118. Main notify thread.
  119. Arguments:
  120. None.
  121. Globals:
  122. g_hStopEvent -- waits on shutdown even
  123. Return Value:
  124. None.
  125. --*/
  126. {
  127. DWORD handleCount;
  128. DWORD waitResult;
  129. HANDLE handleArray[3];
  130. DNSDBG( INIT, (
  131. "\nStart NotifyThread\n" ));
  132. //
  133. // get file change handle
  134. //
  135. g_hHostFileChange = CreateHostsFileChangeHandle();
  136. //
  137. // wait on
  138. // - host file change => flush+rebuild cache
  139. // - registry change => reread config info
  140. // - shutdown => exit
  141. //
  142. handleArray[0] = g_hStopEvent;
  143. handleCount = 1;
  144. if ( g_hHostFileChange )
  145. {
  146. handleArray[handleCount++] = g_hHostFileChange;
  147. }
  148. if ( g_hRegistryChange )
  149. {
  150. handleArray[handleCount++] = g_hRegistryChange;
  151. }
  152. if ( handleCount == 1 )
  153. {
  154. DNSDBG( ANY, (
  155. "No change handles -- exit notify thread.\n" ));
  156. goto ThreadExit;
  157. }
  158. while( 1 )
  159. {
  160. waitResult = WaitForMultipleObjects(
  161. handleCount,
  162. handleArray,
  163. FALSE,
  164. INFINITE );
  165. switch( waitResult )
  166. {
  167. case WAIT_OBJECT_0:
  168. // shutdown event
  169. // - if stopping exit
  170. // - do garbage collection if required
  171. // - otherwise short wait to avoid spin if screwup
  172. // and not get thrashed by failed garbage collection
  173. DNSLOG_F1( "NotifyThread: Shutdown Event" );
  174. if ( g_StopFlag )
  175. {
  176. goto ThreadExit;
  177. }
  178. else if ( g_GarbageCollectFlag )
  179. {
  180. Cache_GarbageCollect( 0 );
  181. }
  182. ELSE_ASSERT_FALSE;
  183. Sleep( 1000 );
  184. if ( g_StopFlag )
  185. {
  186. goto ThreadExit;
  187. }
  188. continue;
  189. case WAIT_OBJECT_0 + 1:
  190. // host file change -- flush cache
  191. DNSLOG_F1( "NotifyThread: Host file change event" );
  192. // reset notification -- BEFORE reload
  193. if ( !FindNextChangeNotification( g_hHostFileChange ) )
  194. {
  195. DNSLOG_F1( "NotifyThread failed to get handle" );
  196. DNSLOG_F1( "from FindNextChangeNotification." );
  197. DNSLOG_F2( "Error code: <0x%.8X>", GetLastError() );
  198. goto ThreadExit;
  199. }
  200. Cache_Flush();
  201. break;
  202. case WAIT_OBJECT_0 + 2:
  203. // registry change notification -- flush cache and reload
  204. DNSLOG_F1( "NotifyThread: Registry change event" );
  205. break;
  206. default:
  207. ASSERT( g_StopFlag );
  208. if ( g_StopFlag )
  209. {
  210. goto ThreadExit;
  211. }
  212. Sleep( 5000 );
  213. continue;
  214. }
  215. }
  216. ThreadExit:
  217. DNSDBG( INIT, (
  218. "NotifyThread exit\n" ));
  219. DNSLOG_F1( "NotifyThread exiting." );
  220. }
  221. VOID
  222. StartNotify(
  223. VOID
  224. )
  225. /*++
  226. Routine Description:
  227. Start notify thread.
  228. Arguments:
  229. None.
  230. Return Value:
  231. ERROR_SUCCESS if successful.
  232. ErrorCode on failure.
  233. --*/
  234. {
  235. //
  236. // clear
  237. //
  238. g_NotifyThreadId = 0;
  239. g_hNotifyThread = NULL;
  240. g_hHostFileChange = NULL;
  241. g_hRegistryChange = NULL;
  242. //
  243. // host file write monitor thread
  244. // keeps cache in sync when write made to host file
  245. //
  246. g_hNotifyThread = CreateThread(
  247. NULL,
  248. 0,
  249. (LPTHREAD_START_ROUTINE) NotifyThread,
  250. NULL,
  251. 0,
  252. &g_NotifyThreadId );
  253. if ( !g_hNotifyThread )
  254. {
  255. DNS_STATUS status = GetLastError();
  256. DNSLOG_F1( "ERROR: InitializeCache function failed to create" );
  257. DNSLOG_F1( " HOSTS file monitor thread." );
  258. DNSLOG_F2( " Error code: <0x%.8X>", status );
  259. DNSLOG_F1( " NOTE: Resolver service will continue to run." );
  260. DNSDBG( ANY, (
  261. "FAILED Notify thread start!\n"
  262. "\tstatus = %d\n",
  263. status ));
  264. }
  265. }
  266. VOID
  267. ShutdownNotify(
  268. VOID
  269. )
  270. /*++
  271. Routine Description:
  272. Shutdown notify thread.
  273. Arguments:
  274. None.
  275. Return Value:
  276. ERROR_SUCCESS if successful.
  277. ErrorCode on failure.
  278. --*/
  279. {
  280. DWORD waitResult;
  281. DNSDBG( INIT, ( "NotifyShutdown()\n" ));
  282. //
  283. // wait for notify thread to stop
  284. //
  285. ThreadShutdownWait( g_hNotifyThread );
  286. g_hNotifyThread = NULL;
  287. //
  288. // close notification handles
  289. //
  290. if ( g_hRegistryChange )
  291. {
  292. CloseHandle( g_hRegistryChange );
  293. }
  294. if ( g_hHostFileChange )
  295. {
  296. CloseHandle( g_hHostFileChange );
  297. }
  298. // clear globals
  299. g_NotifyThreadId = 0;
  300. g_hNotifyThread = NULL;
  301. g_hHostFileChange = NULL;
  302. g_hRegistryChange = NULL;
  303. }
  304. //
  305. // End notify.c
  306. //