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}
diff --git a/p2p/base/p2p_transport_channel_unittest.cc b/p2p/base/p2p_transport_channel_unittest.cc
index bab75de..623bb7c 100644
--- a/p2p/base/p2p_transport_channel_unittest.cc
+++ b/p2p/base/p2p_transport_channel_unittest.cc
@@ -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 @@
   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 @@
   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 @@
   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 @@
                      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 @@
   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
diff --git a/p2p/base/stun_port.cc b/p2p/base/stun_port.cc
index f94ea65..03d9553 100644
--- a/p2p/base/stun_port.cc
+++ b/p2p/base/stun_port.cc
@@ -196,7 +196,7 @@
            username,
            password),
       requests_(thread),
-      socket_(NULL),
+      socket_(nullptr),
       error_(0),
       ready_(false),
       stun_keepalive_delay_(STUN_KEEPALIVE_INTERVAL),
@@ -208,7 +208,7 @@
 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 @@
 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::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(
diff --git a/p2p/client/basic_port_allocator_unittest.cc b/p2p/client/basic_port_allocator_unittest.cc
index 067e757..a893554 100644
--- a/p2p/client/basic_port_allocator_unittest.cc
+++ b/p2p/client/basic_port_allocator_unittest.cc
@@ -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 @@
   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();
diff --git a/pc/peer_connection_histogram_unittest.cc b/pc/peer_connection_histogram_unittest.cc
index 97555a9..54c251a 100644
--- a/pc/peer_connection_histogram_unittest.cc
+++ b/pc/peer_connection_histogram_unittest.cc
@@ -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 @@
     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(
diff --git a/pc/peer_connection_integrationtest.cc b/pc/peer_connection_integrationtest.cc
index 3a39971..0fc2e15 100644
--- a/pc/peer_connection_integrationtest.cc
+++ b/pc/peer_connection_integrationtest.cc
@@ -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 @@
     }
   }
 
-  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 @@
     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 @@
 
     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 @@
   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 @@
   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 @@
 
   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);
     }
   }
 
diff --git a/rtc_base/fake_network.h b/rtc_base/fake_network.h
index 1da9814..5913cc3 100644
--- a/rtc_base/fake_network.h
+++ b/rtc_base/fake_network.h
@@ -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 @@
   // 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 @@
     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 @@
   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