bes Updated for version 3.20.13
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
49#include "ServerApp.h"
50#include "ServerExitConditions.h"
51#include "TheBESKeys.h"
52#include "BESLog.h"
53#include "SocketListener.h"
54#include "TcpSocket.h"
55#include "UnixSocket.h"
56#include "BESServerHandler.h"
57#include "BESError.h"
58#include "PPTServer.h"
59#include "BESMemoryManager.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: " << getpid() << ") caught SIGPIPE (master listener PID: "
181 << master_listener_pid << "). Child listener Exiting." << endl);
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: " << getpid() << ") caught SIGPIPE." << endl);
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
263ServerApp::~ServerApp()
264{
265 delete TheBESKeys::TheKeys();
266}
267
268int ServerApp::initialize(int argc, char **argv)
269{
270 int c = 0;
271 bool needhelp = false;
272 string dashi;
273 string dashc;
274 string dashd;
275
276 // If you change the getopt statement below, be sure to make the
277 // corresponding change in daemon.cc and besctl.in
278 while ((c = getopt(argc, argv, "hvsd:c:p:u:i:r:H:")) != -1) {
279 switch (c) {
280 case 'i':
281 dashi = optarg;
282 break;
283 case 'c':
284 dashc = optarg;
285 break;
286 case 'r':
287 break; // we can ignore the /var/run directory option here
288 case 'p':
289 d_port = atoi(optarg);
290 d_got_port = true;
291 break;
292 case 'H':
293 d_ip_value = optarg;
294 d_got_ip = true;
295 break;
296 case 'u':
297 d_unix_socket_value = optarg;
298 break;
299 case 'd':
300 dashd = optarg;
301 break;
302 case 'v':
303 BESServerUtils::show_version(BESApp::TheApplication()->appName());
304 break;
305 case 's':
306 d_is_secure = true;
307 break;
308 case 'h':
309 case '?':
310 default:
311 needhelp = true;
312 break;
313 }
314 }
315
316 // before we can do any processing, log any messages, initialize any
317 // modules, do anything, we need to determine where the BES
318 // configuration file lives. From here we get the name of the log
319 // file, group and user id, and information that the modules will
320 // need to run properly.
321
322 // If the -c option was passed, set the config file name in TheBESKeys
323 if (!dashc.empty()) {
325 }
326
327 // If the -c option was not passed, but the -i option
328 // was passed, then use the -i option to construct
329 // the path to the config file
330 if (dashc.empty() && !dashi.empty()) {
332 string conf_file = dashi + "etc/bes/bes.conf";
333 TheBESKeys::ConfigFile = conf_file;
334 }
335
336 if (!dashd.empty()) BESDebug::SetUp(dashd);
337
338 // register the two debug context for the server and ppt. The
339 // Default Module will register the bes context.
340 BESDebug::Register("server");
341 BESDebug::Register("ppt");
342
343 // Because we are now running as the user specified in the
344 // configuration file, we won't be able to listen on system ports.
345 // If this is a problem, we may need to move this code above setting
346 // the user and group ids.
347 bool found = false;
348 string port_key = "BES.ServerPort";
349 if (!d_got_port) {
350 string sPort;
351 try {
352 TheBESKeys::TheKeys()->get_value(port_key, sPort, found);
353 }
354 catch (BESError &e) {
355 string err = string("FAILED: ") + e.get_message();
356 cerr << err << endl;
357 ERROR_LOG(err << endl);
358 exit(SERVER_EXIT_FATAL_CANNOT_START);
359 }
360 if (found) {
361 d_port = atoi(sPort.c_str());
362 if (d_port != 0) {
363 d_got_port = true;
364 }
365 }
366 }
367
368 found = false;
369 string ip_key = "BES.ServerIP";
370 if (!d_got_ip) {
371 try {
372 TheBESKeys::TheKeys()->get_value(ip_key, d_ip_value, found);
373 }
374 catch (BESError &e) {
375 string err = string("FAILED: ") + e.get_message();
376 cerr << err << endl;
377 ERROR_LOG(err << endl);
378 exit(SERVER_EXIT_FATAL_CANNOT_START);
379 }
380
381 if (found) {
382 d_got_ip = true;
383 }
384 }
385
386 found = false;
387 string socket_key = "BES.ServerUnixSocket";
388 if (d_unix_socket_value.empty()) {
389 try {
390 TheBESKeys::TheKeys()->get_value(socket_key, d_unix_socket_value, found);
391 }
392 catch (BESError &e) {
393 string err = string("FAILED: ") + e.get_message();
394 cerr << err << endl;
395 ERROR_LOG(err << endl);
396 exit(SERVER_EXIT_FATAL_CANNOT_START);
397 }
398 }
399
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";
405 cout << endl << msg;
406 ERROR_LOG(msg << endl);
407 BESServerUtils::show_usage(BESApp::TheApplication()->appName());
408 }
409
410 found = false;
411 if (!d_is_secure) {
412 string key = "BES.ServerSecure";
413 string isSecure;
414 try {
415 TheBESKeys::TheKeys()->get_value(key, isSecure, found);
416 }
417 catch (BESError &e) {
418 string err = string("FAILED: ") + e.get_message();
419 cerr << err << endl;
420 ERROR_LOG(err << endl);
421 exit(SERVER_EXIT_FATAL_CANNOT_START);
422 }
423 if (isSecure == "Yes" || isSecure == "YES" || isSecure == "yes") {
424 d_is_secure = true;
425 }
426 }
427
428 BESDEBUG("beslistener", "beslistener: initializing default module ... " << endl);
429 BESDefaultModule::initialize(argc, argv);
430 BESDEBUG("beslistener", "beslistener: done initializing default module" << endl);
431
432 BESDEBUG("beslistener", "beslistener: initializing default commands ... " << endl);
434 BESDEBUG("beslistener", "beslistener: done initializing default commands" << endl);
435
436 // This will load and initialize all the modules
437 BESDEBUG("beslistener", "beslistener: initializing loaded modules ... " << endl);
438 int ret = BESModuleApp::initialize(argc, argv);
439 BESDEBUG("beslistener", "beslistener: done initializing loaded modules" << endl);
440
441 BESDEBUG("beslistener", "beslistener: initialized settings:" << *this);
442
443 if (needhelp) {
444 BESServerUtils::show_usage(BESApp::TheApplication()->appName());
445 }
446
447 // This sets the process group to be ID of this process. All children
448 // will get this GID. Then use killpg() to send a signal to this process
449 // and all the children.
450 session_id = setsid();
451 BESDEBUG("beslistener", "beslistener: The master beslistener session id (group id): " << session_id << endl);
452
453 master_listener_pid = getpid();
454 BESDEBUG("beslistener", "beslistener: The master beslistener Process id: " << master_listener_pid << endl);
455
456 return ret;
457}
458
459// NB: when this method returns, the return value is passed to the ServerApp::terminate()
460// method. Look at BESApp.cc to see how BESApp::main() is written.
462{
463 try {
464 BESDEBUG("beslistener", "beslistener: initializing memory pool ... " << endl);
465 BESMemoryManager::initialize_memory_pool();
466 BESDEBUG("beslistener", "OK" << endl);
467
468 SocketListener listener;
469 if (d_port) {
470 if (!d_ip_value.empty())
471 d_tcp_socket = new TcpSocket(d_ip_value, d_port);
472 else
473 d_tcp_socket = new TcpSocket(d_port);
474
475 listener.listen(d_tcp_socket);
476
477 BESDEBUG("beslistener", "beslistener: listening on port (" << d_port << ")" << endl);
478
479 // Write to stdout works because the besdaemon is listening on the
480 // other end of a pipe where the pipe fd[1] has been dup2'd to
481 // stdout. See daemon.cc:start_master_beslistener.
482 // NB MASTER_TO_DAEMON_PIPE_FD is 1 (stdout)
483 int status = BESLISTENER_RUNNING;
484 long res = write(MASTER_TO_DAEMON_PIPE_FD, &status, sizeof(status));
485
486 if (res == -1) {
487 ERROR_LOG("Master listener could not send status to daemon: " << strerror(errno) << endl);
488 ::exit(SERVER_EXIT_FATAL_CANNOT_START);
489 }
490 }
491
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);
496 }
497
498 BESServerHandler handler;
499
500 d_ppt_server = new PPTServer(&handler, &listener, d_is_secure);
501
502 register_signal_handlers();
503
504 // Loop forever, processing signals and running the code in PPTServer::initConnection().
505 // NB: The code in initConnection() used to loop forever, but I moved that out to here
506 // so the signal handlers could be in this class. The PPTServer::initConnection() method
507 // is also used by daemon.cc but this class (ServerApp; the beslistener) and the besdaemon
508 // need to do different things for the signals like HUP and TERM, so they cannot share
509 // the signal processing code. One fix for the problem described in ticket 2025 was to
510 // move the signal handlers into PPTServer. Changing how the 'forever' loops are organized
511 // and keeping the signal processing code here (and in daemon.cc) is another solution that
512 // preserves the correct behavior of the besdaemon, too. jhrg 3/5/14
513 while (true) {
514 block_signals();
515
516 if (sigterm | sighup | sigchild | sigpipe) {
517 int stat;
518 pid_t cpid;
519 while ((cpid = wait4(0 /*any child in the process group*/, &stat, WNOHANG, 0/*no rusage*/)) > 0) {
520 d_ppt_server->decr_num_children();
521 if (sigpipe) {
522 INFO_LOG("Master listener caught SISPIPE from child: " << cpid << endl);
523 }
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);
526 }
527 }
528
529 if (sighup) {
530 BESDEBUG("ppt2", "Master listener caught SIGHUP, exiting with SERVER_EXIT_RESTART" << endl);
531
532 INFO_LOG("Master listener caught SIGHUP, exiting with SERVER_EXIT_RESTART" << endl);
533
534#if 0
535 d_ppt_server->closeConnection();
536 close(BESLISTENER_PIPE_FD);
537#endif
538 return SERVER_EXIT_RESTART;
539#if 0
540 ::exit(SERVER_EXIT_RESTART);
541#endif
542 }
543
544 if (sigterm) {
545 BESDEBUG("ppt2", "Master listener caught SIGTERM, exiting with SERVER_NORMAL_SHUTDOWN" << endl);
546
547 INFO_LOG("Master listener caught SIGTERM, exiting with SERVER_NORMAL_SHUTDOWN" << endl);
548
549#if 0
550 d_ppt_server->closeConnection();
551 close(BESLISTENER_PIPE_FD);
552#endif
553 return SERVER_EXIT_NORMAL_SHUTDOWN;
554#if 0
555 ::exit(SERVER_EXIT_NORMAL_SHUTDOWN);
556#endif
557 }
558
559 sigchild = 0; // Only reset this signal, all others cause an exit/restart
560 unblock_signals();
561
562 // This is where the 'child listener' is started. This method will call
563 // BESServerHandler::handle(...) that will, in turn, fork. The child process
564 // becomes the 'child listener' that actually processes a request.
565 //
566 // This call blocks, using select(), until a client asks for another beslistener.
567 d_ppt_server->initConnection();
568 }
569#if 0
570 d_ppt_server->closeConnection();
571#endif
572 }
573 catch (BESError &se) {
574 BESDEBUG("beslistener", "beslistener: caught BESError (" << se.get_message() << ")" << endl);
575
576 ERROR_LOG(se.get_message() << endl);
577#if 0
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);
581#endif
582 return SERVER_EXIT_FATAL_CANNOT_START;
583 }
584 catch (...) {
585 ERROR_LOG("caught unknown exception initializing sockets" << endl);
586#if 0
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);
590#endif
591 return SERVER_EXIT_FATAL_CANNOT_START;
592 }
593
594#if 0
595 close(BESLISTENER_PIPE_FD);
596 return 0;
597#endif
598}
599
600// The BESApp::main() method will call terminate() with the return value of
601// run(). The return value from terminate() is the return value the BESApp::main().
602int ServerApp::terminate(int status)
603{
604 pid_t apppid = getpid();
605 // is this the parent process - the master beslistener?
606 if (apppid == d_pid) {
607 // I don't understand the following comment. jhrg 3/23/22
608 // These are all safe to call in a signal handler
609 if (d_ppt_server) {
610 d_ppt_server->closeConnection();
611 delete d_ppt_server;
612 }
613 if (d_tcp_socket) {
614 d_tcp_socket->close();
615 delete d_tcp_socket;
616 }
617 if (d_unix_socket) {
618 d_unix_socket->close();
619 delete d_unix_socket;
620 }
621
622 // Do this in the reverse order that it was initialized. So
623 // terminate the loaded modules first, then the default
624 // commands, then the default module.
625
626 // These are not safe to call in a signal handler
627 BESDEBUG("beslistener", "beslistener: terminating loaded modules ... " << endl);
629 BESDEBUG("beslistener", "beslistener: done terminating loaded modules" << endl);
630
631 BESDEBUG("beslistener", "beslistener: terminating default commands ... " << endl);
633 BESDEBUG("beslistener", "beslistener: done terminating default commands ... " << endl);
634
635 BESDEBUG("beslistener", "beslistener: terminating default module ... " << endl);
636 BESDefaultModule::terminate();
637 BESDEBUG("beslistener", "beslistener: done terminating default module ... " << endl);
638
639 xmlCleanupParser();
640
641 // Only the master listener and the daemon know about this communication channel.
642 // Once we send the status back to the daemon, close the pipe.
643 write(MASTER_TO_DAEMON_PIPE_FD, &status, sizeof(status));
644 close(MASTER_TO_DAEMON_PIPE_FD);
645 }
646
647 return status;
648}
649
656void ServerApp::dump(ostream &strm) const
657{
658 strm << BESIndent::LMarg << "ServerApp::dump - (" << (void *) this << ")" << endl;
659 BESIndent::Indent();
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;
667 if (d_tcp_socket) {
668 strm << BESIndent::LMarg << "tcp socket:" << endl;
669 BESIndent::Indent();
670 d_tcp_socket->dump(strm);
671 BESIndent::UnIndent();
672 }
673 else {
674 strm << BESIndent::LMarg << "tcp socket: null" << endl;
675 }
676 if (d_unix_socket) {
677 strm << BESIndent::LMarg << "unix socket:" << endl;
678 BESIndent::Indent();
679 d_unix_socket->dump(strm);
680 BESIndent::UnIndent();
681 }
682 else {
683 strm << BESIndent::LMarg << "unix socket: null" << endl;
684 }
685 if (d_ppt_server) {
686 strm << BESIndent::LMarg << "ppt server:" << endl;
687 BESIndent::Indent();
688 d_ppt_server->dump(strm);
689 BESIndent::UnIndent();
690 }
691 else {
692 strm << BESIndent::LMarg << "ppt server: null" << endl;
693 }
694 BESModuleApp::dump(strm);
695 BESIndent::UnIndent();
696}
697
698int main(int argc, char **argv)
699{
700 try {
701 ServerApp app;
702 return app.main(argc, argv);
703 }
704 catch (BESError &e) {
705 cerr << "Caught unhandled exception: " << endl;
706 cerr << e.get_message() << endl;
707 return 1;
708 }
709 catch (const std::exception &e) {
710 cerr << "Caught unhandled standard exception: " << endl;
711 cerr << e.what() << endl;
712 return 1;
713 }
714 catch (...) {
715 cerr << "Caught unhandled, unknown exception" << endl;
716 return 1;
717 }
718}
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:98
static void Register(const std::string &flagName)
register the specified debug flag
Definition: BESDebug.h:149
Base exception class for the BES with basic string message.
Definition: BESError.h:59
std::string get_message() const
get the error message for this exception
Definition: BESError.h:111
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.
Definition: BESModuleApp.h:55
int terminate(int sig=0) override
clean up after the application
int initialize(int argC, char **argV) override
Load and initialize any BES modules.
Definition: BESModuleApp.cc:71
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:110
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
Definition: PPTServer.cc:140
void dump(std::ostream &strm) const override
dumps information about this object
Definition: PPTServer.cc:278
int initialize(int argC, char **argV) override
Load and initialize any BES modules.
Definition: ServerApp.cc:268
int run() override
The body of the application, implementing the primary functionality of the BES application.
Definition: ServerApp.cc:461
void dump(std::ostream &strm) const override
dumps information about this object
Definition: ServerApp.cc:656
int terminate(int status=0) override
clean up after the application
Definition: ServerApp.cc:602
virtual void dump(std::ostream &strm) const
dumps information about this object
Definition: TcpSocket.cc:588
void get_value(const std::string &s, std::string &val, bool &found)
Retrieve the value of a given key, if set.
Definition: TheBESKeys.cc:340
static TheBESKeys * TheKeys()
Definition: TheBESKeys.cc:71
static std::string ConfigFile
Definition: TheBESKeys.h:185
virtual void dump(std::ostream &strm) const
dumps information about this object
Definition: UnixSocket.cc:250