diff options
author | jar@chromium.org <jar@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-02-26 05:33:45 +0000 |
---|---|---|
committer | jar@chromium.org <jar@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-02-26 05:33:45 +0000 |
commit | 7be4c7eef651408e7e0cd30edf5b48e2ee93f226 (patch) | |
tree | b3d6849e0df9a999c5a9d6425dd4004bd474d508 | |
parent | 196e32aed9931577e45f76d482f5db8372a51a31 (diff) | |
download | chromium_src-7be4c7eef651408e7e0cd30edf5b48e2ee93f226.zip chromium_src-7be4c7eef651408e7e0cd30edf5b48e2ee93f226.tar.gz chromium_src-7be4c7eef651408e7e0cd30edf5b48e2ee93f226.tar.bz2 |
Revert 39998 - Revert 39996 Refine IPv6 probe to require that the client has an IPv6 address on an interface
This is a second attempt to land a reviewed change. It was reverted because
the tree got very red (for other reasons), and it was plausible that this
change was causing startup latency in Mac and Linux (causing both perf bots
to go red). If this landing turns those perf-bots red (tonight) I'll need
to revert. (... and I'll need to rearchitect to do the probes
asynchronously, and get off the startup-critical-path.
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
TBR=jar@chromium.org
Review URL: http://codereview.chromium.org/660073
TBR=jar@chromium.org
Review URL: http://codereview.chromium.org/661164
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@40099 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r-- | chrome/browser/io_thread.cc | 61 | ||||
-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 |
5 files changed, 121 insertions, 49 deletions
diff --git a/chrome/browser/io_thread.cc b/chrome/browser/io_thread.cc index f4d4698..6378c50 100644 --- a/chrome/browser/io_thread.cc +++ b/chrome/browser/io_thread.cc @@ -24,44 +24,49 @@ namespace { net::HostResolver* CreateGlobalHostResolver( net::NetworkChangeNotifier* network_change_notifier) { - net::HostResolver* global_host_resolver = NULL; - const CommandLine& command_line = *CommandLine::ForCurrentProcess(); - - global_host_resolver = + net::HostResolver* global_host_resolver = net::CreateSystemHostResolver(network_change_notifier); + // Determine if we should disable IPv6 support. if (!command_line.HasSwitch(switches::kEnableIPv6)) { - // Measure impact of allowing IPv6 support without probing. - const FieldTrial::Probability kDivisor = 100; - const FieldTrial::Probability kProbability = 50; // 50% probability. - FieldTrial* trial = new FieldTrial("IPv6_Probe", kDivisor); - int skip_group = trial->AppendGroup("_IPv6_probe_skipped", kProbability); - trial->AppendGroup("_IPv6_probe_done", - FieldTrial::kAllRemainingProbability); - bool use_ipv6_probe = (trial->group() != skip_group); - - // Perform probe, and then optionally use result to disable IPv6. - // Some users report confused OS handling of IPv6, leading to large - // latency. If we can show that IPv6 is not supported, then disabliing it - // will work around such problems. - if ((!net::IPv6Supported() && use_ipv6_probe) || - command_line.HasSwitch(switches::kDisableIPv6)) + if (command_line.HasSwitch(switches::kDisableIPv6)) { global_host_resolver->SetDefaultAddressFamily(net::ADDRESS_FAMILY_IPV4); + } else { + net::HostResolverImpl* host_resolver_impl = + global_host_resolver->GetAsHostResolverImpl(); + if (host_resolver_impl != NULL) { + // (optionally) Use probe to decide if support is warranted. + + // Measure impact of probing to allow IPv6. + // Some users report confused OS handling of IPv6, leading to large + // latency. If we can show that IPv6 is not supported, then disabliing + // it will work around such problems. + const FieldTrial::Probability kDivisor = 100; + const FieldTrial::Probability kProbability = 50; // 50% probability. + FieldTrial* trial = new FieldTrial("IPv6_Probe", kDivisor); + int skip_group = trial->AppendGroup("_IPv6_probe_skipped", + kProbability); + trial->AppendGroup("_IPv6_probe_done", + FieldTrial::kAllRemainingProbability); + bool use_ipv6_probe = (trial->group() != skip_group); + if (use_ipv6_probe) + host_resolver_impl->ProbeIPv6Support(); + } + } } // If hostname remappings were specified on the command-line, layer these // rules on top of the real host resolver. This allows forwarding all requests // through a designated test server. - if (command_line.HasSwitch(switches::kHostResolverRules)) { - net::MappedHostResolver* remapped_resolver = - new net::MappedHostResolver(global_host_resolver); - global_host_resolver = remapped_resolver; - remapped_resolver->SetRulesFromString( - command_line.GetSwitchValueASCII(switches::kHostResolverRules)); - } - - return global_host_resolver; + if (!command_line.HasSwitch(switches::kHostResolverRules)) + return global_host_resolver; + + net::MappedHostResolver* remapped_resolver = + new net::MappedHostResolver(global_host_resolver); + remapped_resolver->SetRulesFromString( + command_line.GetSwitchValueASCII(switches::kHostResolverRules)); + return remapped_resolver; } } // namespace 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 |