When doing continual gathering, remove the local ports when a corresponding network is dropped.

BUG=

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

Cr-Commit-Position: refs/heads/master@{#11660}
diff --git a/webrtc/base/network.cc b/webrtc/base/network.cc
index 6b04f89..4f3b919 100644
--- a/webrtc/base/network.cc
+++ b/webrtc/base/network.cc
@@ -317,10 +317,11 @@
     networks_ = merged_list;
     // Reset the active states of all networks.
     for (const auto& kv : networks_map_) {
-      kv.second->set_active(false);
-    }
-    for (Network* network : networks_) {
-      network->set_active(true);
+      Network* network = kv.second;
+      // If |network| is in the newly generated |networks_|, it is active.
+      bool found = std::find(networks_.begin(), networks_.end(), network) !=
+                   networks_.end();
+      network->set_active(found);
     }
     std::sort(networks_.begin(), networks_.end(), SortNetworks);
     // Now network interfaces are sorted, we should set the preference value
diff --git a/webrtc/base/network.h b/webrtc/base/network.h
index 10ce6f0..a81bcab 100644
--- a/webrtc/base/network.h
+++ b/webrtc/base/network.h
@@ -265,6 +265,8 @@
           AdapterType type);
   ~Network();
 
+  sigslot::signal1<const Network*> SignalInactive;
+
   const DefaultLocalAddressProvider* default_local_address_provider() {
     return default_local_address_provider_;
   }
@@ -342,7 +344,15 @@
   // we do not remove it (because it may be used elsewhere). Instead, we mark
   // it inactive, so that we can detect network changes properly.
   bool active() const { return active_; }
-  void set_active(bool active) { active_ = active; }
+  void set_active(bool active) {
+    if (active_ == active) {
+      return;
+    }
+    active_ = active;
+    if (!active) {
+      SignalInactive(this);
+    }
+  }
 
   // Debugging description of this network
   std::string ToString() const;
diff --git a/webrtc/base/network_unittest.cc b/webrtc/base/network_unittest.cc
index 0f7d6db..7ad45a3 100644
--- a/webrtc/base/network_unittest.cc
+++ b/webrtc/base/network_unittest.cc
@@ -58,6 +58,16 @@
     callback_called_ = true;
   }
 
+  void listenToNetworkInactive(BasicNetworkManager& network_manager) {
+    BasicNetworkManager::NetworkList networks;
+    network_manager.GetNetworks(&networks);
+    for (Network* network : networks) {
+      network->SignalInactive.connect(this, &NetworkTest::OnNetworkInactive);
+    }
+  }
+
+  void OnNetworkInactive(const Network* network) { num_networks_inactive_++; }
+
   NetworkManager::Stats MergeNetworkList(
       BasicNetworkManager& network_manager,
       const NetworkManager::NetworkList& list,
@@ -147,6 +157,8 @@
 
  protected:
   bool callback_called_;
+  // Number of networks that become inactive.
+  int num_networks_inactive_ = 0;
 };
 
 class TestBasicNetworkManager : public BasicNetworkManager {
@@ -280,6 +292,7 @@
   EXPECT_TRUE(changed);
   EXPECT_EQ(stats.ipv6_network_count, 0);
   EXPECT_EQ(stats.ipv4_network_count, 1);
+  listenToNetworkInactive(manager);
   list.clear();
 
   manager.GetNetworks(&list);
@@ -294,7 +307,9 @@
   EXPECT_TRUE(changed);
   EXPECT_EQ(stats.ipv6_network_count, 0);
   EXPECT_EQ(stats.ipv4_network_count, 1);
+  EXPECT_EQ(1, num_networks_inactive_);
   list.clear();
+  num_networks_inactive_ = 0;
 
   manager.GetNetworks(&list);
   EXPECT_EQ(1U, list.size());
@@ -309,6 +324,7 @@
   EXPECT_TRUE(changed);
   EXPECT_EQ(stats.ipv6_network_count, 0);
   EXPECT_EQ(stats.ipv4_network_count, 2);
+  EXPECT_EQ(0, num_networks_inactive_);
   list.clear();
 
   // Verify that we get previous instances of Network objects.
@@ -326,6 +342,7 @@
   EXPECT_FALSE(changed);
   EXPECT_EQ(stats.ipv6_network_count, 0);
   EXPECT_EQ(stats.ipv4_network_count, 2);
+  EXPECT_EQ(0, num_networks_inactive_);
   list.clear();
 
   // Verify that we get previous instances of Network objects.
diff --git a/webrtc/p2p/base/p2ptransportchannel.cc b/webrtc/p2p/base/p2ptransportchannel.cc
index 87a50bc..74f1392 100644
--- a/webrtc/p2p/base/p2ptransportchannel.cc
+++ b/webrtc/p2p/base/p2ptransportchannel.cc
@@ -12,13 +12,15 @@
 
 #include <algorithm>
 #include <set>
-#include "webrtc/p2p/base/common.h"
-#include "webrtc/p2p/base/relayport.h"  // For RELAY_PORT_TYPE.
-#include "webrtc/p2p/base/stunport.h"  // For STUN_PORT_TYPE.
+
 #include "webrtc/base/common.h"
 #include "webrtc/base/crc32.h"
 #include "webrtc/base/logging.h"
 #include "webrtc/base/stringencode.h"
+#include "webrtc/p2p/base/candidate.h"
+#include "webrtc/p2p/base/common.h"
+#include "webrtc/p2p/base/relayport.h"  // For RELAY_PORT_TYPE.
+#include "webrtc/p2p/base/stunport.h"   // For STUN_PORT_TYPE.
 #include "webrtc/system_wrappers/include/field_trial.h"
 
 namespace {
@@ -464,6 +466,8 @@
   port->SignalUnknownAddress.connect(
       this, &P2PTransportChannel::OnUnknownAddress);
   port->SignalDestroyed.connect(this, &P2PTransportChannel::OnPortDestroyed);
+  port->SignalNetworkInactive.connect(
+      this, &P2PTransportChannel::OnPortNetworkInactive);
   port->SignalRoleConflict.connect(
       this, &P2PTransportChannel::OnRoleConflict);
   port->SignalSentPacket.connect(this, &P2PTransportChannel::OnSentPacket);
@@ -1415,6 +1419,23 @@
             << static_cast<int>(ports_.size()) << " remaining";
 }
 
+void P2PTransportChannel::OnPortNetworkInactive(PortInterface* port) {
+  // If it does not gather continually, the port will be removed from the list
+  // when ICE restarts.
+  if (!gather_continually_) {
+    return;
+  }
+  auto it = std::find(ports_.begin(), ports_.end(), port);
+  // Don't need to do anything if the port has been deleted from the port list.
+  if (it == ports_.end()) {
+    return;
+  }
+  ports_.erase(it);
+  LOG(INFO) << "Removed port due to inactive networks: " << ports_.size()
+            << " remaining";
+  // TODO(honghaiz): Signal candidate removals to the remote side.
+}
+
 // We data is available, let listeners know
 void P2PTransportChannel::OnReadPacket(Connection* connection,
                                        const char* data,
diff --git a/webrtc/p2p/base/p2ptransportchannel.h b/webrtc/p2p/base/p2ptransportchannel.h
index f2e9315..fde0026 100644
--- a/webrtc/p2p/base/p2ptransportchannel.h
+++ b/webrtc/p2p/base/p2ptransportchannel.h
@@ -227,6 +227,7 @@
                         const std::string& remote_username,
                         bool port_muxed);
   void OnPortDestroyed(PortInterface* port);
+  void OnPortNetworkInactive(PortInterface* port);
   void OnRoleConflict(PortInterface* port);
 
   void OnConnectionStateChange(Connection* connection);
diff --git a/webrtc/p2p/base/p2ptransportchannel_unittest.cc b/webrtc/p2p/base/p2ptransportchannel_unittest.cc
index ab17cfb..38f12fa 100644
--- a/webrtc/p2p/base/p2ptransportchannel_unittest.cc
+++ b/webrtc/p2p/base/p2ptransportchannel_unittest.cc
@@ -1770,6 +1770,37 @@
                  ep2_ch1()->GetState(), 1000);
 }
 
+// Tests that when a network interface becomes inactive, the ports associated
+// with that network will be removed from the port list of the channel if
+// and only if Continual Gathering is enabled.
+TEST_F(P2PTransportChannelMultihomedTest, TestNetworkBecomesInactive) {
+  AddAddress(0, kPublicAddrs[0]);
+  AddAddress(1, kPublicAddrs[1]);
+  // Create channels and let them go writable, as usual.
+  CreateChannels(1);
+  ep1_ch1()->SetIceConfig(CreateIceConfig(2000, true));
+  ep2_ch1()->SetIceConfig(CreateIceConfig(2000, false));
+
+  SetAllocatorFlags(0, kOnlyLocalPorts);
+  SetAllocatorFlags(1, kOnlyLocalPorts);
+  EXPECT_TRUE_WAIT_MARGIN(ep1_ch1()->receiving() && ep1_ch1()->writable() &&
+                              ep2_ch1()->receiving() && ep2_ch1()->writable(),
+                          1000, 1000);
+  // More than one port has been created.
+  EXPECT_LE(1U, ep1_ch1()->ports().size());
+  // Endpoint 1 enabled continual gathering; the port will be removed
+  // when the interface is removed.
+  RemoveAddress(0, kPublicAddrs[0]);
+  EXPECT_EQ(0U, ep1_ch1()->ports().size());
+
+  size_t num_ports = ep2_ch1()->ports().size();
+  EXPECT_LE(1U, num_ports);
+  // Endpoint 2 did not enable continual gathering; the port will not be removed
+  // when the interface is removed.
+  RemoveAddress(1, kPublicAddrs[1]);
+  EXPECT_EQ(num_ports, ep2_ch1()->ports().size());
+}
+
 /*
 
 TODO(pthatcher): Once have a way to handle network interfaces changes
diff --git a/webrtc/p2p/base/port.cc b/webrtc/p2p/base/port.cc
index 4d95279..ed26fe4 100644
--- a/webrtc/p2p/base/port.cc
+++ b/webrtc/p2p/base/port.cc
@@ -20,6 +20,7 @@
 #include "webrtc/base/helpers.h"
 #include "webrtc/base/logging.h"
 #include "webrtc/base/messagedigest.h"
+#include "webrtc/base/network.h"
 #include "webrtc/base/scoped_ptr.h"
 #include "webrtc/base/stringencode.h"
 #include "webrtc/base/stringutils.h"
@@ -195,6 +196,7 @@
     ice_username_fragment_ = rtc::CreateRandomString(ICE_UFRAG_LENGTH);
     password_ = rtc::CreateRandomString(ICE_PWD_LENGTH);
   }
+  network_->SignalInactive.connect(this, &Port::OnNetworkInactive);
   // TODO(honghaiz): Make it configurable from user setting.
   network_cost_ =
       (network_->type() == rtc::ADAPTER_TYPE_CELLULAR) ? kMaxNetworkCost : 0;
@@ -633,11 +635,16 @@
   }
 }
 
+void Port::OnNetworkInactive(const rtc::Network* network) {
+  ASSERT(network == network_);
+  SignalNetworkInactive(this);
+}
+
 std::string Port::ToString() const {
   std::stringstream ss;
-  ss << "Port[" << content_name_ << ":" << component_
-     << ":" << generation_ << ":" << type_
-     << ":" << network_->ToString() << "]";
+  ss << "Port[" << std::hex << this << std::dec << ":" << content_name_ << ":"
+     << component_ << ":" << generation_ << ":" << type_ << ":"
+     << network_->ToString() << "]";
   return ss.str();
 }
 
diff --git a/webrtc/p2p/base/port.h b/webrtc/p2p/base/port.h
index 95abe86..75b786f 100644
--- a/webrtc/p2p/base/port.h
+++ b/webrtc/p2p/base/port.h
@@ -358,6 +358,8 @@
     return ice_role_ == ICEROLE_CONTROLLED && connections_.empty();
   }
 
+  void OnNetworkInactive(const rtc::Network* network);
+
   rtc::Thread* thread_;
   rtc::PacketSocketFactory* factory_;
   std::string type_;
diff --git a/webrtc/p2p/base/portinterface.h b/webrtc/p2p/base/portinterface.h
index e83879f..e738619 100644
--- a/webrtc/p2p/base/portinterface.h
+++ b/webrtc/p2p/base/portinterface.h
@@ -104,6 +104,9 @@
   // any usefulness.
   sigslot::signal1<PortInterface*> SignalDestroyed;
 
+  // Signaled when the network used by this port becomes inactive.
+  sigslot::signal1<PortInterface*> SignalNetworkInactive;
+
   // Signaled when Port discovers ice role conflict with the peer.
   sigslot::signal1<PortInterface*> SignalRoleConflict;