47#include <libxml/xmlmemory.h>
50#include "ServerExitConditions.h"
51#include "TheBESKeys.h"
53#include "SocketListener.h"
55#include "UnixSocket.h"
56#include "BESServerHandler.h"
59#include "BESMemoryManager.h"
61#include "BESCatalogUtils.h"
63#include "BESServerUtils.h"
66#include "BESDefaultModule.h"
67#include "BESXMLDefaultCommands.h"
68#include "BESDaemonConstants.h"
72static int session_id = 0;
76static volatile sig_atomic_t sigchild = 0;
77static volatile sig_atomic_t sigpipe = 0;
78static volatile sig_atomic_t sigterm = 0;
79static volatile sig_atomic_t sighup = 0;
83static volatile int master_listener_pid = -1;
86static string bes_exit_message(
int cpid,
int stat)
89 oss <<
"beslistener child pid: " << cpid;
90 if (WIFEXITED(stat)) {
91 oss <<
" exited with status: " << WEXITSTATUS(stat);
93 else if (WIFSIGNALED(stat)) {
94 oss <<
" exited with signal: " << WTERMSIG(stat);
96 if (WCOREDUMP(stat)) oss <<
" and a core dump!";
100 oss <<
" exited, but I have no clue as to why";
108static void block_signals()
112 sigaddset(&set, SIGCHLD);
113 sigaddset(&set, SIGHUP);
114 sigaddset(&set, SIGTERM);
115 sigaddset(&set, SIGPIPE);
117 if (sigprocmask(SIG_BLOCK, &set,
nullptr) < 0) {
118 throw BESInternalError(
string(
"sigprocmask error: ") + strerror(errno) +
" while trying to block signals.",
123static void unblock_signals()
127 sigaddset(&set, SIGCHLD);
128 sigaddset(&set, SIGHUP);
129 sigaddset(&set, SIGTERM);
130 sigaddset(&set, SIGPIPE);
132 if (sigprocmask(SIG_UNBLOCK, &set,
nullptr) < 0) {
133 throw BESInternalError(
string(
"sigprocmask error: ") + strerror(errno) +
" while trying to unblock signals.",
145static void catch_sig_child(
int sig)
147 if (sig == SIGCHLD) {
155static void catch_sig_hup(
int sig)
162static void catch_sig_pipe(
int sig)
164 if (sig == SIGPIPE) {
179 if (getpid() != master_listener_pid) {
180 INFO_LOG(
"Child listener (PID: " << getpid() <<
") caught SIGPIPE (master listener PID: "
181 << master_listener_pid <<
"). Child listener Exiting." << endl);
190 signal(sig, SIG_DFL);
194 INFO_LOG(
"Master listener (PID: " << getpid() <<
") caught SIGPIPE." << endl);
204static void catch_sig_term(
int sig)
206 if (sig == SIGTERM) {
219static void register_signal_handlers()
221 struct sigaction act;
222 sigemptyset(&act.sa_mask);
223 sigaddset(&act.sa_mask, SIGCHLD);
224 sigaddset(&act.sa_mask, SIGPIPE);
225 sigaddset(&act.sa_mask, SIGTERM);
226 sigaddset(&act.sa_mask, SIGHUP);
229 BESDEBUG(
"beslistener",
"beslistener: setting restart for sigchld." << endl);
230 act.sa_flags |= SA_RESTART;
233 BESDEBUG(
"beslistener",
"beslistener: Registering signal handlers ... " << endl);
235 act.sa_handler = catch_sig_child;
236 if (sigaction(SIGCHLD, &act, 0))
237 throw BESInternalFatalError(
"Could not register a handler to catch beslistener child process status.", __FILE__,
240 act.sa_handler = catch_sig_pipe;
241 if (sigaction(SIGPIPE, &act, 0) < 0)
242 throw BESInternalFatalError(
"Could not register a handler to catch beslistener pipe signal.", __FILE__,
245 act.sa_handler = catch_sig_term;
246 if (sigaction(SIGTERM, &act, 0) < 0)
247 throw BESInternalFatalError(
"Could not register a handler to catch beslistener terminate signal.", __FILE__,
250 act.sa_handler = catch_sig_hup;
251 if (sigaction(SIGHUP, &act, 0) < 0)
252 throw BESInternalFatalError(
"Could not register a handler to catch beslistener hup signal.", __FILE__,
255 BESDEBUG(
"beslistener",
"beslistener: OK" << endl);
263ServerApp::~ServerApp()
271 bool needhelp =
false;
278 while ((c = getopt(argc, argv,
"hvsd:c:p:u:i:r:H:")) != -1) {
289 d_port = atoi(optarg);
297 d_unix_socket_value = optarg;
323 if (!dashc.empty()) {
330 if (dashc.empty() && !dashi.empty()) {
332 string conf_file = dashi +
"etc/bes/bes.conf";
348 string port_key =
"BES.ServerPort";
357 ERROR_LOG(err << endl);
358 exit(SERVER_EXIT_FATAL_CANNOT_START);
361 d_port = atoi(sPort.c_str());
369 string ip_key =
"BES.ServerIP";
377 ERROR_LOG(err << endl);
378 exit(SERVER_EXIT_FATAL_CANNOT_START);
387 string socket_key =
"BES.ServerUnixSocket";
388 if (d_unix_socket_value.empty()) {
395 ERROR_LOG(err << endl);
396 exit(SERVER_EXIT_FATAL_CANNOT_START);
400 if (!d_got_port && d_unix_socket_value.empty()) {
401 string msg =
"Must specify a tcp port or a unix socket or both\n";
402 msg +=
"Please specify on the command line with -p <port>";
403 msg +=
" and/or -u <unix_socket>\n";
404 msg +=
"Or specify in the bes configuration file with " + port_key +
" and/or " + socket_key +
"\n";
406 ERROR_LOG(msg << endl);
412 string key =
"BES.ServerSecure";
420 ERROR_LOG(err << endl);
421 exit(SERVER_EXIT_FATAL_CANNOT_START);
423 if (isSecure ==
"Yes" || isSecure ==
"YES" || isSecure ==
"yes") {
428 BESDEBUG(
"beslistener",
"beslistener: initializing default module ... " << endl);
429 BESDefaultModule::initialize(argc, argv);
430 BESDEBUG(
"beslistener",
"beslistener: done initializing default module" << endl);
432 BESDEBUG(
"beslistener",
"beslistener: initializing default commands ... " << endl);
434 BESDEBUG(
"beslistener",
"beslistener: done initializing default commands" << endl);
437 BESDEBUG(
"beslistener",
"beslistener: initializing loaded modules ... " << endl);
439 BESDEBUG(
"beslistener",
"beslistener: done initializing loaded modules" << endl);
441 BESDEBUG(
"beslistener",
"beslistener: initialized settings:" << *
this);
450 session_id = setsid();
451 BESDEBUG(
"beslistener",
"beslistener: The master beslistener session id (group id): " << session_id << endl);
453 master_listener_pid = getpid();
454 BESDEBUG(
"beslistener",
"beslistener: The master beslistener Process id: " << master_listener_pid << endl);
464 BESDEBUG(
"beslistener",
"beslistener: initializing memory pool ... " << endl);
465 BESMemoryManager::initialize_memory_pool();
466 BESDEBUG(
"beslistener",
"OK" << endl);
470 if (!d_ip_value.empty())
471 d_tcp_socket =
new TcpSocket(d_ip_value, d_port);
475 listener.listen(d_tcp_socket);
477 BESDEBUG(
"beslistener",
"beslistener: listening on port (" << d_port <<
")" << endl);
483 int status = BESLISTENER_RUNNING;
484 long res = write(MASTER_TO_DAEMON_PIPE_FD, &status,
sizeof(status));
487 ERROR_LOG(
"Master listener could not send status to daemon: " << strerror(errno) << endl);
488 ::exit(SERVER_EXIT_FATAL_CANNOT_START);
492 if (!d_unix_socket_value.empty()) {
493 d_unix_socket =
new UnixSocket(d_unix_socket_value);
494 listener.listen(d_unix_socket);
495 BESDEBUG(
"beslistener",
"beslistener: listening on unix socket (" << d_unix_socket_value <<
")" << endl);
500 d_ppt_server =
new PPTServer(&handler, &listener, d_is_secure);
502 register_signal_handlers();
516 if (sigterm | sighup | sigchild | sigpipe) {
519 while ((cpid = wait4(0 , &stat, WNOHANG, 0)) > 0) {
520 d_ppt_server->decr_num_children();
522 INFO_LOG(
"Master listener caught SISPIPE from child: " << cpid << endl);
524 INFO_LOG(bes_exit_message(cpid, stat) <<
"; num children: " << d_ppt_server->get_num_children() << endl);
525 BESDEBUG(
"ppt2", bes_exit_message(cpid, stat) <<
"; num children: " << d_ppt_server->get_num_children() << endl);
530 BESDEBUG(
"ppt2",
"Master listener caught SIGHUP, exiting with SERVER_EXIT_RESTART" << endl);
532 INFO_LOG(
"Master listener caught SIGHUP, exiting with SERVER_EXIT_RESTART" << endl);
535 d_ppt_server->closeConnection();
536 close(BESLISTENER_PIPE_FD);
538 return SERVER_EXIT_RESTART;
540 ::exit(SERVER_EXIT_RESTART);
545 BESDEBUG(
"ppt2",
"Master listener caught SIGTERM, exiting with SERVER_NORMAL_SHUTDOWN" << endl);
547 INFO_LOG(
"Master listener caught SIGTERM, exiting with SERVER_NORMAL_SHUTDOWN" << endl);
550 d_ppt_server->closeConnection();
551 close(BESLISTENER_PIPE_FD);
553 return SERVER_EXIT_NORMAL_SHUTDOWN;
555 ::exit(SERVER_EXIT_NORMAL_SHUTDOWN);
570 d_ppt_server->closeConnection();
574 BESDEBUG(
"beslistener",
"beslistener: caught BESError (" << se.
get_message() <<
")" << endl);
578 int status = SERVER_EXIT_FATAL_CANNOT_START;
579 write(MASTER_TO_DAEMON_PIPE_FD, &status,
sizeof(status));
580 close(MASTER_TO_DAEMON_PIPE_FD);
582 return SERVER_EXIT_FATAL_CANNOT_START;
585 ERROR_LOG(
"caught unknown exception initializing sockets" << endl);
587 int status = SERVER_EXIT_FATAL_CANNOT_START;
588 write(MASTER_TO_DAEMON_PIPE_FD, &status,
sizeof(status));
589 close(MASTER_TO_DAEMON_PIPE_FD);
591 return SERVER_EXIT_FATAL_CANNOT_START;
595 close(BESLISTENER_PIPE_FD);
604 pid_t apppid = getpid();
606 if (apppid == d_pid) {
610 d_ppt_server->closeConnection();
614 d_tcp_socket->close();
618 d_unix_socket->close();
619 delete d_unix_socket;
627 BESDEBUG(
"beslistener",
"beslistener: terminating loaded modules ... " << endl);
629 BESDEBUG(
"beslistener",
"beslistener: done terminating loaded modules" << endl);
631 BESDEBUG(
"beslistener",
"beslistener: terminating default commands ... " << endl);
633 BESDEBUG(
"beslistener",
"beslistener: done terminating default commands ... " << endl);
635 BESDEBUG(
"beslistener",
"beslistener: terminating default module ... " << endl);
636 BESDefaultModule::terminate();
637 BESDEBUG(
"beslistener",
"beslistener: done terminating default module ... " << endl);
643 write(MASTER_TO_DAEMON_PIPE_FD, &status,
sizeof(status));
644 close(MASTER_TO_DAEMON_PIPE_FD);
658 strm << BESIndent::LMarg <<
"ServerApp::dump - (" << (
void *)
this <<
")" << endl;
660 strm << BESIndent::LMarg <<
"got IP? " << d_got_ip << endl;
661 strm << BESIndent::LMarg <<
"IP: " << d_ip_value << endl;
662 strm << BESIndent::LMarg <<
"got port? " << d_got_port << endl;
663 strm << BESIndent::LMarg <<
"port: " << d_port << endl;
664 strm << BESIndent::LMarg <<
"unix socket: " << d_unix_socket_value << endl;
665 strm << BESIndent::LMarg <<
"is secure? " << d_is_secure << endl;
666 strm << BESIndent::LMarg <<
"pid: " << d_pid << endl;
668 strm << BESIndent::LMarg <<
"tcp socket:" << endl;
670 d_tcp_socket->
dump(strm);
671 BESIndent::UnIndent();
674 strm << BESIndent::LMarg <<
"tcp socket: null" << endl;
677 strm << BESIndent::LMarg <<
"unix socket:" << endl;
679 d_unix_socket->
dump(strm);
680 BESIndent::UnIndent();
683 strm << BESIndent::LMarg <<
"unix socket: null" << endl;
686 strm << BESIndent::LMarg <<
"ppt server:" << endl;
688 d_ppt_server->
dump(strm);
689 BESIndent::UnIndent();
692 strm << BESIndent::LMarg <<
"ppt server: null" << endl;
695 BESIndent::UnIndent();
698int main(
int argc,
char **argv)
702 return app.
main(argc, argv);
705 cerr <<
"Caught unhandled exception: " << endl;
709 catch (
const std::exception &e) {
710 cerr <<
"Caught unhandled standard exception: " << endl;
711 cerr << e.what() << endl;
715 cerr <<
"Caught unhandled, unknown exception" << endl;
std::string appName() const
Returns the name of the application.
static BESApp * TheApplication()
Returns the BESApp application object for this application.
virtual int main(int argC, char **argV)
main routine, the main entry point for any BES applications.
static void SetUp(const std::string &values)
Sets up debugging for the bes.
static void Register(const std::string &flagName)
register the specified debug flag
Base exception class for the BES with basic string message.
std::string get_message() const
get the error message for this exception
exception thrown if internal error encountered
exception thrown if an internal error is found and is fatal to the BES
Base application object for all BES applications.
int terminate(int sig=0) override
clean up after the application
int initialize(int argC, char **argV) override
Load and initialize any BES modules.
void dump(std::ostream &strm) const override
dumps information about this object
static void trim_if_trailing_slash(std::string &value)
If the string ends in a slash, remove it This function works for empty strings (doing nothing)....
static int terminate(void)
Removes the default set of BES XML commands from the list of possible commands.
static int initialize(int argc, char **argv)
Loads the default set of BES XML commands.
void initConnection() override
void dump(std::ostream &strm) const override
dumps information about this object
int initialize(int argC, char **argV) override
Load and initialize any BES modules.
int run() override
The body of the application, implementing the primary functionality of the BES application.
void dump(std::ostream &strm) const override
dumps information about this object
int terminate(int status=0) override
clean up after the application
virtual void dump(std::ostream &strm) const
dumps information about this object
void get_value(const std::string &s, std::string &val, bool &found)
Retrieve the value of a given key, if set.
static TheBESKeys * TheKeys()
static std::string ConfigFile
virtual void dump(std::ostream &strm) const
dumps information about this object