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,2005 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>
00035 #include <grp.h>
00036 #include <pwd.h>
00037 
00038 #include <iostream>
00039 #include <fstream>
00040 
00041 using std::cout ;
00042 using std::cerr ;
00043 using std::endl ;
00044 using std::ios ;
00045 using std::ofstream ;
00046 
00047 #include "config.h"
00048 
00049 #include "ServerApp.h"
00050 #include "ServerExitConditions.h"
00051 #include "TheBESKeys.h"
00052 #include "SocketListener.h"
00053 #include "TcpSocket.h"
00054 #include "UnixSocket.h"
00055 #include "BESServerHandler.h"
00056 #include "BESException.h"
00057 #include "PPTException.h"
00058 #include "PPTServer.h"
00059 #include "PPTException.h"
00060 #include "SocketException.h"
00061 #include "BESMemoryManager.h"
00062 #include "BESDebug.h"
00063 #include "BESServerUtils.h"
00064 
00065 #include "BESDefaultModule.h"
00066 #include "BESDefaultCommands.h"
00067 
00068 ServerApp::ServerApp()
00069     : BESModuleApp(),
00070       _portVal( 0 ),
00071       _gotPort( false ),
00072       _unixSocket( "" ),
00073       _secure( false ),
00074       _mypid( 0 ),
00075       _ts( 0 ),
00076       _us( 0 ),
00077       _ps( 0 )
00078 {
00079     _mypid = getpid() ;
00080 }
00081 
00082 ServerApp::~ServerApp()
00083 {
00084 }
00085 
00086 void
00087 ServerApp::signalTerminate( int sig )
00088 {
00089     if( sig == SIGTERM )
00090     {
00091         BESApp::TheApplication()->terminate( sig ) ;
00092         exit( SERVER_EXIT_NORMAL_SHUTDOWN ) ;
00093     }
00094 }
00095 
00096 void
00097 ServerApp::signalInterrupt( int sig )
00098 {
00099     if( sig == SIGINT )
00100     {
00101         BESApp::TheApplication()->terminate( sig ) ;
00102         exit( SERVER_EXIT_NORMAL_SHUTDOWN ) ;
00103     }
00104 }
00105 
00106 void
00107 ServerApp::signalRestart( int sig )
00108 {
00109     if( sig == SIGUSR1 )
00110     {
00111         BESApp::TheApplication()->terminate( sig ) ;
00112         exit( SERVER_EXIT_RESTART ) ;
00113     }
00114 }
00115 
00116 void
00117 ServerApp::set_group_id()
00118 {
00119 #if !defined(OS2) && !defined(TPF)
00120     // OS/2 and TPF don't support groups.
00121 
00122     // get group id or name from BES configuration file
00123     // If BES.Group begins with # then it is a group id,
00124     // else it is a group name and look up the id.
00125     BESDEBUG( "server", "ServerApp: Setting group id ... " )
00126     bool found = false ;
00127     string key = "BES.Group" ;
00128     string group_str = TheBESKeys::TheKeys()->get_key( key, found ) ;
00129     if( !found || group_str.empty() )
00130     {
00131         BESDEBUG( "server", "FAILED" << endl ) ;
00132         cerr << "FAILED: Group not specified in BES configuration file"
00133              << endl ;
00134         exit( SERVER_EXIT_FATAL_CAN_NOT_START ) ;
00135     }
00136     BESDEBUG( "server", "to " << group_str << " ... " )
00137 
00138     gid_t new_gid = 0 ;
00139     if( group_str[0] == '#' )
00140     {
00141         // group id starts with a #, so is a group id
00142         const char *group_c = group_str.c_str() ;
00143         group_c++ ;
00144         new_gid = atoi( group_c ) ;
00145     }
00146     else
00147     {
00148         // specified group is a group name
00149         struct group *ent ;
00150         ent = getgrnam( group_str.c_str() ) ;
00151         if( !ent )
00152         {
00153             BESDEBUG( "server", "FAILED" << endl ) ;
00154             cerr << "FAILED: Group " << group_str << " does not exist" << endl ;
00155             exit( SERVER_EXIT_FATAL_CAN_NOT_START ) ;
00156         }
00157         new_gid = ent->gr_gid ;
00158     }
00159 
00160     if( new_gid < 1 )
00161     {
00162         BESDEBUG( "server", "FAILED" << endl ) ;
00163         cerr << "FAILED: Group id " << new_gid
00164              << " not a valid group id for BES" << endl ;
00165         exit( SERVER_EXIT_FATAL_CAN_NOT_START ) ;
00166     }
00167 
00168     BESDEBUG( "server", "to id " << new_gid << " ... " )
00169     if( setgid( new_gid ) == -1 )
00170     {
00171         BESDEBUG( "server", "FAILED" << endl ) ;
00172         cerr << "FAILED: unable to set the group id to " << new_gid << endl ;
00173         exit( SERVER_EXIT_FATAL_CAN_NOT_START ) ;
00174     }
00175 
00176     BESDEBUG( "server", "OK" << endl ) ;
00177 #else
00178     BESDEBUG( "server", "ServerApp: Groups not supported in this OS" )
00179 #endif
00180 }
00181 
00182 void
00183 ServerApp::set_user_id()
00184 {
00185     BESDEBUG( "server", "ServerApp: Setting user id ... " )
00186 
00187     // Get user name or id from the BES configuration file.
00188     // If the BES.User value begins with # then it is a user
00189     // id, else it is a user name and need to look up the
00190     // user id.
00191     bool found = false ;
00192     string key = "BES.User" ;
00193     string user_str = TheBESKeys::TheKeys()->get_key( key, found ) ;
00194     if( !found || user_str.empty() )
00195     {
00196         BESDEBUG( "server", "FAILED" << endl ) ;
00197         cerr << "FAILED: User not specified in BES configuration file"
00198              << endl ;
00199         exit( SERVER_EXIT_FATAL_CAN_NOT_START ) ;
00200     }
00201     BESDEBUG( "server", "to " << user_str << " ... " )
00202 
00203     uid_t new_id = 0 ;
00204     if( user_str[0] == '#' )
00205     {
00206         const char *user_str_c = user_str.c_str() ;
00207         user_str_c++ ;
00208         new_id = atoi( user_str_c ) ;
00209     }
00210     else
00211     {
00212         struct passwd *ent ;
00213         ent = getpwnam( user_str.c_str() ) ;
00214         if( !ent )
00215         {
00216             BESDEBUG( "server", "FAILED" << endl ) ;
00217             cerr << "FAILED: Bad user name specified: "
00218                  << user_str << endl ;
00219             exit( SERVER_EXIT_FATAL_CAN_NOT_START ) ;
00220         }
00221         new_id = ent->pw_uid ;
00222     }
00223 
00224     // new user id can not be root (0)
00225     if( !new_id )
00226     {
00227         BESDEBUG( "server", "FAILED" << endl ) ;
00228         cerr << "FAILED: BES can not run as root" << endl ;
00229         exit( SERVER_EXIT_FATAL_CAN_NOT_START ) ;
00230     }
00231 
00232     BESDEBUG( "server", "to " << new_id << " ... " )
00233     if( setuid( new_id ) == -1 )
00234     {
00235         BESDEBUG( "server", "FAILED" << endl ) ;
00236         cerr << "FAILED: Unable to set user id to "
00237              << new_id << endl ;
00238         exit( SERVER_EXIT_FATAL_CAN_NOT_START ) ;
00239     }
00240 }
00241 
00242 int
00243 ServerApp::initialize( int argc, char **argv )
00244 {
00245     // must be root to run this app and to set user id and group id later
00246     uid_t curr_euid = geteuid() ;
00247     if( curr_euid )
00248     {
00249         cerr << "FAILED: Must be root to run BES" << endl ;
00250         exit( SERVER_EXIT_FATAL_CAN_NOT_START ) ;
00251     }
00252 
00253     int c = 0 ;
00254     bool needhelp = false ;
00255     string dashi ;
00256     string dashc ;
00257 
00258     // If you change the getopt statement below, be sure to make the
00259     // corresponding change in daemon.cc and besctl.in
00260     while( ( c = getopt( argc, argv, "hvsd:c:p:u:i:r:" ) ) != EOF )
00261     {
00262         switch( c )
00263         {
00264             case 'i':
00265                 dashi = optarg ;
00266                 break ;
00267             case 'c':
00268                 dashc = optarg ;
00269                 break ;
00270             case 'r':
00271                 break ; // we can ignore the /var/run directory option here
00272             case 'p':
00273                 _portVal = atoi( optarg ) ;
00274                 _gotPort = true ;
00275                 break ;
00276             case 'u':
00277                 _unixSocket = optarg ;
00278                 break ;
00279             case 'd':
00280                 BESDebug::SetUp( optarg ) ;
00281                 break ;
00282             case 'v':
00283                 BESServerUtils::show_version( BESApp::TheApplication()->appName() ) ;
00284                 break ;
00285             case 's':
00286                 _secure = true ;
00287                 break ;
00288             case 'h':
00289             case '?':
00290             default:
00291                 needhelp = true ;
00292                 break ;
00293         }
00294     }
00295 
00296     // If the -c optiion was passed, set the config file
00297     // name in TheBESKeys
00298     if( !dashc.empty() )
00299     {
00300         TheBESKeys::ConfigFile = dashc ;
00301     }
00302 
00303     // If the -c option was not passed, but the -i option
00304     // was passed, then use the -i option to construct
00305     // the path to the config file
00306     if( dashc.empty() && !dashi.empty() )
00307     {
00308         if( dashi[dashi.length()-1] != '/' )
00309         {
00310             dashi += '/' ;
00311         }
00312         string conf_file = dashi + "etc/bes/bes.conf" ;
00313         TheBESKeys::ConfigFile = conf_file ;
00314     }
00315 
00316     bool found = false ;
00317     string port_key = "BES.ServerPort" ;
00318     if( !_gotPort )
00319     {
00320         string sPort = TheBESKeys::TheKeys()->get_key( port_key, found ) ;
00321         if( found )
00322         {
00323             _portVal = atoi( sPort.c_str() ) ;
00324             if( _portVal != 0 )
00325             {
00326                 _gotPort = true ;
00327             }
00328         }
00329     }
00330 
00331     found = false ;
00332     string socket_key = "BES.ServerUnixSocket" ;
00333     if( _unixSocket == "" )
00334     {
00335         _unixSocket = TheBESKeys::TheKeys()->get_key( socket_key, found ) ;
00336     }
00337 
00338     if( !_gotPort && _unixSocket == "" )
00339     {
00340         cout << endl << "Must specify either a tcp port"
00341              << " or a unix socket or both" << endl ;
00342         cout << "Please specify on the command line with"
00343              << " -p <port> -u <unix_socket> "
00344              << endl
00345              << "Or specify in the bes configuration file with "
00346              << port_key << " and/or " << socket_key
00347              << endl << endl ;
00348         BESServerUtils::show_usage( BESApp::TheApplication()->appName() ) ;
00349     }
00350 
00351     found = false ;
00352     if( _secure == false )
00353     {
00354         string key = "BES.ServerSecure" ;
00355         string isSecure = TheBESKeys::TheKeys()->get_key( key, found ) ;
00356         if( isSecure == "Yes" || isSecure == "YES" || isSecure == "yes" )
00357         {
00358             _secure = true ;
00359         }
00360     }
00361 
00362     BESDEBUG( "server", "ServerApp: Registering signal SIGTERM ... " )
00363     if( signal( SIGTERM, signalTerminate ) == SIG_ERR )
00364     {
00365         BESDEBUG( "server", "FAILED" << endl ) ;
00366         cerr << "FAILED: Can not register SIGTERM signal handler" << endl ;
00367         exit( SERVER_EXIT_FATAL_CAN_NOT_START ) ;
00368     }
00369     BESDEBUG( "server", "OK" << endl ) ;
00370 
00371     BESDEBUG( "server", "ServerApp: Registering signal SIGINT ... " )
00372     if( signal( SIGINT, signalInterrupt ) == SIG_ERR )
00373     {
00374         BESDEBUG( "server", "FAILED" << endl ) ;
00375         cerr << "FAILED: Can not register SIGINT signal handler" << endl ;
00376         exit( SERVER_EXIT_FATAL_CAN_NOT_START ) ;
00377     }
00378     BESDEBUG( "server", "OK" << endl ) ;
00379 
00380     BESDEBUG( "server", "ServerApp: Registering signal SIGUSR1 ... " )
00381     if( signal( SIGUSR1, signalRestart ) == SIG_ERR )
00382     {
00383         BESDEBUG( "server", "FAILED" << endl ) ;
00384         cerr << "FAILED: Can not register SIGUSR1 signal handler" << endl ;
00385         exit( SERVER_EXIT_FATAL_CAN_NOT_START ) ;
00386     }
00387     BESDEBUG( "server", "OK" << endl ) ;
00388 
00389     BESDEBUG( "server", "ServerApp: initializing default module ... " )
00390     BESDefaultModule::initialize( argc, argv ) ;
00391     BESDEBUG( "server", "OK" << endl ) ;
00392 
00393     BESDEBUG( "server", "ServerApp: initializing default commands ... " )
00394     BESDefaultCommands::initialize( argc, argv ) ;
00395     BESDEBUG( "server", "OK" << endl ) ;
00396 
00397     int ret = BESModuleApp::initialize( argc, argv ) ;
00398 
00399     BESDEBUG( "server", "ServerApp: initialized settings:" << *this ) ;
00400 
00401     if( needhelp )
00402     {
00403         BESServerUtils::show_usage( BESApp::TheApplication()->appName() ) ;
00404     }
00405 
00406     // Now that we have loaded all modules and given them the chance to initialize
00407     // set the user id and the group id to what is specified in the BES
00408     // configuration file.
00409     set_group_id() ;
00410     set_user_id() ;
00411 
00412     return ret ;
00413 }
00414 
00415 int
00416 ServerApp::run()
00417 {
00418     try
00419     {
00420         BESDEBUG( "server", "ServerApp: initializing memory pool ... " )
00421         BESMemoryManager::initialize_memory_pool() ;
00422         BESDEBUG( "server", "OK" << endl ) ;
00423 
00424         SocketListener listener ;
00425 
00426         if( _portVal )
00427         {
00428             _ts = new TcpSocket( _portVal ) ;
00429             listener.listen( _ts ) ;
00430             BESDEBUG( "server", "ServerApp: listening on port (" << _portVal << ")" << endl )
00431         }
00432 
00433         if( !_unixSocket.empty() )
00434         {
00435             _us = new UnixSocket( _unixSocket ) ;
00436             listener.listen( _us ) ;
00437             BESDEBUG( "server", "ServerApp: listening on unix socket (" << _unixSocket << ")" << endl )
00438         }
00439 
00440         BESServerHandler handler ;
00441 
00442         _ps = new PPTServer( &handler, &listener, _secure ) ;
00443         _ps->initConnection() ;
00444     }
00445     catch( SocketException &se )
00446     {
00447         cerr << "caught SocketException" << endl ;
00448         cerr << se.getMessage() << endl ;
00449         return 1 ;
00450     }
00451     catch( PPTException &pe )
00452     {
00453         cerr << "caught PPTException" << endl ;
00454         cerr << pe.getMessage() << endl ;
00455         return 1 ;
00456     }
00457     catch( ... )
00458     {
00459         cerr << "caught unknown exception" << endl ;
00460         return 1 ;
00461     }
00462 
00463     return 0 ;
00464 }
00465 
00466 int
00467 ServerApp::terminate( int sig )
00468 {
00469     pid_t apppid = getpid() ;
00470     if( apppid == _mypid )
00471     {
00472         if( _ps )
00473         {
00474             _ps->closeConnection() ;
00475             delete _ps ;
00476         }
00477         if( _ts )
00478         {
00479             _ts->close() ;
00480             delete _ts ;
00481         }
00482         if( _us )
00483         {
00484             _us->close() ;
00485             delete _us ;
00486         }
00487 
00488         BESDEBUG( "server", "ServerApp: terminating default module ... " )
00489         BESDefaultModule::terminate( ) ;
00490         BESDEBUG( "server", "OK" << endl ) ;
00491 
00492         BESDEBUG( "server", "ServerApp: terminating default commands ... " )
00493         BESDefaultCommands::terminate( ) ;
00494         BESDEBUG( "server", "OK" << endl ) ;
00495 
00496         BESModuleApp::terminate( sig ) ;
00497     }
00498     return sig ;
00499 }
00500 
00507 void
00508 ServerApp::dump( ostream &strm ) const
00509 {
00510     strm << BESIndent::LMarg << "ServerApp::dump - ("
00511                              << (void *)this << ")" << endl ;
00512     BESIndent::Indent() ;
00513     strm << BESIndent::LMarg << "got port? " << _gotPort << endl ;
00514     strm << BESIndent::LMarg << "port: " << _portVal << endl ;
00515     strm << BESIndent::LMarg << "unix socket: " << _unixSocket << endl ;
00516     strm << BESIndent::LMarg << "is secure? " << _secure << endl ;
00517     strm << BESIndent::LMarg << "pid: " << _mypid << endl ;
00518     if( _ts )
00519     {
00520         strm << BESIndent::LMarg << "tcp socket:" << endl ;
00521         BESIndent::Indent() ;
00522         _ts->dump( strm ) ;
00523         BESIndent::UnIndent() ;
00524     }
00525     else
00526     {
00527         strm << BESIndent::LMarg << "tcp socket: null" << endl ;
00528     }
00529     if( _us )
00530     {
00531         strm << BESIndent::LMarg << "unix socket:" << endl ;
00532         BESIndent::Indent() ;
00533         _us->dump( strm ) ;
00534         BESIndent::UnIndent() ;
00535     }
00536     else
00537     {
00538         strm << BESIndent::LMarg << "unix socket: null" << endl ;
00539     }
00540     if( _ps )
00541     {
00542         strm << BESIndent::LMarg << "ppt server:" << endl ;
00543         BESIndent::Indent() ;
00544         _ps->dump( strm ) ;
00545         BESIndent::UnIndent() ;
00546     }
00547     else
00548     {
00549         strm << BESIndent::LMarg << "ppt server: null" << endl ;
00550     }
00551     BESModuleApp::dump( strm ) ;
00552     BESIndent::UnIndent() ;
00553 }
00554 
00555 int
00556 main( int argc, char **argv )
00557 {
00558     try
00559     {
00560         ServerApp app ;
00561         return app.main( argc, argv ) ;
00562     }
00563     catch( BESException &e )
00564     {
00565         cerr << "Caught unhandled exception: " << endl ;
00566         cerr << e.get_message() << endl ;
00567         return 1 ;
00568     }
00569     catch( ... )
00570     {
00571         cerr << "Caught unhandled, unknown exception" << endl ;
00572         return 1 ;
00573     }
00574     return 0 ;
00575 }
00576 

Generated on Wed Jan 2 06:00:40 2008 for OPeNDAP Back End Server (BES) by  doxygen 1.5.4