diff options
author | Primiano Tucci <primiano@google.com> | 2014-09-30 14:46:33 +0100 |
---|---|---|
committer | Primiano Tucci <primiano@google.com> | 2014-09-30 14:46:33 +0100 |
commit | da0509e3087cc5ee9adc0fe1abb85112ea6529a5 (patch) | |
tree | 532416c2f3025131e902ab655f3d404945485a6b /p2p | |
parent | 67bbc8e3efef31646fec91b0b422a78708a3f4aa (diff) | |
parent | 6fd722a3e5cdf933ad206ec7cd697ce95a5630cd (diff) | |
download | talk-da0509e3087cc5ee9adc0fe1abb85112ea6529a5.tar.gz |
Merge from Chromium at DEPS revision 267aeeb8d85candroid-cts-5.1_r9android-cts-5.1_r8android-cts-5.1_r7android-cts-5.1_r6android-cts-5.1_r5android-cts-5.1_r4android-cts-5.1_r3android-cts-5.1_r28android-cts-5.1_r27android-cts-5.1_r26android-cts-5.1_r25android-cts-5.1_r24android-cts-5.1_r23android-cts-5.1_r22android-cts-5.1_r21android-cts-5.1_r20android-cts-5.1_r2android-cts-5.1_r19android-cts-5.1_r18android-cts-5.1_r17android-cts-5.1_r16android-cts-5.1_r15android-cts-5.1_r14android-cts-5.1_r13android-cts-5.1_r10android-cts-5.1_r1android-5.1.1_r9android-5.1.1_r8android-5.1.1_r7android-5.1.1_r6android-5.1.1_r5android-5.1.1_r4android-5.1.1_r38android-5.1.1_r37android-5.1.1_r36android-5.1.1_r35android-5.1.1_r34android-5.1.1_r33android-5.1.1_r30android-5.1.1_r3android-5.1.1_r29android-5.1.1_r28android-5.1.1_r26android-5.1.1_r25android-5.1.1_r24android-5.1.1_r23android-5.1.1_r22android-5.1.1_r20android-5.1.1_r2android-5.1.1_r19android-5.1.1_r18android-5.1.1_r17android-5.1.1_r16android-5.1.1_r15android-5.1.1_r14android-5.1.1_r13android-5.1.1_r12android-5.1.1_r10android-5.1.1_r1android-5.1.0_r5android-5.1.0_r4android-5.1.0_r3android-5.1.0_r1lollipop-mr1-wfc-releaselollipop-mr1-releaselollipop-mr1-fi-releaselollipop-mr1-devlollipop-mr1-cts-release
This commit was generated by merge_to_master.py.
Change-Id: I3cccc8f04ad0036aecdb7eefe316a059ebcefaf9
Diffstat (limited to 'p2p')
36 files changed, 888 insertions, 203 deletions
diff --git a/p2p/base/asyncstuntcpsocket.h b/p2p/base/asyncstuntcpsocket.h index b63c0b5..136b4df 100644 --- a/p2p/base/asyncstuntcpsocket.h +++ b/p2p/base/asyncstuntcpsocket.h @@ -25,8 +25,8 @@ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef TALK_BASE_ASYNCSTUNTCPSOCKET_H_ -#define TALK_BASE_ASYNCSTUNTCPSOCKET_H_ +#ifndef TALK_P2P_BASE_ASYNCSTUNTCPSOCKET_H_ +#define TALK_P2P_BASE_ASYNCSTUNTCPSOCKET_H_ #include "webrtc/base/asynctcpsocket.h" #include "webrtc/base/scoped_ptr.h" @@ -64,4 +64,4 @@ class AsyncStunTCPSocket : public rtc::AsyncTCPSocketBase { } // namespace cricket -#endif // TALK_BASE_ASYNCSTUNTCPSOCKET_H_ +#endif // TALK_P2P_BASE_ASYNCSTUNTCPSOCKET_H_ diff --git a/p2p/base/basicpacketsocketfactory.h b/p2p/base/basicpacketsocketfactory.h index b1bae35..77b1652 100644 --- a/p2p/base/basicpacketsocketfactory.h +++ b/p2p/base/basicpacketsocketfactory.h @@ -25,8 +25,8 @@ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef TALK_BASE_BASICPACKETSOCKETFACTORY_H_ -#define TALK_BASE_BASICPACKETSOCKETFACTORY_H_ +#ifndef TALK_P2P_BASE_BASICPACKETSOCKETFACTORY_H_ +#define TALK_P2P_BASE_BASICPACKETSOCKETFACTORY_H_ #include "talk/p2p/base/packetsocketfactory.h" @@ -65,4 +65,4 @@ class BasicPacketSocketFactory : public PacketSocketFactory { } // namespace rtc -#endif // TALK_BASE_BASICPACKETSOCKETFACTORY_H_ +#endif // TALK_P2P_BASE_BASICPACKETSOCKETFACTORY_H_ diff --git a/p2p/base/constants.cc b/p2p/base/constants.cc index 2e57d9d..278a615 100644 --- a/p2p/base/constants.cc +++ b/p2p/base/constants.cc @@ -29,7 +29,7 @@ #include <string> -#include "talk/xmllite/qname.h" +#include "webrtc/libjingle/xmllite/qname.h" namespace cricket { diff --git a/p2p/base/constants.h b/p2p/base/constants.h index 61dd815..4cd1166 100644 --- a/p2p/base/constants.h +++ b/p2p/base/constants.h @@ -29,7 +29,7 @@ #define TALK_P2P_BASE_CONSTANTS_H_ #include <string> -#include "talk/xmllite/qname.h" +#include "webrtc/libjingle/xmllite/qname.h" // This file contains constants related to signaling that are used in various // classes in this directory. diff --git a/p2p/base/p2ptransport.cc b/p2p/base/p2ptransport.cc index b992cc0..06941ac 100644 --- a/p2p/base/p2ptransport.cc +++ b/p2p/base/p2ptransport.cc @@ -35,8 +35,8 @@ #include "talk/p2p/base/parsing.h" #include "talk/p2p/base/sessionmanager.h" #include "talk/p2p/base/sessionmessages.h" -#include "talk/xmllite/qname.h" -#include "talk/xmllite/xmlelement.h" +#include "webrtc/libjingle/xmllite/qname.h" +#include "webrtc/libjingle/xmllite/xmlelement.h" #include "talk/xmpp/constants.h" #include "webrtc/base/base64.h" #include "webrtc/base/common.h" diff --git a/p2p/base/packetsocketfactory.h b/p2p/base/packetsocketfactory.h index 6b82682..46767c2 100644 --- a/p2p/base/packetsocketfactory.h +++ b/p2p/base/packetsocketfactory.h @@ -25,8 +25,8 @@ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef TALK_BASE_PACKETSOCKETFACTORY_H_ -#define TALK_BASE_PACKETSOCKETFACTORY_H_ +#ifndef TALK_P2P_BASE_PACKETSOCKETFACTORY_H_ +#define TALK_P2P_BASE_PACKETSOCKETFACTORY_H_ #include "webrtc/base/proxyinfo.h" @@ -66,4 +66,4 @@ class PacketSocketFactory { } // namespace rtc -#endif // TALK_BASE_PACKETSOCKETFACTORY_H_ +#endif // TALK_P2P_BASE_PACKETSOCKETFACTORY_H_ diff --git a/p2p/base/parsing.h b/p2p/base/parsing.h index 635b122..2aab2f8 100644 --- a/p2p/base/parsing.h +++ b/p2p/base/parsing.h @@ -30,7 +30,7 @@ #include <string> #include <vector> -#include "talk/xmllite/xmlelement.h" // Needed to delete ParseError.extra. +#include "webrtc/libjingle/xmllite/xmlelement.h" // Needed to delete ParseError.extra. #include "webrtc/base/basictypes.h" #include "webrtc/base/stringencode.h" diff --git a/p2p/base/port.cc b/p2p/base/port.cc index 3820154..0cf46eb 100644 --- a/p2p/base/port.cc +++ b/p2p/base/port.cc @@ -1212,7 +1212,7 @@ std::string Connection::ToString() const { << ":" << local.type() << ":" << local.protocol() << ":" << local.address().ToSensitiveString() << "->" << remote.id() << ":" << remote.component() - << ":" << remote.preference() + << ":" << remote.priority() << ":" << remote.type() << ":" << remote.protocol() << ":" << remote.address().ToSensitiveString() << "|" << CONNECT_STATE_ABBREV[connected()] diff --git a/p2p/base/port.h b/p2p/base/port.h index cccfdad..4893586 100644 --- a/p2p/base/port.h +++ b/p2p/base/port.h @@ -155,6 +155,7 @@ class Port : public PortInterface, public rtc::MessageHandler, uint64 IceTiebreaker() const { return tiebreaker_; } virtual bool SharedSocket() const { return shared_socket_; } + void ResetSharedSocket() { shared_socket_ = false; } // The thread on which this port performs its I/O. rtc::Thread* thread() { return thread_; } diff --git a/p2p/base/portallocator.h b/p2p/base/portallocator.h index 84e5fea..5bc389e 100644 --- a/p2p/base/portallocator.h +++ b/p2p/base/portallocator.h @@ -44,17 +44,18 @@ namespace cricket { // Clients can override this class to control port allocation, including // what kinds of ports are allocated. -const uint32 PORTALLOCATOR_DISABLE_UDP = 0x01; -const uint32 PORTALLOCATOR_DISABLE_STUN = 0x02; -const uint32 PORTALLOCATOR_DISABLE_RELAY = 0x04; -const uint32 PORTALLOCATOR_DISABLE_TCP = 0x08; -const uint32 PORTALLOCATOR_ENABLE_SHAKER = 0x10; -const uint32 PORTALLOCATOR_ENABLE_BUNDLE = 0x20; -const uint32 PORTALLOCATOR_ENABLE_IPV6 = 0x40; -const uint32 PORTALLOCATOR_ENABLE_SHARED_UFRAG = 0x80; -const uint32 PORTALLOCATOR_ENABLE_SHARED_SOCKET = 0x100; -const uint32 PORTALLOCATOR_ENABLE_STUN_RETRANSMIT_ATTRIBUTE = 0x200; -const uint32 PORTALLOCATOR_ENABLE_TURN_SHARED_SOCKET = 0x400; +enum { + PORTALLOCATOR_DISABLE_UDP = 0x01, + PORTALLOCATOR_DISABLE_STUN = 0x02, + PORTALLOCATOR_DISABLE_RELAY = 0x04, + PORTALLOCATOR_DISABLE_TCP = 0x08, + PORTALLOCATOR_ENABLE_SHAKER = 0x10, + PORTALLOCATOR_ENABLE_BUNDLE = 0x20, + PORTALLOCATOR_ENABLE_IPV6 = 0x40, + PORTALLOCATOR_ENABLE_SHARED_UFRAG = 0x80, + PORTALLOCATOR_ENABLE_SHARED_SOCKET = 0x100, + PORTALLOCATOR_ENABLE_STUN_RETRANSMIT_ATTRIBUTE = 0x200, +}; const uint32 kDefaultPortAllocatorFlags = 0; @@ -63,6 +64,15 @@ const uint32 kDefaultStepDelay = 1000; // 1 sec step delay. // internal. Less than 20ms is not acceptable. We choose 50ms as our default. const uint32 kMinimumStepDelay = 50; +// CF = CANDIDATE FILTER +enum { + CF_NONE = 0x0, + CF_HOST = 0x1, + CF_REFLEXIVE = 0x2, + CF_RELAY = 0x4, + CF_ALL = 0x7, +}; + class PortAllocatorSessionMuxer; class PortAllocatorSession : public sigslot::has_slots<> { @@ -118,7 +128,8 @@ class PortAllocator : public sigslot::has_slots<> { min_port_(0), max_port_(0), step_delay_(kDefaultStepDelay), - allow_tcp_listen_(true) { + allow_tcp_listen_(true), + candidate_filter_(CF_ALL) { // This will allow us to have old behavior on non webrtc clients. } virtual ~PortAllocator(); @@ -158,7 +169,6 @@ class PortAllocator : public sigslot::has_slots<> { uint32 step_delay() const { return step_delay_; } void set_step_delay(uint32 delay) { - ASSERT(delay >= kMinimumStepDelay); step_delay_ = delay; } @@ -167,6 +177,13 @@ class PortAllocator : public sigslot::has_slots<> { allow_tcp_listen_ = allow_tcp_listen; } + uint32 candidate_filter() { return candidate_filter_; } + bool set_candidate_filter(uint32 filter) { + // TODO(mallinath) - Do transition check? + candidate_filter_ = filter; + return true; + } + protected: virtual PortAllocatorSession* CreateSessionInternal( const std::string& content_name, @@ -184,6 +201,7 @@ class PortAllocator : public sigslot::has_slots<> { uint32 step_delay_; SessionMuxerMap muxers_; bool allow_tcp_listen_; + uint32 candidate_filter_; }; } // namespace cricket diff --git a/p2p/base/rawtransport.cc b/p2p/base/rawtransport.cc index 5913177..2af1864 100644 --- a/p2p/base/rawtransport.cc +++ b/p2p/base/rawtransport.cc @@ -32,8 +32,8 @@ #include "talk/p2p/base/rawtransport.h" #include "talk/p2p/base/rawtransportchannel.h" #include "talk/p2p/base/sessionmanager.h" -#include "talk/xmllite/qname.h" -#include "talk/xmllite/xmlelement.h" +#include "webrtc/libjingle/xmllite/qname.h" +#include "webrtc/libjingle/xmllite/xmlelement.h" #include "talk/xmpp/constants.h" #include "webrtc/base/common.h" diff --git a/p2p/base/rawtransportchannel.cc b/p2p/base/rawtransportchannel.cc index ef0a532..ae268e3 100644 --- a/p2p/base/rawtransportchannel.cc +++ b/p2p/base/rawtransportchannel.cc @@ -36,8 +36,8 @@ #include "talk/p2p/base/relayport.h" #include "talk/p2p/base/sessionmanager.h" #include "talk/p2p/base/stunport.h" -#include "talk/xmllite/qname.h" -#include "talk/xmllite/xmlelement.h" +#include "webrtc/libjingle/xmllite/qname.h" +#include "webrtc/libjingle/xmllite/xmlelement.h" #include "talk/xmpp/constants.h" #include "webrtc/base/common.h" diff --git a/p2p/base/session.h b/p2p/base/session.h index 756bbe0..e06cf00 100644 --- a/p2p/base/session.h +++ b/p2p/base/session.h @@ -39,7 +39,7 @@ #include "talk/p2p/base/sessionmanager.h" #include "talk/p2p/base/sessionmessages.h" #include "talk/p2p/base/transport.h" -#include "talk/xmllite/xmlelement.h" +#include "webrtc/libjingle/xmllite/xmlelement.h" #include "talk/xmpp/constants.h" #include "webrtc/base/refcount.h" #include "webrtc/base/scoped_ptr.h" diff --git a/p2p/base/session_unittest.cc b/p2p/base/session_unittest.cc index 90cd06d..4674d2c 100644 --- a/p2p/base/session_unittest.cc +++ b/p2p/base/session_unittest.cc @@ -601,8 +601,7 @@ class TestPortAllocatorSession : public cricket::PortAllocatorSession { network_("network", "unittest", rtc::IPAddress(INADDR_LOOPBACK), 8), socket_factory_(rtc::Thread::Current()), - running_(false), - port_(28653) { + running_(false) { network_.AddIP(address_.ipaddr()); } @@ -655,7 +654,6 @@ class TestPortAllocatorSession : public cricket::PortAllocatorSession { rtc::Network network_; rtc::BasicPacketSocketFactory socket_factory_; bool running_; - int port_; }; class TestPortAllocator : public cricket::PortAllocator { diff --git a/p2p/base/sessiondescription.cc b/p2p/base/sessiondescription.cc index 7009aa8..7ad3d48 100644 --- a/p2p/base/sessiondescription.cc +++ b/p2p/base/sessiondescription.cc @@ -27,7 +27,7 @@ #include "talk/p2p/base/sessiondescription.h" -#include "talk/xmllite/xmlelement.h" +#include "webrtc/libjingle/xmllite/xmlelement.h" namespace cricket { diff --git a/p2p/base/sessionmessages.cc b/p2p/base/sessionmessages.cc index bfba273..b2fd9d6 100644 --- a/p2p/base/sessionmessages.cc +++ b/p2p/base/sessionmessages.cc @@ -36,7 +36,7 @@ #include "talk/p2p/base/sessionclient.h" #include "talk/p2p/base/sessiondescription.h" #include "talk/p2p/base/transport.h" -#include "talk/xmllite/xmlconstants.h" +#include "webrtc/libjingle/xmllite/xmlconstants.h" #include "talk/xmpp/constants.h" #include "webrtc/base/logging.h" #include "webrtc/base/scoped_ptr.h" diff --git a/p2p/base/sessionmessages.h b/p2p/base/sessionmessages.h index 38fca98..7e1f8ac 100644 --- a/p2p/base/sessionmessages.h +++ b/p2p/base/sessionmessages.h @@ -36,7 +36,7 @@ #include "talk/p2p/base/parsing.h" #include "talk/p2p/base/sessiondescription.h" // Needed to delete contents. #include "talk/p2p/base/transportinfo.h" -#include "talk/xmllite/xmlelement.h" +#include "webrtc/libjingle/xmllite/xmlelement.h" #include "webrtc/base/basictypes.h" namespace cricket { diff --git a/p2p/base/stun.cc b/p2p/base/stun.cc index be96b76..061fd9a 100644 --- a/p2p/base/stun.cc +++ b/p2p/base/stun.cc @@ -41,6 +41,7 @@ using rtc::ByteBuffer; namespace cricket { +const char STUN_ERROR_REASON_TRY_ALTERNATE_SERVER[] = "Try Alternate Server"; const char STUN_ERROR_REASON_BAD_REQUEST[] = "Bad Request"; const char STUN_ERROR_REASON_UNAUTHORIZED[] = "Unauthorized"; const char STUN_ERROR_REASON_FORBIDDEN[] = "Forbidden"; @@ -401,7 +402,7 @@ StunAttributeValueType StunMessage::GetAttributeValueType(int type) const { case STUN_ATTR_NONCE: return STUN_VALUE_BYTE_STRING; case STUN_ATTR_XOR_MAPPED_ADDRESS: return STUN_VALUE_XOR_ADDRESS; case STUN_ATTR_SOFTWARE: return STUN_VALUE_BYTE_STRING; - case STUN_ATTR_ALTERNATE_SERVER: return STUN_VALUE_BYTE_STRING; + case STUN_ATTR_ALTERNATE_SERVER: return STUN_VALUE_ADDRESS; case STUN_ATTR_FINGERPRINT: return STUN_VALUE_UINT32; case STUN_ATTR_RETRANSMIT_COUNT: return STUN_VALUE_UINT32; default: return STUN_VALUE_UNKNOWN; diff --git a/p2p/base/stun.h b/p2p/base/stun.h index b22b51e..c4f522b 100644 --- a/p2p/base/stun.h +++ b/p2p/base/stun.h @@ -63,7 +63,7 @@ enum StunAttributeType { STUN_ATTR_NONCE = 0x0015, // ByteString STUN_ATTR_XOR_MAPPED_ADDRESS = 0x0020, // XorAddress STUN_ATTR_SOFTWARE = 0x8022, // ByteString - STUN_ATTR_ALTERNATE_SERVER = 0x8023, // ByteString + STUN_ATTR_ALTERNATE_SERVER = 0x8023, // Address STUN_ATTR_FINGERPRINT = 0x8028, // UInt32 STUN_ATTR_RETRANSMIT_COUNT = 0xFF00 // UInt32 }; @@ -104,6 +104,7 @@ enum StunErrorCode { }; // Strings for the error codes above. +extern const char STUN_ERROR_REASON_TRY_ALTERNATE_SERVER[]; extern const char STUN_ERROR_REASON_BAD_REQUEST[]; extern const char STUN_ERROR_REASON_UNAUTHORIZED[]; extern const char STUN_ERROR_REASON_UNKNOWN_ATTRIBUTE[]; diff --git a/p2p/base/stunport.h b/p2p/base/stunport.h index 0a49b67..b3b6d5b 100644 --- a/p2p/base/stunport.h +++ b/p2p/base/stunport.h @@ -82,7 +82,7 @@ class UDPPort : public Port { return socket_->GetLocalAddress(); } - const ServerAddresses server_addresses() const { + const ServerAddresses& server_addresses() const { return server_addresses_; } void diff --git a/p2p/base/testturnserver.h b/p2p/base/testturnserver.h index e2c0ccb..6c30afe 100644 --- a/p2p/base/testturnserver.h +++ b/p2p/base/testturnserver.h @@ -29,6 +29,7 @@ #define TALK_P2P_BASE_TESTTURNSERVER_H_ #include <string> +#include <vector> #include "talk/p2p/base/basicpacketsocketfactory.h" #include "talk/p2p/base/stun.h" @@ -41,6 +42,27 @@ namespace cricket { static const char kTestRealm[] = "example.org"; static const char kTestSoftware[] = "TestTurnServer"; +class TestTurnRedirector : public TurnRedirectInterface { + public: + explicit TestTurnRedirector(const std::vector<rtc::SocketAddress>& addresses) + : alternate_server_addresses_(addresses), + iter_(alternate_server_addresses_.begin()) { + } + + virtual bool ShouldRedirect(const rtc::SocketAddress&, + rtc::SocketAddress* out) { + if (!out || iter_ == alternate_server_addresses_.end()) { + return false; + } + *out = *iter_++; + return true; + } + + private: + const std::vector<rtc::SocketAddress>& alternate_server_addresses_; + std::vector<rtc::SocketAddress>::const_iterator iter_; +}; + class TestTurnServer : public TurnAuthInterface { public: TestTurnServer(rtc::Thread* thread, @@ -61,6 +83,10 @@ class TestTurnServer : public TurnAuthInterface { TurnServer* server() { return &server_; } + void set_redirect_hook(TurnRedirectInterface* redirect_hook) { + server_.set_redirect_hook(redirect_hook); + } + void AddInternalSocket(const rtc::SocketAddress& int_addr, ProtocolType proto) { rtc::Thread* thread = rtc::Thread::Current(); diff --git a/p2p/base/transport.cc b/p2p/base/transport.cc index 6ee7b2a..d88f5e7 100644 --- a/p2p/base/transport.cc +++ b/p2p/base/transport.cc @@ -33,7 +33,7 @@ #include "talk/p2p/base/port.h" #include "talk/p2p/base/sessionmanager.h" #include "talk/p2p/base/transportchannelimpl.h" -#include "talk/xmllite/xmlelement.h" +#include "webrtc/libjingle/xmllite/xmlelement.h" #include "talk/xmpp/constants.h" #include "webrtc/base/bind.h" #include "webrtc/base/common.h" diff --git a/p2p/base/transport_unittest.cc b/p2p/base/transport_unittest.cc index fa2c116..8f7dae2 100644 --- a/p2p/base/transport_unittest.cc +++ b/p2p/base/transport_unittest.cc @@ -31,7 +31,7 @@ #include "talk/p2p/base/parsing.h" #include "talk/p2p/base/rawtransport.h" #include "talk/p2p/base/sessionmessages.h" -#include "talk/xmllite/xmlelement.h" +#include "webrtc/libjingle/xmllite/xmlelement.h" #include "talk/xmpp/constants.h" #include "webrtc/base/fakesslidentity.h" #include "webrtc/base/gunit.h" diff --git a/p2p/base/turnport.cc b/p2p/base/turnport.cc index 3faacd1..2908d71 100644 --- a/p2p/base/turnport.cc +++ b/p2p/base/turnport.cc @@ -51,6 +51,10 @@ static const int TURN_PERMISSION_TIMEOUT = 5 * 60 * 1000; // 5 minutes static const size_t TURN_CHANNEL_HEADER_SIZE = 4U; +// Retry at most twice (i.e. three different ALLOCATE requests) on +// STUN_ERROR_ALLOCATION_MISMATCH error per rfc5766. +static const size_t MAX_ALLOCATE_MISMATCH_RETRIES = 2; + inline bool IsTurnChannelData(uint16 msg_type) { return ((msg_type & 0xC000) == 0x4000); // MSB are 0b01 } @@ -78,6 +82,7 @@ class TurnAllocateRequest : public StunRequest { private: // Handles authentication challenge from the server. void OnAuthChallenge(StunMessage* response, int code); + void OnTryAlternate(StunMessage* response, int code); void OnUnknownAttribute(StunMessage* response); TurnPort* port_; @@ -187,7 +192,8 @@ TurnPort::TurnPort(rtc::Thread* thread, request_manager_(thread), next_channel_number_(TURN_CHANNEL_NUMBER_START), connected_(false), - server_priority_(server_priority) { + server_priority_(server_priority), + allocate_mismatch_retries_(0) { request_manager_.SignalSendPacket.connect(this, &TurnPort::OnSendStunPacket); } @@ -211,7 +217,8 @@ TurnPort::TurnPort(rtc::Thread* thread, request_manager_(thread), next_channel_number_(TURN_CHANNEL_NUMBER_START), connected_(false), - server_priority_(server_priority) { + server_priority_(server_priority), + allocate_mismatch_retries_(0) { request_manager_.SignalSendPacket.connect(this, &TurnPort::OnSendStunPacket); } @@ -253,6 +260,9 @@ void TurnPort::PrepareAddress() { return; } + // Insert the current address to prevent redirection pingpong. + attempted_server_addresses_.insert(server_address_.address); + LOG_J(LS_INFO, this) << "Trying to connect to TURN server via " << ProtoToString(server_address_.proto) << " @ " << server_address_.address.ToSensitiveString(); @@ -267,6 +277,8 @@ void TurnPort::PrepareAddress() { } bool TurnPort::CreateTurnClientSocket() { + ASSERT(!socket_ || SharedSocket()); + if (server_address_.proto == PROTO_UDP && !SharedSocket()) { socket_ = socket_factory()->CreateUdpSocket( rtc::SocketAddress(ip(), 0), min_port(), max_port()); @@ -336,6 +348,29 @@ void TurnPort::OnSocketClose(rtc::AsyncPacketSocket* socket, int error) { } } +void TurnPort::OnAllocateMismatch() { + if (allocate_mismatch_retries_ >= MAX_ALLOCATE_MISMATCH_RETRIES) { + LOG_J(LS_WARNING, this) << "Giving up on the port after " + << allocate_mismatch_retries_ + << " retries for STUN_ERROR_ALLOCATION_MISMATCH"; + OnAllocateError(); + return; + } + + LOG_J(LS_INFO, this) << "Allocating a new socket after " + << "STUN_ERROR_ALLOCATION_MISMATCH, retry = " + << allocate_mismatch_retries_ + 1; + if (SharedSocket()) { + ResetSharedSocket(); + } else { + delete socket_; + } + socket_ = NULL; + + PrepareAddress(); + ++allocate_mismatch_retries_; +} + Connection* TurnPort::CreateConnection(const Candidate& address, CandidateOrigin origin) { // TURN-UDP can only connect to UDP candidates. @@ -458,6 +493,38 @@ void TurnPort::OnReadyToSend(rtc::AsyncPacketSocket* socket) { } } + +// Update current server address port with the alternate server address port. +bool TurnPort::SetAlternateServer(const rtc::SocketAddress& address) { + // Check if we have seen this address before and reject if we did. + AttemptedServerSet::iterator iter = attempted_server_addresses_.find(address); + if (iter != attempted_server_addresses_.end()) { + LOG_J(LS_WARNING, this) << "Redirection to [" + << address.ToSensitiveString() + << "] ignored, allocation failed."; + return false; + } + + // If protocol family of server address doesn't match with local, return. + if (!IsCompatibleAddress(address)) { + LOG(LS_WARNING) << "Server IP address family does not match with " + << "local host address family type"; + return false; + } + + LOG_J(LS_INFO, this) << "Redirecting from TURN server [" + << server_address_.address.ToSensitiveString() + << "] to TURN server [" + << address.ToSensitiveString() + << "]"; + server_address_ = ProtocolAddress(address, server_address_.proto, + server_address_.secure); + + // Insert the current address to prevent redirection pingpong. + attempted_server_addresses_.insert(server_address_.address); + return true; +} + void TurnPort::ResolveTurnAddress(const rtc::SocketAddress& address) { if (resolver_) return; @@ -544,6 +611,9 @@ void TurnPort::OnMessage(rtc::Message* message) { if (message->message_id == MSG_ERROR) { SignalPortError(this); return; + } else if (message->message_id == MSG_ALLOCATE_MISMATCH) { + OnAllocateMismatch(); + return; } Port::OnMessage(message); @@ -805,6 +875,14 @@ void TurnAllocateRequest::OnErrorResponse(StunMessage* response) { case STUN_ERROR_UNAUTHORIZED: // Unauthrorized. OnAuthChallenge(response, error_code->code()); break; + case STUN_ERROR_TRY_ALTERNATE: + OnTryAlternate(response, error_code->code()); + break; + case STUN_ERROR_ALLOCATION_MISMATCH: + // We must handle this error async because trying to delete the socket in + // OnErrorResponse will cause a deadlock on the socket. + port_->thread()->Post(port_, TurnPort::MSG_ALLOCATE_MISMATCH); + break; default: LOG_J(LS_WARNING, port_) << "Allocate response error, code=" << error_code->code(); @@ -849,6 +927,57 @@ void TurnAllocateRequest::OnAuthChallenge(StunMessage* response, int code) { port_->SendRequest(new TurnAllocateRequest(port_), 0); } +void TurnAllocateRequest::OnTryAlternate(StunMessage* response, int code) { + // TODO(guoweis): Currently, we only support UDP redirect + if (port_->server_address().proto != PROTO_UDP) { + LOG_J(LS_WARNING, port_) << "Receiving 300 Alternate Server on non-UDP " + << "allocating request from [" + << port_->server_address().address.ToSensitiveString() + << "], failed as currently not supported"; + port_->OnAllocateError(); + return; + } + + // According to RFC 5389 section 11, there are use cases where + // authentication of response is not possible, we're not validating + // message integrity. + + // Get the alternate server address attribute value. + const StunAddressAttribute* alternate_server_attr = + response->GetAddress(STUN_ATTR_ALTERNATE_SERVER); + if (!alternate_server_attr) { + LOG_J(LS_WARNING, port_) << "Missing STUN_ATTR_ALTERNATE_SERVER " + << "attribute in try alternate error response"; + port_->OnAllocateError(); + return; + } + if (!port_->SetAlternateServer(alternate_server_attr->GetAddress())) { + port_->OnAllocateError(); + return; + } + + // Check the attributes. + const StunByteStringAttribute* realm_attr = + response->GetByteString(STUN_ATTR_REALM); + if (realm_attr) { + LOG_J(LS_INFO, port_) << "Applying STUN_ATTR_REALM attribute in " + << "try alternate error response."; + port_->set_realm(realm_attr->GetString()); + } + + const StunByteStringAttribute* nonce_attr = + response->GetByteString(STUN_ATTR_NONCE); + if (nonce_attr) { + LOG_J(LS_INFO, port_) << "Applying STUN_ATTR_NONCE attribute in " + << "try alternate error response."; + port_->set_nonce(nonce_attr->GetString()); + } + + // Send another allocate request to alternate server, + // with the received realm and nonce values. + port_->SendRequest(new TurnAllocateRequest(port_), 0); +} + TurnRefreshRequest::TurnRefreshRequest(TurnPort* port) : StunRequest(new TurnMessage()), port_(port) { @@ -876,7 +1005,6 @@ void TurnRefreshRequest::OnResponse(StunMessage* response) { } void TurnRefreshRequest::OnErrorResponse(StunMessage* response) { - // TODO(juberti): Handle 437 error response as a success. const StunErrorCodeAttribute* error_code = response->GetErrorCode(); LOG_J(LS_WARNING, port_) << "Refresh response error, code=" << error_code->code(); diff --git a/p2p/base/turnport.h b/p2p/base/turnport.h index d73b11d..ab7d4e7 100644 --- a/p2p/base/turnport.h +++ b/p2p/base/turnport.h @@ -30,6 +30,7 @@ #include <stdio.h> #include <list> +#include <set> #include <string> #include "talk/p2p/base/port.h" @@ -119,6 +120,12 @@ class TurnPort : public Port { int error() const { return error_; } + void OnAllocateMismatch(); + + rtc::AsyncPacketSocket* socket() const { + return socket_; + } + // Signal with resolved server address. // Parameters are port, server address and resolved server address. // This signal will be sent only if server address is resolved successfully. @@ -153,10 +160,14 @@ class TurnPort : public Port { int server_priority); private: - enum { MSG_ERROR = MSG_FIRST_AVAILABLE }; + enum { + MSG_ERROR = MSG_FIRST_AVAILABLE, + MSG_ALLOCATE_MISMATCH + }; typedef std::list<TurnEntry*> EntryList; typedef std::map<rtc::Socket::Option, int> SocketOptionsMap; + typedef std::set<rtc::SocketAddress> AttemptedServerSet; virtual void OnMessage(rtc::Message* pmsg); @@ -170,6 +181,7 @@ class TurnPort : public Port { } } + bool SetAlternateServer(const rtc::SocketAddress& address); void ResolveTurnAddress(const rtc::SocketAddress& address); void OnResolveResult(rtc::AsyncResolverInterface* resolver); @@ -207,6 +219,7 @@ class TurnPort : public Port { ProtocolAddress server_address_; RelayCredentials credentials_; + AttemptedServerSet attempted_server_addresses_; rtc::AsyncPacketSocket* socket_; SocketOptionsMap socket_options_; @@ -226,6 +239,9 @@ class TurnPort : public Port { // calculating the candidate priority. int server_priority_; + // The number of retries made due to allocate mismatch error. + size_t allocate_mismatch_retries_; + friend class TurnEntry; friend class TurnAllocateRequest; friend class TurnRefreshRequest; diff --git a/p2p/base/turnport_unittest.cc b/p2p/base/turnport_unittest.cc index 44dc64f..d895cbd 100644 --- a/p2p/base/turnport_unittest.cc +++ b/p2p/base/turnport_unittest.cc @@ -64,6 +64,8 @@ static const SocketAddress kTurnUdpIntAddr("99.99.99.3", static const SocketAddress kTurnTcpIntAddr("99.99.99.4", cricket::TURN_SERVER_PORT); static const SocketAddress kTurnUdpExtAddr("99.99.99.5", 0); +static const SocketAddress kTurnAlternateUdpIntAddr( + "99.99.99.6", cricket::TURN_SERVER_PORT); static const SocketAddress kTurnUdpIPv6IntAddr( "2400:4030:1:2c00:be30:abcd:efab:cdef", cricket::TURN_SERVER_PORT); static const SocketAddress kTurnUdpIPv6ExtAddr( @@ -208,10 +210,13 @@ class TurnPortTest : public testing::Test, const cricket::ProtocolAddress& server_address) { ASSERT(server_address.proto == cricket::PROTO_UDP); - socket_.reset(socket_factory_.CreateUdpSocket( - rtc::SocketAddress(kLocalAddr1.ipaddr(), 0), 0, 0)); - ASSERT_TRUE(socket_ != NULL); - socket_->SignalReadPacket.connect(this, &TurnPortTest::OnSocketReadPacket); + if (!socket_) { + socket_.reset(socket_factory_.CreateUdpSocket( + rtc::SocketAddress(kLocalAddr1.ipaddr(), 0), 0, 0)); + ASSERT_TRUE(socket_ != NULL); + socket_->SignalReadPacket.connect( + this, &TurnPortTest::OnSocketReadPacket); + } cricket::RelayCredentials credentials(username, password); turn_port_.reset(cricket::TurnPort::Create( @@ -411,6 +416,80 @@ TEST_F(TurnPortTest, TestTurnAllocateBadPassword) { ASSERT_EQ(0U, turn_port_->Candidates().size()); } +// Tests that a new local address is created after +// STUN_ERROR_ALLOCATION_MISMATCH. +TEST_F(TurnPortTest, TestTurnAllocateMismatch) { + // Do a normal allocation first. + CreateTurnPort(kTurnUsername, kTurnPassword, kTurnUdpProtoAddr); + turn_port_->PrepareAddress(); + EXPECT_TRUE_WAIT(turn_ready_, kTimeout); + rtc::SocketAddress first_addr(turn_port_->socket()->GetLocalAddress()); + + // Forces the socket server to assign the same port. + ss_->SetNextPortForTesting(first_addr.port()); + + turn_ready_ = false; + CreateTurnPort(kTurnUsername, kTurnPassword, kTurnUdpProtoAddr); + turn_port_->PrepareAddress(); + + // Verifies that the new port has the same address. + EXPECT_EQ(first_addr, turn_port_->socket()->GetLocalAddress()); + + EXPECT_TRUE_WAIT(turn_ready_, kTimeout); + + // Verifies that the new port has a different address now. + EXPECT_NE(first_addr, turn_port_->socket()->GetLocalAddress()); +} + +// Tests that a shared-socket-TurnPort creates its own socket after +// STUN_ERROR_ALLOCATION_MISMATCH. +TEST_F(TurnPortTest, TestSharedSocketAllocateMismatch) { + // Do a normal allocation first. + CreateSharedTurnPort(kTurnUsername, kTurnPassword, kTurnUdpProtoAddr); + turn_port_->PrepareAddress(); + EXPECT_TRUE_WAIT(turn_ready_, kTimeout); + rtc::SocketAddress first_addr(turn_port_->socket()->GetLocalAddress()); + + turn_ready_ = false; + CreateSharedTurnPort(kTurnUsername, kTurnPassword, kTurnUdpProtoAddr); + + // Verifies that the new port has the same address. + EXPECT_EQ(first_addr, turn_port_->socket()->GetLocalAddress()); + EXPECT_TRUE(turn_port_->SharedSocket()); + + turn_port_->PrepareAddress(); + EXPECT_TRUE_WAIT(turn_ready_, kTimeout); + + // Verifies that the new port has a different address now. + EXPECT_NE(first_addr, turn_port_->socket()->GetLocalAddress()); + EXPECT_FALSE(turn_port_->SharedSocket()); +} + +TEST_F(TurnPortTest, TestTurnTcpAllocateMismatch) { + turn_server_.AddInternalSocket(kTurnTcpIntAddr, cricket::PROTO_TCP); + CreateTurnPort(kTurnUsername, kTurnPassword, kTurnTcpProtoAddr); + + // Do a normal allocation first. + turn_port_->PrepareAddress(); + EXPECT_TRUE_WAIT(turn_ready_, kTimeout); + rtc::SocketAddress first_addr(turn_port_->socket()->GetLocalAddress()); + + // Forces the socket server to assign the same port. + ss_->SetNextPortForTesting(first_addr.port()); + + turn_ready_ = false; + CreateTurnPort(kTurnUsername, kTurnPassword, kTurnTcpProtoAddr); + turn_port_->PrepareAddress(); + + // Verifies that the new port has the same address. + EXPECT_EQ(first_addr, turn_port_->socket()->GetLocalAddress()); + + EXPECT_TRUE_WAIT(turn_ready_, kTimeout); + + // Verifies that the new port has a different address now. + EXPECT_NE(first_addr, turn_port_->socket()->GetLocalAddress()); +} + // Do a TURN allocation and try to send a packet to it from the outside. // The packet should be dropped. Then, try to send a packet from TURN to the // outside. It should reach its destination. Finally, try again from the @@ -445,6 +524,103 @@ TEST_F(TurnPortTest, TestTurnTlsTcpConnectionFails) { ASSERT_EQ(0U, turn_port_->Candidates().size()); } +// Test try-alternate-server feature. +TEST_F(TurnPortTest, TestTurnAlternateServer) { + std::vector<rtc::SocketAddress> redirect_addresses; + redirect_addresses.push_back(kTurnAlternateUdpIntAddr); + + cricket::TestTurnRedirector redirector(redirect_addresses); + turn_server_.AddInternalSocket(kTurnAlternateUdpIntAddr, + cricket::PROTO_UDP); + turn_server_.set_redirect_hook(&redirector); + CreateTurnPort(kTurnUsername, kTurnPassword, kTurnUdpProtoAddr); + + // Retrieve the address before we run the state machine. + const SocketAddress old_addr = turn_port_->server_address().address; + + turn_port_->PrepareAddress(); + EXPECT_TRUE_WAIT(turn_ready_, kTimeout); + // Retrieve the address again, the turn port's address should be + // changed. + const SocketAddress new_addr = turn_port_->server_address().address; + EXPECT_NE(old_addr, new_addr); + ASSERT_EQ(1U, turn_port_->Candidates().size()); + EXPECT_EQ(kTurnUdpExtAddr.ipaddr(), + turn_port_->Candidates()[0].address().ipaddr()); + EXPECT_NE(0, turn_port_->Candidates()[0].address().port()); +} + +// Test that we fail when we redirect to an address different from +// current IP family. +TEST_F(TurnPortTest, TestTurnAlternateServerV4toV6) { + std::vector<rtc::SocketAddress> redirect_addresses; + redirect_addresses.push_back(kTurnUdpIPv6IntAddr); + + cricket::TestTurnRedirector redirector(redirect_addresses); + turn_server_.AddInternalSocket(kTurnAlternateUdpIntAddr, + cricket::PROTO_UDP); + turn_server_.set_redirect_hook(&redirector); + CreateTurnPort(kTurnUsername, kTurnPassword, kTurnUdpProtoAddr); + turn_port_->PrepareAddress(); + EXPECT_TRUE_WAIT(turn_error_, kTimeout); +} + +// Test that we fail to handle alternate-server response over TCP protocol. +TEST_F(TurnPortTest, TestTurnAlternateServerTcp) { + std::vector<rtc::SocketAddress> redirect_addresses; + redirect_addresses.push_back(kTurnAlternateUdpIntAddr); + + cricket::TestTurnRedirector redirector(redirect_addresses); + turn_server_.set_redirect_hook(&redirector); + turn_server_.AddInternalSocket(kTurnTcpIntAddr, cricket::PROTO_TCP); + CreateTurnPort(kTurnUsername, kTurnPassword, kTurnTcpProtoAddr); + + turn_server_.AddInternalSocket(kTurnAlternateUdpIntAddr, cricket::PROTO_TCP); + turn_port_->PrepareAddress(); + EXPECT_TRUE_WAIT(turn_error_, kTimeout); +} + +// Test try-alternate-server catches the case of pingpong. +TEST_F(TurnPortTest, TestTurnAlternateServerPingPong) { + std::vector<rtc::SocketAddress> redirect_addresses; + redirect_addresses.push_back(kTurnAlternateUdpIntAddr); + redirect_addresses.push_back(kTurnUdpIntAddr); + + cricket::TestTurnRedirector redirector(redirect_addresses); + + turn_server_.AddInternalSocket(kTurnAlternateUdpIntAddr, + cricket::PROTO_UDP); + turn_server_.set_redirect_hook(&redirector); + CreateTurnPort(kTurnUsername, kTurnPassword, kTurnUdpProtoAddr); + + turn_port_->PrepareAddress(); + EXPECT_TRUE_WAIT(turn_error_, kTimeout); + ASSERT_EQ(0U, turn_port_->Candidates().size()); + rtc::SocketAddress address; + // Verify that we have exhausted all alternate servers instead of + // failure caused by other errors. + EXPECT_FALSE(redirector.ShouldRedirect(address, &address)); +} + +// Test try-alternate-server catch the case of repeated server. +TEST_F(TurnPortTest, TestTurnAlternateServerDetectRepetition) { + std::vector<rtc::SocketAddress> redirect_addresses; + redirect_addresses.push_back(kTurnAlternateUdpIntAddr); + redirect_addresses.push_back(kTurnAlternateUdpIntAddr); + + cricket::TestTurnRedirector redirector(redirect_addresses); + + turn_server_.AddInternalSocket(kTurnAlternateUdpIntAddr, + cricket::PROTO_UDP); + turn_server_.set_redirect_hook(&redirector); + CreateTurnPort(kTurnUsername, kTurnPassword, kTurnUdpProtoAddr); + + turn_port_->PrepareAddress(); + EXPECT_TRUE_WAIT(turn_error_, kTimeout); + ASSERT_EQ(0U, turn_port_->Candidates().size()); +} + + // Run TurnConnectionTest with one-time-use nonce feature. // Here server will send a 438 STALE_NONCE error message for // every TURN transaction. @@ -515,4 +691,3 @@ TEST_F(TurnPortTest, TestResolverShutdown) { EXPECT_EQ(last_fd_count, GetFDCount()); } #endif - diff --git a/p2p/base/turnserver.cc b/p2p/base/turnserver.cc index abc065a..dbcbcd4 100644 --- a/p2p/base/turnserver.cc +++ b/p2p/base/turnserver.cc @@ -62,9 +62,9 @@ inline bool IsTurnChannelData(uint16 msg_type) { return ((msg_type & 0xC000) == 0x4000); } -// IDs used for posted messages. +// IDs used for posted messages for TurnServer::Allocation. enum { - MSG_TIMEOUT, + MSG_ALLOCATION_TIMEOUT, }; // Encapsulates a TURN allocation. @@ -208,6 +208,7 @@ TurnServer::TurnServer(rtc::Thread* thread) : thread_(thread), nonce_key_(rtc::CreateRandomString(kNonceKeySize)), auth_hook_(NULL), + redirect_hook_(NULL), enable_otu_nonce_(false) { } @@ -316,6 +317,15 @@ void TurnServer::HandleStunMessage(Connection* conn, const char* data, return; } + if (redirect_hook_ != NULL && msg.type() == STUN_ALLOCATE_REQUEST) { + rtc::SocketAddress address; + if (redirect_hook_->ShouldRedirect(conn->src(), &address)) { + SendErrorResponseWithAlternateServer( + conn, &msg, address); + return; + } + } + // Look up the key that we'll use to validate the M-I. If we have an // existing allocation, the key will already be cached. Allocation* allocation = FindAllocation(conn); @@ -334,7 +344,6 @@ void TurnServer::HandleStunMessage(Connection* conn, const char* data, } if (!allocation && msg.type() == STUN_ALLOCATE_REQUEST) { - // This is a new allocate request. HandleAllocateRequest(conn, &msg, key); } else if (allocation && (msg.type() != STUN_ALLOCATE_REQUEST || @@ -551,6 +560,17 @@ void TurnServer::SendErrorResponseWithRealmAndNonce( SendStun(conn, &resp); } +void TurnServer::SendErrorResponseWithAlternateServer( + Connection* conn, const StunMessage* msg, + const rtc::SocketAddress& addr) { + TurnMessage resp; + InitErrorResponse(msg, STUN_ERROR_TRY_ALTERNATE, + STUN_ERROR_REASON_TRY_ALTERNATE_SERVER, &resp); + VERIFY(resp.AddAttribute(new StunAddressAttribute( + STUN_ATTR_ALTERNATE_SERVER, addr))); + SendStun(conn, &resp); +} + void TurnServer::SendStun(Connection* conn, StunMessage* msg) { rtc::ByteBuffer buf; // Add a SOFTWARE attribute if one is set. @@ -588,7 +608,9 @@ void TurnServer::DestroyInternalSocket(rtc::AsyncPacketSocket* socket) { InternalSocketMap::iterator iter = server_sockets_.find(socket); if (iter != server_sockets_.end()) { rtc::AsyncPacketSocket* socket = iter->first; - delete socket; + // We must destroy the socket async to avoid invalidating the sigslot + // callback list iterator inside a sigslot callback. + rtc::Thread::Current()->Dispose(socket); server_sockets_.erase(iter); } } @@ -642,7 +664,7 @@ TurnServer::Allocation::~Allocation() { it != perms_.end(); ++it) { delete *it; } - thread_->Clear(this, MSG_TIMEOUT); + thread_->Clear(this, MSG_ALLOCATION_TIMEOUT); LOG_J(LS_INFO, this) << "Allocation destroyed"; } @@ -687,7 +709,7 @@ void TurnServer::Allocation::HandleAllocateRequest(const TurnMessage* msg) { // Figure out the lifetime and start the allocation timer. int lifetime_secs = ComputeLifetime(msg); - thread_->PostDelayed(lifetime_secs * 1000, this, MSG_TIMEOUT); + thread_->PostDelayed(lifetime_secs * 1000, this, MSG_ALLOCATION_TIMEOUT); LOG_J(LS_INFO, this) << "Created allocation, lifetime=" << lifetime_secs; @@ -714,8 +736,8 @@ void TurnServer::Allocation::HandleRefreshRequest(const TurnMessage* msg) { int lifetime_secs = ComputeLifetime(msg); // Reset the expiration timer. - thread_->Clear(this, MSG_TIMEOUT); - thread_->PostDelayed(lifetime_secs * 1000, this, MSG_TIMEOUT); + thread_->Clear(this, MSG_ALLOCATION_TIMEOUT); + thread_->PostDelayed(lifetime_secs * 1000, this, MSG_ALLOCATION_TIMEOUT); LOG_J(LS_INFO, this) << "Refreshed allocation, lifetime=" << lifetime_secs; @@ -943,7 +965,7 @@ void TurnServer::Allocation::SendExternal(const void* data, size_t size, } void TurnServer::Allocation::OnMessage(rtc::Message* msg) { - ASSERT(msg->message_id == MSG_TIMEOUT); + ASSERT(msg->message_id == MSG_ALLOCATION_TIMEOUT); SignalDestroyed(this); delete this; } @@ -968,16 +990,16 @@ TurnServer::Permission::Permission(rtc::Thread* thread, } TurnServer::Permission::~Permission() { - thread_->Clear(this, MSG_TIMEOUT); + thread_->Clear(this, MSG_ALLOCATION_TIMEOUT); } void TurnServer::Permission::Refresh() { - thread_->Clear(this, MSG_TIMEOUT); - thread_->PostDelayed(kPermissionTimeout, this, MSG_TIMEOUT); + thread_->Clear(this, MSG_ALLOCATION_TIMEOUT); + thread_->PostDelayed(kPermissionTimeout, this, MSG_ALLOCATION_TIMEOUT); } void TurnServer::Permission::OnMessage(rtc::Message* msg) { - ASSERT(msg->message_id == MSG_TIMEOUT); + ASSERT(msg->message_id == MSG_ALLOCATION_TIMEOUT); SignalDestroyed(this); delete this; } @@ -989,16 +1011,16 @@ TurnServer::Channel::Channel(rtc::Thread* thread, int id, } TurnServer::Channel::~Channel() { - thread_->Clear(this, MSG_TIMEOUT); + thread_->Clear(this, MSG_ALLOCATION_TIMEOUT); } void TurnServer::Channel::Refresh() { - thread_->Clear(this, MSG_TIMEOUT); - thread_->PostDelayed(kChannelTimeout, this, MSG_TIMEOUT); + thread_->Clear(this, MSG_ALLOCATION_TIMEOUT); + thread_->PostDelayed(kChannelTimeout, this, MSG_ALLOCATION_TIMEOUT); } void TurnServer::Channel::OnMessage(rtc::Message* msg) { - ASSERT(msg->message_id == MSG_TIMEOUT); + ASSERT(msg->message_id == MSG_ALLOCATION_TIMEOUT); SignalDestroyed(this); delete this; } diff --git a/p2p/base/turnserver.h b/p2p/base/turnserver.h index 4798232..553d00c 100644 --- a/p2p/base/turnserver.h +++ b/p2p/base/turnserver.h @@ -63,6 +63,14 @@ class TurnAuthInterface { std::string* key) = 0; }; +// An interface enables Turn Server to control redirection behavior. +class TurnRedirectInterface { + public: + virtual bool ShouldRedirect(const rtc::SocketAddress& address, + rtc::SocketAddress* out) = 0; + virtual ~TurnRedirectInterface() {} +}; + // The core TURN server class. Give it a socket to listen on via // AddInternalServerSocket, and a factory to create external sockets via // SetExternalSocketFactory, and it's ready to go. @@ -83,6 +91,10 @@ class TurnServer : public sigslot::has_slots<> { // Sets the authentication callback; does not take ownership. void set_auth_hook(TurnAuthInterface* auth_hook) { auth_hook_ = auth_hook; } + void set_redirect_hook(TurnRedirectInterface* redirect_hook) { + redirect_hook_ = redirect_hook; + } + void set_enable_otu_nonce(bool enable) { enable_otu_nonce_ = enable; } // Starts listening for packets from internal clients. @@ -155,6 +167,11 @@ class TurnServer : public sigslot::has_slots<> { const StunMessage* req, int code, const std::string& reason); + + void SendErrorResponseWithAlternateServer(Connection* conn, + const StunMessage* req, + const rtc::SocketAddress& addr); + void SendStun(Connection* conn, StunMessage* msg); void Send(Connection* conn, const rtc::ByteBuffer& buf); @@ -171,14 +188,17 @@ class TurnServer : public sigslot::has_slots<> { std::string realm_; std::string software_; TurnAuthInterface* auth_hook_; + TurnRedirectInterface* redirect_hook_; // otu - one-time-use. Server will respond with 438 if it's // sees the same nonce in next transaction. bool enable_otu_nonce_; + InternalSocketMap server_sockets_; ServerSocketMap server_listen_sockets_; rtc::scoped_ptr<rtc::PacketSocketFactory> external_socket_factory_; rtc::SocketAddress external_addr_; + AllocationMap allocations_; }; diff --git a/p2p/client/autoportallocator.h b/p2p/client/autoportallocator.h index 298f829..ed87162 100644 --- a/p2p/client/autoportallocator.h +++ b/p2p/client/autoportallocator.h @@ -25,8 +25,8 @@ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef TALK_EXAMPLES_LOGIN_AUTOPORTALLOCATOR_H_ -#define TALK_EXAMPLES_LOGIN_AUTOPORTALLOCATOR_H_ +#ifndef TALK_P2P_CLIENT_AUTOPORTALLOCATOR_H_ +#define TALK_P2P_CLIENT_AUTOPORTALLOCATOR_H_ #include <string> #include <vector> @@ -66,4 +66,4 @@ class AutoPortAllocator : public cricket::HttpPortAllocator { } }; -#endif // TALK_EXAMPLES_LOGIN_AUTOPORTALLOCATOR_H_ +#endif // TALK_P2P_CLIENT_AUTOPORTALLOCATOR_H_ diff --git a/p2p/client/basicportallocator.cc b/p2p/client/basicportallocator.cc index d39db8f..0ec13e7 100644 --- a/p2p/client/basicportallocator.cc +++ b/p2p/client/basicportallocator.cc @@ -47,13 +47,15 @@ using rtc::CreateRandomString; namespace { -const uint32 MSG_CONFIG_START = 1; -const uint32 MSG_CONFIG_READY = 2; -const uint32 MSG_ALLOCATE = 3; -const uint32 MSG_ALLOCATION_PHASE = 4; -const uint32 MSG_SHAKE = 5; -const uint32 MSG_SEQUENCEOBJECTS_CREATED = 6; -const uint32 MSG_CONFIG_STOP = 7; +enum { + MSG_CONFIG_START, + MSG_CONFIG_READY, + MSG_ALLOCATE, + MSG_ALLOCATION_PHASE, + MSG_SHAKE, + MSG_SEQUENCEOBJECTS_CREATED, + MSG_CONFIG_STOP, +}; const int PHASE_UDP = 0; const int PHASE_RELAY = 1; @@ -147,9 +149,6 @@ class AllocationSequence : public rtc::MessageHandler, const rtc::PacketTime& packet_time); void OnPortDestroyed(PortInterface* port); - void OnResolvedTurnServerAddress( - TurnPort* port, const rtc::SocketAddress& server_address, - const rtc::SocketAddress& resolved_server_address); BasicPortAllocatorSession* session_; rtc::Network* network_; @@ -161,8 +160,7 @@ class AllocationSequence : public rtc::MessageHandler, rtc::scoped_ptr<rtc::AsyncPacketSocket> udp_socket_; // There will be only one udp port per AllocationSequence. UDPPort* udp_port_; - // Keeping a map for turn ports keyed with server addresses. - std::map<rtc::SocketAddress, Port*> turn_ports_; + std::vector<TurnPort*> turn_ports_; int phase_; }; @@ -228,10 +226,11 @@ BasicPortAllocator::~BasicPortAllocator() { PortAllocatorSession *BasicPortAllocator::CreateSessionInternal( const std::string& content_name, int component, const std::string& ice_ufrag, const std::string& ice_pwd) { - return new BasicPortAllocatorSession(this, content_name, component, - ice_ufrag, ice_pwd); + return new BasicPortAllocatorSession( + this, content_name, component, ice_ufrag, ice_pwd); } + // BasicPortAllocatorSession BasicPortAllocatorSession::BasicPortAllocatorSession( BasicPortAllocator *allocator, @@ -432,7 +431,11 @@ void BasicPortAllocatorSession::DoAllocate() { } if (!(sequence_flags & PORTALLOCATOR_ENABLE_IPV6) && +#ifdef USE_WEBRTC_DEV_BRANCH + networks[i]->GetBestIP().family() == AF_INET6) { +#else // USE_WEBRTC_DEV_BRANCH networks[i]->ip().family() == AF_INET6) { +#endif // USE_WEBRTC_DEV_BRANCH // Skip IPv6 networks unless the flag's been set. continue; } @@ -530,8 +533,10 @@ void BasicPortAllocatorSession::OnCandidateReady( // Send candidates whose protocol is enabled. std::vector<Candidate> candidates; ProtocolType pvalue; + bool candidate_allowed_to_send = CheckCandidateFilter(c); if (StringToProto(c.protocol().c_str(), &pvalue) && - data->sequence()->ProtocolEnabled(pvalue)) { + data->sequence()->ProtocolEnabled(pvalue) && + candidate_allowed_to_send) { candidates.push_back(c); } @@ -542,7 +547,9 @@ void BasicPortAllocatorSession::OnCandidateReady( // Moving to READY state as we have atleast one candidate from the port. // Since this port has atleast one candidate we should forward this port // to listners, to allow connections from this port. - if (!data->ready()) { + // Also we should make sure that candidate gathered from this port is allowed + // to send outside. + if (!data->ready() && candidate_allowed_to_send) { data->set_ready(); SignalPortReady(this, port); } @@ -588,6 +595,8 @@ void BasicPortAllocatorSession::OnProtocolEnabled(AllocationSequence* seq, const std::vector<Candidate>& potentials = it->port()->Candidates(); for (size_t i = 0; i < potentials.size(); ++i) { + if (!CheckCandidateFilter(potentials[i])) + continue; ProtocolType pvalue; if (!StringToProto(potentials[i].protocol().c_str(), &pvalue)) continue; @@ -602,6 +611,31 @@ void BasicPortAllocatorSession::OnProtocolEnabled(AllocationSequence* seq, } } +bool BasicPortAllocatorSession::CheckCandidateFilter(const Candidate& c) { + uint32 filter = allocator_->candidate_filter(); + bool allowed = false; + if (filter & CF_RELAY) { + allowed |= (c.type() == RELAY_PORT_TYPE); + } + + if (filter & CF_REFLEXIVE) { + // We allow host candidates if the filter allows server-reflexive candidates + // and the candidate is a public IP. Because we don't generate + // server-reflexive candidates if they have the same IP as the host + // candidate (i.e. when the host candidate is a public IP), filtering to + // only server-reflexive candidates won't work right when the host + // candidates have public IPs. + allowed |= (c.type() == STUN_PORT_TYPE) || + (c.type() == LOCAL_PORT_TYPE && !c.address().IsPrivateIP()); + } + + if (filter & CF_HOST) { + allowed |= (c.type() == LOCAL_PORT_TYPE); + } + + return allowed; +} + void BasicPortAllocatorSession::OnPortAllocationComplete( AllocationSequence* seq) { // Send candidate allocation complete signal if all ports are done. @@ -698,7 +732,12 @@ AllocationSequence::AllocationSequence(BasicPortAllocatorSession* session, uint32 flags) : session_(session), network_(network), + +#ifdef USE_WEBRTC_DEV_BRANCH + ip_(network->GetBestIP()), +#else // USE_WEBRTC_DEV_BRANCH ip_(network->ip()), +#endif // USE_WEBRTC_DEV_BRANCH config_(config), state_(kInit), flags_(flags), @@ -741,7 +780,11 @@ AllocationSequence::~AllocationSequence() { void AllocationSequence::DisableEquivalentPhases(rtc::Network* network, PortConfiguration* config, uint32* flags) { +#ifdef USE_WEBRTC_DEV_BRANCH + if (!((network == network_) && (ip_ == network->GetBestIP()))) { +#else // USE_WEBRTC_DEV_BRANCH if (!((network == network_) && (ip_ == network->ip()))) { +#endif // USE_WEBRTC_DEV_BRANCH // Different network setup; nothing is equivalent. return; } @@ -1020,26 +1063,15 @@ void AllocationSequence::CreateTurnPort(const RelayServerConfig& config) { // don't pass shared socket for ports which will create TCP sockets. // TODO(mallinath) - Enable shared socket mode for TURN ports. Disabled // due to webrtc bug https://code.google.com/p/webrtc/issues/detail?id=3537 - if (IsFlagSet(PORTALLOCATOR_ENABLE_TURN_SHARED_SOCKET) && + if (IsFlagSet(PORTALLOCATOR_ENABLE_SHARED_SOCKET) && relay_port->proto == PROTO_UDP) { port = TurnPort::Create(session_->network_thread(), session_->socket_factory(), network_, udp_socket_.get(), session_->username(), session_->password(), *relay_port, config.credentials, config.priority); - // If we are using shared socket for TURN and udp ports, we need to - // find a way to demux the packets to the correct port when received. - // Mapping against server_address is one way of doing this. When packet - // is received the remote_address will be checked against the map. - // If server address is not resolved, a signal will be sent from the port - // after the address is resolved. The map entry will updated with the - // resolved address when the signal is received from the port. - if ((*relay_port).address.IsUnresolved()) { - // If server address is not resolved then listen for signal from port. - port->SignalResolvedServerAddress.connect( - this, &AllocationSequence::OnResolvedTurnServerAddress); - } - turn_ports_[(*relay_port).address] = port; + + turn_ports_.push_back(port); // Listen to the port destroyed signal, to allow AllocationSequence to // remove entrt from it's map. port->SignalDestroyed.connect(this, &AllocationSequence::OnPortDestroyed); @@ -1063,51 +1095,45 @@ void AllocationSequence::OnReadPacket( const rtc::SocketAddress& remote_addr, const rtc::PacketTime& packet_time) { ASSERT(socket == udp_socket_.get()); - // If the packet is received from one of the TURN server in the config, then - // pass down the packet to that port, otherwise it will be handed down to - // the local udp port. - Port* port = NULL; - std::map<rtc::SocketAddress, Port*>::iterator iter = - turn_ports_.find(remote_addr); - if (iter != turn_ports_.end()) { - port = iter->second; - } else if (udp_port_) { - port = udp_port_; + + bool turn_port_found = false; + + // Try to find the TurnPort that matches the remote address. Note that the + // message could be a STUN binding response if the TURN server is also used as + // a STUN server. We don't want to parse every message here to check if it is + // a STUN binding response, so we pass the message to TurnPort regardless of + // the message type. The TurnPort will just ignore the message since it will + // not find any request by transaction ID. + for (std::vector<TurnPort*>::const_iterator it = turn_ports_.begin(); + it != turn_ports_.end(); ++it) { + TurnPort* port = *it; + if (port->server_address().address == remote_addr) { + port->HandleIncomingPacket(socket, data, size, remote_addr, packet_time); + turn_port_found = true; + break; + } } - ASSERT(port != NULL); - if (port) { - port->HandleIncomingPacket(socket, data, size, remote_addr, packet_time); + + if (udp_port_) { + const ServerAddresses& stun_servers = udp_port_->server_addresses(); + + // Pass the packet to the UdpPort if there is no matching TurnPort, or if + // the TURN server is also a STUN server. + if (!turn_port_found || + stun_servers.find(remote_addr) != stun_servers.end()) { + udp_port_->HandleIncomingPacket( + socket, data, size, remote_addr, packet_time); + } } } void AllocationSequence::OnPortDestroyed(PortInterface* port) { if (udp_port_ == port) { udp_port_ = NULL; - } else { - std::map<rtc::SocketAddress, Port*>::iterator iter; - for (iter = turn_ports_.begin(); iter != turn_ports_.end(); ++iter) { - if (iter->second == port) { - turn_ports_.erase(iter); - break; - } - } - } -} - -void AllocationSequence::OnResolvedTurnServerAddress( - TurnPort* port, const rtc::SocketAddress& server_address, - const rtc::SocketAddress& resolved_server_address) { - std::map<rtc::SocketAddress, Port*>::iterator iter; - iter = turn_ports_.find(server_address); - if (iter == turn_ports_.end()) { - LOG(LS_INFO) << "TurnPort entry is not found in the map."; return; } - ASSERT(iter->second == port); - // Remove old entry and then insert using the resolved address as key. - turn_ports_.erase(iter); - turn_ports_[resolved_server_address] = port; + turn_ports_.erase(std::find(turn_ports_.begin(), turn_ports_.end(), port)); } // PortConfiguration diff --git a/p2p/client/basicportallocator.h b/p2p/client/basicportallocator.h index 5f43880..d424772 100644 --- a/p2p/client/basicportallocator.h +++ b/p2p/client/basicportallocator.h @@ -160,7 +160,6 @@ class BasicPortAllocatorSession : public PortAllocatorSession, void set_ready() { ASSERT(state_ == STATE_INIT); state_ = STATE_READY; } void set_complete() { - ASSERT(state_ == STATE_READY); state_ = STATE_COMPLETE; } void set_error() { @@ -201,6 +200,8 @@ class BasicPortAllocatorSession : public PortAllocatorSession, void OnPortAllocationComplete(AllocationSequence* seq); PortData* FindPort(Port* port); + bool CheckCandidateFilter(const Candidate& c); + BasicPortAllocator* allocator_; rtc::Thread* network_thread_; rtc::scoped_ptr<rtc::PacketSocketFactory> owned_socket_factory_; diff --git a/p2p/client/connectivitychecker.cc b/p2p/client/connectivitychecker.cc index 06de5e4..723c5a1 100644 --- a/p2p/client/connectivitychecker.cc +++ b/p2p/client/connectivitychecker.cc @@ -1,5 +1,29 @@ -// Copyright 2011 Google Inc. All Rights Reserved. - +/* + * libjingle + * Copyright 2011, Google Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ #include <string> @@ -214,7 +238,12 @@ void ConnectivityChecker::OnRequestDone(rtc::AsyncHttpRequest* request) { return; } rtc::ProxyInfo proxy_info = request->proxy(); - NicMap::iterator i = nics_.find(NicId(networks[0]->ip(), proxy_info.address)); + NicMap::iterator i = +#ifdef USE_WEBRTC_DEV_BRANCH + nics_.find(NicId(networks[0]->GetBestIP(), proxy_info.address)); +#else // USE_WEBRTC_DEV_BRANCH + nics_.find(NicId(networks[0]->ip(), proxy_info.address)); +#endif // USE_WEBRTC_DEV_BRANCH if (i != nics_.end()) { int port = request->port(); uint32 now = rtc::Time(); @@ -247,7 +276,11 @@ void ConnectivityChecker::OnRelayPortComplete(Port* port) { ASSERT(worker_ == rtc::Thread::Current()); RelayPort* relay_port = reinterpret_cast<RelayPort*>(port); const ProtocolAddress* address = relay_port->ServerAddress(0); +#ifdef USE_WEBRTC_DEV_BRANCH + rtc::IPAddress ip = port->Network()->GetBestIP(); +#else // USE_WEBRTC_DEV_BRANCH rtc::IPAddress ip = port->Network()->ip(); +#endif // USE_WEBRTC_DEV_BRANCH NicMap::iterator i = nics_.find(NicId(ip, port->proxy().address)); if (i != nics_.end()) { // We have it already, add the new information. @@ -281,7 +314,11 @@ void ConnectivityChecker::OnStunPortComplete(Port* port) { ASSERT(worker_ == rtc::Thread::Current()); const std::vector<Candidate> candidates = port->Candidates(); Candidate c = candidates[0]; +#ifdef USE_WEBRTC_DEV_BRANCH + rtc::IPAddress ip = port->Network()->GetBestIP(); +#else // USE_WEBRTC_DEV_BRANCH rtc::IPAddress ip = port->Network()->ip(); +#endif // USE_WEBRTC_DEV_BRANCH NicMap::iterator i = nics_.find(NicId(ip, port->proxy().address)); if (i != nics_.end()) { // We have it already, add the new information. @@ -300,7 +337,11 @@ void ConnectivityChecker::OnStunPortComplete(Port* port) { void ConnectivityChecker::OnStunPortError(Port* port) { ASSERT(worker_ == rtc::Thread::Current()); LOG(LS_ERROR) << "Stun address error."; +#ifdef USE_WEBRTC_DEV_BRANCH + rtc::IPAddress ip = port->Network()->GetBestIP(); +#else // USE_WEBRTC_DEV_BRANCH rtc::IPAddress ip = port->Network()->ip(); +#endif // USE_WEBRTC_DEV_BRANCH NicMap::iterator i = nics_.find(NicId(ip, port->proxy().address)); if (i != nics_.end()) { // We have it already, add the new information. @@ -337,19 +378,36 @@ HttpPortAllocator* ConnectivityChecker::CreatePortAllocator( StunPort* ConnectivityChecker::CreateStunPort( const std::string& username, const std::string& password, const PortConfiguration* config, rtc::Network* network) { - return StunPort::Create(worker_, socket_factory_.get(), - network, network->ip(), 0, 0, - username, password, config->stun_servers); + return StunPort::Create(worker_, + socket_factory_.get(), + network, +#ifdef USE_WEBRTC_DEV_BRANCH + network->GetBestIP(), +#else // USE_WEBRTC_DEV_BRANCH + network->ip(), +#endif // USE_WEBRTC_DEV_BRANCH + 0, + 0, + username, + password, + config->stun_servers); } RelayPort* ConnectivityChecker::CreateRelayPort( const std::string& username, const std::string& password, const PortConfiguration* config, rtc::Network* network) { - return RelayPort::Create(worker_, socket_factory_.get(), - network, network->ip(), + return RelayPort::Create(worker_, + socket_factory_.get(), + network, +#ifdef USE_WEBRTC_DEV_BRANCH + network->GetBestIP(), +#else // USE_WEBRTC_DEV_BRANCH + network->ip(), +#endif // USE_WEBRTC_DEV_BRANCH port_allocator_->min_port(), port_allocator_->max_port(), - username, password); + username, + password); } void ConnectivityChecker::CreateRelayPorts( @@ -365,8 +423,12 @@ void ConnectivityChecker::CreateRelayPorts( for (relay = config->relays.begin(); relay != config->relays.end(); ++relay) { for (uint32 i = 0; i < networks.size(); ++i) { - NicMap::iterator iter = nics_.find(NicId(networks[i]->ip(), - proxy_info.address)); + NicMap::iterator iter = +#ifdef USE_WEBRTC_DEV_BRANCH + nics_.find(NicId(networks[i]->GetBestIP(), proxy_info.address)); +#else // USE_WEBRTC_DEV_BRANCH + nics_.find(NicId(networks[i]->ip(), proxy_info.address)); +#endif // USE_WEBRTC_DEV_BRANCH if (iter != nics_.end()) { // TODO: Now setting the same start time for all protocols. // This might affect accuracy, but since we are mainly looking for @@ -423,7 +485,11 @@ void ConnectivityChecker::AllocatePorts() { rtc::ProxyInfo proxy_info = GetProxyInfo(); bool allocate_relay_ports = false; for (uint32 i = 0; i < networks.size(); ++i) { +#ifdef USE_WEBRTC_DEV_BRANCH + if (AddNic(networks[i]->GetBestIP(), proxy_info.address)) { +#else // USE_WEBRTC_DEV_BRANCH if (AddNic(networks[i]->ip(), proxy_info.address)) { +#endif // USE_WEBRTC_DEV_BRANCH Port* port = CreateStunPort(username, password, &config, networks[i]); if (port) { @@ -500,7 +566,12 @@ void ConnectivityChecker::RegisterHttpStart(int port) { return; } rtc::ProxyInfo proxy_info = GetProxyInfo(); - NicMap::iterator i = nics_.find(NicId(networks[0]->ip(), proxy_info.address)); + NicMap::iterator i = +#ifdef USE_WEBRTC_DEV_BRANCH + nics_.find(NicId(networks[0]->GetBestIP(), proxy_info.address)); +#else // USE_WEBRTC_DEV_BRANCH + nics_.find(NicId(networks[0]->ip(), proxy_info.address)); +#endif // USE_WEBRTC_DEV_BRANCH if (i != nics_.end()) { uint32 now = rtc::Time(); NicInfo* nic_info = &i->second; diff --git a/p2p/client/connectivitychecker_unittest.cc b/p2p/client/connectivitychecker_unittest.cc index b96cf17..187505a 100644 --- a/p2p/client/connectivitychecker_unittest.cc +++ b/p2p/client/connectivitychecker_unittest.cc @@ -1,5 +1,29 @@ -// Copyright 2011 Google Inc. All Rights Reserved. - +/* + * libjingle + * Copyright 2011, Google Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ #include <string> @@ -211,19 +235,35 @@ class ConnectivityCheckerForTest : public ConnectivityChecker { virtual StunPort* CreateStunPort( const std::string& username, const std::string& password, const PortConfiguration* config, rtc::Network* network) { - return new FakeStunPort(worker(), socket_factory_, - network, network->ip(), - kMinPort, kMaxPort, - username, password, + return new FakeStunPort(worker(), + socket_factory_, + network, +#ifdef USE_WEBRTC_DEV_BRANCH + network->GetBestIP(), +#else // USE_WEBRTC_DEV_BRANCH + network->ip(), +#endif // USE_WEBRTC_DEV_BRANCH + kMinPort, + kMaxPort, + username, + password, config->stun_servers); } virtual RelayPort* CreateRelayPort( const std::string& username, const std::string& password, const PortConfiguration* config, rtc::Network* network) { - return new FakeRelayPort(worker(), socket_factory_, - network, network->ip(), - kMinPort, kMaxPort, - username, password); + return new FakeRelayPort(worker(), + socket_factory_, + network, +#ifdef USE_WEBRTC_DEV_BRANCH + network->GetBestIP(), +#else // USE_WEBRTC_DEV_BRANCH + network->ip(), +#endif // USE_WEBRTC_DEV_BRANCH + kMinPort, + kMaxPort, + username, + password); } virtual void InitiateProxyDetection() { if (!proxy_initiated_) { diff --git a/p2p/client/fakeportallocator.h b/p2p/client/fakeportallocator.h index 6c36c4e..e1a04dd 100644 --- a/p2p/client/fakeportallocator.h +++ b/p2p/client/fakeportallocator.h @@ -1,6 +1,29 @@ -// Copyright 2010 Google Inc. All Rights Reserved, -// -// Author: Justin Uberti (juberti@google.com) +/* + * libjingle + * Copyright 2010, Google Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ #ifndef TALK_P2P_CLIENT_FAKEPORTALLOCATOR_H_ #define TALK_P2P_CLIENT_FAKEPORTALLOCATOR_H_ @@ -39,10 +62,18 @@ class FakePortAllocatorSession : public PortAllocatorSession { virtual void StartGettingPorts() { if (!port_) { - port_.reset(cricket::UDPPort::Create(worker_thread_, factory_, - &network_, network_.ip(), 0, 0, - username(), - password())); + port_.reset(cricket::UDPPort::Create(worker_thread_, + factory_, + &network_, +#ifdef USE_WEBRTC_DEV_BRANCH + network_.GetBestIP(), +#else // USE_WEBRTC_DEV_BRANCH + network_.ip(), +#endif // USE_WEBRTC_DEV_BRANCH + 0, + 0, + username(), + password())); AddPort(port_.get()); } ++port_config_count_; diff --git a/p2p/client/portallocator_unittest.cc b/p2p/client/portallocator_unittest.cc index 57cfbe3..e793064 100644 --- a/p2p/client/portallocator_unittest.cc +++ b/p2p/client/portallocator_unittest.cc @@ -53,6 +53,7 @@ using rtc::SocketAddress; using rtc::Thread; static const SocketAddress kClientAddr("11.11.11.11", 0); +static const SocketAddress kPrivateAddr("192.168.1.11", 0); static const SocketAddress kClientIPv6Addr( "2401:fa00:4:1000:be30:5bff:fee5:c3", 0); static const SocketAddress kClientAddr2("22.22.22.22", 0); @@ -132,9 +133,32 @@ class PortAllocatorTest : public testing::Test, public sigslot::has_slots<> { bool SetPortRange(int min_port, int max_port) { return allocator_->SetPortRange(min_port, max_port); } - rtc::NATServer* CreateNatServer(const SocketAddress& addr, - rtc::NATType type) { - return new rtc::NATServer(type, vss_.get(), addr, vss_.get(), addr); + void ResetWithNatServer(const rtc::SocketAddress& stun_server) { + nat_server_.reset(new rtc::NATServer( + rtc::NAT_OPEN_CONE, vss_.get(), kNatAddr, vss_.get(), kNatAddr)); + + ServerAddresses stun_servers; + stun_servers.insert(stun_server); + allocator_.reset(new cricket::BasicPortAllocator( + &network_manager_, &nat_socket_factory_, stun_servers)); + allocator().set_step_delay(cricket::kMinimumStepDelay); + } + + void AddTurnServers(const rtc::SocketAddress& udp_turn, + const rtc::SocketAddress& tcp_turn) { + cricket::RelayServerConfig relay_server(cricket::RELAY_TURN); + cricket::RelayCredentials credentials(kTurnUsername, kTurnPassword); + relay_server.credentials = credentials; + + if (!udp_turn.IsNil()) { + relay_server.ports.push_back(cricket::ProtocolAddress( + kTurnUdpIntAddr, cricket::PROTO_UDP, false)); + } + if (!tcp_turn.IsNil()) { + relay_server.ports.push_back(cricket::ProtocolAddress( + kTurnTcpIntAddr, cricket::PROTO_TCP, false)); + } + allocator_->AddRelay(relay_server); } bool CreateSession(int component) { @@ -253,6 +277,7 @@ class PortAllocatorTest : public testing::Test, public sigslot::has_slots<> { rtc::scoped_ptr<rtc::VirtualSocketServer> vss_; rtc::scoped_ptr<rtc::FirewallSocketServer> fss_; rtc::SocketServerScope ss_scope_; + rtc::scoped_ptr<rtc::NATServer> nat_server_; rtc::NATSocketFactory nat_factory_; rtc::BasicPacketSocketFactory nat_socket_factory_; cricket::TestStunServer stun_server_; @@ -538,7 +563,7 @@ TEST_F(PortAllocatorTest, TestCandidatePriorityOfMultipleInterfaces) { // Test to verify ICE restart process. TEST_F(PortAllocatorTest, TestGetAllPortsRestarts) { AddInterface(kClientAddr); - EXPECT_TRUE(CreateSession(1)); + EXPECT_TRUE(CreateSession(cricket::ICE_CANDIDATE_COMPONENT_RTP)); session_->StartGettingPorts(); EXPECT_EQ_WAIT(7U, candidates_.size(), kDefaultAllocationTimeout); EXPECT_EQ(4U, ports_.size()); @@ -546,6 +571,73 @@ TEST_F(PortAllocatorTest, TestGetAllPortsRestarts) { // TODO - Extend this to verify ICE restart. } +// Test ICE candidate filter mechanism with options Relay/Host/Reflexive. +TEST_F(PortAllocatorTest, TestCandidateFilterWithRelayOnly) { + AddInterface(kClientAddr); + allocator().set_candidate_filter(cricket::CF_RELAY); + EXPECT_TRUE(CreateSession(cricket::ICE_CANDIDATE_COMPONENT_RTP)); + session_->StartGettingPorts(); + EXPECT_TRUE_WAIT(candidate_allocation_done_, kDefaultAllocationTimeout); + // Using GTURN, we will have 4 candidates. + EXPECT_EQ(4U, candidates_.size()); + EXPECT_EQ(1U, ports_.size()); // Only Relay port will be in ready state. + for (size_t i = 0; i < candidates_.size(); ++i) { + EXPECT_EQ(std::string(cricket::RELAY_PORT_TYPE), candidates_[i].type()); + } +} + +TEST_F(PortAllocatorTest, TestCandidateFilterWithHostOnly) { + AddInterface(kClientAddr); + allocator().set_flags(cricket::PORTALLOCATOR_ENABLE_SHARED_UFRAG | + cricket::PORTALLOCATOR_ENABLE_SHARED_SOCKET); + allocator().set_candidate_filter(cricket::CF_HOST); + EXPECT_TRUE(CreateSession(cricket::ICE_CANDIDATE_COMPONENT_RTP)); + session_->StartGettingPorts(); + EXPECT_TRUE_WAIT(candidate_allocation_done_, kDefaultAllocationTimeout); + EXPECT_EQ(2U, candidates_.size()); // Host UDP/TCP candidates only. + EXPECT_EQ(2U, ports_.size()); // UDP/TCP ports only. + for (size_t i = 0; i < candidates_.size(); ++i) { + EXPECT_EQ(std::string(cricket::LOCAL_PORT_TYPE), candidates_[i].type()); + } +} + +// Host is behind the NAT. +TEST_F(PortAllocatorTest, TestCandidateFilterWithReflexiveOnly) { + AddInterface(kPrivateAddr); + ResetWithNatServer(kStunAddr); + + allocator().set_flags(cricket::PORTALLOCATOR_ENABLE_SHARED_UFRAG | + cricket::PORTALLOCATOR_ENABLE_SHARED_SOCKET); + allocator().set_candidate_filter(cricket::CF_REFLEXIVE); + EXPECT_TRUE(CreateSession(cricket::ICE_CANDIDATE_COMPONENT_RTP)); + session_->StartGettingPorts(); + EXPECT_TRUE_WAIT(candidate_allocation_done_, kDefaultAllocationTimeout); + // Host is behind NAT, no private address will be exposed. Hence only UDP + // port with STUN candidate will be sent outside. + EXPECT_EQ(1U, candidates_.size()); // Only STUN candidate. + EXPECT_EQ(1U, ports_.size()); // Only UDP port will be in ready state. + for (size_t i = 0; i < candidates_.size(); ++i) { + EXPECT_EQ(std::string(cricket::STUN_PORT_TYPE), candidates_[i].type()); + } +} + +// Host is not behind the NAT. +TEST_F(PortAllocatorTest, TestCandidateFilterWithReflexiveOnlyAndNoNAT) { + AddInterface(kClientAddr); + allocator().set_flags(cricket::PORTALLOCATOR_ENABLE_SHARED_UFRAG | + cricket::PORTALLOCATOR_ENABLE_SHARED_SOCKET); + allocator().set_candidate_filter(cricket::CF_REFLEXIVE); + EXPECT_TRUE(CreateSession(cricket::ICE_CANDIDATE_COMPONENT_RTP)); + session_->StartGettingPorts(); + EXPECT_TRUE_WAIT(candidate_allocation_done_, kDefaultAllocationTimeout); + // Host has a public address, both UDP and TCP candidates will be exposed. + EXPECT_EQ(2U, candidates_.size()); // Local UDP + TCP candidate. + EXPECT_EQ(2U, ports_.size()); // UDP and TCP ports will be in ready state. + for (size_t i = 0; i < candidates_.size(); ++i) { + EXPECT_EQ(std::string(cricket::LOCAL_PORT_TYPE), candidates_[i].type()); + } +} + TEST_F(PortAllocatorTest, TestBasicMuxFeatures) { AddInterface(kClientAddr); allocator().set_flags(cricket::PORTALLOCATOR_ENABLE_BUNDLE); @@ -698,13 +790,8 @@ TEST_F(PortAllocatorTest, TestSharedSocketWithoutNat) { // local candidates as client behind a nat. TEST_F(PortAllocatorTest, TestSharedSocketWithNat) { AddInterface(kClientAddr); - rtc::scoped_ptr<rtc::NATServer> nat_server( - CreateNatServer(kNatAddr, rtc::NAT_OPEN_CONE)); - ServerAddresses stun_servers; - stun_servers.insert(kStunAddr); - allocator_.reset(new cricket::BasicPortAllocator( - &network_manager_, &nat_socket_factory_, stun_servers)); - allocator_->set_step_delay(cricket::kMinimumStepDelay); + ResetWithNatServer(kStunAddr); + allocator_->set_flags(allocator().flags() | cricket::PORTALLOCATOR_ENABLE_SHARED_UFRAG | cricket::PORTALLOCATOR_ENABLE_SHARED_SOCKET); @@ -726,14 +813,8 @@ TEST_F(PortAllocatorTest, TestSharedSocketWithoutNatUsingTurn) { turn_server_.AddInternalSocket(kTurnTcpIntAddr, cricket::PROTO_TCP); AddInterface(kClientAddr); allocator_.reset(new cricket::BasicPortAllocator(&network_manager_)); - cricket::RelayServerConfig relay_server(cricket::RELAY_TURN); - cricket::RelayCredentials credentials(kTurnUsername, kTurnPassword); - relay_server.credentials = credentials; - relay_server.ports.push_back(cricket::ProtocolAddress( - kTurnUdpIntAddr, cricket::PROTO_UDP, false)); - relay_server.ports.push_back(cricket::ProtocolAddress( - kTurnTcpIntAddr, cricket::PROTO_TCP, false)); - allocator_->AddRelay(relay_server); + + AddTurnServers(kTurnUdpIntAddr, kTurnTcpIntAddr); allocator_->set_step_delay(cricket::kMinimumStepDelay); allocator_->set_flags(allocator().flags() | @@ -790,20 +871,10 @@ TEST_F(PortAllocatorTest, TestSharedSocketWithServerAddressResolve) { // stun and turn candidates. TEST_F(PortAllocatorTest, TestSharedSocketWithNatUsingTurn) { AddInterface(kClientAddr); - rtc::scoped_ptr<rtc::NATServer> nat_server( - CreateNatServer(kNatAddr, rtc::NAT_OPEN_CONE)); - ServerAddresses stun_servers; - stun_servers.insert(kStunAddr); - allocator_.reset(new cricket::BasicPortAllocator( - &network_manager_, &nat_socket_factory_, stun_servers)); - cricket::RelayServerConfig relay_server(cricket::RELAY_TURN); - cricket::RelayCredentials credentials(kTurnUsername, kTurnPassword); - relay_server.credentials = credentials; - relay_server.ports.push_back(cricket::ProtocolAddress( - kTurnUdpIntAddr, cricket::PROTO_UDP, false)); - allocator_->AddRelay(relay_server); + ResetWithNatServer(kStunAddr); + + AddTurnServers(kTurnUdpIntAddr, rtc::SocketAddress()); - allocator_->set_step_delay(cricket::kMinimumStepDelay); allocator_->set_flags(allocator().flags() | cricket::PORTALLOCATOR_ENABLE_SHARED_UFRAG | cricket::PORTALLOCATOR_ENABLE_SHARED_SOCKET | @@ -829,6 +900,45 @@ TEST_F(PortAllocatorTest, TestSharedSocketWithNatUsingTurn) { EXPECT_EQ(1U, ports_[1]->Candidates().size()); } +// Test that when PORTALLOCATOR_ENABLE_SHARED_SOCKET is enabled and the TURN +// server is also used as the STUN server, we should get 'local', 'stun', and +// 'relay' candidates. +TEST_F(PortAllocatorTest, TestSharedSocketWithNatUsingTurnAsStun) { + AddInterface(kClientAddr); + ResetWithNatServer(kTurnUdpIntAddr); + AddTurnServers(kTurnUdpIntAddr, rtc::SocketAddress()); + + // Must set the step delay to 0 to make sure the relay allocation phase is + // started before the STUN candidates are obtained, so that the STUN binding + // response is processed when both StunPort and TurnPort exist to reproduce + // webrtc issue 3537. + allocator_->set_step_delay(0); + allocator_->set_flags(allocator().flags() | + cricket::PORTALLOCATOR_ENABLE_SHARED_UFRAG | + cricket::PORTALLOCATOR_ENABLE_SHARED_SOCKET | + cricket::PORTALLOCATOR_DISABLE_TCP); + + EXPECT_TRUE(CreateSession(cricket::ICE_CANDIDATE_COMPONENT_RTP)); + session_->StartGettingPorts(); + + ASSERT_EQ_WAIT(3U, candidates_.size(), kDefaultAllocationTimeout); + EXPECT_PRED5(CheckCandidate, candidates_[0], + cricket::ICE_CANDIDATE_COMPONENT_RTP, "local", "udp", kClientAddr); + EXPECT_PRED5(CheckCandidate, candidates_[1], + cricket::ICE_CANDIDATE_COMPONENT_RTP, "stun", "udp", + rtc::SocketAddress(kNatAddr.ipaddr(), 0)); + EXPECT_PRED5(CheckCandidate, candidates_[2], + cricket::ICE_CANDIDATE_COMPONENT_RTP, "relay", "udp", + rtc::SocketAddress(kTurnUdpExtAddr.ipaddr(), 0)); + EXPECT_EQ(candidates_[2].related_address(), candidates_[1].address()); + + EXPECT_TRUE_WAIT(candidate_allocation_done_, kDefaultAllocationTimeout); + EXPECT_EQ(3U, candidates_.size()); + // Local port will be created first and then TURN port. + EXPECT_EQ(2U, ports_[0]->Candidates().size()); + EXPECT_EQ(1U, ports_[1]->Candidates().size()); +} + // This test verifies when PORTALLOCATOR_ENABLE_SHARED_SOCKET flag is enabled // and fail to generate STUN candidate, local UDP candidate is generated // properly. diff --git a/p2p/client/sessionmanagertask.h b/p2p/client/sessionmanagertask.h index d7d9733..e16d9d6 100644 --- a/p2p/client/sessionmanagertask.h +++ b/p2p/client/sessionmanagertask.h @@ -25,8 +25,8 @@ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef _SESSIONMANAGERTASK_H_ -#define _SESSIONMANAGERTASK_H_ +#ifndef TALK_P2P_CLIENT_SESSIONMANAGERTASK_H_ +#define TALK_P2P_CLIENT_SESSIONMANAGERTASK_H_ #include "talk/p2p/base/sessionmanager.h" #include "talk/p2p/client/sessionsendtask.h" @@ -90,4 +90,4 @@ class SessionManagerTask : public buzz::XmppTask { } // namespace cricket -#endif // _SESSIONMANAGERTASK_H_ +#endif // TALK_P2P_CLIENT_SESSIONMANAGERTASK_H_ |