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