Add 16-bit network id to the candidate signaling.
Also include that in the stun-ping request as part of the
network-info attribute.
Change the network cost to be 16 bits.

BUG=

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

Cr-Commit-Position: refs/heads/master@{#12110}
diff --git a/webrtc/api/webrtcsdp.cc b/webrtc/api/webrtcsdp.cc
index 4a296d9..93d4acc 100644
--- a/webrtc/api/webrtcsdp.cc
+++ b/webrtc/api/webrtcsdp.cc
@@ -127,6 +127,7 @@
 static const char kAttributeCandidateUfrag[] = "ufrag";
 static const char kAttributeCandidatePwd[] = "pwd";
 static const char kAttributeCandidateGeneration[] = "generation";
+static const char kAttributeCandidateNetworkId[] = "network-id";
 static const char kAttributeCandidateNetworkCost[] = "network-cost";
 static const char kAttributeFingerprint[] = "fingerprint";
 static const char kAttributeSetup[] = "setup";
@@ -1092,7 +1093,8 @@
   std::string username;
   std::string password;
   uint32_t generation = 0;
-  uint32_t network_cost = 0;
+  uint16_t network_id = 0;
+  uint16_t network_cost = 0;
   for (size_t i = current_position; i + 1 < fields.size(); ++i) {
     // RFC 5245
     // *(SP extension-att-name SP extension-att-value)
@@ -1104,10 +1106,15 @@
       username = fields[++i];
     } else if (fields[i] == kAttributeCandidatePwd) {
       password = fields[++i];
+    } else if (fields[i] == kAttributeCandidateNetworkId) {
+      if (!GetValueFromString(first_line, fields[++i], &network_id, error)) {
+        return false;
+      }
     } else if (fields[i] == kAttributeCandidateNetworkCost) {
       if (!GetValueFromString(first_line, fields[++i], &network_cost, error)) {
         return false;
       }
+      network_cost = std::min(network_cost, cricket::kMaxNetworkCost);
     } else {
       // Skip the unknown extension.
       ++i;
@@ -1116,10 +1123,9 @@
 
   *candidate = Candidate(component_id, cricket::ProtoToString(protocol),
                          address, priority, username, password, candidate_type,
-                         generation, foundation);
+                         generation, foundation, network_id, network_cost);
   candidate->set_related_address(related_address);
   candidate->set_tcptype(tcptype);
-  candidate->set_network_cost(std::min(network_cost, cricket::kMaxNetworkCost));
   return true;
 }
 
@@ -1814,6 +1820,9 @@
     if (include_ufrag && !it->username().empty()) {
       os << " " << kAttributeCandidateUfrag << " " << it->username();
     }
+    if (it->network_id() > 0) {
+      os << " " << kAttributeCandidateNetworkId << " " << it->network_id();
+    }
     if (it->network_cost() > 0) {
       os << " " << kAttributeCandidateNetworkCost << " " << it->network_cost();
     }
diff --git a/webrtc/api/webrtcsdp_unittest.cc b/webrtc/api/webrtcsdp_unittest.cc
index 9559701..c527204 100644
--- a/webrtc/api/webrtcsdp_unittest.cc
+++ b/webrtc/api/webrtcsdp_unittest.cc
@@ -2058,6 +2058,19 @@
                                          candidate_with_ufrag));
   message = webrtc::SdpSerializeCandidate(*jcandidate_);
   EXPECT_EQ(std::string(kRawCandidate) + " ufrag ABC", message);
+
+  Candidate candidate_with_network_info(candidates_.front());
+  candidate_with_network_info.set_network_id(1);
+  jcandidate_.reset(new JsepIceCandidate(std::string("audio"), 0,
+                                         candidate_with_network_info));
+  message = webrtc::SdpSerializeCandidate(*jcandidate_);
+  EXPECT_EQ(std::string(kRawCandidate) + " network-id 1", message);
+  candidate_with_network_info.set_network_cost(999);
+  jcandidate_.reset(new JsepIceCandidate(std::string("audio"), 0,
+                                         candidate_with_network_info));
+  message = webrtc::SdpSerializeCandidate(*jcandidate_);
+  EXPECT_EQ(std::string(kRawCandidate) + " network-id 1 network-cost 999",
+            message);
 }
 
 // TODO(mallinath) : Enable this test once WebRTCSdp capable of parsing
@@ -2325,6 +2338,7 @@
   EXPECT_EQ(kDummyMid, jcandidate.sdp_mid());
   EXPECT_EQ(kDummyIndex, jcandidate.sdp_mline_index());
   EXPECT_TRUE(jcandidate.candidate().IsEquivalent(jcandidate_->candidate()));
+  EXPECT_EQ(0, jcandidate.candidate().network_cost());
 
   // Candidate line without generation extension.
   sdp = kSdpOneCandidate;
@@ -2336,6 +2350,22 @@
   expected.set_generation(0);
   EXPECT_TRUE(jcandidate.candidate().IsEquivalent(expected));
 
+  // Candidate with network id and/or cost.
+  sdp = kSdpOneCandidate;
+  Replace(" generation 2", " generation 2 network-id 2", &sdp);
+  EXPECT_TRUE(SdpDeserializeCandidate(sdp, &jcandidate));
+  EXPECT_EQ(kDummyMid, jcandidate.sdp_mid());
+  EXPECT_EQ(kDummyIndex, jcandidate.sdp_mline_index());
+  expected = jcandidate_->candidate();
+  expected.set_network_id(2);
+  EXPECT_TRUE(jcandidate.candidate().IsEquivalent(expected));
+  EXPECT_EQ(0, jcandidate.candidate().network_cost());
+  // Add network cost
+  Replace(" network-id 2", " network-id 2 network-cost 9", &sdp);
+  EXPECT_TRUE(SdpDeserializeCandidate(sdp, &jcandidate));
+  EXPECT_TRUE(jcandidate.candidate().IsEquivalent(expected));
+  EXPECT_EQ(9, jcandidate.candidate().network_cost());
+
   sdp = kSdpTcpActiveCandidate;
   EXPECT_TRUE(SdpDeserializeCandidate(sdp, &jcandidate));
   // Make a cricket::Candidate equivalent to kSdpTcpCandidate string.
diff --git a/webrtc/base/network.cc b/webrtc/base/network.cc
index 4f3b919..4780e2f 100644
--- a/webrtc/base/network.cc
+++ b/webrtc/base/network.cc
@@ -286,6 +286,7 @@
       // This network is new. Place it in the network map.
       merged_list.push_back(net);
       networks_map_[key] = net;
+      net->set_id(next_available_network_id_++);
       // Also, we might have accumulated IPAddresses from the first
       // step, set it here.
       net->SetIPs(kv.second.ips, true);
diff --git a/webrtc/base/network.h b/webrtc/base/network.h
index 680c005..ee22d5e 100644
--- a/webrtc/base/network.h
+++ b/webrtc/base/network.h
@@ -173,6 +173,11 @@
 
   IPAddress default_local_ipv4_address_;
   IPAddress default_local_ipv6_address_;
+  // We use 16 bits to save the bandwidth consumption when sending the network
+  // id over the Internet. It is OK that the 16-bit integer overflows to get a
+  // network id 0 because we only compare the network ids in the old and the new
+  // best connections in the transport channel.
+  uint16_t next_available_network_id_ = 1;
 };
 
 // Basic implementation of the NetworkManager interface that gets list
@@ -339,6 +344,11 @@
   AdapterType type() const { return type_; }
   void set_type(AdapterType type) { type_ = type; }
 
+  // A unique id assigned by the network manager, which may be signaled
+  // to the remote side in the candidate.
+  uint16_t id() const { return id_; }
+  void set_id(uint16_t id) { id_ = id; }
+
   int preference() const { return preference_; }
   void set_preference(int preference) { preference_ = preference; }
 
@@ -372,6 +382,7 @@
   AdapterType type_;
   int preference_;
   bool active_ = true;
+  uint16_t id_ = 0;
 
   friend class NetworkManager;
 };
diff --git a/webrtc/base/network_unittest.cc b/webrtc/base/network_unittest.cc
index 7ad45a3..7133d8b 100644
--- a/webrtc/base/network_unittest.cc
+++ b/webrtc/base/network_unittest.cc
@@ -299,6 +299,8 @@
   EXPECT_EQ(1U, list.size());
   EXPECT_EQ(ipv4_network1.ToString(), list[0]->ToString());
   Network* net1 = list[0];
+  uint16_t net_id1 = net1->id();
+  EXPECT_EQ(1, net_id1);
   list.clear();
 
   // Replace ipv4_network1 with ipv4_network2.
@@ -315,6 +317,9 @@
   EXPECT_EQ(1U, list.size());
   EXPECT_EQ(ipv4_network2.ToString(), list[0]->ToString());
   Network* net2 = list[0];
+  uint16_t net_id2 = net2->id();
+  // Network id will increase.
+  EXPECT_LT(net_id1, net_id2);
   list.clear();
 
   // Add Network2 back.
@@ -332,6 +337,8 @@
   EXPECT_EQ(2U, list.size());
   EXPECT_TRUE((net1 == list[0] && net2 == list[1]) ||
               (net1 == list[1] && net2 == list[0]));
+  EXPECT_TRUE((net_id1 == list[0]->id() && net_id2 == list[1]->id()) ||
+              (net_id1 == list[1]->id() && net_id2 == list[0]->id()));
   list.clear();
 
   // Call MergeNetworkList() again and verify that we don't get update
@@ -350,6 +357,8 @@
   EXPECT_EQ(2U, list.size());
   EXPECT_TRUE((net1 == list[0] && net2 == list[1]) ||
               (net1 == list[1] && net2 == list[0]));
+  EXPECT_TRUE((net_id1 == list[0]->id() && net_id2 == list[1]->id()) ||
+              (net_id1 == list[1]->id() && net_id2 == list[0]->id()));
   list.clear();
 }
 
diff --git a/webrtc/base/networkmonitor.h b/webrtc/base/networkmonitor.h
index d9d6cc4..35ab2b1 100644
--- a/webrtc/base/networkmonitor.h
+++ b/webrtc/base/networkmonitor.h
@@ -46,6 +46,7 @@
   // This is needed because some operating systems (like Android) require a
   // special bind call to put packets on a non-default network interface.
   virtual int BindSocketToNetwork(int socket_fd, const IPAddress& address) = 0;
+  virtual ~NetworkBinderInterface() {}
 };
 
 /*
diff --git a/webrtc/p2p/base/candidate.h b/webrtc/p2p/base/candidate.h
index 11481cd..4ab1b6f 100644
--- a/webrtc/p2p/base/candidate.h
+++ b/webrtc/p2p/base/candidate.h
@@ -27,7 +27,7 @@
 
 namespace cricket {
 
-const uint32_t kMaxNetworkCost = 999;
+const uint16_t kMaxNetworkCost = 999;
 
 // Candidate for ICE based connection discovery.
 
@@ -40,7 +40,9 @@
         component_(0),
         priority_(0),
         network_type_(rtc::ADAPTER_TYPE_UNKNOWN),
-        generation_(0) {}
+        generation_(0),
+        network_id_(0),
+        network_cost_(0) {}
 
   Candidate(int component,
             const std::string& protocol,
@@ -50,7 +52,9 @@
             const std::string& password,
             const std::string& type,
             uint32_t generation,
-            const std::string& foundation)
+            const std::string& foundation,
+            uint16_t network_id = 0,
+            uint16_t network_cost = 0)
       : id_(rtc::CreateRandomString(8)),
         component_(component),
         protocol_(protocol),
@@ -61,7 +65,9 @@
         type_(type),
         network_type_(rtc::ADAPTER_TYPE_UNKNOWN),
         generation_(generation),
-        foundation_(foundation) {}
+        foundation_(foundation),
+        network_id_(network_id),
+        network_cost_(network_cost) {}
 
   const std::string & id() const { return id_; }
   void set_id(const std::string & id) { id_ = id; }
@@ -143,11 +149,15 @@
   // |network_cost| measures the cost/penalty of using this candidate. A network
   // cost of 0 indicates this candidate can be used freely. A value of
   // |kMaxNetworkCost| indicates it should be used only as the last resort.
-  void set_network_cost(uint32_t network_cost) {
+  void set_network_cost(uint16_t network_cost) {
     ASSERT(network_cost <= kMaxNetworkCost);
     network_cost_ = network_cost;
   }
-  uint32_t network_cost() const { return network_cost_; }
+  uint16_t network_cost() const { return network_cost_; }
+
+  // An ID assigned to the network hosting the candidate.
+  uint16_t network_id() const { return network_id_; }
+  void set_network_id(uint16_t network_id) { network_id_ = network_id; }
 
   const std::string& foundation() const {
     return foundation_;
@@ -178,13 +188,14 @@
   // Determines whether this candidate is equivalent to the given one.
   bool IsEquivalent(const Candidate& c) const {
     // We ignore the network name, since that is just debug information, and
-    // the priority, since that should be the same if the rest is (and it's
-    // a float so equality checking is always worrisome).
+    // the priority and the network cost, since they should be the same if the
+    // rest are.
     return (component_ == c.component_) && (protocol_ == c.protocol_) &&
            (address_ == c.address_) && (username_ == c.username_) &&
            (password_ == c.password_) && (type_ == c.type_) &&
            (generation_ == c.generation_) && (foundation_ == c.foundation_) &&
-           (related_address_ == c.related_address_);
+           (related_address_ == c.related_address_) &&
+           (network_id_ == c.network_id_);
   }
 
   // Determines whether this candidate can be considered equivalent to the
@@ -238,7 +249,7 @@
     ost << "Cand[" << transport_name_ << ":" << foundation_ << ":" << component_
         << ":" << protocol_ << ":" << priority_ << ":" << address << ":"
         << type_ << ":" << related_address_ << ":" << username_ << ":"
-        << password_ << ":" << network_cost_ << "]";
+        << password_ << ":" << network_id_ << ":" << network_cost_ << "]";
     return ost.str();
   }
 
@@ -257,8 +268,9 @@
   std::string foundation_;
   rtc::SocketAddress related_address_;
   std::string tcptype_;
-  uint32_t network_cost_ = 0;
   std::string transport_name_;
+  uint16_t network_id_;
+  uint16_t network_cost_;
 };
 
 // Used during parsing and writing to map component to channel name
diff --git a/webrtc/p2p/base/p2ptransportchannel.cc b/webrtc/p2p/base/p2ptransportchannel.cc
index 759fd46..e0428d6 100644
--- a/webrtc/p2p/base/p2ptransportchannel.cc
+++ b/webrtc/p2p/base/p2ptransportchannel.cc
@@ -614,25 +614,30 @@
     }
     int remote_candidate_priority = priority_attr->value();
 
-    const StunUInt32Attribute* cost_attr =
-        stun_msg->GetUInt32(STUN_ATTR_NETWORK_COST);
-    uint32_t network_cost = (cost_attr) ? cost_attr->value() : 0;
+    uint16_t network_id = 0;
+    uint16_t network_cost = 0;
+    const StunUInt32Attribute* network_attr =
+        stun_msg->GetUInt32(STUN_ATTR_NETWORK_INFO);
+    if (network_attr) {
+      uint32_t network_info = network_attr->value();
+      network_id = static_cast<uint16_t>(network_info >> 16);
+      network_cost = static_cast<uint16_t>(network_info);
+    }
 
     // RFC 5245
     // If the source transport address of the request does not match any
     // existing remote candidates, it represents a new peer reflexive remote
     // candidate.
-    remote_candidate = Candidate(component(), ProtoToString(proto), address, 0,
-                                 remote_username, remote_password,
-                                 PRFLX_PORT_TYPE, remote_generation, "");
+    remote_candidate = Candidate(
+        component(), ProtoToString(proto), address, remote_candidate_priority,
+        remote_username, remote_password, PRFLX_PORT_TYPE, remote_generation,
+        "", network_id, network_cost);
 
     // From RFC 5245, section-7.2.1.3:
     // The foundation of the candidate is set to an arbitrary value, different
     // from the foundation for all other remote candidates.
     remote_candidate.set_foundation(
         rtc::ToString<uint32_t>(rtc::ComputeCrc32(remote_candidate.id())));
-    remote_candidate.set_priority(remote_candidate_priority);
-    remote_candidate.set_network_cost(network_cost);
   }
 
   // RFC5245, the agent constructs a pair whose local candidate is equal to
diff --git a/webrtc/p2p/base/port.cc b/webrtc/p2p/base/port.cc
index 9207c9d..eba15f6 100644
--- a/webrtc/p2p/base/port.cc
+++ b/webrtc/p2p/base/port.cc
@@ -242,25 +242,17 @@
     ASSERT(!tcptype.empty());
   }
 
-  Candidate c;
-  c.set_id(rtc::CreateRandomString(8));
-  c.set_component(component_);
-  c.set_type(type);
-  c.set_protocol(protocol);
+  std::string foundation =
+      ComputeFoundation(type, protocol, relay_protocol, base_address);
+  Candidate c(component_, protocol, address, 0U, username_fragment(), password_,
+              type, generation_, foundation, network_->id(), network_cost_);
+  c.set_priority(
+      c.GetPriority(type_preference, network_->preference(), relay_preference));
   c.set_relay_protocol(relay_protocol);
   c.set_tcptype(tcptype);
-  c.set_address(address);
-  c.set_priority(c.GetPriority(type_preference, network_->preference(),
-                               relay_preference));
-  c.set_username(username_fragment());
-  c.set_password(password_);
   c.set_network_name(network_->name());
   c.set_network_type(network_->type());
-  c.set_network_cost(network_cost_);
-  c.set_generation(generation_);
   c.set_related_address(related_address);
-  c.set_foundation(
-      ComputeFoundation(type, protocol, relay_protocol, base_address));
   candidates_.push_back(c);
   SignalCandidateReady(this, c);
 
@@ -705,11 +697,10 @@
           static_cast<uint32_t>(connection_->pings_since_last_response_.size() -
                                 1)));
     }
-    uint32_t network_cost = connection_->port()->network_cost();
-    if (network_cost > 0) {
-      request->AddAttribute(
-          new StunUInt32Attribute(STUN_ATTR_NETWORK_COST, network_cost));
-    }
+    uint32_t network_info = connection_->port()->Network()->id();
+    network_info = (network_info << 16) | connection_->port()->network_cost();
+    request->AddAttribute(
+        new StunUInt32Attribute(STUN_ATTR_NETWORK_INFO, network_info));
 
     // Adding ICE_CONTROLLED or ICE_CONTROLLING attribute based on the role.
     if (connection_->port()->GetIceRole() == ICEROLE_CONTROLLING) {
@@ -1412,11 +1403,12 @@
   new_local_candidate.set_password(local_candidate().password());
   new_local_candidate.set_network_name(local_candidate().network_name());
   new_local_candidate.set_network_type(local_candidate().network_type());
-  new_local_candidate.set_network_cost(local_candidate().network_cost());
   new_local_candidate.set_related_address(local_candidate().address());
   new_local_candidate.set_foundation(ComputeFoundation(
       PRFLX_PORT_TYPE, local_candidate().protocol(),
       local_candidate().relay_protocol(), local_candidate().address()));
+  new_local_candidate.set_network_id(local_candidate().network_id());
+  new_local_candidate.set_network_cost(local_candidate().network_cost());
 
   // Change the local candidate of this Connection to the new prflx candidate.
   local_candidate_index_ = port_->AddPrflxCandidate(new_local_candidate);
diff --git a/webrtc/p2p/base/port.h b/webrtc/p2p/base/port.h
index 65f82e4..4c5a150 100644
--- a/webrtc/p2p/base/port.h
+++ b/webrtc/p2p/base/port.h
@@ -296,7 +296,7 @@
   void set_candidate_filter(uint32_t candidate_filter) {
     candidate_filter_ = candidate_filter;
   }
-  int32_t network_cost() const { return network_cost_; }
+  int16_t network_cost() const { return network_cost_; }
 
  protected:
   enum {
@@ -403,7 +403,7 @@
   // A virtual cost perceived by the user, usually based on the network type
   // (WiFi. vs. Cellular). It takes precedence over the priority when
   // comparing two connections.
-  uint32_t network_cost_;
+  uint16_t network_cost_;
 
   friend class Connection;
 };
diff --git a/webrtc/p2p/base/port_unittest.cc b/webrtc/p2p/base/port_unittest.cc
index be5ced9..d27be29 100644
--- a/webrtc/p2p/base/port_unittest.cc
+++ b/webrtc/p2p/base/port_unittest.cc
@@ -559,6 +559,10 @@
     }
   }
 
+  void SetNetworkType(rtc::AdapterType adapter_type) {
+    network_.set_type(adapter_type);
+  }
+
   void TestCrossFamilyPorts(int type);
 
   void ExpectPortsCanConnect(bool can_connect, Port* p1, Port* p2);
@@ -1757,6 +1761,51 @@
   ASSERT_TRUE(use_candidate_attr != NULL);
 }
 
+TEST_F(PortTest, TestNetworkInfoAttribute) {
+  rtc::scoped_ptr<TestPort> lport(
+      CreateTestPort(kLocalAddr1, "lfrag", "lpass"));
+  // Set the network type for rport to be cellular so its cost will be 999.
+  SetNetworkType(rtc::ADAPTER_TYPE_CELLULAR);
+  rtc::scoped_ptr<TestPort> rport(
+      CreateTestPort(kLocalAddr2, "rfrag", "rpass"));
+  lport->SetIceRole(cricket::ICEROLE_CONTROLLING);
+  lport->SetIceTiebreaker(kTiebreaker1);
+  rport->SetIceRole(cricket::ICEROLE_CONTROLLED);
+  rport->SetIceTiebreaker(kTiebreaker2);
+
+  uint16_t lnetwork_id = 9;
+  lport->Network()->set_id(lnetwork_id);
+  // Send a fake ping from lport to rport.
+  lport->PrepareAddress();
+  rport->PrepareAddress();
+  Connection* lconn =
+      lport->CreateConnection(rport->Candidates()[0], Port::ORIGIN_MESSAGE);
+  lconn->Ping(0);
+  ASSERT_TRUE_WAIT(lport->last_stun_msg() != NULL, 1000);
+  IceMessage* msg = lport->last_stun_msg();
+  const StunUInt32Attribute* network_info_attr =
+      msg->GetUInt32(STUN_ATTR_NETWORK_INFO);
+  ASSERT_TRUE(network_info_attr != NULL);
+  uint32_t network_info = network_info_attr->value();
+  EXPECT_EQ(lnetwork_id, network_info >> 16);
+  // Default network cost is 0.
+  EXPECT_EQ(0U, network_info & 0xFFFF);
+
+  // Send a fake ping from rport to lport.
+  uint16_t rnetwork_id = 8;
+  rport->Network()->set_id(rnetwork_id);
+  Connection* rconn =
+      rport->CreateConnection(lport->Candidates()[0], Port::ORIGIN_MESSAGE);
+  rconn->Ping(0);
+  ASSERT_TRUE_WAIT(rport->last_stun_msg() != NULL, 1000);
+  msg = rport->last_stun_msg();
+  network_info_attr = msg->GetUInt32(STUN_ATTR_NETWORK_INFO);
+  ASSERT_TRUE(network_info_attr != NULL);
+  network_info = network_info_attr->value();
+  EXPECT_EQ(rnetwork_id, network_info >> 16);
+  EXPECT_EQ(cricket::kMaxNetworkCost, network_info & 0xFFFF);
+}
+
 // Test handling STUN messages.
 TEST_F(PortTest, TestHandleStunMessage) {
   // Our port will act as the "remote" port.
diff --git a/webrtc/p2p/base/stun.h b/webrtc/p2p/base/stun.h
index 9c84713..aada43c 100644
--- a/webrtc/p2p/base/stun.h
+++ b/webrtc/p2p/base/stun.h
@@ -606,7 +606,9 @@
   STUN_ATTR_USE_CANDIDATE = 0x0025,    // No content, Length = 0
   STUN_ATTR_ICE_CONTROLLED = 0x8029,   // UInt64
   STUN_ATTR_ICE_CONTROLLING = 0x802A,  // UInt64
-  STUN_ATTR_NETWORK_COST = 0xC057      // UInt32
+  // UInt32. The higher 16 bits are the network ID. The lower 16 bits are the
+  // network cost.
+  STUN_ATTR_NETWORK_INFO = 0xC057
 };
 
 // RFC 5245-defined errors.
@@ -621,7 +623,7 @@
   virtual StunAttributeValueType GetAttributeValueType(int type) const {
     switch (type) {
       case STUN_ATTR_PRIORITY:
-      case STUN_ATTR_NETWORK_COST:
+      case STUN_ATTR_NETWORK_INFO:
         return STUN_VALUE_UINT32;
       case STUN_ATTR_USE_CANDIDATE:   return STUN_VALUE_BYTE_STRING;
       case STUN_ATTR_ICE_CONTROLLED:  return STUN_VALUE_UINT64;