1 martin 1.4 //%LICENSE////////////////////////////////////////////////////////////////
2 //
3 // Licensed to The Open Group (TOG) under one or more contributor license
4 // agreements. Refer to the OpenPegasusNOTICE.txt file distributed with
5 // this work for additional information regarding copyright ownership.
6 // Each contributor licenses this file to you under the OpenPegasus Open
7 // Source License; you may not use this file except in compliance with the
8 // License.
9 //
10 // Permission is hereby granted, free of charge, to any person obtaining a
11 // copy of this software and associated documentation files (the "Software"),
12 // to deal in the Software without restriction, including without limitation
13 // the rights to use, copy, modify, merge, publish, distribute, sublicense,
14 // and/or sell copies of the Software, and to permit persons to whom the
15 // Software is furnished to do so, subject to the following conditions:
16 //
17 // The above copyright notice and this permission notice shall be included
18 // in all copies or substantial portions of the Software.
19 //
20 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
21 // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
22 martin 1.4 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
23 // IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
24 // CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
25 // TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
26 // SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
27 h.sterling 1.1 //
|
28 martin 1.4 //////////////////////////////////////////////////////////////////////////
|
29 h.sterling 1.1 //
30 // Author: Tony Fiorentino (fiorentino_tony@emc.com)
31 //
32 //%/////////////////////////////////////////////////////////////////////////////
33 #include <time.h>
34 #include <stdio.h>
35 #include <windows.h>
36 #include <process.h>
37
38 #include "Service.h"
39
40 //-------------------------------------------------------------------------
41 // G L O B A L S
42 //-------------------------------------------------------------------------
43 int Service::g_argc = 0;
44 char **Service::g_argv = NULL;
45 char *Service::g_service_name = NULL;
46 char *Service::g_event_source = NULL;
47 DWORD Service::g_flags = 0;
48 DWORD Service::g_current_state = 0;
49 SERVICE_STATUS_HANDLE Service::g_service_status_handle = 0;
50 h.sterling 1.1 SERVICE_MAIN_T Service::g_service_main = NULL;
51
52 //-------------------------------------------------------------------------
53 // P U B L I C
54 //-------------------------------------------------------------------------
|
55 kumpf 1.3 Service::Service()
|
56 h.sterling 1.1 {
57 }
58
|
59 kumpf 1.3 Service::Service(const char* service_name)
|
60 h.sterling 1.1 {
|
61 kumpf 1.3 // ATTN: I have to allocate memory here, unless I want to change the
62 // char* g_service_name to a char[]. Changing to an array of char
63 // affects a lot more code. Previously, this method had a char* for its
64 // input parameter, and since we were using #define's the values were
65 // always in memory.
66 // Now we are using an interface method that returns const char* -hns PEP222
|
67 h.sterling 1.1 g_service_name = (char*) malloc(strlen(service_name)+1);
68 memset(g_service_name, '\0', strlen(service_name)+1);
69 strncpy(g_service_name, service_name, strlen(service_name));
70 }
71
|
72 kumpf 1.3 Service::Service(
73 const char* service_name,
74 char* event_source)
|
75 h.sterling 1.1 {
76 g_event_source = event_source;
77
78 g_service_name = (char*) malloc(strlen(service_name)+1);
79 memset(g_service_name, '\0', strlen(service_name)+1);
80 strncpy(g_service_name, service_name, strlen(service_name));
81 }
82
|
83 kumpf 1.3 Service::~Service()
|
84 h.sterling 1.1 {
|
85 kumpf 1.3 // ATTN: Will open Bugzilla on this. I need to change this to either use
86 // char arrays OR deallocate the memory elsewhere. I cannot use any fancy
87 // AutoPtr stuff since Pegasus code is kept out of this OS-specific file
|
88 h.sterling 1.1 // -hns PEP#222
89 /*if (g_service_name != NULL)
90 {
91 free(g_service_name);
92 }*/
93 }
94
|
95 kumpf 1.3 void Service::SetServiceName(char* service_name)
|
96 h.sterling 1.1 {
97 if (g_service_name != NULL)
98 {
99 free(g_service_name);
100 }
101
102 g_service_name = (char*) malloc(strlen(service_name)+1);
103 memset(g_service_name, '\0', strlen(service_name)+1);
104 strncpy(g_service_name, service_name, strlen(service_name));
105 }
106
107 /*-------------------------------------------------------------------------*
108 * Method: Install *
109 * *
110 * Args: *
111 * display_name *
112 * The service's display name (hopefully more descriptive, will show *
113 * up in the Win32 Services MMC snapin as "Service Name"). *
114 * *
115 * exe_name: *
116 * The service's executable name (full path, please) *
117 h.sterling 1.1 * *
118 * flags: *
119 * Reserved. Currently unused. *
120 * *
121 * Description: *
122 * This function creates the service. *
123 * *
124 * NOTE: If the process is successfully launched as a Win32 service, this *
125 * function never returns, but calls exit() instead. *
126 *-------------------------------------------------------------------------*/
|
127 kumpf 1.3 Service::ReturnCode Service::Install(
|
128 h.sterling 1.1 char *display_name,
129 char *description,
130 char *exe_name)
131 {
|
132 kumpf 1.3 ReturnCode status = SERVICE_RETURN_SUCCESS;
133 SC_HANDLE sch;
|
134 h.sterling 1.1
|
135 kumpf 1.3 if (g_service_name == NULL || display_name == NULL || exe_name == NULL)
136 return SERVICE_ERROR_NOT_FOUND; // SERVICE_ERROR_NOT_FOUND
137 else if ((sch = OpenSCManager(NULL, NULL, SC_MANAGER_CREATE_SERVICE)) ==
138 NULL)
139 status = get_error(GetLastError(), "open");
140 else
141 {
142 SC_HANDLE service = CreateService(
143 sch, // SCManager database
144 g_service_name, // name of service
145 display_name, // service name to display
146 SERVICE_ALL_ACCESS, // desired access
147 SERVICE_WIN32_OWN_PROCESS, // service type
148 SERVICE_DEMAND_START, // start type
149 SERVICE_ERROR_NORMAL, // error control type
150 exe_name, // service's binary
151 NULL, // no load ordering group
152 NULL, // no tag identifier
153 NULL, // no dependencies
154 NULL, // LocalSystem account
155 NULL); // no password
156 kumpf 1.3
157 if (service == NULL)
|
158 h.sterling 1.1 {
|
159 kumpf 1.3 status = get_error(GetLastError(), "create");
160 return status;
|
161 h.sterling 1.1 }
|
162 kumpf 1.3 else
|
163 h.sterling 1.1 {
|
164 kumpf 1.3 change_service_description(service, description);
165 CloseServiceHandle(service);
|
166 h.sterling 1.1 }
|
167 kumpf 1.3
168 CloseServiceHandle(sch);
|
169 h.sterling 1.1 }
170
|
171 kumpf 1.3 return status;
|
172 h.sterling 1.1 }
173
174 /*-------------------------------------------------------------------------*
175 * Method: Remove *
176 * *
177 * Description: *
178 * Removes the service. *
179 *-------------------------------------------------------------------------*/
|
180 kumpf 1.3 Service::ReturnCode Service::Remove()
|
181 h.sterling 1.1 {
|
182 kumpf 1.3 ReturnCode status = SERVICE_RETURN_SUCCESS;
183 SC_HANDLE sch;
|
184 h.sterling 1.1
|
185 kumpf 1.3 if (g_service_name == NULL)
186 return SERVICE_ERROR_NOT_FOUND; /* SERVICE_ERROR_NOT_FOUND */
187 else if ((sch = OpenSCManager(NULL, NULL, SC_MANAGER_CREATE_SERVICE)) ==
188 NULL)
189 status = get_error(GetLastError(), "open");
190 else
191 {
192 SC_HANDLE service = OpenService(sch, g_service_name, DELETE);
193
194 if (service == NULL)
|
195 h.sterling 1.1 {
|
196 kumpf 1.3 status = get_error(GetLastError(), "open");
|
197 h.sterling 1.1 }
|
198 kumpf 1.3 else
|
199 h.sterling 1.1 {
|
200 kumpf 1.3 if (!DeleteService(service))
|
201 h.sterling 1.1 {
|
202 kumpf 1.3 status = get_error(GetLastError(), "remove");
|
203 h.sterling 1.1 }
204
|
205 kumpf 1.3 CloseServiceHandle(service);
|
206 h.sterling 1.1 }
|
207 kumpf 1.3
208 CloseServiceHandle(sch);
|
209 h.sterling 1.1 }
210
|
211 kumpf 1.3 return status;
|
212 h.sterling 1.1 }
213
214 /*-------------------------------------------------------------------------*
215 * Method: Start *
216 * *
217 * Args: *
218 * wait_time: *
219 * The user supplied wait (~1 second per QueryServiceStatus() attempt) *
220 * *
221 * Description: *
222 * Attempt to start the service. *
223 *-------------------------------------------------------------------------*/
|
224 kumpf 1.3 Service::ReturnCode Service::Start(int wait_time)
|
225 h.sterling 1.1 {
|
226 kumpf 1.3 ReturnCode status = SERVICE_RETURN_SUCCESS;
227 SERVICE_STATUS service_status;
228 SC_HANDLE sch;
229
230 if (g_service_name == NULL)
231 return SERVICE_ERROR_NOT_FOUND; // SERVICE_ERROR_NOT_FOUND
232 else if ((sch = OpenSCManager(NULL, NULL, GENERIC_READ)) == NULL)
|
233 h.sterling 1.1 status = get_error(GetLastError(), "open");
|
234 kumpf 1.3 else
235 {
236 SC_HANDLE service = OpenService(
237 sch, g_service_name, SERVICE_START | SERVICE_QUERY_STATUS);
238
239 if (service == NULL)
240 status = get_error(GetLastError(), "open");
241 else if (!StartService(service, g_argc, (const char **)g_argv))
242 status = get_error(GetLastError(), "start");
243 else
|
244 h.sterling 1.1 {
|
245 kumpf 1.3 int i, max = (wait_time > 0) ? wait_time : 5;
|
246 h.sterling 1.1
|
247 kumpf 1.3 // Loop up to max times waiting for the service
248 // state to change to RUNNING
|
249 h.sterling 1.1
|
250 kumpf 1.3 for (i = 0; i < max; i++)
|
251 h.sterling 1.1 {
|
252 kumpf 1.3 if (!QueryServiceStatus(service, &service_status))
|
253 h.sterling 1.1 {
|
254 kumpf 1.3 status = get_error(GetLastError(), "query");
255 return status; // QUERY_FAIL
|
256 h.sterling 1.1 }
257
|
258 kumpf 1.3 if (service_status.dwCurrentState == SERVICE_RUNNING)
259 break;
|
260 h.sterling 1.1
|
261 kumpf 1.3 Sleep(1 * CLOCKS_PER_SEC);
|
262 h.sterling 1.1 }
263
|
264 kumpf 1.3 status = (i < max) ?
265 SERVICE_RETURN_SUCCESS : SERVICE_ERROR_REQUEST_TIMEOUT;
266
267 CloseServiceHandle(service);
|
268 h.sterling 1.1 }
|
269 kumpf 1.3
270 CloseServiceHandle(sch);
|
271 h.sterling 1.1 }
272
|
273 kumpf 1.3 return status;
274 }
|
275 h.sterling 1.1
276 /*-------------------------------------------------------------------------*
277 * Method: Stop *
278 * *
279 * Args: *
280 * wait_time: *
281 * The user supplied wait (~1 second per QueryServiceStatus() attempt) *
282 * *
283 * Description: *
284 * Attempt to stop the service. *
285 *-------------------------------------------------------------------------*/
|
286 kumpf 1.3 Service::ReturnCode Service::Stop(int wait_time)
|
287 h.sterling 1.1 {
|
288 kumpf 1.3 ReturnCode status = SERVICE_RETURN_SUCCESS;
289 SERVICE_STATUS service_status;
290 SC_HANDLE sch;
291
292 if (g_service_name == NULL)
293 return SERVICE_ERROR_NOT_FOUND; // SERVICE_ERROR_NOT_FOUND
294 else if ((sch = OpenSCManager(NULL, NULL, GENERIC_READ)) == NULL)
|
295 h.sterling 1.1 status = get_error(GetLastError(), "open");
|
296 kumpf 1.3 // show_error("OpenSCMManager", "service", GetLastError());
297 else
298 {
299 SC_HANDLE service = OpenService(
300 sch, g_service_name, SERVICE_STOP | SERVICE_QUERY_STATUS);
301
302 if (service == NULL)
303 status = get_error(GetLastError(), "open");
304 else if (!ControlService(
305 service, SERVICE_CONTROL_STOP, &service_status))
306 status = get_error(GetLastError(), "stop");
307 else
|
308 h.sterling 1.1 {
|
309 kumpf 1.3 int i, max = (wait_time > 0) ? wait_time : 5;
|
310 h.sterling 1.1
|
311 kumpf 1.3 // Loop up to max times waiting for the service
312 // state to change to STOPPED
|
313 h.sterling 1.1
|
314 kumpf 1.3 for (i = 0; i < max; i++)
|
315 h.sterling 1.1 {
|
316 kumpf 1.3 if (!QueryServiceStatus(service, &service_status))
|
317 h.sterling 1.1 {
|
318 kumpf 1.3 status = get_error(GetLastError(), "query");
319 return status; // QUERY_FAIL
|
320 h.sterling 1.1 }
321
|
322 kumpf 1.3 if (service_status.dwCurrentState == SERVICE_STOPPED)
323 break;
|
324 h.sterling 1.1
|
325 kumpf 1.3 Sleep(1 * CLOCKS_PER_SEC);
|
326 h.sterling 1.1 }
327
|
328 kumpf 1.3 status = (i < max) ?
329 SERVICE_RETURN_SUCCESS : SERVICE_ERROR_REQUEST_TIMEOUT;
330
331 CloseServiceHandle(service);
|
332 h.sterling 1.1 }
|
333 kumpf 1.3
334 CloseServiceHandle(sch);
|
335 h.sterling 1.1 }
336
|
337 kumpf 1.3 return status;
|
338 h.sterling 1.1 }
339
340 /*-------------------------------------------------------------------------*
341 * Method: Run *
342 * *
343 * Args: *
344 * service_main: *
345 * The user supplied service_main function (not to be confused with *
346 * real_service_main above) *
347 * *
348 * flags: *
349 * Reserved. Currently unused. *
350 * *
351 * Description: *
352 * This function interacts with the SCM to run the current process *
353 * as a Win32 service. *
354 * *
355 * NOTE: If the process is successfully launched as a Win32 service, this *
356 * function never returns, but calls exit() instead. *
357 *-------------------------------------------------------------------------*/
358
|
359 kumpf 1.3 Service::ReturnCode Service::Run(SERVICE_MAIN_T service_main, DWORD flags)
|
360 h.sterling 1.1 {
|
361 kumpf 1.3 ReturnCode status = SERVICE_RETURN_SUCCESS;
|
362 h.sterling 1.1
|
363 kumpf 1.3 SERVICE_TABLE_ENTRY dispatchTable[] =
364 {
365 { g_service_name, real_service_main },
366 { NULL, NULL }
367 };
|
368 h.sterling 1.1
|
369 kumpf 1.3 // Validate the arguments as best we can
|
370 h.sterling 1.1
|
371 kumpf 1.3 if (g_service_name == NULL || service_main == NULL)
372 return SERVICE_ERROR_NOT_FOUND; // SERVICE_ERROR_NOT_FOUND
|
373 h.sterling 1.1
|
374 kumpf 1.3 // Save parameters in global variables
|
375 h.sterling 1.1
|
376 kumpf 1.3 g_flags = flags;
377 g_service_main = service_main;
|
378 h.sterling 1.1
|
379 kumpf 1.3 // Kick off the service
|
380 h.sterling 1.1
|
381 kumpf 1.3 if (!StartServiceCtrlDispatcher(dispatchTable))
|
382 h.sterling 1.1 {
|
383 kumpf 1.3 status = get_error(GetLastError(), "start");
384 return status; // FAIL
|
385 h.sterling 1.1 }
386
|
387 kumpf 1.3 // Don't call exit()
388 return status;
|
389 h.sterling 1.1 }
390
391 /*-------------------------------------------------------------------------*
392 * Method: GetState *
393 * *
394 * Description: *
395 * Returns the state of the service into "state". *
396 *-------------------------------------------------------------------------*/
|
397 kumpf 1.3 Service::ReturnCode Service::GetState(State* state)
|
398 h.sterling 1.1 {
|
399 kumpf 1.3 ReturnCode status = SERVICE_RETURN_SUCCESS;
400 SERVICE_STATUS service_status;
401 SC_HANDLE sch;
402
403 if (g_service_name == NULL)
404 return SERVICE_ERROR_NOT_FOUND; // SERVICE_ERROR_NOT_FOUND
405 else if ((sch = OpenSCManager(NULL, NULL, GENERIC_READ)) == NULL)
|
406 h.sterling 1.1 status = get_error(GetLastError(), "open");
|
407 kumpf 1.3 else
408 {
409 SC_HANDLE service =
410 OpenService(sch, g_service_name, SERVICE_QUERY_STATUS);
411
412 if (service == NULL)
413 status = get_error(GetLastError(), "open");
414 else if (!QueryServiceStatus(service, &service_status))
415 status = get_error(GetLastError(), "query");
416 else
|
417 h.sterling 1.1 {
|
418 kumpf 1.3 *state = get_state(service_status.dwCurrentState);
419 CloseServiceHandle(service);
|
420 h.sterling 1.1 }
|
421 kumpf 1.3
422 CloseServiceHandle(sch);
|
423 h.sterling 1.1 }
424
|
425 kumpf 1.3 return status;
|
426 h.sterling 1.1 }
427
428 /*-------------------------------------------------------------------------*
429 * Method: LogEvent *
430 * *
431 * Args: *
432 * event_type: *
433 * The Win32 event type. Valid event types are: *
434 * EVENTLOG_SUCCESS : Success event *
435 * EVENTLOG_ERROR_TYPE : Error event *
436 * EVENTLOG_WARNING_TYPE : Warning event *
437 * EVENTLOG_INFORMATION_TYPE : Information event *
438 * EVENTLOG_AUDIT_SUCCESS : Success audit event *
439 * EVENTLOG_AUDIT_FAILURE : Failure audit event *
440 * *
441 * event_id: *
442 * A fancy name for error code or error number. *
443 * *
444 * string: *
445 * String to be logged or merged in with the error string in the *
446 * message DLL. *
447 h.sterling 1.1 * *
448 * Description: *
449 * This function provides a simple layer over the Win32 error logging *
450 * API's. *
451 * *
452 * Returns: *
453 * true if event was successfully logged *
454 * false if the event could not be logged *
455 *-------------------------------------------------------------------------*/
|
456 kumpf 1.3 bool Service::LogEvent(WORD event_type, DWORD event_id, const char *string)
|
457 h.sterling 1.1 {
|
458 kumpf 1.3 BOOL status;
459 HANDLE h_event_source = RegisterEventSource(NULL, g_event_source);
|
460 h.sterling 1.1
|
461 kumpf 1.3 if (h_event_source == NULL)
462 FALSE;
|
463 h.sterling 1.1
|
464 kumpf 1.3 status = ReportEvent(
465 h_event_source,
466 event_type,
467 0,
468 event_id,
469 NULL,
470 1,
471 0,
472 &string,
473 NULL);
|
474 h.sterling 1.1
|
475 kumpf 1.3 DeregisterEventSource(h_event_source);
|
476 h.sterling 1.1
|
477 kumpf 1.3 return (status == TRUE);
|
478 h.sterling 1.1 }
479
480 //-------------------------------------------------------------------------
481 // P R I V A T E
482 //-------------------------------------------------------------------------
483 /*-------------------------------------------------------------------------*
484 * Routine: real_service_main *
485 * *
486 * Args: *
487 * argc: *
488 * The number of arguments in the argv array *
489 * argv: *
490 * An array of strings representing the command line arguments *
491 * *
492 * Description: *
493 * This function is the real service main (as opposed to the user *
494 * supplied service main, which is called service_main). *
495 * *
496 * Returns: *
497 * nothing *
498 *-------------------------------------------------------------------------*/
499 h.sterling 1.1 void __stdcall
500 Service::real_service_main(DWORD argc, LPTSTR *argv)
501 {
|
502 kumpf 1.3 // Let the SCM know we're alive and kicking
|
503 h.sterling 1.1
|
504 kumpf 1.3 report_status(SERVICE_START_PENDING, NO_ERROR, 0, 5000);
|
505 h.sterling 1.1
|
506 kumpf 1.3 // If the command line arguments include the string "-debug" then
507 // invoke the debugger
|
508 h.sterling 1.1
|
509 kumpf 1.3 if (check_args_for_string("-debug"))
510 DebugBreak();
|
511 h.sterling 1.1
|
512 kumpf 1.3 // Save copy of argc and argc in global variables
|
513 h.sterling 1.1
|
514 kumpf 1.3 g_argc = argc;
515 g_argv = argv;
|
516 h.sterling 1.1
|
517 kumpf 1.3 // Start service actions
|
518 h.sterling 1.1
|
519 kumpf 1.3 g_service_status_handle =
520 RegisterServiceCtrlHandler(g_service_name, service_control_handler);
|
521 h.sterling 1.1
|
522 kumpf 1.3 if (g_service_status_handle == 0)
|
523 h.sterling 1.1 {
|
524 kumpf 1.3 show_error("register", "Service Control Handler", GetLastError());
525 report_status(SERVICE_STOPPED, NO_ERROR, 0, 5000);
526 return;
|
527 h.sterling 1.1 }
528
|
529 kumpf 1.3 // Change our state to RUNNING, then invoke the user supplied
530 // service_main function. After the user's service_main exits,
531 // change the service state to STOPPED.
|
532 h.sterling 1.1
|
533 kumpf 1.3 report_status(SERVICE_RUNNING, NO_ERROR, 0, 5000);
534 g_service_main(STARTUP_FLAG, argc, argv);
535 report_status(SERVICE_STOPPED, NO_ERROR, 0, 5000);
|
536 h.sterling 1.1
|
537 kumpf 1.3 return;
|
538 h.sterling 1.1 }
539
540 /*-------------------------------------------------------------------------*
541 * Routine: check_args_for_string *
542 * *
543 * Args: *
544 * string: *
545 * The string to match. *
546 * *
547 * Description: *
548 * This function iterates through the command line arguments searching *
549 * for the string specified by the string parameter. *
550 * *
551 * Returns: *
552 * true if the string was found *
553 * false if the string was not found *
554 *-------------------------------------------------------------------------*/
|
555 kumpf 1.3 bool Service::check_args_for_string(char* string)
|
556 h.sterling 1.1 {
|
557 kumpf 1.3 int i;
|
558 h.sterling 1.1
|
559 kumpf 1.3 for (i = 1; i < g_argc; i++)
|
560 h.sterling 1.1 {
|
561 kumpf 1.3 if (strcmp(g_argv[i], string) == 0)
562 return true;
|
563 h.sterling 1.1 }
564
|
565 kumpf 1.3 return false;
|
566 h.sterling 1.1 }
567
568 /*-------------------------------------------------------------------------*
569 * Method: service_control_handler *
570 * *
571 * Args: *
572 * control: *
573 * The control sent from the SCM telling us what action to take: *
574 * start, stop, pause, continue, etc. *
575 * *
576 * Description: *
577 * This function handles control messages sent from the SCM. Currently *
578 * the only message that is handled differently is the STOP message, *
579 * which invokes the user's service main function passing to it the *
580 * SHUTDOWN_FLAG. The user is then responsible to perform all shutdown *
581 * related tasks. *
582 * *
583 * Returns: *
584 * Nothing *
585 *-------------------------------------------------------------------------*/
586
587 h.sterling 1.1 void WINAPI
588 Service::service_control_handler(DWORD control)
589 {
|
590 kumpf 1.3 /* Currently, only the stop contol requires special handling */
|
591 h.sterling 1.1
|
592 kumpf 1.3 if (control == SERVICE_CONTROL_STOP)
|
593 h.sterling 1.1 {
|
594 kumpf 1.3 report_status(SERVICE_STOP_PENDING, NO_ERROR, 0, 5000);
595 g_service_main(SHUTDOWN_FLAG, g_argc, g_argv);
596 return;
|
597 h.sterling 1.1 }
598
|
599 kumpf 1.3 /* For every other control, just send back our current state */
|
600 h.sterling 1.1
|
601 kumpf 1.3 report_status(g_current_state, NO_ERROR, 0, 5000);
|
602 h.sterling 1.1 }
603
604 /*-------------------------------------------------------------------------*
605 * Method: report_status *
606 * *
607 * Args: *
608 * current_state: *
609 * The service's new state. May be any valid Win32 service state. *
610 * *
611 * exit_code: *
612 * This must be a Win32 exit code. If the server is exiting due to *
613 * an error returned from the Win32 API, then this is the place to *
614 * report the error status. Most of the time, this will be NO_ERROR. *
615 * *
616 * check_point: *
617 * An integer value that should start at zero and increment as each *
618 * discrete step within a phase is completed. For example, if startup *
619 * consists of 3 steps, then the startup will issue its first check- *
620 * point of zero, then increment up through and including 2 as each *
621 * step is finished. *
622 * *
623 h.sterling 1.1 * wait_hint: *
624 * Tells the SCM how long to expect to wait for the next status *
625 * update. *
626 * *
627 * Description: *
628 * This function provides an even higher level of abstraction over *
629 * the Win32 event logging API's. *
630 * *
631 * Returns: *
632 * true if the status was successfully reported *
633 * false if the status could not be reported *
634 *-------------------------------------------------------------------------*/
|
635 kumpf 1.3 bool Service::report_status(
636 DWORD current_state,
637 DWORD exit_code,
638 DWORD check_point,
639 DWORD wait_hint)
640 {
641 SERVICE_STATUS current_status =
642 {
643 SERVICE_WIN32,
644 current_state,
645 SERVICE_CONTROL_INTERROGATE,
646 exit_code,
647 0,
648 check_point,
649 wait_hint
650 };
651
652 /* Wait until we're started before we accept a stop control */
653
654 if (current_state == SERVICE_RUNNING)
655 current_status.dwControlsAccepted += SERVICE_ACCEPT_STOP;
656 kumpf 1.3
657 /* Save new state */
658
659 g_current_state = current_state;
660
661 return (SetServiceStatus(g_service_status_handle, ¤t_status) == TRUE);
|
662 h.sterling 1.1 }
663
664 /*-------------------------------------------------------------------------*
665 * Method: change_service_description *
666 * *
667 * Args: *
668 * service: *
669 * Handle to the service *
670 * *
671 * description: *
672 * The service's description *
673 * *
674 * Description: *
675 * This function sets the description for the service. The description *
676 * text shows up in the Services mmc snapin. The description is added *
677 * as a benefit to users, but does not affect the service's operation. *
678 * Therefore, if this function should fail for any reason, there is *
679 * no need to stop. That's why this function has no return value. *
680 * *
681 * Returns: *
682 * Nothing *
683 h.sterling 1.1 * *
684 * Notes: *
685 * This function uses the ChangeServiceConfig2() API function which *
686 * first appeared in Windows2000. Therefore, this code checks the *
687 * OS version, before calling ChangeServiceConfig2(). *
688 *-------------------------------------------------------------------------*/
|
689 kumpf 1.3 void Service::change_service_description(SC_HANDLE service, char *description)
|
690 h.sterling 1.1 {
|
691 kumpf 1.3 OSVERSIONINFO osvi;
692
693 /*
694 * Test for Windows 2000 or greater
695 */
|
696 h.sterling 1.1
|
697 kumpf 1.3 osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
|
698 h.sterling 1.1
|
699 kumpf 1.3 if (GetVersionEx(&osvi) != 0 &&
700 osvi.dwPlatformId == VER_PLATFORM_WIN32_NT &&
701 osvi.dwMajorVersion >= 5)
|
702 h.sterling 1.1 {
|
703 kumpf 1.3 typedef BOOL
704 (WINAPI *CHANGE_SERVICE_CONFIG2_T)(SC_HANDLE, DWORD, LPVOID);
|
705 h.sterling 1.1
|
706 kumpf 1.3 HINSTANCE hdll = LoadLibrary("advapi32.dll");
|
707 h.sterling 1.1
|
708 kumpf 1.3 if (hdll != NULL)
|
709 h.sterling 1.1 {
|
710 kumpf 1.3 SERVICE_DESCRIPTION sd;
711 CHANGE_SERVICE_CONFIG2_T csc;
|
712 h.sterling 1.1
|
713 kumpf 1.3 csc = (CHANGE_SERVICE_CONFIG2_T)
714 GetProcAddress(hdll, "ChangeServiceConfig2A");
|
715 h.sterling 1.1
|
716 kumpf 1.3 if (csc)
|
717 h.sterling 1.1 {
|
718 kumpf 1.3 sd.lpDescription = description;
719 csc(service, SERVICE_CONFIG_DESCRIPTION, &sd);
|
720 h.sterling 1.1 }
721
|
722 kumpf 1.3 FreeLibrary(hdll);
|
723 h.sterling 1.1 }
724 }
725 }
726
727 /*-------------------------------------------------------------------------*
728 * Method: show_error *
729 * *
730 * Args: *
731 * action: *
732 * A single verb decribing the action going on when the error *
733 * occurred. For example, "opening", "creating", etc. *
734 * *
735 * object: *
736 * Description of the object on which was action occurred. Examples *
737 * are "file", "service", etc. *
738 * *
739 * hr: *
740 * The error status. Can be an hresult, or Win32 error status. *
741 * *
742 * Description: *
743 * This function provides an even higher level of abstraction over *
744 h.sterling 1.1 * the Win32 event logging API's. *
745 * *
746 * Returns: *
747 * true if event was successfully logged *
748 * false if the event could not be logged *
749 *-------------------------------------------------------------------------*/
|
750 kumpf 1.3 bool Service::show_error(const char *action, const char *object, DWORD hr)
|
751 h.sterling 1.1 {
|
752 kumpf 1.3 char console_title[_MAX_PATH] = {0};
753 char txt[_MAX_PATH] = "";
754 char msg[_MAX_PATH] = "";
755 DWORD nchars;
756
757 nchars = FormatMessage(
758 FORMAT_MESSAGE_FROM_SYSTEM,
759 NULL,
760 hr,
761 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
762 msg,
763 sizeof(msg),
764 NULL);
765
766 if (nchars == 0)
767 sprintf(msg, "Unknown error code - %%X%x", hr);
768 else if (nchars > 1)
769 {
770 if (msg[nchars - 1] == '\n') msg[nchars - 1] = '\0';
771 if (msg[nchars - 2] == '\r') msg[nchars - 2] = '\0';
772 }
773 kumpf 1.3
774 sprintf(txt,
775 "Failed to %s %s %s. Reason: %s",
776 action,
777 object,
778 g_service_name,
779 msg);
780
781 // Running from a console window
782 // send courtesy message txt to stderr
783 if (GetConsoleTitle(console_title, _MAX_PATH) > 0)
|
784 h.sterling 1.1 {
785 PEGASUS_STD(cerr) << txt << PEGASUS_STD(endl);
786 }
787
|
788 kumpf 1.3 return LogEvent(EVENTLOG_ERROR_TYPE, 1, txt);
|
789 h.sterling 1.1 }
790
|
791 kumpf 1.3 Service::State Service::get_state(DWORD scm_state)
|
792 h.sterling 1.1 {
|
793 kumpf 1.3 return (State)scm_state;
|
794 h.sterling 1.1 }
795
|
796 kumpf 1.3 Service::ReturnCode Service::get_error(DWORD error_status, const char *action)
|
797 h.sterling 1.1 {
|
798 kumpf 1.3 switch (error_status)
|
799 h.sterling 1.1 {
800 /*
|
801 kumpf 1.3 // INFO: Could add cases to suppress error message.
802 case ERROR_SERVICE_DOES_NOT_EXIST:
803 case ERROR_SERVICE_CANNOT_ACCEPT_CTRL:
804 break;
|
805 h.sterling 1.1 */
|
806 kumpf 1.3 case SERVICE_RETURN_SUCCESS:
807 break;
|
808 h.sterling 1.1
|
809 kumpf 1.3 default:
810 show_error(action, "service", error_status);
811 break;
|
812 h.sterling 1.1 }
|
813 kumpf 1.3 return (ReturnCode)error_status;
|
814 h.sterling 1.1 }
815
|