📄 transportselector.cxx
字号:
#if defined(HAVE_CONFIG_H)#include "resip/stack/config.hxx"#endif#ifdef WIN32#include <winsock2.h> #include <ws2tcpip.h> #include <wspiapi.h> // Required for freeaddrinfo implementation in Windows 2000, NT, Me/95/98#else#include <sys/types.h>#include <sys/socket.h>#include <arpa/inet.h>#include <netdb.h>#endif#include "resip/stack/NameAddr.hxx"#include "resip/stack/Uri.hxx"#include "resip/stack/ExtensionParameter.hxx"#include "resip/stack/Security.hxx"#include "resip/stack/Compression.hxx"#include "resip/stack/SipMessage.hxx"#include "resip/stack/TransactionState.hxx"#include "resip/stack/TransportFailure.hxx"#include "resip/stack/TransportSelector.hxx"#include "resip/stack/InternalTransport.hxx"#include "resip/stack/TcpBaseTransport.hxx"#include "resip/stack/TcpTransport.hxx"#include "resip/stack/TlsTransport.hxx"#include "resip/stack/UdpTransport.hxx"#include "resip/stack/DtlsTransport.hxx"#include "resip/stack/Uri.hxx"#include "rutil/DataStream.hxx"#include "rutil/DnsUtil.hxx"#include "rutil/Inserter.hxx"#include "rutil/Logger.hxx"#include "rutil/Socket.hxx"#include "rutil/WinLeakCheck.hxx"#include "rutil/dns/DnsStub.hxx"#ifdef USE_SIGCOMP#include <osc/Stack.h>#include <osc/SigcompMessage.h>#endif#ifdef WIN32#include "rutil/WinCompat.hxx"#endif#ifdef __MINGW32__#define gai_strerror strerror#endif#include <sys/types.h>using namespace resip;#define RESIPROCATE_SUBSYSTEM Subsystem::TRANSPORTTransportSelector::TransportSelector(Fifo<TransactionMessage>& fifo, Security* security, DnsStub& dnsStub, Compression &compression) : mDns(dnsStub), mStateMacFifo(fifo), mSecurity(security), mSocket( INVALID_SOCKET ), mSocket6( INVALID_SOCKET ), mCompression(compression), mSigcompStack (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}template<class T> void deleteMap(T& m){ for (typename T::iterator it = m.begin(); it != m.end(); it++) { delete it->second; } m.clear();}TransportSelector::~TransportSelector(){ mConnectionlessMap.clear(); deleteMap(mExactTransports); deleteMap(mAnyInterfaceTransports); deleteMap(mTlsTransports);#ifdef USE_SIGCOMP delete mSigcompStack;#endif}voidTransportSelector::shutdown(){ //!dcm! repeat shutodwn template pattern in all loop over all tranport functions, refactor to functor? 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(); }}boolTransportSelector::isFinished() const{ 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; } return true;}voidTransportSelector::addTransport(std::auto_ptr<Transport> autoTransport){ 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)); } else if(transport->transport()==TLS) { assert(dynamic_cast<TlsTransport*>(transport)); } else if(transport->transport()==UDP) { assert(dynamic_cast<UdpTransport*>(transport)); }#if USE_DTLS else if(transport->transport()==DTLS) { assert(dynamic_cast<DtlsTransport*>(transport)); }#endif else { assert(0); } Tuple tuple(transport->interfaceName(), transport->port(), transport->ipVersion(), transport->transport()); mTypeToTransportMap.insert(std::make_pair(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->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->transport()==UDP || transport->transport()==DTLS) { mConnectionlessMap[transport->getTuple().mFlowKey]=transport; } if (transport->shareStackProcessAndSelect()) { mSharedProcessTransports.push_back(transport); } else { mHasOwnProcessTransports.push_back(transport); mHasOwnProcessTransports.back()->startOwnProcessing(); }} voidTransportSelector::buildFdSet(FdSet& fdset){ mDns.buildFdSet(fdset); for(TransportList::iterator it = mSharedProcessTransports.begin(); it != mSharedProcessTransports.end(); it++) { (*it)->buildFdSet(fdset); }}voidTransportSelector::process(FdSet& fdset){ mDns.process(fdset); for(TransportList::iterator it = mSharedProcessTransports.begin(); it != mSharedProcessTransports.end(); it++) { try { (*it)->process(fdset); } catch (BaseException& e) { ErrLog (<< "Exception thrown from Transport::process: " << e); } }}boolTransportSelector::hasDataToSend() const{ for(TransportList::const_iterator it = mSharedProcessTransports.begin(); it != mSharedProcessTransports.end(); it++) { if ((*it)->hasDataToSend()) { return true; } } return false;}//!jf! the problem here is that DnsResult is returned after looking//mDns.lookup() but this can result in a synchronous call to handle() which//assumes that dnsresult has been assigned to the TransactionState//!dcm! -- now 2-phase to fix thisDnsResult*TransportSelector::createDnsResult(DnsHandler* handler){ return mDns.createDnsResult(handler);}voidTransportSelector::dnsResolve(DnsResult* result, SipMessage* msg){ // 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->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->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->header(h_RequestLine).uri()); mDns.lookup(result, msg->header(h_RequestLine).uri()); } } else if (msg->isResponse()) { ErrLog(<<"unimplemented response dns"); assert(0); } else { assert(0); }}bool isDgramTransport (TransportType type){ static const bool unknown_transport = false; switch(type) { case UDP: case DTLS: case DCCP: case SCTP: return true; case TCP: case TLS: return false; default: assert(unknown_transport); return unknown_transport; // !kh! just to make it compile wo/warning. }}TupleTransportSelector::getFirstInterface(bool is_v4, TransportType type){// !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}TupleTransportSelector::determineSourceInterface(SipMessage* msg, const Tuple& target) const{ assert(msg->exists(h_Vias)); assert(!msg->header(h_Vias).empty()); const Via& via = msg->header(h_Vias).front(); if (msg->isRequest() && !via.sentHost().empty()) // hint provided in sent-by of via by application { DebugLog( << "hint provided by app: " << msg->header(h_Vias).front()); return Tuple(via.sentHost(), via.sentPort(), target.ipVersion(), target.getType()); } else { 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.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -