NT_Service.h

Go to the documentation of this file.
00001 // -*- C++ -*-
00002 
00003 //==========================================================================
00004 /**
00005  *  @file    NT_Service.h
00006  *
00007  *  NT_Service.h,v 4.30 2005/10/28 16:14:53 ossama Exp
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_HAS_PHARLAP) && \
00025    !defined (ACE_HAS_WINCE)
00026 
00027 #include "ace/ACE.h"
00028 #include "ace/OS_Log_Msg_Attributes.h"
00029 #include "ace/Service_Object.h"
00030 #include "ace/Task.h"
00031 #include "ace/OS_NS_errno.h" // needed for those using our macros
00032 
00033 // ACE_NT_SERVICE_START_TIMEOUT is an estimate of the number of
00034 // milliseconds your service will take to start.  Default is 5
00035 // seconds; you can pass a different value (or set one) when you
00036 // create the ACE_NT_Service object for your service.
00037 #if !defined ACE_NT_SERVICE_START_TIMEOUT
00038 #define ACE_NT_SERVICE_START_TIMEOUT  5000
00039 #endif /* ACE_NT_SERVICE_TIMEOUT */
00040 
00041 ACE_BEGIN_VERSIONED_NAMESPACE_DECL
00042 
00043 /**
00044  * @class ACE_NT_Service
00045  *
00046  * @brief Provide the base class which defines the interface for controlling
00047  * an NT service.
00048  *
00049  * NT Services can be implemented using the framework defined by
00050  * the ACE_NT_Service class, and the macros defined in this file.
00051  * Some quick refresher notes on NT Services:
00052  *
00053  *   - The main program defines an array of entries describing the
00054  *     services offered.  The ACE_NT_SERVICE_ENTRY macro can help with
00055  *     this.
00056  *   - For each service, a separate ServiceMain and Handler function
00057  *     need to be defined.  These are taken care of by the
00058  *     ACE_NT_SERVICE_DEFINE macro.
00059  *   - When the main program/thread calls
00060  *     StartServiceCtrlDispatcher, NT creates a thread for each
00061  *     service, and runs the ServiceMain function for the service in
00062  *     that new thread.  When that thread exits, the service is gone.
00063  *
00064  *   To use this facility, you could derive a class from
00065  *   ACE_Service_Object (if you want to start via ACE's service
00066  *   configurator), or use any other class to run when the image
00067  *   starts (assuming that NT runs the image).  You must set up an
00068  *   NT SERVICE_TABLE_ENTRY array to define your service(s).  You
00069  *   can use the ACE_NT_SERVICE_... macros defined below for this.
00070  *
00071  *   A SERVICE_TABLE might look like this:
00072  *       ACE_NT_SERVICE_REFERENCE(Svc1);  // If service is in another file
00073  *       SERVICE_TABLE_ENTRY myServices[] = {
00074  *                    ACE_NT_SERVICE_ENTRY ("MyNeatService", Svc1),
00075  *                    { 0, 0 } };
00076  *
00077  *   In the file where your service(s) are implemented, use the
00078  *   ACE_NT_SERVICE_DEFINE macro to set up the following:
00079  *    1. A pointer to the service's implementation object (must be derived
00080  *       from ACE_NT_Service).
00081  *    2. The service's Handler function (forwards all requests to the
00082  *       ACE_NT_Service-derived object's handle_control function).
00083  *    3. The service's ServiceMain function.  Creates a new instance
00084  *       of the ACE_NT_Service-derived class SVCCLASS, unless one has
00085  *       been created already.
00086  *
00087  *   If you are using all the default constructor values, you can
00088  *   let the generated ServiceMain function create the object, else
00089  *   you need to create it by hand before calling
00090  *   StartServiceCtrlDispatcher.  Set the pointer so ServiceMain
00091  *   won't create another one.  Another reason you may want to do
00092  *   the object creation yourself is if you want to also implement
00093  *   suspend and resume functions (the ones inherited from
00094  *   ACE_Service_Object) to do something intelligent to the services
00095  *   which are running, like call their handle_control functions to
00096  *   request suspend and resume actions, similar to what NT would do
00097  *   if a Services control panel applet would do if the user clicks
00098  *   on Suspend.
00099  */
00100 class ACE_Export ACE_NT_Service : public ACE_Task<ACE_MT_SYNCH>
00101 {
00102 
00103 public:
00104   // = Initialization and termination methods.
00105   /// Constructor primarily for use when running the service.
00106   ACE_NT_Service (DWORD start_timeout = ACE_NT_SERVICE_START_TIMEOUT,
00107                   DWORD service_type = SERVICE_WIN32_OWN_PROCESS,
00108                   DWORD controls_mask = SERVICE_ACCEPT_STOP);
00109 
00110   /// Constructor primarily for use when inserting/removing/controlling
00111   /// the service.
00112   ACE_NT_Service (const ACE_TCHAR *name,
00113                   const ACE_TCHAR *desc = 0,
00114                   DWORD start_timeout = ACE_NT_SERVICE_START_TIMEOUT,
00115                   DWORD service_type = SERVICE_WIN32_OWN_PROCESS,
00116                   DWORD controls_mask = SERVICE_ACCEPT_STOP);
00117 
00118   virtual ~ACE_NT_Service (void);
00119 
00120   // = Functions to operate the service
00121 
00122   /**
00123    * Hook called to open the service.  By default, sets the service
00124    * status to SERVICE_START_PENDING, calls the @c svc() method,
00125    * interprets and sets the service status, and returns.
00126    */
00127   virtual int open (void *args = 0);
00128 
00129   /**
00130    * Hook called when terminating the service. Inherited from
00131    * ACE_Shared_Object. Default implementation sets the service status
00132    * to SERVICE_STOPPED.
00133    */
00134   virtual int fini (void);
00135 
00136   /**
00137    * The actual service implementation.  This function need not be overridden
00138    * by applications that are just using SCM capabilities, but must be
00139    * by subclasses when actually running the service.  It is expected that
00140    * this function will set the status to RUNNING.
00141    */
00142   virtual int svc (void);
00143 
00144   /**
00145    * This function is called in response to a request from the Service
00146    * Dispatcher.  It must interact with the <svc> function to effect the
00147    * requested control operation.  The default implementation handles
00148    * all requests as follows:
00149    *    SERVICE_CONTROL_STOP: set stop pending, set cancel flag
00150    *    SERVICE_CONTROL_PAUSE: set pause pending, <suspend>, set paused
00151    *    SERVICE_CONTROL_CONTINUE: set continue pending, <resume>, set running
00152    *    SERVICE_CONTROL_INTERROGATE: reports current status
00153    *    SERVICE_CONTROL_SHUTDOWN: same as SERVICE_CONTROL_STOP.
00154    */
00155   virtual void  handle_control (DWORD control_code);
00156 
00157   /// Set the svc_handle_ member.  This is only a public function because
00158   /// the macro-generated service function calls it.
00159   void svc_handle (const SERVICE_STATUS_HANDLE new_svc_handle);
00160 
00161 
00162   // = Methods which can be used to do SCP-like functions. The first group
00163   // are used to register/insert and remove the service's definition in the
00164   // SCM registry.
00165 
00166   /// Sets the name and description for the service.
00167   /// If desc is 0, it takes the same value as name.
00168   void name (const ACE_TCHAR *name, const ACE_TCHAR *desc = 0);
00169 
00170   /// Get the service name.
00171   const ACE_TCHAR *name (void) const;
00172 
00173   /// Get the service description.
00174   const ACE_TCHAR *desc (void) const;
00175 
00176   /// Sets the host machine
00177   void host (const ACE_TCHAR *host);
00178 
00179   /// Get the host machine.
00180   const ACE_TCHAR *host (void) const;
00181 
00182   /**
00183    * Insert (create) the service in the NT Service Control Manager,
00184    * with the given creation values.  exe_path defaults to the path name
00185    * of the program that calls the function.  All other 0-defaulted arguments
00186    * pass 0 into the service creation, taking NT_specified defaults.
00187    * Returns -1 on error, 0 on success.
00188    */
00189   int insert (DWORD start_type = SERVICE_DEMAND_START,
00190               DWORD error_control = SERVICE_ERROR_IGNORE,
00191               const ACE_TCHAR *exe_path = 0,
00192               const ACE_TCHAR *group_name = 0,
00193               LPDWORD tag_id = 0,
00194               const ACE_TCHAR *dependencies = 0,
00195               const ACE_TCHAR *account_name = 0,
00196               const ACE_TCHAR *password = 0);
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_HAS_PHARLAP && !ACE_HAS_WINCE */
00436 
00437 #include /**/ "ace/post.h"
00438 
00439 #endif /* ACE_SERVICE_OBJECT_H */

Generated on Thu Nov 9 09:41:57 2006 for ACE by doxygen 1.3.6