windows-nt/Source/XPSP1/NT/net/snmp/newagent/exe/service.c
2020-09-26 16:20:57 +08:00

560 lines
14 KiB
C
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*++
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;
}