⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 transportselector.cxx

📁 一个著名的SIP协议栈
💻 CXX
📖 第 1 页 / 共 4 页
字号:
               // 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 target.transport
         assert(target.transport);
         
         source = target.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);
            /* determineSourceInterface will return an arbitrary port here,
               so use the port specified in target.transport->port().
            */
            assert(source.ipVersion()==temp.ipVersion() &&
                     source.getType()==temp.getType());

            source.setPort(target.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, target.transport, and target should be
      // _fully_ specified.

      if (target.transport)
      {
         // 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++)
            {
               NameAddr& contact = *i;
               // No host specified, so use the ip address and port of the
               // transport used. Otherwise, leave it as is.
               if (contact.uri().host().empty())
               {
                  contact.uri().host() = (target.transport->hasSpecificContact() ? 
                                          target.transport->interfaceName() : 
                                          Tuple::inet_ntop(source) );
                  contact.uri().port() = target.transport->port();

                  if (target.transport->transport() != UDP)
                  {
                     contact.uri().param(p_transport) = Tuple::toData(target.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 (contact.uri().exists(p_addTransport))
                  {
                     if (target.transport->transport() != UDP)
                     {
                        contact.uri().param(p_transport) = Tuple::toData(target.transport->transport());
                     }
                     contact.uri().remove(p_addTransport);
                  }
               }

            }
         }

         // Fix the Referred-By header if no host specified.
         if (msg->exists(h_ReferredBy))
         {
            if (msg->header(h_ReferredBy).uri().host().empty())
            {
               msg->header(h_ReferredBy).uri().host() = Tuple::inet_ntop(source);
               msg->header(h_ReferredBy).uri().port() = target.transport->port();
            }
         }

         if (msg->exists(h_RecordRoutes) && !msg->header(h_RecordRoutes).empty())
         {
            NameAddr& rr = msg->header(h_RecordRoutes).back();
            if (rr.uri().host().empty())
            {
               rr.uri().host() = Tuple::inet_ntop(source);
               rr.uri().port() = target.transport->port();
               if (target.transport->transport() != UDP && !rr.uri().exists(p_transport))
               {
                  rr.uri().param(p_transport) = Tuple::toData(target.transport->transport());
               }
               // 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();
                  }
               }
            }
         }
         
         // See draft-ietf-sip-identity
         if (mSecurity && msg->exists(h_Identity) && msg->header(h_Identity).value().empty())
         {
            DateCategory now;
            msg->header(h_Date) = now;
#if defined(USE_SSL)
            try
            {
               const Data& domain = msg->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
         }

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

         Data& encoded = msg->getEncoded();
         encoded.clear();
         DataStream encodeStream(encoded);
         msg->encode(encodeStream);
         encodeStream.flush();
         msg->getCompartmentId() = remoteSigcompId;
         
         assert(!msg->getEncoded().empty());
         DebugLog (<< "Transmitting to " << target
                   << " tlsDomain=" << msg->getTlsDomain()
                   << " via " << source
				   << std::endl << std::endl << encoded.escaped());

         target.transport->send(target, encoded, msg->getTransactionId(),
                                remoteSigcompId);
      }
      else
      {
         InfoLog (<< "tid=" << msg->getTransactionId() << " failed to find a transport to " << target);
         mStateMacFifo.add(new TransportFailure(msg->getTransactionId(), TransportFailure::NoTransport));
      }

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

void
TransportSelector::retransmit(SipMessage* msg, Tuple& target)
{
   assert(target.transport);

   // !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(!msg->getEncoded().empty())
   {
      //DebugLog(<<"!ah! retransmit to " << target);
      target.transport->send(target, msg->getEncoded(), msg->getTransactionId(),                             msg->getCompartmentId());
   }
}

unsigned int
TransportSelector::sumTransportFifoSizes() const
{
   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 = mV4TlsTransports.begin();
        i != mV4TlsTransports.end(); ++i)
   {
      sum += i->second->getFifoSize();
   }

#ifdef USE_IPV6
   for (TlsTransportMap::const_iterator i = mV6TlsTransports.begin();
        i != mV6TlsTransports.end(); ++i)
   {
      sum += i->second->getFifoSize();
   }
#endif

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

#ifdef USE_IPV6
   for (TlsTransportMap::const_iterator i = mV6DtlsTransports.begin();
        i != mV6DtlsTransports.end(); ++i)
   {
      sum += i->second->getFifoSize();
   }
#endif

#endif
   
   return sum;
}

Connection*
TransportSelector::findConnection(const Tuple& target)
{
   //!bwc! If we can find a match in the ConnectionManager, we can get
   //determine what Tranport this needs to be sent on. This may also let
   // us know immediately what our source needs to be.
   if(target.getType()==TCP || target.getType()==TLS)
   {
      TcpBaseTransport* tcpb=0;
      Connection* conn=0;
      TransportList::const_iterator i;

      for(i=mSharedProcessTransports.begin();i!=mSharedProcessTransports.end();i++)
      {
         if( (tcpb=dynamic_cast<TcpBaseTransport*>(*i)) )
         {
            conn = tcpb->getConnectionManager().findConnection(target);
            if(conn)
            {
               return conn;
            }
         }
      }
      
      for(i=mHasOwnProcessTransports.begin();i!=mHasOwnProcessTransports.end();i++)
      {
         if( (tcpb=dynamic_cast<TcpBaseTransport*>(*i)) )
         {
            conn = tcpb->getConnectionManager().findConnection(target);
            if(conn)
            {
               return conn;
            }
         }
      }

   }
   
   return 0;
}


Transport*
TransportSelector::findTransportByDest(SipMessage* msg, Tuple& target)
{
   if(!target.transport)
   {
      if(target.getType()!=UDP) // !bwc! Maybe we can find a connection?
      {
         if( !target.connectionId) // !bwc! Don't have a cid yet...
         {
            static ExtensionParameter p_cid("cid");
            unsigned long cid=0;
            if(msg->exists(h_Routes) && 
               !msg->header(h_Routes).empty() && 
               msg->header(h_Routes).front().uri().exists(p_cid))

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -