libassa 3.5.1
Loading...
Searching...
No Matches
GenServer.cpp
Go to the documentation of this file.
1// -*- c++ -*-
2//---------------------------------------------------------------------------
3// GenServer.cpp
4//---------------------------------------------------------------------------
5// Copyright (c) 1997-2004,2005 by Vladislav Grinchenko
6//
7// This library is free software; you can redistribute it and/or
8// modify it under the terms of the GNU Library General Public
9// License as published by the Free Software Foundation; either
10// version 2 of the License, or (at your option) any later version.
11//---------------------------------------------------------------------------
12
13/*
14 [a e g ijk o qr tu wxy ]
15 [ABC EFGHIJK MNOPQR TUVWXYZ]
16
17" Standard command-line arguments: \n"
18" \n"
19" -b, --daemon BOOL - Run process as true UNIX daemon \n"
20" -l, --pidfile PATH - The process ID is written to the lockfile PATH \n"
21" instead of default ~/.{procname}.pid \n"
22" -L, --ommit-pidfile BOOL - Do not create PID lockfile \n"
23" -d, --log-stdout BOOL - Write debug to standard output \n"
24" -D, --log-file NAME - Write debug to NAME file \n"
25" -z, --log-size NUM - Maximum size debug file can reach \n"
26" (default is 10Mb) \n"
27" -c, --log-level NUM - Log verbosity \n"
28" -s, --with-log-server BOOL - Redirect log messages to the log server \n"
29" -S, --log-server NAME - Define assa-logd server address \n"
30" (default: assalogd@localhost) \n"
31" -m, --mask MASK - Mask (default: ALL = 0x7fffffff) \n"
32" -p, --port NAME - The TCP/IP port NAME (default - procname) \n"
33" -n, --instance NUM - Process instance NUM (default - none) \n"
34" -f, --config-file NAME - Alternative config file NAME \n"
35" -h, --help - Print this message \n"
36" -v, --version - Print version number \n"
37" \n"
38" NOTE: BOOL value is either 'yes' or 'no' \n"
39*/
40//------------------------------------------------------------------------------
41
42#include <sys/types.h> // stat(2)
43#include <sys/stat.h> // stat(2)
44#include <unistd.h> // stat(2)
45
46#ifdef __CYGWIN32__ // to resolve h_errno dependency
47# include <errno.h>
48# include <netdb.h>
49#endif
50
51#include "assa/GenServer.h"
52#include "assa/CommonUtils.h"
53
54using namespace ASSA;
55
57 :
58 m_log_size (10485760), // 10 Mb
59 m_instance (-1),
60 m_with_log_server ("no"),
61 m_log_server ("assalogd@"),
62 m_mask (ALL),
63 m_graceful_quit (false),
64 m_version ("unknown"),
65 m_revision (0),
66 m_author ("John Doe"),
67 m_help_msg ("No help available"),
68 m_log_flag (KEEPLOG),
69 m_log_stdout ("no"),
70 m_daemon ("no"),
71 m_ommit_pidfile ("no"),
72 m_log_level (-1),
73 m_help_flag (false),
74 m_version_flag (false),
75 m_exit_value (0)
76{
77 add_flag_opt ('h', "help", &m_help_flag);
78 add_flag_opt ('v', "version", &m_version_flag);
79
80 add_opt ('d', "log-stdout", &m_log_stdout);
81 add_opt ('b', "daemon", &m_daemon);
82 add_opt ('L', "ommit-pidfile", &m_ommit_pidfile);
83 add_opt ('s', "with-log-server", &m_with_log_server);
84 add_opt ('m', "mask", &m_mask);
85 add_opt ('D', "log-file", &m_log_file);
86 add_opt ('f', "config-file", &m_config_file);
87 add_opt ('n', "instance", &m_instance);
88 add_opt ('p', "port", &m_port);
89 add_opt ('z', "log-size", &m_log_size);
90 add_opt ('l', "pidfile", &m_pidfile);
91 add_opt ('S', "log-server", &m_log_server);
92 add_opt ('c', "log-level", &m_log_level);
93
96 char hn[64];
97 ::gethostname (hn, sizeof (hn)-1);
99}
100
112~GenServer ()
113{
115}
116
117//------------------------------------------------------------------------------
118// Get command line process name parse command line arguments
119// request internals initialization.
120//------------------------------------------------------------------------------
121
122void
124init (int* argc, char* argv [], const char* ht_)
125{
126 char* cp = argv [0];
127 m_help_msg = ht_;
128
134 cp += strlen(argv[0]); // position at the end
135 while (*cp-- != ASSA_DIR_SEPARATOR) {
136 ;
137 }
138 cp += 2;
139 }
140
141#if defined (WIN32) // get rid of '.exe'
142 char* extidx = cp;
143 while (*extidx) {
144 if (*extidx == '.') {
145 *extidx = '\0';
146 break;
147 }
148 extidx++;
149 }
150#endif
152
153 if (!parse_args ((const char **)argv)) {
154 std::cerr << "Error in arguments: " << get_opt_error () << std::endl;
155 std::cerr << "Try '" << argv[0] << " --help' for details.\n";
156 exit (1);
157 }
158
159 if (m_help_flag) {
160 display_help ();
161 exit (0);
162 }
163
164 if (m_version_flag) {
165 std::cerr << '\n' << argv[0] << " " << get_version () << '\n' << '\n'
166 << "Written by " << m_author << "\n\n";
167 exit (0);
168 }
169
173 std::string s;
174
175 if (m_default_config_file.size ()) {
178 }
179
180 if (m_config_file.size ()) {
183 }
184
185 if (m_log_file.size ()) {
186 s = ASSA::Utils::strenv (m_log_file.c_str ());
187 m_log_file = s;
188 }
189
190 if (m_pidfile.size ()) {
191 s = ASSA::Utils::strenv (m_pidfile.c_str ());
192 m_pidfile = s;
193 }
194
197 if (m_daemon == "yes") {
199 }
200
203 char instbuf[16]; // INT_MAX [-]2147483647
204 sprintf(instbuf, "%d", m_instance);
205
206 if (m_proc_name.length() == 0) {
208
209 if (m_instance != -1) {
211 }
212 }
213 if (m_port.length() == 0) {
215 }
216
217#if !defined(WIN32)
222
230 ignore_act.register_action( SIGHUP );
231
232 ignore_act.register_action( SIGPIPE );
233 ignore_act.register_action( SIGCHLD );
234#if !(defined (__FreeBSD__) || defined(__FreeBSD_kernel__) \
235 || defined (__NetBSD__))
236 ignore_act.register_action( SIGCLD );
237#endif
238 ignore_act.register_action( SIGALRM );
239
245
253
261
262#endif // !defined(WIN32)
263
267}
268
269void
272{
273 static const char self[] = "GenServer::init_internals";
274
279#if defined (WIN32)
280 m_default_config_file = this->get_cmdline_name () + ".ini";
281#else
282 m_default_config_file = "$HOME/." + this->get_cmdline_name ();
284#endif
285
291 if (m_log_flag == RMLOG && m_log_stdout == "no")
292 {
293 struct stat fst;
294 if (::stat (m_log_file.c_str(), &fst) == 0)
295 {
296 if (S_ISREG (fst.st_mode)) {
297 ::unlink (m_log_file.c_str());
298 }
299 }
300 }
301
310
311 if (m_log_stdout == "yes") {
313 }
314 else {
315 if (m_with_log_server == "yes") {
317 m_log_file.c_str(),
318 get_reactor (),
319 m_mask,
320 m_log_size) ;
321 }
322 else {
324 }
325 }
326
327 trace(self);
328
329 if (m_ommit_pidfile == "no")
330 {
331 if (m_pidfile.size () == 0) {
332 string s ("~/." + m_proc_name + ".pid");
333 m_pidfile = ASSA::Utils::strenv (s.c_str ());
334 }
335 if (! m_pidfile_lock.lock (m_pidfile)) {
336 DL((ASSAERR,"Failed to lock PID file: %s\n",
338 exit (1);
339 }
340 }
341
342 DL((APP,"\n" ));
343 DL((APP,"========================================================\n"));
344 DL((APP,"|| Server configuration settings ||\n"));
345 DL((APP,"========================================================\n"));
346 DL((APP," cmd_line_name = '%s'\n", m_cmdline_name.c_str() ));
347 DL((APP," name = '%s'\n", m_proc_name.c_str() ));
348 DL((APP," default config file = '%s'\n", m_default_config_file.c_str()));
349 DL((APP," config file = '%s'\n", m_config_file.c_str() ));
350 DL((APP," mask = 0x%X\n", m_mask ));
351 dump ();
352 DL((APP,"========================================================\n"));
353 DL((APP,"\n"));
354}
355
356bool
359{
360#if defined(WIN32)
361 return true;
362#else
364
365 if (!f.isChild ()) { // parent exits
366 exit (0);
367 }
368
369 int size = 1024;
370 int i = 0;
372
373 for (i = 0; i < size; i++) {
374 (void) close (i);
375 }
376
377 nullfd = open ("/dev/null", O_WRONLY | O_CREAT, 0666);
378 if (nullfd == -1) {
379 syslog (LOG_ERR,"failed to open \"/dev/null\"");
380 return false;
381 }
382
383 (void) dup2 (nullfd, 1);
384 (void) dup2 (nullfd, 2);
385 (void) close (nullfd);
386
387 if ( setsid() == -1 ) {
388 syslog (LOG_ERR,"setsid() failed");
389 return false;
390 }
391
392 /*---
393 Changing to root directory would be the right thing to do for a
394 server (so that it wouldn't possibly depend on any mounted file
395 systems. But, in practice, it might cause a lot of problems.
396 ---*/
397#if 0
398 if ( chdir("/") == -1 ) {
399 return false;
400 }
401#endif
402 return (true);
403
404#endif // defined(WIN32)
405}
406
407int
410{
411 trace("GenServer::handle_signal");
412 std::ostringstream m;
413
414 switch (signum_)
415 {
416 case SIGTERM: m << "SIGTERM signal caugth. "; break;
417 case SIGINT: m << "SIGINT signal caugth. "; break;
418 default: m << "Unexpected signal caugth.";
419 }
420 m << "Signal # " << signum_ << std::ends;
421 DL((APP,"%s\n", m.str ().c_str () ));
422 DL((APP,"Initiating shutdown sequence...\n"));
423
425
426 DL((APP, "Shutdown sequence completed - Exiting !\n"));
427
428 /* Calling stop_service () triggers a call to Reactor::stopReactor()
429 with subsequent call to Reactor::removeIOHandler() and then
430 EventHandler::handle_close(). If EventHandler is in the middle
431 of the *slow* system call such as read(2), handle_close() will
432 destry EventHandler, and after cotrol is returned from
433 GenServer::handle_signal(), *slow* system call is restarted
434 and proceeds to operate on the memory that has been deleted already.
435
436 Calling Reactor::deactivate() instead delays memory release.
437 */
439 m_graceful_quit = true;
440
441 return 0;
442}
443
#define ASSA_DIR_SEPARATOR
CommonUtils.h.
Definition CommonUtils.h:47
GenServer is a base class for generic servers.
#define ASSAIOSIG
Definition Handlers.h:38
#define trace(s)
trace() is used to trace function call chain in C++ program.
Definition Logger.h:429
#define DL(X)
A macro for writing debug message to the Logger.
Definition Logger.h:273
A wrapper class to provide AutoPtr with reference semantics.
Definition AutoPtr.h:32
bool parse_args(const char *argv[])
Parse command line arguments based on installed options set.
bool add_opt(const char c, const string &s, string *str)
Add an option with STL string argument.
bool add_flag_opt(const char c, const string &s, bool *f)
Add binary flag option.
void dump() const
Write options set to the log file.
const char * get_opt_error() const
If previous call to one of member functions returned false, retrieve detailed error message.
EventHandler class.
Fork class is a simple wrapper around C library function fork().
Definition Fork.h:86
@ LEAVE_ALONE
Ignore all running children on exit.
Definition Fork.h:94
@ IGNORE_STATUS
Don't wait for child to complete.
Definition Fork.h:100
string m_log_server
Log server, assa-logd, address (port@host)
Definition GenServer.h:263
Reactor * get_reactor()
Obtain reference to the Reactor.
Definition GenServer.h:221
string m_author
Author's name.
Definition GenServer.h:289
static bool become_daemon()
Become a daemon process.
string m_cmdline_name
process name as appeared on command line
Definition GenServer.h:238
string get_cmdline_name()
Get command-line process name.
Definition GenServer.h:190
int m_instance
Process instance.
Definition GenServer.h:253
GenServer()
Constructor.
Definition GenServer.cpp:56
string m_log_file
Full pathname of debug file.
Definition GenServer.h:256
virtual ~GenServer()
Destructor.
PidFileLock m_pidfile_lock
PID File lock.
Definition GenServer.h:313
bool m_graceful_quit
Flag that indicates wheather server outgh to stop and exit.
Definition GenServer.h:269
string m_config_file
alternative configuration file name
Definition GenServer.h:247
void init_internals()
Initialize internals.
string m_ommit_pidfile
If 'yes', skip PID file locking creation/locking step.
Definition GenServer.h:304
string m_pidfile
PID File lock path name.
Definition GenServer.h:316
virtual void display_help()
List options and invocation syntax to stdout.
Definition GenServer.h:375
string m_with_log_server
If 'yes', send log messages to the log server.
Definition GenServer.h:259
bool m_version_flag
Version option flag.
Definition GenServer.h:326
u_int m_log_size
Max size of the log file.
Definition GenServer.h:250
long m_mask
Debug file mask to filter debug/error messages.
Definition GenServer.h:266
string m_log_stdout
If 'yes', redirects all logging messages to std::cerr.
Definition GenServer.h:298
string m_default_config_file
standard configuration file name
Definition GenServer.h:244
SIGPOLLHandler m_sig_poll
Function that swallows SIGPOLL calls.
Definition GenServer.h:276
@ RMLOG
Remove existing log file and start afresh.
Definition GenServer.h:70
string m_port
listening port name
Definition GenServer.h:241
LogFlag m_log_flag
Log file initialization flag. If RM_LOG, remove old log file.
Definition GenServer.h:295
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
const char * m_help_msg
Help information.
Definition GenServer.h:292
string get_proc_name()
Get name of process+instance_number.
Definition GenServer.h:182
virtual void init(int *argc, char *argv[], const char *help_info)
Provide an entry point into the service and perfom initialization of the service.
string m_proc_name
process name (considering instance_number)
Definition GenServer.h:235
int m_log_level
Logging level - an integer number that incrementally increases verbosity of the looing messages.
Definition GenServer.h:310
int handle_signal(int signum_)
Handle fatal signals.
SigHandlers m_sig_dispatcher
Signal handlers dispatcher.
Definition GenServer.h:273
string get_version()
Obtain version information.
Definition GenServer.h:366
bool m_help_flag
Help option flag.
Definition GenServer.h:321
string m_daemon
Daemon option flag. If 'yes', become a UNIX daemon process.
Definition GenServer.h:301
const char * get_error_msg() const
In case of error, return a verbal description of the last error.
bool lock(const string &filename_)
Lock the file.
void deactivate(void)
Deactivate Reactor.
Definition Reactor.h:234
virtual int install(int signum_, EventHandler *new_hand_, SigAction *new_disp_=0, EventHandler **old_hand_=0, SigAction *old_disp_=0)
Register EventHandler with dispatching system.
int open_log_file(const char *logfname_, u_long groups_=ALL, u_long maxsize_=10485760)
Open log file.
Definition Logger.h:319
int log_close(void)
Close logging stream.
Definition Logger.h:359
void set_app_name(const std::string &appname_)
Set application name.
Definition Logger.h:305
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
int open_log_stdout(u_long groups_=ALL)
Write log message to standard output.
Definition Logger.h:327
std::string strenv(const char *in_)
Expand the passed string in_ by substituting environment variable names for their values.
@ APP
Application-level messages
Definition LogMask.h:27
@ ASSAERR
ASSA and system errors
Definition LogMask.h:34
@ ALL
All messages: library + application
Definition LogMask.h:62