OPeNDAP Hyrax Back End Server (BES)
Updated for version 3.8.3
|
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