47#include <libxml/xmlmemory.h>
48#include <libxml/parser.h>
51#include "ServerExitConditions.h"
52#include "TheBESKeys.h"
54#include "SocketListener.h"
56#include "UnixSocket.h"
57#include "BESServerHandler.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: " + std::to_string(getpid()) +
") caught SIGPIPE (master listener PID: "
181 + std::to_string(master_listener_pid) +
"). Child listener Exiting.");
190 signal(sig, SIG_DFL);
194 INFO_LOG(
"Master listener (PID: " + std::to_string(getpid()) +
") caught SIGPIPE.");
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);
266 bool needhelp =
false;
273 while ((c = getopt(argc, argv,
"hvsd:c:p:u:i:r:H:")) != -1) {
284 d_port = atoi(optarg);
292 d_unix_socket_value = optarg;
318 if (!dashc.empty()) {
325 if (dashc.empty() && !dashi.empty()) {
327 string conf_file = dashi +
"etc/bes/bes.conf";
343 string port_key =
"BES.ServerPort";
353 exit(SERVER_EXIT_FATAL_CANNOT_START);
356 d_port = atoi(sPort.c_str());
364 string ip_key =
"BES.ServerIP";
373 exit(SERVER_EXIT_FATAL_CANNOT_START);
382 string socket_key =
"BES.ServerUnixSocket";
383 if (d_unix_socket_value.empty()) {
391 exit(SERVER_EXIT_FATAL_CANNOT_START);
395 if (!d_got_port && d_unix_socket_value.empty()) {
396 string msg =
"Must specify a tcp port or a unix socket or both\n";
397 msg +=
"Please specify on the command line with -p <port>";
398 msg +=
" and/or -u <unix_socket>\n";
399 msg +=
"Or specify in the bes configuration file with " + port_key +
" and/or " + socket_key +
"\n";
407 string key =
"BES.ServerSecure";
416 exit(SERVER_EXIT_FATAL_CANNOT_START);
418 if (isSecure ==
"Yes" || isSecure ==
"YES" || isSecure ==
"yes") {
423 BESDEBUG(
"beslistener",
"beslistener: initializing default module ... " << endl);
424 BESDefaultModule::initialize(argc, argv);
425 BESDEBUG(
"beslistener",
"beslistener: done initializing default module" << endl);
427 BESDEBUG(
"beslistener",
"beslistener: initializing default commands ... " << endl);
429 BESDEBUG(
"beslistener",
"beslistener: done initializing default commands" << endl);
432 BESDEBUG(
"beslistener",
"beslistener: initializing loaded modules ... " << endl);
434 BESDEBUG(
"beslistener",
"beslistener: done initializing loaded modules" << endl);
436 BESDEBUG(
"beslistener",
"beslistener: initialized settings:" << *
this);
445 session_id = setsid();
446 BESDEBUG(
"beslistener",
"beslistener: The master beslistener session id (group id): " << session_id << endl);
448 master_listener_pid = getpid();
449 BESDEBUG(
"beslistener",
"beslistener: The master beslistener Process id: " << master_listener_pid << endl);
459 BESDEBUG(
"beslistener",
"beslistener: initializing memory pool ... " << endl);
460 BESDEBUG(
"beslistener",
"OK" << endl);
464 if (!d_ip_value.empty())
465 d_tcp_socket =
new TcpSocket(d_ip_value, d_port);
469 listener.listen(d_tcp_socket);
471 BESDEBUG(
"beslistener",
"beslistener: listening on port (" << d_port <<
")" << endl);
477 int status = BESLISTENER_RUNNING;
478 long res = write(MASTER_TO_DAEMON_PIPE_FD, &status,
sizeof(status));
481 ERROR_LOG(
"Master listener could not send status to daemon: " +
string(strerror(errno)));
482 ::exit(SERVER_EXIT_FATAL_CANNOT_START);
486 if (!d_unix_socket_value.empty()) {
487 d_unix_socket =
new UnixSocket(d_unix_socket_value);
488 listener.listen(d_unix_socket);
489 BESDEBUG(
"beslistener",
"beslistener: listening on unix socket (" << d_unix_socket_value <<
")" << endl);
494 d_ppt_server =
new PPTServer(&handler, &listener, d_is_secure);
496 register_signal_handlers();
510 if (sigterm | sighup | sigchild | sigpipe) {
513 while ((cpid = wait4(0 , &stat, WNOHANG, 0)) > 0) {
514 d_ppt_server->decr_num_children();
516 INFO_LOG(
"Master listener caught SISPIPE from child: " + std::to_string(cpid));
518 INFO_LOG(bes_exit_message(cpid, stat) +
"; num children: " + std::to_string(d_ppt_server->get_num_children()));
519 BESDEBUG(
"ppt2", bes_exit_message(cpid, stat) <<
"; num children: " << d_ppt_server->get_num_children() << endl);
524 BESDEBUG(
"ppt2",
"Master listener caught SIGHUP, exiting with SERVER_EXIT_RESTART");
525 INFO_LOG(
"Master listener caught SIGHUP, exiting with SERVER_EXIT_RESTART");
526 return SERVER_EXIT_RESTART;
530 BESDEBUG(
"ppt2",
"Master listener caught SIGTERM, exiting with SERVER_NORMAL_SHUTDOWN");
531 INFO_LOG(
"Master listener caught SIGTERM, exiting with SERVER_NORMAL_SHUTDOWN");
532 return SERVER_EXIT_NORMAL_SHUTDOWN;
543 d_ppt_server->initConnection();
547 BESDEBUG(
"beslistener",
"beslistener: caught BESError (" << se.
get_message() <<
")" << endl);
550 return SERVER_EXIT_FATAL_CANNOT_START;
553 ERROR_LOG(
"caught unknown exception initializing sockets");
554 return SERVER_EXIT_FATAL_CANNOT_START;
562 pid_t apppid = getpid();
564 if (apppid == d_pid) {
568 d_ppt_server->closeConnection();
572 d_tcp_socket->close();
576 d_unix_socket->close();
577 delete d_unix_socket;
585 BESDEBUG(
"beslistener",
"beslistener: terminating loaded modules ... " << endl);
587 BESDEBUG(
"beslistener",
"beslistener: done terminating loaded modules" << endl);
589 BESDEBUG(
"beslistener",
"beslistener: terminating default commands ... " << endl);
591 BESDEBUG(
"beslistener",
"beslistener: done terminating default commands ... " << endl);
593 BESDEBUG(
"beslistener",
"beslistener: terminating default module ... " << endl);
594 BESDefaultModule::terminate();
595 BESDEBUG(
"beslistener",
"beslistener: done terminating default module ... " << endl);
601 write(MASTER_TO_DAEMON_PIPE_FD, &status,
sizeof(status));
602 close(MASTER_TO_DAEMON_PIPE_FD);
616 strm << BESIndent::LMarg <<
"ServerApp::dump - (" << (
void *)
this <<
")" << endl;
618 strm << BESIndent::LMarg <<
"got IP? " << d_got_ip << endl;
619 strm << BESIndent::LMarg <<
"IP: " << d_ip_value << endl;
620 strm << BESIndent::LMarg <<
"got port? " << d_got_port << endl;
621 strm << BESIndent::LMarg <<
"port: " << d_port << endl;
622 strm << BESIndent::LMarg <<
"unix socket: " << d_unix_socket_value << endl;
623 strm << BESIndent::LMarg <<
"is secure? " << d_is_secure << endl;
624 strm << BESIndent::LMarg <<
"pid: " << d_pid << endl;
626 strm << BESIndent::LMarg <<
"tcp socket:" << endl;
628 d_tcp_socket->dump(strm);
629 BESIndent::UnIndent();
632 strm << BESIndent::LMarg <<
"tcp socket: null" << endl;
635 strm << BESIndent::LMarg <<
"unix socket:" << endl;
637 d_unix_socket->dump(strm);
638 BESIndent::UnIndent();
641 strm << BESIndent::LMarg <<
"unix socket: null" << endl;
644 strm << BESIndent::LMarg <<
"ppt server:" << endl;
646 d_ppt_server->dump(strm);
647 BESIndent::UnIndent();
650 strm << BESIndent::LMarg <<
"ppt server: null" << endl;
653 BESIndent::UnIndent();
656int main(
int argc,
char **argv)
660 return app.
main(argc, argv);
663 cerr <<
"Caught unhandled exception: " << endl;
667 catch (
const std::exception &e) {
668 cerr <<
"Caught unhandled standard exception: " << endl;
669 cerr << e.what() << endl;
673 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.
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
void get_value(const std::string &s, std::string &val, bool &found)
Retrieve the value of a given key, if set.
static TheBESKeys * TheKeys()
Access to the singleton.
static std::string ConfigFile