| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157 |
- #if 0 //def _WIN32
- #include "net-snmp/net-snmp-config.h"
- #include "net-snmp/library/system.h"
- #include <stdlib.h> /* calloc() */
- #include <stdio.h> /* sprintf() */
- #include <windows.h>
- #include <process.h> /* _beginthreadex() */
- #include "net-snmp/library/winservice.h"
- #ifdef mingw32 /* MinGW doesn't fully support exception handling. */
- #define TRY if(1)
- #define LEAVE goto labelFIN
- #define FINALLY do { \
- labelFIN: \
- ; \
- } while(0); if(1)
- #else
- #define TRY __try
- #define LEAVE __leave
- #define FINALLY __finally
- #endif /* mingw32 */
- #if defined(WIN32) && defined(HAVE_WIN32_PLATFORM_SDK) && !defined(mingw32)
- #pragma comment(lib, "iphlpapi.lib")
- #endif
- #if defined(WIN32) && !defined(mingw32)
- #ifdef USING_WINEXTDLL_MODULE
- #pragma comment(lib, "snmpapi.lib")
- #pragma comment(lib, "mgmtapi.lib")
- #endif
- #endif
- /*
- * Error levels returned when registering or unregistering the service
- */
- enum service_status {
- SERVICE_ERROR_NONE = 0,
- SERVICE_ERROR_SCM_OPEN = 1, /* Can not open SCM */
- SERVICE_ERROR_CREATE_SERVICE = 2, /* Can not create service */
- SERVICE_ERROR_CREATE_REGISTRY_ENTRIES = 3, /* Can not create registry entries */
- SERVICE_ERROR_OPEN_SERVICE = 4, /* Can not open service (service does not exist) */
- };
- /*
- * Define Message catalog ID
- * MessageId: DISPLAY_MSG
- * MessageText: %1.
- */
- enum { DISPLAY_MSG = 0x00000064L };
- /*
- * Hint Value to SCM to wait before sending successive commands to service
- */
- enum { SCM_WAIT_INTERVAL = 7000 };
- static void WINAPI ServiceMain(DWORD argc, char *argv[]);
- static void WINAPI ControlHandler(DWORD dwControl);
- static void ProcessServiceStop(void);
- static void ProcessServicePause(void);
- static void ProcessServiceContinue(void);
- static void ProcessServiceInterrogate(void);
- static BOOL SetSimpleSecurityAttributes(SECURITY_ATTRIBUTES
- *pSecurityAttr);
- static void FreeSecurityAttributes(SECURITY_ATTRIBUTES *pSecurityAttr);
- static unsigned WINAPI ThreadFunction(void *lpParam);
- /*
- * External global variables used here
- */
- /*
- * Application Name
- * This should be declared by the application, which wants to register as
- * windows service
- */
- extern "C" {
- char *m_pApp_name_long;
- }
- /*
- * Declare global variable
- */
- /*
- * Flag to indicate whether process is running as Service
- */
- static BOOL g_fRunningAsService;
- /*
- * Variable to maintain Current Service status
- */
- static SERVICE_STATUS ServiceStatus;
- /*
- * Service Handle
- */
- static SERVICE_STATUS_HANDLE hServiceStatus;
- /*
- * Service Table Entry
- */
- SERVICE_TABLE_ENTRY ServiceTableEntry[] = {
- { NULL, ServiceMain }, /* Service Main function */
- { NULL, NULL }
- };
- /*
- * Handle to Thread, to implement Pause, Resume and Stop functions
- */
- static HANDLE hServiceThread = NULL; /* Thread Handle */
- /*
- * Holds calling partys Function Entry point, that should start
- * when entering service mode
- */
- static int(*ServiceEntryPoint)(int Argc, char *Argv[]);
- /*
- * To hold Stop Function address, to be called when STOP request
- * received from the SCM
- */
- static void(*StopFunction)(void);
- /*
- * To update windows service status to SCM
- */
- static BOOL UpdateServiceStatus(DWORD dwStatus, DWORD dwErrorCode,
- DWORD dwWaitHint);
- /*
- * To Report current service status to SCM
- */
- static BOOL ReportCurrentServiceStatus(void);
- void ProcessError(WORD eventLogType, const char *pszMessage,
- int useGetLastError, int quiet);
- #ifndef HAVE__BEGINTHREADEX
- static uintptr_t
- _beginthreadex(void *security, unsigned stack_size,
- unsigned(__stdcall *start_address) (void *), void *arglist,
- unsigned initflag, unsigned *thrdaddr)
- {
- return (uintptr_t)CreateThread(security, stack_size,
- (LPTHREAD_START_ROUTINE)start_address,
- arglist, initflag, (LPDWORD)thrdaddr);
- }
- #if 0
- static void
- _endthreadex(unsigned retval)
- {
- ExitThread(retval);
- }
- #endif
- #endif
- /*
- * To register as Windows Service with SCM(Service Control Manager)
- * Input - Service Name, Service Display Name,Service Description and
- * Service startup arguments
- */
- int
- RegisterService(const char *lpszServiceName,
- const char *lpszServiceDisplayName,
- const char *lpszServiceDescription,
- InputParams *StartUpArg, int quiet)
- { /* Startup argument to the service */
- char szServicePath[MAX_PATH]; /* To hold module File name */
- char MsgErrorString[1024]; /* Message or Error string */
- char szServiceCommand[MAX_PATH + 9]; /* Command to execute */
- SC_HANDLE hSCManager = NULL;
- SC_HANDLE hService = NULL;
- static const char szRegAppLogKey[] =
- "SYSTEM\\CurrentControlSet\\Services\\EventLog\\Application\\";
- char szRegKey[512];
- HKEY hKey = NULL; /* Key to registry entry */
- HKEY hParamKey = NULL; /* To store startup parameters */
- DWORD dwData; /* Type of logging supported */
- int i, j; /* Loop variables */
- int exitStatus = 0;
- GetModuleFileName(NULL, szServicePath, MAX_PATH);
- TRY{
- /*
- * Open Service Control Manager handle
- */
- hSCManager = OpenSCManager(NULL, NULL, SC_MANAGER_CREATE_SERVICE);
- if (hSCManager == NULL) {
- ProcessError(EVENTLOG_ERROR_TYPE,
- "Can't open SCM (Service Control Manager)", 1,
- quiet);
- exitStatus = SERVICE_ERROR_SCM_OPEN;
- LEAVE;
- }
- /*
- * Generate the command to be executed by the SCM
- */
- snprintf(szServiceCommand, sizeof(szServiceCommand),
- "\"%s\" %s", szServicePath, "-service");
- /*
- * Create the desired service
- */
- hService = CreateService(hSCManager, lpszServiceName, lpszServiceDisplayName, SERVICE_ALL_ACCESS, SERVICE_WIN32_OWN_PROCESS, SERVICE_AUTO_START, SERVICE_ERROR_NORMAL, szServiceCommand, NULL, /* load-order group */
- NULL, /* group member tag */
- NULL, /* dependencies */
- NULL, /* account */
- NULL); /* password */
- if (hService == NULL) {
- snprintf(MsgErrorString, sizeof(MsgErrorString),
- "%s %s", "Can't create service",
- lpszServiceDisplayName);
- ProcessError(EVENTLOG_ERROR_TYPE, MsgErrorString, 1, quiet);
- exitStatus = SERVICE_ERROR_CREATE_SERVICE;
- LEAVE;
- }
- /*
- * Create registry entries for the event log
- */
- /*
- * Create registry Application event log key
- */
- snprintf(szRegKey, sizeof(szRegKey), "%s%s", szRegAppLogKey,
- lpszServiceName);
- /*
- * Create registry key
- */
- if (RegCreateKey(HKEY_LOCAL_MACHINE, szRegKey, &hKey) !=
- ERROR_SUCCESS) {
- snprintf(MsgErrorString, sizeof(MsgErrorString),
- "%s %s",
- "is unable to create registry entries",
- lpszServiceDisplayName);
- ProcessError(EVENTLOG_ERROR_TYPE, MsgErrorString, 1, quiet);
- exitStatus = SERVICE_ERROR_CREATE_REGISTRY_ENTRIES;
- LEAVE;
- }
- /*
- * Add Event ID message file name to the 'EventMessageFile' subkey
- */
- RegSetValueEx(hKey, "EventMessageFile", 0, REG_EXPAND_SZ,
- (CONST BYTE *)szServicePath,
- strlen(szServicePath) + sizeof(char));
- /*
- * Set the supported types flags.
- */
- dwData =
- EVENTLOG_ERROR_TYPE | EVENTLOG_WARNING_TYPE |
- EVENTLOG_INFORMATION_TYPE;
- RegSetValueEx(hKey, "TypesSupported", 0, REG_DWORD,
- (CONST BYTE *)&dwData, sizeof(dwData));
- /*
- * Close Registry key
- */
- RegCloseKey(hKey);
- /*
- * Set Service Description String and save startup parameters if present
- */
- if (lpszServiceDescription != NULL || StartUpArg->Argc > 2) {
- /*
- * Create Registry Key path
- */
- snprintf(szRegKey, sizeof(szRegKey),
- "SYSTEM\\CurrentControlSet\\Services\\%s",
- m_pApp_name_long);
- hKey = NULL;
- /*
- * Open Registry key using Create and Set access.
- */
- if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, szRegKey, 0, KEY_WRITE,
- &hKey) != ERROR_SUCCESS) {
- snprintf(MsgErrorString, sizeof(MsgErrorString),
- "%s %s",
- "is unable to create registry entries",
- lpszServiceDisplayName);
- ProcessError(EVENTLOG_ERROR_TYPE, MsgErrorString, 1,
- quiet);
- exitStatus = SERVICE_ERROR_CREATE_REGISTRY_ENTRIES;
- LEAVE;
- }
- /*
- * Create description subkey and the set value
- */
- if (lpszServiceDescription != NULL) {
- if (RegSetValueEx(hKey, "Description", 0, REG_SZ,
- (CONST BYTE *)lpszServiceDescription,
- strlen(lpszServiceDescription) +
- sizeof(char)) != ERROR_SUCCESS) {
- snprintf(MsgErrorString, sizeof(MsgErrorString),
- "%s %s",
- "is unable to create registry entries",
- lpszServiceDisplayName);
- ProcessError(EVENTLOG_ERROR_TYPE, MsgErrorString, 1,
- quiet);
- exitStatus = SERVICE_ERROR_CREATE_REGISTRY_ENTRIES;
- LEAVE;
- };
- }
- /*
- * Save startup arguments if they are present
- */
- if (StartUpArg->Argc > 2) {
- /*
- * Create Subkey parameters
- */
- if (RegCreateKeyEx
- (hKey, "Parameters", 0, NULL,
- REG_OPTION_NON_VOLATILE, KEY_WRITE, NULL,
- &hParamKey, NULL) != ERROR_SUCCESS) {
- snprintf(MsgErrorString, sizeof(MsgErrorString),
- "%s %s",
- "is unable to create registry entries",
- lpszServiceDisplayName);
- ProcessError(EVENTLOG_ERROR_TYPE, MsgErrorString, 1,
- quiet);
- exitStatus = SERVICE_ERROR_CREATE_REGISTRY_ENTRIES;
- LEAVE;
- }
- /*
- * Save parameters
- */
- /*
- * Loop through arguments
- */
- if (quiet) /* Make sure we don't store -quiet arg */
- i = 3;
- else
- i = 2;
- for (j = 1; i < StartUpArg->Argc; i++, j++) {
- snprintf(szRegKey, sizeof(szRegKey), "%s%d", "Param",
- j);
- /*
- * Create registry key
- */
- if (RegSetValueEx
- (hParamKey, szRegKey, 0, REG_SZ,
- (CONST BYTE *)StartUpArg->Argv[i],
- strlen(StartUpArg->Argv[i]) +
- sizeof(char)) != ERROR_SUCCESS) {
- snprintf(MsgErrorString, sizeof(MsgErrorString),
- "%s %s",
- "is unable to create registry entries",
- lpszServiceDisplayName);
- ProcessError(EVENTLOG_ERROR_TYPE, MsgErrorString,
- 1, quiet);
- exitStatus = SERVICE_ERROR_CREATE_REGISTRY_ENTRIES;
- LEAVE;
- };
- }
- }
- /*
- * Everything is set, delete hKey
- */
- RegCloseKey(hParamKey);
- RegCloseKey(hKey);
- }
- /*
- * Ready to log messages
- */
- /*
- * Successfully registered as service
- */
- snprintf(MsgErrorString, sizeof(MsgErrorString), "%s %s",
- lpszServiceName, "successfully registered as a service");
- /*
- * Log message to eventlog
- */
- ProcessError(EVENTLOG_INFORMATION_TYPE, MsgErrorString, 0, quiet);
- }
- FINALLY{
- if (hSCManager)
- CloseServiceHandle(hSCManager);
- if (hService)
- CloseServiceHandle(hService);
- if (hKey)
- RegCloseKey(hKey);
- if (hParamKey)
- RegCloseKey(hParamKey);
- }
- return (exitStatus);
- }
- /*
- * Unregister the service with the Windows SCM
- * Input - ServiceName
- */
- int
- UnregisterService(const char *lpszServiceName, int quiet)
- {
- char MsgErrorString[1024]; /* Message or Error string */
- SC_HANDLE hSCManager = NULL; /* SCM handle */
- SC_HANDLE hService = NULL; /* Service Handle */
- SERVICE_STATUS sStatus;
- static const char szRegAppLogKey[] =
- "SYSTEM\\CurrentControlSet\\Services\\EventLog\\Application\\";
- char szRegKey[512];
- int exitStatus = 0;
- /*
- * HKEY hKey = NULL; ?* Key to registry entry
- */
- TRY{
- /*
- * Open Service Control Manager
- */
- hSCManager = OpenSCManager(NULL, NULL, SC_MANAGER_CREATE_SERVICE);
- if (hSCManager == NULL) {
- ProcessError(EVENTLOG_ERROR_TYPE,
- "Can't open SCM (Service Control Manager)", 1,
- quiet);
- exitStatus = SERVICE_ERROR_SCM_OPEN;
- LEAVE;
- }
- /*
- * Open registered service
- */
- hService =
- OpenService(hSCManager, lpszServiceName, SERVICE_ALL_ACCESS);
- if (hService == NULL) {
- snprintf(MsgErrorString, sizeof(MsgErrorString),
- "%s %s", "Can't open service", lpszServiceName);
- ProcessError(EVENTLOG_ERROR_TYPE, MsgErrorString, 1, quiet);
- exitStatus = SERVICE_ERROR_OPEN_SERVICE;
- LEAVE;
- }
- /*
- * Query service status
- * If running stop before deleting
- */
- if (QueryServiceStatus(hService, &sStatus)) {
- if (sStatus.dwCurrentState == SERVICE_RUNNING
- || sStatus.dwCurrentState == SERVICE_PAUSED) {
- ControlService(hService, SERVICE_CONTROL_STOP, &sStatus);
- }
- };
- /*
- * Delete the service
- */
- if (DeleteService(hService) == FALSE) {
- snprintf(MsgErrorString, sizeof(MsgErrorString),
- "%s %s", "Can't delete service", lpszServiceName);
- /*
- * Log message to eventlog
- */
- ProcessError(EVENTLOG_ERROR_TYPE, MsgErrorString, 0, quiet);
- LEAVE;
- }
- /*
- * Log "Service deleted successfully " message to eventlog
- */
- snprintf(MsgErrorString, sizeof(MsgErrorString), "%s %s",
- lpszServiceName, "service deleted");
- ProcessError(EVENTLOG_INFORMATION_TYPE, MsgErrorString, 0, quiet);
- /*
- * Delete registry entries for EventLog
- */
- snprintf(szRegKey, sizeof(szRegKey), "%s%s", szRegAppLogKey,
- lpszServiceName);
- RegDeleteKey(HKEY_LOCAL_MACHINE, szRegKey);
- }
- /*
- * Delete the handles
- */
- FINALLY{
- if (hService)
- CloseServiceHandle(hService);
- if (hSCManager)
- CloseServiceHandle(hSCManager);
- }
- return (exitStatus);
- }
- /*
- * Write a message to the Windows event log.
- */
- static void
- WriteToEventLog(WORD wType, const char *pszFormat, ...)
- {
- char szMessage[512];
- const char *LogStr[1];
- va_list ArgList;
- HANDLE hEventSource = NULL;
- va_start(ArgList, pszFormat);
- vsnprintf(szMessage, sizeof(szMessage), pszFormat, ArgList);
- va_end(ArgList);
- LogStr[0] = szMessage;
- hEventSource = RegisterEventSource(NULL, m_pApp_name_long);
- if (hEventSource == NULL)
- return;
- ReportEvent(hEventSource, wType, 0,
- DISPLAY_MSG, NULL, 1, 0, LogStr, NULL);
- DeregisterEventSource(hEventSource);
- }
- /*
- * Pre-process the second command-line argument from the user.
- * Service related options are:
- * -register - registers the service
- * -unregister - unregisters the service
- * -service - run as service
- * other command-line arguments are ignored here.
- *
- * Return: Type indicating the option specified
- */
- enum net_snmp_cmd_line_action
- ParseCmdLineForServiceOption(int argc, char *argv[], int *quiet)
- {
- enum net_snmp_cmd_line_action nReturn = RUN_AS_CONSOLE; /* default is to run as a console application */
- if (argc >= 2) {
- /*
- * second argument present
- */
- if (strcasecmp("-register", argv[1]) == 0) {
- nReturn = REGISTER_SERVICE;
- }
- else if (strcasecmp("-unregister", argv[1]) == 0) {
- nReturn = UN_REGISTER_SERVICE;
- }
- else if (strcasecmp("-service", argv[1]) == 0) {
- nReturn = RUN_AS_SERVICE;
- }
- }
- #if 1
- if (argc >= 3) {
- /*
- * third argument present
- */
- if (strcasecmp("-quiet", argv[2]) == 0) {
- *quiet = 1;
- }
- }
- #endif
- return nReturn;
- }
- /*
- * Write error message to event log, console or pop-up window.
- *
- * If useGetLastError is 1, the last error returned from GetLastError()
- * is appended to pszMessage, separated by a ": ".
- *
- * eventLogType: MessageBox equivalent:
- *
- * EVENTLOG_INFORMATION_TYPE MB_ICONASTERISK
- * EVENTLOG_WARNING_TYPE MB_ICONEXCLAMATION
- * EVENTLOG_ERROR_TYPE MB_ICONSTOP
- *
- */
- void
- ProcessError(WORD eventLogType, const char *pszMessage,
- int useGetLastError, int quiet)
- {
- HANDLE hEventSource = NULL;
- char pszMessageFull[1024]; /* Combined pszMessage and GetLastError */
- /*
- * If useGetLastError enabled, generate text from GetLastError() and append to
- * pszMessageFull
- */
- if (useGetLastError) {
- char *pErrorMsgTemp = NULL;
- FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
- FORMAT_MESSAGE_FROM_SYSTEM, NULL, GetLastError(),
- MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
- (LPTSTR)&pErrorMsgTemp, 0, NULL);
- snprintf(pszMessageFull, sizeof(pszMessageFull), "%s: %s",
- pszMessage, pErrorMsgTemp);
- if (pErrorMsgTemp) {
- LocalFree(pErrorMsgTemp);
- pErrorMsgTemp = NULL;
- }
- }
- else {
- snprintf(pszMessageFull, sizeof(pszMessageFull), "%s", pszMessage);
- }
- hEventSource = RegisterEventSource(NULL, m_pApp_name_long);
- if (hEventSource != NULL) {
- const char *LogStr[1];
- LogStr[0] = pszMessageFull;
- if (ReportEvent(hEventSource, eventLogType, 0, DISPLAY_MSG, /* just output the text to the event log */
- NULL, 1, 0, LogStr, NULL)) {
- }
- else {
- char *pErrorMsgTemp = NULL;
- FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
- FORMAT_MESSAGE_FROM_SYSTEM, NULL, GetLastError(),
- MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
- (LPTSTR)&pErrorMsgTemp, 0, NULL);
- fprintf(stderr,
- "Could NOT lot to Event Log. Error returned from ReportEvent(): %s\n",
- pErrorMsgTemp);
- if (pErrorMsgTemp) {
- LocalFree(pErrorMsgTemp);
- pErrorMsgTemp = NULL;
- }
- }
- DeregisterEventSource(hEventSource);
- }
- if (quiet) {
- fprintf(stderr, "%s\n", pszMessageFull);
- }
- else {
- switch (eventLogType) {
- case EVENTLOG_INFORMATION_TYPE:
- MessageBox(NULL, pszMessageFull, m_pApp_name_long,
- MB_ICONASTERISK);
- break;
- case EVENTLOG_WARNING_TYPE:
- MessageBox(NULL, pszMessageFull, m_pApp_name_long,
- MB_ICONEXCLAMATION);
- break;
- case EVENTLOG_ERROR_TYPE:
- MessageBox(NULL, pszMessageFull, m_pApp_name_long, MB_ICONSTOP);
- break;
- default:
- MessageBox(NULL, pszMessageFull, m_pApp_name_long,
- EVENTLOG_WARNING_TYPE);
- break;
- }
- }
- }
- /*
- * Update current service status.
- * Sends the current service status to the SCM. Also updates
- * the global service status structure.
- */
- static BOOL
- UpdateServiceStatus(DWORD dwStatus, DWORD dwErrorCode, DWORD dwWaitHint)
- {
- static DWORD dwCheckpoint = 1;
- DWORD dwControls =
- SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_PAUSE_CONTINUE;
- if (g_fRunningAsService == FALSE)
- return FALSE;
- ZeroMemory(&ServiceStatus, sizeof(ServiceStatus));
- ServiceStatus.dwServiceType = SERVICE_WIN32;
- ServiceStatus.dwCurrentState = dwStatus;
- ServiceStatus.dwWaitHint = dwWaitHint;
- if (dwErrorCode) {
- ServiceStatus.dwWin32ExitCode = ERROR_SERVICE_SPECIFIC_ERROR;
- ServiceStatus.dwServiceSpecificExitCode = dwErrorCode;
- }
- /*
- * special cases that depend on the new state
- */
- switch (dwStatus) {
- case SERVICE_START_PENDING:
- dwControls = 0;
- break;
- case SERVICE_RUNNING:
- case SERVICE_STOPPED:
- dwCheckpoint = 0;
- break;
- }
- ServiceStatus.dwCheckPoint = dwCheckpoint++;
- ServiceStatus.dwControlsAccepted = dwControls;
- return ReportCurrentServiceStatus();
- }
- /*
- * Reports current service status to SCM
- */
- static BOOL
- ReportCurrentServiceStatus()
- {
- return SetServiceStatus(hServiceStatus, &ServiceStatus);
- }
- /*
- * ServiceMain function.
- */
- static void WINAPI
- ServiceMain(DWORD argc, char *argv[])
- {
- SECURITY_ATTRIBUTES SecurityAttributes;
- unsigned threadId;
- /*
- * Input arguments
- */
- DWORD ArgCount = 0;
- char **ArgArray = NULL;
- char szRegKey[512];
- HKEY hParamKey = NULL;
- DWORD TotalParams = 0;
- int i;
- InputParams ThreadInputParams;
- /*
- * Build the Input parameters to pass to worker thread
- */
- /*
- * SCM sends Service Name as first arg, increment to point
- * arguments user specified while starting control agent
- */
- /*
- * Read registry parameter
- */
- ArgCount = 1;
- /*
- * Create registry key path
- */
- snprintf(szRegKey, sizeof(szRegKey), "%s%s\\%s",
- "SYSTEM\\CurrentControlSet\\Services\\", m_pApp_name_long,
- "Parameters");
- if (RegOpenKeyEx
- (HKEY_LOCAL_MACHINE, szRegKey, 0, KEY_ALL_ACCESS,
- &hParamKey) == ERROR_SUCCESS) {
- /*
- * Read startup configuration information
- */
- /*
- * Find number of subkeys inside parameters
- */
- if (RegQueryInfoKey(hParamKey, NULL, NULL, 0,
- NULL, NULL, NULL, &TotalParams,
- NULL, NULL, NULL, NULL) == ERROR_SUCCESS) {
- if (TotalParams != 0) {
- ArgCount += TotalParams;
- /*
- * Allocate memory to hold strings
- */
- ArgArray = (char**)calloc(ArgCount, sizeof(ArgArray[0]));
- if (ArgArray == 0) {
- WriteToEventLog(EVENTLOG_ERROR_TYPE,
- "Resource failure");
- return;
- }
- /*
- * Copy first argument
- */
- ArgArray[0] = strdup(argv[0]);
- for (i = 1; i <= TotalParams; i++) {
- DWORD dwErrorcode;
- DWORD nSize;
- DWORD nRegkeyType;
- char *szValue;
- /*
- * Create Subkey value name
- */
- snprintf(szRegKey, sizeof(szRegKey), "%s%d", "Param",
- i);
- /*
- * Query subkey.
- */
- nSize = 0;
- dwErrorcode =
- RegQueryValueEx(hParamKey, szRegKey, NULL,
- &nRegkeyType, NULL, &nSize);
- if (dwErrorcode == ERROR_SUCCESS) {
- if (nRegkeyType == REG_SZ
- || nRegkeyType == REG_EXPAND_SZ) {
- szValue = (char*)malloc(nSize + sizeof(szValue[0]));
- if (szValue) {
- dwErrorcode =
- RegQueryValueEx(hParamKey, szRegKey,
- NULL, &nRegkeyType,
- (LPBYTE)szValue,
- &nSize);
- if (dwErrorcode == ERROR_SUCCESS) {
- szValue[nSize] = 0;
- ArgArray[i] = szValue;
- }
- else {
- free(szValue);
- WriteToEventLog(EVENTLOG_ERROR_TYPE,
- "Querying registry key %s failed: error code %ld",
- szRegKey, dwErrorcode);
- }
- }
- else
- WriteToEventLog(EVENTLOG_ERROR_TYPE,
- "Querying registry key %s failed: out of memory",
- szRegKey);
- }
- else
- WriteToEventLog(EVENTLOG_ERROR_TYPE,
- "Type %ld of registry key %s is incorrect",
- nRegkeyType, szRegKey);
- }
- else
- WriteToEventLog(EVENTLOG_ERROR_TYPE,
- "Querying registry key %s failed: error code %ld",
- szRegKey, dwErrorcode);
- if (!ArgArray[i]) {
- TotalParams = ArgCount = i;
- break;
- }
- }
- }
- }
- RegCloseKey(hParamKey);
- }
- if (ArgCount == 1) {
- /*
- * No startup args are given
- */
- ThreadInputParams.Argc = argc;
- ThreadInputParams.Argv = argv;
- }
- else {
- ThreadInputParams.Argc = ArgCount;
- ThreadInputParams.Argv = ArgArray;
- }
- /*
- * Register Service Control Handler
- */
- hServiceStatus =
- RegisterServiceCtrlHandler(m_pApp_name_long, ControlHandler);
- if (hServiceStatus == 0) {
- WriteToEventLog(EVENTLOG_ERROR_TYPE,
- "RegisterServiceCtrlHandler failed");
- return;
- }
- /*
- * Update the service status to START_PENDING.
- */
- UpdateServiceStatus(SERVICE_START_PENDING, NO_ERROR,
- SCM_WAIT_INTERVAL);
- /*
- * Start the worker thread, which does the majority of the work .
- */
- TRY{
- if (SetSimpleSecurityAttributes(&SecurityAttributes) == FALSE) {
- WriteToEventLog(EVENTLOG_ERROR_TYPE,
- "Couldn't init security attributes");
- LEAVE;
- }
- hServiceThread =
- (void *)_beginthreadex(&SecurityAttributes, 0,
- ThreadFunction,
- (void *)&ThreadInputParams, 0,
- &threadId);
- if (hServiceThread == NULL) {
- WriteToEventLog(EVENTLOG_ERROR_TYPE,
- "Couldn't start worker thread");
- LEAVE;
- }
- /*
- * Set service status to SERVICE_RUNNING.
- */
- UpdateServiceStatus(SERVICE_RUNNING, NO_ERROR, SCM_WAIT_INTERVAL);
- /*
- * Wait until the worker thread finishes.
- */
- WaitForSingleObject(hServiceThread, INFINITE);
- }
- FINALLY{
- /*
- * Release resources
- */
- UpdateServiceStatus(SERVICE_STOPPED, NO_ERROR, SCM_WAIT_INTERVAL);
- if (hServiceThread)
- CloseHandle(hServiceThread);
- FreeSecurityAttributes(&SecurityAttributes);
- /*
- * Free allocated argument list
- */
- if (ArgCount > 1 && ArgArray != NULL) {
- /*
- * Free all strings
- */
- for (i = 0; i < ArgCount; i++) {
- free(ArgArray[i]);
- }
- free(ArgArray);
- }
- }
- }
- /*
- * Function to start as Windows service
- * The calling party should specify their entry point as input parameter
- * Returns TRUE if the Service is started successfully
- */
- BOOL
- RunAsService(int(*ServiceFunction)(int, char **))
- {
- /*
- * Set the ServiceEntryPoint
- */
- ServiceEntryPoint = ServiceFunction;
- /*
- * By default, mark as Running as a service
- */
- g_fRunningAsService = TRUE;
- /*
- * Initialize ServiceTableEntry table
- */
- ServiceTableEntry[0].lpServiceName = m_pApp_name_long; /* Application Name */
- /*
- * Call SCM via StartServiceCtrlDispatcher to run as Service
- * * If the function returns TRUE we are running as Service,
- */
- if (StartServiceCtrlDispatcher(ServiceTableEntry) == FALSE) {
- g_fRunningAsService = FALSE;
- /*
- * Some other error has occurred.
- */
- WriteToEventLog(EVENTLOG_ERROR_TYPE,
- "Couldn't start service - %s", m_pApp_name_long);
- }
- return g_fRunningAsService;
- }
- /*
- * Service control handler function
- * Responds to SCM commands/requests
- * This service handles 4 commands
- * - interrogate, pause, continue and stop.
- */
- void WINAPI
- ControlHandler(DWORD dwControl)
- {
- switch (dwControl) {
- case SERVICE_CONTROL_INTERROGATE:
- ProcessServiceInterrogate();
- break;
- case SERVICE_CONTROL_PAUSE:
- ProcessServicePause();
- break;
- case SERVICE_CONTROL_CONTINUE:
- ProcessServiceContinue();
- break;
- case SERVICE_CONTROL_STOP:
- ProcessServiceStop();
- break;
- }
- }
- /*
- * To stop the service.
- * If a stop function was registered, invoke it,
- * otherwise terminate the worker thread.
- * After stopping, Service status is set to STOP in
- * main loop
- */
- void
- ProcessServiceStop(void)
- {
- UpdateServiceStatus(SERVICE_STOP_PENDING, NO_ERROR, SCM_WAIT_INTERVAL);
- if (StopFunction != NULL) {
- (*StopFunction) ();
- }
- else {
- TerminateThread(hServiceThread, 0);
- }
- }
- /*
- * Returns the current state of the service to the SCM.
- */
- void
- ProcessServiceInterrogate(void)
- {
- ReportCurrentServiceStatus();
- }
- /*
- * To Create a security descriptor with a NULL ACL, which
- * allows unlimited access. Returns a SECURITY_ATTRIBUTES
- * structure that contains the security descriptor.
- * The structure contains a dynamically allocated security
- * descriptor that must be freed either manually, or by
- * calling FreeSecurityAttributes
- */
- BOOL
- SetSimpleSecurityAttributes(SECURITY_ATTRIBUTES *pSecurityAttr)
- {
- BOOL fReturn = FALSE;
- SECURITY_DESCRIPTOR *pSecurityDesc = NULL;
- /*
- * If an invalid address is passed as a parameter, return
- * FALSE right away.
- */
- if (!pSecurityAttr)
- return FALSE;
- pSecurityDesc =
- (SECURITY_DESCRIPTOR *)LocalAlloc(LPTR,
- SECURITY_DESCRIPTOR_MIN_LENGTH);
- if (!pSecurityDesc)
- return FALSE;
- fReturn =
- InitializeSecurityDescriptor(pSecurityDesc,
- SECURITY_DESCRIPTOR_REVISION);
- if (fReturn != FALSE) {
- fReturn =
- SetSecurityDescriptorDacl(pSecurityDesc, TRUE, NULL, FALSE);
- }
- if (fReturn != FALSE) {
- pSecurityAttr->nLength = sizeof(SECURITY_ATTRIBUTES);
- pSecurityAttr->lpSecurityDescriptor = pSecurityDesc;
- pSecurityAttr->bInheritHandle = TRUE;
- }
- else {
- /*
- * Couldn't initialize or set security descriptor.
- */
- LocalFree(pSecurityDesc);
- }
- return fReturn;
- }
- /*
- * This function Frees the security descriptor, if any was created.
- */
- void
- FreeSecurityAttributes(SECURITY_ATTRIBUTES *pSecurityAttr)
- {
- if (pSecurityAttr && pSecurityAttr->lpSecurityDescriptor)
- LocalFree(pSecurityAttr->lpSecurityDescriptor);
- }
- /*
- * This function runs in the worker thread
- * until an exit is forced, or until the SCM issues the STOP command.
- * Invokes registered service function
- * Returns when called registered function returns
- *
- * Input:
- * lpParam contains argc and argv, pass to service main function
- */
- unsigned WINAPI
- ThreadFunction(void *lpParam)
- {
- InputParams *pInputArg = (InputParams *)lpParam;
- return (*ServiceEntryPoint) (pInputArg->Argc, pInputArg->Argv);
- }
- /*
- * This function is called to register an application-specific function
- * which is invoked when the SCM stops the worker thread.
- */
- void
- RegisterStopFunction(void(*StopFunc)(void))
- {
- StopFunction = StopFunc;
- }
- /*
- * SCM pause command invokes this function
- * If the service is not running, this function does nothing.
- * Otherwise, suspend the worker thread and update the status.
- */
- void
- ProcessServicePause(void)
- {
- if (ServiceStatus.dwCurrentState == SERVICE_RUNNING) {
- UpdateServiceStatus(SERVICE_PAUSE_PENDING, NO_ERROR,
- SCM_WAIT_INTERVAL);
- if (SuspendThread(hServiceThread) != -1) {
- UpdateServiceStatus(SERVICE_PAUSED, NO_ERROR,
- SCM_WAIT_INTERVAL);
- }
- }
- }
- /*
- * SCM resume command invokes this function
- * If the service is not paused, this function does nothing.
- * Otherwise, resume the worker thread and update the status.
- */
- void
- ProcessServiceContinue(void)
- {
- if (ServiceStatus.dwCurrentState == SERVICE_PAUSED) {
- UpdateServiceStatus(SERVICE_CONTINUE_PENDING, NO_ERROR,
- SCM_WAIT_INTERVAL);
- if (ResumeThread(hServiceThread) != -1) {
- UpdateServiceStatus(SERVICE_RUNNING, NO_ERROR,
- SCM_WAIT_INTERVAL);
- }
- }
- }
- #endif /* WIN32 */
|