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,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 <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 "BESCmdInterface.h"
00055 #include "TheBESKeys.h"
00056 #include "BESInternalError.h"
00057 #include "ServerExitConditions.h"
00058 #include "BESUtil.h"
00059 #include "PPTStreamBuf.h"
00060 #include "BESDebug.h"
00061 
00062 BESServerHandler::BESServerHandler()
00063 {
00064     bool found = false ;
00065     _method = TheBESKeys::TheKeys()->get_key( "BES.ProcessManagerMethod", found ) ;
00066     if( _method != "multiple" && _method != "single" )
00067     {
00068         cerr << "Unable to determine method to handle clients, "
00069              << "single or multiple as defined by BES.ProcessManagerMethod"
00070              << endl ;
00071         exit( SERVER_EXIT_FATAL_CAN_NOT_START ) ;
00072     }
00073 }
00074 
00075 // *** I'm not sure that we need to fork twice. jhrg 11/14/05
00076 // The reason that we fork twice is explained in Advanced Programming in the
00077 // Unit Environment by W. Richard Stevens. In the 'multiple' case we don't
00078 // want to leave any zombie processes.
00079 void
00080 BESServerHandler::handle( Connection *c )
00081 {
00082     if(_method=="single")
00083     {
00084         execute( c ) ;
00085     }
00086     else
00087     {
00088         int main_process = getpid() ;
00089         pid_t pid ;
00090         if( ( pid = fork() ) < 0 )
00091         {
00092             string error( "fork error" ) ;
00093             const char* error_info = strerror( errno ) ;
00094             if( error_info )
00095                 error += " " + (string)error_info ;
00096             throw BESInternalError( error, __FILE__, __LINE__ ) ;
00097         }
00098         else if( pid == 0 ) /* child process */
00099         {
00100             pid_t pid1 ;
00101             // we fork twice so we do not have zombie children
00102             if( ( pid1 = fork() ) < 0 )
00103             {
00104                 // we must send a signal of inmediate termination to the
00105                 // main server 
00106                 kill( main_process, 9 ) ;
00107                 perror( "fork error" ) ;
00108                 exit( SERVER_EXIT_CHILD_SUBPROCESS_ABNORMAL_TERMINATION ) ;
00109             } 
00110             else if( pid1 == 0 ) /* child of the child */
00111             {
00112                 execute( c ) ;
00113             }
00114             sleep( 1 ) ;
00115             c->closeConnection() ;
00116             exit( SERVER_EXIT_CHILD_SUBPROCESS_NORMAL_TERMINATION ) ;
00117         }
00118         if( waitpid( pid, NULL, 0 ) != pid )
00119         {
00120             string error( "waitpid error" ) ;
00121             const char *error_info = strerror( errno ) ;
00122             if( error_info )
00123                 error += " " + (string)error_info ;
00124             throw BESInternalError( error, __FILE__, __LINE__ ) ;
00125         } 
00126         c->closeConnection() ;
00127     }
00128 }
00129 
00130 void
00131 BESServerHandler::execute( Connection *c )
00132 {
00133     ostringstream strm ;
00134     strm << "ip " << c->getSocket()->getIp() << ", port " << c->getSocket()->getPort() ;
00135     string from = strm.str() ;
00136 
00137     map<string,string> extensions ;
00138 
00139     for(;;)
00140     {
00141         ostringstream ss ;
00142 
00143         bool done = false ;
00144         while( !done )
00145             done = c->receive( extensions, &ss ) ;
00146 
00147         if( extensions["status"] == c->exit() )
00148         {
00149             c->closeConnection() ;
00150             exit( CHILD_SUBPROCESS_READY ) ;
00151         }
00152 
00153         string cmd_str = BESUtil::www2id( ss.str(), "%", "%20" ) ;
00154         BESDEBUG( "server", "BESServerHandler::execute - command = " << cmd_str << endl )
00155 
00156         /*
00157         int send_size = 0 ;
00158         socklen_t send_size_len = (socklen_t)sizeof( send_size ) ;
00159         int ret = getsockopt( c->getSocket()->getSocketDescriptor(),
00160                               SOL_SOCKET, SO_SNDBUF,
00161                               (char *)&send_size, &send_size_len ) ;
00162         cerr << "send_size = " << send_size << endl ;
00163         */
00164 
00165         PPTStreamBuf fds( c->getSocket()->getSocketDescriptor(), 4000 ) ;
00166         std::streambuf *holder ;
00167         holder = cout.rdbuf() ;
00168         cout.rdbuf( &fds ) ;
00169 
00170         BESCmdInterface cmd( cmd_str, &cout ) ;
00171         int status = cmd.execute_request( from ) ;
00172 
00173         if( status == 0 )
00174         {
00175             BESDEBUG( "server", "BESServerHandler::execute - executed successfully" << endl )
00176             fds.finish() ;
00177             cout.rdbuf( holder ) ;
00178         }
00179         else
00180         {
00181             // an error has occurred.
00182             BESDEBUG( "server", "BESServerHandler::execute - error occurred" << endl )
00183 
00184             // flush what we have in the stream to the client
00185             cout << flush ;
00186 
00187             // Send the extension status=error to the client so that it can reset.
00188             map<string,string> extensions ;
00189             extensions["status"] = "error" ;
00190             c->sendExtensions( extensions ) ;
00191 
00192             // transmit the error message. finish_with_error will transmit
00193             // the error
00194             cmd.finish_with_error( status ) ;
00195 
00196             // we are finished, send the last chunk
00197             fds.finish() ;
00198 
00199             // reset the streams buffer
00200             cout.rdbuf( holder ) ;
00201 
00202             switch (status)
00203             {
00204                 case BES_INTERNAL_FATAL_ERROR:
00205                     {
00206                         cout << "BES server " << getpid()
00207                              << ": Status not OK, dispatcher returned value "
00208                              << status << endl ;
00209                         //string toSend = "FATAL ERROR: server must exit!" ;
00210                         //c->send( toSend ) ;
00211                         c->sendExit() ;
00212                         c->closeConnection() ;
00213                         exit( CHILD_SUBPROCESS_READY ) ;
00214                     }
00215                     break;
00216                 case BES_INTERNAL_ERROR: 
00217                 case BES_SYNTAX_USER_ERROR:
00218                 case BES_FORBIDDEN_ERROR:
00219                 case BES_NOT_FOUND_ERROR:
00220                 default:
00221                     break;
00222             }
00223         }
00224     }
00225 }
00226 
00233 void
00234 BESServerHandler::dump( ostream &strm ) const
00235 {
00236     strm << BESIndent::LMarg << "BESServerHandler::dump - ("
00237                              << (void *)this << ")" << endl ;
00238     BESIndent::Indent() ;
00239     strm << BESIndent::LMarg << "server method: " << _method << endl ;
00240     BESIndent::UnIndent() ;
00241 }
00242 

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