diff --git a/webrtc/base/ipaddress.cc b/webrtc/base/ipaddress.cc index 4441e16f6b..4f311d5a29 100644 --- a/webrtc/base/ipaddress.cc +++ b/webrtc/base/ipaddress.cc @@ -186,6 +186,30 @@ void IPAddress::set_strip_sensitive(bool enable) { strip_sensitive_ = enable; } +bool InterfaceAddress::operator==(const InterfaceAddress &other) const { + return ipv6_flags_ == other.ipv6_flags() && + static_cast(*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(*this) = other; + return *this; +} + +std::ostream& operator<<(std::ostream& os, const InterfaceAddress& ip) { + os << static_cast(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 @@ bool IPFromString(const std::string& str, IPAddress* out) { 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 e7d649acbf..12db5c5bfd 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 @@ class IPAddress { ::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 @@ class IPAddress { 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 @@ class IPAddress { 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 657595f68f..e8473351cb 100644 --- a/webrtc/base/ipaddress_unittest.cc +++ b/webrtc/base/ipaddress_unittest.cc @@ -856,4 +856,41 @@ TEST(IPAddressTest, TestToSensitiveString) { 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 686de974d4..8c84c2e370 100644 --- a/webrtc/base/network.cc +++ b/webrtc/base/network.cc @@ -67,7 +67,7 @@ const int kHighestNetworkPreference = 127; typedef struct { Network* net; - std::vector ips; + std::vector ips; } AddressList; bool CompareNetworks(const Network* a, const Network* b) { @@ -176,9 +176,9 @@ void NetworkManagerBase::MergeNetworkList(const NetworkList& new_networks, consolidated_address_list[key] = addrlist; might_add_to_merged_list = true; } - const std::vector& addresses = list[i]->GetIPs(); + const std::vector& addresses = list[i]->GetIPs(); AddressList& current_list = consolidated_address_list[key]; - for (std::vector::const_iterator it = addresses.begin(); + for (std::vector::const_iterator it = addresses.begin(); it != addresses.end(); ++it) { current_list.ips.push_back(*it); @@ -648,15 +648,15 @@ std::string Network::ToString() const { // 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& ips, bool changed) { +bool Network::SetIPs(const std::vector& 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::const_iterator it = ips.begin(); + for (std::vector::const_iterator it = ips.begin(); !changed && it != ips.end(); ++it) { bool found = false; - for (std::vector::iterator inner_it = ips_.begin(); + for (std::vector::iterator inner_it = ips_.begin(); !found && inner_it != ips_.end(); ++inner_it) { if (*it == *inner_it) { @@ -669,4 +669,14 @@ bool Network::SetIPs(const std::vector& ips, bool changed) { 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(ips_.at(0)); +} + } // namespace rtc diff --git a/webrtc/base/network.h b/webrtc/base/network.h index 855b1b74a5..4cdd4d8eb5 100644 --- a/webrtc/base/network.h +++ b/webrtc/base/network.h @@ -189,22 +189,27 @@ class Network { // 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& ips, bool already_changed); + bool SetIPs(const std::vector& ips, bool already_changed); // Get the list of IP Addresses associated with this network. - const std::vector& GetIPs() { return ips_;} + const std::vector& GetIPs() const { return ips_;} // Clear the network's list of addresses. void ClearIPs() { ips_.clear(); } @@ -231,7 +236,7 @@ class Network { IPAddress prefix_; int prefix_length_; std::string key_; - std::vector ips_; + std::vector ips_; int scope_id_; bool ignored_; AdapterType type_;