diff --git a/webrtc/p2p/base/candidate.h b/webrtc/p2p/base/candidate.h index 5073aeb322..723dbc9f47 100644 --- a/webrtc/p2p/base/candidate.h +++ b/webrtc/p2p/base/candidate.h @@ -161,7 +161,6 @@ class Candidate { const std::string& foundation() const { return foundation_; } - void set_foundation(const std::string& foundation) { foundation_ = foundation; } @@ -184,6 +183,10 @@ class Candidate { transport_name_ = transport_name; } + // The URL of the ICE server which this candidate is gathered from. + const std::string& url() const { return url_; } + void set_url(const std::string& url) { url_ = url; } + // Determines whether this candidate is equivalent to the given one. bool IsEquivalent(const Candidate& c) const { // We ignore the network name, since that is just debug information, and @@ -284,6 +287,7 @@ class Candidate { std::string transport_name_; uint16_t network_id_; uint16_t network_cost_; + std::string url_; }; // Used during parsing and writing to map component to channel name diff --git a/webrtc/p2p/base/port.cc b/webrtc/p2p/base/port.cc index 385022c11a..9c4c362257 100644 --- a/webrtc/p2p/base/port.cc +++ b/webrtc/p2p/base/port.cc @@ -252,6 +252,7 @@ void Port::AddAddress(const rtc::SocketAddress& address, const std::string& type, uint32_t type_preference, uint32_t relay_preference, + const std::string& url, bool final) { if (protocol == TCP_PROTOCOL_NAME && type == LOCAL_PORT_TYPE) { RTC_DCHECK(!tcptype.empty()); @@ -268,6 +269,7 @@ void Port::AddAddress(const rtc::SocketAddress& address, c.set_network_name(network_->name()); c.set_network_type(network_->type()); c.set_related_address(related_address); + c.set_url(url); candidates_.push_back(c); SignalCandidateReady(this, c); diff --git a/webrtc/p2p/base/port.h b/webrtc/p2p/base/port.h index 6cfbbd84c5..ba30c480f9 100644 --- a/webrtc/p2p/base/port.h +++ b/webrtc/p2p/base/port.h @@ -332,6 +332,7 @@ class Port : public PortInterface, public rtc::MessageHandler, const std::string& type, uint32_t type_preference, uint32_t relay_preference, + const std::string& url, bool final); // Adds the given connection to the map keyed by the remote candidate address. diff --git a/webrtc/p2p/base/port_unittest.cc b/webrtc/p2p/base/port_unittest.cc index 38012a683a..9714280b93 100644 --- a/webrtc/p2p/base/port_unittest.cc +++ b/webrtc/p2p/base/port_unittest.cc @@ -146,7 +146,7 @@ class TestPort : public Port { virtual void PrepareAddress() { rtc::SocketAddress addr(ip(), min_port()); AddAddress(addr, addr, rtc::SocketAddress(), "udp", "", "", Type(), - ICE_TYPE_PREFERENCE_HOST, 0, true); + ICE_TYPE_PREFERENCE_HOST, 0, "", true); } virtual bool SupportsProtocol(const std::string& protocol) const { @@ -158,7 +158,7 @@ class TestPort : public Port { // Exposed for testing candidate building. void AddCandidateAddress(const rtc::SocketAddress& addr) { AddAddress(addr, addr, rtc::SocketAddress(), "udp", "", "", Type(), - type_preference_, 0, false); + type_preference_, 0, "", false); } void AddCandidateAddress(const rtc::SocketAddress& addr, const rtc::SocketAddress& base_address, @@ -166,7 +166,7 @@ class TestPort : public Port { int type_preference, bool final) { AddAddress(addr, base_address, rtc::SocketAddress(), "udp", "", "", type, - type_preference, 0, final); + type_preference, 0, "", final); } virtual Connection* CreateConnection(const Candidate& remote_candidate, diff --git a/webrtc/p2p/base/relayport.cc b/webrtc/p2p/base/relayport.cc index 8f7036cc5f..2ab71dc3e4 100644 --- a/webrtc/p2p/base/relayport.cc +++ b/webrtc/p2p/base/relayport.cc @@ -245,7 +245,7 @@ void RelayPort::SetReady() { // address. AddAddress(iter->address, iter->address, rtc::SocketAddress(), proto_name, proto_name, "", RELAY_PORT_TYPE, ICE_TYPE_PREFERENCE_RELAY_UDP, - 0, false); + 0, "", false); } ready_ = true; SignalPortComplete(this); diff --git a/webrtc/p2p/base/stunport.cc b/webrtc/p2p/base/stunport.cc index be844d54dc..43e8d9fb5c 100644 --- a/webrtc/p2p/base/stunport.cc +++ b/webrtc/p2p/base/stunport.cc @@ -315,7 +315,7 @@ void UDPPort::OnLocalAddressReady(rtc::AsyncPacketSocket* socket, MaybeSetDefaultLocalAddress(&addr); AddAddress(addr, addr, rtc::SocketAddress(), UDP_PROTOCOL_NAME, "", "", - LOCAL_PORT_TYPE, ICE_TYPE_PREFERENCE_HOST, 0, false); + LOCAL_PORT_TYPE, ICE_TYPE_PREFERENCE_HOST, 0, "", false); MaybePrepareStunCandidate(); } @@ -453,9 +453,12 @@ void UDPPort::OnStunBindingRequestSucceeded( related_address.family()); } + std::ostringstream url; + url << "stun:" << stun_server_addr.ipaddr().ToString() << ":" + << stun_server_addr.port(); AddAddress(stun_reflected_addr, socket_->GetLocalAddress(), related_address, UDP_PROTOCOL_NAME, "", "", STUN_PORT_TYPE, - ICE_TYPE_PREFERENCE_SRFLX, 0, false); + ICE_TYPE_PREFERENCE_SRFLX, 0, url.str(), false); } MaybeSetPortCompleteOrError(); } diff --git a/webrtc/p2p/base/stunport_unittest.cc b/webrtc/p2p/base/stunport_unittest.cc index aa708c1ba1..f8903d3a2f 100644 --- a/webrtc/p2p/base/stunport_unittest.cc +++ b/webrtc/p2p/base/stunport_unittest.cc @@ -201,6 +201,8 @@ TEST_F(StunPortTest, TestPrepareAddress) { EXPECT_TRUE_SIMULATED_WAIT(done(), kTimeoutMs, fake_clock); ASSERT_EQ(1U, port()->Candidates().size()); EXPECT_TRUE(kLocalAddr.EqualIPs(port()->Candidates()[0].address())); + std::string expected_server_url = "stun:127.0.0.1:5000"; + EXPECT_EQ(port()->Candidates()[0].url(), expected_server_url); // TODO: Add IPv6 tests here, once either physicalsocketserver supports // IPv6, or this test is changed to use VirtualSocketServer. diff --git a/webrtc/p2p/base/tcpport.cc b/webrtc/p2p/base/tcpport.cc index 11997871f0..209f569f5c 100644 --- a/webrtc/p2p/base/tcpport.cc +++ b/webrtc/p2p/base/tcpport.cc @@ -178,7 +178,7 @@ void TCPPort::PrepareAddress() { AddAddress(socket_->GetLocalAddress(), socket_->GetLocalAddress(), rtc::SocketAddress(), TCP_PROTOCOL_NAME, "", TCPTYPE_PASSIVE_STR, LOCAL_PORT_TYPE, - ICE_TYPE_PREFERENCE_HOST_TCP, 0, true); + ICE_TYPE_PREFERENCE_HOST_TCP, 0, "", true); } else { LOG_J(LS_INFO, this) << "Not listening due to firewall restrictions."; // Note: We still add the address, since otherwise the remote side won't @@ -188,7 +188,7 @@ void TCPPort::PrepareAddress() { AddAddress(rtc::SocketAddress(ip(), DISCARD_PORT), rtc::SocketAddress(ip(), 0), rtc::SocketAddress(), TCP_PROTOCOL_NAME, "", TCPTYPE_ACTIVE_STR, LOCAL_PORT_TYPE, - ICE_TYPE_PREFERENCE_HOST_TCP, 0, true); + ICE_TYPE_PREFERENCE_HOST_TCP, 0, "", true); } } @@ -300,7 +300,7 @@ void TCPPort::OnAddressReady(rtc::AsyncPacketSocket* socket, const rtc::SocketAddress& address) { AddAddress(address, address, rtc::SocketAddress(), TCP_PROTOCOL_NAME, "", TCPTYPE_PASSIVE_STR, LOCAL_PORT_TYPE, ICE_TYPE_PREFERENCE_HOST_TCP, - 0, true); + 0, "", true); } TCPConnection::TCPConnection(TCPPort* port, diff --git a/webrtc/p2p/base/turnport.cc b/webrtc/p2p/base/turnport.cc index 7e0e64d6ed..789842dfb5 100644 --- a/webrtc/p2p/base/turnport.cc +++ b/webrtc/p2p/base/turnport.cc @@ -745,7 +745,7 @@ void TurnPort::OnAllocateSuccess(const rtc::SocketAddress& address, ProtoToString(server_address_.proto), // The first hop protocol. "", // TCP canddiate type, empty for turn candidates. RELAY_PORT_TYPE, GetRelayPreference(server_address_.proto), - server_priority_, true); + server_priority_, ReconstructedServerUrl(), true); } void TurnPort::OnAllocateError() { @@ -1073,6 +1073,34 @@ bool TurnPort::SetEntryChannelId(const rtc::SocketAddress& address, return true; } +std::string TurnPort::ReconstructedServerUrl() { + // draft-petithuguenin-behave-turn-uris-01 + // turnURI = scheme ":" turn-host [ ":" turn-port ] + // [ "?transport=" transport ] + // scheme = "turn" / "turns" + // transport = "udp" / "tcp" / transport-ext + // transport-ext = 1*unreserved + // turn-host = IP-literal / IPv4address / reg-name + // turn-port = *DIGIT + std::string scheme = "turn"; + std::string transport = "tcp"; + switch (server_address_.proto) { + case PROTO_SSLTCP: + case PROTO_TLS: + scheme = "turns"; + break; + case PROTO_UDP: + transport = "udp"; + break; + case PROTO_TCP: + break; + } + std::ostringstream url; + url << scheme << ":" << server_address_.address.ipaddr().ToString() << ":" + << server_address_.address.port() << "?transport=" << transport; + return url.str(); +} + TurnAllocateRequest::TurnAllocateRequest(TurnPort* port) : StunRequest(new TurnMessage()), port_(port) { diff --git a/webrtc/p2p/base/turnport.h b/webrtc/p2p/base/turnport.h index b421453636..e5f384fa57 100644 --- a/webrtc/p2p/base/turnport.h +++ b/webrtc/p2p/base/turnport.h @@ -260,6 +260,9 @@ class TurnPort : public Port { // pruned (a.k.a. write-timed-out). Returns true if a connection is found. bool FailAndPruneConnection(const rtc::SocketAddress& address); + // Reconstruct the URL of the server which the candidate is gathered from. + std::string ReconstructedServerUrl(); + ProtocolAddress server_address_; TlsCertPolicy tls_cert_policy_ = TlsCertPolicy::TLS_CERT_POLICY_SECURE; RelayCredentials credentials_; diff --git a/webrtc/p2p/base/turnport_unittest.cc b/webrtc/p2p/base/turnport_unittest.cc index 69b25ea0d8..7223eabbee 100644 --- a/webrtc/p2p/base/turnport_unittest.cc +++ b/webrtc/p2p/base/turnport_unittest.cc @@ -647,6 +647,40 @@ TEST_F(TurnPortTest, TestTurnPortType) { EXPECT_EQ(cricket::RELAY_PORT_TYPE, turn_port_->Type()); } +// Tests that the URL of the servers can be correctly reconstructed when +// gathering the candidates. +TEST_F(TurnPortTest, TestReconstructedServerUrl) { + // Connect the TURN server using UDP. + CreateTurnPort(kTurnUsername, kTurnPassword, kTurnUdpProtoAddr); + turn_port_->PrepareAddress(); + EXPECT_TRUE_SIMULATED_WAIT(turn_ready_, kSimulatedRtt * 2, fake_clock_); + std::string expected_server_url = "turn:99.99.99.3:3478?transport=udp"; + EXPECT_EQ(turn_port_->Candidates()[0].url(), expected_server_url); + + // Connect the server with IPV6 using UDP. + turn_ready_ = false; + turn_server_.AddInternalSocket(kTurnUdpIPv6IntAddr, PROTO_UDP); + CreateTurnPort(kLocalIPv6Addr, kTurnUsername, kTurnPassword, + kTurnUdpIPv6ProtoAddr); + turn_port_->PrepareAddress(); + EXPECT_TRUE_SIMULATED_WAIT(turn_ready_, kSimulatedRtt * 2, fake_clock_); + ASSERT_EQ(1U, turn_port_->Candidates().size()); + expected_server_url = + "turn:2400:4030:1:2c00:be30:abcd:efab:cdef:3478?transport=udp"; + EXPECT_EQ(turn_port_->Candidates()[0].url(), expected_server_url); + + // Connection the server using TCP. + turn_ready_ = false; + turn_server_.AddInternalSocket(kTurnTcpIntAddr, PROTO_TCP); + CreateTurnPort(kTurnUsername, kTurnPassword, kTurnTcpProtoAddr); + turn_port_->PrepareAddress(); + EXPECT_TRUE_SIMULATED_WAIT(turn_ready_, kSimulatedRtt * 3, fake_clock_); + ASSERT_EQ(1U, turn_port_->Candidates().size()); + expected_server_url = "turn:99.99.99.4:3478?transport=tcp"; + EXPECT_EQ(turn_port_->Candidates()[0].url(), expected_server_url); + turn_ready_ = false; +} + // Do a normal TURN allocation. TEST_F(TurnPortTest, TestTurnAllocate) { CreateTurnPort(kTurnUsername, kTurnPassword, kTurnUdpProtoAddr);