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