/home/bes3soft/bes3soft/Boss/7.0.2/dist/7.0.2/Utilities/JobInfoSvc/JobInfoSvc-00-00-02/xmlrpc++0.7/src/XmlRpcServerConnection.cpp

Go to the documentation of this file.
00001 
00002 #include "XmlRpcServerConnection.h"
00003 
00004 #include "XmlRpcSocket.h"
00005 #include "XmlRpc.h"
00006 #ifndef MAKEDEPEND
00007 # include <stdio.h>
00008 # include <stdlib.h>
00009 #endif
00010 #include <cstring>
00011 
00012 using namespace XmlRpc;
00013 
00014 // Static data
00015 const char XmlRpcServerConnection::METHODNAME_TAG[] = "<methodName>";
00016 const char XmlRpcServerConnection::PARAMS_TAG[] = "<params>";
00017 const char XmlRpcServerConnection::PARAMS_ETAG[] = "</params>";
00018 const char XmlRpcServerConnection::PARAM_TAG[] = "<param>";
00019 const char XmlRpcServerConnection::PARAM_ETAG[] = "</param>";
00020 
00021 const std::string XmlRpcServerConnection::SYSTEM_MULTICALL = "system.multicall";
00022 const std::string XmlRpcServerConnection::METHODNAME = "methodName";
00023 const std::string XmlRpcServerConnection::PARAMS = "params";
00024 
00025 const std::string XmlRpcServerConnection::FAULTCODE = "faultCode";
00026 const std::string XmlRpcServerConnection::FAULTSTRING = "faultString";
00027 
00028 
00029 
00030 // The server delegates handling client requests to a serverConnection object.
00031 XmlRpcServerConnection::XmlRpcServerConnection(int fd, XmlRpcServer* server, bool deleteOnClose /*= false*/) :
00032   XmlRpcSource(fd, deleteOnClose)
00033 {
00034   XmlRpcUtil::log(2,"XmlRpcServerConnection: new socket %d.", fd);
00035   _server = server;
00036   _connectionState = READ_HEADER;
00037   _keepAlive = true;
00038 }
00039 
00040 
00041 XmlRpcServerConnection::~XmlRpcServerConnection()
00042 {
00043   XmlRpcUtil::log(4,"XmlRpcServerConnection dtor.");
00044   _server->removeConnection(this);
00045 }
00046 
00047 
00048 // Handle input on the server socket by accepting the connection
00049 // and reading the rpc request. Return true to continue to monitor
00050 // the socket for events, false to remove it from the dispatcher.
00051 unsigned
00052 XmlRpcServerConnection::handleEvent(unsigned /*eventType*/)
00053 {
00054   if (_connectionState == READ_HEADER)
00055     if ( ! readHeader()) return 0;
00056 
00057   if (_connectionState == READ_REQUEST)
00058     if ( ! readRequest()) return 0;
00059 
00060   if (_connectionState == WRITE_RESPONSE)
00061     if ( ! writeResponse()) return 0;
00062 
00063   return (_connectionState == WRITE_RESPONSE) 
00064         ? XmlRpcDispatch::WritableEvent : XmlRpcDispatch::ReadableEvent;
00065 }
00066 
00067 
00068 bool
00069 XmlRpcServerConnection::readHeader()
00070 {
00071   // Read available data
00072   bool eof;
00073   if ( ! XmlRpcSocket::nbRead(this->getfd(), _header, &eof)) {
00074     // Its only an error if we already have read some data
00075     if (_header.length() > 0)
00076       XmlRpcUtil::error("XmlRpcServerConnection::readHeader: error while reading header (%s).",XmlRpcSocket::getErrorMsg().c_str());
00077     return false;
00078   }
00079 
00080   XmlRpcUtil::log(4, "XmlRpcServerConnection::readHeader: read %d bytes.", _header.length());
00081   char *hp = (char*)_header.c_str();  // Start of header
00082   char *ep = hp + _header.length();   // End of string
00083   char *bp = 0;                       // Start of body
00084   char *lp = 0;                       // Start of content-length value
00085   char *kp = 0;                       // Start of connection value
00086 
00087   for (char *cp = hp; (bp == 0) && (cp < ep); ++cp) {
00088         if ((ep - cp > 16) && (strncasecmp(cp, "Content-length: ", 16) == 0))
00089           lp = cp + 16;
00090         else if ((ep - cp > 12) && (strncasecmp(cp, "Connection: ", 12) == 0))
00091           kp = cp + 12;
00092         else if ((ep - cp > 4) && (strncmp(cp, "\r\n\r\n", 4) == 0))
00093           bp = cp + 4;
00094         else if ((ep - cp > 2) && (strncmp(cp, "\n\n", 2) == 0))
00095           bp = cp + 2;
00096   }
00097 
00098   // If we haven't gotten the entire header yet, return (keep reading)
00099   if (bp == 0) {
00100     // EOF in the middle of a request is an error, otherwise its ok
00101     if (eof) {
00102       XmlRpcUtil::log(4, "XmlRpcServerConnection::readHeader: EOF");
00103       if (_header.length() > 0)
00104         XmlRpcUtil::error("XmlRpcServerConnection::readHeader: EOF while reading header");
00105       return false;   // Either way we close the connection
00106     }
00107     
00108     return true;  // Keep reading
00109   }
00110 
00111   // Decode content length
00112   if (lp == 0) {
00113     XmlRpcUtil::error("XmlRpcServerConnection::readHeader: No Content-length specified");
00114     return false;   // We could try to figure it out by parsing as we read, but for now...
00115   }
00116 
00117   _contentLength = atoi(lp);
00118   if (_contentLength <= 0) {
00119     XmlRpcUtil::error("XmlRpcServerConnection::readHeader: Invalid Content-length specified (%d).", _contentLength);
00120     return false;
00121   }
00122         
00123   XmlRpcUtil::log(3, "XmlRpcServerConnection::readHeader: specified content length is %d.", _contentLength);
00124 
00125   // Otherwise copy non-header data to request buffer and set state to read request.
00126   _request = bp;
00127 
00128   // Parse out any interesting bits from the header (HTTP version, connection)
00129   _keepAlive = true;
00130   if (_header.find("HTTP/1.0") != std::string::npos) {
00131     if (kp == 0 || strncasecmp(kp, "keep-alive", 10) != 0)
00132       _keepAlive = false;           // Default for HTTP 1.0 is to close the connection
00133   } else {
00134     if (kp != 0 && strncasecmp(kp, "close", 5) == 0)
00135       _keepAlive = false;
00136   }
00137   XmlRpcUtil::log(3, "KeepAlive: %d", _keepAlive);
00138 
00139 
00140   _header = ""; 
00141   _connectionState = READ_REQUEST;
00142   return true;    // Continue monitoring this source
00143 }
00144 
00145 bool
00146 XmlRpcServerConnection::readRequest()
00147 {
00148   // If we dont have the entire request yet, read available data
00149   if (int(_request.length()) < _contentLength) {
00150     bool eof;
00151     if ( ! XmlRpcSocket::nbRead(this->getfd(), _request, &eof)) {
00152       XmlRpcUtil::error("XmlRpcServerConnection::readRequest: read error (%s).",XmlRpcSocket::getErrorMsg().c_str());
00153       return false;
00154     }
00155 
00156     // If we haven't gotten the entire request yet, return (keep reading)
00157     if (int(_request.length()) < _contentLength) {
00158       if (eof) {
00159         XmlRpcUtil::error("XmlRpcServerConnection::readRequest: EOF while reading request");
00160         return false;   // Either way we close the connection
00161       }
00162       return true;
00163     }
00164   }
00165 
00166   // Otherwise, parse and dispatch the request
00167   XmlRpcUtil::log(3, "XmlRpcServerConnection::readRequest read %d bytes.", _request.length());
00168   //XmlRpcUtil::log(5, "XmlRpcServerConnection::readRequest:\n%s\n", _request.c_str());
00169 
00170   _connectionState = WRITE_RESPONSE;
00171 
00172   return true;    // Continue monitoring this source
00173 }
00174 
00175 
00176 bool
00177 XmlRpcServerConnection::writeResponse()
00178 {
00179   if (_response.length() == 0) {
00180     executeRequest();
00181     _bytesWritten = 0;
00182     if (_response.length() == 0) {
00183       XmlRpcUtil::error("XmlRpcServerConnection::writeResponse: empty response.");
00184       return false;
00185     }
00186   }
00187 
00188   // Try to write the response
00189   if ( ! XmlRpcSocket::nbWrite(this->getfd(), _response, &_bytesWritten)) {
00190     XmlRpcUtil::error("XmlRpcServerConnection::writeResponse: write error (%s).",XmlRpcSocket::getErrorMsg().c_str());
00191     return false;
00192   }
00193   XmlRpcUtil::log(3, "XmlRpcServerConnection::writeResponse: wrote %d of %d bytes.", _bytesWritten, _response.length());
00194 
00195   // Prepare to read the next request
00196   if (_bytesWritten == int(_response.length())) {
00197     _header = "";
00198     _request = "";
00199     _response = "";
00200     _connectionState = READ_HEADER;
00201   }
00202 
00203   return _keepAlive;    // Continue monitoring this source if true
00204 }
00205 
00206 // Run the method, generate _response string
00207 void
00208 XmlRpcServerConnection::executeRequest()
00209 {
00210   XmlRpcValue params, resultValue;
00211   std::string methodName = parseRequest(params);
00212   XmlRpcUtil::log(2, "XmlRpcServerConnection::executeRequest: server calling method '%s'", 
00213                     methodName.c_str());
00214 
00215   try {
00216 
00217     if ( ! executeMethod(methodName, params, resultValue) &&
00218          ! executeMulticall(methodName, params, resultValue))
00219       generateFaultResponse(methodName + ": unknown method name");
00220     else
00221       generateResponse(resultValue.toXml());
00222 
00223   } catch (const XmlRpcException& fault) {
00224     XmlRpcUtil::log(2, "XmlRpcServerConnection::executeRequest: fault %s.",
00225                     fault.getMessage().c_str()); 
00226     generateFaultResponse(fault.getMessage(), fault.getCode());
00227   }
00228 }
00229 
00230 // Parse the method name and the argument values from the request.
00231 std::string
00232 XmlRpcServerConnection::parseRequest(XmlRpcValue& params)
00233 {
00234   int offset = 0;   // Number of chars parsed from the request
00235 
00236   std::string methodName = XmlRpcUtil::parseTag(METHODNAME_TAG, _request, &offset);
00237 
00238   if (methodName.size() > 0 && XmlRpcUtil::findTag(PARAMS_TAG, _request, &offset))
00239   {
00240     int nArgs = 0;
00241     while (XmlRpcUtil::nextTagIs(PARAM_TAG, _request, &offset)) {
00242       params[nArgs++] = XmlRpcValue(_request, &offset);
00243       (void) XmlRpcUtil::nextTagIs(PARAM_ETAG, _request, &offset);
00244     }
00245 
00246     (void) XmlRpcUtil::nextTagIs(PARAMS_ETAG, _request, &offset);
00247   }
00248 
00249   return methodName;
00250 }
00251 
00252 // Execute a named method with the specified params.
00253 bool
00254 XmlRpcServerConnection::executeMethod(const std::string& methodName, 
00255                                       XmlRpcValue& params, XmlRpcValue& result)
00256 {
00257   XmlRpcServerMethod* method = _server->findMethod(methodName);
00258 
00259   if ( ! method) return false;
00260 
00261   method->execute(params, result);
00262 
00263   // Ensure a valid result value
00264   if ( ! result.valid())
00265       result = std::string();
00266 
00267   return true;
00268 }
00269 
00270 // Execute multiple calls and return the results in an array.
00271 bool
00272 XmlRpcServerConnection::executeMulticall(const std::string& methodName, 
00273                                          XmlRpcValue& params, XmlRpcValue& result)
00274 {
00275   if (methodName != SYSTEM_MULTICALL) return false;
00276 
00277   // There ought to be 1 parameter, an array of structs
00278   if (params.size() != 1 || params[0].getType() != XmlRpcValue::TypeArray)
00279     throw XmlRpcException(SYSTEM_MULTICALL + ": Invalid argument (expected an array)");
00280 
00281   int nc = params[0].size();
00282   result.setSize(nc);
00283 
00284   for (int i=0; i<nc; ++i) {
00285 
00286     if ( ! params[0][i].hasMember(METHODNAME) ||
00287          ! params[0][i].hasMember(PARAMS)) {
00288       result[i][FAULTCODE] = -1;
00289       result[i][FAULTSTRING] = SYSTEM_MULTICALL +
00290               ": Invalid argument (expected a struct with members methodName and params)";
00291       continue;
00292     }
00293 
00294     const std::string& methodName = params[0][i][METHODNAME];
00295     XmlRpcValue& methodParams = params[0][i][PARAMS];
00296 
00297     XmlRpcValue resultValue;
00298     resultValue.setSize(1);
00299     try {
00300       if ( ! executeMethod(methodName, methodParams, resultValue[0]) &&
00301            ! executeMulticall(methodName, params, resultValue[0]))
00302       {
00303         result[i][FAULTCODE] = -1;
00304         result[i][FAULTSTRING] = methodName + ": unknown method name";
00305       }
00306       else
00307         result[i] = resultValue;
00308 
00309     } catch (const XmlRpcException& fault) {
00310         result[i][FAULTCODE] = fault.getCode();
00311         result[i][FAULTSTRING] = fault.getMessage();
00312     }
00313   }
00314 
00315   return true;
00316 }
00317 
00318 
00319 // Create a response from results xml
00320 void
00321 XmlRpcServerConnection::generateResponse(std::string const& resultXml)
00322 {
00323   const char RESPONSE_1[] = 
00324     "<?xml version=\"1.0\"?>\r\n"
00325     "<methodResponse><params><param>\r\n\t";
00326   const char RESPONSE_2[] =
00327     "\r\n</param></params></methodResponse>\r\n";
00328 
00329   std::string body = RESPONSE_1 + resultXml + RESPONSE_2;
00330   std::string header = generateHeader(body);
00331 
00332   _response = header + body;
00333   XmlRpcUtil::log(5, "XmlRpcServerConnection::generateResponse:\n%s\n", _response.c_str()); 
00334 }
00335 
00336 // Prepend http headers
00337 std::string
00338 XmlRpcServerConnection::generateHeader(std::string const& body)
00339 {
00340   std::string header = 
00341     "HTTP/1.1 200 OK\r\n"
00342     "Server: ";
00343   header += XMLRPC_VERSION;
00344   header += "\r\n"
00345     "Content-Type: text/xml\r\n"
00346     "Content-length: ";
00347 
00348   char buffLen[40];
00349   sprintf(buffLen,"%d\r\n\r\n", body.size());
00350 
00351   return header + buffLen;
00352 }
00353 
00354 
00355 void
00356 XmlRpcServerConnection::generateFaultResponse(std::string const& errorMsg, int errorCode)
00357 {
00358   const char RESPONSE_1[] = 
00359     "<?xml version=\"1.0\"?>\r\n"
00360     "<methodResponse><fault>\r\n\t";
00361   const char RESPONSE_2[] =
00362     "\r\n</fault></methodResponse>\r\n";
00363 
00364   XmlRpcValue faultStruct;
00365   faultStruct[FAULTCODE] = errorCode;
00366   faultStruct[FAULTSTRING] = errorMsg;
00367   std::string body = RESPONSE_1 + faultStruct.toXml() + RESPONSE_2;
00368   std::string header = generateHeader(body);
00369 
00370   _response = header + body;
00371 }
00372 

Generated on Tue Nov 29 23:14:44 2016 for BOSS_7.0.2 by  doxygen 1.4.7