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

Generated on 27 Oct 2009 for OPeNDAP Hyrax Back End Server (BES) by  doxygen 1.6.1