Leaked source code of windows server 2003
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.

489 lines
18 KiB

  1. /************************************************************************************************
  2. Copyright (c) 2001 Microsoft Corporation
  3. Module Name: Service.cpp.
  4. Abstract: Implements the CService class. See Service.h for details.
  5. Notes:
  6. History: 01/25/2001 - created, Luciano Passuello (lucianop).
  7. ************************************************************************************************/
  8. #include "stdafx.h"
  9. #include "Service.h"
  10. // static variables initialization
  11. const DWORD CService::dwStateNoChange = 0xFFFFFFFF;
  12. /************************************************************************************************
  13. Member: CService::CService, constructor, public.
  14. Synopsis: Initializes internal variables, such as event logging defaults.
  15. Effects:
  16. Arguments: [szName] - the SCM short name for the service.
  17. [szDisplay] - the SCM display name for the service.
  18. [dwType] - see CreateService for further documentation.
  19. Notes:
  20. History: 01/25/2001 - created, Luciano Passuello (lucianop).
  21. ************************************************************************************************/
  22. CService::CService(LPCTSTR szName, LPCTSTR szDisplay, DWORD dwType) :
  23. m_dwType(dwType)
  24. {
  25. ASSERT(!(NULL == szName));
  26. ASSERT(!(NULL == szDisplay));
  27. m_hServiceStatus = NULL;
  28. m_dwRequestedControl = 0;
  29. // Control Events
  30. m_hWatcherThread = NULL;
  31. m_dwState = 0;
  32. m_dwControlsAccepted = 0;
  33. m_dwCheckpoint = 0;
  34. m_dwWaitHint = 0;
  35. // Initialize event handles to NULL
  36. for(int i = 0; i < nNumServiceEvents; i++)
  37. m_hServiceEvent[i] = NULL;
  38. // Copy string names
  39. _tcsncpy(m_szName, szName, nMaxServiceLen);
  40. _tcsncpy(m_szDisplay, szDisplay, nMaxServiceLen);
  41. // Set up class critical section
  42. InitializeCriticalSection(&m_cs);
  43. }
  44. /************************************************************************************************
  45. Member: CService::~CService, destructor, public.
  46. Synopsis: Deinitializes internal variables.
  47. Notes:
  48. History: 01/25/2001 - created, Luciano Passuello (lucianop).
  49. ************************************************************************************************/
  50. CService::~CService()
  51. {
  52. DeleteCriticalSection(&m_cs);
  53. }
  54. /************************************************************************************************
  55. Member: CService::PreInit, destructor, public.
  56. Synopsis: Initialialization of variables. This is performed before launching the watcher
  57. thread and notifying status to the SCM.
  58. Notes: (*) If you override this, call the base class version in the beginning!!
  59. History: 01/25/2001 - created, Luciano Passuello (lucianop).
  60. ************************************************************************************************/
  61. void CService::PreInit()
  62. {
  63. // Initialize Events
  64. for(int i = 0; i < nNumServiceEvents; i++)
  65. {
  66. m_hServiceEvent[i] = CreateEvent(NULL, TRUE, FALSE, NULL);
  67. if(!m_hServiceEvent[i])
  68. {
  69. AbortService();
  70. }
  71. }
  72. }
  73. /************************************************************************************************
  74. Member: CService::PreInit, destructor, public.
  75. Synopsis: Initialialization of variables. This is performed before launching the watcher
  76. thread and notifying status to the SCM.
  77. Notes: (*) If you override this, call the base class version in the beginning!!
  78. History: 01/25/2001 - created, Luciano Passuello (lucianop).
  79. ************************************************************************************************/
  80. void CService::DeInit()
  81. {
  82. // Wait for the watcher thread to terminate
  83. if(m_hWatcherThread)
  84. {
  85. // Wait a reasonable amount of time
  86. WaitForSingleObject(m_hWatcherThread, 10000);
  87. CloseHandle(m_hWatcherThread);
  88. }
  89. // Uninitialize any resources created in Init()
  90. for(int i = 0 ; i < nNumServiceEvents ; i++)
  91. {
  92. if(m_hServiceEvent[i])
  93. CloseHandle(m_hServiceEvent[i]);
  94. }
  95. }
  96. /************************************************************************************************
  97. Member: CService::ServiceMainMember, protected
  98. Synopsis: does the main service thread processing. (ServiceMain() equivalent)
  99. Notes: This is delegated from the static thread entry-point.
  100. History: 01/25/2001 - created, Luciano Passuello (lucianop).
  101. ************************************************************************************************/
  102. void CService::ServiceMainMember(DWORD argc, LPTSTR* argv, LPHANDLER_FUNCTION pf,
  103. LPTHREAD_START_ROUTINE pfnWTP)
  104. {
  105. OnBeforeStart();
  106. PreInit();
  107. SetupHandlerInside(pf);
  108. ParseArgs(argc, argv);
  109. LaunchWatcherThread(pfnWTP);
  110. Init();
  111. OnAfterStart();
  112. Run();
  113. DeInit();
  114. }
  115. /************************************************************************************************
  116. Member: CService::SetupHandlerInside, protected
  117. Synopsis: Register the control handler for the service.
  118. Arguments: [lpHandlerProc] - pointer to the function implementing the SCM event handling.
  119. Notes:
  120. History: 01/25/2001 - created, Luciano Passuello (lucianop).
  121. ************************************************************************************************/
  122. bool CService::SetupHandlerInside(LPHANDLER_FUNCTION lpHandlerProc)
  123. {
  124. m_hServiceStatus = RegisterServiceCtrlHandler(m_szName, lpHandlerProc);
  125. if(!m_hServiceStatus)
  126. {
  127. AbortService();
  128. }
  129. SetStatus(SERVICE_START_PENDING, 1, 5000);
  130. return true;
  131. }
  132. /************************************************************************************************
  133. Member: CService::HandlerMember, protected
  134. Synopsis: Handles service start, stop, etc. requests from the SCM
  135. Arguments: [dwControl] - event request code.
  136. Notes:
  137. History: 01/25/2001 - created, Luciano Passuello (lucianop).
  138. ************************************************************************************************/
  139. void CService::HandlerMember(DWORD dwControl)
  140. {
  141. // Keep an additional control request of the same type
  142. // from coming in when you're already handling it
  143. if(m_dwRequestedControl == dwControl)
  144. return;
  145. switch(dwControl)
  146. {
  147. case SERVICE_CONTROL_STOP:
  148. m_dwRequestedControl = dwControl;
  149. // Notify the service to stop...
  150. OnStopRequest();
  151. SetEvent(m_hServiceEvent[STOP]);
  152. break;
  153. case SERVICE_CONTROL_PAUSE:
  154. m_dwRequestedControl = dwControl;
  155. // Notify the service to pause...
  156. OnPauseRequest();
  157. SetEvent(m_hServiceEvent[PAUSE]);
  158. break;
  159. case SERVICE_CONTROL_CONTINUE:
  160. if(GetStatus() != SERVICE_RUNNING)
  161. {
  162. m_dwRequestedControl = dwControl;
  163. // Notify the service to continue...
  164. OnContinueRequest();
  165. SetEvent(m_hServiceEvent[CONTINUE]);
  166. }
  167. break;
  168. case SERVICE_CONTROL_SHUTDOWN:
  169. m_dwRequestedControl = dwControl;
  170. OnShutdownRequest();
  171. SetEvent(m_hServiceEvent[SHUTDOWN]);
  172. break;
  173. case SERVICE_CONTROL_INTERROGATE:
  174. // Return current status on interrogation
  175. SetStatus(GetStatus());
  176. break;
  177. default: // User Defined
  178. m_dwRequestedControl = dwControl;
  179. HandleUserDefined(dwControl);
  180. }
  181. }
  182. void CService::LaunchWatcherThread(LPTHREAD_START_ROUTINE pfnWTP)
  183. {
  184. if(NULL != pfnWTP)
  185. {
  186. m_hWatcherThread = (HANDLE)_beginthreadex(0, 0, (unsigned (WINAPI*)(void*))pfnWTP, 0, 0, NULL);
  187. }
  188. if(!m_hWatcherThread)
  189. {
  190. AbortService();
  191. }
  192. }
  193. DWORD CService::WatcherThreadMemberProc()
  194. {
  195. DWORD dwWait = 0;
  196. bool bControlWait = true;
  197. // Wait for any events to signal
  198. while(bControlWait)
  199. {
  200. dwWait = WaitForMultipleObjects(nNumServiceEvents, m_hServiceEvent, FALSE, INFINITE);
  201. switch(dwWait - WAIT_OBJECT_0)
  202. {
  203. case STOP:
  204. bControlWait = false;
  205. break;
  206. case PAUSE:
  207. OnPause();
  208. ResetEvent(m_hServiceEvent[PAUSE]);
  209. break;
  210. case CONTINUE:
  211. OnContinue();
  212. ResetEvent(m_hServiceEvent[CONTINUE]);
  213. break;
  214. case SHUTDOWN:
  215. OnShutdown();
  216. bControlWait = false;
  217. break;
  218. }
  219. }
  220. //Wait for the global shutdown event
  221. while(1)
  222. {
  223. dwWait = WaitForSingleObject(g_hShutDown, 5000);
  224. if(WAIT_OBJECT_0==dwWait || WAIT_ABANDONED == dwWait)
  225. {
  226. break;
  227. }
  228. else if(WAIT_TIMEOUT == dwWait)
  229. {
  230. SetStatus(SERVICE_STOP_PENDING, 1, 10000);
  231. }
  232. }
  233. return 0;
  234. }
  235. void CService::SetStatus(DWORD dwNewState, DWORD dwNewCheckpoint, DWORD dwNewHint, DWORD dwNewControls,
  236. DWORD dwExitCode, DWORD dwSpecificExit)
  237. {
  238. // The only state that can set Exit Codes is STOPPED
  239. // Fix if necessary, just in case not set properly.
  240. if(dwNewState != SERVICE_STOPPED)
  241. {
  242. dwExitCode = S_OK;
  243. dwSpecificExit = 0;
  244. }
  245. // Only pending states can set checkpoints or wait hints,
  246. // and pending states *must* set wait hints
  247. if((SERVICE_STOPPED == dwNewState) || (SERVICE_PAUSED == dwNewState) || (SERVICE_RUNNING == dwNewState))
  248. {
  249. // Requires hint and checkpoint == 0
  250. // Fix it so that NO_CHANGE from previous state doesn't cause nonzero
  251. dwNewHint = 0;
  252. dwNewCheckpoint = 0;
  253. }
  254. else
  255. {
  256. // Requires hint and checkpoint != 0
  257. if(dwNewHint <= 0 || dwNewCheckpoint <=0)
  258. {
  259. AbortService();
  260. }
  261. }
  262. // Function can be called by multiple threads - protect member data
  263. EnterCriticalSection(&m_cs);
  264. // Alter states if changing
  265. m_dwState = dwNewState;
  266. if(dwNewCheckpoint != dwStateNoChange)
  267. {
  268. m_dwCheckpoint = dwNewCheckpoint;
  269. }
  270. if(dwNewHint != dwStateNoChange)
  271. {
  272. m_dwWaitHint = dwNewHint;
  273. }
  274. if(dwNewControls != dwStateNoChange)
  275. {
  276. m_dwControlsAccepted = dwNewControls;
  277. }
  278. SERVICE_STATUS ss = {m_dwType, m_dwState, m_dwControlsAccepted, dwExitCode, dwSpecificExit, m_dwCheckpoint, m_dwWaitHint};
  279. LeaveCriticalSection(&m_cs);
  280. SetServiceStatus(m_hServiceStatus, &ss);
  281. }
  282. /************************************************************************************************
  283. Member: CService::AbortService, protected
  284. Synopsis: Generic error handler, call this when you fall in to a critical error and
  285. must abort the service.
  286. Arguments: [dwErrorNum] - Error code reported back to SCM.
  287. Notes:
  288. History: 01/31/2001 - created, Luciano Passuello (lucianop).
  289. ************************************************************************************************/
  290. void CService::AbortService(DWORD dwErrorNum /*= GetLastError()*/)
  291. {
  292. // clean up service and stop service notifying error to the SCM
  293. OnStopRequest();
  294. DeInit();
  295. OnStop(dwErrorNum);
  296. ExitProcess(dwErrorNum);
  297. }
  298. /************************************************************************************************
  299. Member: CService::Init, overridable, public.
  300. Synopsis: Override this to implement initialization code for your specific service.
  301. Notes:
  302. History: 01/25/2001 - created, Luciano Passuello (lucianop).
  303. ************************************************************************************************/
  304. void CService::Init()
  305. {}
  306. /************************************************************************************************
  307. Member: CService::HandleUserDefined, overridable, public.
  308. Synopsis: Override this to implement custom SCM requests to your service.
  309. Notes:
  310. History: 01/25/2001 - created, Luciano Passuello (lucianop).
  311. ************************************************************************************************/
  312. void CService::HandleUserDefined(DWORD /*dwControl*/)
  313. {}
  314. /************************************************************************************************
  315. Member: CService::OnPause, overridable, public.
  316. Synopsis: Override this to implement code that runs when the service pauses.
  317. Notes:
  318. History: 01/25/2001 - created, Luciano Passuello (lucianop).
  319. ************************************************************************************************/
  320. void CService::OnPause()
  321. {}
  322. /************************************************************************************************
  323. Member: CService::OnContinue, overridable, public.
  324. Synopsis: Override this to implement code that runs when the service resumes from a pause.
  325. Notes:
  326. History: 01/25/2001 - created, Luciano Passuello (lucianop).
  327. ************************************************************************************************/
  328. void CService::OnContinue()
  329. {}
  330. /************************************************************************************************
  331. Member: CService::OnShutdown, overridable, public.
  332. Synopsis: Override this to implement code that runs when service is stopped by a shutdown.
  333. Notes:
  334. History: 01/25/2001 - created, Luciano Passuello (lucianop).
  335. ************************************************************************************************/
  336. void CService::OnShutdown()
  337. {}
  338. /************************************************************************************************
  339. Member: CService::ParseArgs, overridable, public.
  340. Synopsis: Override this to implement parsing of service command line parameters.
  341. Notes:
  342. History: 01/25/2001 - created, Luciano Passuello (lucianop).
  343. ************************************************************************************************/
  344. void CService::ParseArgs(DWORD /*argc*/, LPTSTR* /*argv*/)
  345. {}
  346. /************************************************************************************************
  347. Member: CService::OnBeforeStart, overridable, public.
  348. Synopsis: Override this to add code that's run before trying to start the service.
  349. Notes: A common use would be to log that the service will try to start.
  350. History: 01/25/2001 - created, Luciano Passuello (lucianop).
  351. ************************************************************************************************/
  352. void CService::OnBeforeStart()
  353. {}
  354. /************************************************************************************************
  355. Member: CService::OnAfterStart, overridable, public.
  356. Synopsis: Override this to add code that's run just after the service was started.
  357. Notes: A common use would be to log that the service was successfully started.
  358. History: 01/25/2001 - created, Luciano Passuello (lucianop).
  359. ************************************************************************************************/
  360. void CService::OnAfterStart()
  361. {}
  362. /************************************************************************************************
  363. Member: CService::OnStopRequest, overridable, public.
  364. Synopsis: Override this to add code that's run when the service receives a stop request.
  365. Notes: A common use is to log that the service received the stop request.
  366. This function DOESN'T run in the main thread. Protect resources if needed.
  367. History: 02/05/2001 - created, Luciano Passuello (lucianop).
  368. ************************************************************************************************/
  369. void CService::OnStopRequest()
  370. {}
  371. /************************************************************************************************
  372. Member: CService::OnPauseRequest, overridable, public.
  373. Synopsis: Override this to add code that's run when the service receives a pause request.
  374. Notes: A common use is to log that the service received the pause request.
  375. This function DOESN'T run in the main thread. Protect resources if needed.
  376. History: 02/05/2001 - created, Luciano Passuello (lucianop).
  377. ************************************************************************************************/
  378. void CService::OnPauseRequest()
  379. {}
  380. /************************************************************************************************
  381. Member: CService::OnContinueRequest, overridable, public.
  382. Synopsis: Override this to add code that's run when the service receives a continue request.
  383. Notes: A common use is to log that the service received the continue request.
  384. This function DOESN'T run in the main thread. Protect resources if needed.
  385. History: 02/05/2001 - created, Luciano Passuello (lucianop).
  386. ************************************************************************************************/
  387. void CService::OnContinueRequest()
  388. {}
  389. /************************************************************************************************
  390. Member: CService::OnShutdownRequest, overridable, public.
  391. Synopsis: Override this to add code that's run when the service receives a shutdown request.
  392. Notes: A common use is to log that the service received the shutdown request.
  393. This function DOESN'T run in the main thread. Protect resources if needed.
  394. History: 02/05/2001 - created, Luciano Passuello (lucianop).
  395. ************************************************************************************************/
  396. void CService::OnShutdownRequest()
  397. {}
  398. // End of file Service.cpp.