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

Generated on Tue Mar 4 23:13:36 2008 for OPeNDAP Back End Server (BES) by  doxygen 1.5.1