OPeNDAP Hyrax Back End Server (BES)
Updated for version 3.8.3
|
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 bool do_exit = false ; 00450 try 00451 { 00452 if( _cmd != "" ) 00453 { 00454 do_exit = _client->executeCommands( _cmd, _repeat ) ; 00455 } 00456 else if( _inputStrm ) 00457 { 00458 do_exit = _client->executeCommands( *_inputStrm, _repeat ) ; 00459 } 00460 else 00461 { 00462 do_exit = _client->interact() ; 00463 } 00464 } 00465 catch( BESError &e ) 00466 { 00467 cerr << "error processing commands" << endl ; 00468 cerr << e.get_message() << endl ; 00469 } 00470 00471 try 00472 { 00473 BESDEBUG( "cmdln", "CmdApp: shutting down client ... " << endl ) ; 00474 if( _client ) 00475 { 00476 // if do_exit is set, then the client has shut itself down 00477 if( !do_exit ) 00478 _client->shutdownClient() ; 00479 delete _client ; 00480 _client = 0 ; 00481 } 00482 BESDEBUG( "cmdln", "OK" << endl ) ; 00483 00484 BESDEBUG( "cmdln", "CmdApp: closing input stream ... " << endl ) ; 00485 if( _createdInputStrm ) 00486 { 00487 _inputStrm->close() ; 00488 delete _inputStrm ; 00489 _inputStrm = 0 ; 00490 } 00491 BESDEBUG( "cmdln", "OK" << endl ) ; 00492 } 00493 catch( BESError &e ) 00494 { 00495 BESDEBUG( "cmdln", "FAILED" << endl ) ; 00496 cerr << "error closing the client" << endl ; 00497 cerr << e.get_message() << endl ; 00498 return 1 ; 00499 } 00500 00501 return 0 ; 00502 } 00503 00510 void 00511 CmdApp::dump( ostream &strm ) const 00512 { 00513 strm << BESIndent::LMarg << "CmdApp::dump - (" 00514 << (void *)this << ")" << endl ; 00515 BESIndent::Indent() ; 00516 if( _client ) 00517 { 00518 strm << BESIndent::LMarg << "client: " << endl ; 00519 BESIndent::Indent() ; 00520 _client->dump( strm ) ; 00521 BESIndent::UnIndent() ; 00522 } 00523 else 00524 { 00525 strm << BESIndent::LMarg << "client: null" << endl ; 00526 } 00527 strm << BESIndent::LMarg << "host: " << _hostStr << endl ; 00528 strm << BESIndent::LMarg << "unix socket: " << _unixStr << endl ; 00529 strm << BESIndent::LMarg << "port: " << _portVal << endl ; 00530 strm << BESIndent::LMarg << "command: " << _cmd << endl ; 00531 strm << BESIndent::LMarg << "output stream: " << (void *)_outputStrm << endl ; 00532 strm << BESIndent::LMarg << "input stream: " << (void *)_inputStrm << endl ; 00533 strm << BESIndent::LMarg << "created input stream? " << _createdInputStrm << endl ; 00534 strm << BESIndent::LMarg << "timeout: " << _timeout << endl ; 00535 BESBaseApp::dump( strm ) ; 00536 BESIndent::UnIndent() ; 00537 } 00538 00539 int 00540 main( int argc, char **argv ) 00541 { 00542 CmdApp app ; 00543 return app.main( argc, argv ) ; 00544 } 00545