Reland "Enable any address ports by default."

This reverts commit 056a68da896d9a578b9ea83e56d261648ea0adc6.

Reason for revert: Trying to reland.

Original change's description:
> Revert "Enable any address ports by default."
> 
> This reverts commit f04148c810aad2a0809dc8978650c55308381c47.
> 
> Reason for revert: Speculative revert. I suspect this is breaking a
> downstream test (I'll reland if it is not the culprit).
> 
> Original change's description:
> > Enable any address ports by default.
> > 
> > Ports not bound to any specific network interface are allocated by
> > default. These any address ports are pruned after allocation,
> > conditional on the allocation results of normal ports that are bound to
> > the enumerated interfaces.
> > 
> > Bug: webrtc:9313
> > Change-Id: I3ce12eeab0cf3547224e5f8c188d061fc530e145
> > Reviewed-on: https://webrtc-review.googlesource.com/78383
> > Commit-Queue: Qingsi Wang <qingsi@google.com>
> > Reviewed-by: Taylor Brandstetter <deadbeef@webrtc.org>
> > Cr-Commit-Position: refs/heads/master@{#23673}
> 
> TBR=deadbeef@webrtc.org,pthatcher@webrtc.org,qingsi@google.com
> 
> Change-Id: I3b3dc42c7de46d198d4b9c270020dcf1100dd907
> No-Presubmit: true
> No-Tree-Checks: true
> No-Try: true
> Bug: webrtc:9313
> Reviewed-on: https://webrtc-review.googlesource.com/84300
> Reviewed-by: Mirko Bonadei <mbonadei@webrtc.org>
> Commit-Queue: Mirko Bonadei <mbonadei@webrtc.org>
> Cr-Commit-Position: refs/heads/master@{#23678}

TBR=deadbeef@webrtc.org,mbonadei@webrtc.org,pthatcher@webrtc.org,qingsi@google.com

# Not skipping CQ checks because original CL landed > 1 day ago.

Bug: webrtc:9313
Change-Id: I98442346babb5d8953d37dc5825efaf79804ed7f
Reviewed-on: https://webrtc-review.googlesource.com/85000
Reviewed-by: Mirko Bonadei <mbonadei@webrtc.org>
Commit-Queue: Qingsi Wang <qingsi@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#23720}
diff --git a/p2p/base/p2pconstants.cc b/p2p/base/p2pconstants.cc
index 7dad2d0..5df2861 100644
--- a/p2p/base/p2pconstants.cc
+++ b/p2p/base/p2pconstants.cc
@@ -72,4 +72,8 @@
 // of increased memory, but in some networks (2G), we observe up to 60s RTTs.
 const int CONNECTION_RESPONSE_TIMEOUT = 60 * 1000;  // 60 seconds
 
+// TODO(qingsi): Review and calibrate the value (bugs.webrtc.org/9427).
+const int kMaxWaitMsBeforeSignalingAnyAddressPortsAndCandidates =
+    2.5 * 1000;  // 2.5 seconds
+
 }  // namespace cricket
diff --git a/p2p/base/p2pconstants.h b/p2p/base/p2pconstants.h
index b2e92ef..3378335 100644
--- a/p2p/base/p2pconstants.h
+++ b/p2p/base/p2pconstants.h
@@ -102,7 +102,12 @@
 // The minimum time we will wait before destroying a connection after creating
 // it.
 extern const int MIN_CONNECTION_LIFETIME;
-
+// TODO(qingsi): Rename all constants to kConstant style.
+//
+// The maximum time in milliseconds we will wait before signaling any address
+// ports and candidates gathered from these ports, if the candidate allocation
+// is not done yet.
+extern const int kMaxWaitMsBeforeSignalingAnyAddressPortsAndCandidates;
 }  // namespace cricket
 
 #endif  // P2P_BASE_P2PCONSTANTS_H_
diff --git a/p2p/base/p2ptransportchannel_unittest.cc b/p2p/base/p2ptransportchannel_unittest.cc
index 57af9dc..4cf3c53 100644
--- a/p2p/base/p2ptransportchannel_unittest.cc
+++ b/p2p/base/p2ptransportchannel_unittest.cc
@@ -52,6 +52,7 @@
                                    cricket::PORTALLOCATOR_DISABLE_RELAY |
                                    cricket::PORTALLOCATOR_DISABLE_TCP;
 static const int LOW_RTT = 20;
+static const SocketAddress kAnyAddr("0.0.0.0", 0);
 // Addresses on the public internet.
 static const SocketAddress kPublicAddrs[2] = {SocketAddress("11.11.11.11", 0),
                                               SocketAddress("22.22.22.22", 0)};
@@ -426,6 +427,7 @@
 
   rtc::NATSocketServer* nat() { return nss_.get(); }
   rtc::FirewallSocketServer* fw() { return ss_.get(); }
+  rtc::VirtualSocketServer* vss() { return vss_.get(); }
 
   Endpoint* GetEndpoint(int endpoint) {
     if (endpoint == 0) {
@@ -1042,10 +1044,12 @@
         AddAddress(endpoint, kPublicAddrs[endpoint]);
         // Block all UDP
         fw()->AddRule(false, rtc::FP_UDP, rtc::FD_ANY, kPublicAddrs[endpoint]);
+        fw()->AddRule(false, rtc::FP_UDP, rtc::FD_ANY, kAnyAddr);
         if (config == BLOCK_UDP_AND_INCOMING_TCP) {
           // Block TCP inbound to the endpoint
           fw()->AddRule(false, rtc::FP_TCP, SocketAddress(),
                         kPublicAddrs[endpoint]);
+          fw()->AddRule(false, rtc::FP_TCP, SocketAddress(), kAnyAddr);
         } else if (config == BLOCK_ALL_BUT_OUTGOING_HTTP) {
           // Block all TCP to/from the endpoint except 80/443 out
           fw()->AddRule(true, rtc::FP_TCP, kPublicAddrs[endpoint],
@@ -1054,12 +1058,14 @@
                         SocketAddress(rtc::IPAddress(INADDR_ANY), 443));
           fw()->AddRule(false, rtc::FP_TCP, rtc::FD_ANY,
                         kPublicAddrs[endpoint]);
+          fw()->AddRule(false, rtc::FP_TCP, rtc::FD_ANY, kAnyAddr);
         } else if (config == PROXY_HTTPS) {
           // Block all TCP to/from the endpoint except to the proxy server
           fw()->AddRule(true, rtc::FP_TCP, kPublicAddrs[endpoint],
                         kHttpsProxyAddrs[endpoint]);
           fw()->AddRule(false, rtc::FP_TCP, rtc::FD_ANY,
                         kPublicAddrs[endpoint]);
+          fw()->AddRule(false, rtc::FP_TCP, rtc::FD_ANY, kAnyAddr);
           SetProxy(endpoint, rtc::PROXY_HTTPS);
         } else if (config == PROXY_SOCKS) {
           // Block all TCP to/from the endpoint except to the proxy server
@@ -1067,6 +1073,7 @@
                         kSocksProxyAddrs[endpoint]);
           fw()->AddRule(false, rtc::FP_TCP, rtc::FD_ANY,
                         kPublicAddrs[endpoint]);
+          fw()->AddRule(false, rtc::FP_TCP, rtc::FD_ANY, kAnyAddr);
           SetProxy(endpoint, rtc::PROXY_SOCKS5);
         }
         break;
@@ -1709,16 +1716,8 @@
 // connections. This has been observed in some scenarios involving
 // VPNs/firewalls.
 TEST_F(P2PTransportChannelTest, CanOnlyMakeOutgoingTcpConnections) {
-  // The PORTALLOCATOR_ENABLE_ANY_ADDRESS_PORTS flag is required if the
-  // application needs this use case to work, since the application must accept
-  // the tradeoff that more candidates need to be allocated.
-  //
-  // TODO(deadbeef): Later, make this flag the default, and do more elegant
-  // things to ensure extra candidates don't waste resources?
-  ConfigureEndpoints(
-      OPEN, OPEN,
-      kDefaultPortAllocatorFlags | PORTALLOCATOR_ENABLE_ANY_ADDRESS_PORTS,
-      kDefaultPortAllocatorFlags);
+  ConfigureEndpoints(OPEN, OPEN, kDefaultPortAllocatorFlags,
+                     kDefaultPortAllocatorFlags);
   // In order to simulate nothing working but outgoing TCP connections, prevent
   // the endpoint from binding to its interface's address as well as the
   // "any" addresses. It can then only make a connection by using "Connect()".
@@ -3069,6 +3068,33 @@
   DestroyChannels();
 }
 
+// Test that when explicit binding to network interfaces is disallowed, we may
+// still establish a connection by using the any address fallback.
+TEST_F(P2PTransportChannelMultihomedTest,
+       BindingToAnyAddressRevealsViableRouteWhenExplicitBindingFails) {
+  rtc::ScopedFakeClock clock;
+  AddAddress(0, kPublicAddrs[0]);
+  AddAddress(1, kPublicAddrs[1]);
+  fw()->SetUnbindableIps({kPublicAddrs[0].ipaddr()});
+  // When bound to the any address, the port allocator should discover the
+  // alternative local address.
+  vss()->SetAlternativeLocalAddress(kAnyAddr.ipaddr(),
+                                    kAlternateAddrs[0].ipaddr());
+  SetAllocatorFlags(0, kOnlyLocalPorts);
+  SetAllocatorFlags(1, kOnlyLocalPorts);
+  IceConfig default_config;
+  CreateChannels(default_config, default_config);
+  EXPECT_TRUE_SIMULATED_WAIT(ep1_ch1()->receiving() && ep1_ch1()->writable() &&
+                                 ep2_ch1()->receiving() &&
+                                 ep2_ch1()->writable(),
+                             kMediumTimeout, clock);
+  EXPECT_TRUE(
+      ep1_ch1()->selected_connection() && ep2_ch1()->selected_connection() &&
+      LocalCandidate(ep1_ch1())->address().EqualIPs(kAlternateAddrs[0]));
+
+  DestroyChannels();
+}
+
 // A collection of tests which tests a single P2PTransportChannel by sending
 // pings.
 class P2PTransportChannelPingTest : public testing::Test,
diff --git a/p2p/base/portallocator.h b/p2p/base/portallocator.h
index dcf6c6b..f5e5452 100644
--- a/p2p/base/portallocator.h
+++ b/p2p/base/portallocator.h
@@ -75,13 +75,11 @@
   // When specified, do not collect IPv6 ICE candidates on Wi-Fi.
   PORTALLOCATOR_ENABLE_IPV6_ON_WIFI = 0x4000,
 
-  // When this flag is set, ports not bound to any specific network interface
-  // will be used, in addition to normal ports bound to the enumerated
-  // interfaces. Without this flag, these "any address" ports would only be
-  // used when network enumeration fails or is disabled. But under certain
-  // conditions, these ports may succeed where others fail, so they may allow
-  // the application to work in a wider variety of environments, at the expense
-  // of having to allocate additional candidates.
+  // This flag is deprecated; we now always enable any address ports, only
+  // using them if they end up using interfaces that weren't otherwise
+  // accessible.
+  //
+  // TODO(qingsi): Remove this flag when downstream projects no longer use it.
   PORTALLOCATOR_ENABLE_ANY_ADDRESS_PORTS = 0x8000,
 
   // Exclude link-local network interfaces
diff --git a/p2p/base/stunserver.cc b/p2p/base/stunserver.cc
index 00eacf1..50cb654 100644
--- a/p2p/base/stunserver.cc
+++ b/p2p/base/stunserver.cc
@@ -54,7 +54,7 @@
 void StunServer::OnBindingRequest(StunMessage* msg,
                                   const rtc::SocketAddress& remote_addr) {
   StunMessage response;
-  GetStunBindReqponse(msg, remote_addr, &response);
+  GetStunBindResponse(msg, remote_addr, &response);
   SendResponse(response, remote_addr);
 }
 
@@ -83,7 +83,7 @@
     RTC_LOG_ERR(LS_ERROR) << "sendto";
 }
 
-void StunServer::GetStunBindReqponse(StunMessage* request,
+void StunServer::GetStunBindResponse(StunMessage* request,
                                      const rtc::SocketAddress& remote_addr,
                                      StunMessage* response) const {
   response->SetType(STUN_BINDING_RESPONSE);
diff --git a/p2p/base/stunserver.h b/p2p/base/stunserver.h
index 9016d06..5d0f130 100644
--- a/p2p/base/stunserver.h
+++ b/p2p/base/stunserver.h
@@ -52,7 +52,7 @@
   void SendResponse(const StunMessage& msg, const rtc::SocketAddress& addr);
 
   // A helper method to compose a STUN binding response.
-  void GetStunBindReqponse(StunMessage* request,
+  void GetStunBindResponse(StunMessage* request,
                            const rtc::SocketAddress& remote_addr,
                            StunMessage* response) const;
 
diff --git a/p2p/base/teststunserver.cc b/p2p/base/teststunserver.cc
index 13bc577..7a18d7a 100644
--- a/p2p/base/teststunserver.cc
+++ b/p2p/base/teststunserver.cc
@@ -27,7 +27,7 @@
     StunServer::OnBindingRequest(msg, remote_addr);
   } else {
     StunMessage response;
-    GetStunBindReqponse(msg, fake_stun_addr_, &response);
+    GetStunBindResponse(msg, fake_stun_addr_, &response);
     SendResponse(response, remote_addr);
   }
 }
diff --git a/p2p/client/basicportallocator.cc b/p2p/client/basicportallocator.cc
index 14cf1ae..4335dda 100644
--- a/p2p/client/basicportallocator.cc
+++ b/p2p/client/basicportallocator.cc
@@ -26,6 +26,7 @@
 #include "p2p/base/udpport.h"
 #include "rtc_base/checks.h"
 #include "rtc_base/helpers.h"
+#include "rtc_base/ipaddress.h"
 #include "rtc_base/logging.h"
 
 using rtc::CreateRandomId;
@@ -39,6 +40,7 @@
   MSG_ALLOCATION_PHASE,
   MSG_SEQUENCEOBJECTS_CREATED,
   MSG_CONFIG_STOP,
+  MSG_SIGNAL_ANY_ADDRESS_PORTS,
 };
 
 const int PHASE_UDP = 0;
@@ -111,6 +113,10 @@
   networks->erase(start_to_remove, networks->end());
 }
 
+bool IsAnyAddressPort(const cricket::Port* port) {
+  return rtc::IPIsAny(port->Network()->GetBestIP());
+}
+
 }  // namespace
 
 namespace cricket {
@@ -148,7 +154,7 @@
     : network_manager_(network_manager), socket_factory_(socket_factory) {
   InitRelayPortFactory(nullptr);
   RTC_DCHECK(relay_port_factory_ != nullptr);
-  RTC_DCHECK(socket_factory_ != NULL);
+  RTC_DCHECK(socket_factory_ != nullptr);
   SetConfiguration(stun_servers, std::vector<RelayServerConfig>(), 0, false,
                    nullptr);
   Construct();
@@ -160,7 +166,7 @@
     const rtc::SocketAddress& relay_address_udp,
     const rtc::SocketAddress& relay_address_tcp,
     const rtc::SocketAddress& relay_address_ssl)
-    : network_manager_(network_manager), socket_factory_(NULL) {
+    : network_manager_(network_manager), socket_factory_(nullptr) {
   InitRelayPortFactory(nullptr);
   RTC_DCHECK(relay_port_factory_ != nullptr);
   RTC_DCHECK(network_manager_ != nullptr);
@@ -265,7 +271,7 @@
                            ice_pwd,
                            allocator->flags()),
       allocator_(allocator),
-      network_thread_(NULL),
+      network_thread_(nullptr),
       socket_factory_(allocator->socket_factory()),
       allocation_started_(false),
       network_manager_started_(false),
@@ -278,7 +284,7 @@
 
 BasicPortAllocatorSession::~BasicPortAllocatorSession() {
   allocator_->network_manager()->StopUpdating();
-  if (network_thread_ != NULL)
+  if (network_thread_ != nullptr)
     network_thread_->Clear(this);
 
   for (uint32_t i = 0; i < sequences_.size(); ++i) {
@@ -445,7 +451,7 @@
   std::vector<PortData*> ports_to_prune = GetUnprunedPorts(networks);
   if (!ports_to_prune.empty()) {
     RTC_LOG(LS_INFO) << "Prune " << ports_to_prune.size() << " ports";
-    PrunePortsAndRemoveCandidates(ports_to_prune);
+    PrunePortsAndSignalCandidatesRemoval(ports_to_prune);
   }
 
   if (allocation_started_ && network_manager_started_ && !IsStopped()) {
@@ -567,6 +573,10 @@
       RTC_DCHECK(rtc::Thread::Current() == network_thread_);
       OnConfigStop();
       break;
+    case MSG_SIGNAL_ANY_ADDRESS_PORTS:
+      RTC_DCHECK(rtc::Thread::Current() == network_thread_);
+      SignalAnyAddressPortsAndCandidatesReadyIfNotRedundant();
+      break;
     default:
       RTC_NOTREACHED();
   }
@@ -629,7 +639,7 @@
 
   // If we stopped anything that was running, send a done signal now.
   if (send_signal) {
-    MaybeSignalCandidatesAllocationDone();
+    FireAllocationStatusSignalsIfNeeded();
   }
 }
 
@@ -657,22 +667,24 @@
       rtc::NetworkManager::ENUMERATION_BLOCKED) {
     set_flags(flags() | PORTALLOCATOR_DISABLE_ADAPTER_ENUMERATION);
   }
-  // If the adapter enumeration is disabled, we'll just bind to any address
-  // instead of specific NIC. This is to ensure the same routing for http
-  // traffic by OS is also used here to avoid any local or public IP leakage
-  // during stun process.
-  if (flags() & PORTALLOCATOR_DISABLE_ADAPTER_ENUMERATION) {
-    network_manager->GetAnyAddressNetworks(&networks);
-  } else {
+
+  // If adapter enumeration is disabled, we'll just bind to any address
+  // instead of a specific NIC. This is to ensure that WebRTC traffic is routed
+  // by the OS in the same way that HTTP traffic would be, and no additional
+  // local or public IPs are leaked during ICE processing.
+  //
+  // Even when adapter enumeration is enabled, we still bind to the "any"
+  // address as a fallback, since this may potentially reveal network
+  // interfaces that weren't otherwise accessible. Note that the candidates
+  // gathered by binding to the "any" address won't be surfaced to the
+  // application if they're determined to be redundant (if they have the same
+  // address as a candidate gathered by binding to an interface explicitly).
+  if (!(flags() & PORTALLOCATOR_DISABLE_ADAPTER_ENUMERATION)) {
     network_manager->GetNetworks(&networks);
-    // If network enumeration fails, use the ANY address as a fallback, so we
-    // can at least try gathering candidates using the default route chosen by
-    // the OS. Or, if the PORTALLOCATOR_ENABLE_ANY_ADDRESS_PORTS flag is
-    // set, we'll use ANY address candidates either way.
-    if (networks.empty() || flags() & PORTALLOCATOR_ENABLE_ANY_ADDRESS_PORTS) {
-      network_manager->GetAnyAddressNetworks(&networks);
-    }
   }
+
+  network_manager->GetAnyAddressNetworks(&networks);
+
   // Filter out link-local networks if needed.
   if (flags() & PORTALLOCATOR_DISABLE_LINK_LOCAL_NETWORKS) {
     NetworkFilter link_local_filter(
@@ -691,11 +703,12 @@
   if (flags() & PORTALLOCATOR_DISABLE_COSTLY_NETWORKS) {
     uint16_t lowest_cost = rtc::kNetworkCostMax;
     for (rtc::Network* network : networks) {
-      // Don't determine the lowest cost from a link-local network.
-      // On iOS, a device connected to the computer will get a link-local
-      // network for communicating with the computer, however this network can't
-      // be used to connect to a peer outside the network.
-      if (rtc::IPIsLinkLocal(network->GetBestIP())) {
+      // Don't determine the lowest cost from a link-local or any address
+      // network. On iOS, a device connected to the computer will get a
+      // link-local network for communicating with the computer, however this
+      // network can't be used to connect to a peer outside the network.
+      if (rtc::IPIsLinkLocal(network->GetBestIP()) ||
+          rtc::IPIsAny(network->GetBestIP())) {
         continue;
       }
       lowest_cost = std::min<uint16_t>(lowest_cost, network->GetCost());
@@ -793,6 +806,19 @@
   if (done_signal_needed) {
     network_thread_->Post(RTC_FROM_HERE, this, MSG_SEQUENCEOBJECTS_CREATED);
   }
+
+  // If adapter enumeration is enabled, then we prefer binding to individual
+  // network adapters, only using ports bound to the "any" address (0.0.0.0) if
+  // they reveal an interface not otherwise accessible. Normally these will be
+  // surfaced when candidate allocation completes, but sometimes candidate
+  // allocation can take a long time, if a STUN transaction times out for
+  // instance. So as a backup, we'll surface these ports/candidates after
+  // |kMaxWaitMsBeforeSignalingAnyAddressPortsAndCandidates| passes.
+  if (!(flags() & PORTALLOCATOR_DISABLE_ADAPTER_ENUMERATION)) {
+    network_thread_->PostDelayed(
+        RTC_FROM_HERE, kMaxWaitMsBeforeSignalingAnyAddressPortsAndCandidates,
+        this, MSG_SIGNAL_ANY_ADDRESS_PORTS);
+  }
 }
 
 void BasicPortAllocatorSession::OnNetworksChanged() {
@@ -812,7 +838,7 @@
   if (!ports_to_prune.empty()) {
     RTC_LOG(LS_INFO) << "Prune " << ports_to_prune.size()
                      << " ports because their networks were gone";
-    PrunePortsAndRemoveCandidates(ports_to_prune);
+    PrunePortsAndSignalCandidatesRemoval(ports_to_prune);
   }
 
   if (allocation_started_ && !IsStopped()) {
@@ -875,14 +901,14 @@
 void BasicPortAllocatorSession::OnAllocationSequenceObjectsCreated() {
   allocation_sequences_created_ = true;
   // Send candidate allocation complete signal if we have no sequences.
-  MaybeSignalCandidatesAllocationDone();
+  FireAllocationStatusSignalsIfNeeded();
 }
 
 void BasicPortAllocatorSession::OnCandidateReady(Port* port,
                                                  const Candidate& c) {
   RTC_DCHECK(rtc::Thread::Current() == network_thread_);
   PortData* data = FindPort(port);
-  RTC_DCHECK(data != NULL);
+  RTC_DCHECK(data != nullptr);
   RTC_LOG(LS_INFO) << port->ToString()
                    << ": Gathered candidate: " << c.ToSensitiveString();
   // Discarding any candidate signal if port allocation status is
@@ -911,23 +937,56 @@
     }
     // If the current port is not pruned yet, SignalPortReady.
     if (!data->pruned()) {
-      RTC_LOG(LS_INFO) << port->ToString() << ": Port ready.";
-      SignalPortReady(this, port);
       port->KeepAliveUntilPruned();
+      // We postpone the signaling of any address ports to when the candidates
+      // allocation is done or the candidate allocation process has start for
+      // more than kMaxWaitMsBeforeSignalingAnyAddressPortsAndCandidates, and
+      // we check whether they are redundant or not (in
+      // SignalAnyAddressPortsAndCandidatesReadyIfNotRedundant). Otherwise,
+      // connectivity checks will be sent from these possibly redundant ports,
+      // likely also resulting in "prflx" candidate pairs being created on the
+      // other side if not pruned in time. The signaling of any address ports
+      // that are not redundant happens in
+      // SignalAnyAddressPortsAndCandidatesReadyIfNotRedundant.
+      //
+      // If adapter enumeration is disabled, these "any" address ports
+      // are all we'll get, so we can signal them immediately.
+      //
+      // Same logic applies to candidates below.
+
+      if (!IsAnyAddressPort(port) ||
+          (flags() & PORTALLOCATOR_DISABLE_ADAPTER_ENUMERATION)) {
+        RTC_LOG(INFO) << port->ToString() << ": Port ready.";
+        SignalPortReady(this, port);
+        data->set_signaled();
+      }
     }
   }
 
   if (data->ready() && CheckCandidateFilter(c)) {
-    std::vector<Candidate> candidates;
-    candidates.push_back(SanitizeRelatedAddress(c));
-    SignalCandidatesReady(this, candidates);
+    // See comment above about why we delay signaling candidates from "any
+    // address" ports.
+    //
+    // For candidates gathered after the any address port is signaled, we will
+    // not perform the redundancy check anymore. Note that late candiates
+    // gathered from the any address port should be a srflx candidate from a
+    // late STUN binding response.
+    if (data->signaled()) {
+      std::vector<Candidate> candidates;
+      candidates.push_back(SanitizeRelatedAddress(c));
+      SignalCandidatesReady(this, candidates);
+    } else {
+      RTC_LOG(INFO) << "Candidate not signaled yet because it is from the "
+                       "any address port: "
+                    << c.ToSensitiveString();
+    }
   } else {
     RTC_LOG(LS_INFO) << "Discarding candidate because it doesn't match filter.";
   }
 
   // If we have pruned any port, maybe need to signal port allocation done.
   if (pruned) {
-    MaybeSignalCandidatesAllocationDone();
+    FireAllocationStatusSignalsIfNeeded();
   }
 }
 
@@ -961,7 +1020,7 @@
         ComparePort(data.port(), best_turn_port) < 0) {
       pruned = true;
       if (data.port() != newly_pairable_turn_port) {
-        // These ports will be pruned in PrunePortsAndRemoveCandidates.
+        // These ports will be pruned in PrunePortsAndSignalCandidatesRemoval.
         ports_to_prune.push_back(&data);
       } else {
         data.Prune();
@@ -972,7 +1031,7 @@
   if (!ports_to_prune.empty()) {
     RTC_LOG(LS_INFO) << "Prune " << ports_to_prune.size()
                      << " low-priority TURN ports";
-    PrunePortsAndRemoveCandidates(ports_to_prune);
+    PrunePortsAndSignalCandidatesRemoval(ports_to_prune);
   }
   return pruned;
 }
@@ -988,7 +1047,7 @@
   RTC_LOG(LS_INFO) << port->ToString()
                    << ": Port completed gathering candidates.";
   PortData* data = FindPort(port);
-  RTC_DCHECK(data != NULL);
+  RTC_DCHECK(data != nullptr);
 
   // Ignore any late signals.
   if (!data->inprogress()) {
@@ -998,7 +1057,7 @@
   // Moving to COMPLETE state.
   data->set_complete();
   // Send candidate allocation complete signal if this was the last port.
-  MaybeSignalCandidatesAllocationDone();
+  FireAllocationStatusSignalsIfNeeded();
 }
 
 void BasicPortAllocatorSession::OnPortError(Port* port) {
@@ -1006,7 +1065,7 @@
   RTC_LOG(LS_INFO) << port->ToString()
                    << ": Port encountered error while gathering candidates.";
   PortData* data = FindPort(port);
-  RTC_DCHECK(data != NULL);
+  RTC_DCHECK(data != nullptr);
   // We might have already given up on this port and stopped it.
   if (!data->inprogress()) {
     return;
@@ -1016,7 +1075,7 @@
   // But this signal itself is generic.
   data->set_error();
   // Send candidate allocation complete signal if this was the last port.
-  MaybeSignalCandidatesAllocationDone();
+  FireAllocationStatusSignalsIfNeeded();
 }
 
 bool BasicPortAllocatorSession::CheckCandidateFilter(const Candidate& c) const {
@@ -1060,24 +1119,34 @@
   // prevent even default IP addresses from leaking), we still don't want to
   // ping from them, even if device enumeration is disabled.  Thus, we check for
   // both device enumeration and host candidates being disabled.
-  bool network_enumeration_disabled = c.address().IsAnyIP();
+  bool candidate_has_any_address = c.address().IsAnyIP();
   bool can_ping_from_candidate =
       (port->SharedSocket() || c.protocol() == TCP_PROTOCOL_NAME);
   bool host_candidates_disabled = !(candidate_filter_ & CF_HOST);
 
   return candidate_signalable ||
-         (network_enumeration_disabled && can_ping_from_candidate &&
+         (candidate_has_any_address && can_ping_from_candidate &&
           !host_candidates_disabled);
 }
 
 void BasicPortAllocatorSession::OnPortAllocationComplete(
     AllocationSequence* seq) {
   // Send candidate allocation complete signal if all ports are done.
-  MaybeSignalCandidatesAllocationDone();
+  FireAllocationStatusSignalsIfNeeded();
 }
 
-void BasicPortAllocatorSession::MaybeSignalCandidatesAllocationDone() {
+void BasicPortAllocatorSession::FireAllocationStatusSignalsIfNeeded() {
   if (CandidatesAllocationDone()) {
+    // Now that allocation is done, we can surface any ports bound to the "any"
+    // address if they're not redundant (if they don't have the same address as
+    // a port bound to a specific interface). We don't surface them as soon as
+    // they're gathered because we may not know yet whether they're redundant.
+    //
+    // This also happens after a timeout of 2 seconds (see comment in
+    // DoAllocate); if allocation completes first we clear that timer since
+    // it's not needed.
+    network_thread_->Clear(this, MSG_SIGNAL_ANY_ADDRESS_PORTS);
+    SignalAnyAddressPortsAndCandidatesReadyIfNotRedundant();
     if (pooled()) {
       RTC_LOG(LS_INFO) << "All candidates gathered for pooled session.";
     } else {
@@ -1088,7 +1157,96 @@
   }
 }
 
-void BasicPortAllocatorSession::OnPortDestroyed(PortInterface* port) {
+// We detect the redundancy in any address ports as follows:
+//
+// 1. Delay the signaling of all any address ports and candidates gathered from
+// these ports, which happens in OnCandidateReady.
+//
+// 2. For all non-any address ports, collect the IPs of their candidates
+// (ignoring "active" TCP candidates, since no sockets are created for them
+// until a connection is made and there's no guarantee they'll work).
+//
+// 3. For each any address port, compare their candidates to the existing IPs
+// collected from step 2, and this port can be signaled if it has candidates
+// with unseen IPs.
+void BasicPortAllocatorSession::
+    SignalAnyAddressPortsAndCandidatesReadyIfNotRedundant() {
+  // Note that this is called either when allocation completes, or after a
+  // timeout, so some ports may still be waiting for STUN transactions to
+  // finish.
+  //
+  // First, get a list of all "any address" ports that have not yet been
+  // signaled, and a list of candidate IP addresses from all other ports.
+  std::vector<PortData*> maybe_signalable_any_address_ports;
+  std::set<rtc::IPAddress> ips_from_non_any_address_ports;
+  for (PortData& port_data : ports_) {
+    if (!port_data.ready()) {
+      continue;
+    }
+    if (IsAnyAddressPort(port_data.port())) {
+      if (!port_data.signaled()) {
+        maybe_signalable_any_address_ports.push_back(&port_data);
+      }
+    } else {
+      for (const Candidate& c : port_data.port()->Candidates()) {
+        // If the port of the candidate is |DISCARD_PORT| (9), this is an
+        // "active" TCP candidate and it doesn't mean we actually bound a
+        // socket to this address, so ignore it.
+        if (c.address().port() != DISCARD_PORT) {
+          ips_from_non_any_address_ports.insert(c.address().ipaddr());
+        }
+      }
+    }
+  }
+  // Now signal "any" address ports that have a unique address, and prune any
+  // that don't.
+  std::vector<PortData*> signalable_any_address_ports;
+  std::vector<PortData*> prunable_any_address_ports;
+  std::vector<Candidate> signalable_candidates_from_any_address_ports;
+  for (PortData* port_data : maybe_signalable_any_address_ports) {
+    bool port_signalable = false;
+    for (const Candidate& c : port_data->port()->Candidates()) {
+      if (!CandidatePairable(c, port_data->port()) ||
+          ips_from_non_any_address_ports.count(c.address().ipaddr())) {
+        continue;
+      }
+      // Even when a port is bound to the "any" address, it should normally
+      // still have an associated IP (determined by calling "connect" and then
+      // "getsockaddr"). Though sometimes even this fails (meaning |is_any_ip|
+      // will be true), and thus we have no way of knowing whether the port is
+      // redundant or not. In that case, we'll use the port if we have
+      // *no* ports bound to specific addresses. This is needed for corner
+      // cases such as bugs.webrtc.org/7798.
+      bool is_any_ip = rtc::IPIsAny(c.address().ipaddr());
+      if (is_any_ip && !ips_from_non_any_address_ports.empty()) {
+        continue;
+      }
+      port_signalable = true;
+      // Still need to check the candidiate filter and sanitize the related
+      // address before signaling the candidate itself.
+      if (CheckCandidateFilter(c)) {
+        signalable_candidates_from_any_address_ports.push_back(
+            SanitizeRelatedAddress(c));
+      }
+    }
+    if (port_signalable) {
+      signalable_any_address_ports.push_back(port_data);
+    } else {
+      prunable_any_address_ports.push_back(port_data);
+    }
+  }
+  PrunePorts(prunable_any_address_ports);
+  for (PortData* port_data : signalable_any_address_ports) {
+    RTC_LOG(INFO) << port_data->port()->ToString() << ": Port ready.";
+    SignalPortReady(this, port_data->port());
+    port_data->set_signaled();
+  }
+  RTC_LOG(INFO) << "Signaling candidates from the any address ports.";
+  SignalCandidatesReady(this, signalable_candidates_from_any_address_ports);
+}
+
+void BasicPortAllocatorSession::OnPortDestroyed(
+    PortInterface* port) {
   RTC_DCHECK(rtc::Thread::Current() == network_thread_);
   for (std::vector<PortData>::iterator iter = ports_.begin();
        iter != ports_.end(); ++iter) {
@@ -1110,7 +1268,7 @@
       return &*it;
     }
   }
-  return NULL;
+  return nullptr;
 }
 
 std::vector<BasicPortAllocatorSession::PortData*>
@@ -1127,7 +1285,7 @@
   return unpruned_ports;
 }
 
-void BasicPortAllocatorSession::PrunePortsAndRemoveCandidates(
+std::vector<Candidate> BasicPortAllocatorSession::PrunePorts(
     const std::vector<PortData*>& port_data_list) {
   std::vector<PortInterface*> pruned_ports;
   std::vector<Candidate> removed_candidates;
@@ -1145,6 +1303,12 @@
   if (!pruned_ports.empty()) {
     SignalPortsPruned(this, pruned_ports);
   }
+  return removed_candidates;
+}
+
+void BasicPortAllocatorSession::PrunePortsAndSignalCandidatesRemoval(
+    const std::vector<PortData*>& port_data_list) {
+  std::vector<Candidate> removed_candidates = PrunePorts(port_data_list);
   if (!removed_candidates.empty()) {
     RTC_LOG(LS_INFO) << "Removed " << removed_candidates.size()
                      << " candidates";
@@ -1164,7 +1328,7 @@
       state_(kInit),
       flags_(flags),
       udp_socket_(),
-      udp_port_(NULL),
+      udp_port_(nullptr),
       phase_(0) {}
 
 void AllocationSequence::Init() {
@@ -1176,13 +1340,13 @@
       udp_socket_->SignalReadPacket.connect(this,
                                             &AllocationSequence::OnReadPacket);
     }
-    // Continuing if |udp_socket_| is NULL, as local TCP and RelayPort using TCP
-    // are next available options to setup a communication channel.
+    // Continuing if |udp_socket_| is null, as local TCP and RelayPort using
+    // TCP are next available options to setup a communication channel.
   }
 }
 
 void AllocationSequence::Clear() {
-  udp_port_ = NULL;
+  udp_port_ = nullptr;
   relay_ports_.clear();
 }
 
@@ -1319,7 +1483,7 @@
 
   // TODO(mallinath) - Remove UDPPort creating socket after shared socket
   // is enabled completely.
-  UDPPort* port = NULL;
+  UDPPort* port = nullptr;
   bool emit_local_candidate_for_anyaddress =
       !IsFlagSet(PORTALLOCATOR_DISABLE_DEFAULT_LOCAL_CANDIDATE);
   if (IsFlagSet(PORTALLOCATOR_ENABLE_SHARED_SOCKET) && udp_socket_) {
@@ -1527,7 +1691,7 @@
         continue;
       }
     }
-    RTC_DCHECK(port != NULL);
+    RTC_DCHECK(port != nullptr);
     session_->AddAllocatedPort(port.release(), this, true);
   }
 }
@@ -1573,7 +1737,7 @@
 
 void AllocationSequence::OnPortDestroyed(PortInterface* port) {
   if (udp_port_ == port) {
-    udp_port_ = NULL;
+    udp_port_ = nullptr;
     return;
   }
 
diff --git a/p2p/client/basicportallocator.h b/p2p/client/basicportallocator.h
index 07bf2f9..2105172 100644
--- a/p2p/client/basicportallocator.h
+++ b/p2p/client/basicportallocator.h
@@ -168,6 +168,10 @@
     bool error() const { return state_ == STATE_ERROR; }
     bool pruned() const { return state_ == STATE_PRUNED; }
     bool inprogress() const { return state_ == STATE_INPROGRESS; }
+    // True if this port has been fired in SignalPortReady. This may be false
+    // even if ready() is true if the port was bound to the "any" address; see
+    // comment above SignalAnyAddressPortsAndCandidatesReadyIfNotRedundant.
+    bool signaled() const { return signaled_; }
     // Returns true if this port is ready to be used.
     bool ready() const {
       return has_pairable_candidate_ && state_ != STATE_ERROR &&
@@ -191,6 +195,7 @@
       RTC_DCHECK(state_ == STATE_INPROGRESS);
       state_ = STATE_ERROR;
     }
+    void set_signaled() { signaled_ = true; }
 
    private:
     enum State {
@@ -203,6 +208,7 @@
     Port* port_ = nullptr;
     AllocationSequence* sequence_ = nullptr;
     bool has_pairable_candidate_ = false;
+    bool signaled_ = false;
     State state_ = STATE_INPROGRESS;
   };
 
@@ -224,7 +230,6 @@
   void OnPortError(Port* port);
   void OnProtocolEnabled(AllocationSequence* seq, ProtocolType proto);
   void OnPortDestroyed(PortInterface* port);
-  void MaybeSignalCandidatesAllocationDone();
   void OnPortAllocationComplete(AllocationSequence* seq);
   PortData* FindPort(Port* port);
   std::vector<rtc::Network*> GetNetworks();
@@ -241,9 +246,13 @@
 
   std::vector<PortData*> GetUnprunedPorts(
       const std::vector<rtc::Network*>& networks);
+  // Prunes ports and removes candidates gathered from these ports locally. The
+  // list of the removed candidates are returned.
+  std::vector<Candidate> PrunePorts(
+      const std::vector<PortData*>& port_data_list);
   // Prunes ports and signal the remote side to remove the candidates that
   // were previously signaled from these ports.
-  void PrunePortsAndRemoveCandidates(
+  void PrunePortsAndSignalCandidatesRemoval(
       const std::vector<PortData*>& port_data_list);
   // Gets filtered and sanitized candidates generated from a port and
   // append to |candidates|.
@@ -252,6 +261,12 @@
   Port* GetBestTurnPortForNetwork(const std::string& network_name) const;
   // Returns true if at least one TURN port is pruned.
   bool PruneTurnPorts(Port* newly_pairable_turn_port);
+  // Fires signals related to aggregate status update in the allocation,
+  // including candidates allocation done, and any address ports and their
+  // candidates ready.
+  void FireAllocationStatusSignalsIfNeeded();
+  // TODO(qingsi): Rename "any address" to "wildcard address" in p2p/.
+  void SignalAnyAddressPortsAndCandidatesReadyIfNotRedundant();
 
   BasicPortAllocator* allocator_;
   rtc::Thread* network_thread_;
diff --git a/p2p/client/basicportallocator_unittest.cc b/p2p/client/basicportallocator_unittest.cc
index 42699a9..d995eb1 100644
--- a/p2p/client/basicportallocator_unittest.cc
+++ b/p2p/client/basicportallocator_unittest.cc
@@ -1148,15 +1148,20 @@
   allocator_->set_step_delay(kDefaultStepDelay);
   ASSERT_TRUE(CreateSession(ICE_CANDIDATE_COMPONENT_RTP));
   session_->StartGettingPorts();
+  // Host and STUN candidates from kClientAddr.
   ASSERT_EQ_SIMULATED_WAIT(2U, candidates_.size(), 1000, fake_clock);
+  // UDP and STUN ports on kClientAddr.
   EXPECT_EQ(2U, ports_.size());
+  // Host, STUN and relay candidates from kClientAddr.
   ASSERT_EQ_SIMULATED_WAIT(6U, candidates_.size(), 2000, fake_clock);
+  // UDP, STUN and relay ports on kClientAddr.
   EXPECT_EQ(3U, ports_.size());
   EXPECT_TRUE(HasCandidate(candidates_, "relay", "udp", kRelayUdpIntAddr));
   EXPECT_TRUE(HasCandidate(candidates_, "relay", "udp", kRelayUdpExtAddr));
   EXPECT_TRUE(HasCandidate(candidates_, "relay", "tcp", kRelayTcpIntAddr));
   EXPECT_TRUE(
       HasCandidate(candidates_, "relay", "ssltcp", kRelaySslTcpIntAddr));
+  // One more TCP candidate from kClientAddr.
   ASSERT_EQ_SIMULATED_WAIT(7U, candidates_.size(), 1500, fake_clock);
   EXPECT_TRUE(HasCandidate(candidates_, "local", "tcp", kClientAddr));
   EXPECT_EQ(4U, ports_.size());
@@ -1466,17 +1471,20 @@
 // Testing STUN timeout.
 TEST_F(BasicPortAllocatorTest, TestGetAllPortsNoUdpAllowed) {
   fss_->AddRule(false, rtc::FP_UDP, rtc::FD_ANY, kClientAddr);
+  fss_->AddRule(false, rtc::FP_UDP, rtc::FD_ANY, kAnyAddr);
   AddInterface(kClientAddr);
   ASSERT_TRUE(CreateSession(ICE_CANDIDATE_COMPONENT_RTP));
   session_->StartGettingPorts();
   EXPECT_EQ_SIMULATED_WAIT(2U, candidates_.size(), kDefaultAllocationTimeout,
                            fake_clock);
+  // UDP and TCP ports on kClientAddr.
   EXPECT_EQ(2U, ports_.size());
   EXPECT_TRUE(HasCandidate(candidates_, "local", "udp", kClientAddr));
   EXPECT_TRUE(HasCandidate(candidates_, "local", "tcp", kClientAddr));
   // RelayPort connection timeout is 3sec. TCP connection with RelayServer
   // will be tried after about 3 seconds.
   EXPECT_EQ_SIMULATED_WAIT(6U, candidates_.size(), 3500, fake_clock);
+  // UDP, TCP and relay ports on kClientAddr.
   EXPECT_EQ(3U, ports_.size());
   EXPECT_TRUE(HasCandidate(candidates_, "relay", "udp", kRelayUdpIntAddr));
   EXPECT_TRUE(HasCandidate(candidates_, "relay", "tcp", kRelayTcpIntAddr));
@@ -1983,12 +1991,14 @@
                         PORTALLOCATOR_DISABLE_TCP |
                         PORTALLOCATOR_ENABLE_SHARED_SOCKET);
   fss_->AddRule(false, rtc::FP_UDP, rtc::FD_ANY, kClientAddr);
+  fss_->AddRule(false, rtc::FP_UDP, rtc::FD_ANY, kAnyAddr);
   AddInterface(kClientAddr);
   ASSERT_TRUE(CreateSession(ICE_CANDIDATE_COMPONENT_RTP));
   session_->StartGettingPorts();
-  ASSERT_EQ_SIMULATED_WAIT(1U, ports_.size(), kDefaultAllocationTimeout,
+  ASSERT_EQ_SIMULATED_WAIT(1U, candidates_.size(), kDefaultAllocationTimeout,
                            fake_clock);
-  EXPECT_EQ(1U, candidates_.size());
+  // UDP ports on kClientAddr.
+  EXPECT_EQ(1U, ports_.size());
   EXPECT_TRUE(HasCandidate(candidates_, "local", "udp", kClientAddr));
   // STUN timeout is 9.5sec. We need to wait to get candidate done signal.
   EXPECT_TRUE_SIMULATED_WAIT(candidate_allocation_done_, kStunTimeoutMs,
@@ -1996,6 +2006,137 @@
   EXPECT_EQ(1U, candidates_.size());
 }
 
+// Test that any address ports that are redundant do not surface.
+TEST_F(BasicPortAllocatorTest, RedundantAnyAddressPortsDoNotSurface) {
+  allocator().set_flags(allocator().flags() | PORTALLOCATOR_DISABLE_RELAY |
+                        PORTALLOCATOR_DISABLE_TCP |
+                        PORTALLOCATOR_ENABLE_SHARED_SOCKET);
+  AddInterface(kClientAddr);
+  // The any address ports will be duplicates of kClientAddr.
+  vss_->SetAlternativeLocalAddress(kAnyAddr.ipaddr(), kClientAddr.ipaddr());
+  ASSERT_TRUE(CreateSession(ICE_CANDIDATE_COMPONENT_RTP));
+  session_->StartGettingPorts();
+  EXPECT_TRUE_SIMULATED_WAIT(candidate_allocation_done_, kStunTimeoutMs,
+                             fake_clock);
+  EXPECT_EQ(1U, ports_.size());
+  EXPECT_EQ(1, CountPorts(ports_, "local", PROTO_UDP, kClientAddr));
+}
+
+// Test that candidates from the any address ports are not pruned if the
+// explicit binding to enumerated networks fails.
+TEST_F(BasicPortAllocatorTest,
+       CandidatesFromAnyAddressPortsCanSurfaceWhenExplicitBindingFails) {
+  allocator().set_flags(allocator().flags() | PORTALLOCATOR_DISABLE_RELAY |
+                        PORTALLOCATOR_DISABLE_TCP |
+                        PORTALLOCATOR_ENABLE_SHARED_SOCKET);
+  AddInterface(kClientAddr);
+  fss_->SetUnbindableIps({kClientAddr.ipaddr()});
+  // The any address ports will be duplicates of kClientAddr, but the explict
+  // binding will fail.
+  vss_->SetAlternativeLocalAddress(kAnyAddr.ipaddr(), kClientAddr.ipaddr());
+  ASSERT_TRUE(CreateSession(ICE_CANDIDATE_COMPONENT_RTP));
+  session_->StartGettingPorts();
+  EXPECT_TRUE_SIMULATED_WAIT(candidate_allocation_done_, kStunTimeoutMs,
+                             fake_clock);
+  EXPECT_EQ(1, CountPorts(ports_, "local", PROTO_UDP, kAnyAddr));
+  EXPECT_EQ(1U, candidates_.size());
+  EXPECT_TRUE(HasCandidate(candidates_, "local", "udp", kClientAddr));
+}
+
+// Test that for an endpoint whose network enumeration only reveals one address
+// (kClientAddr), it can observe a different address when binding to the "any"
+// address. BasicPortAllocator should detect this and surface candidates for
+// each address.
+TEST_F(BasicPortAllocatorTest,
+       CandidatesFromAnyAddressPortsCanSurfaceIfNotRedundant) {
+  allocator().set_flags(allocator().flags() | PORTALLOCATOR_DISABLE_RELAY |
+                        PORTALLOCATOR_DISABLE_TCP |
+                        PORTALLOCATOR_ENABLE_SHARED_SOCKET);
+  AddInterface(kClientAddr);
+  // When bound to the any address, the port allocator should discover the
+  // alternative local address.
+  vss_->SetAlternativeLocalAddress(kAnyAddr.ipaddr(), kClientAddr2.ipaddr());
+  ASSERT_TRUE(CreateSession(ICE_CANDIDATE_COMPONENT_RTP));
+  session_->StartGettingPorts();
+  EXPECT_TRUE_SIMULATED_WAIT(candidate_allocation_done_, kStunTimeoutMs,
+                             fake_clock);
+  EXPECT_EQ(1, CountPorts(ports_, "local", PROTO_UDP, kAnyAddr));
+  EXPECT_EQ(2U, candidates_.size());
+  EXPECT_TRUE(HasCandidate(candidates_, "local", "udp", kClientAddr));
+  EXPECT_TRUE(HasCandidate(candidates_, "local", "udp", kClientAddr2));
+}
+
+// Test that any address ports and their candidates are eventually signaled
+// after the maximum wait interval for the completion of candidate allocation,
+// when the any address ports and candidates are not redundant.
+TEST_F(BasicPortAllocatorTest,
+       GetAnyAddressPortsAfterMaximumWaitForCandidateAllocationDone) {
+  ResetWithTurnServersNoNat(kTurnUdpIntAddr, rtc::SocketAddress());
+  AddInterface(kClientAddr);
+  vss_->SetAlternativeLocalAddress(kAnyAddr.ipaddr(), kClientAddr2.ipaddr());
+  // STUN binding request and TURN allocation request will time out.
+  fss_->AddRule(false, rtc::FP_UDP, rtc::FD_ANY, kClientAddr);
+  ASSERT_TRUE(CreateSession(ICE_CANDIDATE_COMPONENT_RTP));
+  session_->StartGettingPorts();
+  SIMULATED_WAIT(false, kMaxWaitMsBeforeSignalingAnyAddressPortsAndCandidates,
+                 fake_clock);
+  EXPECT_EQ(2U, candidates_.size());
+  EXPECT_TRUE(HasCandidate(candidates_, "local", "udp", kClientAddr));
+  EXPECT_TRUE(HasCandidate(candidates_, "local", "tcp", kClientAddr));
+  SIMULATED_WAIT(false, 1, fake_clock);
+  EXPECT_FALSE(candidate_allocation_done_);
+  // Candidates from the any address ports.
+  EXPECT_EQ(6U, candidates_.size());
+  EXPECT_TRUE(HasCandidate(candidates_, "local", "udp", kClientAddr2));
+  EXPECT_TRUE(HasCandidate(candidates_, "stun", "udp", kClientAddr2));
+  EXPECT_TRUE(HasCandidate(candidates_, "relay", "udp", kTurnUdpExtAddr));
+  EXPECT_TRUE(HasCandidate(candidates_, "local", "tcp", kClientAddr2));
+}
+
+// Test that the TCP port with the wildcard address is signaled if no ports are
+// bound to enuemrated networks.
+TEST_F(BasicPortAllocatorTest,
+       GetAnyAddressTcpPortWhenNoPortsBoundToEnumeratedNetworks) {
+  ResetWithTurnServersNoNat(kTurnUdpIntAddr, rtc::SocketAddress());
+  AddInterface(kClientAddr);
+  fss_->SetUnbindableIps({kClientAddr.ipaddr()});
+  ASSERT_TRUE(CreateSession(ICE_CANDIDATE_COMPONENT_RTP));
+  session_->StartGettingPorts();
+  SIMULATED_WAIT(false,
+                 kMaxWaitMsBeforeSignalingAnyAddressPortsAndCandidates + 1,
+                 fake_clock);
+  EXPECT_EQ(1, CountPorts(ports_, "local", PROTO_TCP, kAnyAddr));
+}
+
+// Test that the STUN candidate from the any address port can still surface, if
+// it is gathered after this port is signaled, .
+TEST_F(BasicPortAllocatorTest,
+       StunCandidateFromAnyAddressPortsGatheredLateCanBeSignaled) {
+  ResetWithTurnServersNoNat(kTurnUdpIntAddr, rtc::SocketAddress());
+  AddInterface(kClientAddr);
+  vss_->SetAlternativeLocalAddress(kAnyAddr.ipaddr(), kClientAddr2.ipaddr());
+  fss_->AddRule(false, rtc::FP_UDP, rtc::FD_ANY, kClientAddr);
+  fss_->AddRule(false, rtc::FP_UDP, rtc::FD_ANY, kClientAddr2);
+  ASSERT_TRUE(CreateSession(ICE_CANDIDATE_COMPONENT_RTP));
+  session_->StartGettingPorts();
+  SIMULATED_WAIT(false,
+                 kMaxWaitMsBeforeSignalingAnyAddressPortsAndCandidates + 1000,
+                 fake_clock);
+  EXPECT_FALSE(candidate_allocation_done_);
+  EXPECT_EQ(4U, candidates_.size());
+  EXPECT_TRUE(HasCandidate(candidates_, "local", "udp", kClientAddr));
+  EXPECT_TRUE(HasCandidate(candidates_, "local", "tcp", kClientAddr));
+  EXPECT_TRUE(HasCandidate(candidates_, "local", "udp", kClientAddr2));
+  EXPECT_TRUE(HasCandidate(candidates_, "local", "tcp", kClientAddr2));
+  fss_->ClearRules();
+  EXPECT_TRUE_SIMULATED_WAIT(candidate_allocation_done_,
+                             kDefaultAllocationTimeout, fake_clock);
+  EXPECT_EQ(7U, candidates_.size());
+  EXPECT_TRUE(HasCandidate(candidates_, "stun", "udp", kClientAddr));
+  EXPECT_TRUE(HasCandidate(candidates_, "stun", "udp", kClientAddr2));
+  EXPECT_TRUE(HasCandidate(candidates_, "relay", "udp", kTurnUdpExtAddr));
+}
+
 // Test that when the NetworkManager doesn't have permission to enumerate
 // adapters, the PORTALLOCATOR_DISABLE_ADAPTER_ENUMERATION is specified
 // automatically.