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 
70 using namespace std;
71 
72 static int session_id = 0;
73 
74 // These are set to 1 by their respective handlers and then processed in the
75 // signal processing loop.
76 static volatile sig_atomic_t sigchild = 0;
77 static volatile sig_atomic_t sigpipe = 0;
78 static volatile sig_atomic_t sigterm = 0;
79 static volatile sig_atomic_t sighup = 0;
80 
81 // Set in ServerApp::initialize().
82 // Added jhrg 9/22/15
83 static volatile int master_listener_pid = -1;
84 
85 #if 1
86 static 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
108 static 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 
123 static 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).
145 static 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.
155 static void catch_sig_hup(int sig)
156 {
157  if (sig == SIGHUP) {
158  sighup = 1;
159  }
160 }
161 
162 static 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.
204 static void catch_sig_term(int sig)
205 {
206  if (sig == SIGTERM) {
207  sigterm = 1;
208  }
209 }
210 
219 static 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 
258 ServerApp::ServerApp() : BESModuleApp()
259 {
260  d_pid = getpid();
261 }
262 
263 ServerApp::~ServerApp()
264 {
265  delete TheBESKeys::TheKeys();
266 }
267 
268 int 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()) {
324  TheBESKeys::ConfigFile = dashc;
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().
602 int 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);
628  BESModuleApp::terminate(status);
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 
656 void 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 
698 int 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 }
static BESApp * TheApplication()
Returns the BESApp application object for this application.
Definition: BESApp.h:139
std::string appName() const
Returns the name of the application.
Definition: BESApp.h:130
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