Generate localhost candidate when no STUN/TURN and portallocator has the right flag spefied.

BUG=webrtc:4517
R=pthatcher@webrtc.org

Review URL: https://codereview.webrtc.org/1275703006 .

Cr-Commit-Position: refs/heads/master@{#9726}
This commit is contained in:
Guo-wei Shieh 2015-08-18 13:05:20 -07:00
parent bef77e234f
commit 0a2955f227
13 changed files with 129 additions and 48 deletions

View File

@ -223,6 +223,9 @@ class PeerConnectionInterface : public rtc::RefCountInterface {
// TODO(pthatcher): Rename this ice_servers, but update Chromium
// at the same time.
IceServers servers;
// A localhost candidate is signaled whenever a candidate with the any
// address is allocated.
bool enable_localhost_ice_candidate;
BundlePolicy bundle_policy;
RtcpMuxPolicy rtcp_mux_policy;
TcpCandidatePolicy tcp_candidate_policy;
@ -231,6 +234,7 @@ class PeerConnectionInterface : public rtc::RefCountInterface {
RTCConfiguration()
: type(kAll),
enable_localhost_ice_candidate(false),
bundle_policy(kBundlePolicyBalanced),
rtcp_mux_policy(kRtcpMuxPolicyNegotiate),
tcp_candidate_policy(kTcpCandidatePolicyEnabled),

View File

@ -678,6 +678,13 @@ bool WebRtcSession::Initialize(
}
port_allocator()->set_candidate_filter(
ConvertIceTransportTypeToCandidateFilter(rtc_configuration.type));
if (rtc_configuration.enable_localhost_ice_candidate) {
port_allocator()->set_flags(
port_allocator()->flags() |
cricket::PORTALLOCATOR_ENABLE_LOCALHOST_CANDIDATE);
}
return true;
}

View File

@ -498,4 +498,13 @@ int IPAddressPrecedence(const IPAddress& ip) {
return 0;
}
} // Namespace talk base
IPAddress GetLoopbackIP(int family) {
if (family == AF_INET) {
return rtc::IPAddress(INADDR_LOOPBACK);
}
if (family == AF_INET6) {
return rtc::IPAddress(in6addr_loopback);
}
return rtc::IPAddress();
}
} // Namespace rtc

View File

@ -179,6 +179,8 @@ int IPAddressPrecedence(const IPAddress& ip);
// Returns 'ip' truncated to be 'length' bits long.
IPAddress TruncateIP(const IPAddress& ip, int length);
IPAddress GetLoopbackIP(int family);
// Returns the number of contiguously set bits, counting from the MSB in network
// byte order, in this IPAddress. Bits after the first 0 encountered are not
// counted.

View File

@ -433,7 +433,7 @@ class PortTest : public testing::Test, public sigslot::has_slots<> {
PacketSocketFactory* socket_factory) {
UDPPort* port = UDPPort::Create(main_, socket_factory, &network_,
addr.ipaddr(), 0, 0, username_, password_,
std::string());
std::string(), false);
port->SetIceProtocolType(ice_protocol_);
return port;
}

View File

@ -38,6 +38,7 @@ enum {
PORTALLOCATOR_ENABLE_SHARED_SOCKET = 0x100,
PORTALLOCATOR_ENABLE_STUN_RETRANSMIT_ATTRIBUTE = 0x200,
PORTALLOCATOR_DISABLE_ADAPTER_ENUMERATION = 0x400,
PORTALLOCATOR_ENABLE_LOCALHOST_CANDIDATE = 0x800,
};
const uint32 kDefaultPortAllocatorFlags = 0;

View File

@ -15,6 +15,7 @@
#include "webrtc/p2p/base/stun.h"
#include "webrtc/base/common.h"
#include "webrtc/base/helpers.h"
#include "webrtc/base/ipaddress.h"
#include "webrtc/base/logging.h"
#include "webrtc/base/nethelpers.h"
@ -164,14 +165,16 @@ UDPPort::UDPPort(rtc::Thread* thread,
rtc::AsyncPacketSocket* socket,
const std::string& username,
const std::string& password,
const std::string& origin)
const std::string& origin,
bool emit_localhost_for_anyaddress)
: Port(thread, factory, network, socket->GetLocalAddress().ipaddr(),
username, password),
requests_(thread),
socket_(socket),
error_(0),
ready_(false),
stun_keepalive_delay_(KEEPALIVE_DELAY) {
stun_keepalive_delay_(KEEPALIVE_DELAY),
emit_localhost_for_anyaddress_(emit_localhost_for_anyaddress) {
requests_.set_origin(origin);
}
@ -183,14 +186,16 @@ UDPPort::UDPPort(rtc::Thread* thread,
uint16 max_port,
const std::string& username,
const std::string& password,
const std::string& origin)
const std::string& origin,
bool emit_localhost_for_anyaddress)
: Port(thread, LOCAL_PORT_TYPE, factory, network, ip, min_port, max_port,
username, password),
requests_(thread),
socket_(NULL),
error_(0),
ready_(false),
stun_keepalive_delay_(KEEPALIVE_DELAY) {
stun_keepalive_delay_(KEEPALIVE_DELAY),
emit_localhost_for_anyaddress_(emit_localhost_for_anyaddress) {
requests_.set_origin(origin);
}
@ -280,9 +285,17 @@ int UDPPort::GetError() {
void UDPPort::OnLocalAddressReady(rtc::AsyncPacketSocket* socket,
const rtc::SocketAddress& address) {
AddAddress(address, address, rtc::SocketAddress(),
UDP_PROTOCOL_NAME, "", LOCAL_PORT_TYPE,
ICE_TYPE_PREFERENCE_HOST, 0, false);
// When adapter enumeration is disabled and binding to the any address, the
// loopback address will be issued as a candidate instead if
// |emit_localhost_for_anyaddress| is true. This is to allow connectivity on
// demo pages without STUN/TURN to work.
rtc::SocketAddress addr = address;
if (addr.IsAnyIP() && emit_localhost_for_anyaddress_) {
addr.SetIP(rtc::GetLoopbackIP(addr.family()));
}
AddAddress(addr, addr, rtc::SocketAddress(), UDP_PROTOCOL_NAME, "",
LOCAL_PORT_TYPE, ICE_TYPE_PREFERENCE_HOST, 0, false);
MaybePrepareStunCandidate();
}

View File

@ -34,9 +34,11 @@ class UDPPort : public Port {
rtc::AsyncPacketSocket* socket,
const std::string& username,
const std::string& password,
const std::string& origin) {
const std::string& origin,
bool emit_localhost_for_anyaddress) {
UDPPort* port = new UDPPort(thread, factory, network, socket,
username, password, origin);
username, password, origin,
emit_localhost_for_anyaddress);
if (!port->Init()) {
delete port;
port = NULL;
@ -52,10 +54,12 @@ class UDPPort : public Port {
uint16 max_port,
const std::string& username,
const std::string& password,
const std::string& origin) {
const std::string& origin,
bool emit_localhost_for_anyaddress) {
UDPPort* port = new UDPPort(thread, factory, network,
ip, min_port, max_port,
username, password, origin);
username, password, origin,
emit_localhost_for_anyaddress);
if (!port->Init()) {
delete port;
port = NULL;
@ -110,7 +114,8 @@ class UDPPort : public Port {
uint16 max_port,
const std::string& username,
const std::string& password,
const std::string& origin);
const std::string& origin,
bool emit_localhost_for_anyaddress);
UDPPort(rtc::Thread* thread,
rtc::PacketSocketFactory* factory,
@ -118,7 +123,8 @@ class UDPPort : public Port {
rtc::AsyncPacketSocket* socket,
const std::string& username,
const std::string& password,
const std::string& origin);
const std::string& origin,
bool emit_localhost_for_anyaddress);
bool Init();
@ -202,6 +208,10 @@ class UDPPort : public Port {
bool ready_;
int stun_keepalive_delay_;
// This is true when no STUN or TURN is specified in AllocationSequence and
// PORTALLOCATOR_ENABLE_LOCALHOST_CANDIDATE is specified.
bool emit_localhost_for_anyaddress_;
friend class StunBindingRequest;
};
@ -245,7 +255,7 @@ class StunPort : public UDPPort {
const ServerAddresses& servers,
const std::string& origin)
: UDPPort(thread, factory, network, ip, min_port, max_port, username,
password, origin) {
password, origin, false) {
// UDPPort will set these to local udp, updating these to STUN.
set_type(STUN_PORT_TYPE);
set_server_addresses(servers);

View File

@ -82,7 +82,7 @@ class StunPortTest : public testing::Test,
rtc::Thread::Current(), &socket_factory_,
&network_, socket_.get(),
rtc::CreateRandomString(16), rtc::CreateRandomString(22),
std::string()));
std::string(), false));
ASSERT_TRUE(stun_port_ != NULL);
ServerAddresses stun_servers;
stun_servers.insert(server_addr);

View File

@ -272,7 +272,7 @@ class TurnPortTest : public testing::Test,
udp_port_.reset(UDPPort::Create(main_, &socket_factory_, &network_,
kLocalAddr2.ipaddr(), 0, 0,
kIceUfrag2, kIcePwd2,
std::string()));
std::string(), false));
// Set protocol type to RFC5245, as turn port is also in same mode.
// UDP port will be controlled.
udp_port_->SetIceProtocolType(cricket::ICEPROTO_RFC5245);

View File

@ -555,6 +555,13 @@ bool BasicPortAllocatorSession::CheckCandidateFilter(const Candidate& c) {
return true;
}
// If it's loopback address, we should allow it as it's for demo page
// connectivity when no TURN/STUN specified.
if (c.address().IsLoopbackIP()) {
ASSERT((flags() & PORTALLOCATOR_ENABLE_LOCALHOST_CANDIDATE) != 0);
return true;
}
// This is just to prevent the case when binding to any address (all 0s), if
// somehow the host candidate address is not all 0s. Either because local
// installed proxy changes the address or a packet has been sent for any
@ -825,20 +832,19 @@ void AllocationSequence::CreateUDPPorts() {
// TODO(mallinath) - Remove UDPPort creating socket after shared socket
// is enabled completely.
UDPPort* port = NULL;
bool emit_localhost_for_anyaddress =
IsFlagSet(PORTALLOCATOR_ENABLE_LOCALHOST_CANDIDATE);
if (IsFlagSet(PORTALLOCATOR_ENABLE_SHARED_SOCKET) && udp_socket_) {
port = UDPPort::Create(session_->network_thread(),
session_->socket_factory(), network_,
udp_socket_.get(),
session_->username(), session_->password(),
session_->allocator()->origin());
port = UDPPort::Create(
session_->network_thread(), session_->socket_factory(), network_,
udp_socket_.get(), session_->username(), session_->password(),
session_->allocator()->origin(), emit_localhost_for_anyaddress);
} else {
port = UDPPort::Create(session_->network_thread(),
session_->socket_factory(),
network_, ip_,
session_->allocator()->min_port(),
session_->allocator()->max_port(),
session_->username(), session_->password(),
session_->allocator()->origin());
port = UDPPort::Create(
session_->network_thread(), session_->socket_factory(), network_, ip_,
session_->allocator()->min_port(), session_->allocator()->max_port(),
session_->username(), session_->password(),
session_->allocator()->origin(), emit_localhost_for_anyaddress);
}
if (port) {

View File

@ -53,7 +53,8 @@ class FakePortAllocatorSession : public PortAllocatorSession {
0,
username(),
password(),
std::string()));
std::string(),
false));
AddPort(port_.get());
}
++port_config_count_;

View File

@ -243,11 +243,15 @@ class PortAllocatorTest : public testing::Test, public sigslot::has_slots<> {
// it should be ignore.
void CheckDisableAdapterEnumeration(
uint32 total_ports,
const rtc::IPAddress& host_candidate_addr,
const rtc::IPAddress& stun_candidate_addr,
const rtc::IPAddress& relay_candidate_udp_transport_addr,
const rtc::IPAddress& relay_candidate_tcp_transport_addr) {
EXPECT_TRUE(CreateSession(cricket::ICE_CANDIDATE_COMPONENT_RTP));
session_->set_flags(cricket::PORTALLOCATOR_DISABLE_ADAPTER_ENUMERATION |
if (!session_) {
EXPECT_TRUE(CreateSession(cricket::ICE_CANDIDATE_COMPONENT_RTP));
}
session_->set_flags(session_->flags() |
cricket::PORTALLOCATOR_DISABLE_ADAPTER_ENUMERATION |
cricket::PORTALLOCATOR_ENABLE_SHARED_UFRAG |
cricket::PORTALLOCATOR_ENABLE_SHARED_SOCKET);
allocator().set_allow_tcp_listen(false);
@ -255,28 +259,36 @@ class PortAllocatorTest : public testing::Test, public sigslot::has_slots<> {
EXPECT_TRUE_WAIT(candidate_allocation_done_, kDefaultAllocationTimeout);
uint32 total_candidates = 0;
if (!stun_candidate_addr.IsNil()) {
if (!host_candidate_addr.IsNil()) {
EXPECT_PRED5(CheckCandidate, candidates_[total_candidates],
cricket::ICE_CANDIDATE_COMPONENT_RTP, "local", "udp",
rtc::SocketAddress(host_candidate_addr, 0));
++total_candidates;
EXPECT_PRED5(CheckCandidate, candidates_[0],
}
if (!stun_candidate_addr.IsNil()) {
EXPECT_PRED5(CheckCandidate, candidates_[total_candidates],
cricket::ICE_CANDIDATE_COMPONENT_RTP, "stun", "udp",
rtc::SocketAddress(stun_candidate_addr, 0));
EXPECT_EQ(
rtc::EmptySocketAddressWithFamily(candidates_[0].address().family()),
candidates_[0].related_address());
EXPECT_EQ(rtc::EmptySocketAddressWithFamily(
candidates_[total_candidates].address().family()),
candidates_[total_candidates].related_address());
++total_candidates;
}
if (!relay_candidate_udp_transport_addr.IsNil()) {
++total_candidates;
EXPECT_PRED5(CheckCandidate, candidates_[1],
EXPECT_PRED5(CheckCandidate, candidates_[total_candidates],
cricket::ICE_CANDIDATE_COMPONENT_RTP, "relay", "udp",
rtc::SocketAddress(relay_candidate_udp_transport_addr, 0));
EXPECT_EQ(stun_candidate_addr, candidates_[1].related_address().ipaddr());
EXPECT_EQ(stun_candidate_addr,
candidates_[total_candidates].related_address().ipaddr());
++total_candidates;
}
if (!relay_candidate_tcp_transport_addr.IsNil()) {
++total_candidates;
EXPECT_PRED5(CheckCandidate, candidates_[2],
EXPECT_PRED5(CheckCandidate, candidates_[total_candidates],
cricket::ICE_CANDIDATE_COMPONENT_RTP, "relay", "udp",
rtc::SocketAddress(relay_candidate_tcp_transport_addr, 0));
EXPECT_EQ(stun_candidate_addr, candidates_[2].related_address().ipaddr());
EXPECT_EQ(stun_candidate_addr,
candidates_[total_candidates].related_address().ipaddr());
++total_candidates;
}
EXPECT_EQ(total_candidates, candidates_.size());
@ -509,7 +521,7 @@ TEST_F(PortAllocatorTest, TestDisableAdapterEnumerationBehindNat) {
AddTurnServers(kTurnUdpIntAddr, rtc::SocketAddress());
// Expect to see 3 ports: STUN, TURN/UDP and TCP ports, and both STUN and
// TURN/UDP candidates.
CheckDisableAdapterEnumeration(3U, kNatUdpAddr.ipaddr(),
CheckDisableAdapterEnumeration(3U, rtc::IPAddress(), kNatUdpAddr.ipaddr(),
kTurnUdpExtAddr.ipaddr(), rtc::IPAddress());
}
@ -523,7 +535,7 @@ TEST_F(PortAllocatorTest,
AddTurnServers(kTurnUdpIntAddr, rtc::SocketAddress());
// Expect to see 3 ports: STUN, TURN/UDP and TCP ports, and both STUN and
// TURN/UDP candidates.
CheckDisableAdapterEnumeration(3U, kNatUdpAddr.ipaddr(),
CheckDisableAdapterEnumeration(3U, rtc::IPAddress(), kNatUdpAddr.ipaddr(),
kTurnUdpExtAddr.ipaddr(), rtc::IPAddress());
}
@ -537,7 +549,7 @@ TEST_F(PortAllocatorTest, TestDisableAdapterEnumerationBehindNatWithTcp) {
AddTurnServers(kTurnUdpIntAddr, kTurnTcpIntAddr);
// Expect to see 4 ports - STUN, TURN/UDP, TURN/TCP and TCP port. STUN,
// TURN/UDP, and TURN/TCP candidates.
CheckDisableAdapterEnumeration(4U, kNatUdpAddr.ipaddr(),
CheckDisableAdapterEnumeration(4U, rtc::IPAddress(), kNatUdpAddr.ipaddr(),
kTurnUdpExtAddr.ipaddr(),
kTurnUdpExtAddr.ipaddr());
}
@ -552,7 +564,7 @@ TEST_F(PortAllocatorTest, TestDisableAdapterEnumerationWithoutNat) {
// Expect to see 3 ports: STUN, TURN/UDP and TCP ports, but only both STUN and
// TURN candidates. The STUN candidate should have kClientAddr as srflx
// address, and TURN candidate with kClientAddr as the related address.
CheckDisableAdapterEnumeration(3U, kClientAddr.ipaddr(),
CheckDisableAdapterEnumeration(3U, rtc::IPAddress(), kClientAddr.ipaddr(),
kTurnUdpExtAddr.ipaddr(), rtc::IPAddress());
}
@ -563,6 +575,22 @@ TEST_F(PortAllocatorTest, TestDisableAdapterEnumerationWithoutNatOrServers) {
ResetWithNoServersOrNat();
// Expect to see 2 ports: STUN and TCP ports, but no candidate.
CheckDisableAdapterEnumeration(2U, rtc::IPAddress(), rtc::IPAddress(),
rtc::IPAddress(), rtc::IPAddress());
}
// Test that when adapter enumeration is disabled, with
// PORTALLOCATOR_ENABLE_LOCALHOST_CANDIDATE specified, for endpoints not behind
// a NAT, there are a localhost candidate in addition to a STUN candidate.
TEST_F(PortAllocatorTest,
TestDisableAdapterEnumerationWithoutNatLocalhostCandidateRequested) {
AddInterfaceAsDefaultRoute(kClientAddr);
ResetWithStunServerNoNat(kStunAddr);
EXPECT_TRUE(CreateSession(cricket::ICE_CANDIDATE_COMPONENT_RTP));
session_->set_flags(cricket::PORTALLOCATOR_ENABLE_LOCALHOST_CANDIDATE);
// Expect to see 2 ports: STUN and TCP ports, localhost candidate and STUN
// candidate.
CheckDisableAdapterEnumeration(2U, rtc::GetLoopbackIP(AF_INET),
kClientAddr.ipaddr(), rtc::IPAddress(),
rtc::IPAddress());
}