reSIProcate/stack  9694
Classes | Public Member Functions | Static Public Member Functions | Private Types | Private Member Functions | Private Attributes | Friends
resip::TransportSelector Class Reference

#include <TransportSelector.hxx>

Collaboration diagram for resip::TransportSelector:
Collaboration graph
[legend]

List of all members.

Classes

class  TlsTransportKey

Public Member Functions

 TransportSelector (Fifo< TransactionMessage > &fifo, Security *security, DnsStub &dnsStub, Compression &compression)
virtual ~TransportSelector ()
bool hasDataToSend () const
void shutdown ()
 Shuts down all transports.
bool isFinished () const
 Returns true if all Transports have their buffers cleared, false otherwise.
void setPollGrp (FdPollGrp *pollGrp)
 Configure a PollGrp to use (instead of buildFdSet/process) Must be called before adding any transports.
void createSelectInterruptor ()
 Called when the TransportSelector will be running in a different.
void process (FdSet &fdset)
 Calls process on all suitable transports NOTE that TransportSelector no longer handles DNSInterface NOTE not used with pollGrp.
void process ()
void buildFdSet (FdSet &fdset)
 Builds an FdSet comprised of all FDs from all suitable Transports.
void poke ()
 Causes transport process loops to be interrupted if there is stuff in their transmit fifos.
void addTransport (std::auto_ptr< Transport > transport, bool immediate)
DnsResultcreateDnsResult (DnsHandler *handler)
 jf! the problem here is that DnsResult is returned after looking
void dnsResolve (DnsResult *result, SipMessage *msg)
bool transmit (SipMessage *msg, Tuple &target, SendData *sendData=0)
 Results in msg->resolve() being called to either kick off dns resolution or to pick the next tuple and will cause the message to be encoded and via updated.
void retransmit (const SendData &msg)
 Resend to the same transport as last time.
void closeConnection (const Tuple &peer)
unsigned int sumTransportFifoSizes () const
unsigned int getTimeTillNextProcessMS ()
Fifo< TransactionMessage > & stateMacFifo ()
void registerMarkListener (MarkListener *listener)
void unregisterMarkListener (MarkListener *listener)
void setEnumSuffixes (const std::vector< Data > &suffixes)
void terminateFlow (const resip::Tuple &flow)
void enableFlowTimer (const resip::Tuple &flow)
void setCongestionManager (CongestionManager *manager)

Static Public Member Functions

static Tuple getFirstInterface (bool is_v4, TransportType type)

Private Types

typedef std::map< Tuple,
Transport * > 
ExactTupleMap
typedef std::map< Tuple,
Transport
*, Tuple::AnyInterfaceCompare
AnyInterfaceTupleMap
typedef std::map< Tuple,
Transport
*, Tuple::AnyPortCompare
AnyPortTupleMap
typedef std::map< Tuple,
Transport
*, Tuple::AnyPortAnyInterfaceCompare
AnyPortAnyInterfaceTupleMap
typedef std::map
< TlsTransportKey, Transport * > 
TlsTransportMap
typedef std::vector< Transport * > TransportList
typedef std::multimap< Tuple,
Transport
*, Tuple::AnyPortAnyInterfaceCompare
TypeToTransportMap

Private Member Functions

void addTransportInternal (std::auto_ptr< Transport > transport)
void checkTransportAddQueue ()
ConnectionfindConnection (const Tuple &dest) const
TransportfindTransportBySource (Tuple &src, const SipMessage *msg) const
TransportfindLoopbackTransportBySource (bool ignorePort, Tuple &src) const
 Search for Transport on any loopback interface matching {search}.
TransportfindTransportByDest (const Tuple &dest)
TransportfindTransportByVia (SipMessage *msg, const Tuple &dest, Tuple &src) const
 Check the msg's top Via header for a source host&port that indicates a particular Transport.
TransportfindTlsTransport (const Data &domain, TransportType type, IpVersion ipv) const
Tuple determineSourceInterface (SipMessage *msg, const Tuple &dest) const

Private Attributes

DnsInterface mDns
Fifo< TransactionMessage > & mStateMacFifo
SecuritymSecurity
ExactTupleMap mExactTransports
AnyInterfaceTupleMap mAnyInterfaceTransports
AnyPortTupleMap mAnyPortTransports
AnyPortAnyInterfaceTupleMap mAnyPortAnyInterfaceTransports
std::vector< Transport * > mTransports
TlsTransportMap mTlsTransports
TransportList mSharedProcessTransports
TransportList mHasOwnProcessTransports
TypeToTransportMap mTypeToTransportMap
Socket mSocket
Socket mSocket6
GenericIPAddress mUnspecified
GenericIPAddress mUnspecified6
CompressionmCompression
 SigComp configuration object.
osc::Stack * mSigcompStack
FdPollGrpmPollGrp
int mAvgBufferSize
Fifo< TransportmTransportsToAdd
std::auto_ptr< SelectInterruptormSelectInterruptor
FdPollItemHandle mInterruptorHandle

Friends

class TestTransportSelector
class SipStack

Detailed Description

TransportSelector has two distinct roles. The first is transmit on the best outgoing Transport for a given SipMessage based on the target's TransportType and the hints present in the topmost Via in the SipMessage. The second role is to hold all Transports added to the SipStack, and if a given Transport returns true for shareStackProcessAndSelect(), TransportSelector will include the Transport in the FdSet processing loop. If the Transport returns false for shareStackProcessAndSelect(), TransportSelector will call startOwnProcessing on Transport add.

Definition at line 52 of file TransportSelector.hxx.


Member Typedef Documentation

Definition at line 158 of file TransportSelector.hxx.

Definition at line 166 of file TransportSelector.hxx.

Definition at line 162 of file TransportSelector.hxx.

Definition at line 154 of file TransportSelector.hxx.

Definition at line 219 of file TransportSelector.hxx.

typedef std::vector<Transport*> resip::TransportSelector::TransportList [private]

Definition at line 223 of file TransportSelector.hxx.

Definition at line 227 of file TransportSelector.hxx.


Constructor & Destructor Documentation

TransportSelector::TransportSelector ( Fifo< TransactionMessage > &  fifo,
Security security,
DnsStub dnsStub,
Compression compression 
)

Definition at line 65 of file TransportSelector.cxx.

References resip::Compression::addCompressorsToStack(), DebugLog, resip::Compression::getStateHandler(), INVALID_SOCKET, resip::Compression::isEnabled(), mCompression, mSigcompStack, mUnspecified, mUnspecified6, and resip::GenericIPAddress::v4Address.

                                                                                                                                   :
   mDns(dnsStub),
   mStateMacFifo(fifo),
   mSecurity(security),
   mSocket( INVALID_SOCKET ),
   mSocket6( INVALID_SOCKET ),
   mCompression(compression),
   mSigcompStack (0),
   mPollGrp(0),
   mAvgBufferSize(1024),
   mInterruptorHandle(0)
{
   memset(&mUnspecified.v4Address, 0, sizeof(sockaddr_in));
   mUnspecified.v4Address.sin_family = AF_UNSPEC;

#ifdef USE_IPV6
   memset(&mUnspecified6.v6Address, 0, sizeof(sockaddr_in6));
   mUnspecified6.v6Address.sin6_family = AF_UNSPEC;
#endif

#ifdef USE_SIGCOMP
   if (mCompression.isEnabled())
   {
      DebugLog (<< "Compression enabled for Transport Selector");
      mSigcompStack = new osc::Stack(mCompression.getStateHandler());
      mCompression.addCompressorsToStack(mSigcompStack);
   }
   else
   {
      DebugLog (<< "Compression disabled for Transport Selector");
   }
#else
   DebugLog (<< "No compression library available");
#endif
}

Here is the call graph for this function:

TransportSelector::~TransportSelector ( ) [virtual]

Member Function Documentation

void TransportSelector::addTransport ( std::auto_ptr< Transport transport,
bool  immediate 
)
void TransportSelector::addTransportInternal ( std::auto_ptr< Transport transport) [private]

Definition at line 179 of file TransportSelector.cxx.

References resip::DnsInterface::addTransportType(), DebugLog, resip::DTLS, resip::Data::empty(), resip::Transport::getTuple(), resip::Transport::hasSpecificContact(), resip::Transport::interfaceName(), resip::Transport::ipVersion(), resip::Tuple::isAnyInterface(), mAnyInterfaceTransports, mAnyPortAnyInterfaceTransports, mAnyPortTransports, mDns, mExactTransports, mHasOwnProcessTransports, mPollGrp, mSharedProcessTransports, mTlsTransports, mTransports, mTypeToTransportMap, resip::Transport::port(), resip::Transport::setKey(), resip::Transport::setPollGrp(), resip::Transport::shareStackProcessAndSelect(), resip::TCP, resip::TLS, resip::Transport::tlsDomain(), resip::Transport::transport(), and resip::UDP.

Referenced by addTransport(), and checkTransportAddQueue().

{
   Transport* transport = autoTransport.release();
   mDns.addTransportType(transport->transport(), transport->ipVersion());

   // !bwc! This is a multimap from TransportType/IpVersion to Transport*.
   // Make _extra_ sure that no garbage goes in here.
   if(transport->transport()==TCP)
   {
      assert(dynamic_cast<TcpTransport*>(transport));
   }
#ifdef USE_SSL
   else if(transport->transport()==TLS)
   {
      assert(dynamic_cast<TlsTransport*>(transport));
   }
#endif
   else if(transport->transport()==UDP)
   {
      assert(dynamic_cast<UdpTransport*>(transport));
   }
#ifdef USE_DTLS
#ifdef USE_SSL
   else if(transport->transport()==DTLS)
   {
      assert(dynamic_cast<DtlsTransport*>(transport));
   }
#endif
#endif
   else
   {
      assert(0);
   }

   Tuple tuple(transport->interfaceName(), transport->port(),
               transport->ipVersion(), transport->transport());
   mTypeToTransportMap.insert(TypeToTransportMap::value_type(tuple,transport));

   switch (transport->transport())
   {
      case UDP:
      case TCP:
      {
         assert(mExactTransports.find(tuple) == mExactTransports.end() &&
                mAnyInterfaceTransports.find(tuple) == mAnyInterfaceTransports.end());

         DebugLog (<< "Adding transport: " << tuple);

         // Store the transport in the ANY interface maps if the tuple specifies ANY
         // interface. Store the transport in the specific interface maps if the tuple
         // specifies an interface. See TransportSelector::findTransport.
         if (transport->interfaceName().empty() ||
             transport->getTuple().isAnyInterface() ||
             transport->hasSpecificContact() )
         {
            mAnyInterfaceTransports[tuple] = transport;
            mAnyPortAnyInterfaceTransports[tuple] = transport;
         }
         else
         {
            mExactTransports[tuple] = transport;
            mAnyPortTransports[tuple] = transport;
         }
      }
      break;
      case TLS:
      case DTLS:
      {
         TlsTransportKey key(transport->tlsDomain(),transport->transport(),transport->ipVersion());
         mTlsTransports[key]=transport;
      }
      break;
      default:
         assert(0);
         break;
   }

   if (transport->shareStackProcessAndSelect())
   {
      if ( mPollGrp )
      {
         transport->setPollGrp(mPollGrp);
      }
      mSharedProcessTransports.push_back(transport);
   }
   else
   {
      mHasOwnProcessTransports.push_back(transport);
      mHasOwnProcessTransports.back()->startOwnProcessing();
   }

   mTransports.push_back(transport);
   transport->setKey((unsigned int)mTransports.size());
}

Here is the call graph for this function:

void TransportSelector::buildFdSet ( FdSet fdset)

Builds an FdSet comprised of all FDs from all suitable Transports.

Definition at line 312 of file TransportSelector.cxx.

References mSelectInterruptor, and mSharedProcessTransports.

{
   for(TransportList::iterator it = mSharedProcessTransports.begin();
       it != mSharedProcessTransports.end(); it++)
   {
      (*it)->buildFdSet(fdset);
   }
   if(mSelectInterruptor.get())
   {
      mSelectInterruptor->buildFdSet(fdset);
   }
}
void TransportSelector::checkTransportAddQueue ( ) [private]

Definition at line 371 of file TransportSelector.cxx.

References addTransportInternal(), resip::Fifo< Msg >::getNext(), and mTransportsToAdd.

Referenced by process().

{
   std::auto_ptr<Transport> t(mTransportsToAdd.getNext(-1));
   while(t.get())
   {
      addTransportInternal(t);
      t.reset(mTransportsToAdd.getNext(0));
   }
}

Here is the call graph for this function:

void TransportSelector::closeConnection ( const Tuple peer)

Definition at line 1225 of file TransportSelector.cxx.

References resip::SendData::CloseConnection, resip::SendData::command, resip::Data::Empty, findTransportByDest(), and resip::Transport::send().

Referenced by resip::TransactionState::process(), and terminateFlow().

{
   Transport* t = findTransportByDest(peer);
   if(t)
   {
      SendData* close=new SendData(peer, 
                                    resip::Data::Empty,
                                    resip::Data::Empty,
                                    resip::Data::Empty);
      close->command = SendData::CloseConnection;
      t->send(std::auto_ptr<SendData>(close));
   }
}

Here is the call graph for this function:

DnsResult * TransportSelector::createDnsResult ( DnsHandler handler)

jf! the problem here is that DnsResult is returned after looking

dcm! -- now 2-phase to fix this

Definition at line 422 of file TransportSelector.cxx.

References resip::DnsInterface::createDnsResult(), and mDns.

Referenced by resip::StatelessHandler::process(), and resip::TransactionState::sendCurrentToWire().

{
   return mDns.createDnsResult(handler);
}

Here is the call graph for this function:

void TransportSelector::createSelectInterruptor ( )

Called when the TransportSelector will be running in a different.

Definition at line 299 of file TransportSelector.cxx.

References resip::FdPollGrp::addPollItem(), FPEM_Read, mInterruptorHandle, mPollGrp, and mSelectInterruptor.

Referenced by resip::TransportSelectorThread::TransportSelectorThread().

Here is the call graph for this function:

Tuple TransportSelector::determineSourceInterface ( SipMessage msg,
const Tuple dest 
) const [private]

Definition at line 606 of file TransportSelector.cxx.

References DebugLog, resip::DTLS, ErrLog, resip::Transport::error(), resip::SipMessage::exists(), resip::getErrno(), getFirstInterface(), resip::Tuple::getMutableSockaddr(), resip::Tuple::getSockaddr(), resip::Tuple::getType(), resip::SipMessage::header(), InfoLog, INVALID_SOCKET, resip::Tuple::isAnyInterface(), resip::SipMessage::isRequest(), resip::Tuple::isV4(), len, resip::Tuple::length(), mSocket, mSocket6, mUnspecified, mUnspecified6, resip::Tuple::setPort(), resip::Tuple::setSockaddr(), resip::InternalTransport::socket(), strerror(), resip::TLS, resip::Tuple::toGenericIPAddress(), resip::UDP, resip::V4, resip::GenericIPAddress::v4Address, and resip::V6.

Referenced by transmit().

{
   assert(msg->exists(h_Vias));
   assert(!msg->header(h_Vias).empty());
   const Via& via = msg->header(h_Vias).front();

   // this case should be handled already for UDP and TCP targets
   assert( (!(msg->isRequest() && !via.sentHost().empty())) || (target.getType() == TLS || target.getType() == DTLS) );
   if (1)
   {
      Tuple source(target);
#if defined(WIN32) && !defined(NO_IPHLPAPI)
      try
      {
         GenericIPAddress addr = WinCompat::determineSourceInterface(target.toGenericIPAddress());
         source.setSockaddr(addr);
      }
      catch (WinCompat::Exception&)
      {
         ErrLog (<< "Can't find source interface to use");
         throw Transport::Exception("Can't find source interface", __FILE__, __LINE__);
      }
#else
      // !kh!
      // The connected UDP technique doesn't work all the time.
      // 1. Might not work on all implementaions as stated in UNP vol.1 8.14.
      // 2. Might not work under unspecified condition on Windows,
      //    search "getsockname" in MSDN library.
      // 3. We've experienced this issue on our production software.

      // this process will determine which interface the kernel would use to
      // send a packet to the target by making a connect call on a udp socket.
      Socket tmp = INVALID_SOCKET;
      if (target.isV4())
      {
         if (mSocket == INVALID_SOCKET)
         {
            mSocket = InternalTransport::socket(UDP, V4); // may throw
         }
         tmp = mSocket;
      }
      else
      {
         if (mSocket6 == INVALID_SOCKET)
         {
            mSocket6 = InternalTransport::socket(UDP, V6); // may throw
         }
         tmp = mSocket6;
      }

      int ret = connect(tmp,&target.getSockaddr(), target.length());
      if (ret < 0)
      {
         int e = getErrno();
         Transport::error( e );
         InfoLog(<< "Unable to route to " << target << " : [" << e << "] " << strerror(e) );
         throw Transport::Exception("Can't find source address for Via", __FILE__,__LINE__);
      }

      socklen_t len = source.length();
      ret = getsockname(tmp,&source.getMutableSockaddr(), &len);
      if (ret < 0)
      {
         int e = getErrno();
         Transport::error(e);
         InfoLog(<< "Can't determine name of socket " << target << " : " << strerror(e) );
         throw Transport::Exception("Can't find source address for Via", __FILE__,__LINE__);
      }

      // !kh! test if connected UDP technique results INADDR_ANY, i.e. 0.0.0.0.
      // if it does, assume the first avaiable interface.
      if(source.isV4())
      {
         long src = (reinterpret_cast<const sockaddr_in*>(&source.getSockaddr())->sin_addr.s_addr);
         if(src == INADDR_ANY)
         {
            InfoLog(<< "Connected UDP failed to determine source address, use first address instaed.");
            source = getFirstInterface(true, target.getType());
         }
      }
      else  // IPv6
      {
//should never reach here in WIN32 w/ V6 support
#if defined(USE_IPV6) && !defined(WIN32)
         if (source.isAnyInterface())  
         {
            source = getFirstInterface(false, target.getType());
         }
# endif
      }
      // Unconnect.
      // !jf! This is necessary, but I am not sure what we can do if this
      // fails. I'm not sure the stack can recover from this error condition.
      if (target.isV4())
      {
         ret = connect(mSocket,
                       (struct sockaddr*)&mUnspecified.v4Address,
                       sizeof(mUnspecified.v4Address));
      }
#ifdef USE_IPV6
      else
      {
         ret = connect(mSocket6,
                       (struct sockaddr*)&mUnspecified6.v6Address,
                       sizeof(mUnspecified6.v6Address));
      }
#else
      else
      {
         assert(0);
      }
#endif

      if ( ret<0 )
      {
         int e =  getErrno();
         //.dcm. OS X 10.5 workaround, we could #ifdef for specific OS X version.
         if  (!(e ==EAFNOSUPPORT || e == EADDRNOTAVAIL))
         {
            ErrLog(<< "Can't disconnect socket :  " << strerror(e) );
            Transport::error(e);
            throw Transport::Exception("Can't disconnect socket", __FILE__,__LINE__);
         }
      }
#endif

      // This is the port that the request will get sent out from. By default,
      // this value will be 0, since the Helper that creates the request will not
      // assign it. In this case, the stack will pick an arbitrary (but appropriate)
      // transport. If it is non-zero, it will only match transports that are bound to
      // the specified port (and fail if none are available)

      if(msg->isRequest())
      {
         source.setPort(via.sentPort());
      }
      else
      {
         source.setPort(0);
      }

      DebugLog (<< "Looked up source for destination: " << target
                << " -> " << source
                << " sent-by=" << via.sentHost()
                << " sent-port=" << via.sentPort());

      return source;
   }
}

Here is the call graph for this function:

void TransportSelector::dnsResolve ( DnsResult result,
SipMessage msg 
)

Definition at line 428 of file TransportSelector.cxx.

References resip::SipMessage::const_header(), DebugLog, ErrLog, resip::SipMessage::exists(), resip::SipMessage::getForceTarget(), resip::SipMessage::hasForceTarget(), resip::SipMessage::isRequest(), resip::SipMessage::isResponse(), resip::DnsInterface::lookup(), mDns, resip::SipMessage::setForceTarget(), and resip::RequestLine::uri().

Referenced by resip::StatelessHandler::process(), and resip::TransactionState::sendCurrentToWire().

{
   // Picking the target destination:
   //   - for request, use forced target if set
   //     otherwise use loose routing behaviour (route or, if none, request-uri)
   //   - for response, use forced target if set, otherwise look at via

   if (msg->isRequest())
   {
      // If this is an ACK we need to fix the tid to reflect that
      if (msg->hasForceTarget())
      {
         //DebugLog(<< "!ah! RESOLVING request with force target : " << msg->getForceTarget() );
         mDns.lookup(result, msg->getForceTarget());
      }
      else if (msg->exists(h_Routes) && !msg->const_header(h_Routes).empty())
      {
         // put this into the target, in case the send later fails, so we don't
         // lose the target
         msg->setForceTarget(msg->const_header(h_Routes).front().uri());
         DebugLog (<< "Looking up dns entries (from route) for " << msg->getForceTarget());
         mDns.lookup(result, msg->getForceTarget());
      }
      else
      {
         DebugLog (<< "Looking up dns entries for " << msg->const_header(h_RequestLine).uri());
         mDns.lookup(result, msg->const_header(h_RequestLine).uri());
      }
   }
   else if (msg->isResponse())
   {
      ErrLog(<<"unimplemented response dns");
      assert(0);
   }
   else
   {
      assert(0);
   }
}

Here is the call graph for this function:

void TransportSelector::enableFlowTimer ( const resip::Tuple flow)

Definition at line 1272 of file TransportSelector.cxx.

References resip::SendData::command, resip::Data::Empty, resip::SendData::EnableFlowTimer, findTransportByDest(), and resip::Transport::send().

Referenced by resip::TransactionState::process().

{
   Transport* t = findTransportByDest(flow);
   if(t)
   {
      SendData* enableFlowTimer=new SendData(flow, 
                                    resip::Data::Empty,
                                    resip::Data::Empty,
                                    resip::Data::Empty);
      enableFlowTimer->command = SendData::EnableFlowTimer;
      t->send(std::auto_ptr<SendData>(enableFlowTimer));
   }
}

Here is the call graph for this function:

Connection* resip::TransportSelector::findConnection ( const Tuple dest) const [private]
Transport * TransportSelector::findLoopbackTransportBySource ( bool  ignorePort,
Tuple search 
) const [private]

Search for Transport on any loopback interface matching {search}.

WATCHOUT: This is O(N) walk thru (nearly) all transports.

Definition at line 1320 of file TransportSelector.cxx.

References DebugLog, mExactTransports, resip::V4, and resip::V6.

Referenced by findTransportBySource().

{
   //When we are sending to a loopback address, the kernel makes an
   //(effectively) arbitrary choice of which loopback address to send
   //from. (Since any loopback address can be used to send to any other
   //loopback address) This choice may not agree with our idea of what
   //address we should be sending from, so we need to just choose the
   //loopback address we like, and ignore what the kernel told us to do.
   ExactTupleMap::const_iterator i;
   for (i=mExactTransports.begin();i != mExactTransports.end();i++)
   {
      DebugLog(<<"search: " << search << " elem: " << i->first);
      if(i->first.ipVersion()==V4)
      {
         //Compare only the first byte (the 127)
         if(i->first.isEqualWithMask(search,8,ignorePort))
         {
            search=i->first;
            DebugLog(<<"Match!");
            return i->second;
         }
      }
#ifdef USE_IPV6
      else if(i->first.ipVersion()==V6)
      {
         //What to do?
      }
#endif
      else
      {
         assert(0);
      }
   }
   
   return 0;
} // of findLoopbackTransport
Transport * TransportSelector::findTlsTransport ( const Data domain,
resip::TransportType  type,
resip::IpVersion  version 
) const [private]

Definition at line 1453 of file TransportSelector.cxx.

References DebugLog, resip::DTLS, resip::Data::Empty, mTlsTransports, and resip::TLS.

Referenced by findTransportBySource().

{
   assert(type==TLS || type==DTLS);
   DebugLog (<< "Searching for " << ((type==TLS) ? "TLS" : "DTLS") << " transport for domain='"
                  << domainname << "'" << " have " << mTlsTransports.size());

   if (domainname == Data::Empty)
   {
      for(TlsTransportMap::const_iterator i=mTlsTransports.begin();
            i!=mTlsTransports.end();++i)
      {
         if(i->first.mType==type && i->first.mVersion==version)
         {
            DebugLog(<<"Found a default transport.");
            return i->second;
         }
      }
   }
   else
   {
      TlsTransportKey key(domainname,type,version);

      TlsTransportMap::const_iterator i=mTlsTransports.find(key);

      if(i!=mTlsTransports.end())
      {
         DebugLog(<< "Found a transport.");
         return i->second;
      }
   }

   DebugLog(<<"No transport found.");
   return 0;
}
Transport * TransportSelector::findTransportByDest ( const Tuple dest) [private]

Definition at line 1287 of file TransportSelector.cxx.

References mTransports, mTypeToTransportMap, and resip::Tuple::transportKey.

Referenced by closeConnection(), enableFlowTimer(), retransmit(), and transmit().

{
   if(target.transportKey)
   {
      if(target.transportKey <= mTransports.size())
      {
         return mTransports[target.transportKey-1];
      }
   }
   else
   {
      std::pair<TypeToTransportMap::iterator, TypeToTransportMap::iterator> range(mTypeToTransportMap.equal_range(target));

      if(range.first != range.second) // At least one match
      {
         TypeToTransportMap::iterator i=range.first;
         ++i;
         if(i==range.second) // Exactly one match
         {
            return range.first->second;
         }
      }
   }

   // .bwc. No luck here. Maybe findTransportBySource will end up working.
   return 0;
}
Transport * TransportSelector::findTransportBySource ( Tuple src,
const SipMessage msg 
) const [private]

Definition at line 1358 of file TransportSelector.cxx.

References DebugLog, resip::DTLS, resip::Data::empty(), findLoopbackTransportBySource(), findTlsTransport(), resip::Tuple::getPort(), resip::SipMessage::getTlsDomain(), resip::Tuple::getType(), resip::Inserter(), resip::Tuple::ipVersion(), resip::Tuple::isLoopback(), mAnyInterfaceTransports, mAnyPortAnyInterfaceTransports, mAnyPortTransports, mExactTransports, resip::TLS, and WarningLog.

Referenced by findTransportByVia(), and transmit().

{
   DebugLog(<< "findTransportBySource(" << search << ")");

   if(msg && 
      !msg->getTlsDomain().empty() && 
      (search.getType()==TLS || search.getType()==DTLS))
   {
      // We should not be willing to attempt sending on a TLS/DTLS transport 
      // that does not have the cert we're attempting to use, even if the 
      // IP/port/proto match. If we have not specified which identity we want
      // to use, then proceed with the code below.
      return findTlsTransport(msg->getTlsDomain(),search.getType(),search.ipVersion());
   }

   bool ignorePort = (search.getPort() == 0);
   DebugLog(<< "should port be ignored: " << ignorePort);

   if (!ignorePort)
   {
      // 1. search for matching port on a specific interface
      {
         ExactTupleMap::const_iterator i = mExactTransports.find(search);
         if (i != mExactTransports.end())
         {
            DebugLog(<< "findTransport (exact) => " << *(i->second));
            return i->second;
         }
      }

      // 2. search for matching port on any loopback interface
      if (search.isLoopback())
      {
         Transport *trans=findLoopbackTransportBySource( /*ignorePort*/false, search);
         if (trans)
         {
            return trans;
         }
      }

      // 3. search for specific port on ANY interface
      {
         AnyInterfaceTupleMap::const_iterator i = mAnyInterfaceTransports.find(search);
         if (i != mAnyInterfaceTransports.end())
         {
            DebugLog(<< "findTransport (any interface) => " << *(i->second));
            return i->second;
         }
      }
   }
   else
   {
      // 1. search for ANY port on specific interface
      {
         AnyPortTupleMap::const_iterator i = mAnyPortTransports.find(search);
         if (i != mAnyPortTransports.end())
         {
            DebugLog(<< "findTransport (any port, specific interface) => " << *(i->second));
            return i->second;
         }
      }

      // 2. search for ANY port on any loopback interface
      if (search.isLoopback())
      {
         Transport *trans = findLoopbackTransportBySource( /*ignorePort*/true, search);
         if (trans)
         {
            return trans;
         }
      }

      // 3. search for ANY port on ANY interface
      {
         //CerrLog(<< "Trying AnyPortAnyInterfaceTupleMap " << mAnyPortAnyInterfaceTransports.size());
         AnyPortAnyInterfaceTupleMap::const_iterator i = mAnyPortAnyInterfaceTransports.find(search);
         if (i != mAnyPortAnyInterfaceTransports.end())
         {
            DebugLog(<< "findTransport (any port, any interface) => " << *(i->second));
            return i->second;
         }
      }
   }

   DebugLog (<< "Exact interface / Specific port: " << Inserter(mExactTransports));
   DebugLog (<< "Any interface / Specific port: " << Inserter(mAnyInterfaceTransports));
   DebugLog (<< "Exact interface / Any port: " << Inserter(mAnyPortTransports));
   DebugLog (<< "Any interface / Any port: " << Inserter(mAnyPortAnyInterfaceTransports));

   WarningLog(<< "Can't find matching transport " << search);
   return 0;
}

Here is the call graph for this function:

Transport * TransportSelector::findTransportByVia ( SipMessage msg,
const Tuple target,
Tuple source 
) const [private]

Check the msg's top Via header for a source host&port that indicates a particular Transport.

Do NOT do this for a response, as it would allow malicious downstream to insert bogus host in via header that we would then use.

Definition at line 559 of file TransportSelector.cxx.

References resip::LazyParser::clear(), resip::SipMessage::const_header(), resip::SipMessage::exists(), findTransportBySource(), resip::Tuple::getPort(), resip::Tuple::getType(), resip::SipMessage::header(), resip::Tuple::ipVersion(), resip::Tuple::isAnyInterface(), resip::Tuple::mFlowKey, resip::Transport::port(), resip::Tuple::setPort(), resip::toTransportType(), and WarningLog.

Referenced by transmit().

{
   assert(msg->exists(h_Vias));
   assert(!msg->const_header(h_Vias).empty());
   const Via& via = msg->const_header(h_Vias).front();

   if (via.sentHost().empty() && via.transport().empty())
   {
      return 0;
   }

   // XXX: Is there better way to do below (without the copy)?
   source = Tuple(via.sentHost(), via.sentPort(), target.ipVersion(), 
      via.transport().empty() ? target.getType() : toTransportType(via.transport()));  // Transport type is pre-populated in via, lock to it

   if ( target.mFlowKey!=0 && (source.getPort()==0 || source.isAnyInterface()) )
   {
      WarningLog(<< "Sending request with incomplete Via header and FlowKey."
        <<" This code no smart enough to pick the correct Transport."
        <<" Via=" << via);
      assert(0);
   }
   if ( source.isAnyInterface() )
   {
      // INADDR_ANY cannot go out on the wire, so remove it from
      // via header now.
      // transmit() will later use determineSourceInterface() to
      // get the actual interface to populate the Contact & Via headers.
      // Not sure if we should support this case or just assert.
      // .gh. This should be supported, in case only the transport part of the Via is set
      msg->header(h_Vias).front().sentHost().clear();
   }

   Transport *trans;
   if ( (trans = findTransportBySource(source, msg)) == NULL )
   {
      return NULL;
   }
   if(source.getPort()==0)
   {
      source.setPort(trans->port());
   }
   return trans;
}

Here is the call graph for this function:

Tuple TransportSelector::getFirstInterface ( bool  is_v4,
TransportType  type 
) [static]

Definition at line 491 of file TransportSelector.cxx.

References resip::Transport::error(), resip::getErrno(), InfoLog, isDgramTransport(), and strerror().

Referenced by determineSourceInterface().

{
// !kh! both getaddrinfo() and IPv6 are not supported by cygwin, yet.
#ifdef __CYGWIN__
   assert(0);
   return Tuple();
#else
   // !kh!
   // 1. Query local hostname.
   char hostname[256] = "";
   if(gethostname(hostname, sizeof(hostname)) != 0)
   {
      int e = getErrno();
      Transport::error( e );
      InfoLog(<< "Can't query local hostname : [" << e << "] " << strerror(e) );
      throw Transport::Exception("Can't query local hostname", __FILE__, __LINE__);
   }
   InfoLog(<< "Local hostname is [" << hostname << "]");

   // !kh!
   // 2. Resolve address(es) of local hostname for specified transport.
   const bool is_dgram = isDgramTransport(type);
   addrinfo hint;
   memset(&hint, 0, sizeof(hint));
   hint.ai_family    = is_v4 ? PF_INET : PF_INET6;
   hint.ai_flags     = AI_PASSIVE;
   hint.ai_socktype  = is_dgram ? SOCK_DGRAM : SOCK_STREAM;

   addrinfo* results;
   int ret = getaddrinfo(
      hostname,
      0,
      &hint,
      &results);

   if(ret != 0)
   {
      Transport::error( ret ); // !kh! is this the correct sematics? ret is not errno.
      InfoLog(<< "Can't resolve " << hostname << "'s address : [" << ret << "] " << gai_strerror(ret) );
      throw Transport::Exception("Can't resolve hostname", __FILE__,__LINE__);
   }

   // !kh!
   // 3. Use first address resolved if there are more than one.
   // What should I do if there are more than one address?
   // i.e. results->ai_next != 0.
   Tuple source(*(results->ai_addr), type);
   InfoLog(<< "Local address is " << source);
   addrinfo* ai = results->ai_next;
   for(; ai; ai = ai->ai_next)
   {
      Tuple addr(*(ai->ai_addr), type);
      InfoLog(<<"Additional address " << addr);
   }
   freeaddrinfo(results);

   return source;
#endif
}

Here is the call graph for this function:

unsigned int TransportSelector::getTimeTillNextProcessMS ( )

Definition at line 1489 of file TransportSelector.cxx.

References hasDataToSend().

Referenced by resip::SipStack::getTimeTillNextProcessMS().

{
   return hasDataToSend() ? 0 : INT_MAX;
}

Here is the call graph for this function:

bool TransportSelector::hasDataToSend ( ) const
Return values:
trueSome transport in the transport list has data to send
falseNo transport in the transport list has data to send

Definition at line 404 of file TransportSelector.cxx.

References mSharedProcessTransports.

Referenced by getTimeTillNextProcessMS(), and poke().

{
   for(TransportList::const_iterator it = mSharedProcessTransports.begin();
       it != mSharedProcessTransports.end(); it++)
   {
      if ((*it)->hasDataToSend())
      {
         return true;
      }
   }
   return false;
}
bool TransportSelector::isFinished ( ) const

Returns true if all Transports have their buffers cleared, false otherwise.

Definition at line 147 of file TransportSelector.cxx.

References mAnyInterfaceTransports, mExactTransports, and mTlsTransports.

Referenced by resip::TransactionController::process().

{
   for (ExactTupleMap::const_iterator i=mExactTransports.begin(); i!=mExactTransports.end(); ++i)
   {
      if (!i->second->isFinished()) return false;
   }
   for (AnyInterfaceTupleMap::const_iterator i=mAnyInterfaceTransports.begin(); i!=mAnyInterfaceTransports.end(); ++i)
   {
      if (!i->second->isFinished()) return false;
   }
   for (TlsTransportMap::const_iterator i=mTlsTransports.begin(); i!=mTlsTransports.end(); ++i)
   {
      if (!i->second->isFinished()) return false;
   }
   return true;
}
void TransportSelector::poke ( )

Causes transport process loops to be interrupted if there is stuff in their transmit fifos.

Definition at line 382 of file TransportSelector.cxx.

References ErrLog, hasDataToSend(), mHasOwnProcessTransports, and mSelectInterruptor.

Referenced by resip::TransactionController::process().

{
   for(TransportList::iterator it = mHasOwnProcessTransports.begin(); 
       it != mHasOwnProcessTransports.end(); it++)
   {
      try
      {
         (*it)->poke();
      }
      catch (BaseException& e)
      {
         ErrLog (<< "Exception thrown from Transport::process: " << e);
      }
   }

   if(mSelectInterruptor.get() && hasDataToSend())
   {
      mSelectInterruptor->handleProcessNotification();
   }
}

Here is the call graph for this function:

void TransportSelector::process ( FdSet fdset)

Calls process on all suitable transports NOTE that TransportSelector no longer handles DNSInterface NOTE not used with pollGrp.

Definition at line 326 of file TransportSelector.cxx.

References checkTransportAddQueue(), ErrLog, mSelectInterruptor, and mSharedProcessTransports.

Referenced by resip::SipStack::processTimers(), and resip::TransportSelectorThread::thread().

{
   checkTransportAddQueue();

   for(TransportList::iterator it = mSharedProcessTransports.begin(); 
       it != mSharedProcessTransports.end(); it++)
   {
      try
      {
         (*it)->process(fdset);
      }
      catch (BaseException& e)
      {
         ErrLog (<< "Exception thrown from Transport::process: " << e);
      }
   }

   if(mSelectInterruptor.get())
   {
      mSelectInterruptor->process(fdset);
   }
}

Here is the call graph for this function:

void TransportSelector::process ( )

Definition at line 350 of file TransportSelector.cxx.

References checkTransportAddQueue(), ErrLog, and mSharedProcessTransports.

{
   // This function will only be sufficient if these Transports are hooked into
   // a FdPollGrp.
   checkTransportAddQueue();

   for(TransportList::iterator it = mSharedProcessTransports.begin(); 
       it != mSharedProcessTransports.end(); it++)
   {
      try
      {
         (*it)->process();
      }
      catch (BaseException& e)
      {
         ErrLog (<< "Exception thrown from Transport::process: " << e);
      }
   }
}

Here is the call graph for this function:

void TransportSelector::registerMarkListener ( MarkListener listener)
void TransportSelector::retransmit ( const SendData msg)

Resend to the same transport as last time.

Definition at line 1189 of file TransportSelector.cxx.

References resip::SendData::clone(), resip::SendData::destination, findTransportByDest(), resip::Transport::send(), and resip::Tuple::transportKey.

Referenced by resip::TransactionState::sendCurrentToWire().

{
   assert(data.destination.transportKey);
   Transport* transport = findTransportByDest(data.destination);

   // !jf! The previous call to transmit may have blocked or failed (It seems to
   // block in windows when the network is disconnected - don't know why just
   // yet.

   // !kh!
   // My speculation for blocking is; when network is disconnected, WinSock sets
   // a timer (to give up) and tries to defer reporting the error, in hope of
   // the network would be recovered. Before the timer fires, applications could
   // still select() (or the likes) their socket descriptors and find they are
   // writable if there is still room in buffer (per socket). If the send()s or
   // sendto()s made during this time period overflows the buffer, it blocks.
   // But I somewhat doubt this would be noticed, because block would be brief,
   // once the timer fires, the blocked call would return error.
   // Note that the block applies to both UDP and TCP sockets.
   // Quote from Linux man page:
   // When the message does not fit into the send buffer of the socket,  send
   // normally  blocks, unless the socket has been placed in non-blocking I/O
   // mode. In non-blocking mode it would return EAGAIN in this case.
   // Quote from MSDN library:
   // If no buffer space is available within the transport system to hold the
   // data to be transmitted, sendto will block unless the socket has been
   // placed in a nonblocking mode.

   if(transport)
   {
      // If this is not true, it means the transport has been removed.
      transport->send(std::auto_ptr<SendData>(data.clone()));
   }
}

Here is the call graph for this function:

void resip::TransportSelector::setCongestionManager ( CongestionManager manager) [inline]

Definition at line 122 of file TransportSelector.hxx.

References mHasOwnProcessTransports, and mSharedProcessTransports.

Referenced by resip::TransactionController::setCongestionManager().

      {
         for(TransportList::iterator i=mSharedProcessTransports.begin();
               i!=mSharedProcessTransports.end();++i)
         {
            (*i)->setCongestionManager(manager);
         }

         for(TransportList::iterator i=mHasOwnProcessTransports.begin();
               i!=mHasOwnProcessTransports.end();++i)
         {
            (*i)->setCongestionManager(manager);
         }
      }
void resip::TransportSelector::setEnumSuffixes ( const std::vector< Data > &  suffixes)
void TransportSelector::setPollGrp ( FdPollGrp pollGrp)

Configure a PollGrp to use (instead of buildFdSet/process) Must be called before adding any transports.

Definition at line 275 of file TransportSelector.cxx.

References resip::FdPollGrp::addPollItem(), resip::FdPollGrp::delPollItem(), FPEM_Read, mInterruptorHandle, mPollGrp, mSelectInterruptor, and mSharedProcessTransports.

Referenced by resip::SipStack::init(), resip::SipStack::SipStack(), resip::TransportSelectorThread::TransportSelectorThread(), ~TransportSelector(), and resip::TransportSelectorThread::~TransportSelectorThread().

{
   if(mPollGrp && mInterruptorHandle)
   {
      // unregister our select interruptor
      mPollGrp->delPollItem(mInterruptorHandle);
      mInterruptorHandle=0;
   }

   mPollGrp = grp;

   if(mPollGrp && mSelectInterruptor.get())
   {
      mInterruptorHandle = mPollGrp->addPollItem(mSelectInterruptor->getReadSocket(), FPEM_Read, mSelectInterruptor.get());
   }

   for(TransportList::iterator t=mSharedProcessTransports.begin(); 
         t!=mSharedProcessTransports.end(); ++t)
   {
      (*t)->setPollGrp(mPollGrp);
   }
}

Here is the call graph for this function:

void TransportSelector::shutdown ( )

Shuts down all transports.

dcm! repeat shutdown template pattern in all loop over all transport functions, refactor to functor?

Definition at line 129 of file TransportSelector.cxx.

References mAnyInterfaceTransports, mExactTransports, and mTlsTransports.

Referenced by resip::TransactionController::shutdown().

{
    for (ExactTupleMap::iterator i=mExactTransports.begin(); i!=mExactTransports.end(); ++i)
   {
      i->second->shutdown();
   }
   for (AnyInterfaceTupleMap::iterator i=mAnyInterfaceTransports.begin(); i!=mAnyInterfaceTransports.end(); ++i)
   {
      i->second->shutdown();
   }
   for (TlsTransportMap::iterator i=mTlsTransports.begin(); i!=mTlsTransports.end(); ++i)
   {
      i->second->shutdown();
   }
}
Fifo<TransactionMessage>& resip::TransportSelector::stateMacFifo ( ) [inline]

Definition at line 112 of file TransportSelector.hxx.

References mStateMacFifo.

Referenced by resip::SipStack::addTransport(), and resip::SipStack::stateMacFifo().

{ return mStateMacFifo; }
unsigned int TransportSelector::sumTransportFifoSizes ( ) const

Definition at line 1240 of file TransportSelector.cxx.

References mAnyPortAnyInterfaceTransports, mAnyPortTransports, and mTlsTransports.

Referenced by resip::TransactionController::sumTransportFifoSizes().

{
   unsigned int sum = 0;

   for (AnyPortTupleMap::const_iterator i = mAnyPortTransports.begin();
        i != mAnyPortTransports.end(); ++i)
   {
      sum += i->second->getFifoSize();
   }

   for (AnyPortAnyInterfaceTupleMap::const_iterator i = mAnyPortAnyInterfaceTransports.begin();
        i != mAnyPortAnyInterfaceTransports.end(); ++i)
   {
      sum += i->second->getFifoSize();
   }

   for (TlsTransportMap::const_iterator i = mTlsTransports.begin();
        i != mTlsTransports.end(); ++i)
   {
      sum += i->second->getFifoSize();
   }

   return sum;
}
void TransportSelector::terminateFlow ( const resip::Tuple flow)

Definition at line 1266 of file TransportSelector.cxx.

References closeConnection().

Referenced by resip::TransactionState::process().

{
   closeConnection(flow);
}

Here is the call graph for this function:

bool TransportSelector::transmit ( SipMessage msg,
Tuple target,
SendData sendData = 0 
)

Results in msg->resolve() being called to either kick off dns resolution or to pick the next tuple and will cause the message to be encoded and via updated.

Definition at line 759 of file TransportSelector.cxx.

References resip::Fifo< Msg >::add(), resip::SipMessage::callOutboundDecorators(), resip::BaseSecurity::computeIdentity(), resip::SipMessage::const_header(), DebugLog, determineSourceInterface(), resip::Data::empty(), resip::Data::Empty, resip::SipMessage::encode(), resip::NameAddr::exists(), resip::Uri::exists(), resip::SipMessage::exists(), findTransportByDest(), findTransportBySource(), findTransportByVia(), resip::SipMessage::getCanonicalIdentityString(), resip::Transport::getKey(), resip::Tuple::getPort(), resip::Compression::getSigcompId(), resip::SipMessage::getTlsDomain(), resip::SipMessage::getTransactionId(), resip::Transport::getTuple(), resip::Tuple::getType(), resip::Transport::hasSpecificContact(), resip::SipMessage::header(), resip::Uri::host(), resip::Tuple::inet_ntop(), InfoLog, resip::Transport::interfaceName(), resip::Tuple::ipVersion(), resip::Tuple::isAnyInterface(), resip::Compression::isEnabled(), resip::SipMessage::isRequest(), resip::SipMessage::isResponse(), resip::LazyParser::isWellFormed(), mAvgBufferSize, mCompression, resip::Tuple::mFlowKey, resip::SipMessage::mIsDecorated, mSecurity, mStateMacFifo, resip::TransportFailure::NoRoute, resip::TransportFailure::NoTransport, resip::Tuple::onlyUseExistingConnection, resip::ParserCategory::param(), resip::Uri::port(), resip::Transport::port(), resip::Via::remove(), resip::Uri::remove(), resip::SipMessage::remove(), resip::SipMessage::rollbackOutboundDecorators(), resip::Transport::send(), resip::Tuple::setPort(), resip::toData(), resip::toDataLower(), resip::Tuple::transport, resip::Transport::transport(), resip::Tuple::transportKey, resip::TransportFailure::TransportNoExistConn, resip::UDP, resip::RequestLine::uri(), and resip::NameAddr::uri().

Referenced by resip::StatelessMessage::handle(), resip::TransactionState::handleBadRequest(), resip::StatelessHandler::process(), resip::TransactionState::process(), resip::TransactionState::processSipMessageAsNew(), and resip::TransactionState::sendCurrentToWire().

{
   assert(msg);

   if(msg->mIsDecorated)
   {
      msg->rollbackOutboundDecorators();
   }

   try
   {
      TransportFailure::FailureReason transportFailureReason = TransportFailure::NoTransport;

      // !ah! You NEED to do this for responses too -- the transport doesn't
      // !ah! know it's IP addres(es) in all cases, AND it's function of the dest.
      // (imagine a synthetic message...)

      Tuple source;
      // .bwc. We need 3 things here:
      // 1) A Transport* to call send() on.
      // 2) A complete Tuple to pass in this call (target).
      // 3) A host, port, and protocol for filling out the topmost via, and
      //    possibly stuff like Contact, Referred-By, and other headers that
      //    must specify a hostname that the TU was unable to supply, because
      //    it didn't know what interface/port the message would be sent on.
      //    (source)
      /*
         Our Transport* might be found in target. If so, we can skip this block
         of stuff.
         Alternatively, we might not have the transport to start with. However,
         given a connection id, we will be able to find the Connection we
         should use, we can get the Transport we want. If we have no connection
         id, but we know we are using TLS or DTLS and have a tls hostname, we
         can use the hostname to find the appropriate transport. If all else
         fails, we must resort to the connected UDP trick to fill out source,
         which in turn is used to look up a matching transport.

         Given the transport, it is always possible to get the port/protocol,
         and usually possible to get the host (if it is bound to INADDR_ANY, we
         can't tell). However, if we had to fill out source in order to find
         the transport in the first place, this is not an issue.
      */

      Data remoteSigcompId;

      Transport* transport=0;

      if (msg->isRequest())
      {
         transport = findTransportByVia(msg, target, source);
         if (!transport)
         {
            if ((transport = findTransportByDest(target)) != NULL)
            {
               source = transport->getTuple();
            }
         }
         
         if(!transport && target.mFlowKey && target.onlyUseExistingConnection)
         {
            // .bwc. Connection info was specified, and use of this connection
            // was mandatory, but connection is no longer around. We fail.
            transportFailureReason = TransportFailure::TransportNoExistConn;
         }
         else if (transport)// .bwc. Here we use transport to find source.
         {
            assert( source.getType()!=0 );

            // .bwc. If the transport has an ambiguous interface, we need to
            //look a little closer.
            if(source.isAnyInterface())
            {
               Tuple temp = determineSourceInterface(msg,target);

               // .bwc. determineSourceInterface() can give us a port, if the TU
               // put one in the topmost Via.
               assert(source.ipVersion()==temp.ipVersion() &&
                        source.getType()==temp.getType());
               source=temp;

               /* determineSourceInterface might return an arbitrary port
                  here, so use the port specified in transport->port().
               */
               if(source.getPort()==0)
               {
                  source.setPort(transport->port());
               }
            }
         }
         // .bwc. Here we use source to find transport.
         else
         {
            source = determineSourceInterface(msg, target);
            transport = findTransportBySource(source, msg);

            // .bwc. determineSourceInterface might give us a port
            if(transport && source.getPort()==0)
            {
               source.setPort(transport->port());
            }
         }

         target.transportKey=transport ? transport->getKey() : 0;

         // .bwc. Topmost Via is only filled out in the request case. Also, if
         // we don't have a transport at this point, we're going to fail,
         // so don't bother doing the work.
         if(target.transportKey)
         {
            Via& topVia(msg->header(h_Vias).front());
            topVia.remove(p_maddr); // !jf! why do this?

            // insert the via
            if (topVia.transport().empty())
            {
               topVia.transport() = Tuple::toData(source.getType());
            }
            if (!topVia.sentHost().size())
            {
               topVia.sentHost() = Tuple::inet_ntop(source);
            }
            if (!topVia.sentPort())
            {
               topVia.sentPort() = source.getPort();
            }

            if (mCompression.isEnabled())
            {
               // Indicate support for SigComp, if appropriate.
               if (!topVia.exists(p_comp))
               {
                  topVia.param(p_comp) = "sigcomp";
               }
               if (!topVia.exists(p_sigcompId))
               {
                  topVia.param(p_sigcompId) = mCompression.getSigcompId();
               }

               // Figure out remote identifier (from Route header
               // field, if present; otherwise, from Request-URI).
               // XXX rohc-sip-sigcomp-03 says to use +sip.instance,
               // but this is impossible to actually do if you're
               // not actually the registrar, and really hard even
               // if you are.
               Uri destination;// (*reinterpret_cast<Uri*>(0)); // !bwc! What?

               if(msg->exists(h_Routes) &&
                  !msg->const_header(h_Routes).empty())
               {
                  destination = msg->const_header(h_Routes).front().uri();
               }
               else
               {
                  destination = msg->const_header(h_RequestLine).uri();
               }

               if (destination.exists(p_comp) &&
                   destination.param(p_comp) == "sigcomp")
               {
                  if (destination.exists(p_sigcompId))
                  {
                      remoteSigcompId = destination.param(p_sigcompId);
                  }
                  else
                  {
                      remoteSigcompId = destination.host();
                  }
               }
               // Squirrel the compartment away in the branch so that
               // we can figure out (pre-transaction-matching) what
               // compartment incoming requests are associated with.
               topVia.param(p_branch).setSigcompCompartment(remoteSigcompId);
            }
         }

      }
      else if (msg->isResponse())
      {
         // We assume that all stray responses have been discarded, so we always
         // know the transport that the corresponding request was received on
         // and this has been copied by TransactionState::sendToWire into transport
         transport=findTransportByDest(target);

         // !bwc! May eventually remove this once we allow transports to be 
         // removed while running.
         assert(transport);
         
         source = transport->getTuple();

         // .bwc. If the transport has an ambiguous interface, we need to
         //look a little closer.
         if(source.isAnyInterface())
         {
            Tuple temp = source;
            source = determineSourceInterface(msg,target);
            assert(source.ipVersion()==temp.ipVersion() &&
                     source.getType()==temp.getType());

            /* determineSourceInterface might return an arbitrary port here,
               so use the port specified in transport->port().
            */
            if(source.getPort()==0)
            {
               source.setPort(transport->port());
            }
         }
         if (mCompression.isEnabled())
         {
            // Figure out remote identifier (from Via header field).
            Via& topVia(msg->header(h_Vias).front());

            if(topVia.exists(p_comp) &&
               topVia.param(p_comp) == "sigcomp")
            {
               if (topVia.exists(p_sigcompId))
               {
                   remoteSigcompId = topVia.param(p_sigcompId);
               }
               else
               {
                   // XXX rohc-sigcomp-sip-03 says "sent-by",
                   // but this should probably be "received" if present,
                   // and "sent-by" otherwise.
                   // XXX Also, the spec is ambiguous about whether
                   // to include the port in this identifier.
                   remoteSigcompId = topVia.sentHost();
               }
            }
         }
      }
      else
      {
         assert(0);
      }

      // .bwc. At this point, source, transport, and target should be
      // _fully_ specified.

      if (transport)
      {
         // !bwc! TODO This filling in of stuff really should be handled with
         // the callOutboundDecorators() callback. (Or, at the very least,
         // we should allow this code to be turned off through configuration.
         // There are plenty of cases where this stuff is not at all necessary.)
         // There is a contact header and it contains exactly one entry
         if (msg->exists(h_Contacts) && msg->header(h_Contacts).size()==1)
         {
            for (NameAddrs::iterator i=msg->header(h_Contacts).begin(); i != msg->header(h_Contacts).end(); i++)
            {
               const NameAddr& c_contact = *i;
               NameAddr& contact = *i;
               // No host specified, so use the ip address and port of the
               // transport used. Otherwise, leave it as is.
               if (c_contact.uri().host().empty())
               {
                  contact.uri().host() = (transport->hasSpecificContact() ? 
                                          transport->interfaceName() : 
                                          Tuple::inet_ntop(source) );
                  contact.uri().port() = transport->port();

                  if (transport->transport() != UDP && !contact.uri().exists(p_gr))
                  {
                     contact.uri().param(p_transport) = Tuple::toDataLower(transport->transport());
                  }

                  // Add comp=sigcomp to contact URI
                  // Also, If no +sip.instance on contact HEADER,
                  // add sigcomp-id="<urn>" to contact URI.
                  if (mCompression.isEnabled())
                  {
                     if (!contact.uri().exists(p_comp))
                     {
                        contact.uri().param(p_comp) = "sigcomp";
                     }
                     if (!contact.exists(p_Instance) &&
                         !contact.uri().exists(p_sigcompId))
                     {
                        contact.uri().param(p_sigcompId)
                          = mCompression.getSigcompId();
                     }
                  }
               }
               else
               {
                  if (c_contact.uri().exists(p_addTransport))
                  {
                     if (target.getType() != UDP)
                     {
                        contact.uri().param(p_transport) = Tuple::toDataLower(target.getType());
                     }
                     contact.uri().remove(p_addTransport);
                  }
               }

            }
         }

         // !bwc! TODO make this configurable
         // Fix the Referred-By header if no host specified.
         // If malformed, leave it alone.
         if (msg->exists(h_ReferredBy)
               && msg->const_header(h_ReferredBy).isWellFormed())
         {
            if (msg->const_header(h_ReferredBy).uri().host().empty())
            {
               msg->header(h_ReferredBy).uri().host() = Tuple::inet_ntop(source);
               msg->header(h_ReferredBy).uri().port() = transport->port();
            }
         }

         // !bwc! TODO make this configurable
         // .bwc. Only try fiddling with this is if the Record-Route is well-
         // formed. If the topmost Record-Route is malformed, we have no idea
         // whether it came from something the TU synthesized or from the wire.
         // We shouldn't touch it. Frankly, I take issue with the method we have
         // chosen to signal to the stack that we want it to fill out various
         // header-field-values.
         if (msg->exists(h_RecordRoutes)
               && !msg->const_header(h_RecordRoutes).empty() 
               && msg->const_header(h_RecordRoutes).front().isWellFormed())
         {
            const NameAddr& c_rr = msg->const_header(h_RecordRoutes).front();
            NameAddr& rr = msg->header(h_RecordRoutes).front();
            if (c_rr.uri().host().empty())
            {
               rr.uri().host() = Tuple::inet_ntop(source);
               rr.uri().port() = transport->port();
               if (target.getType() != UDP && !rr.uri().exists(p_transport))
               {
                  rr.uri().param(p_transport) = Tuple::toDataLower(target.getType());
               }
               // Add comp=sigcomp and sigcomp-id="<urn>" to Record-Route
               // XXX This isn't quite right -- should be set only
               // on routes facing the client. Doing this correctly
               // requires double-record-routing
               if (mCompression.isEnabled())
               {
                  if (!rr.uri().exists(p_comp))
                  {
                     rr.uri().param(p_comp) = "sigcomp";
                  }
                  if (!rr.uri().exists(p_sigcompId))
                  {
                     rr.uri().param(p_sigcompId) = mCompression.getSigcompId();
                  }
               }
            }
         }
         
         // !bwc! TODO make this configurable
         // See draft-ietf-sip-identity
         if (mSecurity && msg->exists(h_Identity) && msg->const_header(h_Identity).value().empty())
         {
            DateCategory now;
            msg->header(h_Date) = now;
#if defined(USE_SSL)
            try
            {
               const Data& domain = msg->const_header(h_From).uri().host();
               msg->header(h_Identity).value() = mSecurity->computeIdentity( domain,
                                                                             msg->getCanonicalIdentityString());
            }
            catch (Security::Exception& e)
            {
               InfoLog (<< "Couldn't add identity header: " << e);
               msg->remove(h_Identity);
               if (msg->exists(h_IdentityInfo))
               {
                  msg->remove(h_IdentityInfo);
               }
            }
#endif
         }

         target.transportKey=transport->getKey();

         // !bwc! Deprecated. Stop doing this eventually.
         target.transport=transport;

         // Call back anyone who wants to perform outbound decoration
         msg->callOutboundDecorators(source, target,remoteSigcompId);

         std::auto_ptr<SendData> send(new SendData(target, 
                                                   resip::Data::Empty, 
                                                   msg->getTransactionId(),
                                                   remoteSigcompId));

         send->data.reserve(mAvgBufferSize + mAvgBufferSize/4);

         DataStream str(send->data);
         msg->encode(str);
         str.flush();

         // !bwc! Moving average of message size. (Used to intelligently
         // predict how much space to reserve in the buffer, to minimize
         // dynamic resizing.)
         mAvgBufferSize = (255*mAvgBufferSize + send->data.size()+128)/256;

         assert(!send->data.empty());
         DebugLog (<< "Transmitting to " << target
                   << " tlsDomain=" << msg->getTlsDomain()
                   << " via " << source
                   << std::endl << std::endl << send->data.escaped()
                   << "sigcomp id=" << remoteSigcompId);

         if(sendData)
         {
            *sendData = *send;
         }

         transport->send(send);
         return true;
      }
      else
      {
         InfoLog (<< "tid=" << msg->getTransactionId() << " failed to find a transport to " << target);
         mStateMacFifo.add(new TransportFailure(msg->getTransactionId(), transportFailureReason));
         return false;
      }

   }
   catch (Transport::Exception& )
   {
      InfoLog (<< "tid=" << msg->getTransactionId() << " no route to target: " << target);
      mStateMacFifo.add(new TransportFailure(msg->getTransactionId(), TransportFailure::NoRoute));
      return false;
   }
}

Here is the call graph for this function:

void TransportSelector::unregisterMarkListener ( MarkListener listener)

Friends And Related Function Documentation

friend class SipStack [friend]

Definition at line 251 of file TransportSelector.hxx.

friend class TestTransportSelector [friend]

Definition at line 250 of file TransportSelector.hxx.


Member Data Documentation

Definition at line 245 of file TransportSelector.hxx.

Referenced by transmit().

SigComp configuration object.

Definition at line 239 of file TransportSelector.hxx.

Referenced by transmit(), and TransportSelector().

Definition at line 248 of file TransportSelector.hxx.

Referenced by createSelectInterruptor(), and setPollGrp().

Definition at line 151 of file TransportSelector.hxx.

Referenced by transmit().

Definition at line 247 of file TransportSelector.hxx.

Referenced by buildFdSet(), createSelectInterruptor(), poke(), process(), and setPollGrp().

Definition at line 240 of file TransportSelector.hxx.

Referenced by TransportSelector(), and ~TransportSelector().

Definition at line 231 of file TransportSelector.hxx.

Referenced by determineSourceInterface(), and ~TransportSelector().

Definition at line 232 of file TransportSelector.hxx.

Referenced by determineSourceInterface(), and ~TransportSelector().

Definition at line 150 of file TransportSelector.hxx.

Referenced by stateMacFifo(), and transmit().

Definition at line 246 of file TransportSelector.hxx.

Referenced by addTransport(), and checkTransportAddQueue().

Definition at line 235 of file TransportSelector.hxx.

Referenced by determineSourceInterface(), and TransportSelector().

Definition at line 236 of file TransportSelector.hxx.

Referenced by determineSourceInterface(), and TransportSelector().


The documentation for this class was generated from the following files: