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.
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: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.
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