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.

1208 lines
24 KiB

  1. /*++
  2. Copyright (c) 1997-2001 Microsoft Corporation
  3. Module Name:
  4. dnsrslvr.c
  5. Abstract:
  6. DNS Resolver Service
  7. Main service module.
  8. Author:
  9. Glenn Curtis (glennc) 25-Feb-1997
  10. Revision History:
  11. Jim Gilroy (jamesg) March 2000 cleanup
  12. Jim Gilroy (jamesg) Nov 2000 rewrite
  13. --*/
  14. #include "local.h"
  15. #ifdef BUILD_W2K
  16. #include <services.h>
  17. #else
  18. #include <svcs.h>
  19. #endif
  20. //
  21. // Service control
  22. //
  23. SERVICE_STATUS ServiceStatus;
  24. SERVICE_STATUS_HANDLE ServiceStatusHandle = (SERVICE_STATUS_HANDLE) 0;
  25. #ifdef BUILD_W2K
  26. PSVCS_GLOBAL_DATA g_pSvchostData;
  27. #else
  28. PSVCHOST_GLOBAL_DATA g_pSvchostData;
  29. #endif
  30. HANDLE g_hStopEvent;
  31. BOOL g_StopFlag;
  32. BOOL g_fServiceControlHandled;
  33. //
  34. // Service state
  35. //
  36. #define RES_STATUS_BEGIN 0x0cc00000
  37. #define RES_STATUS_ZERO_INIT 0x0cc00001
  38. #define RES_STATUS_CREATED_CS 0x0cc00002
  39. #define RES_STATUS_CREATED_EVENT 0x0cc00003
  40. #define RES_STATUS_READ_REGISTRY 0x0cc00004
  41. #define RES_STATUS_ALLOC_CACHE 0x0cc00005
  42. #define RES_STATUS_START_NOTIFY 0x0cc00006
  43. #define RES_STATUS_START_IP_LIST 0x0cc00007
  44. #define RES_STATUS_START_RPC 0x0cc00008
  45. #define RES_STATUS_REG_CONTROL 0x0cc00009
  46. #define RES_STATUS_RUNNING 0x0cc00100
  47. #define RES_STATUS_STOPPING 0x0cc00300
  48. #define RES_STATUS_SIGNALED_STOP 0x0cc00301
  49. #define RES_STATUS_STOP_RPC 0x0cc00302
  50. #define RES_STATUS_STOP_NOTIFY 0x0cc00303
  51. #define RES_STATUS_STOP_IP_LIST 0x0cc00304
  52. #define RES_STATUS_FREE_CACHE 0x0cc00305
  53. #define RES_STATUS_FREE_NET_INFO 0x0cc00306
  54. #define RES_STATUS_FREE_IP_LIST 0x0cc00307
  55. #define RES_STATUS_FREE_SERVICE_NOTIFY 0x0cc00308
  56. #define RES_STATUS_DEL_EVENT 0x0cc00309
  57. #define RES_STATUS_DEL_CS 0x0cc00310
  58. #define RES_STATUS_END 0x0cc00400
  59. DWORD g_ResolverStatus = RES_STATUS_BEGIN;
  60. //
  61. // Initialization cleanup\state
  62. //
  63. // Track what we intialized for safer\faster cleanup
  64. //
  65. #define INITFLAG_CS_CREATED 0x00000001
  66. #define INITFLAG_WINSOCK 0x00000002
  67. #define INITFLAG_EVENTS_CREATED 0x00000004
  68. #define INITFLAG_CACHE_CREATED 0x00000008
  69. #define INITFLAG_NOTIFY_STARTED 0x00000010
  70. #define INITFLAG_IP_LIST_CREATED 0x00000020
  71. #define INITFLAG_RPC_SERVER_STARTED 0x00000100
  72. DWORD g_InitState;
  73. //
  74. // Critical sections used
  75. //
  76. CRITICAL_SECTION CacheCritSec;
  77. CRITICAL_SECTION NetworkListCritSec;
  78. CRITICAL_SECTION NetworkFailureCritSec;
  79. //
  80. // Logging control
  81. //
  82. BOOL g_LogTraceInfo = TRUE;
  83. //
  84. // Private protos
  85. //
  86. DWORD
  87. ResolverInitialize(
  88. VOID
  89. );
  90. VOID
  91. ResolverShutdown(
  92. IN DWORD ErrorCode
  93. );
  94. VOID
  95. ResolverControlHandler(
  96. IN DWORD Opcode
  97. );
  98. DWORD
  99. ResolverUpdateStatus(
  100. VOID
  101. );
  102. //
  103. // Service routines
  104. //
  105. //
  106. // NT5 version -- inside services.exe
  107. //
  108. #ifdef BUILD_W2K
  109. VOID
  110. SVCS_ENTRY_POINT(
  111. DWORD NumArgs,
  112. LPTSTR * ArgsArray,
  113. PSVCS_GLOBAL_DATA pSvcsGlobalData,
  114. HANDLE SvcRefHandle
  115. )
  116. /*++
  117. Routine Description:
  118. Main main entry point of resolver service
  119. Arguments:
  120. NumArgs - number of arguments to service start call
  121. ArgsArray - array of ptrs to arguments in service start call
  122. Return Value:
  123. None
  124. --*/
  125. {
  126. //
  127. // save pointer to service data block
  128. //
  129. g_pSvchostData = pSvcsGlobalData;
  130. ResolverInitialize();
  131. }
  132. #else
  133. //
  134. // Whistler+ version -- in svchost.exe process
  135. //
  136. VOID
  137. SvchostPushServiceGlobals(
  138. PSVCHOST_GLOBAL_DATA pGlobals
  139. )
  140. {
  141. g_pSvchostData = pGlobals;
  142. }
  143. VOID
  144. ServiceMain(
  145. IN DWORD NumArgs,
  146. IN LPTSTR * ArgsArray
  147. )
  148. /*++
  149. Routine Description:
  150. Main entry point of resolver service.
  151. Arguments:
  152. NumArgs - number of strings specified in ArgsArray.
  153. ArgsArray - array of ptrs to arguments in service start call
  154. Return Value:
  155. None
  156. --*/
  157. {
  158. //
  159. // Make sure svchost.exe gave us global data
  160. //
  161. ASSERT( g_pSvchostData != NULL );
  162. //
  163. // Startup service, then exit
  164. //
  165. ResolverInitialize();
  166. }
  167. #endif // NT4 \ Whistler+ switch
  168. VOID
  169. ResolverInitFailure(
  170. IN DNS_STATUS Status,
  171. IN DWORD EventId,
  172. IN DWORD MemEventId,
  173. IN PSTR pszDebugString
  174. )
  175. /*++
  176. Routine Description:
  177. Handle resolver init failure.
  178. Function exists to avoid duplicate code.
  179. Arguments:
  180. Return Value:
  181. None
  182. --*/
  183. {
  184. WCHAR numberString[16];
  185. PWSTR eventStrings[1];
  186. DNSLOG_TIME();
  187. DNSLOG_F1( "Resolver Init Failure" );
  188. DNSLOG_F2( " Failure = %s", pszDebugString );
  189. DNSLOG_F2( " Status = %d", Status );
  190. DNSLOG_F1( "" );
  191. DNSDBG( ANY, (
  192. "Resolver Init FAILED!\n"
  193. "\tname = %s\n"
  194. "\tstatus = %d\n"
  195. "\tevent id = %d\n"
  196. "\tmem event = %08x\n",
  197. pszDebugString,
  198. Status,
  199. EventId,
  200. MemEventId ));
  201. DnsDbg_PrintfToDebugger(
  202. "ResolverInitialize - Returning status %d 0x%08x\n"
  203. "\tname = %s\n",
  204. Status, Status,
  205. pszDebugString );
  206. //
  207. // log in memory event
  208. //
  209. LogEventInMemory( MemEventId, Status );
  210. //
  211. // log event
  212. // - convert status to string
  213. //
  214. wsprintfW( numberString, L"0x%.8X", Status );
  215. eventStrings[0] = numberString;
  216. ResolverLogEvent(
  217. EventId,
  218. EVENTLOG_ERROR_TYPE,
  219. 1,
  220. eventStrings,
  221. Status );
  222. // clean up
  223. ResolverShutdown( Status );
  224. }
  225. DWORD
  226. ResolverInitialize(
  227. VOID
  228. )
  229. /*++
  230. Routine Description:
  231. This function initializes the DNS Caching Resolver service.
  232. Arguments:
  233. InitState - Returns a flag to indicate how far we got with
  234. initializing the service before an error occurred.
  235. Return Value:
  236. ERROR_SUCCESS if successful.
  237. ErrorCode on failure.
  238. --*/
  239. {
  240. DNS_STATUS status = NO_ERROR;
  241. //
  242. // init service state
  243. //
  244. g_ResolverStatus = RES_STATUS_BEGIN;
  245. g_InitState = 0;
  246. g_StopFlag = FALSE;
  247. g_hStopEvent = NULL;
  248. g_fServiceControlHandled = FALSE;
  249. //
  250. // initialize logging
  251. //
  252. DNSLOG_INIT();
  253. DNSLOG_F1( "DNS Caching Resolver Service - ResolverInitialize" );
  254. #if DBG
  255. #if 0
  256. Dns_StartDebug(
  257. 0,
  258. "dnsres.flag",
  259. NULL,
  260. "dnsres.log",
  261. 0 );
  262. #endif
  263. Dns_StartDebugEx(
  264. 0, // no flag value
  265. "dnsres.flag",
  266. NULL, // no external flag
  267. "dnsres.log",
  268. 0, // no wrap limit
  269. FALSE, // don't use existing global
  270. FALSE,
  271. TRUE // make this file global
  272. );
  273. #endif
  274. DNSDBG( INIT, ( "DNS resolver startup.\n" ));
  275. IF_DNSDBG( START_BREAK )
  276. {
  277. // since resolver moved to NetworkServices permissions do
  278. // not properly bring up ntsd; instead just give time
  279. // to attach debugger
  280. Sleep( 20000 );
  281. }
  282. //
  283. // initialize service status block
  284. //
  285. ServiceStatusHandle = (SERVICE_STATUS_HANDLE) 0;
  286. ServiceStatus.dwServiceType = SERVICE_WIN32_SHARE_PROCESS;
  287. ServiceStatus.dwCurrentState = SERVICE_START_PENDING;
  288. ServiceStatus.dwControlsAccepted = 0;
  289. ServiceStatus.dwCheckPoint = 0;
  290. ServiceStatus.dwWaitHint = 5000;
  291. ServiceStatus.dwWin32ExitCode = NO_ERROR;
  292. ServiceStatus.dwServiceSpecificExitCode = 0;
  293. ResolverUpdateStatus();
  294. //
  295. // init globals to zero
  296. //
  297. ZeroInitIpListGlobals();
  298. ZeroNetworkConfigGlobals();
  299. g_ResolverStatus = RES_STATUS_ZERO_INIT;
  300. //
  301. // initialize all our critical sections as soon as we can
  302. //
  303. LogEventInMemory( RES_EVENT_INITCRIT_START, 0 );
  304. InitializeCriticalSection( & CacheCritSec );
  305. InitializeCriticalSection( & NetworkListCritSec );
  306. InitializeCriticalSection( & NetworkFailureCritSec );
  307. LogEventInMemory( RES_EVENT_INITCRIT_END,0 );
  308. //
  309. // init our dnslib heap to use dnsapi heap
  310. //
  311. // this is important because we currently mix and match records
  312. // created inside dnsapi (hosts file and query) with a few that
  313. // we roll on our own; need this to be common
  314. //
  315. Dns_LibHeapReset( DnsApiAlloc, DnsApiRealloc, DnsApiFree );
  316. //
  317. // init winsock
  318. //
  319. Dns_InitializeWinsock();
  320. g_InitState |= INITFLAG_WINSOCK;
  321. //
  322. // shutdown event
  323. //
  324. g_hStopEvent = CreateEvent(
  325. NULL, // no security descriptor
  326. TRUE, // do not use automatic reset
  327. FALSE, // initial state: not signalled
  328. NULL // no name
  329. );
  330. if ( !g_hStopEvent )
  331. {
  332. status = GetLastError();
  333. ResolverInitFailure(
  334. status,
  335. 0,
  336. 0,
  337. "CreateEvent() failed" );
  338. return status;
  339. }
  340. g_InitState |= INITFLAG_EVENTS_CREATED;
  341. g_ResolverStatus = RES_STATUS_CREATED_EVENT;
  342. ResolverUpdateStatus();
  343. //
  344. // initialize our global registry values
  345. // - force this just once on startup so we have the
  346. // relevant cache params; after that read only on
  347. // demand when building netinfo blobs
  348. ReadRegistryConfig();
  349. //
  350. // Set the query timeouts to be used from defaults or registry
  351. //
  352. Dns_InitQueryTimeouts();
  353. //
  354. // init socket caching
  355. // - improves perf and prevents socket DOS attack
  356. // - default cache to 10 sockets
  357. //
  358. // DCR: create global for socket caching
  359. //
  360. Dns_CacheSocketInit( 10 );
  361. #if 0
  362. //
  363. // start cache on demand now
  364. //
  365. //
  366. // initialize cache
  367. //
  368. status = Cache_Initialize();
  369. LogEventInMemory( RES_EVENT_INITCACHE, status );
  370. if ( status != NO_ERROR )
  371. {
  372. ResolverInitFailure(
  373. status,
  374. EVENT_DNS_CACHE_START_FAILURE_NO_CONTROL,
  375. 0,
  376. "Cache_Initialize() failed" );
  377. return status;
  378. }
  379. g_InitState |= INITFLAG_CACHE_CREATED;
  380. g_ResolverStatus = RES_STATUS_ALLOC_CACHE;
  381. ResolverUpdateStatus();
  382. #endif
  383. //
  384. // notification thread (host file and registry)
  385. //
  386. StartNotify();
  387. g_InitState |= INITFLAG_NOTIFY_STARTED;
  388. g_ResolverStatus = RES_STATUS_START_NOTIFY;
  389. ResolverUpdateStatus();
  390. //
  391. // IP notification thread
  392. //
  393. status = InitIpListAndNotification();
  394. if ( status != ERROR_SUCCESS )
  395. {
  396. ResolverInitFailure(
  397. status,
  398. 0,
  399. 0,
  400. "IP list init failed" );
  401. return status;
  402. }
  403. g_InitState |= INITFLAG_IP_LIST_CREATED;
  404. g_ResolverStatus = RES_STATUS_START_IP_LIST;
  405. ResolverUpdateStatus();
  406. //
  407. // register control handler
  408. // allows us to receive service requests
  409. //
  410. ServiceStatusHandle = RegisterServiceCtrlHandlerW(
  411. DNS_RESOLVER_SERVICE,
  412. ResolverControlHandler
  413. );
  414. if ( !ServiceStatusHandle )
  415. {
  416. status = GetLastError();
  417. ResolverInitFailure(
  418. status,
  419. EVENT_DNS_CACHE_START_FAILURE_LOW_MEMORY,
  420. RES_EVENT_REGISTER_SCH,
  421. "Call to RegisterServiceCtrlHandlerW failed!"
  422. );
  423. return status;
  424. }
  425. g_ResolverStatus = RES_STATUS_REG_CONTROL;
  426. ResolverUpdateStatus();
  427. //
  428. // initialize RPC interfaces
  429. // - bump our requested stack size up to 8K
  430. // (RPC uses 1800 bytes before we get the stack,
  431. // the new() operator followed by the heap code uses
  432. // another 1200 -- leaving only about a 1000 for
  433. // DNS)
  434. //
  435. LogEventInMemory( RES_EVENT_STARTRPC, 0 );
  436. #if 0
  437. // should not be necessary
  438. // default for all svchost instances has been increased
  439. if ( status != NO_ERROR )
  440. {
  441. DNSDBG( ANY, (
  442. "RpcMgmtSetServerStackSize( 2000 ) = %d\n",
  443. status ));
  444. }
  445. #endif
  446. status = Rpc_Initialize();
  447. #if 0
  448. status = g_pSvchostData->StartRpcServer(
  449. SERVER_INTERFACE_NAME_W,
  450. DnsResolver_ServerIfHandle );
  451. #endif
  452. if ( status != NO_ERROR )
  453. {
  454. LogEventInMemory( RES_EVENT_STATUS, status );
  455. if ( status == RPC_S_TYPE_ALREADY_REGISTERED ||
  456. status == RPC_NT_TYPE_ALREADY_REGISTERED )
  457. {
  458. DNSLOG_TIME();
  459. DNSLOG_F1( " Call to StartRpcServer returned warning that" );
  460. DNSLOG_F1( " the service is already running!" );
  461. DNSLOG_F2( " RpcPipeName : %S", RESOLVER_INTERFACE_NAME_W );
  462. DNSLOG_F1( " Going to just continue running . . ." );
  463. DNSLOG_F1( "" );
  464. DnsDbg_PrintfToDebugger(
  465. "DNS Client (dnsrslvr.dll) - Call to StartRpcServer\n"
  466. "returned warning that the service is already running!\n"
  467. "RpcPipeName : %S"
  468. "Going to just continue running . . .\n",
  469. RESOLVER_INTERFACE_NAME_W );
  470. status = NO_ERROR;
  471. }
  472. else
  473. {
  474. DNSDBG( ANY, (
  475. "RPC init FAILED! status = %d\n"
  476. "\tpipe name = %s\n",
  477. status,
  478. RESOLVER_INTERFACE_NAME_W ));
  479. ResolverInitFailure(
  480. status,
  481. EVENT_DNS_CACHE_START_FAILURE_NO_RPC,
  482. 0,
  483. "Call to StartRpcServer failed!"
  484. );
  485. return status;
  486. }
  487. }
  488. g_ResolverStatus = RES_STATUS_START_RPC;
  489. g_InitState |= INITFLAG_RPC_SERVER_STARTED;
  490. //
  491. // successful startup
  492. // - indicate running
  493. // - indicate what service control messages we want to get
  494. //
  495. ServiceStatus.dwCurrentState = SERVICE_RUNNING;
  496. ServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP |
  497. SERVICE_ACCEPT_PARAMCHANGE |
  498. SERVICE_ACCEPT_NETBINDCHANGE;
  499. ServiceStatus.dwWaitHint = 0;
  500. ServiceStatus.dwWin32ExitCode = NO_ERROR;
  501. ResolverUpdateStatus();
  502. g_ResolverStatus = RES_STATUS_RUNNING;
  503. DNSLOG_F1( "ResolverInitialize - Successful" );
  504. DNSLOG_F1( "" );
  505. return NO_ERROR;
  506. }
  507. VOID
  508. ResolverShutdown(
  509. IN DWORD ErrorCode
  510. )
  511. /*++
  512. Routine Description:
  513. This function shuts down the DNS cache service.
  514. Arguments:
  515. ErrorCode - Supplies the error code of the failure
  516. Return Value:
  517. None.
  518. --*/
  519. {
  520. DWORD status = NO_ERROR;
  521. LONG existingStopFlag;
  522. DNSLOG_TIME();
  523. DNSLOG_F1( "DNS Caching Resolver Service - ResolverShutdown" );
  524. DnsDbg_PrintfToDebugger( "DNS Client - ResolverShutdown!\n" );
  525. //
  526. // indicate shutdown
  527. // - but interlock to avoid dual shutdown
  528. //
  529. existingStopFlag = InterlockedExchange(
  530. &g_StopFlag,
  531. (LONG) TRUE );
  532. if ( existingStopFlag )
  533. {
  534. DNS_ASSERT( FALSE );
  535. return;
  536. }
  537. DNS_ASSERT( g_StopFlag );
  538. //
  539. // indicate stop in progress
  540. //
  541. ServiceStatus.dwCurrentState = SERVICE_STOP_PENDING;
  542. ServiceStatus.dwCheckPoint = 1;
  543. ServiceStatus.dwWaitHint = 60000;
  544. ResolverUpdateStatus();
  545. g_ResolverStatus = RES_STATUS_STOPPING;
  546. //
  547. // wakeup threads to shut down
  548. //
  549. g_StopFlag = TRUE;
  550. if ( g_hStopEvent )
  551. {
  552. if ( !SetEvent(g_hStopEvent) )
  553. {
  554. DnsDbg_PrintfToDebugger(
  555. "DNSCACHE: Error setting g_hStopEvent %lu\n",
  556. GetLastError());
  557. DNS_ASSERT( FALSE );
  558. }
  559. }
  560. g_ResolverStatus = RES_STATUS_SIGNALED_STOP;
  561. //
  562. // cleanup RPC
  563. //
  564. if ( g_InitState & INITFLAG_RPC_SERVER_STARTED )
  565. {
  566. LogEventInMemory( RES_EVENT_STOPRPC, 0 );
  567. Rpc_Shutdown();
  568. #if 0
  569. //status = g_pSvchostData->StopRpcServer( DnsResolver_ServerIfHandle );
  570. #endif
  571. LogEventInMemory( RES_EVENT_STATUS, status );
  572. }
  573. g_ResolverStatus = RES_STATUS_STOP_RPC;
  574. //
  575. // re-signal stop within lock
  576. //
  577. LOCK_CACHE_NO_START();
  578. g_StopFlag = TRUE;
  579. if ( g_hStopEvent )
  580. {
  581. if ( !SetEvent(g_hStopEvent) )
  582. {
  583. DnsDbg_PrintfToDebugger(
  584. "DNSCACHE: Error setting g_hStopEvent %lu\n",
  585. GetLastError());
  586. DNS_ASSERT( FALSE );
  587. }
  588. }
  589. UNLOCK_CACHE();
  590. //
  591. // stop notify thread
  592. //
  593. if ( g_InitState & INITFLAG_NOTIFY_STARTED )
  594. {
  595. ShutdownNotify();
  596. }
  597. g_ResolverStatus = RES_STATUS_STOP_NOTIFY;
  598. //
  599. // stop IP notify thread
  600. //
  601. if ( g_InitState & INITFLAG_IP_LIST_CREATED )
  602. {
  603. ShutdownIpListAndNotify();
  604. }
  605. g_ResolverStatus = RES_STATUS_STOP_IP_LIST;
  606. //
  607. // cleanup cache
  608. //
  609. Cache_Shutdown();
  610. g_ResolverStatus = RES_STATUS_FREE_CACHE;
  611. //
  612. // cleanup service notification list
  613. //
  614. //CleanupServiceNotification();
  615. //g_ResolverStatus = RES_STATUS_FREE_SERVICE_NOTIFY;
  616. //
  617. // cleanup network info globals
  618. //
  619. CleanupNetworkInfo();
  620. g_ResolverStatus = RES_STATUS_FREE_NET_INFO;
  621. //
  622. // cleanup winsock
  623. // cleanup socket caching also
  624. // - this is irrelevant for other services running in
  625. // our process so we shouldn't leave the handles open
  626. //
  627. if ( g_InitState & INITFLAG_WINSOCK )
  628. {
  629. Dns_CacheSocketCleanup();
  630. Dns_CleanupWinsock();
  631. }
  632. //
  633. // cleanup main shutdown event
  634. //
  635. if ( g_InitState & INITFLAG_EVENTS_CREATED )
  636. {
  637. if ( g_hStopEvent )
  638. {
  639. CloseHandle(g_hStopEvent);
  640. g_hStopEvent = NULL;
  641. }
  642. }
  643. g_ResolverStatus = RES_STATUS_DEL_EVENT;
  644. //
  645. // delete critical sections
  646. //
  647. if ( g_InitState & INITFLAG_CS_CREATED )
  648. {
  649. LogEventInMemory( RES_EVENT_DELCRIT_START, 0 );
  650. DeleteCriticalSection( &CacheCritSec );
  651. DeleteCriticalSection( &NetworkListCritSec );
  652. DeleteCriticalSection( &NetworkFailureCritSec );
  653. LogEventInMemory( RES_EVENT_DELCRIT_END, 0 );
  654. }
  655. g_ResolverStatus = RES_STATUS_DEL_CS;
  656. //
  657. // cleanup complete
  658. // tell Service Controller that we are stopped
  659. //
  660. ServiceStatus.dwCurrentState = SERVICE_STOPPED;
  661. ServiceStatus.dwControlsAccepted = 0;
  662. ServiceStatus.dwWin32ExitCode = ErrorCode;
  663. ServiceStatus.dwServiceSpecificExitCode = 0;
  664. ServiceStatus.dwCheckPoint = 0;
  665. ServiceStatus.dwWaitHint = 0;
  666. ResolverUpdateStatus();
  667. g_ResolverStatus = RES_STATUS_END;
  668. DNSLOG_F1( "ResolverShutdown - Finished" );
  669. DNSLOG_F1( "" );
  670. }
  671. BOOL
  672. GetServiceControlLock(
  673. VOID
  674. )
  675. /*++
  676. Routine Description:
  677. Get exclusive access handling service control message.
  678. Arguments:
  679. None
  680. Return Value:
  681. TRUE -- have exclusive access to handle SCM, other threads locked out
  682. FALSE -- another thread still handling SCM
  683. --*/
  684. {
  685. BOOL fresult;
  686. //
  687. // set handled flag, if not previously set
  688. // if not previous set -> we have exclusive access
  689. //
  690. fresult = InterlockedCompareExchange(
  691. &g_fServiceControlHandled,
  692. (LONG) TRUE, // new value
  693. (LONG) 0 // previous value to do exchange
  694. );
  695. return !fresult;
  696. }
  697. VOID
  698. ReleaseServiceControlLock(
  699. VOID
  700. )
  701. /*++
  702. Routine Description:
  703. Release service control exclusive access.
  704. Arguments:
  705. None
  706. Return Value:
  707. None
  708. --*/
  709. {
  710. //
  711. // clear handled flag
  712. // - since GetServiceControlLock() uses CompareExchange
  713. // we can just clear without interlock
  714. //
  715. DNS_ASSERT( g_fServiceControlHandled );
  716. g_fServiceControlHandled = FALSE;
  717. }
  718. VOID
  719. ResolverControlHandler(
  720. IN DWORD Opcode
  721. )
  722. /*++
  723. Routine Description:
  724. Service control handler for DNS cache service.
  725. Arguments:
  726. Opcode - specifies service action
  727. Return Value:
  728. None.
  729. --*/
  730. {
  731. LogEventInMemory( RES_EVENT_SCH, Opcode );
  732. DNSLOG_TIME();
  733. DNSLOG_F2( "ResolverControlHandler - Recieved opcode %d", Opcode );
  734. DNSDBG( ANY, (
  735. "\n\n"
  736. "ResolverControlHandler() Opcode = %d\n",
  737. Opcode ));
  738. //
  739. // handle various service control codes
  740. //
  741. switch( Opcode )
  742. {
  743. case SERVICE_CONTROL_STOP:
  744. ResolverShutdown( NO_ERROR );
  745. break;
  746. case SERVICE_CONTROL_PARAMCHANGE :
  747. DNSLOG_F1( " Handle Paramchange" );
  748. DNSLOG_F1( "" );
  749. if ( !GetServiceControlLock() )
  750. {
  751. return;
  752. }
  753. //
  754. // rebuild -- with cache flush
  755. //
  756. HandleConfigChange(
  757. "SC -- ParamChange",
  758. TRUE // flush cache
  759. );
  760. //
  761. // signal other services about PnP
  762. //
  763. // SendServiceNotifications();
  764. ReleaseServiceControlLock();
  765. break;
  766. case SERVICE_CONTROL_NETBINDENABLE:
  767. case SERVICE_CONTROL_NETBINDDISABLE:
  768. DNSLOG_F1( " Handle NetBindEnable\\Disable" );
  769. DNSLOG_F1( "" );
  770. if ( !GetServiceControlLock() )
  771. {
  772. return;
  773. }
  774. //
  775. // rebuild -- with cache flush
  776. //
  777. HandleConfigChange(
  778. "SC -- NetBind",
  779. TRUE // flush cache
  780. );
  781. ReleaseServiceControlLock();
  782. break;
  783. case SERVICE_CONTROL_INTERROGATE:
  784. case SERVICE_CONTROL_NETBINDADD:
  785. case SERVICE_CONTROL_NETBINDREMOVE:
  786. default:
  787. DNSLOG_F1( " This is an unknown opcode, ignoring ..." );
  788. DNSLOG_F1( "" );
  789. break;
  790. }
  791. //
  792. // update service status
  793. //
  794. ResolverUpdateStatus();
  795. DNSLOG_F2( "Resolver Controll Handler (opcode = %d) -- returning", Opcode );
  796. DNSDBG( ANY, (
  797. "Leaving ResolverControlHandler( %d )\n\n\n",
  798. Opcode ));
  799. }
  800. DWORD
  801. ResolverUpdateStatus(
  802. VOID
  803. )
  804. /*++
  805. Routine Description:
  806. Update service controller with current service status.
  807. Arguments:
  808. None.
  809. Return Value:
  810. Return code from SetServiceStatus.
  811. --*/
  812. {
  813. DWORD status = NO_ERROR;
  814. DNSDBG( TRACE, ( "ResolverUpdateStatus()\n" ));
  815. //
  816. // bump the checkpoint
  817. // if status, set it
  818. ServiceStatus.dwCheckPoint++;
  819. #if 0
  820. if ( Status )
  821. {
  822. ServiceStatus.dwWin32ExitCode = Status;
  823. }
  824. #endif
  825. //
  826. // DCR_FIX: this doesn't do much
  827. // usually people write something like this that sets the service
  828. // state AND does the update
  829. //
  830. // QUESTION: what's up with the LogEventInMemory?
  831. //
  832. if ( ServiceStatusHandle == (SERVICE_STATUS_HANDLE) 0 )
  833. {
  834. LogEventInMemory( RES_EVENT_UPDATE_STATUS, ERROR_INVALID_HANDLE );
  835. return ERROR_INVALID_HANDLE;
  836. }
  837. LogEventInMemory( RES_EVENT_UPDATE_STATUS, ServiceStatus.dwWin32ExitCode );
  838. if ( ! SetServiceStatus( ServiceStatusHandle, &ServiceStatus ) )
  839. {
  840. status = GetLastError();
  841. }
  842. LogEventInMemory( RES_EVENT_UPDATE_STATUS, status );
  843. return status;
  844. }
  845. //
  846. // Event logging
  847. //
  848. VOID
  849. ResolverLogEvent(
  850. IN DWORD MessageId,
  851. IN WORD EventType,
  852. IN DWORD StringCount,
  853. IN PWSTR * StringArray,
  854. IN DWORD ErrorCode
  855. )
  856. /*++
  857. Routine Description:
  858. Log to eventlog.
  859. Arguments:
  860. MessageId -- event message id
  861. EventType -- event type (error, warning, info, etc.)
  862. StringCount -- string arg count
  863. StringArray -- imbedded strings
  864. ErrorCode -- error code for data section of event
  865. Return Value:
  866. None
  867. --*/
  868. {
  869. HANDLE hlog;
  870. PVOID pdata = NULL;
  871. //
  872. // open resolver as event source
  873. //
  874. // note: we don't keep log open because events are few
  875. //
  876. hlog = RegisterEventSourceW(
  877. NULL,
  878. DNS_RESOLVER_SERVICE );
  879. if ( hlog == NULL )
  880. {
  881. return;
  882. }
  883. if ( ErrorCode != NO_ERROR )
  884. {
  885. pdata = &ErrorCode;
  886. }
  887. //
  888. // Write to event log
  889. //
  890. // DCR: should get suppression technology here
  891. //
  892. ReportEventW(
  893. hlog,
  894. EventType,
  895. 0, // event category
  896. MessageId,
  897. (PSID) NULL,
  898. (WORD) StringCount,
  899. sizeof(DWORD),
  900. StringArray,
  901. (PVOID) pdata );
  902. DeregisterEventSource( hlog );
  903. }
  904. //
  905. // End dnsrslvr.c
  906. //