libassa
3.5.1
Main Page
Namespaces
Classes
Files
File List
File Members
All
Classes
Namespaces
Files
Functions
Variables
Typedefs
Enumerations
Enumerator
Friends
Macros
assa
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
54
using namespace
ASSA;
55
56
GenServer::GenServer
()
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);
98
m_log_server
+= hn;
99
}
100
111
GenServer::
112
~GenServer
()
113
{
114
Log::log_close
();
115
}
116
117
//------------------------------------------------------------------------------
118
// Get command line process name parse command line arguments
119
// request internals initialization.
120
//------------------------------------------------------------------------------
121
122
void
123
GenServer::
124
init
(
int
* argc,
char
* argv [],
const
char
* ht_)
125
{
126
char
* cp = argv [0];
127
m_help_msg
= ht_;
128
133
if
(strchr(cp,
ASSA_DIR_SEPARATOR
)) {
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
151
m_cmdline_name
= cp;
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 ()) {
176
s =
ASSA::Utils::strenv
(
m_default_config_file
.c_str ());
177
m_default_config_file
= s;
178
}
179
180
if
(
m_config_file
.size ()) {
181
s =
ASSA::Utils::strenv
(
m_config_file
.c_str ());
182
m_config_file
= s;
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"
) {
198
assert(
become_daemon
());
199
}
200
203
char
instbuf[16];
// INT_MAX [-]2147483647
204
sprintf(instbuf,
"%d"
,
m_instance
);
205
206
if
(
m_proc_name
.length() == 0) {
207
m_proc_name
=
m_cmdline_name
;
208
209
if
(
m_instance
!= -1) {
210
m_proc_name
+= instbuf;
211
}
212
}
213
if
(
m_port
.length() == 0) {
214
m_port
=
m_proc_name
;
215
}
216
217
#if !defined(WIN32)
218
221
SigAction
ignore_act( SIG_IGN );
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
244
m_sig_dispatcher
.
install
(
ASSAIOSIG
, &
m_sig_poll
);
245
252
m_sig_dispatcher
.
install
( SIGINT, (
EventHandler
*)
this
);
253
260
m_sig_dispatcher
.
install
( SIGTERM, (
EventHandler
*)
this
);
261
262
#endif // !defined(WIN32)
263
266
init_internals
();
267
}
268
269
void
270
GenServer::
271
init_internals
()
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
();
283
m_default_config_file
=
Utils::strenv
(
m_default_config_file
.c_str ());
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
309
Log::set_app_name
(
get_proc_name
());
310
311
if
(
m_log_stdout
==
"yes"
) {
312
Log::open_log_stdout
(
m_mask
);
313
}
314
else
{
315
if
(
m_with_log_server
==
"yes"
) {
316
Log::open_log_server
(
m_log_server
,
317
m_log_file
.c_str(),
318
get_reactor
(),
319
m_mask
,
320
m_log_size
) ;
321
}
322
else
{
323
Log::open_log_file
(
m_log_file
.c_str(),
m_mask
,
m_log_size
);
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"
,
337
m_pidfile_lock
.
get_error_msg
()));
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
356
bool
357
GenServer::
358
become_daemon
()
359
{
360
#if defined(WIN32)
361
return
true
;
362
#else
363
Fork
f (
Fork::LEAVE_ALONE
,
Fork::IGNORE_STATUS
);
364
365
if
(!f.
isChild
()) {
// parent exits
366
exit (0);
367
}
368
369
int
size = 1024;
370
int
i = 0;
371
pid_t nullfd;
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
407
int
408
GenServer::
409
handle_signal
(
int
signum_)
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
424
fatal_signal_hook
();
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
*/
438
get_reactor
()->
deactivate
();
439
m_graceful_quit
=
true
;
440
441
return
0;
442
}
443
Generated on Fri Apr 11 2014 13:12:32 for libassa by
1.8.1.2