reSIProcate/repro  9694
XmlRpcConnection.cxx
Go to the documentation of this file.
00001 #include <cassert>
00002 
00003 #include <rutil/Data.hxx>
00004 #include <rutil/Socket.hxx>
00005 #include <resip/stack/Symbols.hxx>
00006 #include <rutil/TransportType.hxx>
00007 #include <rutil/Logger.hxx>
00008 #include <resip/stack/Tuple.hxx>
00009 #include <rutil/DnsUtil.hxx>
00010 #include <rutil/ParseBuffer.hxx>
00011 
00012 #include "repro/XmlRpcServerBase.hxx"
00013 #include "repro/XmlRpcConnection.hxx"
00014 
00015 using namespace repro;
00016 using namespace resip;
00017 using namespace std;
00018 
00019 #define RESIPROCATE_SUBSYSTEM Subsystem::REPRO
00020 
00021 unsigned int XmlRpcConnection::NextConnectionId = 1;
00022 
00023 
00024 XmlRpcConnection::XmlRpcConnection(XmlRpcServerBase& server, resip::Socket sock):
00025    mXmlRcpServer(server),
00026    mConnectionId(NextConnectionId++),
00027    mNextRequestId(1),
00028    mSock(sock)
00029 {
00030         assert(mSock > 0);
00031 }
00032 
00033 
00034 XmlRpcConnection::~XmlRpcConnection()
00035 {
00036    assert(mSock > 0);
00037 #ifdef WIN32
00038    closesocket(mSock); 
00039 #else
00040    close(mSock);
00041 #endif
00042    mSock=0;
00043 }
00044 
00045       
00046 void 
00047 XmlRpcConnection::buildFdSet(FdSet& fdset)
00048 {
00049    if (!mTxBuffer.empty())
00050    {
00051       fdset.setWrite(mSock);
00052    }
00053    fdset.setRead(mSock);
00054 }
00055 
00056 
00057 bool 
00058 XmlRpcConnection::process(FdSet& fdset)
00059 {
00060    if (fdset.hasException(mSock))
00061    {
00062       int errNum = 0;
00063       int errNumSize = sizeof(errNum);
00064       getsockopt(mSock,SOL_SOCKET,SO_ERROR,(char *)&errNum,(socklen_t *)&errNumSize);
00065       InfoLog (<< "XmlRpcConnection::process: Exception reading from socket " 
00066                << (int)mSock << " code: " << errNum << "; closing connection");
00067       return false;
00068    }
00069    
00070    if (fdset.readyToRead(mSock))
00071    {
00072       bool ok = processSomeReads();
00073       if (!ok)
00074       {
00075          return false;
00076       }
00077    }
00078    if ((!mTxBuffer.empty()) && fdset.readyToWrite(mSock))
00079    {
00080       bool ok = processSomeWrites();
00081       if (!ok)
00082       {
00083          return false;
00084       }
00085    }
00086 
00087    return true;
00088 }
00089 
00090 bool
00091 XmlRpcConnection::processSomeReads()
00092 {
00093    const int bufSize = 8000;
00094    char buf[bufSize];
00095    
00096  
00097 #if defined(WIN32)
00098    int bytesRead = ::recv(mSock, buf, bufSize, 0);
00099 #else
00100    int bytesRead = ::read(mSock, buf, bufSize);
00101 #endif
00102 
00103    if (bytesRead == INVALID_SOCKET)
00104    {
00105       int e = getErrno();
00106       XmlRpcServerBase::logSocketError(e);
00107       InfoLog (<< "XmlRpcConnection::processSomeReads: Failed read on " << (int)mSock);
00108       return false;
00109    }
00110    else if(bytesRead == 0)
00111    {
00112       DebugLog (<< "XmlRpcConnection::processSomeReads: Connection closed by remote");
00113       return false;
00114    }
00115 
00116    //DebugLog (<< "XmlRpcConnection::processSomeReads: read=" << bytesRead);            
00117 
00118    mRxBuffer += Data( buf, bytesRead );
00119    
00120    while(tryParse());
00121    
00122    return true;
00123 }
00124 
00125 
00126 bool 
00127 XmlRpcConnection::tryParse()
00128 {
00129    ParseBuffer pb(mRxBuffer);
00130    Data initialTag;
00131    const char* start = pb.position();
00132    pb.skipWhitespace();
00133    pb.skipToChar('<');   
00134    if(!pb.eof())
00135    {
00136       pb.skipChar();
00137       const char* anchor = pb.position();
00138       pb.skipToChar('>');
00139       if(!pb.eof())
00140       {
00141          initialTag = pb.data(anchor);
00142          // Find end of initial tag
00143          pb.skipToChars("</" + initialTag + ">");
00144          if (!pb.eof())
00145          {
00146             pb.skipN((int)initialTag.size() + 3);  // Skip past </InitialTag>            
00147             mRequests[mNextRequestId] = pb.data(start);
00148             mXmlRcpServer.handleRequest(mConnectionId, mNextRequestId, mRequests[mNextRequestId]);
00149             mNextRequestId++;
00150 
00151             // Remove processed data from RxBuffer
00152             pb.skipWhitespace();
00153             if(!pb.eof())
00154             {
00155                anchor = pb.position();
00156                pb.skipToEnd();
00157                mRxBuffer = pb.data(anchor);
00158                return true;
00159             }
00160             else
00161             {
00162                mRxBuffer.clear();
00163             }
00164          }   
00165       }
00166    }
00167    return false;
00168 }
00169 
00170 bool
00171 XmlRpcConnection::processSomeWrites()
00172 {
00173    if (mTxBuffer.empty())
00174    {
00175       return true;
00176    }
00177    
00178    //DebugLog (<< "XmlRpcConnection::processSomeWrites: Writing " << mTxBuffer );
00179 
00180 #if defined(WIN32)
00181    int bytesWritten = ::send(mSock, mTxBuffer.data(), (int)mTxBuffer.size(), 0);
00182 #else
00183    int bytesWritten = ::write(mSock, mTxBuffer.data(), mTxBuffer.size() );
00184 #endif
00185 
00186    if (bytesWritten == INVALID_SOCKET)
00187    {
00188       int e = getErrno();
00189       XmlRpcServerBase::logSocketError(e);
00190       InfoLog (<< "XmlRpcConnection::processSomeWrites - failed write on " << mSock << " " << strerror(e));
00191 
00192       return false;
00193    }
00194    
00195    if (bytesWritten == (int)mTxBuffer.size())
00196    {
00197       DebugLog (<< "XmlRpcConnection::processSomeWrites - Wrote it all" );
00198       mTxBuffer = Data::Empty;
00199 
00200       //return false; // return false causes connection to close and clean up
00201       return true;  // keep connection up
00202    }
00203    else
00204    {
00205       Data rest = mTxBuffer.substr(bytesWritten);
00206       mTxBuffer = rest;
00207       DebugLog( << "XmlRpcConnection::processSomeWrites - Wrote " << bytesWritten << " bytes - still need to do " << mTxBuffer );
00208    }
00209    
00210    return true;
00211 }
00212 
00213 bool
00214 XmlRpcConnection::sendResponse(unsigned int requestId, const Data& responseData, bool isFinal)
00215 {
00216    RequestMap::iterator it = mRequests.find(requestId);
00217    if(it != mRequests.end())
00218    {
00219       Data& request = it->second;
00220       Data response(request.size() + responseData.size() + 30, Data::Preallocate);
00221       ParseBuffer pb(request);
00222 
00223       // A response is formed by starting with the request and inserting the 
00224       // ResponseData between <Response> tags at the same level as the <Request> tags
00225       const char* start = pb.position();      
00226       pb.skipToChars("</Request>");
00227       if (!pb.eof())
00228       {
00229          pb.skipN(10);  // Skip past </Request>
00230          pb.skipWhitespace();
00231    
00232          // Response starts with request message up to end of Request tag
00233          response = pb.data(start);
00234    
00235          // Add in response data
00236          response += Symbols::CRLF;
00237          response += "  <Response>" + responseData + "  </Response>";
00238          response += Symbols::CRLF;
00239 
00240          // Add remainder of request message
00241          start = pb.position();
00242          pb.skipToEnd();
00243          response += pb.data(start);
00244       }
00245       else
00246       {
00247          // No Request in message - just send bare response
00248          response = "<Response>" + responseData + "</Response>";
00249       }
00250       mTxBuffer += response;
00251       if(isFinal)
00252       {
00253           mRequests.erase(it);
00254       }
00255       return true;
00256    }
00257    return false;
00258 }
00259 
00260 void
00261 XmlRpcConnection::sendEvent(const Data& eventData)
00262 {
00263    mTxBuffer += eventData;
00264 }
00265 
00266 /* ====================================================================
00267  * The Vovida Software License, Version 1.0 
00268  * 
00269  * Copyright (c) 2000 Vovida Networks, Inc.  All rights reserved.
00270  * Copyright (c) 2010 SIP Spectrum, Inc.  All rights reserved.
00271  * 
00272  * Redistribution and use in source and binary forms, with or without
00273  * modification, are permitted provided that the following conditions
00274  * are met:
00275  * 
00276  * 1. Redistributions of source code must retain the above copyright
00277  *    notice, this list of conditions and the following disclaimer.
00278  * 
00279  * 2. Redistributions in binary form must reproduce the above copyright
00280  *    notice, this list of conditions and the following disclaimer in
00281  *    the documentation and/or other materials provided with the
00282  *    distribution.
00283  * 
00284  * 3. The names "VOCAL", "Vovida Open Communication Application Library",
00285  *    and "Vovida Open Communication Application Library (VOCAL)" must
00286  *    not be used to endorse or promote products derived from this
00287  *    software without prior written permission. For written
00288  *    permission, please contact vocal@vovida.org.
00289  *
00290  * 4. Products derived from this software may not be called "VOCAL", nor
00291  *    may "VOCAL" appear in their name, without prior written
00292  *    permission of Vovida Networks, Inc.
00293  * 
00294  * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED
00295  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
00296  * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE AND
00297  * NON-INFRINGEMENT ARE DISCLAIMED.  IN NO EVENT SHALL VOVIDA
00298  * NETWORKS, INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT DAMAGES
00299  * IN EXCESS OF $1,000, NOR FOR ANY INDIRECT, INCIDENTAL, SPECIAL,
00300  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
00301  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
00302  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
00303  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
00304  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
00305  * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
00306  * DAMAGE.
00307  * 
00308  * ====================================================================
00309  * 
00310  * This software consists of voluntary contributions made by Vovida
00311  * Networks, Inc. and many individuals on behalf of Vovida Networks,
00312  * Inc.  For more information on Vovida Networks, Inc., please see
00313  * <http://www.vovida.org/>.
00314  *
00315  */
00316