bes Updated for version 3.21.1
The Backend Server (BES) is the lower two tiers of the Hyrax data server
ServerApp.cc
1// ServerApp.cc
2
3// This file is part of bes, A C++ back-end server implementation framework
4// for the OPeNDAP Data Access Protocol.
5
6// Copyright (c) 2004-2009 University Corporation for Atmospheric Research
7// Author: Patrick West <pwest@ucar.edu> and Jose Garcia <jgarcia@ucar.edu>
8//
9// This library is free software; you can redistribute it and/or
10// modify it under the terms of the GNU Lesser General Public
11// License as published by the Free Software Foundation; either
12// version 2.1 of the License, or (at your option) any later version.
13//
14// This library is distributed in the hope that it will be useful,
15// but WITHOUT ANY WARRANTY; without even the implied warranty of
16// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17// Lesser General Public License for more details.
18//
19// You should have received a copy of the GNU Lesser General Public
20// License along with this library; if not, write to the Free Software
21// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
22//
23// You can contact University Corporation for Atmospheric Research at
24// 3080 Center Green Drive, Boulder, CO 80301
25
26// (c) COPYRIGHT University Corporation for Atmospheric Research 2004-2005
27// Please read the full copyright statement in the file COPYRIGHT_UCAR.
28//
29// Authors:
30// pwest Patrick West <pwest@ucar.edu>
31// jgarcia Jose Garcia <jgarcia@ucar.edu>
32
33#include "config.h"
34
35#include <unistd.h>
36#include <csignal>
37#include <sys/wait.h> // for wait
38
39#include <iostream>
40#include <exception>
41#include <sstream>
42
43#include <cstring>
44#include <cstdlib>
45#include <cerrno>
46
47#include <libxml/xmlmemory.h>
48#include <libxml/parser.h>
49
50#include "ServerApp.h"
51#include "ServerExitConditions.h"
52#include "TheBESKeys.h"
53#include "BESLog.h"
54#include "SocketListener.h"
55#include "TcpSocket.h"
56#include "UnixSocket.h"
57#include "BESServerHandler.h"
58#include "BESError.h"
59#include "PPTServer.h"
60#include "BESDebug.h"
61#include "BESCatalogUtils.h"
62#include "BESUtil.h"
63#include "BESServerUtils.h"
64#include "BESIndent.h"
65
66#include "BESDefaultModule.h"
67#include "BESXMLDefaultCommands.h"
68#include "BESDaemonConstants.h"
69
70using namespace std;
71
72static int session_id = 0;
73
74// These are set to 1 by their respective handlers and then processed in the
75// signal processing loop.
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;
80
81// Set in ServerApp::initialize().
82// Added jhrg 9/22/15
83static volatile int master_listener_pid = -1;
84
85#if 1
86static string bes_exit_message(int cpid, int stat)
87{
88 ostringstream oss;
89 oss << "beslistener child pid: " << cpid;
90 if (WIFEXITED(stat)) { // exited via exit()?
91 oss << " exited with status: " << WEXITSTATUS(stat);
92 }
93 else if (WIFSIGNALED(stat)) { // exited via a signal?
94 oss << " exited with signal: " << WTERMSIG(stat);
95#ifdef WCOREDUMP
96 if (WCOREDUMP(stat)) oss << " and a core dump!";
97#endif
98 }
99 else {
100 oss << " exited, but I have no clue as to why";
101 }
102
103 return oss.str();
104}
105#endif
106
107// These two functions duplicate code in daemon.cc
108static void block_signals()
109{
110 sigset_t set;
111 sigemptyset(&set);
112 sigaddset(&set, SIGCHLD);
113 sigaddset(&set, SIGHUP);
114 sigaddset(&set, SIGTERM);
115 sigaddset(&set, SIGPIPE);
116
117 if (sigprocmask(SIG_BLOCK, &set, nullptr) < 0) {
118 throw BESInternalError(string("sigprocmask error: ") + strerror(errno) + " while trying to block signals.",
119 __FILE__, __LINE__);
120 }
121}
122
123static void unblock_signals()
124{
125 sigset_t set;
126 sigemptyset(&set);
127 sigaddset(&set, SIGCHLD);
128 sigaddset(&set, SIGHUP);
129 sigaddset(&set, SIGTERM);
130 sigaddset(&set, SIGPIPE);
131
132 if (sigprocmask(SIG_UNBLOCK, &set, nullptr) < 0) {
133 throw BESInternalError(string("sigprocmask error: ") + strerror(errno) + " while trying to unblock signals.",
134 __FILE__, __LINE__);
135 }
136}
137
138// I moved the signal handlers here so that signal processing would be simpler
139// and no library calls would be made to functions that are not 'asynch safe'.
140// This was the fix for ticket 2025 and friends (the zombie process problem).
141// jhrg 3/3/14
142
143// This is needed so that the master bes listener will get the exit status of
144// all the child bes listeners (preventing them from becoming zombies).
145static void catch_sig_child(int sig)
146{
147 if (sig == SIGCHLD) {
148 sigchild = 1;
149 }
150}
151
152// If the HUP signal is sent to the master beslistener, it should exit and
153// return a value indicating to the besdaemon that it should be restarted.
154// This also has the side-affect of re-reading the configuration file.
155static void catch_sig_hup(int sig)
156{
157 if (sig == SIGHUP) {
158 sighup = 1;
159 }
160}
161
162static void catch_sig_pipe(int sig)
163{
164 if (sig == SIGPIPE) {
165 // When a child listener catches SIGPIPE it is because of a
166 // failure on one of its I/O connections - file I/O or, more
167 // likely, network I/O. I have found that C++ ostream objects
168 // seem to 'hide' sigpipe so that a child listener will run
169 // for some time after the client has dropped the
170 // connection. Whether this is from buffering or some other
171 // problem, the situation happens when either the remote
172 // client to exits (e.g., curl) or when Tomcat is stopped
173 // using SIGTERM. So, even though the normal behavior for a
174 // Unix daemon is to look at error codes from write(), etc.,
175 // and exit based on those, this code exits whenever the child
176 // listener catches SIGPIPE. However, if this is the Master
177 // listener, allow the processing loop to handle this signal
178 // and do not exit. jhrg 9/22/15
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.");
182
183 // cleanup code here; only the Master listener should run the code
184 // in ServerApp::terminate(); do nothing for cleanup for a child
185 // listener. jhrg 9/22/15
186
187 // Note that exit() is not safe for use in a signal
188 // handler, so we fall back to the default behavior, which
189 // is to exit.
190 signal(sig, SIG_DFL);
191 raise(sig);
192 }
193 else {
194 INFO_LOG("Master listener (PID: " + std::to_string(getpid()) + ") caught SIGPIPE.");
195
196 sigpipe = 1;
197 }
198 }
199}
200
201// This is the default signal sent by 'kill'; when the master beslistener gets
202// this signal it should stop. besdaemon should not try to start a new
203// master beslistener.
204static void catch_sig_term(int sig)
205{
206 if (sig == SIGTERM) {
207 sigterm = 1;
208 }
209}
210
219static void register_signal_handlers()
220{
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);
227 act.sa_flags = 0;
228#ifdef SA_RESTART
229 BESDEBUG("beslistener", "beslistener: setting restart for sigchld." << endl);
230 act.sa_flags |= SA_RESTART;
231#endif
232
233 BESDEBUG("beslistener", "beslistener: Registering signal handlers ... " << endl);
234
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__,
238 __LINE__);
239
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__,
243 __LINE__);
244
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__,
248 __LINE__);
249
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__,
253 __LINE__);
254
255 BESDEBUG("beslistener", "beslistener: OK" << endl);
256}
257
258ServerApp::ServerApp() : BESModuleApp()
259{
260 d_pid = getpid();
261}
262
263int ServerApp::initialize(int argc, char **argv)
264{
265 int c = 0;
266 bool needhelp = false;
267 string dashi;
268 string dashc;
269 string dashd;
270
271 // If you change the getopt statement below, be sure to make the
272 // corresponding change in daemon.cc and besctl.in
273 while ((c = getopt(argc, argv, "hvsd:c:p:u:i:r:H:")) != -1) {
274 switch (c) {
275 case 'i':
276 dashi = optarg;
277 break;
278 case 'c':
279 dashc = optarg;
280 break;
281 case 'r':
282 break; // we can ignore the /var/run directory option here
283 case 'p':
284 d_port = atoi(optarg);
285 d_got_port = true;
286 break;
287 case 'H':
288 d_ip_value = optarg;
289 d_got_ip = true;
290 break;
291 case 'u':
292 d_unix_socket_value = optarg;
293 break;
294 case 'd':
295 dashd = optarg;
296 break;
297 case 'v':
298 BESServerUtils::show_version(BESApp::TheApplication()->appName());
299 break;
300 case 's':
301 d_is_secure = true;
302 break;
303 case 'h':
304 case '?':
305 default:
306 needhelp = true;
307 break;
308 }
309 }
310
311 // before we can do any processing, log any messages, initialize any
312 // modules, do anything, we need to determine where the BES
313 // configuration file lives. From here we get the name of the log
314 // file, group and user id, and information that the modules will
315 // need to run properly.
316
317 // If the -c option was passed, set the config file name in TheBESKeys
318 if (!dashc.empty()) {
320 }
321
322 // If the -c option was not passed, but the -i option
323 // was passed, then use the -i option to construct
324 // the path to the config file
325 if (dashc.empty() && !dashi.empty()) {
327 string conf_file = dashi + "etc/bes/bes.conf";
328 TheBESKeys::ConfigFile = conf_file;
329 }
330
331 if (!dashd.empty()) BESDebug::SetUp(dashd);
332
333 // register the two debug context for the server and ppt. The
334 // Default Module will register the bes context.
335 BESDebug::Register("server");
336 BESDebug::Register("ppt");
337
338 // Because we are now running as the user specified in the
339 // configuration file, we won't be able to listen on system ports.
340 // If this is a problem, we may need to move this code above setting
341 // the user and group ids.
342 bool found = false;
343 string port_key = "BES.ServerPort";
344 if (!d_got_port) {
345 string sPort;
346 try {
347 TheBESKeys::TheKeys()->get_value(port_key, sPort, found);
348 }
349 catch (BESError &e) {
350 string err = string("FAILED: ") + e.get_message();
351 cerr << err << endl;
352 ERROR_LOG(err);
353 exit(SERVER_EXIT_FATAL_CANNOT_START);
354 }
355 if (found) {
356 d_port = atoi(sPort.c_str());
357 if (d_port != 0) {
358 d_got_port = true;
359 }
360 }
361 }
362
363 found = false;
364 string ip_key = "BES.ServerIP";
365 if (!d_got_ip) {
366 try {
367 TheBESKeys::TheKeys()->get_value(ip_key, d_ip_value, found);
368 }
369 catch (BESError &e) {
370 string err = string("FAILED: ") + e.get_message();
371 cerr << err << endl;
372 ERROR_LOG(err);
373 exit(SERVER_EXIT_FATAL_CANNOT_START);
374 }
375
376 if (found) {
377 d_got_ip = true;
378 }
379 }
380
381 found = false;
382 string socket_key = "BES.ServerUnixSocket";
383 if (d_unix_socket_value.empty()) {
384 try {
385 TheBESKeys::TheKeys()->get_value(socket_key, d_unix_socket_value, found);
386 }
387 catch (BESError &e) {
388 string err = string("FAILED: ") + e.get_message();
389 cerr << err << endl;
390 ERROR_LOG(err);
391 exit(SERVER_EXIT_FATAL_CANNOT_START);
392 }
393 }
394
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";
400 cout << endl << msg;
401 ERROR_LOG(msg);
402 BESServerUtils::show_usage(BESApp::TheApplication()->appName());
403 }
404
405 found = false;
406 if (!d_is_secure) {
407 string key = "BES.ServerSecure";
408 string isSecure;
409 try {
410 TheBESKeys::TheKeys()->get_value(key, isSecure, found);
411 }
412 catch (BESError &e) {
413 string err = string("FAILED: ") + e.get_message();
414 cerr << err << endl;
415 ERROR_LOG(err);
416 exit(SERVER_EXIT_FATAL_CANNOT_START);
417 }
418 if (isSecure == "Yes" || isSecure == "YES" || isSecure == "yes") {
419 d_is_secure = true;
420 }
421 }
422
423 BESDEBUG("beslistener", "beslistener: initializing default module ... " << endl);
424 BESDefaultModule::initialize(argc, argv);
425 BESDEBUG("beslistener", "beslistener: done initializing default module" << endl);
426
427 BESDEBUG("beslistener", "beslistener: initializing default commands ... " << endl);
429 BESDEBUG("beslistener", "beslistener: done initializing default commands" << endl);
430
431 // This will load and initialize all the modules
432 BESDEBUG("beslistener", "beslistener: initializing loaded modules ... " << endl);
433 int ret = BESModuleApp::initialize(argc, argv);
434 BESDEBUG("beslistener", "beslistener: done initializing loaded modules" << endl);
435
436 BESDEBUG("beslistener", "beslistener: initialized settings:" << *this);
437
438 if (needhelp) {
439 BESServerUtils::show_usage(BESApp::TheApplication()->appName());
440 }
441
442 // This sets the process group to be ID of this process. All children
443 // will get this GID. Then use killpg() to send a signal to this process
444 // and all the children.
445 session_id = setsid();
446 BESDEBUG("beslistener", "beslistener: The master beslistener session id (group id): " << session_id << endl);
447
448 master_listener_pid = getpid();
449 BESDEBUG("beslistener", "beslistener: The master beslistener Process id: " << master_listener_pid << endl);
450
451 return ret;
452}
453
454// NB: when this method returns, the return value is passed to the ServerApp::terminate()
455// method. Look at BESApp.cc to see how BESApp::main() is written.
457{
458 try {
459 BESDEBUG("beslistener", "beslistener: initializing memory pool ... " << endl);
460 BESDEBUG("beslistener", "OK" << endl);
461
462 SocketListener listener;
463 if (d_port) {
464 if (!d_ip_value.empty())
465 d_tcp_socket = new TcpSocket(d_ip_value, d_port);
466 else
467 d_tcp_socket = new TcpSocket(d_port);
468
469 listener.listen(d_tcp_socket);
470
471 BESDEBUG("beslistener", "beslistener: listening on port (" << d_port << ")" << endl);
472
473 // Write to stdout works because the besdaemon is listening on the
474 // other end of a pipe where the pipe fd[1] has been dup2'd to
475 // stdout. See daemon.cc:start_master_beslistener.
476 // NB MASTER_TO_DAEMON_PIPE_FD is 1 (stdout)
477 int status = BESLISTENER_RUNNING;
478 long res = write(MASTER_TO_DAEMON_PIPE_FD, &status, sizeof(status));
479
480 if (res == -1) {
481 ERROR_LOG("Master listener could not send status to daemon: " + string(strerror(errno)));
482 ::exit(SERVER_EXIT_FATAL_CANNOT_START);
483 }
484 }
485
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);
490 }
491
492 BESServerHandler handler;
493
494 d_ppt_server = new PPTServer(&handler, &listener, d_is_secure);
495
496 register_signal_handlers();
497
498 // Loop forever, processing signals and running the code in PPTServer::initConnection().
499 // NB: The code in initConnection() used to loop forever, but I moved that out to here
500 // so the signal handlers could be in this class. The PPTServer::initConnection() method
501 // is also used by daemon.cc but this class (ServerApp; the beslistener) and the besdaemon
502 // need to do different things for the signals like HUP and TERM, so they cannot share
503 // the signal processing code. One fix for the problem described in ticket 2025 was to
504 // move the signal handlers into PPTServer. Changing how the 'forever' loops are organized
505 // and keeping the signal processing code here (and in daemon.cc) is another solution that
506 // preserves the correct behavior of the besdaemon, too. jhrg 3/5/14
507 while (true) {
508 block_signals();
509
510 if (sigterm | sighup | sigchild | sigpipe) {
511 int stat;
512 pid_t cpid;
513 while ((cpid = wait4(0 /*any child in the process group*/, &stat, WNOHANG, 0/*no rusage*/)) > 0) {
514 d_ppt_server->decr_num_children();
515 if (sigpipe) {
516 INFO_LOG("Master listener caught SISPIPE from child: " + std::to_string(cpid));
517 }
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);
520 }
521 }
522
523 if (sighup) {
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;
527 }
528
529 if (sigterm) {
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;
533 }
534
535 sigchild = 0; // Only reset this signal, all others cause an exit/restart
536 unblock_signals();
537
538 // This is where the 'child listener' is started. This method will call
539 // BESServerHandler::handle(...) that will, in turn, fork. The child process
540 // becomes the 'child listener' that actually processes a request.
541 //
542 // This call blocks, using select(), until a client asks for another beslistener.
543 d_ppt_server->initConnection();
544 }
545 }
546 catch (BESError &se) {
547 BESDEBUG("beslistener", "beslistener: caught BESError (" << se.get_message() << ")" << endl);
548
549 ERROR_LOG(se.get_message());
550 return SERVER_EXIT_FATAL_CANNOT_START;
551 }
552 catch (...) {
553 ERROR_LOG("caught unknown exception initializing sockets");
554 return SERVER_EXIT_FATAL_CANNOT_START;
555 }
556}
557
558// The BESApp::main() method will call terminate() with the return value of
559// run(). The return value from terminate() is the return value the BESApp::main().
560int ServerApp::terminate(int status)
561{
562 pid_t apppid = getpid();
563 // is this the parent process - the master beslistener?
564 if (apppid == d_pid) {
565 // I don't understand the following comment. jhrg 3/23/22
566 // These are all safe to call in a signal handler
567 if (d_ppt_server) {
568 d_ppt_server->closeConnection();
569 delete d_ppt_server;
570 }
571 if (d_tcp_socket) {
572 d_tcp_socket->close();
573 delete d_tcp_socket;
574 }
575 if (d_unix_socket) {
576 d_unix_socket->close();
577 delete d_unix_socket;
578 }
579
580 // Do this in the reverse order that it was initialized. So
581 // terminate the loaded modules first, then the default
582 // commands, then the default module.
583
584 // These are not safe to call in a signal handler
585 BESDEBUG("beslistener", "beslistener: terminating loaded modules ... " << endl);
587 BESDEBUG("beslistener", "beslistener: done terminating loaded modules" << endl);
588
589 BESDEBUG("beslistener", "beslistener: terminating default commands ... " << endl);
591 BESDEBUG("beslistener", "beslistener: done terminating default commands ... " << endl);
592
593 BESDEBUG("beslistener", "beslistener: terminating default module ... " << endl);
594 BESDefaultModule::terminate();
595 BESDEBUG("beslistener", "beslistener: done terminating default module ... " << endl);
596
597 xmlCleanupParser();
598
599 // Only the master listener and the daemon know about this communication channel.
600 // Once we send the status back to the daemon, close the pipe.
601 write(MASTER_TO_DAEMON_PIPE_FD, &status, sizeof(status));
602 close(MASTER_TO_DAEMON_PIPE_FD);
603 }
604
605 return status;
606}
607
614void ServerApp::dump(ostream &strm) const
615{
616 strm << BESIndent::LMarg << "ServerApp::dump - (" << (void *) this << ")" << endl;
617 BESIndent::Indent();
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;
625 if (d_tcp_socket) {
626 strm << BESIndent::LMarg << "tcp socket:" << endl;
627 BESIndent::Indent();
628 d_tcp_socket->dump(strm);
629 BESIndent::UnIndent();
630 }
631 else {
632 strm << BESIndent::LMarg << "tcp socket: null" << endl;
633 }
634 if (d_unix_socket) {
635 strm << BESIndent::LMarg << "unix socket:" << endl;
636 BESIndent::Indent();
637 d_unix_socket->dump(strm);
638 BESIndent::UnIndent();
639 }
640 else {
641 strm << BESIndent::LMarg << "unix socket: null" << endl;
642 }
643 if (d_ppt_server) {
644 strm << BESIndent::LMarg << "ppt server:" << endl;
645 BESIndent::Indent();
646 d_ppt_server->dump(strm);
647 BESIndent::UnIndent();
648 }
649 else {
650 strm << BESIndent::LMarg << "ppt server: null" << endl;
651 }
652 BESModuleApp::dump(strm);
653 BESIndent::UnIndent();
654}
655
656int main(int argc, char **argv)
657{
658 try {
659 ServerApp app;
660 return app.main(argc, argv);
661 }
662 catch (BESError &e) {
663 cerr << "Caught unhandled exception: " << endl;
664 cerr << e.get_message() << endl;
665 return 1;
666 }
667 catch (const std::exception &e) {
668 cerr << "Caught unhandled standard exception: " << endl;
669 cerr << e.what() << endl;
670 return 1;
671 }
672 catch (...) {
673 cerr << "Caught unhandled, unknown exception" << endl;
674 return 1;
675 }
676}
std::string appName() const
Returns the name of the application.
Definition BESApp.h:130
static BESApp * TheApplication()
Returns the BESApp application object for this application.
Definition BESApp.h:139
virtual int main(int argC, char **argV)
main routine, the main entry point for any BES applications.
Definition BESApp.cc:52
static void SetUp(const std::string &values)
Sets up debugging for the bes.
Definition BESDebug.cc:91
static void Register(const std::string &flagName)
register the specified debug flag
Definition BESDebug.h:126
Base exception class for the BES with basic string message.
Definition BESError.h:66
std::string get_message() const
get the error message for this exception
Definition BESError.h:132
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)....
Definition BESUtil.cc:113
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.
Definition ServerApp.cc:263
int run() override
The body of the application, implementing the primary functionality of the BES application.
Definition ServerApp.cc:456
void dump(std::ostream &strm) const override
dumps information about this object
Definition ServerApp.cc:614
int terminate(int status=0) override
clean up after the application
Definition ServerApp.cc:560
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.
Definition TheBESKeys.cc:85
static std::string ConfigFile
Definition TheBESKeys.h:117