00001 #include "ace_pch.h"
00002
00003
00004
00005
00006 #include "ace/config-all.h"
00007 #if defined (ACE_WIN32) && \
00008 !defined (ACE_HAS_PHARLAP) && !defined (ACE_HAS_WINCE)
00009
00010 #include "ace/NT_Service.h"
00011 #include "ace/Log_Msg.h"
00012 #include "ace/Service_Object.h"
00013
00014 #if !defined (__ACE_INLINE__)
00015 #include "ace/NT_Service.i"
00016 #endif
00017
00018 ACE_ALLOC_HOOK_DEFINE(ACE_NT_Service)
00019
00020
00021
00022 ACE_NT_Service::~ACE_NT_Service (void)
00023 {
00024 if (this->svc_sc_handle_ != 0)
00025 {
00026 CloseServiceHandle (this->svc_sc_handle_);
00027 this->svc_sc_handle_ = 0;
00028 }
00029 delete [] this->desc_;
00030 delete [] this->name_;
00031 delete [] this->host_;
00032 }
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054 int
00055 ACE_NT_Service::open (void *args)
00056 {
00057 ACE_UNUSED_ARG (args);
00058 this->report_status (SERVICE_START_PENDING, 0);
00059
00060 int svc_return = this->svc ();
00061 if (svc_return == 0)
00062 {
00063 this->svc_status_.dwWin32ExitCode = NO_ERROR;
00064 this->svc_status_.dwServiceSpecificExitCode = 0;
00065 }
00066 else
00067 {
00068 if (errno == 0)
00069 {
00070 this->svc_status_.dwWin32ExitCode = GetLastError ();
00071 }
00072 else
00073 {
00074 this->svc_status_.dwWin32ExitCode = ERROR_SERVICE_SPECIFIC_ERROR;
00075 this->svc_status_.dwServiceSpecificExitCode = errno;
00076 }
00077 }
00078
00079 return svc_return;
00080
00081 }
00082
00083 int
00084 ACE_NT_Service::fini (void)
00085 {
00086 return this->report_status (SERVICE_STOPPED, 0);
00087 }
00088
00089
00090 void
00091 ACE_NT_Service::handle_control (DWORD control_code)
00092 {
00093 switch (control_code)
00094 {
00095 case SERVICE_CONTROL_SHUTDOWN:
00096 case SERVICE_CONTROL_STOP:
00097 this->stop_requested (control_code);
00098 break;
00099
00100 case SERVICE_CONTROL_PAUSE:
00101 this->pause_requested (control_code);
00102 break;
00103
00104 case SERVICE_CONTROL_CONTINUE:
00105 this->continue_requested (control_code);
00106 break;
00107
00108 case SERVICE_CONTROL_INTERROGATE:
00109 this->interrogate_requested (control_code);
00110 break;
00111 }
00112 }
00113
00114 void
00115 ACE_NT_Service::stop_requested (DWORD)
00116 {
00117 this->report_status (SERVICE_STOP_PENDING);
00118
00119 }
00120
00121 void
00122 ACE_NT_Service::pause_requested (DWORD)
00123 {
00124 this->report_status (SERVICE_PAUSE_PENDING);
00125 this->suspend ();
00126 this->report_status (SERVICE_PAUSED);
00127 }
00128
00129 void
00130 ACE_NT_Service::continue_requested (DWORD)
00131 {
00132 this->report_status (SERVICE_CONTINUE_PENDING);
00133 this->resume ();
00134 this->report_status (SERVICE_RUNNING);
00135 }
00136
00137 void
00138 ACE_NT_Service::interrogate_requested (DWORD)
00139 {
00140 this->report_status (0);
00141 }
00142
00143 void
00144 ACE_NT_Service::name (const ACE_TCHAR *name, const ACE_TCHAR *desc)
00145 {
00146 delete [] this->desc_;
00147 delete [] this->name_;
00148
00149 if (desc == 0)
00150 desc = name;
00151
00152 this->name_ = ACE::strnew (name);
00153 this->desc_ = ACE::strnew (desc);
00154 }
00155
00156 void
00157 ACE_NT_Service::host (const ACE_TCHAR *host)
00158 {
00159 delete [] this->host_;
00160
00161 if (this->svc_sc_handle_ != 0)
00162 {
00163 CloseServiceHandle (this->svc_sc_handle_);
00164 this->svc_sc_handle_ = 0;
00165 }
00166
00167 if (host == 0)
00168 {
00169 this->host_ = 0;
00170 }
00171 else
00172 {
00173 this->host_ = ACE::strnew (host);
00174 }
00175 }
00176
00177 int
00178 ACE_NT_Service::insert (DWORD start_type,
00179 DWORD error_control,
00180 const ACE_TCHAR *exe_path,
00181 const ACE_TCHAR *group_name,
00182 LPDWORD tag_id,
00183 const ACE_TCHAR *dependencies,
00184 const ACE_TCHAR *account_name,
00185 const ACE_TCHAR *password)
00186 {
00187 ACE_TCHAR this_exe[MAXPATHLEN];
00188
00189
00190 errno = 0;
00191
00192 if (exe_path == 0)
00193 {
00194 if (ACE_TEXT_GetModuleFileName (0, this_exe, sizeof this_exe) == 0)
00195 return -1;
00196 exe_path = this_exe;
00197 }
00198
00199 SC_HANDLE sc_mgr = ACE_TEXT_OpenSCManager (this->host (),
00200 0,
00201 SC_MANAGER_ALL_ACCESS);
00202 if (sc_mgr == 0)
00203 return -1;
00204
00205 SC_HANDLE sh = ACE_TEXT_CreateService (sc_mgr,
00206 this->name (),
00207 this->desc (),
00208 SERVICE_ALL_ACCESS,
00209 this->svc_status_.dwServiceType,
00210 start_type,
00211 error_control,
00212 exe_path,
00213 group_name,
00214 tag_id,
00215 dependencies,
00216 account_name,
00217 password);
00218
00219
00220 if (sh == 0)
00221 ACE_OS::set_errno_to_last_error ();
00222
00223 CloseServiceHandle (sc_mgr);
00224
00225 if (sh == 0)
00226 return -1;
00227
00228 if (this->svc_sc_handle_ != 0)
00229 CloseServiceHandle (this->svc_sc_handle_);
00230 this->svc_sc_handle_ = sh;
00231
00232 return 0;
00233
00234 }
00235
00236 int
00237 ACE_NT_Service::remove (void)
00238 {
00239 if (this->svc_sc_handle () == 0)
00240 return -1;
00241
00242 if (DeleteService (this->svc_sc_handle()) == 0
00243 && GetLastError () != ERROR_SERVICE_MARKED_FOR_DELETE)
00244 return -1;
00245
00246 return 0;
00247 }
00248
00249
00250
00251 int
00252 ACE_NT_Service::startup (DWORD startup)
00253 {
00254 SC_HANDLE svc = this->svc_sc_handle ();
00255 if (svc == 0)
00256 return -1;
00257
00258 BOOL ok =
00259 ChangeServiceConfig (svc,
00260 (DWORD) SERVICE_NO_CHANGE,
00261 startup,
00262 (DWORD) SERVICE_NO_CHANGE,
00263 0,
00264 0,
00265 0,
00266 0,
00267 0, 0,
00268 0);
00269
00270 return ok ? 0 : -1;
00271 }
00272
00273
00274
00275 DWORD
00276 ACE_NT_Service::startup (void)
00277 {
00278
00279
00280
00281
00282 char cfgbuff[1024];
00283 LPQUERY_SERVICE_CONFIG cfg;
00284 DWORD cfgsize, needed_size;
00285
00286 SC_HANDLE svc = this->svc_sc_handle ();
00287 if (svc == 0)
00288 {
00289
00290
00291 return MAXDWORD - 1;
00292 }
00293 cfgsize = sizeof cfgbuff;
00294 cfg = (LPQUERY_SERVICE_CONFIG) cfgbuff;
00295 BOOL ok = QueryServiceConfig (svc, cfg, cfgsize, &needed_size);
00296 if (ok)
00297 return cfg->dwStartType;
00298
00299
00300 return MAXDWORD;
00301
00302 }
00303
00304
00305 void
00306 ACE_NT_Service::capture_log_msg_attributes (void)
00307 {
00308 ACE_Log_Msg::init_hook (this->log_msg_attributes_);
00309 }
00310
00311 void
00312 ACE_NT_Service::inherit_log_msg_attributes (void)
00313 {
00314
00315
00316 ACE_Log_Msg::inherit_hook (0, this->log_msg_attributes_);
00317 }
00318
00319
00320 int
00321 ACE_NT_Service::start_svc (ACE_Time_Value *wait_time,
00322 DWORD *svc_state,
00323 DWORD argc, const ACE_TCHAR **argv)
00324 {
00325 SC_HANDLE svc = this->svc_sc_handle ();
00326 if (svc == 0)
00327 return -1;
00328
00329 if (!ACE_TEXT_StartService (svc, argc, argv))
00330 return -1;
00331
00332 this->wait_for_service_state (SERVICE_RUNNING, wait_time);
00333 if (svc_state != 0)
00334 *svc_state = this->svc_status_.dwCurrentState;
00335
00336 return 0;
00337 }
00338
00339 int
00340 ACE_NT_Service::stop_svc (ACE_Time_Value *wait_time,
00341 DWORD *svc_state)
00342 {
00343 SC_HANDLE svc = this->svc_sc_handle ();
00344 if (svc == 0)
00345 return -1;
00346
00347 if (!ControlService (svc,
00348 SERVICE_CONTROL_STOP,
00349 &this->svc_status_))
00350 return -1;
00351
00352 this->wait_for_service_state (SERVICE_STOPPED,
00353 wait_time);
00354 if (svc_state != 0)
00355 *svc_state = this->svc_status_.dwCurrentState;
00356
00357 return 0;
00358 }
00359
00360 int
00361 ACE_NT_Service::pause_svc (ACE_Time_Value *wait_time,
00362 DWORD *svc_state)
00363 {
00364 SC_HANDLE svc = this->svc_sc_handle ();
00365 if (svc == 0)
00366 return -1;
00367
00368 if (!ControlService (svc,
00369 SERVICE_CONTROL_PAUSE,
00370 &this->svc_status_))
00371 return -1;
00372
00373 this->wait_for_service_state (SERVICE_PAUSED,
00374 wait_time);
00375 if (svc_state != 0)
00376 *svc_state = this->svc_status_.dwCurrentState;
00377
00378 return 0;
00379 }
00380
00381 int
00382 ACE_NT_Service::continue_svc (ACE_Time_Value *wait_time,
00383 DWORD *svc_state)
00384 {
00385 SC_HANDLE svc = this->svc_sc_handle ();
00386 if (svc == 0)
00387 return -1;
00388
00389 if (!ControlService (svc,
00390 SERVICE_CONTROL_CONTINUE,
00391 &this->svc_status_))
00392 return -1;
00393
00394 this->wait_for_service_state (SERVICE_RUNNING,
00395 wait_time);
00396 if (svc_state != 0)
00397 *svc_state = this->svc_status_.dwCurrentState;
00398
00399 return 0;
00400 }
00401
00402 DWORD
00403 ACE_NT_Service::state (ACE_Time_Value *wait_hint)
00404 {
00405 DWORD curr_state;
00406
00407 if (this->state (&curr_state,
00408 wait_hint) == -1)
00409 return 0;
00410 return curr_state;
00411 }
00412
00413 int
00414 ACE_NT_Service::state (DWORD *pstate,
00415 ACE_Time_Value *wait_hint)
00416 {
00417 SC_HANDLE svc = this->svc_sc_handle ();
00418
00419 if (svc == 0)
00420 return -1;
00421
00422
00423
00424
00425
00426 DWORD controls_accepted = this->svc_status_.dwControlsAccepted;
00427
00428 if (QueryServiceStatus (svc,
00429 &this->svc_status_) == 0)
00430 return -1;
00431
00432 if (wait_hint != 0)
00433 wait_hint->msec (this->svc_status_.dwWaitHint);
00434
00435 *pstate = this->svc_status_.dwCurrentState;
00436 this->svc_status_.dwControlsAccepted = controls_accepted;
00437 return 0;
00438 }
00439
00440
00441
00442
00443
00444
00445
00446 int
00447 ACE_NT_Service::test_access (DWORD desired_access)
00448 {
00449 int status = -1;
00450
00451 SC_HANDLE sc_mgr = ACE_TEXT_OpenSCManager (this->host (),
00452 0,
00453 GENERIC_READ);
00454 if (sc_mgr != 0)
00455 {
00456 SC_HANDLE handle = ACE_TEXT_OpenService (sc_mgr,
00457 this->name (),
00458 desired_access);
00459 CloseServiceHandle (sc_mgr);
00460 if (handle != 0)
00461 {
00462 status = 0;
00463 CloseServiceHandle (handle);
00464 }
00465 }
00466
00467 return status;
00468 }
00469
00470
00471
00472
00473
00474
00475
00476
00477
00478
00479
00480 int
00481 ACE_NT_Service::report_status (DWORD new_status,
00482 DWORD time_hint)
00483 {
00484 int bump_checkpoint = 0;
00485 int retval = 0;
00486 DWORD save_controls = 0;
00487
00488 if (new_status != 0)
00489 this->svc_status_.dwCurrentState = new_status;
00490 switch (this->svc_status_.dwCurrentState)
00491 {
00492 case SERVICE_START_PENDING:
00493 save_controls = this->svc_status_.dwControlsAccepted;
00494 this->svc_status_.dwControlsAccepted = 0;
00495
00496 case SERVICE_STOP_PENDING:
00497 case SERVICE_CONTINUE_PENDING:
00498 case SERVICE_PAUSE_PENDING:
00499 this->svc_status_.dwWaitHint = time_hint ? time_hint : this->start_time_;
00500 bump_checkpoint = 1;
00501 break;
00502
00503 default:
00504 this->svc_status_.dwCheckPoint = 0;
00505 }
00506
00507 retval = SetServiceStatus (this->svc_handle_,
00508 &this->svc_status_) ? 0 : -1;
00509
00510 if (save_controls != 0)
00511 this->svc_status_.dwControlsAccepted = save_controls;
00512
00513 if (bump_checkpoint)
00514 ++this->svc_status_.dwCheckPoint;
00515
00516 return retval;
00517 }
00518
00519 SC_HANDLE
00520 ACE_NT_Service::svc_sc_handle (void)
00521 {
00522 if (this->svc_sc_handle_ == 0)
00523 {
00524 SC_HANDLE sc_mgr = ACE_TEXT_OpenSCManager (this->host (),
00525 0,
00526 SC_MANAGER_ALL_ACCESS);
00527 if (sc_mgr != 0)
00528 {
00529 this->svc_sc_handle_ = ACE_TEXT_OpenService (sc_mgr,
00530 this->name (),
00531 SERVICE_ALL_ACCESS);
00532 if (this->svc_sc_handle_ == 0)
00533 ACE_OS::set_errno_to_last_error ();
00534 CloseServiceHandle (sc_mgr);
00535 }
00536 else
00537 ACE_OS::set_errno_to_last_error ();
00538 }
00539
00540 return this->svc_sc_handle_;
00541 }
00542
00543 void
00544 ACE_NT_Service::wait_for_service_state (DWORD desired_state,
00545 ACE_Time_Value *wait_time)
00546 {
00547 DWORD last_state, last_check_point;
00548 int first_time = 1;
00549 int service_ok;
00550
00551 ACE_Time_Value time_out = ACE_OS::gettimeofday ();
00552 if (wait_time != 0)
00553 time_out += *wait_time;
00554
00555
00556 for (;;)
00557 {
00558 service_ok = 0 != QueryServiceStatus (this->svc_sc_handle_,
00559 &this->svc_status_);
00560
00561
00562 if (!service_ok)
00563 break;
00564
00565
00566 if (desired_state == this->svc_status_.dwCurrentState)
00567 break;
00568
00569
00570 if (wait_time != 0 && ACE_OS::gettimeofday () > time_out )
00571 {
00572 errno = ETIME;
00573 break;
00574 }
00575
00576 if (first_time)
00577 {
00578
00579 last_state = this->svc_status_.dwCurrentState;
00580 last_check_point = this->svc_status_.dwCheckPoint;
00581 first_time = 0;
00582 }
00583 else
00584 {
00585
00586 if (last_state != this->svc_status_.dwCurrentState)
00587 {
00588 last_state = this->svc_status_.dwCurrentState;
00589 last_check_point = this->svc_status_.dwCheckPoint;
00590 }
00591 else
00592 {
00593
00594 if (this->svc_status_.dwCheckPoint > last_check_point)
00595 last_check_point = this->svc_status_.dwCheckPoint;
00596 else
00597 {
00598
00599 service_ok = 0;
00600 break;
00601 }
00602 }
00603 }
00604
00605 ::Sleep (this->svc_status_.dwWaitHint);
00606 }
00607
00608 return;
00609 }
00610
00611 #endif