Loading...
Searching...
No Matches
GenServer.cpp
Go to the documentation of this file.
// -*- c++ -*-
//---------------------------------------------------------------------------
// GenServer.cpp
//---------------------------------------------------------------------------
// Copyright (c) 1997-2004,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.
//---------------------------------------------------------------------------
/*
[a e g ijk o qr tu wxy ]
[ABC EFGHIJK MNOPQR TUVWXYZ]
" Standard command-line arguments: \n"
" \n"
" -b, --daemon BOOL - Run process as true UNIX daemon \n"
" -l, --pidfile PATH - The process ID is written to the lockfile PATH \n"
" instead of default ~/.{procname}.pid \n"
" -L, --ommit-pidfile BOOL - Do not create PID lockfile \n"
" -d, --log-stdout BOOL - Write debug to standard output \n"
" -D, --log-file NAME - Write debug to NAME file \n"
" -z, --log-size NUM - Maximum size debug file can reach \n"
" (default is 10Mb) \n"
" -c, --log-level NUM - Log verbosity \n"
" -s, --with-log-server BOOL - Redirect log messages to the log server \n"
" -S, --log-server NAME - Define assa-logd server address \n"
" (default: assalogd@localhost) \n"
" -m, --mask MASK - Mask (default: ALL = 0x7fffffff) \n"
" -p, --port NAME - The TCP/IP port NAME (default - procname) \n"
" -n, --instance NUM - Process instance NUM (default - none) \n"
" -f, --config-file NAME - Alternative config file NAME \n"
" -h, --help - Print this message \n"
" -v, --version - Print version number \n"
" \n"
" NOTE: BOOL value is either 'yes' or 'no' \n"
*/
//------------------------------------------------------------------------------
#include <sys/types.h> // stat(2)
#include <sys/stat.h> // stat(2)
#include <unistd.h> // stat(2)
#ifdef __CYGWIN32__ // to resolve h_errno dependency
# include <errno.h>
# include <netdb.h>
#endif
#include "assa/GenServer.h"
#include "assa/CommonUtils.h"
using namespace ASSA;
GenServer::GenServer ()
:
m_log_size (10485760), // 10 Mb
m_instance (-1),
m_with_log_server ("no"),
m_log_server ("assalogd@"),
m_mask (ALL),
m_graceful_quit (false),
m_version ("unknown"),
m_revision (0),
m_author ("John Doe"),
m_help_msg ("No help available"),
m_log_flag (KEEPLOG),
m_log_stdout ("no"),
m_daemon ("no"),
m_ommit_pidfile ("no"),
m_log_level (-1),
m_help_flag (false),
m_version_flag (false),
m_exit_value (0)
{
add_flag_opt ('h', "help", &m_help_flag);
add_flag_opt ('v', "version", &m_version_flag);
add_opt ('d', "log-stdout", &m_log_stdout);
add_opt ('b', "daemon", &m_daemon);
add_opt ('L', "ommit-pidfile", &m_ommit_pidfile);
add_opt ('s', "with-log-server", &m_with_log_server);
add_opt ('m', "mask", &m_mask);
add_opt ('D', "log-file", &m_log_file);
add_opt ('f', "config-file", &m_config_file);
add_opt ('n', "instance", &m_instance);
add_opt ('p', "port", &m_port);
add_opt ('z', "log-size", &m_log_size);
add_opt ('l', "pidfile", &m_pidfile);
add_opt ('S', "log-server", &m_log_server);
add_opt ('c', "log-level", &m_log_level);
char hn[64];
::gethostname (hn, sizeof (hn)-1);
m_log_server += hn;
}
GenServer::
~GenServer ()
{
Log::log_close ();
}
//------------------------------------------------------------------------------
// Get command line process name parse command line arguments
// request internals initialization.
//------------------------------------------------------------------------------
void
GenServer::
init (int* argc, char* argv [], const char* ht_)
{
char* cp = argv [0];
m_help_msg = ht_;
if (strchr(cp, ASSA_DIR_SEPARATOR)) {
cp += strlen(argv[0]); // position at the end
while (*cp-- != ASSA_DIR_SEPARATOR) {
;
}
cp += 2;
}
#if defined (WIN32) // get rid of '.exe'
char* extidx = cp;
while (*extidx) {
if (*extidx == '.') {
*extidx = '\0';
break;
}
extidx++;
}
#endif
m_cmdline_name = cp;
if (!parse_args ((const char **)argv)) {
std::cerr << "Error in arguments: " << get_opt_error () << std::endl;
std::cerr << "Try '" << argv[0] << " --help' for details.\n";
exit (1);
}
if (m_help_flag) {
display_help ();
exit (0);
}
if (m_version_flag) {
std::cerr << '\n' << argv[0] << " " << get_version () << '\n' << '\n'
<< "Written by " << m_author << "\n\n";
exit (0);
}
std::string s;
if (m_default_config_file.size ()) {
s = ASSA::Utils::strenv (m_default_config_file.c_str ());
m_default_config_file = s;
}
if (m_config_file.size ()) {
s = ASSA::Utils::strenv (m_config_file.c_str ());
m_config_file = s;
}
if (m_log_file.size ()) {
s = ASSA::Utils::strenv (m_log_file.c_str ());
m_log_file = s;
}
if (m_pidfile.size ()) {
s = ASSA::Utils::strenv (m_pidfile.c_str ());
m_pidfile = s;
}
if (m_daemon == "yes") {
assert(become_daemon ());
}
char instbuf[16]; // INT_MAX [-]2147483647
sprintf(instbuf, "%d", m_instance);
if (m_proc_name.length() == 0) {
m_proc_name = m_cmdline_name;
if (m_instance != -1) {
m_proc_name += instbuf;
}
}
if (m_port.length() == 0) {
m_port = m_proc_name;
}
#if !defined(WIN32)
SigAction ignore_act( SIG_IGN );
ignore_act.register_action( SIGHUP );
ignore_act.register_action( SIGPIPE );
ignore_act.register_action( SIGCHLD );
#if !(defined (__FreeBSD__) || defined(__FreeBSD_kernel__) \
|| defined (__NetBSD__))
ignore_act.register_action( SIGCLD );
#endif
ignore_act.register_action( SIGALRM );
m_sig_dispatcher.install ( ASSAIOSIG, &m_sig_poll );
m_sig_dispatcher.install ( SIGINT, (EventHandler*) this );
m_sig_dispatcher.install ( SIGTERM, (EventHandler*) this );
#endif // !defined(WIN32)
init_internals ();
}
void
GenServer::
init_internals ()
{
static const char self[] = "GenServer::init_internals";
#if defined (WIN32)
m_default_config_file = this->get_cmdline_name () + ".ini";
#else
m_default_config_file = "$HOME/." + this->get_cmdline_name ();
m_default_config_file = Utils::strenv (m_default_config_file.c_str ());
#endif
if (m_log_flag == RMLOG && m_log_stdout == "no")
{
struct stat fst;
if (::stat (m_log_file.c_str(), &fst) == 0)
{
if (S_ISREG (fst.st_mode)) {
::unlink (m_log_file.c_str());
}
}
}
Log::set_app_name (get_proc_name ());
if (m_log_stdout == "yes") {
Log::open_log_stdout (m_mask);
}
else {
if (m_with_log_server == "yes") {
Log::open_log_server (m_log_server,
m_log_file.c_str(),
get_reactor (),
m_mask,
m_log_size) ;
}
else {
Log::open_log_file (m_log_file.c_str(), m_mask, m_log_size);
}
}
trace(self);
if (m_ommit_pidfile == "no")
{
if (m_pidfile.size () == 0) {
string s ("~/." + m_proc_name + ".pid");
m_pidfile = ASSA::Utils::strenv (s.c_str ());
}
if (! m_pidfile_lock.lock (m_pidfile)) {
DL((ASSAERR,"Failed to lock PID file: %s\n",
m_pidfile_lock.get_error_msg ()));
exit (1);
}
}
DL((APP,"\n" ));
DL((APP,"========================================================\n"));
DL((APP,"|| Server configuration settings ||\n"));
DL((APP,"========================================================\n"));
DL((APP," cmd_line_name = '%s'\n", m_cmdline_name.c_str() ));
DL((APP," name = '%s'\n", m_proc_name.c_str() ));
DL((APP," default config file = '%s'\n", m_default_config_file.c_str()));
DL((APP," config file = '%s'\n", m_config_file.c_str() ));
DL((APP," mask = 0x%X\n", m_mask ));
dump ();
DL((APP,"========================================================\n"));
DL((APP,"\n"));
}
bool
GenServer::
become_daemon ()
{
#if defined(WIN32)
return true;
#else
Fork f (Fork::LEAVE_ALONE, Fork::IGNORE_STATUS);
if (!f.isChild ()) { // parent exits
exit (0);
}
int size = 1024;
int i = 0;
pid_t nullfd;
for (i = 0; i < size; i++) {
(void) close (i);
}
nullfd = open ("/dev/null", O_WRONLY | O_CREAT, 0666);
if (nullfd == -1) {
syslog (LOG_ERR,"failed to open \"/dev/null\"");
return false;
}
(void) dup2 (nullfd, 1);
(void) dup2 (nullfd, 2);
(void) close (nullfd);
if ( setsid() == -1 ) {
syslog (LOG_ERR,"setsid() failed");
return false;
}
/*---
Changing to root directory would be the right thing to do for a
server (so that it wouldn't possibly depend on any mounted file
systems. But, in practice, it might cause a lot of problems.
---*/
#if 0
if ( chdir("/") == -1 ) {
return false;
}
#endif
return (true);
#endif // defined(WIN32)
}
int
GenServer::
handle_signal (int signum_)
{
trace("GenServer::handle_signal");
std::ostringstream m;
switch (signum_)
{
case SIGTERM: m << "SIGTERM signal caugth. "; break;
case SIGINT: m << "SIGINT signal caugth. "; break;
default: m << "Unexpected signal caugth.";
}
m << "Signal # " << signum_ << std::ends;
DL((APP,"%s\n", m.str ().c_str () ));
DL((APP,"Initiating shutdown sequence...\n"));
fatal_signal_hook ();
DL((APP, "Shutdown sequence completed - Exiting !\n"));
/* Calling stop_service () triggers a call to Reactor::stopReactor()
with subsequent call to Reactor::removeIOHandler() and then
EventHandler::handle_close(). If EventHandler is in the middle
of the *slow* system call such as read(2), handle_close() will
destry EventHandler, and after cotrol is returned from
GenServer::handle_signal(), *slow* system call is restarted
and proceeds to operate on the memory that has been deleted already.
Calling Reactor::deactivate() instead delays memory release.
*/
get_reactor()->deactivate ();
m_graceful_quit = true;
return 0;
}
CommonUtils.h
ASSA_DIR_SEPARATOR
#define ASSA_DIR_SEPARATOR
CommonUtils.h.
Definition CommonUtils.h:47
GenServer.h
GenServer is a base class for generic servers.
ASSAIOSIG
#define ASSAIOSIG
Definition Handlers.h:38
trace
#define trace(s)
trace() is used to trace function call chain in C++ program.
Definition Logger.h:429
DL
#define DL(X)
A macro for writing debug message to the Logger.
Definition Logger.h:273
ASSA::CmdLineOpts::parse_args
bool parse_args(const char *argv[])
Parse command line arguments based on installed options set.
Definition CmdLineOpts.cpp:365
ASSA::CmdLineOpts::add_opt
bool add_opt(const char c, const string &s, string *str)
Add an option with STL string argument.
Definition CmdLineOpts.cpp:220
ASSA::CmdLineOpts::add_flag_opt
bool add_flag_opt(const char c, const string &s, bool *f)
Add binary flag option.
Definition CmdLineOpts.cpp:206
ASSA::CmdLineOpts::dump
void dump() const
Write options set to the log file.
Definition CmdLineOpts.cpp:646
ASSA::CmdLineOpts::get_opt_error
const char * get_opt_error() const
If previous call to one of member functions returned false, retrieve detailed error message.
Definition CmdLineOpts.h:309
ASSA::EventHandler::EventHandler
EventHandler()
Constructor.
Definition EventHandler.h:165
ASSA::Fork
Fork class is a simple wrapper around C library function fork().
Definition Fork.h:86
ASSA::Fork::LEAVE_ALONE
@ LEAVE_ALONE
Ignore all running children on exit.
Definition Fork.h:94
ASSA::Fork::isChild
bool isChild() const
Test whether we are in child section of the code.
Definition Fork.h:136
ASSA::Fork::IGNORE_STATUS
@ IGNORE_STATUS
Don't wait for child to complete.
Definition Fork.h:100
ASSA::GenServer::m_log_server
string m_log_server
Log server, assa-logd, address (port@host).
Definition GenServer.h:263
ASSA::GenServer::get_reactor
Reactor * get_reactor()
Obtain reference to the Reactor.
Definition GenServer.h:221
ASSA::GenServer::m_author
string m_author
Author's name.
Definition GenServer.h:289
ASSA::GenServer::become_daemon
static bool become_daemon()
Become a daemon process.
Definition GenServer.cpp:358
ASSA::GenServer::m_cmdline_name
string m_cmdline_name
process name as appeared on command line
Definition GenServer.h:238
ASSA::GenServer::get_cmdline_name
string get_cmdline_name()
Get command-line process name.
Definition GenServer.h:190
ASSA::GenServer::m_version
string m_version
Software version.
Definition GenServer.h:283
ASSA::GenServer::m_instance
int m_instance
Process instance.
Definition GenServer.h:253
ASSA::GenServer::GenServer
GenServer()
Constructor.
Definition GenServer.cpp:56
ASSA::GenServer::m_log_file
string m_log_file
Full pathname of debug file.
Definition GenServer.h:256
ASSA::GenServer::~GenServer
virtual ~GenServer()
Destructor.
Definition GenServer.cpp:112
ASSA::GenServer::m_pidfile_lock
PidFileLock m_pidfile_lock
PID File lock.
Definition GenServer.h:313
ASSA::GenServer::m_graceful_quit
bool m_graceful_quit
Flag that indicates wheather server outgh to stop and exit.
Definition GenServer.h:269
ASSA::GenServer::m_config_file
string m_config_file
alternative configuration file name
Definition GenServer.h:247
ASSA::GenServer::init_internals
void init_internals()
Initialize internals.
Definition GenServer.cpp:271
ASSA::GenServer::m_ommit_pidfile
string m_ommit_pidfile
If 'yes', skip PID file locking creation/locking step.
Definition GenServer.h:304
ASSA::GenServer::m_pidfile
string m_pidfile
PID File lock path name.
Definition GenServer.h:316
ASSA::GenServer::m_revision
int m_revision
Software revision (patch) level.
Definition GenServer.h:286
ASSA::GenServer::display_help
virtual void display_help()
List options and invocation syntax to stdout.
Definition GenServer.h:375
ASSA::GenServer::m_with_log_server
string m_with_log_server
If 'yes', send log messages to the log server.
Definition GenServer.h:259
ASSA::GenServer::m_version_flag
bool m_version_flag
Version option flag.
Definition GenServer.h:326
ASSA::GenServer::m_log_size
u_int m_log_size
Max size of the log file.
Definition GenServer.h:250
ASSA::GenServer::m_mask
long m_mask
Debug file mask to filter debug/error messages.
Definition GenServer.h:266
ASSA::GenServer::m_log_stdout
string m_log_stdout
If 'yes', redirects all logging messages to std::cerr.
Definition GenServer.h:298
ASSA::GenServer::m_default_config_file
string m_default_config_file
standard configuration file name
Definition GenServer.h:244
ASSA::GenServer::m_sig_poll
SIGPOLLHandler m_sig_poll
Function that swallows SIGPOLL calls.
Definition GenServer.h:276
ASSA::GenServer::KEEPLOG
@ KEEPLOG
By default, append new log records to the existing log file.
Definition GenServer.h:67
ASSA::GenServer::RMLOG
@ RMLOG
Remove existing log file and start afresh.
Definition GenServer.h:70
ASSA::GenServer::m_port
string m_port
listening port name
Definition GenServer.h:241
ASSA::GenServer::m_log_flag
LogFlag m_log_flag
Log file initialization flag. If RM_LOG, remove old log file.
Definition GenServer.h:295
ASSA::GenServer::m_exit_value
int m_exit_value
Exit value of the process.
Definition GenServer.h:329
ASSA::GenServer::fatal_signal_hook
virtual void fatal_signal_hook()
Hook for derived class to do addition clean-up when terminating signal is delivered by OS.
Definition GenServer.h:135
ASSA::GenServer::m_help_msg
const char * m_help_msg
Help information.
Definition GenServer.h:292
ASSA::GenServer::get_proc_name
string get_proc_name()
Get name of process+instance_number.
Definition GenServer.h:182
ASSA::GenServer::init
virtual void init(int *argc, char *argv[], const char *help_info)
Provide an entry point into the service and perfom initialization of the service.
Definition GenServer.cpp:124
ASSA::GenServer::m_proc_name
string m_proc_name
process name (considering instance_number)
Definition GenServer.h:235
ASSA::GenServer::m_log_level
int m_log_level
Logging level - an integer number that incrementally increases verbosity of the looing messages.
Definition GenServer.h:310
ASSA::GenServer::handle_signal
int handle_signal(int signum_)
Handle fatal signals.
Definition GenServer.cpp:409
ASSA::GenServer::m_sig_dispatcher
SigHandlers m_sig_dispatcher
Signal handlers dispatcher.
Definition GenServer.h:273
ASSA::GenServer::get_version
string get_version()
Obtain version information.
Definition GenServer.h:366
ASSA::GenServer::m_help_flag
bool m_help_flag
Help option flag.
Definition GenServer.h:321
ASSA::GenServer::m_daemon
string m_daemon
Daemon option flag. If 'yes', become a UNIX daemon process.
Definition GenServer.h:301
ASSA::Reactor::deactivate
void deactivate(void)
Deactivate Reactor.
Definition Reactor.h:234
ASSA::SigAction
Definition SigAction.h:95
ASSA::SigAction::register_action
int register_action(int signum_, SigAction *oaction_=0)
Register this object as current disposition for signal signum_, and store old disposition in oaction_...
Definition SigAction.h:360
ASSA::Log::open_log_file
int open_log_file(const char *logfname_, u_long groups_=ALL, u_long maxsize_=10485760)
Open log file.
Definition Logger.h:319
ASSA::Log::log_close
int log_close(void)
Close logging stream.
Definition Logger.h:359
ASSA::Log::set_app_name
void set_app_name(const std::string &appname_)
Set application name.
Definition Logger.h:305
ASSA::Log::open_log_server
int open_log_server(const std::string &logsvraddr_, const char *logfname_, Reactor *reactor_, u_long groups_=ASSA::ALL, u_long maxsize_=10485760)
Open connection with and write log message to the log server.
Definition Logger.h:344
ASSA::Log::open_log_stdout
int open_log_stdout(u_long groups_=ALL)
Write log message to standard output.
Definition Logger.h:327
ASSA::Utils::strenv
std::string strenv(const char *in_)
Expand the passed string in_ by substituting environment variable names for their values.
Definition CommonUtils.cpp:123
ASSA
Definition Acceptor.h:40
ASSA::APP
@ APP
Application-level messages.
Definition LogMask.h:27
ASSA::ASSAERR
@ ASSAERR
ASSA and system errors.
Definition LogMask.h:34
ASSA::ALL
@ ALL
All messages: library + application.
Definition LogMask.h:62