|
|
/*++
Copyright (c) 1992-1997 Microsoft Corporation
Module Name:
service.c
Abstract:
Contains service controller code for SNMP service.
Environment:
User Mode - Win32
Revision History:
10-Feb-1997 DonRyan Rewrote to implement SNMPv2 support.
--*/
///////////////////////////////////////////////////////////////////////////////
// //
// Include files //
// //
///////////////////////////////////////////////////////////////////////////////
#include "globals.h"
#include "service.h"
#include "startup.h"
#include "trapthrd.h"
#include "registry.h"
///////////////////////////////////////////////////////////////////////////////
// //
// Global variables //
// //
///////////////////////////////////////////////////////////////////////////////
SERVICE_STATUS_HANDLE g_SnmpSvcHandle = 0; SERVICE_STATUS g_SnmpSvcStatus = { SERVICE_WIN32, // dwServiceType
SERVICE_STOPPED, // dwCurrentState
0, // dwControlsAccepted
NO_ERROR, // dwWin32ExitCode
0, // dwServiceSpecificExitCode
0, // dwCheckPoint
0 // dwWaitHint
};
///////////////////////////////////////////////////////////////////////////////
// //
// Private procedures //
// //
///////////////////////////////////////////////////////////////////////////////
BOOL TerminateService( )
/*++
Routine Description:
Shutdown SNMP service.
Arguments:
None.
Return Values:
Returns true if successful.
--*/
{ // signal io thread to terminate
BOOL fOk = SetEvent(g_hTerminationEvent); if (!fOk) { SNMPDBG(( SNMP_LOG_ERROR, "SNMP: SVC: error 0x%08lx setting termination event.\n", GetLastError() )); }
return fOk; }
BOOL UpdateController( DWORD dwCurrentState, DWORD dwWaitHint )
/*++
Routine Description:
Notify service controller of SNMP service status.
Arguments:
dwCurrentState - state of the service.
dwWaitHint - worst case estimate to next checkpoint.
Return Values:
Returns true if successful.
--*/
{ BOOL fOk = FALSE;
// validate handle
if (g_SnmpSvcHandle != 0) {
static DWORD dwCheckPoint = 1;
// check to see if the service is starting
if (dwCurrentState == SERVICE_START_PENDING) {
// do not accept controls during startup
g_SnmpSvcStatus.dwControlsAccepted = 0;
} else {
// only accept stop command during operation
g_SnmpSvcStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP; }
// if checkpoint needs incrementing
if ((dwCurrentState == SERVICE_RUNNING) || (dwCurrentState == SERVICE_STOPPED)) {
// re-initialize checkpint
g_SnmpSvcStatus.dwCheckPoint = 0; } else { // increment checkpoint to denote processing
g_SnmpSvcStatus.dwCheckPoint = dwCheckPoint++; }
// update global status structure
g_SnmpSvcStatus.dwCurrentState = dwCurrentState; g_SnmpSvcStatus.dwWaitHint = dwWaitHint; SNMPDBG(( SNMP_LOG_TRACE, "SNMP: SVC: setting service status to %s (0x%08lx).\n", SERVICE_STATUS_STRING(g_SnmpSvcStatus.dwCurrentState), g_SnmpSvcStatus.dwCheckPoint )); // register current state with service controller
fOk = SetServiceStatus(g_SnmpSvcHandle, &g_SnmpSvcStatus);
if (!fOk) { SNMPDBG(( SNMP_LOG_WARNING, "SNMP: SVC: error 0x%08lx setting service status.\n", GetLastError() )); } }
return fOk; }
VOID ProcessControllerRequests( DWORD dwOpCode )
/*++
Routine Description:
Control handling function of SNMP service.
Arguments:
dwOpCode - requested control code.
Return Values:
None.
--*/
{ DWORD dwCurrentState = SERVICE_RUNNING; DWORD dwWaitHint = 0; SNMPDBG(( SNMP_LOG_VERBOSE, "SNMP: SVC: processing request to %s service.\n", SERVICE_CONTROL_STRING(dwOpCode) ));
// handle command
switch (dwOpCode) {
case SERVICE_CONTROL_STOP:
// change service status to stopping
dwCurrentState = SERVICE_STOP_PENDING; dwWaitHint = SNMP_WAIT_HINT;
break;
case SERVICE_CONTROL_INTERROGATE:
//
// update controller below...
//
break;
default:
// check for parameters
if (IS_LOGLEVEL(dwOpCode)) {
UINT nLogLevel;
// derive the new log level from the opcode
nLogLevel = dwOpCode - SNMP_SERVICE_LOGLEVEL_BASE; SNMPDBG(( SNMP_LOG_TRACE, "SNMP: SVC: changing log level to %s.\n", SNMP_LOGLEVEL_STRING(nLogLevel) ));
// store the new log level
SnmpSvcSetLogLevel(nLogLevel);
} else if (IS_LOGTYPE(dwOpCode)) {
UINT nLogType;
// derive the new log type from opcode
nLogType = dwOpCode - SNMP_SERVICE_LOGTYPE_BASE; SNMPDBG(( SNMP_LOG_TRACE, "SNMP: SVC: changing log type to %s.\n", SNMP_LOGTYPE_STRING(nLogType) ));
// store the new log type
SnmpSvcSetLogType(nLogType);
} else { SNMPDBG(( SNMP_LOG_WARNING, "SNMP: SVC: unhandled control code %d.\n", dwOpCode )); }
break; }
// report status to controller
UpdateController(dwCurrentState, dwWaitHint);
// make sure to set shutdown event
if (dwCurrentState == SERVICE_STOP_PENDING) {
// terminate
TerminateService(); } }
BOOL WINAPI ProcessConsoleRequests( DWORD dwOpCode )
/*++
Routine Description:
Handle console control events.
Arguments:
dwOpCode - requested control code.
Return Values:
Returns true if request processed.
--*/
{ BOOL fOk = FALSE;
// check if user wants to exit
if ((dwOpCode == CTRL_C_EVENT) || (dwOpCode == CTRL_BREAK_EVENT)) { SNMPDBG(( SNMP_LOG_TRACE, "SNMP: SVC: processing ctrl-c request.\n" ));
// stop service
fOk = TerminateService(); } return fOk; }
VOID ServiceMain( IN DWORD NumberOfArgs, IN LPTSTR ArgumentPtrs[] )
/*++
Routine Description:
Entry point of SNMP service.
Arguments:
NumberOfArgs - number of command line arguments. ArgumentPtrs - array of pointers to arguments.
Return Values:
None.
--*/
{ // check if we need to bypass dispatcher
if (!g_CmdLineArguments.fBypassCtrlDispatcher) {
// register snmp with service controller
g_SnmpSvcHandle = RegisterServiceCtrlHandler( SNMP_SERVICE, ProcessControllerRequests );
// validate handle
if (g_SnmpSvcHandle == 0) {
// save error code in service status structure
g_SnmpSvcStatus.dwWin32ExitCode = GetLastError(); SNMPDBG(( SNMP_LOG_ERROR, "SNMP: SVC: error 0x%08lx registering service.\n", g_SnmpSvcStatus.dwWin32ExitCode ));
return; // bail...
} } // report status to service controller
UpdateController(SERVICE_START_PENDING, SNMP_WAIT_HINT);
// startup agent
if (StartupAgent()) {
// report status to service controller
UpdateController(SERVICE_RUNNING, NO_WAIT_HINT);
// load registry
// this is done after notifying the service controller that SNMP is up and running
// because of the potential delay taken to load each subagent apart.
// it is done here and not in the thread resumed below, because this call has to complete
// before ProcessSubagentEvents() (data structures used in ProcessSubagentEvents() are initialized in
// LoadRegistryParameters())
// bugs: #259509 & #274055.
LoadRegistryParameters();
if (ResumeThread(g_hAgentThread) != 0xFFFFFFFF) { if (ResumeThread(g_hRegistryThread) == 0xFFFFFFFF) { DWORD errCode = GetLastError();
SNMPDBG(( SNMP_LOG_ERROR, "SNMP: SVC: error 0x%08lx starting the ProcessRegistryMessages thread.\n", errCode )); // log an event to system log file - SNMP service is going on but will not update on registry changes
ReportSnmpEvent( SNMP_EVENT_REGNOTIFY_THREAD_FAILED, 0, NULL, errCode ); } // service subagents
ProcessSubagentEvents(); } else { SNMPDBG(( SNMP_LOG_ERROR, "SNMP: SVC: error 0x%08lx starting the ProcessMessages thread.\n", GetLastError() )); } }
// report status to service controller
UpdateController(SERVICE_STOP_PENDING, SNMP_WAIT_HINT);
// stop agent
ShutdownAgent(); // report status to service controller
UpdateController(SERVICE_STOPPED, NO_WAIT_HINT); }
///////////////////////////////////////////////////////////////////////////////
// //
// Public procedures //
// //
///////////////////////////////////////////////////////////////////////////////
INT __cdecl main( DWORD NumberOfArgs, LPSTR ArgumentPtrs[] )
/*++
Routine Description:
Entry point of program.
Arguments:
NumberOfArgs - number of command line arguments. ArgumentPtrs - array of pointers to arguments.
Return Values:
None.
--*/
{ BOOL fOk; DWORD dwLastError;
static SERVICE_TABLE_ENTRY SnmpServiceTable[] = {{SNMP_SERVICE, ServiceMain}, {NULL, NULL}};
// process command line arguments before starting
if (ProcessArguments(NumberOfArgs, ArgumentPtrs)) {
// create manual reset termination event for service
g_hTerminationEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
// check if we need to bypass dispatcher
if (g_CmdLineArguments.fBypassCtrlDispatcher) { SNMPDBG(( SNMP_LOG_TRACE, "SNMP: SVC: bypassing service controller...\n" )); // install console command handler
SetConsoleCtrlHandler(ProcessConsoleRequests, TRUE);
// dispatch snmp service manually
ServiceMain(NumberOfArgs, (LPTSTR*)ArgumentPtrs);
} else { SNMPDBG(( SNMP_LOG_TRACE, "SNMP: SVC: connecting to service controller...\n" ));
// attempt to connect to service controller
fOk = StartServiceCtrlDispatcher(SnmpServiceTable);
if (!fOk) { // retrieve controller failure
dwLastError = GetLastError();
// check to see whether or not the error was unexpected
if (dwLastError == ERROR_FAILED_SERVICE_CONTROLLER_CONNECT) { SNMPDBG(( SNMP_LOG_TRACE, "SNMP: SVC: unable to connect so manually starting...\n" ));
// make note that service is not connected
g_CmdLineArguments.fBypassCtrlDispatcher = TRUE; // install console command handler
SetConsoleCtrlHandler(ProcessConsoleRequests, TRUE);
// attempt to dispatch service manually
ServiceMain(NumberOfArgs, (LPTSTR*)ArgumentPtrs);
} else { SNMPDBG(( SNMP_LOG_ERROR, "SNMP: SVC: error 0x%08lx connecting to controller.\n", dwLastError )); } } }
// close termination event
CloseHandle(g_hTerminationEvent); } SNMPDBG(( SNMP_LOG_TRACE, "SNMP: SVC: service exiting 0x%08lx.\n", g_SnmpSvcStatus.dwWin32ExitCode ));
// return service status code
return g_SnmpSvcStatus.dwWin32ExitCode; }
|