OPeNDAP Hyrax Back End Server (BES)  Updated for version 3.8.3
ServerApp.cc
Go to the documentation of this file.
00001 // ServerApp.cc
00002 
00003 // This file is part of bes, A C++ back-end server implementation framework
00004 // for the OPeNDAP Data Access Protocol.
00005 
00006 // Copyright (c) 2004-2009 University Corporation for Atmospheric Research
00007 // Author: Patrick West <pwest@ucar.edu> and Jose Garcia <jgarcia@ucar.edu>
00008 //
00009 // This library is free software; you can redistribute it and/or
00010 // modify it under the terms of the GNU Lesser General Public
00011 // License as published by the Free Software Foundation; either
00012 // version 2.1 of the License, or (at your option) any later version.
00013 //
00014 // This library is distributed in the hope that it will be useful,
00015 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00016 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00017 // Lesser General Public License for more details.
00018 //
00019 // You should have received a copy of the GNU Lesser General Public
00020 // License along with this library; if not, write to the Free Software
00021 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00022 //
00023 // You can contact University Corporation for Atmospheric Research at
00024 // 3080 Center Green Drive, Boulder, CO 80301
00025 
00026 // (c) COPYRIGHT University Corporation for Atmospheric Research 2004-2005
00027 // Please read the full copyright statement in the file COPYRIGHT_UCAR.
00028 //
00029 // Authors:
00030 //      pwest       Patrick West <pwest@ucar.edu>
00031 //      jgarcia     Jose Garcia <jgarcia@ucar.edu>
00032 
00033 #include <signal.h>
00034 #include <unistd.h> // for getpid
00035 #include <grp.h>    // for getgrnam
00036 #include <pwd.h>    // for getpwnam
00037 
00038 #include <iostream>
00039 #include <fstream>
00040 #include <sstream>
00041 #include <cstdlib>
00042 
00043 using std::cout ;
00044 using std::cerr ;
00045 using std::endl ;
00046 using std::ios ;
00047 using std::ostringstream ;
00048 using std::ofstream ;
00049 
00050 #include "config.h"
00051 
00052 #include "ServerApp.h"
00053 #include "ServerExitConditions.h"
00054 #include "TheBESKeys.h"
00055 #include "BESLog.h"
00056 #include "SocketListener.h"
00057 #include "TcpSocket.h"
00058 #include "UnixSocket.h"
00059 #include "BESServerHandler.h"
00060 #include "BESError.h"
00061 #include "PPTServer.h"
00062 #include "BESMemoryManager.h"
00063 #include "BESDebug.h"
00064 #include "BESServerUtils.h"
00065 
00066 #include "BESDefaultModule.h"
00067 #include "BESXMLDefaultCommands.h"
00068 
00069 ServerApp::ServerApp()
00070     : BESModuleApp(),
00071       _portVal( 0 ),
00072       _gotPort( false ),
00073       _unixSocket( "" ),
00074       _secure( false ),
00075       _mypid( 0 ),
00076       _ts( 0 ),
00077       _us( 0 ),
00078       _ps( 0 )
00079 {
00080     _mypid = getpid() ;
00081 }
00082 
00083 ServerApp::~ServerApp()
00084 {
00085 }
00086 
00087 void
00088 ServerApp::signalTerminate( int sig )
00089 {
00090     if( sig == SIGTERM )
00091     {
00092         BESApp::TheApplication()->terminate( sig ) ;
00093         exit( SERVER_EXIT_NORMAL_SHUTDOWN ) ;
00094     }
00095 }
00096 
00097 void
00098 ServerApp::signalInterrupt( int sig )
00099 {
00100     if( sig == SIGINT )
00101     {
00102         BESApp::TheApplication()->terminate( sig ) ;
00103         exit( SERVER_EXIT_NORMAL_SHUTDOWN ) ;
00104     }
00105 }
00106 
00107 void
00108 ServerApp::signalRestart( int sig )
00109 {
00110     if( sig == SIGUSR1 )
00111     {
00112         BESApp::TheApplication()->terminate( sig ) ;
00113         exit( SERVER_EXIT_RESTART ) ;
00114     }
00115 }
00116 
00117 void
00118 ServerApp::set_group_id()
00119 {
00120 #if !defined(OS2) && !defined(TPF)
00121     // OS/2 and TPF don't support groups.
00122 
00123     // get group id or name from BES configuration file
00124     // If BES.Group begins with # then it is a group id,
00125     // else it is a group name and look up the id.
00126     BESDEBUG( "server", "ServerApp: Setting group id ... " << endl ) ;
00127     bool found = false ;
00128     string key = "BES.Group" ;
00129     string group_str ;
00130     try
00131     {
00132         TheBESKeys::TheKeys()->get_value( key, group_str, found ) ;
00133     }
00134     catch( BESError &e )
00135     {
00136         BESDEBUG( "server", "FAILED" << endl ) ;
00137         string err = string("FAILED: ") + e.get_message() ;
00138         cerr << err << endl ;
00139         (*BESLog::TheLog()) << err << endl ;
00140         exit( SERVER_EXIT_FATAL_CAN_NOT_START ) ;
00141     }
00142     if( !found || group_str.empty() )
00143     {
00144         BESDEBUG( "server", "FAILED" << endl ) ;
00145         string err = "FAILED: Group not specified in BES configuration file" ;
00146         cerr << err << endl ;
00147         (*BESLog::TheLog()) << err << endl ;
00148         exit( SERVER_EXIT_FATAL_CAN_NOT_START ) ;
00149     }
00150     BESDEBUG( "server", "to " << group_str << " ... " << endl ) ;
00151 
00152     gid_t new_gid = 0 ;
00153     if( group_str[0] == '#' )
00154     {
00155         // group id starts with a #, so is a group id
00156         const char *group_c = group_str.c_str() ;
00157         group_c++ ;
00158         new_gid = atoi( group_c ) ;
00159     }
00160     else
00161     {
00162         // specified group is a group name
00163         struct group *ent ;
00164         ent = getgrnam( group_str.c_str() ) ;
00165         if( !ent )
00166         {
00167             BESDEBUG( "server", "FAILED" << endl ) ;
00168             string err = (string)"FAILED: Group " + group_str
00169                          + " does not exist" ;
00170             cerr << err << endl ;
00171             (*BESLog::TheLog()) << err << endl ;
00172             exit( SERVER_EXIT_FATAL_CAN_NOT_START ) ;
00173         }
00174         new_gid = ent->gr_gid ;
00175     }
00176 
00177     if( new_gid < 1 )
00178     {
00179         BESDEBUG( "server", "FAILED" << endl ) ;
00180         ostringstream err ;
00181         err << "FAILED: Group id " << new_gid
00182             << " not a valid group id for BES" ;
00183         cerr << err.str() << endl ;
00184         (*BESLog::TheLog()) << err.str() << endl ;
00185         exit( SERVER_EXIT_FATAL_CAN_NOT_START ) ;
00186     }
00187 
00188     BESDEBUG( "server", "to id " << new_gid << " ... " << endl ) ;
00189     if( setgid( new_gid ) == -1 )
00190     {
00191         BESDEBUG( "server", "FAILED" << endl ) ;
00192         ostringstream err ;
00193         err << "FAILED: unable to set the group id to " << new_gid ;
00194         cerr << err.str() << endl ;
00195         (*BESLog::TheLog()) << err.str() << endl ;
00196         exit( SERVER_EXIT_FATAL_CAN_NOT_START ) ;
00197     }
00198 
00199     BESDEBUG( "server", "OK" << endl ) ;
00200 #else
00201     BESDEBUG( "server", "ServerApp: Groups not supported in this OS" << endl ) ;
00202 #endif
00203 }
00204 
00205 void
00206 ServerApp::set_user_id()
00207 {
00208     BESDEBUG( "server", "ServerApp: Setting user id ... " << endl ) ;
00209 
00210     // Get user name or id from the BES configuration file.
00211     // If the BES.User value begins with # then it is a user
00212     // id, else it is a user name and need to look up the
00213     // user id.
00214     bool found = false ;
00215     string key = "BES.User" ;
00216     string user_str ;
00217     try
00218     {
00219         TheBESKeys::TheKeys()->get_value( key, user_str, found ) ;
00220     }
00221     catch( BESError &e )
00222     {
00223         BESDEBUG( "server", "FAILED" << endl ) ;
00224         string err = (string)"FAILED: " + e.get_message() ;
00225         cerr << err << endl ;
00226         (*BESLog::TheLog()) << err << endl ;
00227         exit( SERVER_EXIT_FATAL_CAN_NOT_START ) ;
00228     }
00229     if( !found || user_str.empty() )
00230     {
00231         BESDEBUG( "server", "FAILED" << endl ) ;
00232         string err = (string)"FAILED: User not specified in BES config file" ;
00233         cerr << err << endl ;
00234         (*BESLog::TheLog()) << err << endl ;
00235         exit( SERVER_EXIT_FATAL_CAN_NOT_START ) ;
00236     }
00237     BESDEBUG( "server", "to " << user_str << " ... " << endl ) ;
00238 
00239     uid_t new_id = 0 ;
00240     if( user_str[0] == '#' )
00241     {
00242         const char *user_str_c = user_str.c_str() ;
00243         user_str_c++ ;
00244         new_id = atoi( user_str_c ) ;
00245     }
00246     else
00247     {
00248         struct passwd *ent ;
00249         ent = getpwnam( user_str.c_str() ) ;
00250         if( !ent )
00251         {
00252             BESDEBUG( "server", "FAILED" << endl ) ;
00253             string err = (string)"FAILED: Bad user name specified: "
00254                          + user_str ;
00255             cerr << err << endl ;
00256             (*BESLog::TheLog()) << err << endl ;
00257             exit( SERVER_EXIT_FATAL_CAN_NOT_START ) ;
00258         }
00259         new_id = ent->pw_uid ;
00260     }
00261 
00262     // new user id cannot be root (0)
00263     if( !new_id )
00264     {
00265         BESDEBUG( "server", "FAILED" << endl ) ;
00266         string err = (string)"FAILED: BES cannot run as root" ;
00267         cerr << err << endl ;
00268         (*BESLog::TheLog()) << err << endl ;
00269         exit( SERVER_EXIT_FATAL_CAN_NOT_START ) ;
00270     }
00271 
00272     BESDEBUG( "server", "to " << new_id << " ... " << endl ) ;
00273     if( setuid( new_id ) == -1 )
00274     {
00275         BESDEBUG( "server", "FAILED" << endl ) ;
00276         ostringstream err ;
00277         err << "FAILED: Unable to set user id to " << new_id ;
00278         cerr << err.str() << endl ;
00279         (*BESLog::TheLog()) << err.str() << endl ;
00280         exit( SERVER_EXIT_FATAL_CAN_NOT_START ) ;
00281     }
00282 }
00283 
00284 int
00285 ServerApp::initialize( int argc, char **argv )
00286 {
00287     int c = 0 ;
00288     bool needhelp = false ;
00289     string dashi ;
00290     string dashc ;
00291 
00292     // If you change the getopt statement below, be sure to make the
00293     // corresponding change in daemon.cc and besctl.in
00294     while( ( c = getopt( argc, argv, "hvsd:c:p:u:i:r:" ) ) != EOF )
00295     {
00296         switch( c )
00297         {
00298             case 'i':
00299                 dashi = optarg ;
00300                 break ;
00301             case 'c':
00302                 dashc = optarg ;
00303                 break ;
00304             case 'r':
00305                 break ; // we can ignore the /var/run directory option here
00306             case 'p':
00307                 _portVal = atoi( optarg ) ;
00308                 _gotPort = true ;
00309                 break ;
00310             case 'u':
00311                 _unixSocket = optarg ;
00312                 break ;
00313             case 'd':
00314                 BESDebug::SetUp( optarg ) ;
00315                 break ;
00316             case 'v':
00317                 BESServerUtils::show_version( BESApp::TheApplication()->appName() ) ;
00318                 break ;
00319             case 's':
00320                 _secure = true ;
00321                 break ;
00322             case 'h':
00323             case '?':
00324             default:
00325                 needhelp = true ;
00326                 break ;
00327         }
00328     }
00329 
00330     // before we can do any processing, log any messages, initialize any
00331     // modules, do anything, we need to determine where the BES
00332     // configuration file lives. From here we get the name of the log
00333     // file, group and user id, and information that the modules will
00334     // need to run properly.
00335 
00336     // If the -c optiion was passed, set the config file name in TheBESKeys
00337     if( !dashc.empty() )
00338     {
00339         TheBESKeys::ConfigFile = dashc ;
00340     }
00341 
00342     // If the -c option was not passed, but the -i option
00343     // was passed, then use the -i option to construct
00344     // the path to the config file
00345     if( dashc.empty() && !dashi.empty() )
00346     {
00347         if( dashi[dashi.length()-1] != '/' )
00348         {
00349             dashi += '/' ;
00350         }
00351         string conf_file = dashi + "etc/bes/bes.conf" ;
00352         TheBESKeys::ConfigFile = conf_file ;
00353     }
00354 
00355     // Now that we have the configuration information, we can log to the
00356     // BES log file if there are errors in starting up, etc...
00357 
00358     uid_t curr_euid = geteuid() ;
00359 #ifndef BES_DEVELOPER
00360     // must be root to run this app and to set user id and group id later
00361     if( curr_euid )
00362     {
00363         string err = "FAILED: Must be root to run BES" ;
00364         cerr << err << endl ;
00365         (*BESLog::TheLog()) << err << endl ;
00366         exit( SERVER_EXIT_FATAL_CAN_NOT_START ) ;
00367     }
00368 #else
00369     cout << "Developer Mode: not testing if BES is run by root" << endl ;
00370 #endif
00371 
00372     // register the two debug context for the server and ppt. The
00373     // Default Module will register the bes context.
00374     BESDebug::Register( "server" ) ;
00375     BESDebug::Register( "ppt" ) ;
00376 
00377     // Before we can load modules, start writing to the BES log
00378     // file, etc... we need to run as the proper user. Set the user
00379     // id and the group id to what is specified in the BES
00380     // configuration file
00381     if( curr_euid == 0 )
00382     {
00383 #ifdef BES_DEVELOPER
00384         cout << "Developer Mode: Running as root - setting group and user ids"
00385              << endl ;
00386 #endif
00387         set_group_id() ;
00388         set_user_id() ;
00389     }
00390     else
00391     {
00392         cout << "Developer Mode: Not setting group or user ids" << endl ;
00393     }
00394 
00395     // Because we are now running as the user specified in the
00396     // configuraiton file, we won't be able to listen on system ports.
00397     // If this is a problem, we may need to move this code above setting
00398     // the user and group ids.
00399     bool found = false ;
00400     string port_key = "BES.ServerPort" ;
00401     if( !_gotPort )
00402     {
00403         string sPort ;
00404         try
00405         {
00406             TheBESKeys::TheKeys()->get_value( port_key, sPort, found ) ;
00407         }
00408         catch( BESError &e )
00409         {
00410             BESDEBUG( "server", "FAILED" << endl ) ;
00411             string err = (string)"FAILED: " + e.get_message() ;
00412             cerr << err << endl ;
00413             (*BESLog::TheLog()) << err << endl ;
00414             exit( SERVER_EXIT_FATAL_CAN_NOT_START ) ;
00415         }
00416         if( found )
00417         {
00418             _portVal = atoi( sPort.c_str() ) ;
00419             if( _portVal != 0 )
00420             {
00421                 _gotPort = true ;
00422             }
00423         }
00424     }
00425 
00426     found = false ;
00427     string socket_key = "BES.ServerUnixSocket" ;
00428     if( _unixSocket == "" )
00429     {
00430         try
00431         {
00432             TheBESKeys::TheKeys()->get_value( socket_key, _unixSocket, found ) ;
00433         }
00434         catch( BESError &e )
00435         {
00436             BESDEBUG( "server", "FAILED" << endl ) ;
00437             string err = (string)"FAILED: " + e.get_message() ;
00438             cerr << err << endl ;
00439             (*BESLog::TheLog()) << err << endl ;
00440             exit( SERVER_EXIT_FATAL_CAN_NOT_START ) ;
00441         }
00442     }
00443 
00444     if( !_gotPort && _unixSocket == "" )
00445     {
00446         string msg = "Must specify a tcp port or a unix socket or both\n" ;
00447         msg += "Please specify on the command line with -p <port>" ;
00448         msg += " and/or -u <unix_socket>\n" ;
00449         msg += "Or specify in the bes configuration file with "
00450             + port_key + " and/or " + socket_key + "\n" ;
00451         cout << endl << msg ;
00452         (*BESLog::TheLog()) << msg << endl ;
00453         BESServerUtils::show_usage( BESApp::TheApplication()->appName() ) ;
00454     }
00455 
00456     found = false ;
00457     if( _secure == false )
00458     {
00459         string key = "BES.ServerSecure" ;
00460         string isSecure ;
00461         try
00462         {
00463             TheBESKeys::TheKeys()->get_value( key, isSecure, found ) ;
00464         }
00465         catch( BESError &e )
00466         {
00467             BESDEBUG( "server", "FAILED" << endl ) ;
00468             string err = (string)"FAILED: " + e.get_message() ;
00469             cerr << err << endl ;
00470             (*BESLog::TheLog()) << err << endl ;
00471             exit( SERVER_EXIT_FATAL_CAN_NOT_START ) ;
00472         }
00473         if( isSecure == "Yes" || isSecure == "YES" || isSecure == "yes" )
00474         {
00475             _secure = true ;
00476         }
00477     }
00478 
00479     BESDEBUG( "server", "ServerApp: Registering signal SIGTERM ... " << endl ) ;
00480     if( signal( SIGTERM, signalTerminate ) == SIG_ERR )
00481     {
00482         BESDEBUG( "server", "FAILED" << endl ) ;
00483         string err = "FAILED: cannot register SIGTERM signal handler" ;
00484         cerr << err << endl ;
00485         (*BESLog::TheLog()) << err << endl ;
00486         exit( SERVER_EXIT_FATAL_CAN_NOT_START ) ;
00487     }
00488     BESDEBUG( "server", "OK" << endl ) ;
00489 
00490     BESDEBUG( "server", "ServerApp: Registering signal SIGINT ... " << endl ) ;
00491     if( signal( SIGINT, signalInterrupt ) == SIG_ERR )
00492     {
00493         BESDEBUG( "server", "FAILED" << endl ) ;
00494         string err = "FAILED: cannot register SIGINT signal handler" ;
00495         cerr << err << endl ;
00496         (*BESLog::TheLog()) << err << endl ;
00497         exit( SERVER_EXIT_FATAL_CAN_NOT_START ) ;
00498     }
00499     BESDEBUG( "server", "OK" << endl ) ;
00500 
00501     BESDEBUG( "server", "ServerApp: Registering signal SIGUSR1 ... " << endl ) ;
00502     if( signal( SIGUSR1, signalRestart ) == SIG_ERR )
00503     {
00504         BESDEBUG( "server", "FAILED" << endl ) ;
00505         string err = "FAILED: cannot register SIGUSR1 signal handler" ;
00506         cerr << err << endl ;
00507         (*BESLog::TheLog()) << err << endl ;
00508         exit( SERVER_EXIT_FATAL_CAN_NOT_START ) ;
00509     }
00510     BESDEBUG( "server", "OK" << endl ) ;
00511 
00512     BESDEBUG( "server", "ServerApp: initializing default module ... "
00513                         << endl ) ;
00514     BESDefaultModule::initialize( argc, argv ) ;
00515     BESDEBUG( "server", "OK" << endl ) ;
00516 
00517     BESDEBUG( "server", "ServerApp: initializing default commands ... "
00518                         << endl ) ;
00519     BESXMLDefaultCommands::initialize( argc, argv ) ;
00520     BESDEBUG( "server", "OK" << endl ) ;
00521 
00522     // This will load and initialize all of the modules
00523     int ret = BESModuleApp::initialize( argc, argv ) ;
00524 
00525     BESDEBUG( "server", "ServerApp: initialized settings:" << *this ) ;
00526 
00527     if( needhelp )
00528     {
00529         BESServerUtils::show_usage( BESApp::TheApplication()->appName() ) ;
00530     }
00531 
00532     return ret ;
00533 }
00534 
00535 int
00536 ServerApp::run()
00537 {
00538     try
00539     {
00540         BESDEBUG( "server", "ServerApp: initializing memory pool ... "
00541                             << endl ) ;
00542         BESMemoryManager::initialize_memory_pool() ;
00543         BESDEBUG( "server", "OK" << endl ) ;
00544 
00545         SocketListener listener ;
00546 
00547         if( _portVal )
00548         {
00549             _ts = new TcpSocket( _portVal ) ;
00550             listener.listen( _ts ) ;
00551             BESDEBUG( "server", "ServerApp: listening on port ("
00552                                 << _portVal << ")" << endl ) ;
00553         }
00554 
00555         if( !_unixSocket.empty() )
00556         {
00557             _us = new UnixSocket( _unixSocket ) ;
00558             listener.listen( _us ) ;
00559             BESDEBUG( "server", "ServerApp: listening on unix socket ("
00560                                 << _unixSocket << ")" << endl ) ;
00561         }
00562 
00563         BESServerHandler handler ;
00564 
00565         _ps = new PPTServer( &handler, &listener, _secure ) ;
00566         _ps->initConnection() ;
00567     }
00568     catch( BESError &se )
00569     {
00570         cerr << se.get_message() << endl ;
00571         (*BESLog::TheLog()) << se.get_message() << endl ;
00572         return 1 ;
00573     }
00574     catch( ... )
00575     {
00576         cerr << "caught unknown exception" << endl ;
00577         (*BESLog::TheLog()) << "caught unknown exception initializing sockets"
00578                             << endl ;
00579         return 1 ;
00580     }
00581 
00582     return 0 ;
00583 }
00584 
00585 int
00586 ServerApp::terminate( int sig )
00587 {
00588     pid_t apppid = getpid() ;
00589     if( apppid == _mypid )
00590     {
00591         if( _ps )
00592         {
00593             _ps->closeConnection() ;
00594             delete _ps ;
00595         }
00596         if( _ts )
00597         {
00598             _ts->close() ;
00599             delete _ts ;
00600         }
00601         if( _us )
00602         {
00603             _us->close() ;
00604             delete _us ;
00605         }
00606 
00607         BESDEBUG( "server", "ServerApp: terminating default module ... "
00608                             << endl ) ;
00609         BESDefaultModule::terminate( ) ;
00610         BESDEBUG( "server", "OK" << endl ) ;
00611 
00612         BESDEBUG( "server", "ServerApp: terminating default commands ...  "
00613                             << endl ) ;
00614         BESXMLDefaultCommands::terminate( ) ;
00615         BESDEBUG( "server", "OK" << endl ) ;
00616 
00617         BESModuleApp::terminate( sig ) ;
00618     }
00619     return sig ;
00620 }
00621 
00628 void
00629 ServerApp::dump( ostream &strm ) const
00630 {
00631     strm << BESIndent::LMarg << "ServerApp::dump - ("
00632                              << (void *)this << ")" << endl ;
00633     BESIndent::Indent() ;
00634     strm << BESIndent::LMarg << "got port? " << _gotPort << endl ;
00635     strm << BESIndent::LMarg << "port: " << _portVal << endl ;
00636     strm << BESIndent::LMarg << "unix socket: " << _unixSocket << endl ;
00637     strm << BESIndent::LMarg << "is secure? " << _secure << endl ;
00638     strm << BESIndent::LMarg << "pid: " << _mypid << endl ;
00639     if( _ts )
00640     {
00641         strm << BESIndent::LMarg << "tcp socket:" << endl ;
00642         BESIndent::Indent() ;
00643         _ts->dump( strm ) ;
00644         BESIndent::UnIndent() ;
00645     }
00646     else
00647     {
00648         strm << BESIndent::LMarg << "tcp socket: null" << endl ;
00649     }
00650     if( _us )
00651     {
00652         strm << BESIndent::LMarg << "unix socket:" << endl ;
00653         BESIndent::Indent() ;
00654         _us->dump( strm ) ;
00655         BESIndent::UnIndent() ;
00656     }
00657     else
00658     {
00659         strm << BESIndent::LMarg << "unix socket: null" << endl ;
00660     }
00661     if( _ps )
00662     {
00663         strm << BESIndent::LMarg << "ppt server:" << endl ;
00664         BESIndent::Indent() ;
00665         _ps->dump( strm ) ;
00666         BESIndent::UnIndent() ;
00667     }
00668     else
00669     {
00670         strm << BESIndent::LMarg << "ppt server: null" << endl ;
00671     }
00672     BESModuleApp::dump( strm ) ;
00673     BESIndent::UnIndent() ;
00674 }
00675 
00676 int
00677 main( int argc, char **argv )
00678 {
00679     try
00680     {
00681         ServerApp app ;
00682         return app.main( argc, argv ) ;
00683     }
00684     catch( BESError &e )
00685     {
00686         cerr << "Caught unhandled exception: " << endl ;
00687         cerr << e.get_message() << endl ;
00688         return 1 ;
00689     }
00690     catch( ... )
00691     {
00692         cerr << "Caught unhandled, unknown exception" << endl ;
00693         return 1 ;
00694     }
00695     return 0 ;
00696 }
00697