reSIProcate/stack  9694
InternalTransport.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 "resip/stack/Helper.hxx"
00012 #include "resip/stack/InternalTransport.hxx"
00013 #include "resip/stack/SipMessage.hxx"
00014 #include "rutil/DnsUtil.hxx"
00015 #include "rutil/Logger.hxx"
00016 #include "rutil/WinLeakCheck.hxx"
00017 
00018 using namespace resip;
00019 using namespace std;
00020 
00021 #define RESIPROCATE_SUBSYSTEM Subsystem::TRANSPORT
00022 
00023 
00024 InternalTransport::InternalTransport(Fifo<TransactionMessage>& rxFifo,
00025                                      int portNum,
00026                                      IpVersion version,
00027                                      const Data& interfaceObj,
00028                                      AfterSocketCreationFuncPtr socketFunc,
00029                                      Compression &compression,
00030                                      unsigned transportFlags) :
00031    Transport(rxFifo, portNum, version, interfaceObj, Data::Empty,
00032              socketFunc, compression, transportFlags),
00033    mFd(INVALID_SOCKET),
00034    mInterruptorHandle(0),
00035    mTxFifoOutBuffer(mTxFifo),
00036    mPollGrp(NULL),
00037    mPollItemHandle(NULL)
00038 {}
00039 
00040 InternalTransport::~InternalTransport()
00041 {
00042    if (mPollItemHandle)
00043       mPollGrp->delPollItem(mPollItemHandle);
00044    if (mInterruptorHandle)
00045       mPollGrp->delPollItem(mInterruptorHandle);
00046 
00047    if  (mFd != INVALID_SOCKET)
00048    {
00049       //DebugLog (<< "Closing " << mFd);
00050       closeSocket(mFd);
00051    }
00052    mFd = -2;
00053    if(!mTxFifo.empty())
00054    {
00055       WarningLog(<< "TX Fifo non-empty in ~InternalTransport! Has " << mTxFifo.size() << " messages.");
00056    }
00057 }
00058 
00059 bool
00060 InternalTransport::isFinished() const
00061 {
00062    return !mTxFifoOutBuffer.messageAvailable();
00063 }
00064 
00065 Socket
00066 InternalTransport::socket(TransportType type, IpVersion ipVer)
00067 {
00068    Socket fd;
00069    switch (type)
00070    {
00071       case UDP:
00072 #ifdef USE_IPV6
00073          fd = ::socket(ipVer == V4 ? PF_INET : PF_INET6, SOCK_DGRAM, IPPROTO_UDP);
00074 #else
00075          fd = ::socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
00076 #endif
00077          break;
00078       case TCP:
00079       case TLS:
00080 #ifdef USE_IPV6
00081          fd = ::socket(ipVer == V4 ? PF_INET : PF_INET6, SOCK_STREAM, 0);
00082 #else
00083          fd = ::socket(PF_INET, SOCK_STREAM, 0);
00084 #endif
00085          break;
00086       default:
00087          InfoLog (<< "Try to create an unsupported socket type: " << Tuple::toData(type));
00088          assert(0);
00089          throw Transport::Exception("Unsupported transport", __FILE__,__LINE__);
00090    }
00091 
00092    if ( fd == INVALID_SOCKET )
00093    {
00094       int e = getErrno();
00095       ErrLog (<< "Failed to create socket: " << strerror(e));
00096       throw Transport::Exception("Can't create TcpBaseTransport", __FILE__,__LINE__);
00097    }
00098 
00099    DebugLog (<< "Creating fd=" << fd << (ipVer == V4 ? " V4/" : " V6/") << (type == UDP ? "UDP" : "TCP"));
00100 
00101    return fd;
00102 }
00103 
00104 void
00105 InternalTransport::bind()
00106 {
00107    DebugLog (<< "Binding to " << Tuple::inet_ntop(mTuple));
00108 
00109    if ( ::bind( mFd, &mTuple.getMutableSockaddr(), mTuple.length()) == SOCKET_ERROR )
00110    {
00111       int e = getErrno();
00112       if ( e == EADDRINUSE )
00113       {
00114          error(e);
00115          ErrLog (<< mTuple << " already in use ");
00116          throw Transport::Exception("port already in use", __FILE__,__LINE__);
00117       }
00118       else
00119       {
00120          error(e);
00121          ErrLog (<< "Could not bind to " << mTuple);
00122          throw Transport::Exception("Could not use port", __FILE__,__LINE__);
00123       }
00124    }
00125 
00126    // If we bound to port 0, then query OS for assigned port number
00127    if(mTuple.getPort() == 0)
00128    {
00129       socklen_t len = sizeof(mTuple.getMutableSockaddr());
00130       if(::getsockname(mFd, &mTuple.getMutableSockaddr(), &len) == SOCKET_ERROR)
00131       {
00132          int e = getErrno();
00133          ErrLog (<<"getsockname failed, error=" << e);
00134          throw Transport::Exception("Could not query port", __FILE__,__LINE__);
00135       }
00136    }
00137 
00138    bool ok = makeSocketNonBlocking(mFd);
00139    if ( !ok )
00140    {
00141       ErrLog (<< "Could not make socket non-blocking " << port());
00142       throw Transport::Exception("Failed making socket non-blocking", __FILE__,__LINE__);
00143    }
00144 
00145    if (mSocketFunc)
00146    {
00147       mSocketFunc(mFd, transport(), __FILE__, __LINE__);
00148    }
00149 }
00150 
00151 unsigned int
00152 InternalTransport::getFifoSize() const
00153 {
00154    return mTxFifo.size();
00155 }
00156 
00157 bool
00158 InternalTransport::hasDataToSend() const
00159 {
00160    return mTxFifoOutBuffer.messageAvailable();
00161 }
00162 
00163 void
00164 InternalTransport::send(std::auto_ptr<SendData> data)
00165 {
00166    mTxFifo.add(data.release());
00167 }
00168 
00169 void
00170 InternalTransport::setPollGrp(FdPollGrp *grp)
00171 {
00172    if(!shareStackProcessAndSelect())
00173    {
00174       // If this transport does not have its own thread, it does not need to
00175       // register its SelectInterruptor because the TransportSelector will take
00176       // care of interrupting the select()/epoll() loop when necessary.
00177       if(mPollGrp && mInterruptorHandle)
00178       {
00179          mPollGrp->delPollItem(mInterruptorHandle);
00180          mInterruptorHandle=0;
00181       }
00182 
00183       if (grp)
00184       {
00185          mInterruptorHandle = grp->addPollItem(mSelectInterruptor.getReadSocket(), FPEM_Read, &mSelectInterruptor);
00186       }
00187    }
00188 
00189    mPollGrp = grp;
00190 }
00191 
00192 void 
00193 InternalTransport::poke()
00194 {
00195    // !bwc! I have tried installing mSelectInterruptor in mTxFifo, but it 
00196    // hampers performance. This seems to be because we get a significant 
00197    // performance boost from having multiple messages added to mTxFifo before 
00198    // mSelectInterruptor is invoked (this is what the TransactionController 
00199    // does; it processes at most 16 TransactionMessages, and then pokes the 
00200    // Transports). Once we have buffered producer queues in place, this 
00201    // performance concern will be rendered moot, and we'll be able to install 
00202    // the interruptor in mTxFifo.
00203    if(mTxFifoOutBuffer.messageAvailable())
00204    {
00205       // This will interrupt the select statement and cause processing of 
00206       // this new outgoing message.
00207       mSelectInterruptor.handleProcessNotification();
00208    }
00209 }
00210 
00211 
00212 /* ====================================================================
00213  * The Vovida Software License, Version 1.0
00214  *
00215  * Copyright (c) 2000 Vovida Networks, Inc.  All rights reserved.
00216  *
00217  * Redistribution and use in source and binary forms, with or without
00218  * modification, are permitted provided that the following conditions
00219  * are met:
00220  *
00221  * 1. Redistributions of source code must retain the above copyright
00222  *    notice, this list of conditions and the following disclaimer.
00223  *
00224  * 2. Redistributions in binary form must reproduce the above copyright
00225  *    notice, this list of conditions and the following disclaimer in
00226  *    the documentation and/or other materials provided with the
00227  *    distribution.
00228  *
00229  * 3. The names "VOCAL", "Vovida Open Communication Application Library",
00230  *    and "Vovida Open Communication Application Library (VOCAL)" must
00231  *    not be used to endorse or promote products derived from this
00232  *    software without prior written permission. For written
00233  *    permission, please contact vocal@vovida.org.
00234  *
00235  * 4. Products derived from this software may not be called "VOCAL", nor
00236  *    may "VOCAL" appear in their name, without prior written
00237  *    permission of Vovida Networks, Inc.
00238  *
00239  * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED
00240  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
00241  * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE AND
00242  * NON-INFRINGEMENT ARE DISCLAIMED.  IN NO EVENT SHALL VOVIDA
00243  * NETWORKS, INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT DAMAGES
00244  * IN EXCESS OF $1,000, NOR FOR ANY INDIRECT, INCIDENTAL, SPECIAL,
00245  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
00246  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
00247  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
00248  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
00249  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
00250  * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
00251  * DAMAGE.
00252  *
00253  * ====================================================================
00254  *
00255  * This software consists of voluntary contributions made by Vovida
00256  * Networks, Inc. and many individuals on behalf of Vovida Networks,
00257  * Inc.  For more information on Vovida Networks, Inc., please see
00258  * <http://www.vovida.org/>.
00259  *
00260  * vi: set shiftwidth=3 expandtab:
00261  */