// -*- c++ -*- //------------------------------------------------------------------------------ // GenServer.h //------------------------------------------------------------------------------ // Copyright (c) 1999-2005 by Vladislav Grinchenko // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Library General Public // License as published by the Free Software Foundation; either // version 2 of the License, or (at your option) any later version. //------------------------------------------------------------------------------ #ifndef GENSERVER_H #define GENSERVER_H extern "C" { #include /* printf, sprintf */ #include #include /* getopt() */ #include /* strlen */ #include /* errno */ #include /* kill */ #include /* open */ #include /* open */ #include /* open */ #include /* PATH_MAX */ #include #if !defined(WIN32) # include /* getrlimit */ # include #endif } #include #include #include #include using std::string; using std::vector; #include "assa/Assure.h" #include "assa/Handlers.h" #include "assa/SigHandlers.h" #include "assa/Fork.h" #include "assa/Reactor.h" #include "assa/CmdLineOpts.h" #include "assa/PidFileLock.h" namespace ASSA { /** @file GenServer.h GenServer is a base class for generic servers. This is an implementation of the Service Configurator pattern. */ class GenServer : public virtual EventHandler, public CmdLineOpts { public: /** @enum LogFlag */ enum LogFlag { KEEPLOG, /**< By default, append new log records to the existing log file. This is operational mode. */ RMLOG /**< Remove existing log file and start afresh. Convenient during development phase. */ }; public: /** Constructor. Corresponds to the object entering the IDLE state. */ GenServer (); /// Destructor virtual ~GenServer (); /** Provide an entry point into the service and perfom initialization of the service. Open log file and log startup options. Process standard command-line arguments. Following signals are handled in uniform manner: SIGHUP, SIGPIPE, SIGCHLD, SIGCLD, SIGALRM, SIGINT, SIGPOLL, SIGTERM. This function corresponds to the object moving from IDLE to RUNNING state as result of service initialization, or reconfiguration of the service and remaining in RUNNING state. @param argc Pointer to number of command line arguments @param argv Command line arguments char* array @param help_info Title that will be displayed with -h option */ virtual void init (int* argc, char* argv[], const char* help_info); /** This is an iterface function corresponding to the object moving back into IDLE state. Derived class is expected to perform actions that terminate execution of the service. */ virtual int fini (void) { return 0; } /** Temporarily suspend the execution of a service. Corresponds to process leaving RUNNING state and entering SUSPENDED state. */ virtual int suspend (void) { return 0; } /** Resume execution of a service. Corresponds to the process returning back to RUNNING state from SUSPENDED state. */ virtual int resume (void) { return 0; } /** Interface function provided for derived classes as a * place to initialize specifics of derived server */ virtual void init_service () =0; /** Interface function provided for derived classes as the main * entry for data processing. This is the place to implement main * event loop. */ virtual void process_events () =0; /** Hook for derived class to do addition clean-up when terminating signal is delivered by OS. Note that signal handling is provided by default and no additional intervention is necessary. Use this method only to enhance it. */ virtual void fatal_signal_hook () { /*--- empty ---*/ } /** Handle fatal signals. Hook (e.g. fatalSignalHook) is provided if derived class needs extra work before falling dead. */ int handle_signal (int signum_); /** Normally called by the main loop to find out whether 'graceful quit' flag had been raised, signaling that some application's component requested to end data processing. @return true when active; false if 'graceful quit' flag has been raised; */ bool service_is_active () { return (!m_graceful_quit); } /** Inform server that it has to stop data processing, clean up and exit. This method will also stop internal Reactor. */ void stop_service (); /** Set Version and Revision number. @param release_ Release number. @param revision_ Patch level. */ void set_version (const string& release_, int revision_); /// Obtain version information string get_version (); /// Set author's name. void set_author (const string& author_); /** New debug information is added to the old log file. To erase old log file, set flag to RMLOG. @param logf_ Defaulted to KEEPLOG that adds log records to the existing log file; RMLOG - remove existing log file and start afresh. */ void set_flags (LogFlag logf_) { m_log_flag = logf_; } /// List options and invocation syntax to stdout virtual void display_help (); /// Get name of process+instance_number string get_proc_name () { return m_proc_name; } /** Change process name. @param proc_name_ new process name */ void set_proc_name (string proc_name_) { m_proc_name = proc_name_; } /// Get command-line process name string get_cmdline_name () { return m_cmdline_name; } /** Get default configuration file name: $HOME/.{command_line_name}.cfg If you want your configuration file name to be different, change the value of m_std_config_name in derived class */ string get_default_config_file () { return m_default_config_file; } /** Get alternative configuration file name. This name is specified as command-line argument '-f' */ string get_config_file () { return m_config_file; } /// Return assumed name of the listening port string get_port () { return m_port; } /** Set listening port name @param port_ new listening port name */ void set_port (string port_) { m_port = port_; } #if !defined(WIN32) /** Obtain reference to the Signal Manager, class SigHandls. */ SigHandlers& get_sig_manager () { return m_sig_dispatcher; } #endif /** Obtain reference to the Reactor. */ Reactor* get_reactor () { return &m_reactor; } /// Become a daemon process static bool become_daemon (); /// Retrieve exit value of the process int get_exit_value () const { return m_exit_value; } protected: /// Set exit value of the process. This value is returned to the shell. void set_exit_value (int v_) { m_exit_value = v_; } protected: /// process name (considering instance_number) string m_proc_name; /// process name as appeared on command line string m_cmdline_name; /// listening port name string m_port; /// standard configuration file name string m_default_config_file; /// alternative configuration file name string m_config_file; /// Max size of the log file u_int m_log_size; /// Process instance int m_instance; /// Full pathname of debug file string m_log_file; /// If 'yes', send log messages to the log server. string m_with_log_server; /** Log server, assa-logd, address (port@@host) */ string m_log_server; /// Debug file mask to filter debug/error messages long m_mask; /// Flag that indicates wheather server outgh to stop and exit bool m_graceful_quit; #if !defined(WIN32) /// Signal handlers dispatcher SigHandlers m_sig_dispatcher; /// Function that swallows SIGPOLL calls SIGPOLLHandler m_sig_poll; #endif /// GenServer object has its very own personal Reactor object. Reactor m_reactor; /// Software version string m_version; /// Software revision (patch) level int m_revision; /// Author's name string m_author; /// Help information const char* m_help_msg; /// Log file initialization flag. If RM_LOG, remove old log file. LogFlag m_log_flag; /** If 'yes', redirects all logging messages to std::cerr. */ string m_log_stdout; /// Daemon option flag. If 'yes', become a UNIX daemon process. string m_daemon; /// If 'yes', skip PID file locking creation/locking step string m_ommit_pidfile; /** Logging level - an integer number that incrementally increases verbosity of the looing messages. The exact meaning of each level is application-specific. */ int m_log_level; /// PID File lock PidFileLock m_pidfile_lock; /// PID File lock path name string m_pidfile; /** Help option flag. If true, [-h, --help] option is being specified on command line. */ bool m_help_flag; /** Version option flag. If true, [-v, --version] options is being specified on command line. */ bool m_version_flag; /// Exit value of the process. int m_exit_value; private: /// No cloning GenServer (const GenServer&); GenServer& operator=(const GenServer&); /// Initialize internals void init_internals (); }; /** Reactor needs to *detach* itself from the Logger * before releasing memory. Otherwise, a race condition * between Logger (singleton) and GenServer (singleton) * might yield core dump if Reactor was destroyed * before Logger. Since Reactor is *attached* to the Logger * with Logger::log_open () for the assa-logd connection, it is * Reactor's responsibility to *detach* first. But, we only care * about GenServer's Reactor. All others (such as those used by * Connector and Acceptor classes) should not. */ inline GenServer:: ~GenServer () { Log::log_close (); } inline void GenServer:: stop_service () { m_graceful_quit = true; m_reactor.deactivate (); } inline void GenServer:: set_version (const string& release_, int revision_) { m_version = release_; m_revision = revision_; } inline void GenServer:: set_author (const string& author_) { m_author = author_; } inline string GenServer:: get_version () { std::ostringstream v; v << "Version: " << m_version << " Revision: " << m_revision << std::ends; return (v.str ()); } inline void GenServer:: display_help () { std::cout << m_help_msg << '\n' << "Written by " << m_author << "\n" << std::endl; } } // The end of namespase ASSA #endif /* GENSERVER_H */