|
|
/*++
Copyright (C) Microsoft Corporation, 1997 - 1999
Module Name:
service.cxx
Abstract:
This contains the Service related functionality of SENS.
Author:
Gopal Parupudi <GopalP>
[Notes:]
This is cloned from \nt\private\eventsystem\server\eventsystem.cpp
Revision History:
GopalP 1/11/1998 Start.
--*/
#include <precomp.hxx>
#include <winuser.h>
#include <dbt.h>
#include "service.hxx"
//
// Constants
//
#define SENS_NAME SENS_STRING("SENS")
#define SENS_DATA 0x19732304
#define SENS_WAIT_HINT 3*1000
enum ACTION { ACTION_NONE, ACTION_APPLICATION, ACTION_SERVICE };
//
// Globals
//
DWORD gdwError; HANDLE ghStopEvent; extern HANDLE ghSensStartedEvent; SYSTEM_POWER_STATUS gSystemPowerState;
//
// Service related stuff
//
SERVICE_STATUS gServiceStatus; // current status of the service
SERVICE_STATUS_HANDLE ghStatusHandle; HDEVNOTIFY ghDeviceNotify;
SERVICE_TABLE_ENTRY gaServiceEntryTable[] = { { SENS_NAME, (LPSERVICE_MAIN_FUNCTION) ServiceMain }, { NULL, NULL } };
//
// Helper functions
//
void __stdcall LogMessage( TCHAR* msg1, TCHAR* msg2 ) /*++
Routine Description:
Arguments:
Return Value:
--*/ { const TCHAR* strings[2] = {msg1, msg2}; HANDLE hEventSource;
hEventSource = RegisterEventSource(NULL, SENS_STRING("SENS"));
if (hEventSource != NULL) { ReportEvent( hEventSource, // event source handle
EVENTLOG_ERROR_TYPE, // event type
0, // event category
0, // event ID
NULL, // current user's SID
2, // strings in lpszStrings
0, // no bytes of raw data
strings, // array of error strings
NULL // no raw data
);
DeregisterEventSource(hEventSource); } }
void ServiceStart( void ) /*++
Routine Description:
Start SENS as service. Stay up until we receive the stop event.
Arguments:
None.
Return Value:
None.
--*/ { // Initialize SENS.
if (FALSE == SensInitialize()) { SensPrintToDebugger(SENS_DBG, ("[SENS] [%d] SensInitialize() failed.\n", GetTickCount())); return; }
// Tell the SCM that we're running now.
if (!ReportStatusToSCM(SERVICE_RUNNING, NO_ERROR, 0)) { SensPrintToDebugger(SENS_DBG, ("[SENS] [%d] ReportStatusToSCM() failed.\n", GetTickCount()));
return; }
// Set the SensStartedEvent now.
if (ghSensStartedEvent != NULL) { SetEvent(ghSensStartedEvent); SensPrintA(SENS_INFO, ("[%d] Successfully signalled starting of SENS.\n", GetTickCount())); } else { SensPrintToDebugger(SENS_DBG, ("[SENS] [%d] Couldn't set the SENS Started event!\n", GetTickCount())); }
SensPrintToDebugger(SENS_DBG, ("\n[SENS] [%d] Started successfully.\n\n", GetTickCount()));
}
void ServiceStop( void ) /*++
Routine Description:
Stop SENS as a service.
Arguments:
None.
Return Value:
None.
--*/ { //
// Cleanup now.
//
SensUninitialize(); }
VOID WINAPI ServiceMain( DWORD argc, TCHAR* argv[] ) /*++
Routine Description:
Perform the actual service initialization.
Arguments:
Usual stuff.
Return Value:
Usual stuff.
--*/ { //
// Initialize Globals.
//
gdwError = 0x0; ghStopEvent = NULL; ghStatusHandle = NULL; memset(&gServiceStatus, 0x0, sizeof(SERVICE_STATUS)); ghDeviceNotify = NULL;
// Service status parameters that don't change.
gServiceStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS; gServiceStatus.dwCurrentState = SERVICE_START_PENDING; gServiceStatus.dwControlsAccepted = 0; gServiceStatus.dwWin32ExitCode = 0; gServiceStatus.dwServiceSpecificExitCode = 0; gServiceStatus.dwCheckPoint = 0; gServiceStatus.dwWaitHint = SENS_WAIT_HINT;
//
// Register our service control handler
//
DEV_BROADCAST_DEVICEINTERFACE PnPFilter;
ghStatusHandle = RegisterServiceCtrlHandlerEx( SENS_NAME, ServiceControl, (PVOID) SENS_DATA ); if (ghStatusHandle == NULL) { return; }
#ifdef PNP_EVENTS
// Before enabling PnP events be aware that the code to unregister for the PnP
// is missing. Since SENS does not use the PnPs the code was all removed.
//
// Register for the PnP Device Interface change notifications
//
PnPFilter.dbcc_size = sizeof(DEV_BROADCAST_DEVICEINTERFACE); PnPFilter.dbcc_devicetype = DBT_DEVTYP_DEVICEINTERFACE; PnPFilter.dbcc_reserved = 0x0; memcpy( &PnPFilter.dbcc_classguid, (LPGUID) &GUID_NDIS_LAN_CLASS, sizeof(GUID) );
ghDeviceNotify = RegisterDeviceNotification( (HANDLE) ghStatusHandle, &PnPFilter, DEVICE_NOTIFY_SERVICE_HANDLE ); if (NULL == ghDeviceNotify) { SensPrintToDebugger(SENS_DBG, ("[SENS] [%d] ServiceMain(): RegisterDeviceNotification() failed\n", GetTickCount())); }
#ifdef DETAIL_DEBUG
SensPrintToDebugger(SENS_DBG, ("[SENS] [%d] ServiceMain(): RegisterDeviceNotification() succeeded\n", GetTickCount())); #endif // DETAIL_DEBUG
#endif // PNP_EVENTS
//
// Save a snapshot of the System Power State.
//
BOOL bRet = GetSystemPowerStatus(&gSystemPowerState); if (bRet == FALSE) { SensPrintA(SENS_ERR, ("SensMessageLoopThread(): GetSystemPowerStatus() failed with " "GLE = %d\n", GetLastError())); } ASSERT(bRet);
// Report the status, the exit code, and the wait hint to the SCM.
if (!ReportStatusToSCM(SERVICE_START_PENDING, NO_ERROR, SENS_WAIT_HINT)) { return; }
// Start the service executing.
ServiceStart();
// Let the thread return. We will use the stop thread to cleanup.
return; }
DWORD WINAPI ServiceControl( DWORD dwCode, DWORD dwEventType, PVOID EventData, PVOID pData ) /*++
Routine Description:
Handle Control Codes from SCM.
Arguments:
dwCode - The control code.
dwEventType - The type of the event.
EventData - Data corresponding to the event.
pData - Additional Data.
Notes:
Refer to \\popcorn\razzle1\src\spec\umevent.doc for further details.
Return Value:
None.
--*/ {
PDEV_BROADCAST_DEVICEINTERFACE pDevice; NTSTATUS NtStatus; ANSI_STRING DeviceNameA; UNICODE_STRING UnicodeString; unsigned char *DeviceUuidA; DWORD dwStatus = NO_ERROR;
pDevice = (PDEV_BROADCAST_DEVICEINTERFACE) EventData; DeviceUuidA = NULL;
#ifdef DETAIL_DEBUG
SensPrintToDebugger(SENS_DBG, ("[SENS] ServiceControl(): dwCode = 0x%x\n", dwCode)); #endif // DETAIL_DEBUG
switch (dwCode) { case SERVICE_CONTROL_STOP: //
// Stop the service.
//
// SERVICE_STOP_PENDING should be reported before setting the Stop
// Event. This avoids a race condition which may result in a 1053
// - "The Service did not respond" error.
//
ReportStatusToSCM(SERVICE_STOP_PENDING, NO_ERROR, SENS_WAIT_HINT);
ServiceStop();
ReportStatusToSCM(SERVICE_STOPPED, NO_ERROR, 0);
return dwStatus;
case SERVICE_CONTROL_INTERROGATE: //
// Update the service status.
//
ReportStatusToSCM(gServiceStatus.dwCurrentState, NO_ERROR, 0); break;
#ifdef PNP_EVENTS
case SERVICE_CONTROL_DEVICEEVENT: //
// PnP event.
//
#ifdef DETAIL_DEBUG
RtlInitUnicodeString(&UnicodeString, (PCWSTR) &pDevice->dbcc_name); NtStatus = RtlUnicodeStringToAnsiString(&DeviceNameA, &UnicodeString, TRUE); UuidToStringA(&pDevice->dbcc_classguid, &DeviceUuidA);
SensPrintToDebugger(SENS_DBG, ("\n-------------------------------------------------------------\n")); SensPrintToDebugger(SENS_DBG, ("SENS received a PnP Event - ")); SensPrintToDebugger(SENS_DBG, ((dwEventType == DBT_DEVICEREMOVECOMPLETE) ? "DEVICE REMOVED\n" : "")); SensPrintToDebugger(SENS_DBG, ((dwEventType == DBT_DEVICEARRIVAL) ? "DEVICE ARRIVED\n" : "\n")); SensPrintToDebugger(SENS_DBG, ("\tdwCode - 0x%x\n", dwCode)); SensPrintToDebugger(SENS_DBG, ("\tdwEventType - 0x%x\n", dwEventType)); SensPrintToDebugger(SENS_DBG, ("\tpData - 0x%x\n", pData)); SensPrintToDebugger(SENS_DBG, ("\tEventData - 0x%x\n", pDevice)); SensPrintToDebugger(SENS_DBG, ("\t o dbcc_size - 0x%x\n", pDevice->dbcc_size)); SensPrintToDebugger(SENS_DBG, ("\t o dbcc_devicetype - 0x%x\n", pDevice->dbcc_devicetype)); SensPrintToDebugger(SENS_DBG, ("\t o dbcc_reserved - 0x%x\n", pDevice->dbcc_reserved)); SensPrintToDebugger(SENS_DBG, ("\t o dbcc_classguid - %s\n", DeviceUuidA)); SensPrintToDebugger(SENS_DBG, ("\t o dbcc_name - %s\n", DeviceNameA.Buffer)); SensPrintToDebugger(SENS_DBG, ("-------------------------------------------------------------\n\n"));
if (NT_SUCCESS(NtStatus)) { RtlFreeAnsiString(&DeviceNameA); } if (DeviceUuidA != NULL) { RpcStringFreeA(&DeviceUuidA); } #endif // DETAIL_DEBUG
break; #endif // PNP_EVENTS
case SERVICE_CONTROL_POWEREVENT: { //
// Power event
//
//
// These are generated every 1% of power change, also by playing
// with the power cpl or plugging in the machine.
//
SYSTEM_POWER_STATUS CurSPstate; SENSEVENT_POWER Data; BOOL bRet; BOOL bFireEvent = FALSE;
bRet = GetSystemPowerStatus(&CurSPstate); ASSERT(bRet);
switch(dwEventType) { case PBT_APMPOWERSTATUSCHANGE: { //
// OnACPower event is fired when
// o previously the machine was not on AC
// o now, it is on AC
//
if ( (CurSPstate.ACLineStatus == AC_LINE_ONLINE) && (gSystemPowerState.ACLineStatus != AC_LINE_ONLINE)) { Data.eType = SENS_EVENT_POWER_ON_ACPOWER; bFireEvent = TRUE; } else //
// OnBatteryPower event is fired when
// o previously the machine was on AC
// o now, it is not on AC
// o the machine has a system battery
//
if ( (CurSPstate.ACLineStatus == AC_LINE_OFFLINE) && (gSystemPowerState.ACLineStatus == AC_LINE_ONLINE) && ((CurSPstate.BatteryFlag & BATTERY_FLAG_NO_BATTERY) == 0)) { Data.eType = SENS_EVENT_POWER_ON_BATTERYPOWER; bFireEvent = TRUE;
// Special case, if the machine goes off battery and has a low
// battery we want to generate both events. Resetting the
// low battery flag here guarantees that next time power changes
// we will fire the low battery event.
CurSPstate.BatteryFlag = CurSPstate.BatteryFlag & ~BATTERY_FLAG_LOW; } else // OnBatteryPowerLow event is fired when
// o the battery is not charging and
// o previously the battery was not low
// o and now the battery is low.
//
if ( (CurSPstate.BatteryFlag & BATTERY_FLAG_LOW) && ( (CurSPstate.BatteryFlag & BATTERY_FLAG_CHARGING) == 0) && ( (gSystemPowerState.BatteryFlag & BATTERY_FLAG_LOW) == 0) ) { Data.eType = SENS_EVENT_POWER_BATTERY_LOW; bFireEvent = TRUE; } else { // Power event we don't about
ASSERT(bFireEvent == FALSE); }
break; }
default: { // Other power event we can ignore
break; } }
if (bFireEvent) { // Save the new state. A critsec is not necessary as service control messages are serialized.
memcpy(&gSystemPowerState, &CurSPstate, sizeof(SYSTEM_POWER_STATUS));
// Fire the event.
memcpy(&Data.PowerStatus, &CurSPstate, sizeof(SYSTEM_POWER_STATUS)); SensFireEvent(&Data); }
dwStatus = SUCCESS; break; }
default:
dwStatus = ERROR_CALL_NOT_IMPLEMENTED;
// invalid control code
break; } return dwStatus; }
BOOL ReportStatusToSCM( DWORD dwCurrentState, DWORD dwExitCode, DWORD dwWaitHint ) /*++
Routine Description:
Report status to SCM.
Arguments:
dwCurrentState - The current state of the service.
dwExitCode - The Win32 Exit code.
dwWaitHint - The amount of time in msec to wait for the SCM to acknowledge.
Return Value:
TRUE, succeeded.
FALSE, otherwise.
--*/ { DWORD dwCheckPoint = 0; BOOL bResult = TRUE;
if (dwCurrentState == SERVICE_START_PENDING) { gServiceStatus.dwControlsAccepted = 0; } else { gServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_POWEREVENT; }
gServiceStatus.dwCurrentState = dwCurrentState; gServiceStatus.dwWin32ExitCode = dwExitCode; gServiceStatus.dwWaitHint = dwWaitHint;
if ( (dwCurrentState == SERVICE_RUNNING) || (dwCurrentState == SERVICE_STOPPED)) { gServiceStatus.dwCheckPoint = 0; } else { gServiceStatus.dwCheckPoint = ++dwCheckPoint; }
//
// Report the status of the service to the SCM.
// Caller handles error reporting, so we can have some context....
//
return SetServiceStatus(ghStatusHandle, &gServiceStatus); }
|