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.

655 lines
17 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 __stdcall
  81. LogWin32Message(
  82. TCHAR* msg
  83. )
  84. /*++
  85. Routine Description:
  86. Arguments:
  87. Return Value:
  88. --*/
  89. {
  90. LPVOID sysmsg;
  91. TCHAR msgbuf[256];
  92. DWORD rc = 1234;
  93. FormatMessage(
  94. FORMAT_MESSAGE_ALLOCATE_BUFFER |
  95. FORMAT_MESSAGE_FROM_SYSTEM |
  96. FORMAT_MESSAGE_IGNORE_INSERTS,
  97. NULL,
  98. rc,
  99. NULL,
  100. (LPTSTR) &sysmsg,
  101. 0,
  102. NULL
  103. );
  104. wsprintf(msgbuf, SENS_STRING("Event System Win32 Error: %s\n"), sysmsg);
  105. LogMessage (msgbuf, msg);
  106. (void) LocalFree (sysmsg);
  107. }
  108. void
  109. ServiceStart(
  110. void
  111. )
  112. /*++
  113. Routine Description:
  114. Start SENS as service. Stay up until we receive the stop event.
  115. Arguments:
  116. None.
  117. Return Value:
  118. None.
  119. --*/
  120. {
  121. // Initialize SENS.
  122. if (FALSE == SensInitialize())
  123. {
  124. LogWin32Message(SENS_STRING("ServiceStart(): SensInitialize() failed"));
  125. SensPrintToDebugger(SENS_DBG, ("[SENS] [%d] SensInitialize() failed.\n", GetTickCount()));
  126. return;
  127. }
  128. // Tell the SCM that we're running now.
  129. if (!ReportStatusToSCM(SERVICE_RUNNING, NO_ERROR, 0))
  130. {
  131. LogWin32Message(SENS_STRING("ServiceStart(): ReportStatusToSCM failed"));
  132. SensPrintToDebugger(SENS_DBG, ("[SENS] [%d] ReportStatusToSCM() failed.\n", GetTickCount()));
  133. return;
  134. }
  135. // Set the SensStartedEvent now.
  136. if (ghSensStartedEvent != NULL)
  137. {
  138. SetEvent(ghSensStartedEvent);
  139. SensPrintA(SENS_INFO, ("[%d] Successfully signalled starting of SENS.\n", GetTickCount()));
  140. }
  141. else
  142. {
  143. SensPrintToDebugger(SENS_DBG, ("[SENS] [%d] Couldn't set the SENS Started event!\n", GetTickCount()));
  144. }
  145. SensPrintToDebugger(SENS_DBG, ("\n[SENS] [%d] Started successfully.\n\n", GetTickCount()));
  146. }
  147. void
  148. ServiceStop(
  149. void
  150. )
  151. /*++
  152. Routine Description:
  153. Stop SENS as a service.
  154. Arguments:
  155. None.
  156. Return Value:
  157. None.
  158. --*/
  159. {
  160. //
  161. // Cleanup now.
  162. //
  163. SensUninitialize();
  164. }
  165. VOID WINAPI
  166. ServiceMain(
  167. DWORD argc,
  168. TCHAR* argv[]
  169. )
  170. /*++
  171. Routine Description:
  172. Perform the actual service initialization.
  173. Arguments:
  174. Usual stuff.
  175. Return Value:
  176. Usual stuff.
  177. --*/
  178. {
  179. //
  180. // Initialize Globals.
  181. //
  182. gdwError = 0x0;
  183. ghStopEvent = NULL;
  184. ghStatusHandle = NULL;
  185. memset(&gServiceStatus, 0x0, sizeof(SERVICE_STATUS));
  186. ghDeviceNotify = NULL;
  187. // Service status parameters that don't change.
  188. gServiceStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
  189. gServiceStatus.dwCurrentState = SERVICE_START_PENDING;
  190. gServiceStatus.dwControlsAccepted = 0;
  191. gServiceStatus.dwWin32ExitCode = 0;
  192. gServiceStatus.dwServiceSpecificExitCode = 0;
  193. gServiceStatus.dwCheckPoint = 0;
  194. gServiceStatus.dwWaitHint = SENS_WAIT_HINT;
  195. //
  196. // Register our service control handler
  197. //
  198. DEV_BROADCAST_DEVICEINTERFACE PnPFilter;
  199. ghStatusHandle = RegisterServiceCtrlHandlerEx(
  200. SENS_NAME,
  201. ServiceControl,
  202. (PVOID) SENS_DATA
  203. );
  204. if (ghStatusHandle == NULL)
  205. {
  206. LogWin32Message(SENS_STRING("ServiceMain(): RegisterServiceCtrlHandlerEx() failed"));
  207. return;
  208. }
  209. #ifdef PNP_EVENTS
  210. // Before enabling PnP events be aware that the code to unregister for the PnP
  211. // is missing. Since SENS does not use the PnPs the code was all removed.
  212. //
  213. // Register for the PnP Device Interface change notifications
  214. //
  215. PnPFilter.dbcc_size = sizeof(DEV_BROADCAST_DEVICEINTERFACE);
  216. PnPFilter.dbcc_devicetype = DBT_DEVTYP_DEVICEINTERFACE;
  217. PnPFilter.dbcc_reserved = 0x0;
  218. memcpy(
  219. &PnPFilter.dbcc_classguid,
  220. (LPGUID) &GUID_NDIS_LAN_CLASS,
  221. sizeof(GUID)
  222. );
  223. ghDeviceNotify = RegisterDeviceNotification(
  224. (HANDLE) ghStatusHandle,
  225. &PnPFilter,
  226. DEVICE_NOTIFY_SERVICE_HANDLE
  227. );
  228. if (NULL == ghDeviceNotify)
  229. {
  230. LogWin32Message(SENS_STRING("ServiceMain(): RegisterDeviceNotification() failed"));
  231. SensPrintToDebugger(SENS_DBG, ("[SENS] [%d] ServiceMain(): RegisterDeviceNotification() failed\n", GetTickCount()));
  232. }
  233. #ifdef DETAIL_DEBUG
  234. SensPrintToDebugger(SENS_DBG, ("[SENS] [%d] ServiceMain(): RegisterDeviceNotification() succeeded\n", GetTickCount()));
  235. #endif // DETAIL_DEBUG
  236. #endif // PNP_EVENTS
  237. //
  238. // Save a snapshot of the System Power State.
  239. //
  240. BOOL bRet = GetSystemPowerStatus(&gSystemPowerState);
  241. if (bRet == FALSE)
  242. {
  243. SensPrintA(SENS_ERR, ("SensMessageLoopThread(): GetSystemPowerStatus() failed with "
  244. "GLE = %d\n", GetLastError()));
  245. }
  246. ASSERT(bRet);
  247. // Report the status, the exit code, and the wait hint to the SCM.
  248. if (!ReportStatusToSCM(SERVICE_START_PENDING, NO_ERROR, SENS_WAIT_HINT))
  249. {
  250. LogWin32Message(SENS_STRING("ServiceMain(): ReportStatusToSCM() failed"));
  251. return;
  252. }
  253. // Start the service executing.
  254. ServiceStart();
  255. // Let the thread return. We will use the stop thread to cleanup.
  256. return;
  257. }
  258. DWORD WINAPI
  259. ServiceControl(
  260. DWORD dwCode,
  261. DWORD dwEventType,
  262. PVOID EventData,
  263. PVOID pData
  264. )
  265. /*++
  266. Routine Description:
  267. Handle Control Codes from SCM.
  268. Arguments:
  269. dwCode - The control code.
  270. dwEventType - The type of the event.
  271. EventData - Data corresponding to the event.
  272. pData - Additional Data.
  273. Notes:
  274. Refer to \\popcorn\razzle1\src\spec\umevent.doc for further details.
  275. Return Value:
  276. None.
  277. --*/
  278. {
  279. PDEV_BROADCAST_DEVICEINTERFACE pDevice;
  280. NTSTATUS NtStatus;
  281. ANSI_STRING DeviceNameA;
  282. UNICODE_STRING UnicodeString;
  283. unsigned char *DeviceUuidA;
  284. DWORD dwStatus = NO_ERROR;
  285. pDevice = (PDEV_BROADCAST_DEVICEINTERFACE) EventData;
  286. DeviceUuidA = NULL;
  287. #ifdef DETAIL_DEBUG
  288. SensPrintToDebugger(SENS_DBG, ("[SENS] ServiceControl(): dwCode = 0x%x\n", dwCode));
  289. #endif // DETAIL_DEBUG
  290. switch (dwCode)
  291. {
  292. case SERVICE_CONTROL_STOP:
  293. //
  294. // Stop the service.
  295. //
  296. // SERVICE_STOP_PENDING should be reported before setting the Stop
  297. // Event. This avoids a race condition which may result in a 1053
  298. // - "The Service did not respond" error.
  299. //
  300. if (!ReportStatusToSCM(SERVICE_STOP_PENDING, NO_ERROR, SENS_WAIT_HINT))
  301. {
  302. LogWin32Message(SENS_STRING("ServiceControl(): ReportStatusToSCM() failed while stopping service"));
  303. }
  304. ServiceStop();
  305. if (!ReportStatusToSCM(SERVICE_STOPPED, NO_ERROR, 0))
  306. {
  307. LogWin32Message(SENS_STRING("ServiceControl(): ReportStatusToSCM() failed while stopping service"));
  308. }
  309. return dwStatus;
  310. case SERVICE_CONTROL_INTERROGATE:
  311. //
  312. // Update the service status.
  313. //
  314. if (!ReportStatusToSCM(gServiceStatus.dwCurrentState, NO_ERROR, 0))
  315. {
  316. LogWin32Message(SENS_STRING("ServiceControl(): ReportStatusToSCM() failed when logging current state"));
  317. }
  318. break;
  319. #ifdef PNP_EVENTS
  320. case SERVICE_CONTROL_DEVICEEVENT:
  321. //
  322. // PnP event.
  323. //
  324. #ifdef DETAIL_DEBUG
  325. RtlInitUnicodeString(&UnicodeString, (PCWSTR) &pDevice->dbcc_name);
  326. NtStatus = RtlUnicodeStringToAnsiString(&DeviceNameA, &UnicodeString, TRUE);
  327. UuidToStringA(&pDevice->dbcc_classguid, &DeviceUuidA);
  328. SensPrintToDebugger(SENS_DBG, ("\n-------------------------------------------------------------\n"));
  329. SensPrintToDebugger(SENS_DBG, ("SENS received a PnP Event - "));
  330. SensPrintToDebugger(SENS_DBG, ((dwEventType == DBT_DEVICEREMOVECOMPLETE) ? "DEVICE REMOVED\n" : ""));
  331. SensPrintToDebugger(SENS_DBG, ((dwEventType == DBT_DEVICEARRIVAL) ? "DEVICE ARRIVED\n" : "\n"));
  332. SensPrintToDebugger(SENS_DBG, ("\tdwCode - 0x%x\n", dwCode));
  333. SensPrintToDebugger(SENS_DBG, ("\tdwEventType - 0x%x\n", dwEventType));
  334. SensPrintToDebugger(SENS_DBG, ("\tpData - 0x%x\n", pData));
  335. SensPrintToDebugger(SENS_DBG, ("\tEventData - 0x%x\n", pDevice));
  336. SensPrintToDebugger(SENS_DBG, ("\t o dbcc_size - 0x%x\n", pDevice->dbcc_size));
  337. SensPrintToDebugger(SENS_DBG, ("\t o dbcc_devicetype - 0x%x\n", pDevice->dbcc_devicetype));
  338. SensPrintToDebugger(SENS_DBG, ("\t o dbcc_reserved - 0x%x\n", pDevice->dbcc_reserved));
  339. SensPrintToDebugger(SENS_DBG, ("\t o dbcc_classguid - %s\n", DeviceUuidA));
  340. SensPrintToDebugger(SENS_DBG, ("\t o dbcc_name - %s\n", DeviceNameA.Buffer));
  341. SensPrintToDebugger(SENS_DBG, ("-------------------------------------------------------------\n\n"));
  342. if (NT_SUCCESS(NtStatus))
  343. {
  344. RtlFreeAnsiString(&DeviceNameA);
  345. }
  346. if (DeviceUuidA != NULL)
  347. {
  348. RpcStringFreeA(&DeviceUuidA);
  349. }
  350. #endif // DETAIL_DEBUG
  351. break;
  352. #endif // PNP_EVENTS
  353. case SERVICE_CONTROL_POWEREVENT:
  354. {
  355. //
  356. // Power event
  357. //
  358. //
  359. // These are generated every 1% of power change, also by playing
  360. // with the power cpl or plugging in the machine.
  361. //
  362. SYSTEM_POWER_STATUS CurSPstate;
  363. SENSEVENT_POWER Data;
  364. BOOL bRet;
  365. BOOL bFireEvent = FALSE;
  366. bRet = GetSystemPowerStatus(&CurSPstate);
  367. ASSERT(bRet);
  368. switch(dwEventType)
  369. {
  370. case PBT_APMPOWERSTATUSCHANGE:
  371. {
  372. //
  373. // OnACPower event is fired when
  374. // o previously the machine was not on AC
  375. // o now, it is on AC
  376. //
  377. if ( (CurSPstate.ACLineStatus == AC_LINE_ONLINE)
  378. && (gSystemPowerState.ACLineStatus != AC_LINE_ONLINE))
  379. {
  380. Data.eType = SENS_EVENT_POWER_ON_ACPOWER;
  381. bFireEvent = TRUE;
  382. }
  383. else
  384. //
  385. // OnBatteryPower event is fired when
  386. // o previously the machine was on AC
  387. // o now, it is not on AC
  388. // o the machine has a system battery
  389. //
  390. if ( (CurSPstate.ACLineStatus == AC_LINE_OFFLINE)
  391. && (gSystemPowerState.ACLineStatus == AC_LINE_ONLINE)
  392. && ((CurSPstate.BatteryFlag & BATTERY_FLAG_NO_BATTERY) == 0))
  393. {
  394. Data.eType = SENS_EVENT_POWER_ON_BATTERYPOWER;
  395. bFireEvent = TRUE;
  396. // Special case, if the machine goes off battery and has a low
  397. // battery we want to generate both events. Resetting the
  398. // low battery flag here guarantees that next time power changes
  399. // we will fire the low battery event.
  400. CurSPstate.BatteryFlag = CurSPstate.BatteryFlag & ~BATTERY_FLAG_LOW;
  401. }
  402. else
  403. // OnBatteryPowerLow event is fired when
  404. // o the battery is not charging and
  405. // o previously the battery was not low
  406. // o and now the battery is low.
  407. //
  408. if ( (CurSPstate.BatteryFlag & BATTERY_FLAG_LOW)
  409. && ( (CurSPstate.BatteryFlag & BATTERY_FLAG_CHARGING) == 0)
  410. && ( (gSystemPowerState.BatteryFlag & BATTERY_FLAG_LOW) == 0) )
  411. {
  412. Data.eType = SENS_EVENT_POWER_BATTERY_LOW;
  413. bFireEvent = TRUE;
  414. }
  415. else
  416. {
  417. // Power event we don't about
  418. ASSERT(bFireEvent == FALSE);
  419. }
  420. break;
  421. }
  422. default:
  423. {
  424. // Other power event we can ignore
  425. break;
  426. }
  427. }
  428. if (bFireEvent)
  429. {
  430. // Save the new state. A critsec is not necessary as service control messages are serialized.
  431. memcpy(&gSystemPowerState, &CurSPstate, sizeof(SYSTEM_POWER_STATUS));
  432. // Fire the event.
  433. memcpy(&Data.PowerStatus, &CurSPstate, sizeof(SYSTEM_POWER_STATUS));
  434. SensFireEvent(&Data);
  435. }
  436. dwStatus = SUCCESS;
  437. break;
  438. }
  439. default:
  440. dwStatus = ERROR_CALL_NOT_IMPLEMENTED;
  441. // invalid control code
  442. break;
  443. }
  444. return dwStatus;
  445. }
  446. BOOL
  447. ReportStatusToSCM(
  448. DWORD dwCurrentState,
  449. DWORD dwExitCode,
  450. DWORD dwWaitHint
  451. )
  452. /*++
  453. Routine Description:
  454. Report status to SCM.
  455. Arguments:
  456. dwCurrentState - The current state of the service.
  457. dwExitCode - The Win32 Exit code.
  458. dwWaitHint - The amount of time in msec to wait for the SCM to acknowledge.
  459. Return Value:
  460. TRUE, succeeded.
  461. FALSE, otherwise.
  462. --*/
  463. {
  464. DWORD dwCheckPoint = 0;
  465. BOOL bResult = TRUE;
  466. if (dwCurrentState == SERVICE_START_PENDING)
  467. {
  468. gServiceStatus.dwControlsAccepted = 0;
  469. }
  470. else
  471. {
  472. gServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_POWEREVENT;
  473. }
  474. gServiceStatus.dwCurrentState = dwCurrentState;
  475. gServiceStatus.dwWin32ExitCode = dwExitCode;
  476. gServiceStatus.dwWaitHint = dwWaitHint;
  477. if ( (dwCurrentState == SERVICE_RUNNING)
  478. || (dwCurrentState == SERVICE_STOPPED))
  479. {
  480. gServiceStatus.dwCheckPoint = 0;
  481. }
  482. else
  483. {
  484. gServiceStatus.dwCheckPoint = ++dwCheckPoint;
  485. }
  486. //
  487. // Report the status of the service to the SCM.
  488. // Caller handles error reporting, so we can have some context....
  489. //
  490. return SetServiceStatus(ghStatusHandle, &gServiceStatus);
  491. }