BESServerHandler.cc

Go to the documentation of this file.
00001 // BESServerHandler.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 <unistd.h>    // for getpid fork sleep
00034 #include <sys/types.h>
00035 #include <sys/socket.h>
00036 #include <signal.h>
00037 #include <sys/wait.h>  // for waitpid
00038 
00039 #include <cstring>
00040 #include <cstdlib>
00041 #include <cerrno>
00042 #include <sstream>
00043 #include <iostream>
00044 
00045 using std::ostringstream ;
00046 using std::cout ;
00047 using std::endl ;
00048 using std::cerr ;
00049 using std::flush ;
00050 
00051 #include "BESServerHandler.h"
00052 #include "Connection.h"
00053 #include "Socket.h"
00054 #include "BESXMLInterface.h"
00055 #include "TheBESKeys.h"
00056 #include "BESInternalError.h"
00057 #include "ServerExitConditions.h"
00058 #include "BESUtil.h"
00059 #include "PPTStreamBuf.h"
00060 #include "PPTProtocol.h"
00061 #include "BESDebug.h"
00062 #include "BESStopWatch.h"
00063 
00064 BESServerHandler::BESServerHandler()
00065 {
00066     bool found = false ;
00067     _method = TheBESKeys::TheKeys()->get_key( "BES.ProcessManagerMethod", found ) ;
00068     if( _method != "multiple" && _method != "single" )
00069     {
00070         cerr << "Unable to determine method to handle clients, "
00071              << "single or multiple as defined by BES.ProcessManagerMethod"
00072              << endl ;
00073         exit( SERVER_EXIT_FATAL_CAN_NOT_START ) ;
00074     }
00075 }
00076 
00077 // *** I'm not sure that we need to fork twice. jhrg 11/14/05
00078 // The reason that we fork twice is explained in Advanced Programming in the
00079 // Unit Environment by W. Richard Stevens. In the 'multiple' case we don't
00080 // want to leave any zombie processes.
00081 void
00082 BESServerHandler::handle( Connection *c )
00083 {
00084     if(_method=="single")
00085     {
00086         execute( c ) ;
00087     }
00088     else
00089     {
00090         int main_process = getpid() ;
00091         pid_t pid ;
00092         if( ( pid = fork() ) < 0 )
00093         {
00094             string error( "fork error" ) ;
00095             const char* error_info = strerror( errno ) ;
00096             if( error_info )
00097                 error += " " + (string)error_info ;
00098             throw BESInternalError( error, __FILE__, __LINE__ ) ;
00099         }
00100         else if( pid == 0 ) /* child process */
00101         {
00102             pid_t pid1 ;
00103             // we fork twice so we do not have zombie children
00104             if( ( pid1 = fork() ) < 0 )
00105             {
00106                 // we must send a signal of immediate termination to the
00107                 // main server
00108                 kill( main_process, 9 ) ;
00109                 perror( "fork error" ) ;
00110                 exit( SERVER_EXIT_CHILD_SUBPROCESS_ABNORMAL_TERMINATION ) ;
00111             }
00112             else if( pid1 == 0 ) /* child of the child */
00113             {
00114                 execute( c ) ;
00115             }
00116             sleep( 1 ) ;
00117             c->closeConnection() ;
00118             exit( SERVER_EXIT_CHILD_SUBPROCESS_NORMAL_TERMINATION ) ;
00119         }
00120         if( waitpid( pid, NULL, 0 ) != pid )
00121         {
00122             string error( "waitpid error" ) ;
00123             const char *error_info = strerror( errno ) ;
00124             if( error_info )
00125                 error += " " + (string)error_info ;
00126             throw BESInternalError( error, __FILE__, __LINE__ ) ;
00127         }
00128         c->closeConnection() ;
00129     }
00130 }
00131 
00132 void
00133 BESServerHandler::execute( Connection *c )
00134 {
00135     ostringstream strm ;
00136     string ip = c->getSocket()->getIp() ;
00137     strm << "ip " << ip << ", port " << c->getSocket()->getPort() ;
00138     string from = strm.str() ;
00139 
00140     map<string,string> extensions ;
00141 
00142     for(;;)
00143     {
00144         ostringstream ss ;
00145 
00146         bool done = false ;
00147         while( !done )
00148             done = c->receive( extensions, &ss ) ;
00149 
00150         if( extensions["status"] == c->exit() )
00151         {
00152             c->closeConnection() ;
00153             exit( CHILD_SUBPROCESS_READY ) ;
00154         }
00155 
00156         // This is code that was in place for the string commands. With xml
00157         // documents everything is taken care of by libxml2. This should be
00158         // happening in the Interface class before passing to the parser, if
00159         // need be. pwest 06 Feb 2009
00160         //string cmd_str = BESUtil::www2id( ss.str(), "%", "%20" ) ;
00161         string cmd_str = ss.str() ;
00162         BESDEBUG( "server", "BESServerHandler::execute - command = " << cmd_str << endl )
00163 
00164         BESStopWatch *sw = 0 ;
00165         if( BESISDEBUG( "timing" ) )
00166         {
00167             sw = new BESStopWatch() ;
00168             sw->start() ;
00169         }
00170 
00171         int descript = c->getSocket()->getSocketDescriptor() ;
00172 
00173         unsigned int bufsize = c->getSendChunkSize() ;
00174         PPTStreamBuf fds( descript, bufsize ) ;
00175         std::streambuf *holder ;
00176         holder = cout.rdbuf() ;
00177         cout.rdbuf( &fds ) ;
00178 
00179         BESXMLInterface cmd( cmd_str, &cout ) ;
00180         int status = cmd.execute_request( from ) ;
00181 
00182         if( status == 0 )
00183         {
00184             BESDEBUG( "server", "BESServerHandler::execute - executed successfully" << endl )
00185             fds.finish() ;
00186             cout.rdbuf( holder ) ;
00187 
00188             if( BESISDEBUG( "timing" ) )
00189             {
00190                 if( sw && sw->stop() )
00191                 {
00192                     BESDEBUG( "timing",
00193                               "BESServerHandler::execute - executed in "
00194                               << sw->seconds() << " seconds and "
00195                               << sw->microseconds() << " microseconds"
00196                               << endl )
00197                 }
00198                 else
00199                 {
00200                     BESDEBUG( "timing", \
00201                           "BESServerHandler::execute - no timing available" )
00202                 }
00203             }
00204         }
00205         else
00206         {
00207             // an error has occurred.
00208             BESDEBUG( "server", "BESServerHandler::execute - error occurred" << endl )
00209 
00210             // flush what we have in the stream to the client
00211             cout << flush ;
00212 
00213             // Send the extension status=error to the client so that it can reset.
00214             map<string,string> extensions ;
00215             extensions["status"] = "error" ;
00216             c->sendExtensions( extensions ) ;
00217 
00218             // transmit the error message. finish_with_error will transmit
00219             // the error
00220             cmd.finish_with_error( status ) ;
00221 
00222             // we are finished, send the last chunk
00223             fds.finish() ;
00224 
00225             // reset the streams buffer
00226             cout.rdbuf( holder ) ;
00227 
00228             switch (status)
00229             {
00230                 case BES_INTERNAL_FATAL_ERROR:
00231                     {
00232                         cout << "BES server " << getpid()
00233                              << ": Status not OK, dispatcher returned value "
00234                              << status << endl ;
00235                         //string toSend = "FATAL ERROR: server must exit!" ;
00236                         //c->send( toSend ) ;
00237                         c->sendExit() ;
00238                         c->closeConnection() ;
00239                         exit( CHILD_SUBPROCESS_READY ) ;
00240                     }
00241                     break;
00242                 case BES_INTERNAL_ERROR:
00243                 case BES_SYNTAX_USER_ERROR:
00244                 case BES_FORBIDDEN_ERROR:
00245                 case BES_NOT_FOUND_ERROR:
00246                 default:
00247                     break;
00248             }
00249         }
00250 
00251         delete sw;
00252     }
00253 }
00254 
00261 void
00262 BESServerHandler::dump( ostream &strm ) const
00263 {
00264     strm << BESIndent::LMarg << "BESServerHandler::dump - ("
00265                              << (void *)this << ")" << endl ;
00266     BESIndent::Indent() ;
00267     strm << BESIndent::LMarg << "server method: " << _method << endl ;
00268     BESIndent::UnIndent() ;
00269 }
00270 

Generated on Sat Aug 22 06:06:22 2009 for OPeNDAP Hyrax Back End Server (BES) by  doxygen 1.6.0