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>
00034 #include <sys/types.h>
00035 #include <signal.h>
00036 #include <sys/wait.h>
00037 #include <errno.h>
00038 
00039 #include <sstream>
00040 #include <iostream>
00041 
00042 using std::ostringstream ;
00043 using std::cout ;
00044 using std::endl ;
00045 using std::cerr ;
00046 using std::flush ;
00047 
00048 #include "BESServerHandler.h"
00049 #include "Connection.h"
00050 #include "Socket.h"
00051 #include "BESCmdInterface.h"
00052 #include "TheBESKeys.h"
00053 #include "BESException.h"
00054 #include "ServerExitConditions.h"
00055 #include "BESStatusReturn.h"
00056 #include "BESUtil.h"
00057 
00058 BESServerHandler::BESServerHandler()
00059 {
00060     bool found = false ;
00061     _method = TheBESKeys::TheKeys()->get_key( "BES.ProcessManagerMethod", found ) ;
00062     if( _method != "multiple" && _method != "single" )
00063     {
00064         cerr << "Unable to determine method to handle clients, "
00065              << "single or multiple as defined by BES.ProcessManagerMethod"
00066              << endl ;
00067         exit( SERVER_EXIT_FATAL_CAN_NOT_START ) ;
00068     }
00069 }
00070 
00071 // *** I'm not sure that we need to fork twice. jhrg 11/14/05
00072 // The reason that we fork twice is explained in Advanced Programming in the
00073 // Unit Environment by W. Richard Stevens. In the 'multiple' case we don't
00074 // want to leave any zombie processes.
00075 void
00076 BESServerHandler::handle( Connection *c )
00077 {
00078     if(_method=="single")
00079     {
00080         execute( c ) ;
00081     }
00082     else
00083     {
00084         int main_process = getpid() ;
00085         pid_t pid ;
00086         if( ( pid = fork() ) < 0 )
00087         {
00088             string error( "fork error" ) ;
00089             const char* error_info = strerror( errno ) ;
00090             if( error_info )
00091                 error += " " + (string)error_info ;
00092             throw BESException( error, __FILE__, __LINE__ ) ;
00093         }
00094         else if( pid == 0 ) /* child process */
00095         {
00096             pid_t pid1 ;
00097             // we fork twice so we do not have zombie children
00098             if( ( pid1 = fork() ) < 0 )
00099             {
00100                 // we must send a signal of inmediate termination to the
00101                 // main server 
00102                 kill( main_process, 9 ) ;
00103                 perror( "fork error" ) ;
00104                 exit( SERVER_EXIT_CHILD_SUBPROCESS_ABNORMAL_TERMINATION ) ;
00105             } 
00106             else if( pid1 == 0 ) /* child of the child */
00107             {
00108                 execute( c ) ;
00109             }
00110             sleep( 1 ) ;
00111             c->closeConnection() ;
00112             exit( SERVER_EXIT_CHILD_SUBPROCESS_NORMAL_TERMINATION ) ;
00113         }
00114         if( waitpid( pid, NULL, 0 ) != pid )
00115         {
00116             string error( "waitpid error" ) ;
00117             const char *error_info = strerror( errno ) ;
00118             if( error_info )
00119                 error += " " + (string)error_info ;
00120             throw BESException( error, __FILE__, __LINE__ ) ;
00121         } 
00122         c->closeConnection() ;
00123     }
00124 }
00125 
00126 void
00127 BESServerHandler::execute( Connection *c )
00128 {
00129     ostringstream strm ;
00130     strm << "ip " << c->getSocket()->getIp() << ", port " << c->getSocket()->getPort() ;
00131     string from = strm.str() ;
00132 
00133     for(;;)
00134     {
00135         ostringstream ss ;
00136 
00137         bool isDone = c->receive( &ss ) ;
00138 
00139         if( isDone )
00140         {
00141             c->closeConnection() ;
00142             exit( CHILD_SUBPROCESS_READY ) ;
00143         }
00144 
00145         int holder = dup( STDOUT_FILENO ) ;
00146         dup2( c->getSocket()->getSocketDescriptor(), STDOUT_FILENO ) ;
00147         
00148         BESCmdInterface cmd( BESUtil::www2id( ss.str(), "%", "%20" ), &cout ) ;
00149         int status = cmd.execute_request( from ) ;
00150 
00151         cout << flush ;
00152         dup2( holder, STDOUT_FILENO ) ;
00153         close( holder ) ;
00154 
00155         if( status == BES_EXECUTED_OK )
00156         {
00157             c->send( "" ) ;
00158         }
00159         else
00160         {
00161             switch (status)
00162             {
00163                 case BES_TERMINATE_IMMEDIATE:
00164                     {
00165                         cout << "BES server " << getpid()
00166                              << ": Status not OK, dispatcher returned value "
00167                              << status << endl ;
00168                         //string toSend = "FATAL ERROR: server must exit!" ;
00169                         //c->send( toSend ) ;
00170                         c->send( "" ) ;
00171                         c->sendExit() ;
00172                         c->closeConnection() ;
00173                         exit( CHILD_SUBPROCESS_READY ) ;
00174                     }
00175                     break;
00176                 case BES_DATA_HANDLER_FAILURE:
00177                     {
00178                         cout << "BES server " << getpid()
00179                              << ": Status not OK, dispatcher returned value "
00180                              << status << endl ;
00181                         //string toSend = "Data Handler Error: server my exit!" ;
00182                         //c->send( toSend ) ;
00183                         c->send( "" ) ;
00184                         c->sendExit() ;
00185                         c->closeConnection() ;
00186                         exit( CHILD_SUBPROCESS_READY ) ;
00187                     }
00188                     break;
00189                 case BES_REQUEST_INCORRECT: 
00190                 case BES_MEMORY_EXCEPTION:
00191                 case BES_CONTAINER_PERSISTENCE_ERROR:
00192                 case BES_INITIALIZATION_FILE_PROBLEM:
00193                 case BES_LOG_FILE_PROBLEM:
00194                 case BES_AGGREGATION_EXCEPTION:
00195                 case BES_FAILED_TO_EXECUTE_COMMIT_COMMAND:
00196                 default:
00197                     {
00198                         c->send( "" ) ;
00199                     }
00200                     break;
00201             }
00202         }
00203     }
00204 }
00205 
00212 void
00213 BESServerHandler::dump( ostream &strm ) const
00214 {
00215     strm << BESIndent::LMarg << "BESServerHandler::dump - ("
00216                              << (void *)this << ")" << endl ;
00217     BESIndent::Indent() ;
00218     strm << BESIndent::LMarg << "server method: " << _method << endl ;
00219     BESIndent::UnIndent() ;
00220 }
00221 

Generated on Fri Nov 30 12:06:47 2007 for OPeNDAP Back End Server (BES) by  doxygen 1.5.1