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.
559 lines
14 KiB
559 lines
14 KiB
/*++
|
|
|
|
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;
|
|
}
|