00001 // -*- C++ -*- 00002 00003 //========================================================================== 00004 /** 00005 * @file NT_Service.h 00006 * 00007 * $Id: NT_Service.h 78245 2007-05-02 12:50:09Z johnnyw $ 00008 * 00009 * @author Steve Huston <shuston@riverace.com> 00010 */ 00011 //========================================================================== 00012 00013 #ifndef ACE_NT_SERVICE_H 00014 #define ACE_NT_SERVICE_H 00015 00016 #include /**/ "ace/pre.h" 00017 00018 #include /**/ "ace/config-all.h" 00019 00020 #if !defined (ACE_LACKS_PRAGMA_ONCE) 00021 # pragma once 00022 #endif /* ACE_LACKS_PRAGMA_ONCE */ 00023 00024 #if defined (ACE_WIN32) && !defined (ACE_LACKS_WIN32_SERVICES) 00025 00026 #include "ace/ACE.h" 00027 #include "ace/OS_Log_Msg_Attributes.h" 00028 #include "ace/Service_Object.h" 00029 #include "ace/Task.h" 00030 #include "ace/OS_NS_errno.h" // needed for those using our macros 00031 00032 // ACE_NT_SERVICE_START_TIMEOUT is an estimate of the number of 00033 // milliseconds your service will take to start. Default is 5 00034 // seconds; you can pass a different value (or set one) when you 00035 // create the ACE_NT_Service object for your service. 00036 #if !defined ACE_NT_SERVICE_START_TIMEOUT 00037 #define ACE_NT_SERVICE_START_TIMEOUT 5000 00038 #endif /* ACE_NT_SERVICE_TIMEOUT */ 00039 00040 ACE_BEGIN_VERSIONED_NAMESPACE_DECL 00041 00042 /** 00043 * @class ACE_NT_Service 00044 * 00045 * @brief Provide the base class which defines the interface for controlling 00046 * an NT service. 00047 * 00048 * NT Services can be implemented using the framework defined by 00049 * the ACE_NT_Service class, and the macros defined in this file. 00050 * Some quick refresher notes on NT Services: 00051 * 00052 * - The main program defines an array of entries describing the 00053 * services offered. The ACE_NT_SERVICE_ENTRY macro can help with 00054 * this. 00055 * - For each service, a separate ServiceMain and Handler function 00056 * need to be defined. These are taken care of by the 00057 * ACE_NT_SERVICE_DEFINE macro. 00058 * - When the main program/thread calls 00059 * StartServiceCtrlDispatcher, NT creates a thread for each 00060 * service, and runs the ServiceMain function for the service in 00061 * that new thread. When that thread exits, the service is gone. 00062 * 00063 * To use this facility, you could derive a class from 00064 * ACE_Service_Object (if you want to start via ACE's service 00065 * configurator), or use any other class to run when the image 00066 * starts (assuming that NT runs the image). You must set up an 00067 * NT SERVICE_TABLE_ENTRY array to define your service(s). You 00068 * can use the ACE_NT_SERVICE_... macros defined below for this. 00069 * 00070 * A SERVICE_TABLE might look like this: 00071 * ACE_NT_SERVICE_REFERENCE(Svc1); // If service is in another file 00072 * SERVICE_TABLE_ENTRY myServices[] = { 00073 * ACE_NT_SERVICE_ENTRY ("MyNeatService", Svc1), 00074 * { 0, 0 } }; 00075 * 00076 * In the file where your service(s) are implemented, use the 00077 * ACE_NT_SERVICE_DEFINE macro to set up the following: 00078 * 1. A pointer to the service's implementation object (must be derived 00079 * from ACE_NT_Service). 00080 * 2. The service's Handler function (forwards all requests to the 00081 * ACE_NT_Service-derived object's handle_control function). 00082 * 3. The service's ServiceMain function. Creates a new instance 00083 * of the ACE_NT_Service-derived class SVCCLASS, unless one has 00084 * been created already. 00085 * 00086 * If you are using all the default constructor values, you can 00087 * let the generated ServiceMain function create the object, else 00088 * you need to create it by hand before calling 00089 * StartServiceCtrlDispatcher. Set the pointer so ServiceMain 00090 * won't create another one. Another reason you may want to do 00091 * the object creation yourself is if you want to also implement 00092 * suspend and resume functions (the ones inherited from 00093 * ACE_Service_Object) to do something intelligent to the services 00094 * which are running, like call their handle_control functions to 00095 * request suspend and resume actions, similar to what NT would do 00096 * if a Services control panel applet would do if the user clicks 00097 * on Suspend. 00098 */ 00099 class ACE_Export ACE_NT_Service : public ACE_Task<ACE_MT_SYNCH> 00100 { 00101 00102 public: 00103 // = Initialization and termination methods. 00104 /// Constructor primarily for use when running the service. 00105 ACE_NT_Service (DWORD start_timeout = ACE_NT_SERVICE_START_TIMEOUT, 00106 DWORD service_type = SERVICE_WIN32_OWN_PROCESS, 00107 DWORD controls_mask = SERVICE_ACCEPT_STOP); 00108 00109 /// Constructor primarily for use when inserting/removing/controlling 00110 /// the service. 00111 ACE_NT_Service (const ACE_TCHAR *name, 00112 const ACE_TCHAR *desc = 0, 00113 DWORD start_timeout = ACE_NT_SERVICE_START_TIMEOUT, 00114 DWORD service_type = SERVICE_WIN32_OWN_PROCESS, 00115 DWORD controls_mask = SERVICE_ACCEPT_STOP); 00116 00117 virtual ~ACE_NT_Service (void); 00118 00119 // = Functions to operate the service 00120 00121 /** 00122 * Hook called to open the service. By default, sets the service 00123 * status to SERVICE_START_PENDING, calls the @c svc() method, 00124 * interprets and sets the service status, and returns. 00125 */ 00126 virtual int open (void *args = 0); 00127 00128 /** 00129 * Hook called when terminating the service. Inherited from 00130 * ACE_Shared_Object. Default implementation sets the service status 00131 * to SERVICE_STOPPED. 00132 */ 00133 virtual int fini (void); 00134 00135 /** 00136 * The actual service implementation. This function need not be overridden 00137 * by applications that are just using SCM capabilities, but must be 00138 * by subclasses when actually running the service. It is expected that 00139 * this function will set the status to RUNNING. 00140 */ 00141 virtual int svc (void); 00142 00143 /** 00144 * This function is called in response to a request from the Service 00145 * Dispatcher. It must interact with the <svc> function to effect the 00146 * requested control operation. The default implementation handles 00147 * all requests as follows: 00148 * SERVICE_CONTROL_STOP: set stop pending, set cancel flag 00149 * SERVICE_CONTROL_PAUSE: set pause pending, <suspend>, set paused 00150 * SERVICE_CONTROL_CONTINUE: set continue pending, <resume>, set running 00151 * SERVICE_CONTROL_INTERROGATE: reports current status 00152 * SERVICE_CONTROL_SHUTDOWN: same as SERVICE_CONTROL_STOP. 00153 */ 00154 virtual void handle_control (DWORD control_code); 00155 00156 /// Set the svc_handle_ member. This is only a public function because 00157 /// the macro-generated service function calls it. 00158 void svc_handle (const SERVICE_STATUS_HANDLE new_svc_handle); 00159 00160 00161 // = Methods which can be used to do SCP-like functions. The first group 00162 // are used to register/insert and remove the service's definition in the 00163 // SCM registry. 00164 00165 /// Sets the name and description for the service. 00166 /// If desc is 0, it takes the same value as name. 00167 void name (const ACE_TCHAR *name, const ACE_TCHAR *desc = 0); 00168 00169 /// Get the service name. 00170 const ACE_TCHAR *name (void) const; 00171 00172 /// Get the service description. 00173 const ACE_TCHAR *desc (void) const; 00174 00175 /// Sets the host machine 00176 void host (const ACE_TCHAR *host); 00177 00178 /// Get the host machine. 00179 const ACE_TCHAR *host (void) const; 00180 00181 /** 00182 * Insert (create) the service in the NT Service Control Manager, 00183 * with the given creation values. exe_path defaults to the path name 00184 * of the program that calls the function. All other 0-defaulted arguments 00185 * pass 0 into the service creation, taking NT_specified defaults. 00186 * Returns -1 on error, 0 on success. 00187 */ 00188 int insert (DWORD start_type = SERVICE_DEMAND_START, 00189 DWORD error_control = SERVICE_ERROR_IGNORE, 00190 const ACE_TCHAR *exe_path = 0, 00191 const ACE_TCHAR *group_name = 0, 00192 LPDWORD tag_id = 0, 00193 const ACE_TCHAR *dependencies = 0, 00194 const ACE_TCHAR *account_name = 0, 00195 const ACE_TCHAR *password = 0, 00196 DWORD desired_access = SERVICE_ALL_ACCESS); 00197 00198 /** 00199 * Remove the service from the NT Service Control Manager. Returns -1 on 00200 * error, 0 on success. This just affects the SCM and registry - the 00201 * can and will keep running fine if it is already running. 00202 */ 00203 int remove (void); 00204 00205 /// Sets the startup type for the service. Returns -1 on error, 0 on success. 00206 int startup (DWORD startup); 00207 00208 /// Returns the current startup type. 00209 DWORD startup (void); 00210 00211 // = Methods to control ACE_Log_Msg behavior in the service. 00212 00213 /** 00214 * Set the ACE_Log_Msg attributes that the service thread will use to 00215 * initialize its ACE_Log_Msg instance. This is how the initiating 00216 * thread's logging ostream, etc. get into the service thread. The 00217 * logging attributes in effect when this function is called are what 00218 * the service thread will have at its disposal when it starts; therefore, 00219 * the main thread should set up logging options for the process, and 00220 * call this function just before calling the StartServiceCtrlDispatcher 00221 * function. 00222 */ 00223 void capture_log_msg_attributes (void); 00224 00225 /** 00226 * Set the ACE_Log_Msg attributes in the current thread to those saved 00227 * in the most recent call to @c capture_log_msg_attributes(). This function 00228 * should be called from the service's service thread. Ideally, it is the 00229 * first method called to be sure that any logging done is incorporated 00230 * correctly into the process's established logging setup. 00231 */ 00232 void inherit_log_msg_attributes (void); 00233 00234 // = Methods which control the service's execution. 00235 00236 // These methods to start/pause/resume/stop/check the service all 00237 // have the following common behavior with respect to <wait_time> 00238 // and return value. <wait_time> is a pointer to an ACE_Time_Value 00239 // object. If not supplied (a zero pointer) the function will wait 00240 // indefinitely for the action to be finalized (service reach 00241 // running state, completely shut down, etc.) or get "stuck" before 00242 // returning. If the time is supplied, it specifies how long to 00243 // wait for the service to reach a steady state, and on return, it 00244 // is updated to the service's last reported wait hint. So, if you 00245 // want to control the waiting yourself (for example, you want to 00246 // react to UI events during the wait) specify a <wait_time> of (0, 00247 // 0) and use the updated time to know when to check the service's 00248 // state again. NOTE!!!! The wait_time things don't work yet. The 00249 // calls always check status once, and do not wait for it to change. 00250 // 00251 // The return value from start_svc, stop_svc, pause_svc, 00252 // continue_svc is 0 if the request to NT to effect the change was 00253 // made successfully. The service may refuse to change, or not do 00254 // what you wanted; so if you need to know, supply a <svc_state> 00255 // pointer to receive the service's reported last state on return 00256 // and check it to see if it's what you want. The functions only 00257 // return -1 when the actual request to the service is refused - 00258 // this would include privilege restrictions and if the service is 00259 // not configured to receive the request (this is most likely to 00260 // happen in the case of pause and continue). 00261 00262 /** 00263 * Start the service (must have been inserted before). wait_time is 00264 * the time to wait for the service to reach a steady state before 00265 * returning. If it is 0, the function waits as long as it takes 00266 * for the service to reach the 'running' state, or gets stuck in 00267 * some other state, or exits. If <wait_time> is supplied, it is 00268 * updated on return to hold the service's last reported wait hint. 00269 * svc_state can be used to receive the state which the service 00270 * settled in. If the value is 0, the service never ran. argc/argv 00271 * are passed to the service's ServiceMain function when it starts. 00272 * Returns 0 for success, -1 for error. 00273 */ 00274 int start_svc (ACE_Time_Value *wait_time = 0, 00275 DWORD *svc_state = 0, 00276 DWORD argc = 0, const ACE_TCHAR **argv = 0); 00277 00278 /** 00279 * Requests the service to stop. Will wait up to <wait_time> for 00280 * the service to actually stop. If not specified, the function 00281 * waits until the service either stops or gets stuck in some other 00282 * state before it stops. If <svc_state> is specified, it receives 00283 * the last reported state of the service. Returns 0 if the request 00284 * was made successfully, -1 if not. 00285 */ 00286 int stop_svc (ACE_Time_Value *wait_time = 0, DWORD *svc_state = 0); 00287 00288 /// Pause the service. 00289 int pause_svc (ACE_Time_Value *wait_time = 0, DWORD *svc_state = 0); 00290 00291 /// Continue the service. 00292 int continue_svc (ACE_Time_Value *wait_time = 0, DWORD *svc_state = 0); 00293 00294 /** 00295 * Get the current state for the service. If <wait_hint> is not 0, 00296 * it receives the service's reported wait hint. Note that this 00297 * function returns 0 on failure (not -1 as is usual in ACE). A 00298 * zero return would (probably) only be returned if there is either 00299 * no service with the given name in the SCM database, or the caller 00300 * does not have sufficient rights to access the service state. The 00301 * set of valid service state values are all greater than 0. 00302 */ 00303 DWORD state (ACE_Time_Value *wait_hint = 0); 00304 00305 /// A version of <state> that returns -1 for failure, 0 for success. 00306 /// The DWORD pointed to by pstate receives the state value. 00307 int state (DWORD *pstate, ACE_Time_Value *wait_hint = 0); 00308 00309 /** 00310 * Test access to the object's service in the SCM. The service must 00311 * already have been inserted in the SCM database. This function 00312 * has no affect on the service itself. Returns 0 if the specified 00313 * access is allowed, -1 otherwise (either the access is denied, or 00314 * there is a problem with the service's definition - check 00315 * ACE_OS::last_error to get the specific error indication. 00316 */ 00317 int test_access (DWORD desired_access = SERVICE_ALL_ACCESS); 00318 00319 /// Declare the dynamic allocation hooks. 00320 ACE_ALLOC_HOOK_DECLARE; 00321 00322 protected: 00323 int report_status (DWORD new_status, DWORD time_hint = 0); 00324 00325 /** 00326 * Return the svc_sc_handle_ member. If the member is null, it 00327 * retrieves the handle from the Service Control Manager and caches 00328 * it. 00329 */ 00330 SC_HANDLE svc_sc_handle (void); 00331 00332 /** 00333 * Waits for the service to reach <desired_state> or get 00334 * (apparently) stuck before it reaches that state. Will wait at 00335 * most <wait_time> to get to the desired state. If <wait_time> is 00336 * 0, then the function keeps waiting until the desired state is 00337 * reached or the service doesn't update its state any further. The 00338 * svc_status_ class member is updated upon return. 00339 */ 00340 void wait_for_service_state (DWORD desired_state, 00341 ACE_Time_Value *wait_time); 00342 00343 /// Called by <handle_control> when a stop/shutdown was requested. 00344 virtual void stop_requested (DWORD control_code); 00345 00346 /// Called by <handle_control> when a pause was requested. 00347 virtual void pause_requested (DWORD control_code); 00348 00349 /// Called by <handle_control> when a continue was requested. 00350 virtual void continue_requested (DWORD control_code); 00351 00352 /// Called by <handle_control> when a interrogate was requested. 00353 virtual void interrogate_requested (DWORD control_code); 00354 00355 protected: 00356 /// Estimate of init time needed 00357 DWORD start_time_; 00358 /// Service handle - doesn't need close. 00359 SERVICE_STATUS_HANDLE svc_handle_; 00360 SERVICE_STATUS svc_status_; 00361 00362 /// Service's SCM handle 00363 SC_HANDLE svc_sc_handle_; 00364 ACE_TCHAR *name_; 00365 ACE_TCHAR *desc_; 00366 ACE_TCHAR *host_; 00367 00368 /// ACE_Log_Msg attributes to inherit from the starting thread. 00369 ACE_OS_Log_Msg_Attributes log_msg_attributes_; 00370 }; 00371 00372 ACE_END_VERSIONED_NAMESPACE_DECL 00373 00374 // These macros help to get things set up correctly at compile time 00375 // and to take most of the grudge work out of creating the proper 00376 // functions and doing the registrations. 00377 // 00378 // ACE_NT_SERVICE_DEFINE - defines the 'ServiceMain' function which NT will 00379 // call in its own thread when the service control 00380 // dispatcher starts. 00381 00382 #define ACE_NT_SERVICE_DEFINE(SVCNAME, SVCCLASS, SVCDESC) \ 00383 ACE_NT_Service * _ace_nt_svc_obj_##SVCNAME = 0; \ 00384 VOID WINAPI ace_nt_svc_handler_##SVCNAME (DWORD fdwControl) { \ 00385 _ace_nt_svc_obj_##SVCNAME->handle_control(fdwControl); \ 00386 } \ 00387 VOID WINAPI ace_nt_svc_main_##SVCNAME (DWORD dwArgc, \ 00388 ACE_TCHAR **lpszArgv) { \ 00389 int delete_svc_obj = 0; \ 00390 if (_ace_nt_svc_obj_##SVCNAME == 0) { \ 00391 ACE_NEW (_ace_nt_svc_obj_##SVCNAME, SVCCLASS); \ 00392 if (_ace_nt_svc_obj_##SVCNAME == 0) \ 00393 return; \ 00394 delete_svc_obj = 1; \ 00395 } \ 00396 else \ 00397 _ace_nt_svc_obj_##SVCNAME->inherit_log_msg_attributes (); \ 00398 _ace_nt_svc_obj_##SVCNAME->init(dwArgc, lpszArgv); \ 00399 _ace_nt_svc_obj_##SVCNAME->svc_handle( \ 00400 ACE_TEXT_RegisterServiceCtrlHandler(SVCDESC, \ 00401 &ace_nt_svc_handler_##SVCNAME)); \ 00402 _ace_nt_svc_obj_##SVCNAME->open(); \ 00403 _ace_nt_svc_obj_##SVCNAME->wait(); \ 00404 _ace_nt_svc_obj_##SVCNAME->fini(); \ 00405 if (delete_svc_obj) { \ 00406 delete _ace_nt_svc_obj_##SVCNAME; \ 00407 _ace_nt_svc_obj_##SVCNAME = 0; \ 00408 } \ 00409 return; \ 00410 } 00411 00412 #define ACE_NT_SERVICE_REFERENCE(SVCNAME) \ 00413 extern ACE_NT_Service * _ace_nt_svc_obj_##SVCNAME; \ 00414 extern VOID WINAPI ace_nt_svc_main_##SVCNAME (DWORD dwArgc, \ 00415 ACE_TCHAR **lpszArgv); 00416 00417 #define ACE_NT_SERVICE_ENTRY(SVCDESC, SVCNAME) \ 00418 { SVCDESC, &ace_nt_svc_main_##SVCNAME } 00419 00420 #define ACE_NT_SERVICE_RUN(SVCNAME, SVCINSTANCE, RET) \ 00421 ACE_TEXT_SERVICE_TABLE_ENTRY _ace_nt_svc_table[2] = \ 00422 { \ 00423 ACE_NT_SERVICE_ENTRY(ACE_TEXT (#SVCNAME), SVCNAME), \ 00424 { 0, 0 } \ 00425 }; \ 00426 _ace_nt_svc_obj_##SVCNAME = SVCINSTANCE; \ 00427 _ace_nt_svc_obj_##SVCNAME->capture_log_msg_attributes (); \ 00428 ACE_OS::last_error (0); \ 00429 int RET = ACE_TEXT_StartServiceCtrlDispatcher(_ace_nt_svc_table); 00430 00431 #if defined (__ACE_INLINE__) 00432 #include "ace/NT_Service.inl" 00433 #endif /* __ACE_INLINE__ */ 00434 00435 #endif /* ACE_WIN32 && !ACE_LACKS_WIN32_SERVICES */ 00436 00437 #include /**/ "ace/post.h" 00438 00439 #endif /* ACE_SERVICE_OBJECT_H */