Add a new class InterfaceAddress inherited from IPAddress to keep track of IPv6 Address flags.

Skeleton put in place in Network::GetFilterIPs() which will be used to
filter addresses

BUG=3773
R=jiayl@webrtc.org

Review URL: https://webrtc-codereview.appspot.com/23439004

git-svn-id: http://webrtc.googlecode.com/svn/trunk@7126 4adac7df-926f-26a2-2b94-8c16560cd09d
diff --git a/webrtc/base/ipaddress.cc b/webrtc/base/ipaddress.cc
index 4441e16..4f311d5 100644
--- a/webrtc/base/ipaddress.cc
+++ b/webrtc/base/ipaddress.cc
@@ -186,6 +186,30 @@
   strip_sensitive_ = enable;
 }
 
+bool InterfaceAddress::operator==(const InterfaceAddress &other) const {
+  return ipv6_flags_ == other.ipv6_flags() &&
+    static_cast<const IPAddress&>(*this) == other;
+}
+
+bool InterfaceAddress::operator!=(const InterfaceAddress &other) const {
+  return !((*this) == other);
+}
+
+const InterfaceAddress& InterfaceAddress::operator=(
+  const InterfaceAddress& other) {
+  ipv6_flags_ = other.ipv6_flags_;
+  static_cast<IPAddress&>(*this) = other;
+  return *this;
+}
+
+std::ostream& operator<<(std::ostream& os, const InterfaceAddress& ip) {
+  os << static_cast<const IPAddress&>(ip);
+
+  if (ip.family() == AF_INET6)
+    os << "|flags:0x" << std::hex << ip.ipv6_flags();
+
+  return os;
+}
 
 bool IsPrivateV4(uint32 ip_in_host_order) {
   return ((ip_in_host_order >> 24) == 127) ||
@@ -235,6 +259,17 @@
   return true;
 }
 
+bool IPFromString(const std::string& str, int flags,
+                  InterfaceAddress* out) {
+  IPAddress ip;
+  if (!IPFromString(str, &ip)) {
+    return false;
+  }
+
+  *out = InterfaceAddress(ip, flags);
+  return true;
+}
+
 bool IPIsAny(const IPAddress& ip) {
   switch (ip.family()) {
     case AF_INET:
diff --git a/webrtc/base/ipaddress.h b/webrtc/base/ipaddress.h
index e7d649a..12db5c5 100644
--- a/webrtc/base/ipaddress.h
+++ b/webrtc/base/ipaddress.h
@@ -33,6 +33,19 @@
 
 namespace rtc {
 
+enum IPv6AddressFlag {
+  IPV6_ADDRESS_FLAG_NONE =           0x00,
+
+  // Temporary address is dynamic by nature and will not carry MAC
+  // address.
+  IPV6_ADDRESS_FLAG_TEMPORARY =      1 << 0,
+
+  // Temporary address could become deprecated once the preferred
+  // lifetime is reached. It is still valid but just shouldn't be used
+  // to create new connection.
+  IPV6_ADDRESS_FLAG_DEPRECATED =     1 << 1,
+};
+
 // Version-agnostic IP address class, wraps a union of in_addr and in6_addr.
 class IPAddress {
  public:
@@ -40,12 +53,12 @@
     ::memset(&u_, 0, sizeof(u_));
   }
 
-  explicit IPAddress(const in_addr &ip4) : family_(AF_INET) {
+  explicit IPAddress(const in_addr& ip4) : family_(AF_INET) {
     memset(&u_, 0, sizeof(u_));
     u_.ip4 = ip4;
   }
 
-  explicit IPAddress(const in6_addr &ip6) : family_(AF_INET6) {
+  explicit IPAddress(const in6_addr& ip6) : family_(AF_INET6) {
     u_.ip6 = ip6;
   }
 
@@ -54,22 +67,22 @@
     u_.ip4.s_addr = HostToNetwork32(ip_in_host_byte_order);
   }
 
-  IPAddress(const IPAddress &other) : family_(other.family_) {
+  IPAddress(const IPAddress& other) : family_(other.family_) {
     ::memcpy(&u_, &other.u_, sizeof(u_));
   }
 
-  ~IPAddress() {}
+  virtual ~IPAddress() {}
 
-  const IPAddress & operator=(const IPAddress &other) {
+  const IPAddress & operator=(const IPAddress& other) {
     family_ = other.family_;
     ::memcpy(&u_, &other.u_, sizeof(u_));
     return *this;
   }
 
-  bool operator==(const IPAddress &other) const;
-  bool operator!=(const IPAddress &other) const;
-  bool operator <(const IPAddress &other) const;
-  bool operator >(const IPAddress &other) const;
+  bool operator==(const IPAddress& other) const;
+  bool operator!=(const IPAddress& other) const;
+  bool operator <(const IPAddress& other) const;
+  bool operator >(const IPAddress& other) const;
   friend std::ostream& operator<<(std::ostream& os, const IPAddress& addr);
 
   int family() const { return family_; }
@@ -108,8 +121,38 @@
   static bool strip_sensitive_;
 };
 
+// IP class which could represent IPv6 address flags which is only
+// meaningful in IPv6 case.
+class InterfaceAddress : public IPAddress {
+ public:
+  InterfaceAddress() : ipv6_flags_(IPV6_ADDRESS_FLAG_NONE) {}
+
+  InterfaceAddress(IPAddress ip)
+    : IPAddress(ip), ipv6_flags_(IPV6_ADDRESS_FLAG_NONE) {}
+
+  InterfaceAddress(IPAddress addr, int ipv6_flags)
+    : IPAddress(addr), ipv6_flags_(ipv6_flags) {}
+
+  InterfaceAddress(const in6_addr& ip6, int ipv6_flags)
+    : IPAddress(ip6), ipv6_flags_(ipv6_flags) {}
+
+  const InterfaceAddress & operator=(const InterfaceAddress& other);
+
+  bool operator==(const InterfaceAddress& other) const;
+  bool operator!=(const InterfaceAddress& other) const;
+
+  int ipv6_flags() const { return ipv6_flags_; }
+  friend std::ostream& operator<<(std::ostream& os,
+                                  const InterfaceAddress& addr);
+
+ private:
+  int ipv6_flags_;
+};
+
 bool IPFromAddrInfo(struct addrinfo* info, IPAddress* out);
 bool IPFromString(const std::string& str, IPAddress* out);
+bool IPFromString(const std::string& str, int flags,
+                  InterfaceAddress* out);
 bool IPIsAny(const IPAddress& ip);
 bool IPIsLoopback(const IPAddress& ip);
 bool IPIsPrivate(const IPAddress& ip);
diff --git a/webrtc/base/ipaddress_unittest.cc b/webrtc/base/ipaddress_unittest.cc
index 657595f..e847335 100644
--- a/webrtc/base/ipaddress_unittest.cc
+++ b/webrtc/base/ipaddress_unittest.cc
@@ -856,4 +856,41 @@
   IPAddress::set_strip_sensitive(false);
 }
 
+TEST(IPAddressTest, TestInterfaceAddress) {
+  in6_addr addr;
+  InterfaceAddress addr1(kIPv6PublicAddr,
+                         IPV6_ADDRESS_FLAG_TEMPORARY);
+  EXPECT_EQ(addr1.ipv6_flags(), IPV6_ADDRESS_FLAG_TEMPORARY);
+  EXPECT_EQ(addr1.family(), AF_INET6);
+
+  addr = addr1.ipv6_address();
+  EXPECT_TRUE(IN6_ARE_ADDR_EQUAL(&addr, &kIPv6PublicAddr));
+
+  InterfaceAddress addr2 = addr1;
+  EXPECT_EQ(addr1, addr2);
+  EXPECT_EQ(addr2.ipv6_flags(), IPV6_ADDRESS_FLAG_TEMPORARY);
+  addr = addr2.ipv6_address();
+  EXPECT_TRUE(IN6_ARE_ADDR_EQUAL(&addr, &kIPv6PublicAddr));
+
+  InterfaceAddress addr3(addr1);
+  EXPECT_EQ(addr1, addr3);
+  EXPECT_EQ(addr3.ipv6_flags(), IPV6_ADDRESS_FLAG_TEMPORARY);
+  addr = addr3.ipv6_address();
+  EXPECT_TRUE(IN6_ARE_ADDR_EQUAL(&addr, &kIPv6PublicAddr));
+
+  InterfaceAddress addr4(kIPv6PublicAddr,
+                         IPV6_ADDRESS_FLAG_DEPRECATED);
+  EXPECT_NE(addr1, addr4);
+
+  // When you compare them as IPAddress, since operator==
+  // is not virtual, it'll be equal.
+  IPAddress *paddr1 = &addr1;
+  IPAddress *paddr4 = &addr4;
+  EXPECT_EQ(*paddr1, *paddr4);
+
+  InterfaceAddress addr5(kIPv6LinkLocalAddr,
+                         IPV6_ADDRESS_FLAG_TEMPORARY);
+  EXPECT_NE(addr1, addr5);
+}
+
 }  // namespace rtc
diff --git a/webrtc/base/network.cc b/webrtc/base/network.cc
index 686de97..8c84c2e 100644
--- a/webrtc/base/network.cc
+++ b/webrtc/base/network.cc
@@ -67,7 +67,7 @@
 
 typedef struct {
   Network* net;
-  std::vector<IPAddress> ips;
+  std::vector<InterfaceAddress> ips;
 } AddressList;
 
 bool CompareNetworks(const Network* a, const Network* b) {
@@ -176,9 +176,9 @@
       consolidated_address_list[key] = addrlist;
       might_add_to_merged_list = true;
     }
-    const std::vector<IPAddress>& addresses = list[i]->GetIPs();
+    const std::vector<InterfaceAddress>& addresses = list[i]->GetIPs();
     AddressList& current_list = consolidated_address_list[key];
-    for (std::vector<IPAddress>::const_iterator it = addresses.begin();
+    for (std::vector<InterfaceAddress>::const_iterator it = addresses.begin();
          it != addresses.end();
          ++it) {
       current_list.ips.push_back(*it);
@@ -648,15 +648,15 @@
 
 // Sets the addresses of this network. Returns true if the address set changed.
 // Change detection is short circuited if the changed argument is true.
-bool Network::SetIPs(const std::vector<IPAddress>& ips, bool changed) {
+bool Network::SetIPs(const std::vector<InterfaceAddress>& ips, bool changed) {
   changed = changed || ips.size() != ips_.size();
   // Detect changes with a nested loop; n-squared but we expect on the order
   // of 2-3 addresses per network.
-  for (std::vector<IPAddress>::const_iterator it = ips.begin();
+  for (std::vector<InterfaceAddress>::const_iterator it = ips.begin();
       !changed && it != ips.end();
       ++it) {
     bool found = false;
-    for (std::vector<IPAddress>::iterator inner_it = ips_.begin();
+    for (std::vector<InterfaceAddress>::iterator inner_it = ips_.begin();
          !found && inner_it != ips_.end();
          ++inner_it) {
       if (*it == *inner_it) {
@@ -669,4 +669,14 @@
   return changed;
 }
 
+// TODO(guoweis): will change the name to a more meaningful name as
+// this is not simply return the first address once the logic of ipv6
+// address selection is complete.
+IPAddress Network::ip() const {
+  if (ips_.size() == 0) {
+    return IPAddress();
+  }
+  return static_cast<IPAddress>(ips_.at(0));
+}
+
 }  // namespace rtc
diff --git a/webrtc/base/network.h b/webrtc/base/network.h
index 855b1b7..4cdd4d8 100644
--- a/webrtc/base/network.h
+++ b/webrtc/base/network.h
@@ -189,22 +189,27 @@
 
   // Returns the Network's current idea of the 'best' IP it has.
   // 'Best' currently means the first one added.
-  // TODO: We should be preferring temporary addresses.
   // Returns an unset IP if this network has no active addresses.
-  IPAddress ip() const {
-    if (ips_.size() == 0) {
-      return IPAddress();
-    }
-    return ips_.at(0);
-  }
+  // Here is the rule on how we mark the IPv6 address as ignorable for webrtc.
+  // 1) return all global temporary dynamic and non-deprecrated ones.
+  // 2) if #1 not available, return global dynamic ones.
+  // 3) if #2 not available, return global ones.
+  // 4) if #3 not available, use ULA ipv6 as last resort.
+  // Note that when not specifying any flag, it's treated as case global
+  // dynamic IPv6 address
+  // TODO(guoweis): will change the name to a more meaningful name as
+  // this is not simply return the first address once the logic of ipv6
+  // address selection is complete.
+  IPAddress ip() const;
+
   // Adds an active IP address to this network. Does not check for duplicates.
-  void AddIP(const IPAddress& ip) { ips_.push_back(ip); }
+  void AddIP(const InterfaceAddress& ip) { ips_.push_back(ip); }
 
   // Sets the network's IP address list. Returns true if new IP addresses were
   // detected. Passing true to already_changed skips this check.
-  bool SetIPs(const std::vector<IPAddress>& ips, bool already_changed);
+  bool SetIPs(const std::vector<InterfaceAddress>& ips, bool already_changed);
   // Get the list of IP Addresses associated with this network.
-  const std::vector<IPAddress>& GetIPs() { return ips_;}
+  const std::vector<InterfaceAddress>& GetIPs() const { return ips_;}
   // Clear the network's list of addresses.
   void ClearIPs() { ips_.clear(); }
 
@@ -231,7 +236,7 @@
   IPAddress prefix_;
   int prefix_length_;
   std::string key_;
-  std::vector<IPAddress> ips_;
+  std::vector<InterfaceAddress> ips_;
   int scope_id_;
   bool ignored_;
   AdapterType type_;