CmdApp.cc

Go to the documentation of this file.
00001 // ClientMain.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 <unistd.h>
00034 #include <signal.h>
00035 
00036 #include <iostream>
00037 #include <string>
00038 #include <fstream>
00039 
00040 using std::cout ;
00041 using std::cerr ;
00042 using std::endl ;
00043 using std::flush ;
00044 using std::string ;
00045 using std::ofstream ;
00046 
00047 #include "CmdApp.h"
00048 #include "CmdClient.h"
00049 #include "PPTException.h"
00050 #include "BESDebug.h"
00051 
00052 #define BES_CMDLN_DEFAULT_TIMEOUT 5
00053 
00054 CmdApp::CmdApp()
00055     : BESBaseApp(),
00056       _client( 0 ),
00057       _hostStr( "" ),
00058       _unixStr( "" ),
00059       _portVal( 0 ),
00060       _outputStrm( 0 ),
00061       _inputStrm( 0 ),
00062       _createdInputStrm( false ),
00063       _timeout( 0 ),
00064       _repeat( 0 )
00065 {
00066 }
00067 
00068 CmdApp::~CmdApp()
00069 {
00070     if( _client )
00071     {
00072         delete _client ;
00073         _client = 0 ;
00074     }
00075 }
00076 
00077 void
00078 CmdApp::showVersion()
00079 {
00080     cout << appName() << ": version 2.0" << endl ;
00081 }
00082 
00083 void
00084 CmdApp::showUsage( )
00085 {
00086     cout << endl ;
00087     cout << appName() << ": the following flags are available:" << endl ;
00088     cout << "    -h <host> - specifies a host for TCP/IP connection" << endl ;
00089     cout << "    -p <port> - specifies a port for TCP/IP connection" << endl ;
00090     cout << "    -u <unixSocket> - specifies a unix socket for connection. " << endl ;
00091     cout << "    -x <command> - specifies a command for the server to execute" << endl ;
00092     cout << "    -i <inputFile> - specifies a file name for a sequence of input commands" << endl ;
00093     cout << "    -f <outputFile> - specifies a file name to output the results of the input" << endl ;
00094     cout << "    -t <timeoutVal> - specifies an optional timeout value in seconds" << endl ;
00095     cout << "    -d - sets the optional debug flag for the client session" << endl ;
00096     cout << "    -r <num> - repeat the command(s) num times" << endl ;
00097     cout << "    -? - display this list of flags" << endl ;
00098     cout << endl ;
00099     BESDebug::Help( cout ) ;
00100 }
00101 
00102 void
00103 CmdApp::signalCannotConnect( int sig )
00104 {
00105     if( sig == SIGCONT )
00106     {
00107         CmdApp *app = dynamic_cast<CmdApp *>(BESApp::TheApplication()) ;
00108         if( app )
00109         {
00110             CmdClient *client = app->client() ;
00111             if( client && !client->isConnected() )
00112             {
00113                 cout << BESApp::TheApplication()->appName()
00114                      << ": No response, server may be down or "
00115                      << "busy with another incoming connection. exiting!\n" ;
00116                 exit( 1 ) ;
00117             }
00118         }
00119     }
00120 }
00121 
00122 void
00123 CmdApp::signalInterrupt( int sig )
00124 {
00125     if( sig == SIGINT )
00126     {
00127         cout << BESApp::TheApplication()->appName()
00128              << ": Please type exit to terminate the session" << endl ;
00129     }
00130     if( signal( SIGINT, CmdApp::signalInterrupt ) == SIG_ERR )
00131     {
00132         cerr << BESApp::TheApplication()->appName()
00133              << ": Could not re-register signal\n" ;
00134     }
00135 }
00136 
00137 void
00138 CmdApp::signalTerminate( int sig )
00139 {
00140     if( sig == SIGTERM )
00141     {
00142         cout << BESApp::TheApplication()->appName()
00143              << ": Please type exit to terminate the session" << endl ;
00144     }
00145     if( signal( SIGTERM, CmdApp::signalTerminate ) == SIG_ERR )
00146     {
00147         cerr << BESApp::TheApplication()->appName()
00148              << ": Could not re-register signal\n" ;
00149     }
00150 }
00151 
00152 void
00153 CmdApp::signalBrokenPipe( int sig )
00154 {
00155     if( sig == SIGPIPE )
00156     {
00157         cout << BESApp::TheApplication()->appName()
00158              << ": got a broken pipe, server may be down or the port invalid."
00159              << endl
00160              << "Please check parameters and try again" << endl ;
00161         CmdApp *app = dynamic_cast<CmdApp *>(BESApp::TheApplication()) ;
00162         if( app )
00163         {
00164           CmdClient *client = app->client() ;
00165           if( client )
00166             {
00167               client->brokenPipe() ;
00168               client->shutdownClient() ;
00169               delete client;
00170               client = 0;
00171             }
00172         }
00173         exit( 1 ) ;
00174     }
00175 }
00176 
00177 void
00178 CmdApp::registerSignals()
00179 {
00180     // Registering SIGCONT for connection unblocking
00181     BESDEBUG( "cmdln", "CmdApp: Registering signal SIGCONT ... " )
00182     if( signal( SIGCONT, signalCannotConnect ) == SIG_ERR )
00183     {
00184         BESDEBUG( "cmdln", "FAILED" << endl ) ;
00185         cerr << appName() << "Failed to register signal SIGCONT" << endl ;
00186         exit( 1 ) ;
00187     }
00188     BESDEBUG( "cmdln", "OK" << endl ) ;
00189 
00190     // Registering SIGINT to disable Ctrl-C from the user in order to avoid
00191     // server instability
00192     BESDEBUG( "cmdln", "CmdApp: Registering signal SIGINT ... " )
00193     if( signal( SIGINT, signalInterrupt ) == SIG_ERR )
00194     {
00195         BESDEBUG( "cmdln", "FAILED" << endl ) ;
00196         cerr << appName() << "Failed to register signal SIGINT" << endl ;
00197         exit( 1 ) ;
00198     }
00199     BESDEBUG( "cmdln", "OK" << endl ) ;
00200 
00201     // Registering SIGTERM to disable kill from the user in order to avoid
00202     // server instability
00203     BESDEBUG( "cmdln", "CmdApp: Registering signal SIGTERM ... " )
00204     if( signal( SIGTERM, signalTerminate ) == SIG_ERR )
00205     {
00206         BESDEBUG( "cmdln", "FAILED" << endl ) ;
00207         cerr << appName() << "Failed to register signal SIGTERM" << endl ;
00208         exit( 1 ) ;
00209     }
00210     BESDEBUG( "cmdln", "OK" << endl ) ;
00211 
00212     // Registering SIGPIE for broken pipes managment.
00213     BESDEBUG( "cmdln", "CmdApp: Registering signal SIGPIPE ... " )
00214     if( signal( SIGPIPE, CmdApp::signalBrokenPipe ) == SIG_ERR )
00215     {
00216         BESDEBUG( "cmdln", "FAILED" << endl ) ;
00217         cerr << appName() << "Failed to register signal SIGPIPE" << endl ;
00218         exit( 1 ) ;
00219     }
00220     BESDEBUG( "cmdln", "OK" << endl ) ;
00221 }
00222 
00223 int
00224 CmdApp::initialize( int argc, char **argv )
00225 {
00226     int retVal = BESBaseApp::initialize( argc, argv ) ;
00227     if( retVal != 0 )
00228         return retVal ;
00229 
00230     string portStr = "" ;
00231     string outputStr = "" ;
00232     string inputStr = "" ;
00233     string timeoutStr = "" ;
00234     string repeatStr = "" ;
00235 
00236     bool badUsage = false ;
00237 
00238     int c ;
00239 
00240     while( ( c = getopt( argc, argv, "?vd:h:p:t:u:x:f:i:r:" ) ) != EOF )
00241     {
00242         switch( c )
00243         {
00244             case 't':
00245                 timeoutStr = optarg ;
00246                 break ;
00247             case 'h':
00248                 _hostStr = optarg ;
00249                 break ;
00250             case 'd':
00251                 BESDebug::SetUp( optarg ) ;
00252                 break ;
00253             case 'v':
00254                 {
00255                     showVersion() ;
00256                     exit( 0 ) ;
00257                 }
00258                 break ;
00259             case 'p':
00260                 portStr = optarg ;
00261                 break ;  
00262             case 'u':
00263                 _unixStr = optarg ;
00264                 break ;
00265             case 'x':
00266                 _cmd = optarg ;
00267                 break ;
00268             case 'f':
00269                 outputStr = optarg ;
00270                 break ;
00271             case 'i':
00272                 inputStr = optarg ;
00273                 break ;
00274             case 'r':
00275                 repeatStr = optarg ;
00276                 break ;
00277             case '?':
00278                 {
00279                     showUsage() ;
00280                     exit( 0 ) ;
00281                 }
00282                 break ;
00283         }
00284     }
00285     if( _hostStr == "" && _unixStr == "" )
00286     {
00287         cerr << "host/port or unix socket must be specified" << endl ;
00288         badUsage = true ;
00289     }
00290 
00291     if( _hostStr != "" && _unixStr != "" )
00292     {
00293         cerr << "must specify either a host and port or a unix socket" << endl ;
00294         badUsage = true ;
00295     }
00296 
00297     if( portStr != "" && _unixStr != "" )
00298     {
00299         cerr << "must specify either a host and port or a unix socket" << endl ;
00300         badUsage = true ;
00301     }
00302 
00303     if( _hostStr != "" )
00304     {
00305         if( portStr == "" )
00306         {
00307             cout << "port must be specified when specifying a host" << endl ;
00308             badUsage = true ;
00309         }
00310         else
00311         {
00312             _portVal = atoi( portStr.c_str() ) ;
00313         }
00314     }
00315 
00316     if( timeoutStr != "" )
00317     {
00318         _timeout = atoi( timeoutStr.c_str() ) ;
00319     }
00320     else
00321     {
00322         _timeout = BES_CMDLN_DEFAULT_TIMEOUT ;
00323     }
00324 
00325     if( outputStr != "" )
00326     {
00327         if( _cmd == "" && inputStr == "" )
00328         {
00329             cerr << "When specifying an output file you must either "
00330                  << "specify a command or an input file"
00331                  << endl ;
00332             badUsage = true ;
00333         }
00334         else if( _cmd != "" && inputStr != "" )
00335         {
00336             cerr << "You must specify either a command or an input file on "
00337                  << "the command line, not both"
00338                  << endl ;
00339             badUsage = true ;
00340         }
00341     }
00342 
00343     if( badUsage == true )
00344     {
00345         showUsage( ) ;
00346         return 1 ;
00347     }
00348 
00349     if( outputStr != "" )
00350     {
00351         _outputStrm = new ofstream( outputStr.c_str() ) ;
00352         if( !(*_outputStrm) )
00353         {
00354             cerr << "could not open the output file " << outputStr << endl ;
00355             badUsage = true ;
00356         }
00357     }
00358 
00359     if( inputStr != "" )
00360     {
00361         _inputStrm = new ifstream( inputStr.c_str() ) ;
00362         if( !(*_inputStrm) )
00363         {
00364             cerr << "could not open the input file " << inputStr << endl ;
00365             badUsage = true ;
00366         }
00367         _createdInputStrm = true ;
00368     }
00369 
00370     if( !repeatStr.empty() )
00371     {
00372         _repeat = atoi( repeatStr.c_str() ) ;
00373         if( !_repeat && repeatStr != "0" )
00374         {
00375             cerr << "repeat number invalid: " << repeatStr << endl ;
00376             badUsage = true ;
00377         }
00378         if( !_repeat )
00379         {
00380             _repeat = 1 ;
00381         }
00382     }
00383 
00384     if( badUsage == true )
00385     {
00386         showUsage( ) ;
00387         return 1 ;
00388     }
00389 
00390     registerSignals() ;
00391 
00392     BESDEBUG( "cmdln", "CmdApp: initialized settings:" << endl << *this ) ;
00393 
00394     return 0 ;
00395 }
00396 
00397 int
00398 CmdApp::run()
00399 {
00400     try
00401     {
00402         _client = new CmdClient( ) ;
00403         if( _hostStr != "" )
00404         {
00405             BESDEBUG( "cmdln", "CmdApp: Connecting to host: " << _hostStr
00406                       << " at port: " << _portVal << " ... " ) ;
00407             _client->startClient( _hostStr, _portVal, _timeout ) ;
00408         }
00409         else
00410         {
00411             BESDEBUG( "cmdln", "CmdApp: Connecting to unix socket: " << _unixStr
00412                       << " ... " ) ;
00413             _client->startClient( _unixStr, _timeout ) ;
00414         }
00415 
00416         if( _outputStrm )
00417         {
00418             _client->setOutput( _outputStrm, true ) ;
00419         }
00420         else
00421         {
00422             _client->setOutput( &cout, false ) ;
00423         }
00424         BESDEBUG( "cmdln", "OK" << endl ) ;
00425     }
00426     catch( PPTException &e )
00427     {
00428         if( _client )
00429         {
00430             _client->shutdownClient() ;
00431             delete _client ;
00432             _client = 0 ;
00433         }
00434         BESDEBUG( "cmdln", "FAILED" << endl ) ;
00435         cerr << "error starting the client" << endl ;
00436         cerr << e.getMessage() << endl ;
00437         exit( 1 ) ;
00438     }
00439 
00440     try
00441     {
00442         if( _cmd != "" )
00443         {
00444             _client->executeCommands( _cmd, _repeat ) ;
00445         }
00446         else if( _inputStrm )
00447         {
00448             _client->executeCommands( *_inputStrm, _repeat ) ;
00449         }
00450         else
00451         {
00452             _client->interact() ;
00453         }
00454     }
00455     catch( PPTException &e )
00456     {
00457         cerr << "error processing commands" << endl ;
00458         cerr << e.getMessage() << endl ;
00459     }
00460 
00461     try
00462     {
00463         BESDEBUG( "cmdln", "CmdApp: shutting down client ... " ) ;
00464         if( _client )
00465         {
00466             _client->shutdownClient() ;
00467             delete _client ;
00468             _client = 0 ;
00469         }
00470         BESDEBUG( "cmdln", "OK" << endl ) ;
00471 
00472         BESDEBUG( "cmdln", "CmdApp: closing input stream ... " ) ;
00473         if( _createdInputStrm )
00474         {
00475             _inputStrm->close() ;
00476             delete _inputStrm ;
00477             _inputStrm = 0 ;
00478         }
00479         BESDEBUG( "cmdln", "OK" << endl ) ;
00480     }
00481     catch( PPTException &e )
00482     {
00483         BESDEBUG( "cmdln", "FAILED" << endl ) ;
00484         cerr << "error closing the client" << endl ;
00485         cerr << e.getMessage() << endl ;
00486         return 1 ;
00487     }
00488 
00489     return 0 ;
00490 }
00491 
00498 void
00499 CmdApp::dump( ostream &strm ) const
00500 {
00501     strm << BESIndent::LMarg << "CmdApp::dump - ("
00502                              << (void *)this << ")" << endl ;
00503     BESIndent::Indent() ;
00504     if( _client )
00505     {
00506         strm << BESIndent::LMarg << "client: " << endl ;
00507         BESIndent::Indent() ;
00508         _client->dump( strm ) ;
00509         BESIndent::UnIndent() ;
00510     }
00511     else
00512     {
00513         strm << BESIndent::LMarg << "client: null" << endl ;
00514     }
00515     strm << BESIndent::LMarg << "host: " << _hostStr << endl ;
00516     strm << BESIndent::LMarg << "unix socket: " << _unixStr << endl ;
00517     strm << BESIndent::LMarg << "port: " << _portVal << endl ;
00518     strm << BESIndent::LMarg << "command: " << _cmd << endl ;
00519     strm << BESIndent::LMarg << "output stream: " << (void *)_outputStrm << endl ;
00520     strm << BESIndent::LMarg << "input stream: " << (void *)_inputStrm << endl ;
00521     strm << BESIndent::LMarg << "created input stream? " << _createdInputStrm << endl ;
00522     strm << BESIndent::LMarg << "timeout: " << _timeout << endl ;
00523     BESBaseApp::dump( strm ) ;
00524     BESIndent::UnIndent() ;
00525 }
00526 
00527 int
00528 main( int argc, char **argv )
00529 {
00530     CmdApp app ;
00531     return app.main( argc, argv ) ;
00532 }
00533 

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