📄 transportselector.cxx
字号:
// 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 + -