/build/buildd/libassa-3.4.1/assa/GenServer.cpp

Go to the documentation of this file.
00001 // -*- c++ -*-
00002 //---------------------------------------------------------------------------
00003 //                            GenServer.cpp
00004 //---------------------------------------------------------------------------
00005 //  Copyright (c) 1997-2004,2005 by Vladislav Grinchenko
00006 //
00007 //  This library is free software; you can redistribute it and/or
00008 //  modify it under the terms of the GNU Library General Public
00009 //  License as published by the Free Software Foundation; either
00010 //  version 2 of the License, or (at your option) any later version.
00011 //---------------------------------------------------------------------------
00012 
00013 /*
00014   [a   e g ijk   o qr tu wxy ]
00015   [ABC EFGHIJK MNOPQR TUVWXYZ]
00016 
00017 " Standard command-line arguments:                                           \n"
00018 "                                                                            \n"
00019 "  -b, --daemon BOOL        - Run process as true UNIX daemon                \n"
00020 "  -l, --pidfile PATH       - The process ID is written to the lockfile PATH \n"
00021 "                             instead of default ~/.{procname}.pid           \n"
00022 "  -L, --ommit-pidfile BOOL - Do not create PID lockfile                     \n"
00023 "  -d, --log-stdout BOOL    - Write debug to standard output                 \n"
00024 "  -D, --log-file NAME      - Write debug to NAME file                       \n"
00025 "  -z, --log-size NUM       - Maximum size debug file can reach              \n"
00026 "                             (default is 10Mb)                              \n"
00027 "  -c, --log-level NUM      - Log verbosity                                  \n"
00028 "  -s, --with-log-server BOOL - Redirect log messages to the log server      \n"
00029 "  -S, --log-server NAME    - Define assa-logd server address                \n"
00030 "                             (default: assalogd@localhost)                  \n"
00031 "  -m, --mask MASK          - Mask (default: ALL = 0x7fffffff)               \n"
00032 "  -p, --port NAME          - The TCP/IP port NAME (default - procname)      \n"
00033 "  -n, --instance NUM       - Process instance NUM (default - none)          \n"
00034 "  -f, --config-file NAME   - Alternative config file NAME                   \n"
00035 "  -h, --help               - Print this message                             \n"
00036 "  -v, --version            - Print version number                           \n"
00037 "                                                                            \n"
00038 " NOTE: BOOL value is either 'yes' or 'no'                                   \n"
00039 */
00040 //------------------------------------------------------------------------------
00041 
00042 #include <sys/types.h>          // stat(2)
00043 #include <sys/stat.h>           // stat(2)
00044 #include <unistd.h>             // stat(2)
00045 
00046 #ifdef __CYGWIN32__             // to resolve h_errno dependency
00047 #  include <errno.h>
00048 #  include <netdb.h>            
00049 #endif
00050 
00051 #include "assa/GenServer.h"
00052 #include "assa/CommonUtils.h"
00053 
00054 using namespace ASSA;
00055 
00056 GenServer::GenServer () :
00057     m_log_size        (10485760), // 10 Mb 
00058     m_instance        (-1),
00059     m_with_log_server ("no"),
00060     m_log_server      ("assalogd@"),
00061     m_mask            (ALL), 
00062     m_graceful_quit   (false),
00063     m_version         ("unknown"),
00064     m_revision        (0),
00065     m_author          ("John Doe"),
00066     m_help_msg        ("No help available"),
00067     m_log_flag        (KEEPLOG),
00068     m_log_stdout      ("no"),
00069     m_daemon          ("no"),
00070     m_ommit_pidfile   ("no"),
00071     m_log_level       (-1),
00072     m_help_flag       (false),
00073     m_version_flag    (false),
00074     m_exit_value      (0)
00075 {
00076     add_flag_opt ('h', "help",       &m_help_flag);
00077     add_flag_opt ('v', "version",    &m_version_flag);
00078 
00079     add_opt ('d', "log-stdout",      &m_log_stdout);
00080     add_opt ('b', "daemon",          &m_daemon);
00081     add_opt ('L', "ommit-pidfile",   &m_ommit_pidfile);
00082     add_opt ('s', "with-log-server", &m_with_log_server);
00083     add_opt ('m', "mask",            &m_mask);
00084     add_opt ('D', "log-file",        &m_log_file);
00085     add_opt ('f', "config-file",     &m_config_file);
00086     add_opt ('n', "instance",        &m_instance);
00087     add_opt ('p', "port",            &m_port);
00088     add_opt ('z', "log-size",        &m_log_size);
00089     add_opt ('l', "pidfile",         &m_pidfile);
00090     add_opt ('S', "log-server",      &m_log_server);
00091     add_opt ('c', "log-level",       &m_log_level);
00092 }
00093 
00094 //------------------------------------------------------------------------------
00095 //    Get command line process name parse command line arguments
00096 //    request internals initialization.
00097 //------------------------------------------------------------------------------
00098 
00099 void 
00100 GenServer::
00101 init (int* argc, char* argv [], const char* ht_)
00102 {
00103     char* cp = argv [0];
00104     m_help_msg = ht_;
00105 
00110     if ( strchr(cp,'/') ) {
00111         cp += strlen(argv[0]); // position at the end
00112         while ( *cp-- != '/' ) ;
00113         cp += 2;
00114     }
00115     m_cmdline_name = cp;        
00116     
00117     if (!parse_args ((const char **)argv)) {
00118         std::cerr << "Error in arguments: " << get_opt_error () << std::endl;
00119         std::cerr << "Try '" << argv[0] << " --help' for details.\n";
00120         exit (1);
00121     }
00122     if (m_help_flag) {
00123         display_help ();
00124         exit (0);
00125     }
00126     if (m_version_flag) {
00127         std::cerr << '\n' << argv[0] << " " << get_version () << '\n' << '\n'
00128              << "Written by " << m_author << "\n\n";
00129         exit (0);
00130     }
00131     if (m_daemon == "yes") {
00132         assert(become_daemon ());
00133     }
00136     char instbuf[16];       // INT_MAX   [-]2147483647
00137     sprintf(instbuf, "%d", m_instance);
00138 
00139     if (m_proc_name.length() == 0) {
00140         m_proc_name = m_cmdline_name;
00141 
00142         if (m_instance != -1) {
00143             m_proc_name += instbuf;
00144         }
00145     }
00146     if (m_port.length() == 0) {
00147         m_port = m_proc_name;
00148     }
00149 
00153     SigAction ignore_act( SIG_IGN );
00154 
00162     ignore_act.register_action( SIGHUP );
00163     
00164     ignore_act.register_action( SIGPIPE );
00165     ignore_act.register_action( SIGCHLD );
00166 #if !(defined (__FreeBSD__) || defined(__FreeBSD_kernel__) \
00167     || defined (__NetBSD__))
00168     ignore_act.register_action( SIGCLD );
00169 #endif
00170     ignore_act.register_action( SIGALRM );
00171     
00176     m_sig_dispatcher.install ( ASSAIOSIG, &m_sig_poll );
00177 
00184     m_sig_dispatcher.install ( SIGINT, (EventHandler*) this );
00185     
00192     m_sig_dispatcher.install ( SIGTERM, (EventHandler*) this );
00193     
00196     init_internals ();
00197 }
00198 
00199 void 
00200 GenServer::
00201 init_internals ()
00202 {
00203     static const char self[] = "GenServer::init_internals";
00204 
00207     m_default_config_file = "$HOME/." + this->get_cmdline_name ();
00208     m_default_config_file = Utils::strenv (m_default_config_file.c_str ());
00209 
00215     if (m_log_flag == RMLOG && m_log_stdout == "no") {
00216         struct stat fst;
00217         if (::stat (m_log_file.c_str(), &fst) == 0) {
00218             if (S_ISREG (fst.st_mode)) {
00219                 ::unlink (m_log_file.c_str());
00220             }
00221         }
00222     }
00223 
00230     char hn[64];
00231     ::gethostname (hn, sizeof (hn)-1);
00232     m_log_server += hn;
00233 
00234     Log::set_app_name (get_proc_name ());
00235 
00236     if (m_log_stdout == "yes") {
00237         Log::open_log_stdout (m_mask);
00238     }
00239     else {
00240         if (m_with_log_server == "yes") {
00241             Log::open_log_server (m_log_server, 
00242                                   m_log_file.c_str(), 
00243                                   get_reactor (), 
00244                                   m_mask, 
00245                                   m_log_size) ;
00246         }
00247         else {
00248             Log::open_log_file (m_log_file.c_str(), m_mask, m_log_size);
00249         }
00250     }
00251     
00252     trace(self);
00253 
00254     if (m_ommit_pidfile == "no") {
00255         if (m_pidfile.size () == 0) {
00256             m_pidfile = "~/." + m_proc_name + ".pid";
00257         }
00258         if (! m_pidfile_lock.lock (m_pidfile)) {
00259             DL((ERROR,"Failed to lock PID file: %s\n",
00260                 m_pidfile_lock.get_error_msg ()));
00261             exit (1);
00262         }
00263     }
00264 
00265     DL((APP,"\n"                                                        ));
00266     DL((APP,"========================================================\n"));
00267     DL((APP,"||         Server configuration settings              ||\n"));
00268     DL((APP,"========================================================\n"));
00269     DL((APP," cmd_line_name       = '%s'\n", m_cmdline_name.c_str()   ));
00270     DL((APP," name                = '%s'\n", m_proc_name.c_str()      ));
00271     DL((APP," default config file = '%s'\n", m_default_config_file.c_str()));
00272     DL((APP," config file         = '%s'\n", m_config_file.c_str()    ));
00273     DL((APP," mask                = 0x%X\n", m_mask                   ));
00274     dump ();
00275     DL((APP,"========================================================\n"));
00276     DL((APP,"\n"));
00277 }
00278 
00279 bool
00280 GenServer::
00281 become_daemon ()
00282 {
00283     Fork f (Fork::LEAVE_ALONE, Fork::IGNORE_STATUS);
00284 
00285     if (!f.isChild ()) {    // parent exits
00286         exit (0);
00287     }
00288 
00289     int size = 1024;
00290     int i = 0;
00291     pid_t nullfd;
00292 
00293     for (i = 0; i < size; i++) {
00294         (void) close (i);
00295     }
00296         
00297     nullfd = open ("/dev/null", O_WRONLY | O_CREAT, 0666);
00298     if (nullfd == -1) {
00299         syslog (LOG_ERR,"failed to open \"/dev/null\"");
00300         return false;
00301     }
00302 
00303     (void) dup2 (nullfd, 1);
00304     (void) dup2 (nullfd, 2);
00305     (void) close (nullfd);
00306 
00307     if ( setsid() == -1 ) {
00308         syslog (LOG_ERR,"setsid() failed");
00309         return false;
00310     }
00311 
00312     /*---
00313       Changing to root directory would be the right thing to do for a 
00314       server (so that it wouldn't possibly depend on any mounted file 
00315       systems. But, in practice, it might cause a lot of problems.
00316       ---*/
00317 #if 0
00318     if ( chdir("/") == -1 ) {
00319         return false;
00320     }
00321 #endif
00322     return (true);
00323 }
00324 
00325 int 
00326 GenServer::
00327 handle_signal (int signum_)
00328 {
00329     trace("GenServer::handle_signal");
00330     std::ostringstream m;
00331     
00332     switch (signum_) 
00333     {
00334         case SIGTERM: m << "SIGTERM signal caugth. "; break;
00335         case SIGINT:  m << "SIGINT signal caugth. "; break;
00336         default:      m << "Unexpected signal caugth.";
00337     }
00338     m << "Signal # " << signum_ << std::ends;
00339     DL((APP,"%s\n", m.str ().c_str () ));
00340     DL((APP,"Initiating shutdown sequence...\n"));
00341 
00342     fatal_signal_hook ();
00343 
00344     DL((APP, "Shutdown sequence completed - Exiting !\n"));
00345     
00346     /* Calling stop_service () triggers a call to Reactor::stopReactor()
00347        with subsequent call to Reactor::removeIOHandler() and then
00348        EventHandler::handle_close(). If EventHandler is in the middle
00349        of the *slow* system call such as read(2), handle_close() will 
00350        destry EventHandler, and after cotrol is returned from 
00351        GenServer::handle_signal(), *slow* system call is restarted 
00352        and proceeds to operate on the memory that has been deleted already.
00353 
00354        Calling Reactor::deactivate() instead delays memory release.
00355     */
00356     get_reactor()->deactivate ();
00357     m_graceful_quit = true;
00358 
00359     return 0;
00360 }       
00361 

Generated on Tue Jun 20 10:36:21 2006 for libassa by  doxygen 1.4.6