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.

818 lines
21 KiB

  1. //+-----------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. //
  5. // Copyright (c) Microsoft Corporation
  6. //
  7. // File: ktcontrol.cxx
  8. //
  9. // Contents: Kerberos Tunneller, service infrastructure
  10. //
  11. // History: 28-Jun-2001 t-ryanj Created
  12. //
  13. //------------------------------------------------------------------------
  14. #include "ktdebug.h"
  15. #include "ktcontrol.h"
  16. #include "ktcore.h"
  17. #include "ktmem.h"
  18. #include "ktsock.h"
  19. #include "kthttp.h"
  20. VOID WINAPI
  21. KtMainServiceEntry(
  22. IN DWORD argc,
  23. IN LPTSTR argv[]
  24. );
  25. DWORD WINAPI
  26. KtControlHandlerEx(
  27. DWORD dwControl,
  28. DWORD dwEventType,
  29. PVOID pvEventData,
  30. PVOID pvContext
  31. );
  32. BOOL
  33. KtStartupInit(
  34. VOID
  35. );
  36. VOID
  37. KtContinueService(
  38. VOID
  39. );
  40. VOID
  41. KtPauseService(
  42. VOID
  43. );
  44. VOID
  45. KtStopService(
  46. IN DWORD dwWin32ErrorCode
  47. );
  48. BOOL
  49. KtBeginStateTransition(
  50. IN DWORD dwUltimateState,
  51. IN DWORD dwWaitHint
  52. );
  53. BOOL
  54. KtFinishStateTransition(
  55. VOID
  56. );
  57. HANDLE KtIocp = NULL;
  58. HANDLE KtStateTransitionLock = NULL;
  59. LPTSTR KtServiceName = TEXT("kerbtunnel");
  60. SERVICE_TABLE_ENTRY KtServiceTable[] = { { KtServiceName, KtMainServiceEntry },
  61. { NULL, NULL } };
  62. SERVICE_STATUS KtServiceStatus = {0};
  63. SERVICE_STATUS_HANDLE KtServiceStatusHandle = NULL;
  64. //+-------------------------------------------------------------------------
  65. //
  66. // Function: KtStartServiceCtrlDispatcher
  67. //
  68. // Synopsis: Starts the Service Control Dispatcher.
  69. //
  70. // Effects:
  71. //
  72. // Arguments:
  73. //
  74. // Requires:
  75. //
  76. // Returns: Success value.
  77. // If FALSE, GetLastError() for more info.
  78. //
  79. // Notes:
  80. //
  81. //
  82. //--------------------------------------------------------------------------
  83. BOOL
  84. KtStartServiceCtrlDispatcher(
  85. VOID
  86. )
  87. {
  88. return StartServiceCtrlDispatcher( KtServiceTable );
  89. }
  90. //+-------------------------------------------------------------------------
  91. //
  92. // Function: KtFinishStateTransition
  93. //
  94. // Synopsis: Closes out a state transition, reporting the new state
  95. // to service control.
  96. //
  97. // Effects: Modifies KtServiceStatus, the global service state.
  98. //
  99. // Signals KtStateTransitionLock, signifying the completion of
  100. // a state transition.
  101. //
  102. // Arguments:
  103. //
  104. // Requires:
  105. //
  106. // Returns: TRUE on success, FALSE on failure.
  107. // If FALSE, GetLastError() for details.
  108. //
  109. // Notes:
  110. //
  111. //
  112. //--------------------------------------------------------------------------
  113. BOOL
  114. KtFinishStateTransition(
  115. VOID
  116. )
  117. {
  118. BOOL fSuccess = TRUE;
  119. DWORD dwUltimateState;
  120. //
  121. // First, we determine what state we want to be in at the end of the
  122. // transition.
  123. //
  124. switch( KtServiceStatus.dwCurrentState )
  125. {
  126. case SERVICE_START_PENDING:
  127. case SERVICE_CONTINUE_PENDING:
  128. dwUltimateState = SERVICE_RUNNING;
  129. break;
  130. case SERVICE_STOP_PENDING:
  131. dwUltimateState = SERVICE_STOPPED;
  132. break;
  133. case SERVICE_PAUSE_PENDING:
  134. dwUltimateState = SERVICE_PAUSED;
  135. break;
  136. default:
  137. DebugLog( DEB_WARN, "%s(%d): Unhandled case: 0x%x.\n", __FILE__, __LINE__, KtServiceStatus.dwCurrentState );
  138. SetLastError( ERROR_INVALID_PARAMETER );
  139. DsysAssert( KtServiceStatus.dwCurrentState == SERVICE_START_PENDING ||
  140. KtServiceStatus.dwCurrentState == SERVICE_CONTINUE_PENDING ||
  141. KtServiceStatus.dwCurrentState == SERVICE_STOP_PENDING ||
  142. KtServiceStatus.dwCurrentState == SERVICE_PAUSE_PENDING );
  143. goto Error;
  144. }
  145. //
  146. // Time to construct and set the new state.
  147. //
  148. // Checkpoint and WaitHint are always 0 for non-pending states,
  149. // and we only report errors when punting, which is handled by
  150. // a different routine.
  151. //
  152. KtServiceStatus.dwCheckPoint = KtServiceStatus.dwWaitHint = 0;
  153. KtServiceStatus.dwWin32ExitCode = NO_ERROR;
  154. KtServiceStatus.dwServiceSpecificExitCode = 0;
  155. KtServiceStatus.dwCurrentState = dwUltimateState;
  156. if( !SetServiceStatus( KtServiceStatusHandle, &KtServiceStatus ) )
  157. {
  158. DebugLog( DEB_ERROR, "%s(%d): Error from SetServiceStatus: 0x%x.\n", __FILE__, __LINE__, GetLastError() );
  159. goto Error;
  160. }
  161. //
  162. // Now we signal the StateTransition event, indicating that it's
  163. // alright to begin a new state transition.
  164. //
  165. if( !SetEvent( KtStateTransitionLock ) )
  166. {
  167. DebugLog( DEB_ERROR, "%s(%d): Error from SetEvent: 0x%x.\n", __FILE__, __LINE__, GetLastError() );
  168. goto Error;
  169. }
  170. DebugLog( DEB_TRACE, "%s(%d): State transition completed.\n", __FILE__, __LINE__ );
  171. Cleanup:
  172. return fSuccess;
  173. Error:
  174. /* TODO: Event log, and maybe something drastic. */
  175. fSuccess = FALSE;
  176. goto Cleanup;
  177. }
  178. //+-------------------------------------------------------------------------
  179. //
  180. // Function: KtBeginStateTransition
  181. //
  182. // Synopsis: Enters a state transition, reporting an appropriate pending
  183. // state to Service Control and requesting dwWaitHint millisec
  184. // to complete the transition.
  185. //
  186. // Effects: Modifies KtServiceStatus, the global service status.
  187. // Waits for KtStateTransitionLock to begin state transition.
  188. //
  189. // Arguments: dwUltimateState - One of SERVICE_STOPPED, SERVICE_RUNNING,
  190. // or SERVICE_PAUSED.
  191. //
  192. // dwWaitHint - Estimated millisec before next state report.
  193. // Service Control may kill the service if it does not
  194. // report again within the time specified. (See Notes.)
  195. //
  196. // Requires:
  197. //
  198. // Returns: Success value. If FALSE, GetLastError() for details.
  199. //
  200. // Notes: If 0 is supplied as dwWaitHint, this call will go directly
  201. // to the ultimate state rather than a pending state.
  202. //
  203. //--------------------------------------------------------------------------
  204. BOOL
  205. KtBeginStateTransition(
  206. IN DWORD dwUltimateState,
  207. IN DWORD dwWaitHint
  208. )
  209. {
  210. BOOL fSuccess = TRUE;
  211. DWORD dwPendingState = 0;
  212. //
  213. // dwUltimateState is our target state, so determine which pending
  214. // state to be in in the meantime.
  215. //
  216. switch( dwUltimateState )
  217. {
  218. case SERVICE_STOPPED:
  219. dwPendingState = SERVICE_STOP_PENDING;
  220. break;
  221. case SERVICE_RUNNING:
  222. dwPendingState = (KtServiceStatus.dwCurrentState == SERVICE_PAUSED) ? SERVICE_CONTINUE_PENDING : SERVICE_START_PENDING;
  223. break;
  224. case SERVICE_PAUSED:
  225. dwPendingState = SERVICE_PAUSE_PENDING;
  226. break;
  227. default:
  228. DebugLog( DEB_WARN, "%s(%d): Invalid parameter to KtBeginStateTransition: 0x%x.\n", dwUltimateState );
  229. SetLastError(ERROR_INVALID_PARAMETER);
  230. DsysAssert( dwUltimateState == SERVICE_STOPPED ||
  231. dwUltimateState == SERVICE_RUNNING ||
  232. dwUltimateState == SERVICE_PAUSED );
  233. goto Error;
  234. }
  235. //
  236. // Wait for any pending state transitions to complete before
  237. // starting a new one.
  238. //
  239. WaitForSingleObjectEx( KtStateTransitionLock, INFINITE, FALSE );
  240. DebugLog( DEB_TRACE, "%s(%d): Beginning State Transition.\n", __FILE__, __LINE__ );
  241. //
  242. // If dwWaitHint was given as 0, we want to go right ahead
  243. // and set the target state, otherwise we set the appropriate
  244. // pending state.
  245. //
  246. if( dwWaitHint == 0 )
  247. {
  248. if( !KtFinishStateTransition() )
  249. goto Error;
  250. }
  251. else
  252. {
  253. //
  254. // We're ready to initialize and set the state.
  255. //
  256. // Checkpoint is 1 since this will be the first checkpoint
  257. // in the new pending state, WaitHint as supplied, and
  258. // no errors are reported except when stopping.
  259. //
  260. KtServiceStatus.dwCheckPoint = 1;
  261. KtServiceStatus.dwWaitHint = dwWaitHint;
  262. KtServiceStatus.dwWin32ExitCode = NO_ERROR;
  263. KtServiceStatus.dwServiceSpecificExitCode = 0;
  264. KtServiceStatus.dwCurrentState = dwPendingState;
  265. if( !SetServiceStatus( KtServiceStatusHandle, &KtServiceStatus ) )
  266. {
  267. DebugLog( DEB_ERROR, "%s(%d): Error from SetServiceStatus: 0x%x.\n", __FILE__, __LINE__, GetLastError() );
  268. goto Error;
  269. }
  270. }
  271. Cleanup:
  272. return fSuccess;
  273. Error:
  274. fSuccess = FALSE;
  275. goto Cleanup;
  276. }
  277. //+-------------------------------------------------------------------------
  278. //
  279. // Function: KtControlHandlerEx
  280. //
  281. // Synopsis: Service Control Handler, called by Service Control to
  282. // process control events.
  283. //
  284. // Effects: Posts to the i/o completion port to wake a service thread.
  285. //
  286. // Arguments: dwControl - The control to handle.
  287. // dwEventType - Extended info for certain control events.
  288. // pvEventData - Additional info for certain control events.
  289. // pvContext - User defined data. (Unused here.)
  290. //
  291. // Requires:
  292. //
  293. // Returns: Winerror code, spec. NO_ERROR or ERROR_CALL_NOT_IMPLEMENTED.
  294. //
  295. // Notes:
  296. //
  297. //--------------------------------------------------------------------------
  298. DWORD WINAPI
  299. KtControlHandlerEx(
  300. IN DWORD dwControl,
  301. IN DWORD dwEventType,
  302. IN PVOID pvEventData,
  303. IN PVOID pvContext
  304. )
  305. {
  306. DWORD dwReturn = NO_ERROR;
  307. BOOL fPostControlToServiceThread = FALSE;
  308. //
  309. // If we're told to change state, initiate an appropriate state
  310. // transition. To service an INTERROGATE request we merely report
  311. // our current status. No other control events are implemented.
  312. //
  313. switch( dwControl )
  314. {
  315. case SERVICE_CONTROL_STOP:
  316. case SERVICE_CONTROL_SHUTDOWN:
  317. DebugLog( DEB_TRACE, "%s(%d): SERVICE_CONTROL_%s recieved.\n", __FILE__, __LINE__, (dwControl==SERVICE_CONTROL_STOP)?"STOP":"SHUTDOWN" );
  318. KtBeginStateTransition( SERVICE_STOPPED, 2000 );
  319. fPostControlToServiceThread = TRUE;
  320. break;
  321. case SERVICE_CONTROL_PAUSE:
  322. DebugLog( DEB_TRACE, "%s(%d): SERVICE_CONTROL_PAUSE recieved.\n", __FILE__, __LINE__ );
  323. KtBeginStateTransition( SERVICE_PAUSED, 2000 );
  324. fPostControlToServiceThread = TRUE;
  325. break;
  326. case SERVICE_CONTROL_CONTINUE:
  327. DebugLog( DEB_TRACE, "%s(%d): SERVICE_CONTROL_CONTINUE recieved.\n", __FILE__, __LINE__ );
  328. KtBeginStateTransition( SERVICE_RUNNING, 2000 );
  329. fPostControlToServiceThread = TRUE;
  330. break;
  331. case SERVICE_CONTROL_INTERROGATE:
  332. DebugLog( DEB_TRACE, "%s(%d): SERVICE_CONTROL_CONTINUE recieved.\n", __FILE__, __LINE__ );
  333. SetServiceStatus( KtServiceStatusHandle, &KtServiceStatus );
  334. dwReturn = NO_ERROR;
  335. break;
  336. case SERVICE_CONTROL_PARAMCHANGE:
  337. case SERVICE_CONTROL_NETBINDADD:
  338. case SERVICE_CONTROL_NETBINDREMOVE:
  339. case SERVICE_CONTROL_NETBINDENABLE:
  340. case SERVICE_CONTROL_NETBINDDISABLE:
  341. case SERVICE_CONTROL_DEVICEEVENT:
  342. case SERVICE_CONTROL_HARDWAREPROFILECHANGE:
  343. case SERVICE_CONTROL_POWEREVENT:
  344. case SERVICE_CONTROL_SESSIONCHANGE:
  345. DebugLog( DEB_WARN, "%s(%d): Unsupported control recieved.\n", __FILE__, __LINE__ );
  346. dwReturn = ERROR_CALL_NOT_IMPLEMENTED;
  347. break;
  348. default:
  349. DebugLog( DEB_WARN, "%s(%d): Unhandled case: 0x%x.\n", __FILE__, __LINE__, dwControl );
  350. dwReturn = ERROR_CALL_NOT_IMPLEMENTED;
  351. DsysAssert( dwControl == SERVICE_CONTROL_STOP ||
  352. dwControl == SERVICE_CONTROL_SHUTDOWN ||
  353. dwControl == SERVICE_CONTROL_PAUSE ||
  354. dwControl == SERVICE_CONTROL_CONTINUE ||
  355. dwControl == SERVICE_CONTROL_INTERROGATE ||
  356. dwControl == SERVICE_CONTROL_DEVICEEVENT ||
  357. dwControl == SERVICE_CONTROL_HARDWAREPROFILECHANGE ||
  358. dwControl == SERVICE_CONTROL_POWEREVENT ||
  359. dwControl == SERVICE_CONTROL_PARAMCHANGE ||
  360. dwControl == SERVICE_CONTROL_NETBINDADD ||
  361. dwControl == SERVICE_CONTROL_NETBINDREMOVE ||
  362. dwControl == SERVICE_CONTROL_NETBINDENABLE ||
  363. dwControl == SERVICE_CONTROL_NETBINDDISABLE ||
  364. dwControl == SERVICE_CONTROL_DEVICEEVENT ||
  365. dwControl == SERVICE_CONTROL_HARDWAREPROFILECHANGE ||
  366. dwControl == SERVICE_CONTROL_POWEREVENT ||
  367. dwControl == SERVICE_CONTROL_SESSIONCHANGE );
  368. break;
  369. }
  370. //
  371. // If we're changing state, we need to wake up a service thread
  372. // to do the actual work, so we post an event to the Completion
  373. // port with the key KTCK_SERVICE_CONTROL. Since no data transfer
  374. // actually took place, we can pass the control event in as the
  375. // "number of bytes transferred" without ambiguity.
  376. //
  377. if( fPostControlToServiceThread )
  378. {
  379. BOOL IocpSuccess;
  380. IocpSuccess = PostQueuedCompletionStatus( KtIocp,
  381. dwControl,
  382. KTCK_SERVICE_CONTROL,
  383. NULL );
  384. if( !IocpSuccess )
  385. {
  386. DebugLog( DEB_ERROR, "%s(%d): Error posting completion status to I/O completion port: 0x%x.\n", __FILE__, __LINE__, GetLastError() );
  387. dwReturn = GetLastError();
  388. /* TODO: Event log, possibly something drastic. */
  389. }
  390. }
  391. return dwReturn;
  392. }
  393. //+-------------------------------------------------------------------------
  394. //
  395. // Function: KtStartupInit
  396. //
  397. // Synopsis: Does the startup initialization for the service.
  398. //
  399. // Effects:
  400. //
  401. // Arguments:
  402. //
  403. // Requires:
  404. //
  405. // Returns: Success value.
  406. // If initialization fails, KtServiceStatus.dwWin32ErrorCode is set
  407. // to an appropriate error code, and the service stops.
  408. //
  409. // Notes:
  410. //
  411. //--------------------------------------------------------------------------
  412. BOOL
  413. KtStartupInit(
  414. VOID
  415. )
  416. {
  417. BOOL fRet = TRUE;
  418. //
  419. // Initialize the Service Status structure.
  420. //
  421. KtServiceStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
  422. KtServiceStatus.dwCurrentState = SERVICE_START_PENDING;
  423. KtServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_PAUSE_CONTINUE;
  424. KtServiceStatus.dwWin32ExitCode = NO_ERROR;
  425. KtServiceStatus.dwServiceSpecificExitCode = 0;
  426. KtServiceStatus.dwCheckPoint = 0;
  427. KtServiceStatus.dwWaitHint = 2000;
  428. //
  429. // First thing we need to do is get a handle on our status so we can
  430. // tell Service Control what we're doing.
  431. // The SERVICE_STATUS_HANDLE returned by this call need not be closed.
  432. //
  433. DsysAssert(KtServiceStatusHandle == NULL);
  434. KtServiceStatusHandle = RegisterServiceCtrlHandlerEx( KtServiceName,
  435. KtControlHandlerEx,
  436. NULL );
  437. if( KtServiceStatusHandle == NULL )
  438. {
  439. DebugLog( DEB_ERROR, "%s(%d): Error from RegisterServiceCtrlHandlerEx: 0x%x.\n", __FILE__, __LINE__, GetLastError() );
  440. goto Error;
  441. }
  442. //
  443. // Next we create an event (auto reset, initially signalled) that we'll
  444. // use to make sure we aren't in multiple state transitions simultaneously.
  445. //
  446. DsysAssert(KtStateTransitionLock == NULL );
  447. KtStateTransitionLock = CreateEvent( NULL,
  448. FALSE, // NOT manual reset
  449. TRUE, // initially signalled
  450. NULL );
  451. if( KtStateTransitionLock == NULL )
  452. {
  453. DebugLog( DEB_ERROR, "%s(%d): Error from CreateEvent: 0x%x.\n", __FILE__, __LINE__, GetLastError() );
  454. goto Error;
  455. }
  456. //
  457. // Now we can signal Service Control that we're starting.
  458. //
  459. if( !KtBeginStateTransition( SERVICE_RUNNING, 2000 ) )
  460. goto Error;
  461. //
  462. // Create an unassociated I/O Completion port that we'll use to queue
  463. // events to be serviced.
  464. //
  465. DsysAssert(KtIocp == NULL);
  466. KtIocp = CreateIoCompletionPort( INVALID_HANDLE_VALUE, NULL, 0, 0 );
  467. if( KtIocp == NULL )
  468. {
  469. DebugLog( DEB_ERROR, "%s(%d): Error from CreateIoCompletionPort: 0x%x.\n", __FILE__, __LINE__, GetLastError() );
  470. goto Error;
  471. }
  472. //
  473. // Initialize memory routines
  474. //
  475. if( !KtInitMem() )
  476. goto Error;
  477. //
  478. // Initialize Winsock
  479. //
  480. if( !KtInitWinsock() )
  481. goto Error;
  482. //
  483. // Initialize WinInet
  484. //
  485. if( !KtInitHttp() )
  486. goto Error;
  487. //
  488. // Initialize contexts
  489. //
  490. if( !KtInitContexts() )
  491. goto Error;
  492. //
  493. // Finish bringing up the service.
  494. //
  495. KtContinueService();
  496. Cleanup:
  497. return fRet;
  498. Error:
  499. //
  500. // We couldn't get the resources we needed to start, so punt the service.
  501. // Note that KtStopService cleans up any resources we may have successfully
  502. // allocated in this routine.
  503. //
  504. /* TODO: Event log. */
  505. KtStopService( GetLastError() );
  506. fRet = FALSE;
  507. goto Cleanup;
  508. }
  509. //+-------------------------------------------------------------------------
  510. //
  511. // Function: KtContinueService
  512. //
  513. // Synopsis: Continues the service. This is not only the opposite of
  514. // pause, but the second half of the initialization necessary
  515. // to start the service in the first place.
  516. //
  517. // Effects:
  518. //
  519. // Arguments:
  520. //
  521. // Requires:
  522. //
  523. // Returns:
  524. //
  525. // Notes:
  526. //
  527. //--------------------------------------------------------------------------
  528. VOID
  529. KtContinueService(
  530. VOID
  531. )
  532. {
  533. //
  534. // To continue the service we start listening for new connections.
  535. //
  536. if( !KtStartListening() )
  537. goto Error;
  538. KtFinishStateTransition();
  539. return;
  540. Error:
  541. /* TODO: Event log. */
  542. DebugLog( DEB_ERROR, "%s(%d): Unable to bring up service. Shutting down with error code 0x%x.\n", __FILE__, __LINE__, GetLastError() );
  543. KtStopService( GetLastError() );
  544. }
  545. //+-------------------------------------------------------------------------
  546. //
  547. // Function: KtPauseService
  548. //
  549. // Synopsis: Pauses the service.
  550. //
  551. // Effects:
  552. //
  553. // Arguments:
  554. //
  555. // Requires:
  556. //
  557. // Returns:
  558. //
  559. // Notes:
  560. //
  561. //--------------------------------------------------------------------------
  562. VOID
  563. KtPauseService(
  564. VOID
  565. )
  566. {
  567. //
  568. // To pause the service, we stop making new connections, but we can
  569. // leave any open connections open.
  570. //
  571. KtStopListening();
  572. KtFinishStateTransition();
  573. }
  574. //+-------------------------------------------------------------------------
  575. //
  576. // Function: KtStopService
  577. //
  578. // Synopsis: Stops the service.
  579. //
  580. // Effects:
  581. //
  582. // Arguments:
  583. //
  584. // Requires:
  585. //
  586. // Returns:
  587. //
  588. // Notes:
  589. //
  590. //--------------------------------------------------------------------------
  591. VOID
  592. KtStopService(
  593. DWORD dwWin32ErrorCode
  594. )
  595. {
  596. //
  597. // Release all our resources.
  598. //
  599. KtStopListening();
  600. KtCleanupContexts();
  601. KtCleanupHttp();
  602. KtCleanupWinsock();
  603. KtCleanupMem();
  604. if( KtStateTransitionLock )
  605. CloseHandle(KtStateTransitionLock);
  606. if( KtIocp )
  607. CloseHandle(KtIocp);
  608. //
  609. // Tell service control that we're done.
  610. //
  611. KtServiceStatus.dwCurrentState = SERVICE_STOPPED;
  612. KtServiceStatus.dwCheckPoint = 0;
  613. KtServiceStatus.dwWaitHint = 0;
  614. KtServiceStatus.dwWin32ExitCode = dwWin32ErrorCode;
  615. KtServiceStatus.dwServiceSpecificExitCode = 0;
  616. if( KtServiceStatusHandle )
  617. SetServiceStatus( KtServiceStatusHandle, &KtServiceStatus );
  618. }
  619. //+-------------------------------------------------------------------------
  620. //
  621. // Function: KtServiceControlEvent
  622. //
  623. // Synopsis: Dispatches control events to the appropriate routine to
  624. // do the state change.
  625. //
  626. // Effects:
  627. //
  628. // Arguments: dwControl - Code of the control event.
  629. //
  630. // Requires:
  631. //
  632. // Returns:
  633. //
  634. // Notes:
  635. //
  636. //--------------------------------------------------------------------------
  637. VOID
  638. KtServiceControlEvent(
  639. DWORD dwControl
  640. )
  641. {
  642. switch( dwControl )
  643. {
  644. case SERVICE_CONTROL_CONTINUE:
  645. KtContinueService();
  646. break;
  647. case SERVICE_CONTROL_PAUSE:
  648. KtPauseService();
  649. break;
  650. case SERVICE_CONTROL_STOP:
  651. case SERVICE_CONTROL_SHUTDOWN:
  652. KtStopService(NO_ERROR);
  653. break;
  654. default:
  655. DebugLog( DEB_WARN, "%s(%d): Unhandled case: 0x%x.", __FILE__, __LINE__, dwControl );
  656. DsysAssert( dwControl == SERVICE_CONTROL_CONTINUE ||
  657. dwControl == SERVICE_CONTROL_PAUSE ||
  658. dwControl == SERVICE_CONTROL_STOP ||
  659. dwControl == SERVICE_CONTROL_SHUTDOWN );
  660. break;
  661. }
  662. }
  663. //+-------------------------------------------------------------------------
  664. //
  665. // Function: KtMainServiceEntry
  666. //
  667. // Synopsis: This initializes the service, then acts as the main service
  668. // thread.
  669. //
  670. // Effects:
  671. //
  672. // Arguments:
  673. //
  674. // Requires:
  675. //
  676. // Returns:
  677. //
  678. // Notes:
  679. //
  680. //--------------------------------------------------------------------------
  681. VOID WINAPI
  682. KtMainServiceEntry(
  683. IN DWORD argc,
  684. IN LPTSTR argv[]
  685. )
  686. {
  687. //
  688. // Do startup initialization.
  689. //
  690. if( !KtStartupInit() )
  691. goto Cleanup;
  692. //
  693. // Do our thing.
  694. //
  695. KtThreadCore();
  696. Cleanup:
  697. ExitProcess( KtServiceStatus.dwWin32ExitCode );
  698. }
  699. //+-------------------------------------------------------------------------
  700. //
  701. // Function: KtIsStopped
  702. //
  703. // Synopsis: Determines whether the service is still running.
  704. //
  705. // Effects:
  706. //
  707. // Arguments:
  708. //
  709. // Requires:
  710. //
  711. // Returns: TRUE if the service has stopped, FALSE otherwise.
  712. //
  713. // Notes:
  714. //
  715. //--------------------------------------------------------------------------
  716. BOOL
  717. KtIsStopped(
  718. VOID
  719. )
  720. {
  721. return (KtServiceStatus.dwCurrentState == SERVICE_STOPPED);
  722. }