Resolve the race condition between mDNS name registration and
cricket::Port::SignalPortComplete.

The mDNS name registration is asynchronously executed by the mDNS
responder, and a host candidate with an mDNS name is only gathered after
this completes. SignalPortComplete however is currently done
synchronously by UDPPort, and any candidate gathered by a UDPPort after
this signal is fired would be discarded.

Bug: webrtc:9964, webrtc:9605
Change-Id: If8aaf193ef26c06bd118e6418b62ba0de5e87e3c
Reviewed-on: https://webrtc-review.googlesource.com/c/109541
Reviewed-by: Qingsi Wang <qingsi@webrtc.org>
Reviewed-by: Zach Stein <zstein@webrtc.org>
Reviewed-by: Steve Anton <steveanton@webrtc.org>
Commit-Queue: Qingsi Wang <qingsi@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#25534}
diff --git a/p2p/base/port.cc b/p2p/base/port.cc
index b00983a..4954744 100644
--- a/p2p/base/port.cc
+++ b/p2p/base/port.cc
@@ -399,9 +399,9 @@
                       const std::string& type,
                       uint32_t type_preference,
                       uint32_t relay_preference,
-                      bool final) {
+                      bool is_final) {
   AddAddress(address, base_address, related_address, protocol, relay_protocol,
-             tcptype, type, type_preference, relay_preference, "", final);
+             tcptype, type, type_preference, relay_preference, "", is_final);
 }
 
 void Port::AddAddress(const rtc::SocketAddress& address,
@@ -448,9 +448,13 @@
         c.set_address(hostname_address);
         RTC_DCHECK(c.related_address() == rtc::SocketAddress());
         if (weak_ptr != nullptr) {
+          weak_ptr->set_mdns_name_registration_status(
+              MdnsNameRegistrationStatus::kCompleted);
           weak_ptr->FinishAddingAddress(c, is_final);
         }
       };
+      set_mdns_name_registration_status(
+          MdnsNameRegistrationStatus::kInProgress);
       network_->GetMdnsResponder()->CreateNameForAddress(c.address().ipaddr(),
                                                          callback);
       return;
@@ -468,6 +472,10 @@
   candidates_.push_back(c);
   SignalCandidateReady(this, c);
 
+  PostAddAddress(is_final);
+}
+
+void Port::PostAddAddress(bool is_final) {
   if (is_final) {
     SignalPortComplete(this);
   }
diff --git a/p2p/base/port.h b/p2p/base/port.h
index 25a1cf7..e0b3f07 100644
--- a/p2p/base/port.h
+++ b/p2p/base/port.h
@@ -84,6 +84,18 @@
   // frozen because we have not implemented ICE freezing logic.
 };
 
+enum class MdnsNameRegistrationStatus {
+  // IP concealment with mDNS is not enabled or the name registration process is
+  // not started yet.
+  kNotStarted,
+  // A request to create and register an mDNS name for a local IP address of a
+  // host candidate is sent to the mDNS responder.
+  kInProgress,
+  // The name registration is complete and the created name is returned by the
+  // mDNS responder.
+  kCompleted,
+};
+
 // Stats that we can return about the port of a STUN candidate.
 class StunStats {
  public:
@@ -393,7 +405,7 @@
                   const std::string& type,
                   uint32_t type_preference,
                   uint32_t relay_preference,
-                  bool final);
+                  bool is_final);
 
   void AddAddress(const rtc::SocketAddress& address,
                   const rtc::SocketAddress& base_address,
@@ -409,6 +421,8 @@
 
   void FinishAddingAddress(const Candidate& c, bool is_final);
 
+  virtual void PostAddAddress(bool is_final);
+
   // Adds the given connection to the map keyed by the remote candidate address.
   // If an existing connection has the same address, the existing one will be
   // replaced and destroyed.
@@ -444,6 +458,13 @@
 
   void CopyPortInformationToPacketInfo(rtc::PacketInfo* info) const;
 
+  MdnsNameRegistrationStatus mdns_name_registration_status() const {
+    return mdns_name_registration_status_;
+  }
+  void set_mdns_name_registration_status(MdnsNameRegistrationStatus status) {
+    mdns_name_registration_status_ = status;
+  }
+
  private:
   void Construct();
   // Called when one of our connections deletes itself.
@@ -488,6 +509,8 @@
   int16_t network_cost_;
   State state_ = State::INIT;
   int64_t last_time_all_connections_removed_ = 0;
+  MdnsNameRegistrationStatus mdns_name_registration_status_ =
+      MdnsNameRegistrationStatus::kNotStarted;
 
   rtc::WeakPtrFactory<Port> weak_factory_;
 
diff --git a/p2p/base/stunport.cc b/p2p/base/stunport.cc
index 00ecca2..7273123 100644
--- a/p2p/base/stunport.cc
+++ b/p2p/base/stunport.cc
@@ -358,6 +358,10 @@
   MaybePrepareStunCandidate();
 }
 
+void UDPPort::PostAddAddress(bool is_final) {
+  MaybeSetPortCompleteOrError();
+}
+
 void UDPPort::OnReadPacket(rtc::AsyncPacketSocket* socket,
                            const char* data,
                            size_t size,
@@ -517,8 +521,14 @@
 }
 
 void UDPPort::MaybeSetPortCompleteOrError() {
-  if (ready_)
+  if (mdns_name_registration_status() ==
+      MdnsNameRegistrationStatus::kInProgress) {
     return;
+  }
+
+  if (ready_) {
+    return;
+  }
 
   // Do not set port ready if we are still waiting for bind responses.
   const size_t servers_done_bind_request =
diff --git a/p2p/base/stunport.h b/p2p/base/stunport.h
index dc9f0e3..ca43cbc 100644
--- a/p2p/base/stunport.h
+++ b/p2p/base/stunport.h
@@ -160,6 +160,9 @@
 
   void OnLocalAddressReady(rtc::AsyncPacketSocket* socket,
                            const rtc::SocketAddress& address);
+
+  void PostAddAddress(bool is_final) override;
+
   void OnReadPacket(rtc::AsyncPacketSocket* socket,
                     const char* data,
                     size_t size,