Leaked source code of windows server 2003
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

  1. /*++
  2. Copyright (c) 1992-1997 Microsoft Corporation
  3. Module Name:
  4. service.c
  5. Abstract:
  6. Contains service controller code for SNMP service.
  7. Environment:
  8. User Mode - Win32
  9. Revision History:
  10. 10-Feb-1997 DonRyan
  11. Rewrote to implement SNMPv2 support.
  12. --*/
  13. ///////////////////////////////////////////////////////////////////////////////
  14. // //
  15. // Include files //
  16. // //
  17. ///////////////////////////////////////////////////////////////////////////////
  18. #include "globals.h"
  19. #include "service.h"
  20. #include "startup.h"
  21. #include "trapthrd.h"
  22. #include "registry.h"
  23. ///////////////////////////////////////////////////////////////////////////////
  24. // //
  25. // Global variables //
  26. // //
  27. ///////////////////////////////////////////////////////////////////////////////
  28. SERVICE_STATUS_HANDLE g_SnmpSvcHandle = 0;
  29. SERVICE_STATUS g_SnmpSvcStatus = {
  30. SERVICE_WIN32, // dwServiceType
  31. SERVICE_STOPPED, // dwCurrentState
  32. 0, // dwControlsAccepted
  33. NO_ERROR, // dwWin32ExitCode
  34. 0, // dwServiceSpecificExitCode
  35. 0, // dwCheckPoint
  36. 0 // dwWaitHint
  37. };
  38. ///////////////////////////////////////////////////////////////////////////////
  39. // //
  40. // Private procedures //
  41. // //
  42. ///////////////////////////////////////////////////////////////////////////////
  43. BOOL
  44. TerminateService(
  45. )
  46. /*++
  47. Routine Description:
  48. Shutdown SNMP service.
  49. Arguments:
  50. None.
  51. Return Values:
  52. Returns true if successful.
  53. --*/
  54. {
  55. // signal io thread to terminate
  56. BOOL fOk = SetEvent(g_hTerminationEvent);
  57. if (!fOk) {
  58. SNMPDBG((
  59. SNMP_LOG_ERROR,
  60. "SNMP: SVC: error 0x%08lx setting termination event.\n",
  61. GetLastError()
  62. ));
  63. }
  64. return fOk;
  65. }
  66. BOOL
  67. UpdateController(
  68. DWORD dwCurrentState,
  69. DWORD dwWaitHint
  70. )
  71. /*++
  72. Routine Description:
  73. Notify service controller of SNMP service status.
  74. Arguments:
  75. dwCurrentState - state of the service.
  76. dwWaitHint - worst case estimate to next checkpoint.
  77. Return Values:
  78. Returns true if successful.
  79. --*/
  80. {
  81. BOOL fOk = FALSE;
  82. // validate handle
  83. if (g_SnmpSvcHandle != 0) {
  84. static DWORD dwCheckPoint = 1;
  85. // check to see if the service is starting
  86. if (dwCurrentState == SERVICE_START_PENDING) {
  87. // do not accept controls during startup
  88. g_SnmpSvcStatus.dwControlsAccepted = 0;
  89. } else {
  90. // only accept stop command during operation
  91. g_SnmpSvcStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP;
  92. }
  93. // if checkpoint needs incrementing
  94. if ((dwCurrentState == SERVICE_RUNNING) ||
  95. (dwCurrentState == SERVICE_STOPPED)) {
  96. // re-initialize checkpint
  97. g_SnmpSvcStatus.dwCheckPoint = 0;
  98. } else {
  99. // increment checkpoint to denote processing
  100. g_SnmpSvcStatus.dwCheckPoint = dwCheckPoint++;
  101. }
  102. // update global status structure
  103. g_SnmpSvcStatus.dwCurrentState = dwCurrentState;
  104. g_SnmpSvcStatus.dwWaitHint = dwWaitHint;
  105. SNMPDBG((
  106. SNMP_LOG_TRACE,
  107. "SNMP: SVC: setting service status to %s (0x%08lx).\n",
  108. SERVICE_STATUS_STRING(g_SnmpSvcStatus.dwCurrentState),
  109. g_SnmpSvcStatus.dwCheckPoint
  110. ));
  111. // register current state with service controller
  112. fOk = SetServiceStatus(g_SnmpSvcHandle, &g_SnmpSvcStatus);
  113. if (!fOk) {
  114. SNMPDBG((
  115. SNMP_LOG_WARNING,
  116. "SNMP: SVC: error 0x%08lx setting service status.\n",
  117. GetLastError()
  118. ));
  119. }
  120. }
  121. return fOk;
  122. }
  123. VOID
  124. ProcessControllerRequests(
  125. DWORD dwOpCode
  126. )
  127. /*++
  128. Routine Description:
  129. Control handling function of SNMP service.
  130. Arguments:
  131. dwOpCode - requested control code.
  132. Return Values:
  133. None.
  134. --*/
  135. {
  136. DWORD dwCurrentState = SERVICE_RUNNING;
  137. DWORD dwWaitHint = 0;
  138. SNMPDBG((
  139. SNMP_LOG_VERBOSE,
  140. "SNMP: SVC: processing request to %s service.\n",
  141. SERVICE_CONTROL_STRING(dwOpCode)
  142. ));
  143. // handle command
  144. switch (dwOpCode) {
  145. case SERVICE_CONTROL_STOP:
  146. // change service status to stopping
  147. dwCurrentState = SERVICE_STOP_PENDING;
  148. dwWaitHint = SNMP_WAIT_HINT;
  149. break;
  150. case SERVICE_CONTROL_INTERROGATE:
  151. //
  152. // update controller below...
  153. //
  154. break;
  155. default:
  156. // check for parameters
  157. if (IS_LOGLEVEL(dwOpCode)) {
  158. UINT nLogLevel;
  159. // derive the new log level from the opcode
  160. nLogLevel = dwOpCode - SNMP_SERVICE_LOGLEVEL_BASE;
  161. SNMPDBG((
  162. SNMP_LOG_TRACE,
  163. "SNMP: SVC: changing log level to %s.\n",
  164. SNMP_LOGLEVEL_STRING(nLogLevel)
  165. ));
  166. // store the new log level
  167. SnmpSvcSetLogLevel(nLogLevel);
  168. } else if (IS_LOGTYPE(dwOpCode)) {
  169. UINT nLogType;
  170. // derive the new log type from opcode
  171. nLogType = dwOpCode - SNMP_SERVICE_LOGTYPE_BASE;
  172. SNMPDBG((
  173. SNMP_LOG_TRACE,
  174. "SNMP: SVC: changing log type to %s.\n",
  175. SNMP_LOGTYPE_STRING(nLogType)
  176. ));
  177. // store the new log type
  178. SnmpSvcSetLogType(nLogType);
  179. } else {
  180. SNMPDBG((
  181. SNMP_LOG_WARNING,
  182. "SNMP: SVC: unhandled control code %d.\n",
  183. dwOpCode
  184. ));
  185. }
  186. break;
  187. }
  188. // report status to controller
  189. UpdateController(dwCurrentState, dwWaitHint);
  190. // make sure to set shutdown event
  191. if (dwCurrentState == SERVICE_STOP_PENDING) {
  192. // terminate
  193. TerminateService();
  194. }
  195. }
  196. BOOL
  197. WINAPI
  198. ProcessConsoleRequests(
  199. DWORD dwOpCode
  200. )
  201. /*++
  202. Routine Description:
  203. Handle console control events.
  204. Arguments:
  205. dwOpCode - requested control code.
  206. Return Values:
  207. Returns true if request processed.
  208. --*/
  209. {
  210. BOOL fOk = FALSE;
  211. // check if user wants to exit
  212. if ((dwOpCode == CTRL_C_EVENT) ||
  213. (dwOpCode == CTRL_BREAK_EVENT)) {
  214. SNMPDBG((
  215. SNMP_LOG_TRACE,
  216. "SNMP: SVC: processing ctrl-c request.\n"
  217. ));
  218. // stop service
  219. fOk = TerminateService();
  220. }
  221. return fOk;
  222. }
  223. VOID
  224. ServiceMain(
  225. IN DWORD NumberOfArgs,
  226. IN LPTSTR ArgumentPtrs[]
  227. )
  228. /*++
  229. Routine Description:
  230. Entry point of SNMP service.
  231. Arguments:
  232. NumberOfArgs - number of command line arguments.
  233. ArgumentPtrs - array of pointers to arguments.
  234. Return Values:
  235. None.
  236. --*/
  237. {
  238. // check if we need to bypass dispatcher
  239. if (!g_CmdLineArguments.fBypassCtrlDispatcher) {
  240. // register snmp with service controller
  241. g_SnmpSvcHandle = RegisterServiceCtrlHandler(
  242. SNMP_SERVICE,
  243. ProcessControllerRequests
  244. );
  245. // validate handle
  246. if (g_SnmpSvcHandle == 0) {
  247. // save error code in service status structure
  248. g_SnmpSvcStatus.dwWin32ExitCode = GetLastError();
  249. SNMPDBG((
  250. SNMP_LOG_ERROR,
  251. "SNMP: SVC: error 0x%08lx registering service.\n",
  252. g_SnmpSvcStatus.dwWin32ExitCode
  253. ));
  254. return; // bail...
  255. }
  256. }
  257. // report status to service controller
  258. UpdateController(SERVICE_START_PENDING, SNMP_WAIT_HINT);
  259. // startup agent
  260. if (StartupAgent()) {
  261. // report status to service controller
  262. UpdateController(SERVICE_RUNNING, NO_WAIT_HINT);
  263. // load registry
  264. // this is done after notifying the service controller that SNMP is up and running
  265. // because of the potential delay taken to load each subagent apart.
  266. // it is done here and not in the thread resumed below, because this call has to complete
  267. // before ProcessSubagentEvents() (data structures used in ProcessSubagentEvents() are initialized in
  268. // LoadRegistryParameters())
  269. // bugs: #259509 & #274055.
  270. LoadRegistryParameters();
  271. if (ResumeThread(g_hAgentThread) != 0xFFFFFFFF)
  272. {
  273. if (ResumeThread(g_hRegistryThread) == 0xFFFFFFFF)
  274. {
  275. DWORD errCode = GetLastError();
  276. SNMPDBG((
  277. SNMP_LOG_ERROR,
  278. "SNMP: SVC: error 0x%08lx starting the ProcessRegistryMessages thread.\n",
  279. errCode
  280. ));
  281. // log an event to system log file - SNMP service is going on but will not update on registry changes
  282. ReportSnmpEvent(
  283. SNMP_EVENT_REGNOTIFY_THREAD_FAILED,
  284. 0,
  285. NULL,
  286. errCode
  287. );
  288. }
  289. // service subagents
  290. ProcessSubagentEvents();
  291. }
  292. else
  293. {
  294. SNMPDBG((
  295. SNMP_LOG_ERROR,
  296. "SNMP: SVC: error 0x%08lx starting the ProcessMessages thread.\n",
  297. GetLastError()
  298. ));
  299. }
  300. }
  301. // report status to service controller
  302. UpdateController(SERVICE_STOP_PENDING, SNMP_WAIT_HINT);
  303. // stop agent
  304. ShutdownAgent();
  305. // report status to service controller
  306. UpdateController(SERVICE_STOPPED, NO_WAIT_HINT);
  307. }
  308. ///////////////////////////////////////////////////////////////////////////////
  309. // //
  310. // Public procedures //
  311. // //
  312. ///////////////////////////////////////////////////////////////////////////////
  313. INT
  314. __cdecl
  315. main(
  316. DWORD NumberOfArgs,
  317. LPSTR ArgumentPtrs[]
  318. )
  319. /*++
  320. Routine Description:
  321. Entry point of program.
  322. Arguments:
  323. NumberOfArgs - number of command line arguments.
  324. ArgumentPtrs - array of pointers to arguments.
  325. Return Values:
  326. None.
  327. --*/
  328. {
  329. BOOL fOk;
  330. DWORD dwLastError;
  331. static SERVICE_TABLE_ENTRY SnmpServiceTable[] =
  332. {{SNMP_SERVICE, ServiceMain}, {NULL, NULL}};
  333. // process command line arguments before starting
  334. if (ProcessArguments(NumberOfArgs, ArgumentPtrs)) {
  335. // create manual reset termination event for service
  336. g_hTerminationEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
  337. // check if we need to bypass dispatcher
  338. if (g_CmdLineArguments.fBypassCtrlDispatcher) {
  339. SNMPDBG((
  340. SNMP_LOG_TRACE,
  341. "SNMP: SVC: bypassing service controller...\n"
  342. ));
  343. // install console command handler
  344. SetConsoleCtrlHandler(ProcessConsoleRequests, TRUE);
  345. // dispatch snmp service manually
  346. ServiceMain(NumberOfArgs, (LPTSTR*)ArgumentPtrs);
  347. } else {
  348. SNMPDBG((
  349. SNMP_LOG_TRACE,
  350. "SNMP: SVC: connecting to service controller...\n"
  351. ));
  352. // attempt to connect to service controller
  353. fOk = StartServiceCtrlDispatcher(SnmpServiceTable);
  354. if (!fOk) {
  355. // retrieve controller failure
  356. dwLastError = GetLastError();
  357. // check to see whether or not the error was unexpected
  358. if (dwLastError == ERROR_FAILED_SERVICE_CONTROLLER_CONNECT) {
  359. SNMPDBG((
  360. SNMP_LOG_TRACE,
  361. "SNMP: SVC: unable to connect so manually starting...\n"
  362. ));
  363. // make note that service is not connected
  364. g_CmdLineArguments.fBypassCtrlDispatcher = TRUE;
  365. // install console command handler
  366. SetConsoleCtrlHandler(ProcessConsoleRequests, TRUE);
  367. // attempt to dispatch service manually
  368. ServiceMain(NumberOfArgs, (LPTSTR*)ArgumentPtrs);
  369. } else {
  370. SNMPDBG((
  371. SNMP_LOG_ERROR,
  372. "SNMP: SVC: error 0x%08lx connecting to controller.\n",
  373. dwLastError
  374. ));
  375. }
  376. }
  377. }
  378. // close termination event
  379. CloseHandle(g_hTerminationEvent);
  380. }
  381. SNMPDBG((
  382. SNMP_LOG_TRACE,
  383. "SNMP: SVC: service exiting 0x%08lx.\n",
  384. g_SnmpSvcStatus.dwWin32ExitCode
  385. ));
  386. // return service status code
  387. return g_SnmpSvcStatus.dwWin32ExitCode;
  388. }