Replace a broken assumption in candidate gathering for mDNS candidates.

The gathering of host candidates with mDNS names is asynchronous and its
completion can happen after a srflx candidate is gathered by the same
underlying socket. We have a broken check in UDPPort::CreateConnection()
that assumes the gathering of host and srflx candidates is sequential.

This CL also does minor refactoring and clean-up.

Bug: chromium:944577
Change-Id: Ic28136a9515081f40b232a22fcbf4209814ed33a
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/138043
Reviewed-by: Steve Anton <steveanton@webrtc.org>
Reviewed-by: Jeroen de Borst <jeroendb@webrtc.org>
Reviewed-by: Amit Hilbuch <amithi@webrtc.org>
Commit-Queue: Qingsi Wang <qingsi@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#28030}
This commit is contained in:
Qingsi Wang 2019-05-22 14:34:56 -07:00 committed by Commit Bot
parent 7e7c5c3c25
commit ecd3054b56
6 changed files with 114 additions and 33 deletions

View File

@ -10,6 +10,7 @@
#include <list>
#include <memory>
#include <utility>
#include "absl/memory/memory.h"
#include "p2p/base/fake_port_allocator.h"
@ -24,11 +25,13 @@
#include "rtc_base/checks.h"
#include "rtc_base/dscp.h"
#include "rtc_base/fake_clock.h"
#include "rtc_base/fake_mdns_responder.h"
#include "rtc_base/fake_network.h"
#include "rtc_base/firewall_socket_server.h"
#include "rtc_base/gunit.h"
#include "rtc_base/helpers.h"
#include "rtc_base/logging.h"
#include "rtc_base/mdns_responder_interface.h"
#include "rtc_base/nat_server.h"
#include "rtc_base/nat_socket_factory.h"
#include "rtc_base/proxy_server.h"
@ -4619,7 +4622,8 @@ TEST_F(P2PTransportChannelTest,
ConfigureEndpoints(OPEN, OPEN, kOnlyLocalPorts, kOnlyLocalPorts);
// ICE parameter will be set up when creating the channels.
set_remote_ice_parameter_source(FROM_SETICEPARAMETERS);
GetEndpoint(0)->network_manager_.CreateMdnsResponder(rtc::Thread::Current());
GetEndpoint(0)->network_manager_.set_mdns_responder(
absl::make_unique<webrtc::FakeMdnsResponder>(rtc::Thread::Current()));
GetEndpoint(1)->async_resolver_factory_ = &mock_async_resolver_factory;
CreateChannels();
// Pause sending candidates from both endpoints until we find out what port
@ -4690,7 +4694,8 @@ TEST_F(P2PTransportChannelTest,
ConfigureEndpoints(OPEN, OPEN, kOnlyLocalPorts, kOnlyLocalPorts);
// ICE parameter will be set up when creating the channels.
set_remote_ice_parameter_source(FROM_SETICEPARAMETERS);
GetEndpoint(0)->network_manager_.CreateMdnsResponder(rtc::Thread::Current());
GetEndpoint(0)->network_manager_.set_mdns_responder(
absl::make_unique<webrtc::FakeMdnsResponder>(rtc::Thread::Current()));
GetEndpoint(1)->async_resolver_factory_ = &mock_async_resolver_factory;
CreateChannels();
// Pause sending candidates from both endpoints until we find out what port
@ -4757,7 +4762,8 @@ TEST_F(P2PTransportChannelTest, CanConnectWithHostCandidateWithMdnsName) {
ConfigureEndpoints(OPEN, OPEN, kOnlyLocalPorts, kOnlyLocalPorts);
// ICE parameter will be set up when creating the channels.
set_remote_ice_parameter_source(FROM_SETICEPARAMETERS);
GetEndpoint(0)->network_manager_.CreateMdnsResponder(rtc::Thread::Current());
GetEndpoint(0)->network_manager_.set_mdns_responder(
absl::make_unique<webrtc::FakeMdnsResponder>(rtc::Thread::Current()));
GetEndpoint(1)->async_resolver_factory_ = &mock_async_resolver_factory;
CreateChannels();
// Pause sending candidates from both endpoints until we find out what port
@ -4813,7 +4819,8 @@ TEST_F(P2PTransportChannelTest,
kOnlyLocalPorts);
// ICE parameter will be set up when creating the channels.
set_remote_ice_parameter_source(FROM_SETICEPARAMETERS);
GetEndpoint(0)->network_manager_.CreateMdnsResponder(rtc::Thread::Current());
GetEndpoint(0)->network_manager_.set_mdns_responder(
absl::make_unique<webrtc::FakeMdnsResponder>(rtc::Thread::Current()));
GetEndpoint(1)->async_resolver_factory_ = &mock_async_resolver_factory;
CreateChannels();
// Pause sending candidates from both endpoints until we find out what port
@ -4891,6 +4898,50 @@ TEST_F(P2PTransportChannelTest,
DestroyChannels();
}
class MockMdnsResponder : public webrtc::MdnsResponderInterface {
public:
MOCK_METHOD2(CreateNameForAddress,
void(const rtc::IPAddress&, NameCreatedCallback));
MOCK_METHOD2(RemoveNameForAddress,
void(const rtc::IPAddress&, NameRemovedCallback));
};
TEST_F(P2PTransportChannelTest,
SrflxCandidateCanBeGatheredBeforeMdnsCandidateToCreateConnection) {
// ep1 and ep2 will only gather host and srflx candidates with base addresses
// kPublicAddrs[0] and kPublicAddrs[1], respectively, and we use a shared
// socket in gathering.
const auto kOnlyLocalAndStunPorts =
cricket::PORTALLOCATOR_DISABLE_RELAY |
cricket::PORTALLOCATOR_DISABLE_TCP |
cricket::PORTALLOCATOR_ENABLE_SHARED_SOCKET;
// ep1 is configured with a NAT so that we do gather a srflx candidate.
ConfigureEndpoints(NAT_FULL_CONE, OPEN, kOnlyLocalAndStunPorts,
kOnlyLocalAndStunPorts);
// ICE parameter will be set up when creating the channels.
set_remote_ice_parameter_source(FROM_SETICEPARAMETERS);
// Use a mock mDNS responder, which does not complete the name registration by
// ignoring the completion callback.
auto mock_mdns_responder = absl::make_unique<MockMdnsResponder>();
EXPECT_CALL(*mock_mdns_responder, CreateNameForAddress(_, _))
.Times(1)
.WillOnce(Return());
GetEndpoint(0)->network_manager_.set_mdns_responder(
std::move(mock_mdns_responder));
CreateChannels();
// We should be able to form a srflx-host connection to ep2.
ASSERT_TRUE_WAIT((ep1_ch1()->selected_connection()) != nullptr,
kMediumTimeout);
EXPECT_EQ(STUN_PORT_TYPE,
ep1_ch1()->selected_connection()->local_candidate().type());
EXPECT_EQ(LOCAL_PORT_TYPE,
ep1_ch1()->selected_connection()->remote_candidate().type());
DestroyChannels();
}
// Test that after changing the candidate filter from relay-only to allowing all
// types of candidates when doing continual gathering, we can gather without ICE
// restart the other types of candidates that are now enabled and form candidate

View File

@ -196,7 +196,7 @@ UDPPort::UDPPort(rtc::Thread* thread,
username,
password),
requests_(thread),
socket_(NULL),
socket_(nullptr),
error_(0),
ready_(false),
stun_keepalive_delay_(STUN_KEEPALIVE_INTERVAL),
@ -208,7 +208,7 @@ UDPPort::UDPPort(rtc::Thread* thread,
bool UDPPort::Init() {
stun_keepalive_lifetime_ = GetStunKeepaliveLifetime();
if (!SharedSocket()) {
RTC_DCHECK(socket_ == NULL);
RTC_DCHECK(socket_ == nullptr);
socket_ = socket_factory()->CreateUdpSocket(
rtc::SocketAddress(Network()->GetBestIP(), 0), min_port(), max_port());
if (!socket_) {
@ -250,17 +250,35 @@ void UDPPort::MaybePrepareStunCandidate() {
Connection* UDPPort::CreateConnection(const Candidate& address,
CandidateOrigin origin) {
if (!SupportsProtocol(address.protocol())) {
return NULL;
return nullptr;
}
if (!IsCompatibleAddress(address.address())) {
return NULL;
return nullptr;
}
if (SharedSocket() && Candidates()[0].type() != LOCAL_PORT_TYPE) {
// In addition to DCHECK-ing the non-emptiness of local candidates, we also
// skip this Port with null if there are latent bugs to violate it; otherwise
// it would lead to a crash when accessing the local candidate of the
// connection that would be created below.
if (Candidates().empty()) {
RTC_NOTREACHED();
return NULL;
return nullptr;
}
// When the socket is shared, the srflx candidate is gathered by the UDPPort.
// The assumption here is that
// 1) if the IP concealment with mDNS is not enabled, the gathering of the
// host candidate of this port (which is synchronous),
// 2) or otherwise if enabled, the start of name registration of the host
// candidate (as the start of asynchronous gathering)
// is always before the gathering of a srflx candidate (and any prflx
// candidate).
//
// See also the definition of MdnsNameRegistrationStatus::kNotStarted in
// port.h.
RTC_DCHECK(!SharedSocket() || Candidates()[0].type() == LOCAL_PORT_TYPE ||
mdns_name_registration_status() !=
MdnsNameRegistrationStatus::kNotStarted);
Connection* conn = new ProxyConnection(this, 0, address);
AddOrReplaceConnection(conn);
@ -418,7 +436,7 @@ void UDPPort::ResolveStunAddress(const rtc::SocketAddress& stun_addr) {
}
void UDPPort::OnResolveResult(const rtc::SocketAddress& input, int error) {
RTC_DCHECK(resolver_.get() != NULL);
RTC_DCHECK(resolver_.get() != nullptr);
rtc::SocketAddress resolved;
if (error != 0 || !resolver_->GetResolvedAddress(

View File

@ -12,6 +12,7 @@
#include <ostream> // no-presubmit-check TODO(webrtc:8982)
#include "absl/algorithm/container.h"
#include "absl/memory/memory.h"
#include "p2p/base/basic_packet_socket_factory.h"
#include "p2p/base/p2p_constants.h"
#include "p2p/base/stun_port.h"
@ -22,6 +23,7 @@
#include "p2p/base/test_turn_server.h"
#include "p2p/client/basic_port_allocator.h"
#include "rtc_base/fake_clock.h"
#include "rtc_base/fake_mdns_responder.h"
#include "rtc_base/fake_network.h"
#include "rtc_base/firewall_socket_server.h"
#include "rtc_base/gunit.h"
@ -2395,7 +2397,8 @@ TEST_F(BasicPortAllocatorTest, HostCandidateAddressIsReplacedByHostname) {
AddTurnServers(kTurnUdpIntIPv6Addr, kTurnTcpIntIPv6Addr);
ASSERT_EQ(&network_manager_, allocator().network_manager());
network_manager_.CreateMdnsResponder(rtc::Thread::Current());
network_manager_.set_mdns_responder(
absl::make_unique<webrtc::FakeMdnsResponder>(rtc::Thread::Current()));
AddInterface(kClientAddr);
ASSERT_TRUE(CreateSession(ICE_CANDIDATE_COMPONENT_RTP));
session_->StartGettingPorts();

View File

@ -33,6 +33,7 @@
#include "pc/test/mock_peer_connection_observers.h"
#include "rtc_base/arraysize.h"
#include "rtc_base/checks.h"
#include "rtc_base/fake_mdns_responder.h"
#include "rtc_base/fake_network.h"
#include "rtc_base/gunit.h"
#include "rtc_base/ref_counted_object.h"
@ -245,7 +246,8 @@ class PeerConnectionUsageHistogramTest : public ::testing::Test {
webrtc::PeerConnectionDependencies deps(nullptr /* observer_in */);
auto fake_network = NewFakeNetwork();
fake_network->CreateMdnsResponder(rtc::Thread::Current());
fake_network->set_mdns_responder(
absl::make_unique<webrtc::FakeMdnsResponder>(rtc::Thread::Current()));
fake_network->AddInterface(NextLocalAddress());
std::unique_ptr<cricket::BasicPortAllocator> port_allocator(

View File

@ -61,6 +61,7 @@
#include "pc/test/fake_video_track_renderer.h"
#include "pc/test/mock_peer_connection_observers.h"
#include "rtc_base/fake_clock.h"
#include "rtc_base/fake_mdns_responder.h"
#include "rtc_base/fake_network.h"
#include "rtc_base/firewall_socket_server.h"
#include "rtc_base/gunit.h"
@ -552,7 +553,7 @@ class PeerConnectionWrapper : public webrtc::PeerConnectionObserver,
}
}
rtc::FakeNetworkManager* network() const {
rtc::FakeNetworkManager* network_manager() const {
return fake_network_manager_.get();
}
cricket::PortAllocator* port_allocator() const { return port_allocator_; }
@ -565,6 +566,15 @@ class PeerConnectionWrapper : public webrtc::PeerConnectionObserver,
return last_candidate_gathered_;
}
// Sets the mDNS responder for the owned fake network manager and keeps a
// reference to the responder.
void SetMdnsResponder(
std::unique_ptr<webrtc::FakeMdnsResponder> mdns_responder) {
RTC_DCHECK(mdns_responder != nullptr);
mdns_responder_ = mdns_responder.get();
network_manager()->set_mdns_responder(std::move(mdns_responder));
}
private:
explicit PeerConnectionWrapper(const std::string& debug_name)
: debug_name_(debug_name) {}
@ -926,11 +936,10 @@ class PeerConnectionWrapper : public webrtc::PeerConnectionObserver,
if (remote_async_resolver_) {
const auto& local_candidate = candidate->candidate();
const auto& mdns_responder = network()->GetMdnsResponderForTesting();
if (local_candidate.address().IsUnresolvedIP()) {
RTC_DCHECK(local_candidate.type() == cricket::LOCAL_PORT_TYPE);
rtc::SocketAddress resolved_addr(local_candidate.address());
const auto resolved_ip = mdns_responder->GetMappedAddressForName(
const auto resolved_ip = mdns_responder_->GetMappedAddressForName(
local_candidate.address().hostname());
RTC_DCHECK(!resolved_ip.IsNil());
resolved_addr.SetResolvedIP(resolved_ip);
@ -959,6 +968,8 @@ class PeerConnectionWrapper : public webrtc::PeerConnectionObserver,
std::string debug_name_;
std::unique_ptr<rtc::FakeNetworkManager> fake_network_manager_;
// Reference to the mDNS responder owned by |fake_network_manager_| after set.
webrtc::FakeMdnsResponder* mdns_responder_ = nullptr;
rtc::scoped_refptr<webrtc::PeerConnectionInterface> peer_connection_;
rtc::scoped_refptr<webrtc::PeerConnectionFactoryInterface>
@ -3825,8 +3836,10 @@ TEST_P(PeerConnectionIntegrationTest,
callee()->SetRemoteAsyncResolver(&caller_async_resolver);
// Enable hostname candidates with mDNS names.
caller()->network()->CreateMdnsResponder(network_thread());
callee()->network()->CreateMdnsResponder(network_thread());
caller()->SetMdnsResponder(
absl::make_unique<webrtc::FakeMdnsResponder>(network_thread()));
callee()->SetMdnsResponder(
absl::make_unique<webrtc::FakeMdnsResponder>(network_thread()));
SetPortAllocatorFlags(kOnlyLocalPorts, kOnlyLocalPorts);
@ -3891,15 +3904,15 @@ class PeerConnectionIntegrationIceStatesTest
void SetUpNetworkInterfaces() {
// Remove the default interfaces added by the test infrastructure.
caller()->network()->RemoveInterface(kDefaultLocalAddress);
callee()->network()->RemoveInterface(kDefaultLocalAddress);
caller()->network_manager()->RemoveInterface(kDefaultLocalAddress);
callee()->network_manager()->RemoveInterface(kDefaultLocalAddress);
// Add network addresses for test.
for (const auto& caller_address : CallerAddresses()) {
caller()->network()->AddInterface(caller_address);
caller()->network_manager()->AddInterface(caller_address);
}
for (const auto& callee_address : CalleeAddresses()) {
callee()->network()->AddInterface(callee_address);
callee()->network_manager()->AddInterface(callee_address);
}
}

View File

@ -18,7 +18,7 @@
#include "absl/memory/memory.h"
#include "rtc_base/checks.h"
#include "rtc_base/fake_mdns_responder.h"
#include "rtc_base/mdns_responder_interface.h"
#include "rtc_base/message_handler.h"
#include "rtc_base/network.h"
#include "rtc_base/socket_address.h"
@ -82,13 +82,6 @@ class FakeNetworkManager : public NetworkManagerBase, public MessageHandler {
// MessageHandler interface.
void OnMessage(Message* msg) override { DoUpdateNetworks(); }
void CreateMdnsResponder(rtc::Thread* network_thread) {
if (mdns_responder_ == nullptr) {
mdns_responder_ =
absl::make_unique<webrtc::FakeMdnsResponder>(network_thread);
}
}
using NetworkManagerBase::set_enumeration_permission;
using NetworkManagerBase::set_default_local_addresses;
@ -97,8 +90,9 @@ class FakeNetworkManager : public NetworkManagerBase, public MessageHandler {
return mdns_responder_.get();
}
webrtc::FakeMdnsResponder* GetMdnsResponderForTesting() const {
return mdns_responder_.get();
void set_mdns_responder(
std::unique_ptr<webrtc::MdnsResponderInterface> mdns_responder) {
mdns_responder_ = std::move(mdns_responder);
}
private:
@ -134,7 +128,7 @@ class FakeNetworkManager : public NetworkManagerBase, public MessageHandler {
int start_count_ = 0;
bool sent_first_update_ = false;
std::unique_ptr<webrtc::FakeMdnsResponder> mdns_responder_;
std::unique_ptr<webrtc::MdnsResponderInterface> mdns_responder_;
};
} // namespace rtc