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

Generated on Tue May 11 20:02:06 2010 for OPeNDAP Hyrax Back End Server (BES) by  doxygen 1.4.7