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.

597 lines
16 KiB

  1. /*++
  2. Copyright (C) Microsoft Corporation, 1997 - 1999
  3. Module Name:
  4. service.cxx
  5. Abstract:
  6. This contains the Service related functionality of SENS.
  7. Author:
  8. Gopal Parupudi <GopalP>
  9. [Notes:]
  10. This is cloned from \nt\private\eventsystem\server\eventsystem.cpp
  11. Revision History:
  12. GopalP 1/11/1998 Start.
  13. --*/
  14. #include <precomp.hxx>
  15. #include <winuser.h>
  16. #include <dbt.h>
  17. #include "service.hxx"
  18. //
  19. // Constants
  20. //
  21. #define SENS_NAME SENS_STRING("SENS")
  22. #define SENS_DATA 0x19732304
  23. #define SENS_WAIT_HINT 3*1000
  24. enum ACTION
  25. {
  26. ACTION_NONE,
  27. ACTION_APPLICATION,
  28. ACTION_SERVICE
  29. };
  30. //
  31. // Globals
  32. //
  33. DWORD gdwError;
  34. HANDLE ghStopEvent;
  35. extern HANDLE ghSensStartedEvent;
  36. SYSTEM_POWER_STATUS gSystemPowerState;
  37. //
  38. // Service related stuff
  39. //
  40. SERVICE_STATUS gServiceStatus; // current status of the service
  41. SERVICE_STATUS_HANDLE ghStatusHandle;
  42. HDEVNOTIFY ghDeviceNotify;
  43. SERVICE_TABLE_ENTRY gaServiceEntryTable[] = {
  44. { SENS_NAME, (LPSERVICE_MAIN_FUNCTION) ServiceMain },
  45. { NULL, NULL }
  46. };
  47. //
  48. // Helper functions
  49. //
  50. void __stdcall
  51. LogMessage(
  52. TCHAR* msg1,
  53. TCHAR* msg2
  54. )
  55. /*++
  56. Routine Description:
  57. Arguments:
  58. Return Value:
  59. --*/
  60. {
  61. const TCHAR* strings[2] = {msg1, msg2};
  62. HANDLE hEventSource;
  63. hEventSource = RegisterEventSource(NULL, SENS_STRING("SENS"));
  64. if (hEventSource != NULL)
  65. {
  66. ReportEvent(
  67. hEventSource, // event source handle
  68. EVENTLOG_ERROR_TYPE, // event type
  69. 0, // event category
  70. 0, // event ID
  71. NULL, // current user's SID
  72. 2, // strings in lpszStrings
  73. 0, // no bytes of raw data
  74. strings, // array of error strings
  75. NULL // no raw data
  76. );
  77. DeregisterEventSource(hEventSource);
  78. }
  79. }
  80. void
  81. ServiceStart(
  82. void
  83. )
  84. /*++
  85. Routine Description:
  86. Start SENS as service. Stay up until we receive the stop event.
  87. Arguments:
  88. None.
  89. Return Value:
  90. None.
  91. --*/
  92. {
  93. // Initialize SENS.
  94. if (FALSE == SensInitialize())
  95. {
  96. SensPrintToDebugger(SENS_DBG, ("[SENS] [%d] SensInitialize() failed.\n", GetTickCount()));
  97. return;
  98. }
  99. // Tell the SCM that we're running now.
  100. if (!ReportStatusToSCM(SERVICE_RUNNING, NO_ERROR, 0))
  101. {
  102. SensPrintToDebugger(SENS_DBG, ("[SENS] [%d] ReportStatusToSCM() failed.\n", GetTickCount()));
  103. return;
  104. }
  105. // Set the SensStartedEvent now.
  106. if (ghSensStartedEvent != NULL)
  107. {
  108. SetEvent(ghSensStartedEvent);
  109. SensPrintA(SENS_INFO, ("[%d] Successfully signalled starting of SENS.\n", GetTickCount()));
  110. }
  111. else
  112. {
  113. SensPrintToDebugger(SENS_DBG, ("[SENS] [%d] Couldn't set the SENS Started event!\n", GetTickCount()));
  114. }
  115. SensPrintToDebugger(SENS_DBG, ("\n[SENS] [%d] Started successfully.\n\n", GetTickCount()));
  116. }
  117. void
  118. ServiceStop(
  119. void
  120. )
  121. /*++
  122. Routine Description:
  123. Stop SENS as a service.
  124. Arguments:
  125. None.
  126. Return Value:
  127. None.
  128. --*/
  129. {
  130. //
  131. // Cleanup now.
  132. //
  133. SensUninitialize();
  134. }
  135. VOID WINAPI
  136. ServiceMain(
  137. DWORD argc,
  138. TCHAR* argv[]
  139. )
  140. /*++
  141. Routine Description:
  142. Perform the actual service initialization.
  143. Arguments:
  144. Usual stuff.
  145. Return Value:
  146. Usual stuff.
  147. --*/
  148. {
  149. //
  150. // Initialize Globals.
  151. //
  152. gdwError = 0x0;
  153. ghStopEvent = NULL;
  154. ghStatusHandle = NULL;
  155. memset(&gServiceStatus, 0x0, sizeof(SERVICE_STATUS));
  156. ghDeviceNotify = NULL;
  157. // Service status parameters that don't change.
  158. gServiceStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
  159. gServiceStatus.dwCurrentState = SERVICE_START_PENDING;
  160. gServiceStatus.dwControlsAccepted = 0;
  161. gServiceStatus.dwWin32ExitCode = 0;
  162. gServiceStatus.dwServiceSpecificExitCode = 0;
  163. gServiceStatus.dwCheckPoint = 0;
  164. gServiceStatus.dwWaitHint = SENS_WAIT_HINT;
  165. //
  166. // Register our service control handler
  167. //
  168. DEV_BROADCAST_DEVICEINTERFACE PnPFilter;
  169. ghStatusHandle = RegisterServiceCtrlHandlerEx(
  170. SENS_NAME,
  171. ServiceControl,
  172. (PVOID) SENS_DATA
  173. );
  174. if (ghStatusHandle == NULL)
  175. {
  176. return;
  177. }
  178. #ifdef PNP_EVENTS
  179. // Before enabling PnP events be aware that the code to unregister for the PnP
  180. // is missing. Since SENS does not use the PnPs the code was all removed.
  181. //
  182. // Register for the PnP Device Interface change notifications
  183. //
  184. PnPFilter.dbcc_size = sizeof(DEV_BROADCAST_DEVICEINTERFACE);
  185. PnPFilter.dbcc_devicetype = DBT_DEVTYP_DEVICEINTERFACE;
  186. PnPFilter.dbcc_reserved = 0x0;
  187. memcpy(
  188. &PnPFilter.dbcc_classguid,
  189. (LPGUID) &GUID_NDIS_LAN_CLASS,
  190. sizeof(GUID)
  191. );
  192. ghDeviceNotify = RegisterDeviceNotification(
  193. (HANDLE) ghStatusHandle,
  194. &PnPFilter,
  195. DEVICE_NOTIFY_SERVICE_HANDLE
  196. );
  197. if (NULL == ghDeviceNotify)
  198. {
  199. SensPrintToDebugger(SENS_DBG, ("[SENS] [%d] ServiceMain(): RegisterDeviceNotification() failed\n", GetTickCount()));
  200. }
  201. #ifdef DETAIL_DEBUG
  202. SensPrintToDebugger(SENS_DBG, ("[SENS] [%d] ServiceMain(): RegisterDeviceNotification() succeeded\n", GetTickCount()));
  203. #endif // DETAIL_DEBUG
  204. #endif // PNP_EVENTS
  205. //
  206. // Save a snapshot of the System Power State.
  207. //
  208. BOOL bRet = GetSystemPowerStatus(&gSystemPowerState);
  209. if (bRet == FALSE)
  210. {
  211. SensPrintA(SENS_ERR, ("SensMessageLoopThread(): GetSystemPowerStatus() failed with "
  212. "GLE = %d\n", GetLastError()));
  213. }
  214. ASSERT(bRet);
  215. // Report the status, the exit code, and the wait hint to the SCM.
  216. if (!ReportStatusToSCM(SERVICE_START_PENDING, NO_ERROR, SENS_WAIT_HINT))
  217. {
  218. return;
  219. }
  220. // Start the service executing.
  221. ServiceStart();
  222. // Let the thread return. We will use the stop thread to cleanup.
  223. return;
  224. }
  225. DWORD WINAPI
  226. ServiceControl(
  227. DWORD dwCode,
  228. DWORD dwEventType,
  229. PVOID EventData,
  230. PVOID pData
  231. )
  232. /*++
  233. Routine Description:
  234. Handle Control Codes from SCM.
  235. Arguments:
  236. dwCode - The control code.
  237. dwEventType - The type of the event.
  238. EventData - Data corresponding to the event.
  239. pData - Additional Data.
  240. Notes:
  241. Refer to \\popcorn\razzle1\src\spec\umevent.doc for further details.
  242. Return Value:
  243. None.
  244. --*/
  245. {
  246. PDEV_BROADCAST_DEVICEINTERFACE pDevice;
  247. NTSTATUS NtStatus;
  248. ANSI_STRING DeviceNameA;
  249. UNICODE_STRING UnicodeString;
  250. unsigned char *DeviceUuidA;
  251. DWORD dwStatus = NO_ERROR;
  252. pDevice = (PDEV_BROADCAST_DEVICEINTERFACE) EventData;
  253. DeviceUuidA = NULL;
  254. #ifdef DETAIL_DEBUG
  255. SensPrintToDebugger(SENS_DBG, ("[SENS] ServiceControl(): dwCode = 0x%x\n", dwCode));
  256. #endif // DETAIL_DEBUG
  257. switch (dwCode)
  258. {
  259. case SERVICE_CONTROL_STOP:
  260. //
  261. // Stop the service.
  262. //
  263. // SERVICE_STOP_PENDING should be reported before setting the Stop
  264. // Event. This avoids a race condition which may result in a 1053
  265. // - "The Service did not respond" error.
  266. //
  267. ReportStatusToSCM(SERVICE_STOP_PENDING, NO_ERROR, SENS_WAIT_HINT);
  268. ServiceStop();
  269. ReportStatusToSCM(SERVICE_STOPPED, NO_ERROR, 0);
  270. return dwStatus;
  271. case SERVICE_CONTROL_INTERROGATE:
  272. //
  273. // Update the service status.
  274. //
  275. ReportStatusToSCM(gServiceStatus.dwCurrentState, NO_ERROR, 0);
  276. break;
  277. #ifdef PNP_EVENTS
  278. case SERVICE_CONTROL_DEVICEEVENT:
  279. //
  280. // PnP event.
  281. //
  282. #ifdef DETAIL_DEBUG
  283. RtlInitUnicodeString(&UnicodeString, (PCWSTR) &pDevice->dbcc_name);
  284. NtStatus = RtlUnicodeStringToAnsiString(&DeviceNameA, &UnicodeString, TRUE);
  285. UuidToStringA(&pDevice->dbcc_classguid, &DeviceUuidA);
  286. SensPrintToDebugger(SENS_DBG, ("\n-------------------------------------------------------------\n"));
  287. SensPrintToDebugger(SENS_DBG, ("SENS received a PnP Event - "));
  288. SensPrintToDebugger(SENS_DBG, ((dwEventType == DBT_DEVICEREMOVECOMPLETE) ? "DEVICE REMOVED\n" : ""));
  289. SensPrintToDebugger(SENS_DBG, ((dwEventType == DBT_DEVICEARRIVAL) ? "DEVICE ARRIVED\n" : "\n"));
  290. SensPrintToDebugger(SENS_DBG, ("\tdwCode - 0x%x\n", dwCode));
  291. SensPrintToDebugger(SENS_DBG, ("\tdwEventType - 0x%x\n", dwEventType));
  292. SensPrintToDebugger(SENS_DBG, ("\tpData - 0x%x\n", pData));
  293. SensPrintToDebugger(SENS_DBG, ("\tEventData - 0x%x\n", pDevice));
  294. SensPrintToDebugger(SENS_DBG, ("\t o dbcc_size - 0x%x\n", pDevice->dbcc_size));
  295. SensPrintToDebugger(SENS_DBG, ("\t o dbcc_devicetype - 0x%x\n", pDevice->dbcc_devicetype));
  296. SensPrintToDebugger(SENS_DBG, ("\t o dbcc_reserved - 0x%x\n", pDevice->dbcc_reserved));
  297. SensPrintToDebugger(SENS_DBG, ("\t o dbcc_classguid - %s\n", DeviceUuidA));
  298. SensPrintToDebugger(SENS_DBG, ("\t o dbcc_name - %s\n", DeviceNameA.Buffer));
  299. SensPrintToDebugger(SENS_DBG, ("-------------------------------------------------------------\n\n"));
  300. if (NT_SUCCESS(NtStatus))
  301. {
  302. RtlFreeAnsiString(&DeviceNameA);
  303. }
  304. if (DeviceUuidA != NULL)
  305. {
  306. RpcStringFreeA(&DeviceUuidA);
  307. }
  308. #endif // DETAIL_DEBUG
  309. break;
  310. #endif // PNP_EVENTS
  311. case SERVICE_CONTROL_POWEREVENT:
  312. {
  313. //
  314. // Power event
  315. //
  316. //
  317. // These are generated every 1% of power change, also by playing
  318. // with the power cpl or plugging in the machine.
  319. //
  320. SYSTEM_POWER_STATUS CurSPstate;
  321. SENSEVENT_POWER Data;
  322. BOOL bRet;
  323. BOOL bFireEvent = FALSE;
  324. bRet = GetSystemPowerStatus(&CurSPstate);
  325. ASSERT(bRet);
  326. switch(dwEventType)
  327. {
  328. case PBT_APMPOWERSTATUSCHANGE:
  329. {
  330. //
  331. // OnACPower event is fired when
  332. // o previously the machine was not on AC
  333. // o now, it is on AC
  334. //
  335. if ( (CurSPstate.ACLineStatus == AC_LINE_ONLINE)
  336. && (gSystemPowerState.ACLineStatus != AC_LINE_ONLINE))
  337. {
  338. Data.eType = SENS_EVENT_POWER_ON_ACPOWER;
  339. bFireEvent = TRUE;
  340. }
  341. else
  342. //
  343. // OnBatteryPower event is fired when
  344. // o previously the machine was on AC
  345. // o now, it is not on AC
  346. // o the machine has a system battery
  347. //
  348. if ( (CurSPstate.ACLineStatus == AC_LINE_OFFLINE)
  349. && (gSystemPowerState.ACLineStatus == AC_LINE_ONLINE)
  350. && ((CurSPstate.BatteryFlag & BATTERY_FLAG_NO_BATTERY) == 0))
  351. {
  352. Data.eType = SENS_EVENT_POWER_ON_BATTERYPOWER;
  353. bFireEvent = TRUE;
  354. // Special case, if the machine goes off battery and has a low
  355. // battery we want to generate both events. Resetting the
  356. // low battery flag here guarantees that next time power changes
  357. // we will fire the low battery event.
  358. CurSPstate.BatteryFlag = CurSPstate.BatteryFlag & ~BATTERY_FLAG_LOW;
  359. }
  360. else
  361. // OnBatteryPowerLow event is fired when
  362. // o the battery is not charging and
  363. // o previously the battery was not low
  364. // o and now the battery is low.
  365. //
  366. if ( (CurSPstate.BatteryFlag & BATTERY_FLAG_LOW)
  367. && ( (CurSPstate.BatteryFlag & BATTERY_FLAG_CHARGING) == 0)
  368. && ( (gSystemPowerState.BatteryFlag & BATTERY_FLAG_LOW) == 0) )
  369. {
  370. Data.eType = SENS_EVENT_POWER_BATTERY_LOW;
  371. bFireEvent = TRUE;
  372. }
  373. else
  374. {
  375. // Power event we don't about
  376. ASSERT(bFireEvent == FALSE);
  377. }
  378. break;
  379. }
  380. default:
  381. {
  382. // Other power event we can ignore
  383. break;
  384. }
  385. }
  386. if (bFireEvent)
  387. {
  388. // Save the new state. A critsec is not necessary as service control messages are serialized.
  389. memcpy(&gSystemPowerState, &CurSPstate, sizeof(SYSTEM_POWER_STATUS));
  390. // Fire the event.
  391. memcpy(&Data.PowerStatus, &CurSPstate, sizeof(SYSTEM_POWER_STATUS));
  392. SensFireEvent(&Data);
  393. }
  394. dwStatus = SUCCESS;
  395. break;
  396. }
  397. default:
  398. dwStatus = ERROR_CALL_NOT_IMPLEMENTED;
  399. // invalid control code
  400. break;
  401. }
  402. return dwStatus;
  403. }
  404. BOOL
  405. ReportStatusToSCM(
  406. DWORD dwCurrentState,
  407. DWORD dwExitCode,
  408. DWORD dwWaitHint
  409. )
  410. /*++
  411. Routine Description:
  412. Report status to SCM.
  413. Arguments:
  414. dwCurrentState - The current state of the service.
  415. dwExitCode - The Win32 Exit code.
  416. dwWaitHint - The amount of time in msec to wait for the SCM to acknowledge.
  417. Return Value:
  418. TRUE, succeeded.
  419. FALSE, otherwise.
  420. --*/
  421. {
  422. DWORD dwCheckPoint = 0;
  423. BOOL bResult = TRUE;
  424. if (dwCurrentState == SERVICE_START_PENDING)
  425. {
  426. gServiceStatus.dwControlsAccepted = 0;
  427. }
  428. else
  429. {
  430. gServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_POWEREVENT;
  431. }
  432. gServiceStatus.dwCurrentState = dwCurrentState;
  433. gServiceStatus.dwWin32ExitCode = dwExitCode;
  434. gServiceStatus.dwWaitHint = dwWaitHint;
  435. if ( (dwCurrentState == SERVICE_RUNNING)
  436. || (dwCurrentState == SERVICE_STOPPED))
  437. {
  438. gServiceStatus.dwCheckPoint = 0;
  439. }
  440. else
  441. {
  442. gServiceStatus.dwCheckPoint = ++dwCheckPoint;
  443. }
  444. //
  445. // Report the status of the service to the SCM.
  446. // Caller handles error reporting, so we can have some context....
  447. //
  448. return SetServiceStatus(ghStatusHandle, &gServiceStatus);
  449. }