reSIProcate/repro  9694
XmlRpcServerBase.cxx
Go to the documentation of this file.
00001 #ifdef HAVE_CONFIG_H
00002 #include "config.h"
00003 #endif
00004 
00005 #include <cassert>
00006 
00007 #include <rutil/Data.hxx>
00008 #include <rutil/Socket.hxx>
00009 #include <resip/stack/Symbols.hxx>
00010 #include <rutil/TransportType.hxx>
00011 #include <rutil/Logger.hxx>
00012 #include <resip/stack/Tuple.hxx>
00013 #include <rutil/DnsUtil.hxx>
00014 #include <rutil/ParseBuffer.hxx>
00015 #include <resip/stack/Transport.hxx>
00016 
00017 #include "repro/XmlRpcServerBase.hxx"
00018 #include "repro/XmlRpcConnection.hxx"
00019 #include <rutil/WinLeakCheck.hxx>
00020 
00021 using namespace repro;
00022 using namespace resip;
00023 using namespace std;
00024 
00025 #define RESIPROCATE_SUBSYSTEM Subsystem::REPRO
00026 
00027 
00028 XmlRpcServerBase::XmlRpcServerBase(int port, IpVersion ipVer) :
00029    mTuple(Data::Empty,port,ipVer,TCP,Data::Empty),
00030    mSane(true)
00031 {   
00032 #ifdef USE_IPV6
00033    mFd = ::socket(ipVer == V4 ? PF_INET : PF_INET6, SOCK_STREAM, 0);
00034 #else
00035    mFd = ::socket(PF_INET, SOCK_STREAM, 0);
00036 #endif
00037    
00038    if (mFd == INVALID_SOCKET)
00039    {
00040       int e = getErrno();
00041       logSocketError(e);
00042       ErrLog(<< "XmlRpcServerBase::XmlRpcServerBase: Failed to create socket: " << strerror(e));
00043       mSane = false;
00044       return;
00045    }
00046 
00047    DebugLog (<< "XmlRpcServerBase::XmlRpcServerBase: Creating fd=" << (int)mFd 
00048              << (ipVer == V4 ? " V4/" : " V6/") );
00049       
00050    int on = 1;
00051 #if !defined(WIN32)
00052    if (::setsockopt(mFd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)))
00053 #else
00054    if (::setsockopt(mFd, SOL_SOCKET, SO_REUSEADDR, (const char*)&on, sizeof(on)))
00055 #endif
00056    {
00057       int e = getErrno();
00058       logSocketError(e);
00059       ErrLog(<< "XmlRpcServerBase::XmlRpcServerBase: Couldn't set sockoptions SO_REUSEPORT | SO_REUSEADDR: " << strerror(e));
00060       mSane = false;
00061       return;
00062    }
00063    
00064    DebugLog(<< "XmlRpcServerBase::XmlRpcServerBase: Binding to " << Tuple::inet_ntop(mTuple));
00065    
00066    if (::bind( mFd, &mTuple.getMutableSockaddr(), mTuple.length()) == SOCKET_ERROR)
00067    {
00068       int e = getErrno();
00069       logSocketError(e);
00070       if (e == EADDRINUSE)
00071       {
00072          ErrLog(<< "XmlRpcServerBase::XmlRpcServerBase: " << mTuple << " already in use ");
00073       }
00074       else
00075       {
00076          ErrLog(<< "XmlRpcServerBase::XmlRpcServerBase: Could not bind to " << mTuple);
00077       }
00078       mSane = false;
00079       return;
00080    }
00081    
00082    bool ok = makeSocketNonBlocking(mFd);
00083    if (!ok)
00084    {
00085       int e = getErrno();
00086       logSocketError(e);
00087       ErrLog(<< "XmlRpcServerBase::XmlRpcServerBase: Could not make HTTP socket non-blocking " << port);
00088       mSane = false;
00089       return;
00090    }
00091    
00092    // do the listen, seting the maximum queue size for compeletly established
00093    // sockets -- on linux, tcp_max_syn_backlog should be used for the incomplete
00094    // queue size(see man listen)
00095    int e = listen(mFd,5);
00096 
00097    if (e != 0)
00098    {
00099       int e = getErrno();
00100       InfoLog(<< "XmlRpcServerBase::XmlRpcServerBase: Failed listen " << strerror(e));
00101       mSane = false;
00102       return;
00103    }
00104 }
00105 
00106 
00107 XmlRpcServerBase::~XmlRpcServerBase()
00108 {
00109 #if defined(WIN32)
00110    closesocket(mFd);
00111 #else
00112    close(mFd); 
00113 #endif
00114    mFd = 0;
00115    ConnectionMap::iterator it = mConnections.begin();
00116    for(; it != mConnections.end(); it++)
00117    {
00118       delete it->second; 
00119    }
00120 }
00121 
00122 
00123 void 
00124 XmlRpcServerBase::buildFdSet(FdSet& fdset)
00125 { 
00126    mSelectInterruptor.buildFdSet(fdset);
00127 
00128    fdset.setRead(mFd);  // listen socket for server
00129 
00130    ConnectionMap::iterator it = mConnections.begin();
00131    for(; it != mConnections.end(); it++)
00132    {
00133       it->second->buildFdSet(fdset);
00134    }
00135 }
00136 
00137 
00138 void 
00139 XmlRpcServerBase::process(FdSet& fdset)
00140 {
00141    // Process Response fifo first
00142    while (mResponseFifo.messageAvailable())
00143    {
00144       ResponseInfo* responseInfo = mResponseFifo.getNext();
00145       if(responseInfo->getRequestId() == 0)
00146       {
00147          // This is an event and not a response - dispatch to appropriate connection or all connections
00148          if(responseInfo->getConnectionId() == 0)
00149          {
00150             ConnectionMap::iterator it = mConnections.begin();
00151             for(; it != mConnections.end(); it++)
00152             {
00153                it->second->sendEvent(responseInfo->getResponseData());
00154             }
00155          }
00156          else
00157          {
00158             ConnectionMap::iterator it = mConnections.find(responseInfo->getConnectionId());
00159             if(it != mConnections.end())
00160             {
00161                it->second->sendEvent(responseInfo->getResponseData());
00162             }
00163          }
00164       }
00165       else
00166       {
00167          // This is a response to a request - dispatch to appropriate connection
00168          ConnectionMap::iterator it = mConnections.find(responseInfo->getConnectionId());
00169          if(it != mConnections.end())
00170          {
00171             it->second->sendResponse(responseInfo->getRequestId(), responseInfo->getResponseData(), responseInfo->getIsFinal());
00172          }
00173       }
00174       delete responseInfo;
00175    }
00176 
00177    mSelectInterruptor.process(fdset);
00178 
00179    if (fdset.readyToRead(mFd))
00180    {
00181       Tuple tuple(mTuple);
00182       struct sockaddr& peer = tuple.getMutableSockaddr();
00183       socklen_t peerLen = tuple.length();
00184       Socket sock = accept( mFd, &peer, &peerLen);
00185       if (sock == SOCKET_ERROR)
00186       {
00187          int e = getErrno();
00188          switch (e)
00189          {
00190             case EWOULDBLOCK:
00191                return;
00192             default:
00193                logSocketError(e);
00194                ErrLog(<< "XmlRpcServerBase::process: Some error reading from socket: " << e);
00195          }
00196          return;
00197       }
00198       makeSocketNonBlocking(sock);
00199       
00200       if(mConnections.size() == MaxConnections)
00201       {
00202          closeOldestConnection();
00203       }
00204 
00205       XmlRpcConnection* connection = new XmlRpcConnection(*this,sock);
00206       mConnections[connection->getConnectionId()] = connection;
00207       
00208       DebugLog (<< "XmlRpcServerBase::process: Received TCP connection as connection=" << connection->getConnectionId() << " fd=" << (int)sock);
00209    }
00210 
00211    // Call process on each connection
00212    ConnectionMap::iterator it = mConnections.begin();
00213    for(; it != mConnections.end(); )
00214    {
00215       bool ok = it->second->process(fdset);
00216       if (!ok)
00217       {
00218          delete it->second;
00219          mConnections.erase(it++);
00220       }
00221       else
00222       {
00223          it++;
00224       }
00225    }
00226 }
00227 
00228 void 
00229 XmlRpcServerBase::sendResponse(unsigned int connectionId,
00230                                unsigned int requestId, 
00231                                const Data& responseData,
00232                                bool isFinal)
00233 {
00234    mResponseFifo.add(new ResponseInfo(connectionId, requestId, responseData, isFinal));
00235    mSelectInterruptor.interrupt();
00236 }
00237 
00238 void 
00239 XmlRpcServerBase::sendEvent(unsigned int connectionId,
00240                             const Data& eventData)
00241 {
00242    mResponseFifo.add(new ResponseInfo(connectionId, 0 /* requestId */, eventData, true /* isFinal */));
00243    mSelectInterruptor.interrupt();
00244 }
00245 
00246 bool 
00247 XmlRpcServerBase::isSane()
00248 {
00249   return mSane;
00250 }
00251 
00252 void
00253 XmlRpcServerBase::closeOldestConnection()
00254 {
00255    if(mConnections.empty()) return;
00256 
00257    // Oldest Connection is the one with the lowest Id
00258    ConnectionMap::iterator lowestConnectionIdIt = mConnections.end();
00259    ConnectionMap::iterator it = mConnections.begin();
00260    for(; it != mConnections.end(); it++)
00261    {
00262       if(it->second->getConnectionId() < lowestConnectionIdIt->second->getConnectionId())
00263       {
00264          lowestConnectionIdIt = it;
00265       }
00266    }
00267    delete lowestConnectionIdIt->second;
00268    mConnections.erase(lowestConnectionIdIt);
00269 }
00270 
00271 void
00272 XmlRpcServerBase::logSocketError(int e)
00273 {
00274    switch (e)
00275    {
00276       case EAGAIN:
00277          InfoLog (<< "No data ready to read" << strerror(e));
00278          break;
00279       case EINTR:
00280          InfoLog (<< "The call was interrupted by a signal before any data was read : " << strerror(e));
00281          break;
00282       case EIO:
00283          InfoLog (<< "I/O error : " << strerror(e));
00284          break;
00285       case EBADF:
00286          InfoLog (<< "fd is not a valid file descriptor or is not open for reading : " << strerror(e));
00287          break;
00288       case EINVAL:
00289          InfoLog (<< "fd is attached to an object which is unsuitable for reading : " << strerror(e));
00290          break;
00291       case EFAULT:
00292          InfoLog (<< "buf is outside your accessible address space : " << strerror(e));
00293          break;
00294 
00295 #if defined(WIN32)
00296       case WSAENETDOWN: 
00297          InfoLog (<<" The network subsystem has failed.  ");
00298          break;
00299       case WSAEFAULT:
00300          InfoLog (<<" The buf or from parameters are not part of the user address space, "
00301                    "or the fromlen parameter is too small to accommodate the peer address.  ");
00302          break;
00303       case WSAEINTR: 
00304          InfoLog (<<" The (blocking) call was canceled through WSACancelBlockingCall.  ");
00305          break;
00306       case WSAEINPROGRESS: 
00307          InfoLog (<<" A blocking Windows Sockets 1.1 call is in progress, or the "
00308                    "service provider is still processing a callback function.  ");
00309          break;
00310       case WSAEINVAL: 
00311          InfoLog (<<" The socket has not been bound with bind, or an unknown flag was specified, "
00312                    "or MSG_OOB was specified for a socket with SO_OOBINLINE enabled, "
00313                    "or (for byte stream-style sockets only) len was zero or negative.  ");
00314          break;
00315       case WSAEISCONN : 
00316          InfoLog (<<"The socket is connected. This function is not permitted with a connected socket, "
00317                   "whether the socket is connection-oriented or connectionless.  ");
00318          break;
00319       case WSAENETRESET:
00320          InfoLog (<<" The connection has been broken due to the keep-alive activity "
00321                   "detecting a failure while the operation was in progress.  ");
00322          break;
00323       case WSAENOTSOCK :
00324          InfoLog (<<"The descriptor is not a socket.  ");
00325          break;
00326       case WSAEOPNOTSUPP:
00327          InfoLog (<<" MSG_OOB was specified, but the socket is not stream-style such as type "
00328                    "SOCK_STREAM, OOB data is not supported in the communication domain associated with this socket, "
00329                    "or the socket is unidirectional and supports only send operations.  ");
00330          break;
00331       case WSAESHUTDOWN:
00332          InfoLog (<<"The socket has been shut down; it is not possible to recvfrom on a socket after "
00333                   "shutdown has been invoked with how set to SD_RECEIVE or SD_BOTH.  ");
00334          break;
00335       case WSAEMSGSIZE:
00336          InfoLog (<<" The message was too large to fit into the specified buffer and was truncated.  ");
00337          break;
00338       case WSAETIMEDOUT: 
00339          InfoLog (<<" The connection has been dropped, because of a network failure or because the "
00340                   "system on the other end went down without notice.  ");
00341          break;
00342       case WSAECONNRESET : 
00343          InfoLog (<<"Connection reset ");
00344          break;
00345 
00346            case WSAEWOULDBLOCK:
00347          DebugLog (<<"Would Block ");
00348          break;
00349 
00350       case WSAEHOSTUNREACH:
00351          InfoLog (<<"A socket operation was attempted to an unreachable host ");
00352          break;
00353       case WSANOTINITIALISED:
00354          InfoLog (<<"Either the application has not called WSAStartup or WSAStartup failed. "
00355                   "The application may be accessing a socket that the current active task does not own (that is, trying to share a socket between tasks),"
00356                   "or WSACleanup has been called too many times.  ");
00357          break;
00358       case WSAEACCES:
00359          InfoLog (<<"An attempt was made to access a socket in a way forbidden by its access permissions ");
00360          break;
00361       case WSAENOBUFS:
00362          InfoLog (<<"An operation on a socket could not be performed because the system lacked sufficient "
00363                   "buffer space or because a queue was full");
00364          break;
00365       case WSAENOTCONN:
00366          InfoLog (<<"A request to send or receive data was disallowed because the socket is not connected "
00367                   "and (when sending on a datagram socket using sendto) no address was supplied");
00368          break;
00369       case WSAECONNABORTED:
00370          InfoLog (<<"An established connection was aborted by the software in your host computer, possibly "
00371                   "due to a data transmission time-out or protocol error");
00372          break;
00373       case WSAEADDRNOTAVAIL:
00374          InfoLog (<<"The requested address is not valid in its context. This normally results from an attempt to "
00375                   "bind to an address that is not valid for the local computer");
00376          break;
00377       case WSAEAFNOSUPPORT:
00378          InfoLog (<<"An address incompatible with the requested protocol was used");
00379          break;
00380       case WSAEDESTADDRREQ:
00381          InfoLog (<<"A required address was omitted from an operation on a socket");
00382          break;
00383       case WSAENETUNREACH:
00384          InfoLog (<<"A socket operation was attempted to an unreachable network");
00385          break;
00386 
00387 #endif
00388 
00389       default:
00390          InfoLog (<< "Some other error (" << e << "): " << strerror(e));
00391          break;
00392    }
00393 }
00394 
00395 
00396 /* ====================================================================
00397  * The Vovida Software License, Version 1.0 
00398  * 
00399  * Copyright (c) 2000 Vovida Networks, Inc.  All rights reserved.
00400  * Copyright (c) 2010 SIP Spectrum, Inc.  All rights reserved.
00401  * 
00402  * Redistribution and use in source and binary forms, with or without
00403  * modification, are permitted provided that the following conditions
00404  * are met:
00405  * 
00406  * 1. Redistributions of source code must retain the above copyright
00407  *    notice, this list of conditions and the following disclaimer.
00408  * 
00409  * 2. Redistributions in binary form must reproduce the above copyright
00410  *    notice, this list of conditions and the following disclaimer in
00411  *    the documentation and/or other materials provided with the
00412  *    distribution.
00413  * 
00414  * 3. The names "VOCAL", "Vovida Open Communication Application Library",
00415  *    and "Vovida Open Communication Application Library (VOCAL)" must
00416  *    not be used to endorse or promote products derived from this
00417  *    software without prior written permission. For written
00418  *    permission, please contact vocal@vovida.org.
00419  *
00420  * 4. Products derived from this software may not be called "VOCAL", nor
00421  *    may "VOCAL" appear in their name, without prior written
00422  *    permission of Vovida Networks, Inc.
00423  * 
00424  * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED
00425  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
00426  * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE AND
00427  * NON-INFRINGEMENT ARE DISCLAIMED.  IN NO EVENT SHALL VOVIDA
00428  * NETWORKS, INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT DAMAGES
00429  * IN EXCESS OF $1,000, NOR FOR ANY INDIRECT, INCIDENTAL, SPECIAL,
00430  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
00431  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
00432  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
00433  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
00434  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
00435  * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
00436  * DAMAGE.
00437  * 
00438  * ====================================================================
00439  * 
00440  * This software consists of voluntary contributions made by Vovida
00441  * Networks, Inc. and many individuals on behalf of Vovida Networks,
00442  * Inc.  For more information on Vovida Networks, Inc., please see
00443  * <http://www.vovida.org/>.
00444  *
00445  */
00446