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.

452 lines
11 KiB

  1. /******************************************************************************
  2. *
  3. * Copyright (c) 2000 Microsoft Corporation
  4. *
  5. * Module Name:
  6. * NTService.cpp
  7. *
  8. * Abstract:
  9. * This file contains the implementation of CNTService class.
  10. *
  11. * Revision History:
  12. * Ashish Sikka ( ashishs ) 05/08/2000
  13. * created
  14. *****************************************************************************/
  15. #include "precomp.h"
  16. #include "ntservmsg.h" // generated from the MC message compiler
  17. #ifdef THIS_FILE
  18. #undef THIS_FILE
  19. #endif
  20. static char __szTraceSourceFile[] = __FILE__;
  21. #define THIS_FILE __szTraceSourceFile
  22. #define TRACEID 8970
  23. CNTService * g_pSRService=NULL;
  24. #define SERVICE_WAIT_HINT 30 // seconds
  25. extern "C" void CALLBACK
  26. StopCallback(
  27. PVOID pv,
  28. BOOLEAN TimerOrWaitFired);
  29. //
  30. // static variables
  31. //
  32. CNTService::CNTService()
  33. {
  34. TraceFunctEnter("CNTService:CNTService");
  35. m_hEventSource = NULL;
  36. //
  37. // Set up the initial service status
  38. //
  39. m_hServiceStatus = NULL;
  40. m_Status.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
  41. m_Status.dwCurrentState = SERVICE_START_PENDING;
  42. m_Status.dwControlsAccepted = SERVICE_ACCEPT_STOP|SERVICE_ACCEPT_SHUTDOWN;
  43. m_Status.dwWin32ExitCode = 0;
  44. m_Status.dwServiceSpecificExitCode = 0;
  45. m_Status.dwCheckPoint = 0;
  46. m_Status.dwWaitHint = 0;
  47. TraceFunctLeave();
  48. }
  49. CNTService::~CNTService()
  50. {
  51. TENTER("CNTService::~CNTService");
  52. if (m_hEventSource)
  53. {
  54. ::DeregisterEventSource(m_hEventSource);
  55. }
  56. TLEAVE();
  57. }
  58. //
  59. // Logging functions
  60. //
  61. void CNTService::LogEvent(
  62. WORD wType, DWORD dwID,
  63. void * pRawData,
  64. DWORD dwDataSize,
  65. const WCHAR* pszS1,
  66. const WCHAR* pszS2,
  67. const WCHAR* pszS3)
  68. {
  69. TraceFunctEnter("CNTService::LogEvent");
  70. //
  71. // Check the event source has been registered and if
  72. // not then register it now
  73. //
  74. if (!m_hEventSource)
  75. {
  76. m_hEventSource = ::RegisterEventSource(NULL, s_cszServiceName);
  77. }
  78. SRLogEvent (m_hEventSource, wType, dwID, pRawData,
  79. dwDataSize, pszS1, pszS2, pszS3);
  80. TraceFunctLeave();
  81. }
  82. //
  83. // ServiceMain
  84. //
  85. //This function immediately reports the service as having started.
  86. //However, all the initialization is done after the service is
  87. //started. We chose to do this becuase this service may have a long
  88. //initialization time and it may be tricky to keep giving hints to the
  89. //SCM during this time. Also, the service does all the work itself and
  90. //does not service any clients. So it is OK to do initialization after
  91. //the service is reported to be started.
  92. void CNTService::ServiceMain(DWORD dwArgc, LPTSTR* lpszArgv)
  93. {
  94. DWORD dwRc = ERROR_SUCCESS;
  95. HANDLE hSRStopWait = NULL;
  96. TENTER("CNTService::ServiceMain()");
  97. // Register the control request handler
  98. m_hServiceStatus = RegisterServiceCtrlHandler(s_cszServiceName,
  99. SRServiceHandler);
  100. if (m_hServiceStatus != NULL)
  101. {
  102. HKEY hKey = NULL;
  103. DWORD dwBreak = 0;
  104. /*
  105. // tell the service manager that we are starting
  106. // Also inform the Controls accepted
  107. m_Status.dwCheckPoint = 0;
  108. m_Status.dwWaitHint = SERVICE_WAIT_HINT*1000;
  109. SetStatus(SERVICE_START_PENDING);
  110. */
  111. //
  112. // Tell the service manager we are running
  113. //
  114. m_Status.dwCheckPoint = 0;
  115. m_Status.dwWaitHint = 0;
  116. SetStatus(SERVICE_RUNNING);
  117. // break into debugger if need to debug
  118. // this is controlled by setting regkey SRService\DebugBreak to 1
  119. if (ERROR_SUCCESS == RegOpenKeyEx(HKEY_LOCAL_MACHINE,
  120. s_cszServiceRegKey,
  121. 0,
  122. KEY_READ,
  123. &hKey))
  124. {
  125. RegReadDWORD(hKey, s_cszDebugBreak, &dwBreak);
  126. ASSERT (dwBreak != 1);
  127. RegCloseKey(hKey);
  128. }
  129. //
  130. // do boot time tasks - including firstrun if necessary
  131. //
  132. g_pEventHandler = new CEventHandler;
  133. if ( ! g_pEventHandler )
  134. {
  135. dwRc = GetLastError();
  136. TRACE(TRACEID, "! out of memory");
  137. goto done;
  138. }
  139. dwRc = g_pEventHandler->OnBoot( );
  140. if ( ERROR_SUCCESS != dwRc )
  141. {
  142. TRACE(TRACEID, "g_pEventHandler->OnBoot : error=%ld", dwRc);
  143. goto done;
  144. }
  145. // bind the stop event to a callback
  146. // so that this gets called on a thread pool thread
  147. // when the stop event is signalled
  148. if (FALSE == RegisterWaitForSingleObject(&hSRStopWait,
  149. g_pSRConfig->m_hSRStopEvent,
  150. StopCallback,
  151. NULL,
  152. INFINITE,
  153. WT_EXECUTEDEFAULT | WT_EXECUTEONLYONCE))
  154. {
  155. dwRc = GetLastError();
  156. trace(0, "! RegisterWaitForSingleObject : %ld", dwRc);
  157. goto done;
  158. }
  159. }
  160. else
  161. {
  162. // There is not much we can do here if we do not have the
  163. // Service handle. So we will just log an error and exit.
  164. dwRc = GetLastError();
  165. DebugTrace(TRACEID, "RegisterServiceCtrlHandler failed %d", dwRc);
  166. LogEvent(EVENTLOG_ERROR_TYPE, EVMSG_CTRLHANDLERNOTINSTALLED);
  167. }
  168. done:
  169. if (dwRc != ERROR_SUCCESS)
  170. {
  171. if (g_pEventHandler)
  172. {
  173. g_pEventHandler->OnStop();
  174. delete g_pEventHandler;
  175. g_pEventHandler = NULL;
  176. }
  177. m_Status.dwWin32ExitCode = (dwRc != ERROR_SERVICE_DISABLED) ?
  178. dwRc : ERROR_SUCCESS;
  179. SetStatus(SERVICE_STOPPED);
  180. if (dwRc != ERROR_SERVICE_DISABLED)
  181. LogEvent(EVENTLOG_ERROR_TYPE, EVMSG_FAILEDINI, &dwRc, sizeof(dwRc));
  182. }
  183. TLEAVE();
  184. }
  185. //
  186. // SetStatus:
  187. //
  188. void CNTService::SetStatus(DWORD dwState)
  189. {
  190. TENTER("CNTService::SetStatus");
  191. TRACE(TRACEID, "SetStatus(%lu, %lu)", m_hServiceStatus, dwState);
  192. m_Status.dwCurrentState = dwState;
  193. ::SetServiceStatus(m_hServiceStatus, &m_Status);
  194. TLEAVE();
  195. }
  196. void CNTService::OnStop()
  197. {
  198. TENTER("CNTService::OnStop");
  199. // BUGBUG what happens if the service has not started completely
  200. // yet ? We need to make sure that OnStop can only be called after
  201. // g_pEventHandler has been initialized.
  202. if (NULL != g_pEventHandler)
  203. {
  204. // Tell SCM we are stopping
  205. m_Status.dwWin32ExitCode = 0;
  206. m_Status.dwCheckPoint = 0;
  207. // we will stop in half the time we took to start or lesser
  208. m_Status.dwWaitHint = (SERVICE_WAIT_HINT/2)*1000;
  209. SetStatus(SERVICE_STOP_PENDING);
  210. // complete all tasks
  211. g_pEventHandler->SignalStop();
  212. }
  213. TLEAVE();
  214. }
  215. // OnInterrogate is called by the SCM to get information about the
  216. // current status of the service. Since this must report information
  217. // about the service immediately to the SCM, we will run this in the
  218. // same thread on which the handler function is called.
  219. void CNTService::OnInterrogate()
  220. {
  221. TENTER("CNTService::OnInterrogate");
  222. // report the status
  223. ::SetServiceStatus(m_hServiceStatus, &m_Status);
  224. TLEAVE();
  225. }
  226. //
  227. // Handler : static member function (callback) to handle commands from the
  228. // service control manager
  229. //
  230. void WINAPI SRServiceHandler(DWORD dwOpcode)
  231. {
  232. //
  233. // Get a pointer to the object
  234. //
  235. TENTER("CNTService::Handler");
  236. TRACE(TRACEID, "CNTService::Handler(%lu)", dwOpcode);
  237. switch (dwOpcode)
  238. {
  239. case SERVICE_CONTROL_STOP: // 1
  240. //
  241. // if someone disables the service explicitly
  242. // then disable all of SR
  243. //
  244. if (NULL != g_pSRService)
  245. {
  246. DWORD dwStart = 0;
  247. if (ERROR_SUCCESS == GetServiceStartup(s_cszServiceName, &dwStart))
  248. {
  249. if (dwStart == SERVICE_DISABLED || dwStart == SERVICE_DEMAND_START)
  250. {
  251. if (g_pEventHandler)
  252. g_pEventHandler->DisableSRS(NULL);
  253. break;
  254. }
  255. }
  256. else
  257. {
  258. trace(TRACEID, "! GetServiceStartup");
  259. }
  260. }
  261. //
  262. // else fallover
  263. //
  264. case SERVICE_CONTROL_SHUTDOWN: // 5
  265. // BUGBUG - g_pSRService should be accessed in critical section
  266. if (NULL != g_pSRService)
  267. {
  268. g_pSRService->OnStop();
  269. }
  270. break;
  271. case SERVICE_CONTROL_PAUSE: // 2
  272. case SERVICE_CONTROL_CONTINUE: // 3
  273. // we do not do anything here
  274. break;
  275. case SERVICE_CONTROL_INTERROGATE: // 4
  276. // BUGBUG - g_pSRService should be accessed in critical section
  277. if (NULL != g_pSRService)
  278. {
  279. g_pSRService->OnInterrogate();
  280. }
  281. break;
  282. default:
  283. break;
  284. }
  285. TLEAVE();
  286. }
  287. /////////////////////////////////////////////////////////////////////////////
  288. // Exported functions
  289. /////////////////////////////////////////////////////////////////////////////
  290. extern "C"
  291. {
  292. VOID WINAPI ServiceMain(
  293. DWORD dwArgc,
  294. LPWSTR *lpwzArgv )
  295. {
  296. // Initialize tracing
  297. InitAsyncTrace();
  298. TraceFunctEnter("ServiceMain");
  299. g_pSRService = new CNTService();
  300. if (NULL == g_pSRService)
  301. {
  302. // in this case we will just exit. This is because we cannot
  303. // report any status here.
  304. // SCM will assume that the service has failed since it did
  305. // not call RegisterServiceCtrlHandler().
  306. goto cleanup;
  307. }
  308. g_pEventHandler = NULL;
  309. g_pSRService->ServiceMain( dwArgc, NULL );
  310. cleanup:
  311. TraceFunctLeave();
  312. }
  313. BOOL WINAPI DllMain(
  314. HINSTANCE hInstance,
  315. DWORD dwReason,
  316. LPVOID /* lpReserved */
  317. )
  318. {
  319. if (dwReason == DLL_PROCESS_ATTACH)
  320. {
  321. DisableThreadLibraryCalls(hInstance);
  322. }
  323. else if (dwReason == DLL_PROCESS_DETACH)
  324. {
  325. }
  326. return TRUE;
  327. }
  328. // callback for service stop event
  329. void CALLBACK
  330. StopCallback(
  331. PVOID pv,
  332. BOOLEAN TimerOrWaitFired)
  333. {
  334. if (g_pEventHandler)
  335. {
  336. g_pEventHandler->OnStop();
  337. delete g_pEventHandler;
  338. g_pEventHandler = NULL;
  339. }
  340. if (g_pSRService)
  341. {
  342. g_pSRService->SetStatus(SERVICE_STOPPED);
  343. delete g_pSRService;
  344. g_pSRService = NULL;
  345. }
  346. TermAsyncTrace();
  347. }
  348. }