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.

690 lines
14 KiB

  1. /*++
  2. Copyright (c) 1997 Microsoft Corporation
  3. Module Name :
  4. svcinfo.cpp
  5. Abstract:
  6. This module contains the common code for the sti services which involves the
  7. Service Controller dispatch functions.
  8. Author:
  9. Vlad Sadovsky (vlads) 22-Sep-1997
  10. Environment:
  11. User Mode - Win32
  12. Revision History:
  13. 22-Sep-1997 VladS created
  14. --*/
  15. //
  16. // Include Headers
  17. //
  18. #include "cplusinc.h"
  19. #include "sticomm.h"
  20. #include <svcinfo.h>
  21. BOOL g_fIgnoreSC = TRUE;
  22. SVC_INFO::SVC_INFO(
  23. IN LPCTSTR lpszServiceName,
  24. IN TCHAR * lpszModuleName,
  25. IN PFN_SERVICE_SPECIFIC_INITIALIZE pfnInitialize,
  26. IN PFN_SERVICE_SPECIFIC_CLEANUP pfnCleanup,
  27. IN PFN_SERVICE_SPECIFIC_PNPPWRHANDLER pfnPnpPower
  28. )
  29. /*++
  30. Desrcription:
  31. Contructor for SVC_INFO class.
  32. This constructs a new service info object for the service specified.
  33. Arguments:
  34. lpszServiceName
  35. name of the service to be created.
  36. lpszModuleName
  37. name of the module for loading string resources.
  38. pfnInitialize
  39. pointer to function to be called for initialization of
  40. service specific data
  41. pfnCleanup
  42. pointer to function to be called for cleanup of service
  43. specific data
  44. --*/
  45. {
  46. ASSERT( pfnInitialize != NULL && pfnCleanup != NULL && pfnPnpPower!=NULL);
  47. m_sServiceName.Copy(lpszServiceName) ;
  48. m_sModuleName.Copy(lpszModuleName);
  49. //
  50. // Initialize the service status structure.
  51. //
  52. m_svcStatus.dwServiceType = SERVICE_WIN32_SHARE_PROCESS;
  53. m_svcStatus.dwCurrentState = SERVICE_STOPPED;
  54. m_svcStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP
  55. | SERVICE_ACCEPT_PAUSE_CONTINUE
  56. | SERVICE_ACCEPT_SHUTDOWN;
  57. m_svcStatus.dwWin32ExitCode = NO_ERROR;
  58. m_svcStatus.dwServiceSpecificExitCode = NO_ERROR;
  59. m_svcStatus.dwCheckPoint = 0;
  60. m_svcStatus.dwWaitHint = 0;
  61. //
  62. // Initialize Call back functions
  63. //
  64. m_pfnInitialize = pfnInitialize;
  65. m_pfnCleanup = pfnCleanup;
  66. m_pfnPnpPower = pfnPnpPower;
  67. m_dwSignature = SIGNATURE_SVC;
  68. m_hShutdownEvent= NULL;
  69. return;
  70. } // SVC_INFO::SVC_INFO()
  71. SVC_INFO::~SVC_INFO( VOID)
  72. /*++
  73. Description:
  74. Cleanup the SvcInfo object. If the service is not already
  75. terminated, it terminates the service before cleanup.
  76. Arguments:
  77. None
  78. Returns:
  79. None
  80. --*/
  81. {
  82. if ( m_hShutdownEvent != NULL) {
  83. ::CloseHandle( m_hShutdownEvent);
  84. }
  85. m_dwSignature = SIGNATURE_SVC_FREE;
  86. } // SVC_INFO::~SVC_INFO()
  87. DWORD
  88. SVC_INFO::StartServiceOperation(
  89. IN PFN_SERVICE_CTRL_HANDLER pfnCtrlHandler
  90. )
  91. /*++
  92. Description:
  93. Starts the operation of service instantiated in the given
  94. Service Info Object.
  95. Arguments:
  96. pfnCtrlHandler
  97. pointer to a callback function for handling dispatch of
  98. service controller requests. A separate function is required
  99. since Service Controller call back function does not send
  100. context information.
  101. Returns:
  102. NO_ERROR on success and Win32 error code if any failure.
  103. --*/
  104. {
  105. DWORD err;
  106. DWORD cbBuffer;
  107. BOOL fInitCalled = FALSE;
  108. if ( !IsValid()) {
  109. //
  110. // Not successfully initialized.
  111. //
  112. return ( ERROR_INVALID_FUNCTION);
  113. }
  114. if ( !g_fIgnoreSC ) {
  115. m_hsvcStatus = RegisterServiceCtrlHandler(
  116. QueryServiceName(),
  117. pfnCtrlHandler
  118. );
  119. //
  120. // Register the Control Handler routine.
  121. //
  122. if( m_hsvcStatus == NULL_SERVICE_STATUS_HANDLE ) {
  123. err = GetLastError();
  124. goto Cleanup;
  125. }
  126. } else {
  127. m_hsvcStatus = NULL_SERVICE_STATUS_HANDLE;
  128. }
  129. //
  130. // Update the service status.
  131. //
  132. err = UpdateServiceStatus( SERVICE_START_PENDING,
  133. NO_ERROR,
  134. 1,
  135. SERVICE_START_WAIT_HINT );
  136. if( err != NO_ERROR ) {
  137. goto Cleanup;
  138. }
  139. //
  140. // Initialize the service common components
  141. //
  142. #ifdef BUGBUG
  143. if ( !InitializeNTSecurity()) {
  144. err = GetLastError();
  145. goto Cleanup;
  146. }
  147. #endif
  148. //
  149. // Initialize the various service specific components.
  150. //
  151. err = ( *m_pfnInitialize)( this);
  152. fInitCalled = TRUE;
  153. if( err != NO_ERROR ) {
  154. goto Cleanup;
  155. }
  156. //
  157. // Create shutdown event.
  158. //
  159. m_hShutdownEvent = CreateEvent( NULL, // lpsaSecurity
  160. TRUE, // fManualReset
  161. FALSE, // fInitialState
  162. NULL ); // lpszEventName
  163. if( m_hShutdownEvent == NULL )
  164. {
  165. err = GetLastError();
  166. goto Cleanup;
  167. }
  168. //
  169. // Update the service status.
  170. //
  171. err = UpdateServiceStatus( SERVICE_RUNNING,
  172. NO_ERROR,
  173. 0,
  174. 0 );
  175. if( err != NO_ERROR ) {
  176. goto Cleanup;
  177. }
  178. //
  179. // Wait for the shutdown event.
  180. //
  181. err = WaitForSingleObject( m_hShutdownEvent,
  182. INFINITE );
  183. if ( err != WAIT_OBJECT_0) {
  184. //
  185. // Error. Unable to wait for single object.
  186. //
  187. }
  188. //
  189. // Stop time. Tell the Service Controller that we're stopping,
  190. // then terminate the various service components.
  191. //
  192. UpdateServiceStatus( SERVICE_STOP_PENDING,
  193. 0,
  194. 1,
  195. SERVICE_STOP_WAIT_HINT );
  196. //
  197. // Destroy the shutdown event.
  198. //
  199. if( m_hShutdownEvent != NULL ) {
  200. if ( ! CloseHandle( m_hShutdownEvent ) ) {
  201. err = GetLastError();
  202. }
  203. m_hShutdownEvent = NULL;
  204. }
  205. //
  206. // Update the service status.
  207. //
  208. //
  209. // Log successful start
  210. err = UpdateServiceStatus( SERVICE_RUNNING,
  211. NO_ERROR,
  212. 0,
  213. 0 );
  214. if( err != NO_ERROR )
  215. {
  216. goto Cleanup;
  217. }
  218. return TRUE;
  219. Cleanup:
  220. if ( fInitCalled) {
  221. //
  222. // Cleanup partially initialized modules
  223. //
  224. DWORD err1 = ( *m_pfnCleanup)( this);
  225. if ( err1 != NO_ERROR) {
  226. //
  227. // Compound errors possible
  228. //
  229. if ( err != NO_ERROR) {
  230. }
  231. }
  232. }
  233. //
  234. // If we managed to actually connect to the Service Controller,
  235. // then tell it that we're stopped.
  236. //
  237. if ( m_hsvcStatus != NULL_SERVICE_STATUS_HANDLE )
  238. {
  239. UpdateServiceStatus( SERVICE_STOPPED,
  240. err,
  241. 0,
  242. 0 );
  243. }
  244. return ( err);
  245. } // SVC_INFO::StartServiceOperation()
  246. DWORD
  247. SVC_INFO::UpdateServiceStatus(
  248. IN DWORD dwState,
  249. IN DWORD dwWin32ExitCode,
  250. IN DWORD dwCheckPoint,
  251. IN DWORD dwWaitHint )
  252. /*++
  253. Description:
  254. Updates the local copy status of service controller status
  255. and reports it to the service controller.
  256. Arguments:
  257. dwState - New service state.
  258. dwWin32ExitCode - Service exit code.
  259. dwCheckPoint - Check point for lengthy state transitions.
  260. dwWaitHint - Wait hint for lengthy state transitions.
  261. Returns:
  262. NO_ERROR on success and returns Win32 error if failure.
  263. On success the status is reported to service controller.
  264. --*/
  265. {
  266. m_svcStatus.dwCurrentState = dwState;
  267. m_svcStatus.dwWin32ExitCode = dwWin32ExitCode;
  268. m_svcStatus.dwCheckPoint = dwCheckPoint;
  269. m_svcStatus.dwWaitHint = dwWaitHint;
  270. if ( !g_fIgnoreSC ) {
  271. return ReportServiceStatus();
  272. } else {
  273. return ( NO_ERROR);
  274. }
  275. } // SVC_INFO::UpdateServiceStatus()
  276. DWORD
  277. SVC_INFO::ReportServiceStatus( VOID)
  278. /*++
  279. Description:
  280. Wraps the call to SetServiceStatus() function.
  281. Prints the service status data if need be
  282. Arguments:
  283. None
  284. Returns:
  285. NO_ERROR if successful. other Win32 error code on failure.
  286. If successfull the new status has been reported to the service
  287. controller.
  288. --*/
  289. {
  290. DWORD err = NO_ERROR;
  291. if ( !g_fIgnoreSC ) {
  292. if( !SetServiceStatus( m_hsvcStatus, &m_svcStatus ) ) {
  293. err = GetLastError();
  294. }
  295. } else {
  296. err = NO_ERROR;
  297. }
  298. return err;
  299. } // SVC_INFO::ReportServiceStatus()
  300. VOID
  301. SVC_INFO::ServiceCtrlHandler ( IN DWORD dwOpCode)
  302. /*++
  303. Description:
  304. This function received control requests from the service controller.
  305. It runs in the context of service controller's dispatcher thread and
  306. performs the requested function.
  307. ( Note: Avoid time consuming operations in this function.)
  308. Arguments:
  309. dwOpCode
  310. indicates the requested operation. This should be
  311. one of the SERVICE_CONTROL_* manifests.
  312. Returns:
  313. None. If successful, then the state of the service might be changed.
  314. Note:
  315. if an operation ( especially SERVICE_CONTROL_STOP) is very lengthy,
  316. then this routine should report a STOP_PENDING status and create
  317. a worker thread to do the dirty work. The worker thread would then
  318. perform the necessary work and for reporting timely wait hints and
  319. final SERVICE_STOPPED status.
  320. --*/
  321. {
  322. //
  323. // Interpret the opcode.
  324. //
  325. switch( dwOpCode )
  326. {
  327. case SERVICE_CONTROL_INTERROGATE :
  328. InterrogateService();
  329. break;
  330. case SERVICE_CONTROL_STOP :
  331. StopService();
  332. break;
  333. case SERVICE_CONTROL_PAUSE :
  334. PauseService();
  335. break;
  336. case SERVICE_CONTROL_CONTINUE :
  337. ContinueService();
  338. break;
  339. case SERVICE_CONTROL_SHUTDOWN :
  340. ShutdownService();
  341. break;
  342. default :
  343. ASSERTSZ(FALSE,TEXT("Unrecognized Service Opcode"));
  344. break;
  345. }
  346. //
  347. // Report the current service status back to the Service
  348. // Controller. The workers called to implement the OpCodes
  349. // should set the m_svcStatus.dwCurrentState field if
  350. // the service status changed.
  351. //
  352. ReportServiceStatus();
  353. } // SVC_INFO::ServiceCtrlHandler()
  354. VOID
  355. SVC_INFO::InterrogateService( VOID )
  356. /*++
  357. Description:
  358. This function interrogates with the service status.
  359. Actually, nothing needs to be done here; the
  360. status is always updated after a service control.
  361. We have this function here to provide useful
  362. debug info.
  363. --*/
  364. {
  365. return;
  366. } // SVC_INFO::InterrogateService()
  367. VOID
  368. SVC_INFO::StopService( VOID )
  369. /*++
  370. Description:
  371. Stops the service. If the stop cannot be performed in a
  372. timely manner, a worker thread needs to be created to do the
  373. original cleanup work.
  374. Returns:
  375. None. If successful, then the service will be stopped.
  376. The final action of this function is signal the handle for
  377. shutdown event. This will release the main thread which does
  378. necessary cleanup work.
  379. --*/
  380. {
  381. m_svcStatus.dwCurrentState = SERVICE_STOP_PENDING;
  382. m_svcStatus.dwCheckPoint = 0;
  383. SetEvent( m_hShutdownEvent);
  384. return;
  385. } // SVC_INFO::StopService()
  386. VOID
  387. SVC_INFO::PauseService( VOID )
  388. /*++
  389. Description:
  390. This function pauses the service. When the service is paused,
  391. no new user sessions are to be accepted, but existing connections
  392. are not effected.
  393. This function must update the SERVICE_STATUS::dwCurrentState
  394. field before returning.
  395. Returns:
  396. None. If successful the service is paused.
  397. --*/
  398. {
  399. m_svcStatus.dwCurrentState = SERVICE_PAUSED;
  400. return;
  401. } // SVC_INFO::PauseService()
  402. VOID
  403. SVC_INFO::ContinueService( VOID )
  404. /*++
  405. Description:
  406. This function restarts ( continues) a paused service. This
  407. will return the service to the running state.
  408. This function must update the m_svcStatus.dwCurrentState
  409. field to running mode before returning.
  410. Returns:
  411. None. If successful then the service is running.
  412. --*/
  413. {
  414. m_svcStatus.dwCurrentState = SERVICE_RUNNING;
  415. return;
  416. } // SVC_INFO::ContinueService()
  417. VOID
  418. SVC_INFO::ShutdownService( VOID )
  419. /*++
  420. Description:
  421. This function performs the shutdown on a service.
  422. This is called during system shutdown.
  423. This function is time constrained. The service controller gives a
  424. maximum of 20 seconds for shutdown for all active services.
  425. Only timely operations should be performed in this function.
  426. Returns:
  427. None. If successful, the service is shutdown.
  428. --*/
  429. {
  430. DWORD dwCurrentState;
  431. //
  432. // Verify state of the service
  433. //
  434. dwCurrentState = QueryCurrentServiceState();
  435. if ((dwCurrentState !=SERVICE_PAUSED) &&
  436. (dwCurrentState !=SERVICE_RUNNING) ) {
  437. ASSERT( FALSE);
  438. return;
  439. }
  440. m_svcStatus.dwCurrentState = SERVICE_STOP_PENDING;
  441. m_svcStatus.dwCheckPoint = 0;
  442. SetEvent( m_hShutdownEvent);
  443. //
  444. // Stop time. Tell the Service Controller that we're stopping,
  445. // then terminate the various service components.
  446. //
  447. UpdateServiceStatus( SERVICE_STOP_PENDING,
  448. 0,
  449. 1,
  450. SERVICE_STOP_WAIT_HINT );
  451. DWORD err = ( *m_pfnCleanup)( this);
  452. UpdateServiceStatus( SERVICE_STOPPED,
  453. err,
  454. 0,
  455. 0 );
  456. return;
  457. } // SVC_INFO::ShutdownService()
  458. //
  459. // IUnknown methods. Used only for reference counting
  460. //
  461. STDMETHODIMP
  462. SVC_INFO::QueryInterface( REFIID riid, LPVOID * ppvObj)
  463. {
  464. return E_FAIL;
  465. }
  466. STDMETHODIMP_(ULONG)
  467. SVC_INFO::AddRef( void)
  468. {
  469. ::InterlockedIncrement(&m_cRef);
  470. return m_cRef;
  471. }
  472. STDMETHODIMP_(ULONG)
  473. SVC_INFO::Release( void)
  474. {
  475. LONG cNew;
  476. if(!(cNew = ::InterlockedDecrement(&m_cRef))) {
  477. delete this;
  478. }
  479. return cNew;
  480. }
  481. /************************ End of File ***********************/