reSIProcate/stack  9694
Transport.cxx
Go to the documentation of this file.
00001 #if defined(HAVE_CONFIG_H)
00002 #include "config.h"
00003 #endif
00004 
00005 #include <iostream>
00006 
00007 #if defined(HAVE_SYS_SOCKIO_H)
00008 #include <sys/sockio.h>
00009 #endif
00010 
00011 #include "rutil/Socket.hxx"
00012 #include "rutil/DnsUtil.hxx"
00013 #include "rutil/Logger.hxx"
00014 #include "rutil/ParseBuffer.hxx"
00015 
00016 #include "resip/stack/ConnectionTerminated.hxx"
00017 #include "resip/stack/KeepAlivePong.hxx"
00018 #include "resip/stack/Transport.hxx"
00019 #include "resip/stack/SipMessage.hxx"
00020 #include "resip/stack/TransportFailure.hxx"
00021 #include "resip/stack/Helper.hxx"
00022 #include "resip/stack/SendData.hxx"
00023 #include "rutil/WinLeakCheck.hxx"
00024 
00025 using namespace resip;
00026 using namespace std;
00027 
00028 #define RESIPROCATE_SUBSYSTEM Subsystem::TRANSPORT
00029 
00030 Transport::Exception::Exception(const Data& msg, const Data& file, const int line) :
00031    BaseException(msg,file,line)
00032 {
00033 }
00034 
00035 Transport::Transport(Fifo<TransactionMessage>& rxFifo,
00036                      const GenericIPAddress& address,
00037                      const Data& tlsDomain,
00038                      AfterSocketCreationFuncPtr socketFunc,
00039                      Compression &compression) :
00040    mTuple(address),
00041    mHasRecordRoute(false),
00042    mKey(0),
00043    mCongestionManager(0),
00044    mStateMachineFifo(rxFifo, 8),
00045    mShuttingDown(false),
00046    mTlsDomain(tlsDomain),
00047    mSocketFunc(socketFunc),
00048    mCompression(compression),
00049    mTransportFlags(0)
00050 {
00051    mInterface = Tuple::inet_ntop(mTuple);
00052 }
00053 
00054 Transport::Transport(Fifo<TransactionMessage>& rxFifo,
00055                      int portNum,
00056                      IpVersion version,
00057                      const Data& intfc,
00058                      const Data& tlsDomain,
00059                      AfterSocketCreationFuncPtr socketFunc,
00060                      Compression &compression,
00061                      unsigned transportFlags) :
00062    mInterface(intfc),
00063    mTuple(intfc, portNum, version),
00064    mHasRecordRoute(false),
00065    mKey(0),
00066    mCongestionManager(0),
00067    mStateMachineFifo(rxFifo,8),
00068    mShuttingDown(false),
00069    mTlsDomain(tlsDomain),
00070    mSocketFunc(socketFunc),
00071    mCompression(compression),
00072    mTransportFlags(transportFlags)
00073 {
00074 }
00075 
00076 Transport::~Transport()
00077 {
00078 }
00079 
00080 void
00081 Transport::error(int e)
00082 {
00083    switch (e)
00084    {
00085       case EAGAIN:
00086          //InfoLog (<< "No data ready to read" << strerror(e));
00087          break;
00088       case EINTR:
00089          InfoLog (<< "The call was interrupted by a signal before any data was read : " << strerror(e));
00090          break;
00091       case EIO:
00092          InfoLog (<< "I/O error : " << strerror(e));
00093          break;
00094       case EBADF:
00095          InfoLog (<< "fd is not a valid file descriptor or is not open for reading : " << strerror(e));
00096          break;
00097       case EINVAL:
00098          InfoLog (<< "fd is attached to an object which is unsuitable for reading : " << strerror(e));
00099          break;
00100       case EFAULT:
00101          InfoLog (<< "buf is outside your accessible address space : " << strerror(e));
00102          break;
00103 
00104 #if defined(WIN32)
00105       case WSAENETDOWN:
00106          InfoLog (<<" The network subsystem has failed.  ");
00107          break;
00108       case WSAEFAULT:
00109          InfoLog (<<" The buf or from parameters are not part of the user address space, "
00110                    "or the fromlen parameter is too small to accommodate the peer address.  ");
00111          break;
00112       case WSAEINTR:
00113          InfoLog (<<" The (blocking) call was canceled through WSACancelBlockingCall.  ");
00114          break;
00115       case WSAEINPROGRESS:
00116          InfoLog (<<" A blocking Windows Sockets 1.1 call is in progress, or the "
00117                    "service provider is still processing a callback function.  ");
00118          break;
00119       case WSAEINVAL:
00120          InfoLog (<<" The socket has not been bound with bind, or an unknown flag was specified, "
00121                    "or MSG_OOB was specified for a socket with SO_OOBINLINE enabled, "
00122                    "or (for byte stream-style sockets only) len was zero or negative.  ");
00123          break;
00124       case WSAEISCONN :
00125          InfoLog (<<"The socket is connected. This function is not permitted with a connected socket, "
00126                   "whether the socket is connection-oriented or connectionless.  ");
00127          break;
00128       case WSAENETRESET:
00129          InfoLog (<<" The connection has been broken due to the keep-alive activity "
00130                   "detecting a failure while the operation was in progress.  ");
00131          break;
00132       case WSAENOTSOCK :
00133          InfoLog (<<"The descriptor is not a socket.  ");
00134          break;
00135       case WSAEOPNOTSUPP:
00136          InfoLog (<<" MSG_OOB was specified, but the socket is not stream-style such as type "
00137                    "SOCK_STREAM, OOB data is not supported in the communication domain associated with this socket, "
00138                    "or the socket is unidirectional and supports only send operations.  ");
00139          break;
00140       case WSAESHUTDOWN:
00141          InfoLog (<<"The socket has been shut down; it is not possible to recvfrom on a socket after "
00142                   "shutdown has been invoked with how set to SD_RECEIVE or SD_BOTH.  ");
00143          break;
00144       case WSAEMSGSIZE:
00145          InfoLog (<<" The message was too large to fit into the specified buffer and was truncated.  ");
00146          break;
00147       case WSAETIMEDOUT:
00148          InfoLog (<<" The connection has been dropped, because of a network failure or because the "
00149                   "system on the other end went down without notice.  ");
00150          break;
00151       case WSAECONNRESET :
00152          InfoLog (<<"Connection reset ");
00153          break;
00154 
00155       case WSAEWOULDBLOCK:
00156          DebugLog (<<"Would Block ");
00157          break;
00158 
00159       case WSAEHOSTUNREACH:
00160          InfoLog (<<"A socket operation was attempted to an unreachable host ");
00161          break;
00162       case WSANOTINITIALISED:
00163          InfoLog (<<"Either the application has not called WSAStartup or WSAStartup failed. "
00164                   "The application may be accessing a socket that the current active task does not own (that is, trying to share a socket between tasks),"
00165                   "or WSACleanup has been called too many times.  ");
00166          break;
00167       case WSAEACCES:
00168          InfoLog (<<"An attempt was made to access a socket in a way forbidden by its access permissions ");
00169          break;
00170       case WSAENOBUFS:
00171          InfoLog (<<"An operation on a socket could not be performed because the system lacked sufficient "
00172                   "buffer space or because a queue was full");
00173          break;
00174       case WSAENOTCONN:
00175          InfoLog (<<"A request to send or receive data was disallowed because the socket is not connected "
00176                   "and (when sending on a datagram socket using sendto) no address was supplied");
00177          break;
00178       case WSAECONNABORTED:
00179          InfoLog (<<"An established connection was aborted by the software in your host computer, possibly "
00180                   "due to a data transmission time-out or protocol error");
00181          break;
00182       case WSAEADDRNOTAVAIL:
00183          InfoLog (<<"The requested address is not valid in its context. This normally results from an attempt to "
00184                   "bind to an address that is not valid for the local computer");
00185          break;
00186       case WSAEAFNOSUPPORT:
00187          InfoLog (<<"An address incompatible with the requested protocol was used");
00188          break;
00189       case WSAEDESTADDRREQ:
00190          InfoLog (<<"A required address was omitted from an operation on a socket");
00191          break;
00192       case WSAENETUNREACH:
00193          InfoLog (<<"A socket operation was attempted to an unreachable network");
00194          break;
00195 
00196 #endif
00197 
00198       default:
00199          InfoLog (<< "Some other error (" << e << "): " << strerror(e));
00200          break;
00201    }
00202 }
00203 
00204 void
00205 Transport::flowTerminated(const Tuple& flow)
00206 {
00207    mStateMachineFifo.add(new ConnectionTerminated(flow));
00208 }
00209 
00210 void
00211 Transport::keepAlivePong(const Tuple& flow)
00212 {
00213    mStateMachineFifo.add(new KeepAlivePong(flow));
00214 }
00215 
00216 void
00217 Transport::fail(const Data& tid, TransportFailure::FailureReason reason, int subCode)
00218 {
00219    if (!tid.empty())
00220    {
00221       mStateMachineFifo.add(new TransportFailure(tid, reason, subCode));
00222    }
00223 }
00224 
00225 std::auto_ptr<SendData>
00226 Transport::makeSendData( const Tuple& dest, const Data& d, const Data& tid, const Data &sigcompId)
00227 {
00228    assert(dest.getPort() != -1);
00229    std::auto_ptr<SendData> data(new SendData(dest, d, tid, sigcompId));
00230    return data;
00231 }
00232 
00233 void
00234 Transport::makeFailedResponse(const SipMessage& msg,
00235                               int responseCode,
00236                               const char * warning)
00237 {
00238   if (msg.isResponse()) return;
00239 
00240   const Tuple& dest = msg.getSource();
00241 
00242   std::auto_ptr<SipMessage> errMsg(Helper::makeResponse(msg,
00243                                                         responseCode,
00244                                                         warning ? warning : "Original request had no Vias"));
00245 
00246   // make send data here w/ blank tid and blast it out.
00247   // encode message
00248   Data encoded;
00249   encoded.clear();
00250   DataStream encodeStream(encoded);
00251   errMsg->encode(encodeStream);
00252   encodeStream.flush();
00253   assert(!encoded.empty());
00254 
00255   InfoLog(<<"Sending response directly to " << dest << " : " << errMsg->brief() );
00256 
00257   // Calculate compartment ID for outbound message
00258   Data remoteSigcompId;
00259    setRemoteSigcompId(*errMsg,remoteSigcompId);
00260   send(std::auto_ptr<SendData>(makeSendData(dest, encoded, Data::Empty, remoteSigcompId)));
00261 }
00262 
00263 std::auto_ptr<SendData>
00264 Transport::make503(SipMessage& msg, UInt16 retryAfter)
00265 {
00266   std::auto_ptr<SendData> result;
00267   if (msg.isResponse()) return result;
00268 
00269    try
00270    {
00271       if(msg.method()==ACK)
00272       {
00273          return result;
00274       }
00275    }
00276    catch(BaseException&)
00277    {
00278       // .bwc. Parse failed on the start-line. Stop.
00279       return result;
00280    }
00281    
00282   const Tuple& dest = msg.getSource();
00283 
00284    // Calculate compartment ID for outbound message
00285    Data remoteSigcompId;
00286    setRemoteSigcompId(msg,remoteSigcompId);
00287 
00288    // .bwc. msg is completely unverified. Handle with caution.
00289    result=makeSendData(dest, Data::Empty, Data::Empty, remoteSigcompId);
00290    static const Data retryAfterHeader("Retry-After: ");
00291    Data value(retryAfter);
00292    Helper::makeRawResponse(result->data, msg, 503, retryAfterHeader+value+"\r\n");
00293 
00294   return result;
00295 }
00296 
00297 std::auto_ptr<SendData>
00298 Transport::make100(SipMessage& msg)
00299 {
00300   std::auto_ptr<SendData> result;
00301   if (msg.isResponse()) return result;
00302 
00303    try
00304    {
00305       if(msg.method()==ACK)
00306       {
00307          return result;
00308       }
00309    }
00310    catch(BaseException&)
00311    {
00312       // .bwc. Parse failed on the start-line. Stop.
00313       return result;
00314    }
00315    
00316   const Tuple& dest = msg.getSource();
00317 
00318    // Calculate compartment ID for outbound message
00319    Data remoteSigcompId;
00320    setRemoteSigcompId(msg,remoteSigcompId);
00321 
00322    // .bwc. msg is completely unverified. Handle with caution.
00323    result=makeSendData(dest, Data::Empty, Data::Empty, remoteSigcompId);
00324    Helper::makeRawResponse(result->data, msg, 100);
00325 
00326    return result;
00327 }
00328 
00329 void
00330 Transport::setRemoteSigcompId(SipMessage& msg, Data& remoteSigcompId)
00331 {
00332    if (mCompression.isEnabled())
00333    {
00334       try
00335       {
00336          const Via &topVia(msg.const_header(h_Vias).front());
00337          
00338          if(topVia.exists(p_comp) && topVia.param(p_comp) == "sigcomp")
00339          {
00340             if (topVia.exists(p_sigcompId))
00341             {
00342                remoteSigcompId = topVia.param(p_sigcompId);
00343             }
00344             else
00345             {
00346                // XXX rohc-sigcomp-sip-03 says "sent-by",
00347                // but this should probably be "received" if present,
00348                // and "sent-by" otherwise.
00349                // XXX Also, the spec is ambiguous about whether
00350                // to include the port in this identifier.
00351                remoteSigcompId = topVia.sentHost();
00352             }
00353          }
00354       }
00355       catch(BaseException&)
00356       {
00357          // ?bwc? Couldn't grab sigcomp compartment id. We don't even know if
00358          // the initial request was using sigcomp or not. 
00359          // What should we do here?
00360       }
00361    }
00362 }
00363 
00364 void
00365 Transport::stampReceived(SipMessage* message)
00366 {
00367    // set the received= and rport= parameters in the message if necessary !jf!
00368    if (message->isRequest() && message->exists(h_Vias) && !message->const_header(h_Vias).empty())
00369    {
00370       const Tuple& tuple = message->getSource();
00371       Data received = Tuple::inet_ntop(tuple);
00372           if(message->const_header(h_Vias).front().sentHost() != received)  // only add if received address is different from sent-by in Via
00373       {
00374          message->header(h_Vias).front().param(p_received) = received;
00375       }
00376       //message->header(h_Vias).front().param(p_received) = Tuple::inet_ntop(tuple);
00377       if (message->const_header(h_Vias).front().exists(p_rport))
00378       {
00379          message->header(h_Vias).front().param(p_rport).port() = tuple.getPort();
00380       }
00381    }
00382    DebugLog (<< "incoming from: " << message->getSource());
00383    StackLog (<< endl << endl << *message);
00384 }
00385 
00386 
00387 bool
00388 Transport::basicCheck(const SipMessage& msg)
00389 {
00390    resip::Data reason;
00391    if (msg.isExternal())
00392    {
00393       try
00394       {
00395          if (!Helper::validateMessage(msg,&reason))
00396          {
00397             InfoLog(<<"Message Failed basicCheck :" << msg.brief());
00398             if (msg.isRequest() && msg.method()!=ACK )
00399             {
00400                // this is VERY low-level b/c we don't have a transaction...
00401                // here we make a response to warn the offending party.
00402                makeFailedResponse(msg,400,reason.c_str());
00403             }
00404             return false;
00405          }
00406          else if (mShuttingDown && msg.isRequest() && msg.method() != ACK)
00407          {
00408             InfoLog (<< "Server has been shutdown, reject message with 503");
00409             // this is VERY low-level b/c we don't have a transaction...
00410             // here we make a response to warn the offending party.
00411             makeFailedResponse(msg, 503, "Server has been shutdown");
00412             return false;
00413          }
00414       }
00415       catch (BaseException& e)
00416       {
00417          InfoLog (<< "Cannot make failure response to badly constructed message: " << e);
00418          return false;
00419       }
00420    }
00421    return true;
00422 }
00423 
00424 void
00425 Transport::callSocketFunc(Socket sock)
00426 {
00427    if (mSocketFunc)
00428    {
00429       mSocketFunc(sock, transport(), __FILE__, __LINE__);
00430    }
00431 }
00432 
00433 void
00434 Transport::pushRxMsgUp(TransactionMessage* msg)
00435 {
00436    mStateMachineFifo.add(msg);
00437 }
00438 
00439 
00440 bool
00441 Transport::operator==(const Transport& rhs) const
00442 {
00443    return ( ( mTuple.isV4() == rhs.isV4()) &&
00444             ( port() == rhs.port()) &&
00445             ( memcmp(&boundInterface(),&rhs.boundInterface(),mTuple.length()) == 0) );
00446 }
00447 
00448 EncodeStream&
00449 resip::operator<<(EncodeStream& strm, const resip::Transport& rhs)
00450 {
00451    strm << "Transport: " << rhs.mTuple;
00452    if (!rhs.mInterface.empty()) strm << " on " << rhs.mInterface;
00453    return strm;
00454 }
00455 
00456 /* ====================================================================
00457  * The Vovida Software License, Version 1.0
00458  *
00459  * Copyright (c) 2000 Vovida Networks, Inc.  All rights reserved.
00460  *
00461  * Redistribution and use in source and binary forms, with or without
00462  * modification, are permitted provided that the following conditions
00463  * are met:
00464  *
00465  * 1. Redistributions of source code must retain the above copyright
00466  *    notice, this list of conditions and the following disclaimer.
00467  *
00468  * 2. Redistributions in binary form must reproduce the above copyright
00469  *    notice, this list of conditions and the following disclaimer in
00470  *    the documentation and/or other materials provided with the
00471  *    distribution.
00472  *
00473  * 3. The names "VOCAL", "Vovida Open Communication Application Library",
00474  *    and "Vovida Open Communication Application Library (VOCAL)" must
00475  *    not be used to endorse or promote products derived from this
00476  *    software without prior written permission. For written
00477  *    permission, please contact vocal@vovida.org.
00478  *
00479  * 4. Products derived from this software may not be called "VOCAL", nor
00480  *    may "VOCAL" appear in their name, without prior written
00481  *    permission of Vovida Networks, Inc.
00482  *
00483  * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED
00484  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
00485  * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE AND
00486  * NON-INFRINGEMENT ARE DISCLAIMED.  IN NO EVENT SHALL VOVIDA
00487  * NETWORKS, INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT DAMAGES
00488  * IN EXCESS OF $1,000, NOR FOR ANY INDIRECT, INCIDENTAL, SPECIAL,
00489  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
00490  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
00491  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
00492  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
00493  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
00494  * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
00495  * DAMAGE.
00496  *
00497  * ====================================================================
00498  *
00499  * This software consists of voluntary contributions made by Vovida
00500  * Networks, Inc. and many individuals on behalf of Vovida Networks,
00501  * Inc.  For more information on Vovida Networks, Inc., please see
00502  * <http://www.vovida.org/>.
00503  *
00504  * vi: set shiftwidth=3 expandtab:
00505  */