diff --git a/talk/p2p/client/basicportallocator.cc b/talk/p2p/client/basicportallocator.cc index eda0b4b49d..9ca873b99d 100644 --- a/talk/p2p/client/basicportallocator.cc +++ b/talk/p2p/client/basicportallocator.cc @@ -431,7 +431,7 @@ void BasicPortAllocatorSession::DoAllocate() { } if (!(sequence_flags & PORTALLOCATOR_ENABLE_IPV6) && - networks[i]->ip().family() == AF_INET6) { + networks[i]->GetBestIP().family() == AF_INET6) { // Skip IPv6 networks unless the flag's been set. continue; } @@ -728,7 +728,7 @@ AllocationSequence::AllocationSequence(BasicPortAllocatorSession* session, uint32 flags) : session_(session), network_(network), - ip_(network->ip()), + ip_(network->GetBestIP()), config_(config), state_(kInit), flags_(flags), @@ -771,7 +771,7 @@ AllocationSequence::~AllocationSequence() { void AllocationSequence::DisableEquivalentPhases(rtc::Network* network, PortConfiguration* config, uint32* flags) { - if (!((network == network_) && (ip_ == network->ip()))) { + if (!((network == network_) && (ip_ == network->GetBestIP()))) { // Different network setup; nothing is equivalent. return; } diff --git a/talk/p2p/client/connectivitychecker.cc b/talk/p2p/client/connectivitychecker.cc index 06de5e48aa..935c4b39d7 100644 --- a/talk/p2p/client/connectivitychecker.cc +++ b/talk/p2p/client/connectivitychecker.cc @@ -1,5 +1,29 @@ -// Copyright 2011 Google Inc. All Rights Reserved. - +/* + * libjingle + * Copyright 2011, Google Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ #include @@ -214,7 +238,8 @@ void ConnectivityChecker::OnRequestDone(rtc::AsyncHttpRequest* request) { return; } rtc::ProxyInfo proxy_info = request->proxy(); - NicMap::iterator i = nics_.find(NicId(networks[0]->ip(), proxy_info.address)); + NicMap::iterator i = + nics_.find(NicId(networks[0]->GetBestIP(), proxy_info.address)); if (i != nics_.end()) { int port = request->port(); uint32 now = rtc::Time(); @@ -247,7 +272,7 @@ void ConnectivityChecker::OnRelayPortComplete(Port* port) { ASSERT(worker_ == rtc::Thread::Current()); RelayPort* relay_port = reinterpret_cast(port); const ProtocolAddress* address = relay_port->ServerAddress(0); - rtc::IPAddress ip = port->Network()->ip(); + rtc::IPAddress ip = port->Network()->GetBestIP(); NicMap::iterator i = nics_.find(NicId(ip, port->proxy().address)); if (i != nics_.end()) { // We have it already, add the new information. @@ -281,7 +306,7 @@ void ConnectivityChecker::OnStunPortComplete(Port* port) { ASSERT(worker_ == rtc::Thread::Current()); const std::vector candidates = port->Candidates(); Candidate c = candidates[0]; - rtc::IPAddress ip = port->Network()->ip(); + rtc::IPAddress ip = port->Network()->GetBestIP(); NicMap::iterator i = nics_.find(NicId(ip, port->proxy().address)); if (i != nics_.end()) { // We have it already, add the new information. @@ -300,7 +325,7 @@ void ConnectivityChecker::OnStunPortComplete(Port* port) { void ConnectivityChecker::OnStunPortError(Port* port) { ASSERT(worker_ == rtc::Thread::Current()); LOG(LS_ERROR) << "Stun address error."; - rtc::IPAddress ip = port->Network()->ip(); + rtc::IPAddress ip = port->Network()->GetBestIP(); NicMap::iterator i = nics_.find(NicId(ip, port->proxy().address)); if (i != nics_.end()) { // We have it already, add the new information. @@ -337,19 +362,28 @@ HttpPortAllocator* ConnectivityChecker::CreatePortAllocator( StunPort* ConnectivityChecker::CreateStunPort( const std::string& username, const std::string& password, const PortConfiguration* config, rtc::Network* network) { - return StunPort::Create(worker_, socket_factory_.get(), - network, network->ip(), 0, 0, - username, password, config->stun_servers); + return StunPort::Create(worker_, + socket_factory_.get(), + network, + network->GetBestIP(), + 0, + 0, + username, + password, + config->stun_servers); } RelayPort* ConnectivityChecker::CreateRelayPort( const std::string& username, const std::string& password, const PortConfiguration* config, rtc::Network* network) { - return RelayPort::Create(worker_, socket_factory_.get(), - network, network->ip(), + return RelayPort::Create(worker_, + socket_factory_.get(), + network, + network->GetBestIP(), port_allocator_->min_port(), port_allocator_->max_port(), - username, password); + username, + password); } void ConnectivityChecker::CreateRelayPorts( @@ -365,8 +399,8 @@ void ConnectivityChecker::CreateRelayPorts( for (relay = config->relays.begin(); relay != config->relays.end(); ++relay) { for (uint32 i = 0; i < networks.size(); ++i) { - NicMap::iterator iter = nics_.find(NicId(networks[i]->ip(), - proxy_info.address)); + NicMap::iterator iter = + nics_.find(NicId(networks[i]->GetBestIP(), proxy_info.address)); if (iter != nics_.end()) { // TODO: Now setting the same start time for all protocols. // This might affect accuracy, but since we are mainly looking for @@ -423,7 +457,7 @@ void ConnectivityChecker::AllocatePorts() { rtc::ProxyInfo proxy_info = GetProxyInfo(); bool allocate_relay_ports = false; for (uint32 i = 0; i < networks.size(); ++i) { - if (AddNic(networks[i]->ip(), proxy_info.address)) { + if (AddNic(networks[i]->GetBestIP(), proxy_info.address)) { Port* port = CreateStunPort(username, password, &config, networks[i]); if (port) { @@ -500,7 +534,8 @@ void ConnectivityChecker::RegisterHttpStart(int port) { return; } rtc::ProxyInfo proxy_info = GetProxyInfo(); - NicMap::iterator i = nics_.find(NicId(networks[0]->ip(), proxy_info.address)); + NicMap::iterator i = + nics_.find(NicId(networks[0]->GetBestIP(), proxy_info.address)); if (i != nics_.end()) { uint32 now = rtc::Time(); NicInfo* nic_info = &i->second; diff --git a/talk/p2p/client/connectivitychecker_unittest.cc b/talk/p2p/client/connectivitychecker_unittest.cc index b96cf1769f..54369c564e 100644 --- a/talk/p2p/client/connectivitychecker_unittest.cc +++ b/talk/p2p/client/connectivitychecker_unittest.cc @@ -1,5 +1,29 @@ -// Copyright 2011 Google Inc. All Rights Reserved. - +/* + * libjingle + * Copyright 2011, Google Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ #include @@ -211,19 +235,27 @@ class ConnectivityCheckerForTest : public ConnectivityChecker { virtual StunPort* CreateStunPort( const std::string& username, const std::string& password, const PortConfiguration* config, rtc::Network* network) { - return new FakeStunPort(worker(), socket_factory_, - network, network->ip(), - kMinPort, kMaxPort, - username, password, + return new FakeStunPort(worker(), + socket_factory_, + network, + network->GetBestIP(), + kMinPort, + kMaxPort, + username, + password, config->stun_servers); } virtual RelayPort* CreateRelayPort( const std::string& username, const std::string& password, const PortConfiguration* config, rtc::Network* network) { - return new FakeRelayPort(worker(), socket_factory_, - network, network->ip(), - kMinPort, kMaxPort, - username, password); + return new FakeRelayPort(worker(), + socket_factory_, + network, + network->GetBestIP(), + kMinPort, + kMaxPort, + username, + password); } virtual void InitiateProxyDetection() { if (!proxy_initiated_) { diff --git a/talk/p2p/client/fakeportallocator.h b/talk/p2p/client/fakeportallocator.h index 6c36c4e383..4441a2fb04 100644 --- a/talk/p2p/client/fakeportallocator.h +++ b/talk/p2p/client/fakeportallocator.h @@ -1,6 +1,29 @@ -// Copyright 2010 Google Inc. All Rights Reserved, -// -// Author: Justin Uberti (juberti@google.com) +/* + * libjingle + * Copyright 2010, Google Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ #ifndef TALK_P2P_CLIENT_FAKEPORTALLOCATOR_H_ #define TALK_P2P_CLIENT_FAKEPORTALLOCATOR_H_ @@ -39,10 +62,14 @@ class FakePortAllocatorSession : public PortAllocatorSession { virtual void StartGettingPorts() { if (!port_) { - port_.reset(cricket::UDPPort::Create(worker_thread_, factory_, - &network_, network_.ip(), 0, 0, - username(), - password())); + port_.reset(cricket::UDPPort::Create(worker_thread_, + factory_, + &network_, + network_.GetBestIP(), + 0, + 0, + username(), + password())); AddPort(port_.get()); } ++port_config_count_; diff --git a/webrtc/base/nat_unittest.cc b/webrtc/base/nat_unittest.cc index 8b9d8a1509..0e16259a0f 100644 --- a/webrtc/base/nat_unittest.cc +++ b/webrtc/base/nat_unittest.cc @@ -209,7 +209,7 @@ void TestPhysicalInternal(const SocketAddress& int_addr) { // can't talk to ip, so check for connectivity as well. for (std::vector::iterator it = networks.begin(); it != networks.end(); ++it) { - const IPAddress& ip = (*it)->ip(); + const IPAddress& ip = (*it)->GetBestIP(); if (ip.family() == int_addr.family() && TestConnectivity(int_addr, ip)) { ext_addr2.SetIP(ip); break; diff --git a/webrtc/base/network.cc b/webrtc/base/network.cc index 8c84c2e370..c1f978b92f 100644 --- a/webrtc/base/network.cc +++ b/webrtc/base/network.cc @@ -88,10 +88,13 @@ bool SortNetworks(const Network* a, const Network* b) { return a->type() < b->type(); } + IPAddress ip_a = a->GetBestIP(); + IPAddress ip_b = b->GetBestIP(); + // After type, networks are sorted by IP address precedence values // from RFC 3484-bis - if (IPAddressPrecedence(a->ip()) != IPAddressPrecedence(b->ip())) { - return IPAddressPrecedence(a->ip()) > IPAddressPrecedence(b->ip()); + if (IPAddressPrecedence(ip_a) != IPAddressPrecedence(ip_b)) { + return IPAddressPrecedence(ip_a) > IPAddressPrecedence(ip_b); } // TODO(mallinath) - Add VPN and Link speed conditions while sorting. @@ -474,7 +477,7 @@ bool BasicNetworkManager::CreateNetworks(bool include_ignored, } return true; } -#endif // WEBRTC_WIN +#endif // WEBRTC_WIN #if defined(WEBRTC_LINUX) bool IsDefaultRoute(const std::string& network_name) { @@ -636,16 +639,6 @@ Network::Network(const std::string& name, const std::string& desc, ignored_(false), type_(type), preference_(0) { } -std::string Network::ToString() const { - std::stringstream ss; - // Print out the first space-terminated token of the network desc, plus - // the IP address. - ss << "Net[" << description_.substr(0, description_.find(' ')) - << ":" << prefix_.ToSensitiveString() << "/" << prefix_length_ - << ":" << AdapterTypeToString(type_) << "]"; - return ss.str(); -} - // 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) { @@ -669,14 +662,52 @@ 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 { +// Select the best IP address to use from this Network. +IPAddress Network::GetBestIP() const { if (ips_.size() == 0) { return IPAddress(); } - return static_cast(ips_.at(0)); + + if (prefix_.family() == AF_INET) { + return static_cast(ips_.at(0)); + } + + InterfaceAddress selected_ip, ula_ip; + + for (size_t i = 0; i < ips_.size(); i++) { + // Ignore any address which has been deprecated already. + if (ips_[i].ipv6_flags() & IPV6_ADDRESS_FLAG_DEPRECATED) + continue; + + // ULA address should only be returned when we have no other + // global IP. + if (IPIsULA(static_cast(ips_[i]))) { + ula_ip = ips_[i]; + continue; + } + selected_ip = ips_[i]; + + // Search could stop once a temporary non-deprecated one is found. + if (ips_[i].ipv6_flags() & IPV6_ADDRESS_FLAG_TEMPORARY) + break; + } + + // No proper global IPv6 address found, use ULA instead. + if (IPIsUnspec(selected_ip) && !IPIsUnspec(ula_ip)) { + selected_ip = ula_ip; + } + + return static_cast(selected_ip); +} + +std::string Network::ToString() const { + std::stringstream ss; + // Print out the first space-terminated token of the network desc, plus + // the IP address. + ss << "Net[" << description_.substr(0, description_.find(' ')) + << ":" << prefix_.ToSensitiveString() << "/" << prefix_length_ + << ":" << AdapterTypeToString(type_) << "]"; + return ss.str(); } } // namespace rtc diff --git a/webrtc/base/network.h b/webrtc/base/network.h index 4cdd4d8eb5..6f9d08e707 100644 --- a/webrtc/base/network.h +++ b/webrtc/base/network.h @@ -188,19 +188,28 @@ class Network { std::string key() const { return key_; } // Returns the Network's current idea of the 'best' IP it has. - // 'Best' currently means the first one added. - // Returns an unset IP if this network has no active addresses. - // Here is the rule on how we mark the IPv6 address as ignorable for webrtc. + // Or return an unset IP if this network has no active addresses. + // 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. + // 2) if #1 not available, return global ones. + // 3) if #2 not available, use ULA ipv6 as last resort. (ULA stands + // for unique local address, which is not route-able in open + // internet but might be useful for a close WebRTC deployment. + + // TODO(guoweis): rule #3 actually won't happen at current + // implementation. The reason being that ULA address starting with + // 0xfc 0r 0xfd will be grouped into its own Network. The result of + // that is WebRTC will have one extra Network to generate candidates + // but the lack of rule #3 shouldn't prevent turning on IPv6 since + // ULA should only be tried in a close deployment anyway. + // 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; + // IPv6 address + IPAddress GetBestIP() const; + + // Keep the original function here for now. + // TODO(guoweis): Remove this when all callers are migrated to GetBestIP(). + IPAddress ip() const { return GetBestIP(); } // Adds an active IP address to this network. Does not check for duplicates. void AddIP(const InterfaceAddress& ip) { ips_.push_back(ip); } diff --git a/webrtc/base/network_unittest.cc b/webrtc/base/network_unittest.cc index 8123f8bb65..acb118d4ba 100644 --- a/webrtc/base/network_unittest.cc +++ b/webrtc/base/network_unittest.cc @@ -114,7 +114,7 @@ TEST_F(NetworkTest, DISABLED_TestCreateNetworks) { ++it) { sockaddr_storage storage; memset(&storage, 0, sizeof(storage)); - IPAddress ip = (*it)->ip(); + IPAddress ip = (*it)->GetBestIP(); SocketAddress bindaddress(ip, 0); bindaddress.SetScopeID((*it)->scope_id()); // TODO(thaloun): Use rtc::AsyncSocket once it supports IPv6. @@ -650,4 +650,45 @@ TEST_F(NetworkTest, TestMergeNetworkList) { EXPECT_EQ(list2[0]->GetIPs()[1], ip2); } +// Test that the filtering logic follows the defined ruleset in network.h. +TEST_F(NetworkTest, TestIPv6Selection) { + InterfaceAddress ip; + std::string ipstr; + + ipstr = "2401:fa00:4:1000:be30:5bff:fee5:c3"; + ASSERT_TRUE(IPFromString(ipstr, IPV6_ADDRESS_FLAG_DEPRECATED, &ip)); + + // Create a network with this prefix. + Network ipv6_network( + "test_eth0", "Test NetworkAdapter", TruncateIP(ip, 64), 64); + + // When there is no address added, it should return an unspecified + // address. + EXPECT_EQ(ipv6_network.GetBestIP(), IPAddress()); + EXPECT_TRUE(IPIsUnspec(ipv6_network.GetBestIP())); + + // Deprecated one should not be returned. + ipv6_network.AddIP(ip); + EXPECT_EQ(ipv6_network.GetBestIP(), IPAddress()); + + // Add ULA one. ULA is unique local address which is starting either + // with 0xfc or 0xfd. + ipstr = "fd00:fa00:4:1000:be30:5bff:fee5:c4"; + ASSERT_TRUE(IPFromString(ipstr, IPV6_ADDRESS_FLAG_NONE, &ip)); + ipv6_network.AddIP(ip); + EXPECT_EQ(ipv6_network.GetBestIP(), static_cast(ip)); + + // Add global one. + ipstr = "2401:fa00:4:1000:be30:5bff:fee5:c5"; + ASSERT_TRUE(IPFromString(ipstr, IPV6_ADDRESS_FLAG_NONE, &ip)); + ipv6_network.AddIP(ip); + EXPECT_EQ(ipv6_network.GetBestIP(), static_cast(ip)); + + // Add global dynamic temporary one. + ipstr = "2401:fa00:4:1000:be30:5bff:fee5:c6"; + ASSERT_TRUE(IPFromString(ipstr, IPV6_ADDRESS_FLAG_TEMPORARY, &ip)); + ipv6_network.AddIP(ip); + EXPECT_EQ(ipv6_network.GetBestIP(), static_cast(ip)); +} + } // namespace rtc