diff options
author | jar@chromium.org <jar@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-02-25 06:42:19 +0000 |
---|---|---|
committer | jar@chromium.org <jar@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-02-25 06:42:19 +0000 |
commit | 05b88274fffd678b41c68106aa573fb1187ea95b (patch) | |
tree | c4d8d1da429fcd39dbb25ed7c8ec23f8bab0d10a /net | |
parent | 3846bac495aaba9ab3362ac373edb78d50f1f6c4 (diff) | |
download | chromium_src-05b88274fffd678b41c68106aa573fb1187ea95b.zip chromium_src-05b88274fffd678b41c68106aa573fb1187ea95b.tar.gz chromium_src-05b88274fffd678b41c68106aa573fb1187ea95b.tar.bz2 |
Refine IPv6 probe to require that the client has an IPv6 address on an interface
This currently only works on Posix, not windows.
Network changes are monitored, and the test is repeated each time interfaces
change (which is a subset of any IP addresses changing).
The test performed is still relatively low latency, and we *may* need
to eventually move to an high latency test, such as a DNS resolution,
or an actual test connection. If we move in that direction, then we'll
need to post a task to perform the work, rather than immediately returning.
BUG=25680
BUG=12754
r=wtc,eroman
Review URL: http://codereview.chromium.org/652072
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@39996 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'net')
-rw-r--r-- | net/base/host_resolver.h | 2 | ||||
-rw-r--r-- | net/base/host_resolver_impl.cc | 23 | ||||
-rw-r--r-- | net/base/host_resolver_impl.h | 14 | ||||
-rw-r--r-- | net/base/net_util.cc | 70 |
4 files changed, 88 insertions, 21 deletions
diff --git a/net/base/host_resolver.h b/net/base/host_resolver.h index c4cdef6..3dfe3e0 100644 --- a/net/base/host_resolver.h +++ b/net/base/host_resolver.h @@ -170,7 +170,7 @@ class HostResolver : public base::RefCountedThreadSafe<HostResolver> { protected: friend class base::RefCountedThreadSafe<HostResolver>; - HostResolver() { } + HostResolver() {} // If any completion callbacks are pending when the resolver is destroyed, // the host resolutions are cancelled, and the completion callbacks will not diff --git a/net/base/host_resolver_impl.cc b/net/base/host_resolver_impl.cc index 184324b..2f50b10 100644 --- a/net/base/host_resolver_impl.cc +++ b/net/base/host_resolver_impl.cc @@ -20,6 +20,7 @@ #include "net/base/host_resolver_proc.h" #include "net/base/load_log.h" #include "net/base/net_errors.h" +#include "net/base/net_util.h" #include "net/base/network_change_notifier.h" #if defined(OS_WIN) @@ -575,7 +576,8 @@ HostResolverImpl::HostResolverImpl( resolver_proc_(resolver_proc), default_address_family_(ADDRESS_FAMILY_UNSPECIFIED), shutdown_(false), - network_change_notifier_(network_change_notifier) { + network_change_notifier_(network_change_notifier), + ipv6_probe_monitoring_(false) { DCHECK_GT(max_jobs, 0u); // It is cumbersome to expose all of the constraints in the constructor, @@ -736,6 +738,17 @@ void HostResolverImpl::RemoveObserver(HostResolver::Observer* observer) { observers_.erase(it); } +void HostResolverImpl::SetDefaultAddressFamily(AddressFamily address_family) { + ipv6_probe_monitoring_ = false; + default_address_family_ = address_family; +} + +void HostResolverImpl::ProbeIPv6Support() { + DCHECK(!ipv6_probe_monitoring_); + ipv6_probe_monitoring_ = true; + OnIPAddressChanged(); // Give initial setup call. +} + void HostResolverImpl::Shutdown() { shutdown_ = true; @@ -977,6 +990,14 @@ void HostResolverImpl::OnCancelRequest(LoadLog* load_log, void HostResolverImpl::OnIPAddressChanged() { if (cache_.get()) cache_->clear(); + if (ipv6_probe_monitoring_) { + bool support = IPv6Supported(); + default_address_family_ = support ? ADDRESS_FAMILY_UNSPECIFIED + : ADDRESS_FAMILY_IPV4; + LOG(INFO) << "IPv6Probe forced AddressFamily setting to " + << (support ? "ADDRESS_FAMILY_UNSPECIFIED" + : "ADDRESS_FAMILY_IPV4"); + } } // static diff --git a/net/base/host_resolver_impl.h b/net/base/host_resolver_impl.h index 3e273cd..b92b78b 100644 --- a/net/base/host_resolver_impl.h +++ b/net/base/host_resolver_impl.h @@ -88,9 +88,12 @@ class HostResolverImpl : public HostResolver, virtual void AddObserver(HostResolver::Observer* observer); virtual void RemoveObserver(HostResolver::Observer* observer); - virtual void SetDefaultAddressFamily(AddressFamily address_family) { - default_address_family_ = address_family; - } + // Set address family, and disable IPv6 probe support. + virtual void SetDefaultAddressFamily(AddressFamily address_family); + + // Continuously observe whether IPv6 is supported, and set the allowable + // address family to IPv4 iff IPv6 is not supported. + void ProbeIPv6Support(); virtual HostResolverImpl* GetAsHostResolverImpl() { return this; } @@ -244,6 +247,11 @@ class HostResolverImpl : public HostResolver, NetworkChangeNotifier* const network_change_notifier_; + // Indicate if probing is done after each network change event to set address + // family. + // When false, explicit setting of address family is used. + bool ipv6_probe_monitoring_; + scoped_refptr<RequestsTrace> requests_trace_; DISALLOW_COPY_AND_ASSIGN(HostResolverImpl); diff --git a/net/base/net_util.cc b/net/base/net_util.cc index a2eb04d..dea8c40 100644 --- a/net/base/net_util.cc +++ b/net/base/net_util.cc @@ -21,9 +21,11 @@ #include <ws2tcpip.h> #include <wspiapi.h> // Needed for Win2k compat. #elif defined(OS_POSIX) +#include <fcntl.h> +#include <ifaddrs.h> #include <netdb.h> +#include <net/if.h> #include <sys/socket.h> -#include <fcntl.h> #endif #include "base/base64.h" @@ -257,7 +259,7 @@ bool DecodeBQEncoding(const std::string& part, RFC2047EncodingType enc_type, bool DecodeWord(const std::string& encoded_word, const std::string& referrer_charset, - bool *is_rfc2047, + bool* is_rfc2047, std::string* output) { if (!IsStringASCII(encoded_word)) { // Try UTF-8, referrer_charset and the native OS default charset in turn. @@ -1541,15 +1543,21 @@ void SetExplicitlyAllowedPorts(const std::wstring& allowed_ports) { enum IPv6SupportStatus { IPV6_CANNOT_CREATE_SOCKETS, IPV6_CAN_CREATE_SOCKETS, + IPV6_GETIFADDRS_FAILED, + IPV6_GLOBAL_ADDRESS_MISSING, + IPV6_GLOBAL_ADDRESS_PRESENT, IPV6_SUPPORT_MAX // Bounding values for enumeration. }; static void IPv6SupportResults(IPv6SupportStatus result) { static bool run_once = false; - if (run_once) - return; - run_once = true; - UMA_HISTOGRAM_ENUMERATION("Net.IPv6Status", result, IPV6_SUPPORT_MAX); + if (run_once) { + run_once = true; + UMA_HISTOGRAM_ENUMERATION("Net.IPv6Status", result, IPV6_SUPPORT_MAX); + } else { + UMA_HISTOGRAM_ENUMERATION("Net.IPv6Status_retest", result, + IPV6_SUPPORT_MAX); + } } // TODO(jar): The following is a simple estimate of IPv6 support. We may need @@ -1557,27 +1565,58 @@ static void IPv6SupportResults(IPv6SupportStatus result) { // static bool IPv6Supported() { #if defined(OS_POSIX) - int test_socket; - - test_socket = socket(AF_INET6, SOCK_STREAM, 0); + int test_socket = socket(AF_INET6, SOCK_STREAM, 0); if (test_socket == -1) { IPv6SupportResults(IPV6_CANNOT_CREATE_SOCKETS); return false; } - close(test_socket); - IPv6SupportResults(IPV6_CAN_CREATE_SOCKETS); + + // Check to see if any interface has a IPv6 address. + struct ifaddrs* interface_addr = NULL; + int rv = getifaddrs(&interface_addr); + if (rv != 0) { + IPv6SupportResults(IPV6_GETIFADDRS_FAILED); + return true; // Don't yet block IPv6. + } + + bool found_ipv6 = false; + for (struct ifaddrs* interface = interface_addr; + interface != NULL; + interface = interface->ifa_next) { + if (!(IFF_UP & interface->ifa_flags)) + continue; + if (IFF_LOOPBACK & interface->ifa_flags) + continue; + struct sockaddr* addr = interface->ifa_addr; + if (!addr) + continue; + if (addr->sa_family != AF_INET6) + continue; + // Safe cast since this is AF_INET6. + struct sockaddr_in6* addr_in6 = + reinterpret_cast<struct sockaddr_in6*>(addr); + struct in6_addr* sin6_addr = &addr_in6->sin6_addr; + if (IN6_IS_ADDR_LOOPBACK(sin6_addr) || IN6_IS_ADDR_LINKLOCAL(sin6_addr)) + continue; + found_ipv6 = true; + break; + } + freeifaddrs(interface_addr); + if (!found_ipv6) { + IPv6SupportResults(IPV6_GLOBAL_ADDRESS_MISSING); + return false; + } + + IPv6SupportResults(IPV6_GLOBAL_ADDRESS_PRESENT); return true; #elif defined(OS_WIN) EnsureWinsockInit(); - SOCKET test_socket; - - test_socket = socket(AF_INET6, SOCK_STREAM, 0); + SOCKET test_socket = socket(AF_INET6, SOCK_STREAM, 0); if (test_socket == INVALID_SOCKET) { IPv6SupportResults(IPV6_CANNOT_CREATE_SOCKETS); return false; } - closesocket(test_socket); IPv6SupportResults(IPV6_CAN_CREATE_SOCKETS); return true; @@ -1587,5 +1626,4 @@ bool IPv6Supported() { #endif // defined(various platforms) } - } // namespace net |