Commit b8cdc219 authored by sergeyu's avatar sergeyu Committed by Commit bot

Reduce frequency of IPv6 probes in HostResolverImpl.

Currently HostResolverImpl tries to probe IPv6 support for every
Resolve() request, i.e. very often. The probe is implemented using
a dummy UDP socket. This doesn't look efficient because IPv6 state
doesn't change often.

Also this change will decrease frequency of the crash in the linked bug.
In that bug the root cause is that on OSX system certificate library may
close recently created file descriptors it doesn't own. Not creating
dummy UDP sockets very often will help to avoid hitting this bug in the
OS very often.

BUG=481163

Review URL: https://codereview.chromium.org/1138833003

Cr-Commit-Position: refs/heads/master@{#329885}
parent 9444f5f4
......@@ -74,6 +74,15 @@ const unsigned kMinimumTTLSeconds = kCacheEntryTTLSeconds;
const char kLocalhost[] = "localhost.";
// Time between IPv6 probes, i.e. for how long results of each IPv6 probe are
// cached.
const int kIPv6ProbePeriodMs = 1000;
// Google DNS address used for IPv6 probes.
const uint8_t kIPv6ProbeAddress[] =
{ 0x20, 0x01, 0x48, 0x60, 0x48, 0x60, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x88, 0x88 };
// We use a separate histogram name for each platform to facilitate the
// display of error codes by their symbolic name (since each platform has
// different mappings).
......@@ -386,6 +395,15 @@ base::Value* NetLogDnsConfigCallback(const DnsConfig* config,
return config->ToValue();
}
base::Value* NetLogIPv6AvailableCallback(bool ipv6_available,
bool cached,
NetLogCaptureMode /* capture_mode */) {
base::DictionaryValue* dict = new base::DictionaryValue();
dict->SetBoolean("ipv6_available", ipv6_available);
dict->SetBoolean("cached", cached);
return dict;
}
// The logging routines are defined here because some requests are resolved
// without a Request object.
......@@ -1815,6 +1833,7 @@ HostResolverImpl::HostResolverImpl(const Options& options, NetLog* net_log)
num_dns_failures_(0),
probe_ipv6_support_(true),
use_local_ipv6_(false),
last_ipv6_probe_result_(true),
resolved_known_ipv6_hostname_(false),
additional_resolver_flags_(0),
fallback_to_proctask_(true),
......@@ -2167,7 +2186,7 @@ void HostResolverImpl::SetHaveOnlyLoopbackAddresses(bool result) {
HostResolverImpl::Key HostResolverImpl::GetEffectiveKeyForRequest(
const RequestInfo& info,
const IPAddressNumber* ip_number,
const BoundNetLog& net_log) const {
const BoundNetLog& net_log) {
HostResolverFlags effective_flags =
info.host_resolver_flags() | additional_resolver_flags_;
AddressFamily effective_address_family = info.address_family();
......@@ -2183,16 +2202,7 @@ HostResolverImpl::Key HostResolverImpl::GetEffectiveKeyForRequest(
// set) so the code requesting the resolution should be amenable to
// receiving a IPv6 resolution.
ip_number == nullptr) {
// Google DNS address.
const uint8 kIPv6Address[] =
{ 0x20, 0x01, 0x48, 0x60, 0x48, 0x60, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x88, 0x88 };
IPAddressNumber address(kIPv6Address,
kIPv6Address + arraysize(kIPv6Address));
bool rv6 = IsGloballyReachable(address, net_log);
net_log.AddEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_IPV6_REACHABILITY_CHECK,
NetLog::BoolCallback("ipv6_available", rv6));
if (!rv6) {
if (!IsIPv6Reachable(net_log)) {
effective_address_family = ADDRESS_FAMILY_IPV4;
effective_flags |= HOST_RESOLVER_DEFAULT_FAMILY_SET_DUE_TO_NO_IPV6;
}
......@@ -2210,6 +2220,22 @@ HostResolverImpl::Key HostResolverImpl::GetEffectiveKeyForRequest(
return Key(hostname, effective_address_family, effective_flags);
}
bool HostResolverImpl::IsIPv6Reachable(const BoundNetLog& net_log) {
base::TimeTicks now = base::TimeTicks::Now();
bool cached = true;
if ((now - last_ipv6_probe_time_).InMilliseconds() > kIPv6ProbePeriodMs) {
IPAddressNumber address(kIPv6ProbeAddress,
kIPv6ProbeAddress + arraysize(kIPv6ProbeAddress));
last_ipv6_probe_result_ = IsGloballyReachable(address, net_log);
last_ipv6_probe_time_ = now;
cached = false;
}
net_log.AddEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_IPV6_REACHABILITY_CHECK,
base::Bind(&NetLogIPv6AvailableCallback,
last_ipv6_probe_result_, cached));
return last_ipv6_probe_result_;
}
void HostResolverImpl::AbortAllInProgressJobs() {
// In Abort, a Request callback could spawn new Jobs with matching keys, so
// first collect and remove all running jobs from |jobs_|.
......@@ -2279,6 +2305,7 @@ void HostResolverImpl::TryServingAllJobsFromHosts() {
void HostResolverImpl::OnIPAddressChanged() {
resolved_known_ipv6_hostname_ = false;
last_ipv6_probe_time_ = base::TimeTicks();
// Abandon all ProbeJobs.
probe_weak_ptr_factory_.InvalidateWeakPtrs();
if (cache_.get())
......
......@@ -200,7 +200,12 @@ class NET_EXPORT HostResolverImpl
// family when the request leaves it unspecified.
Key GetEffectiveKeyForRequest(const RequestInfo& info,
const IPAddressNumber* ip_number,
const BoundNetLog& net_log) const;
const BoundNetLog& net_log);
// Probes IPv6 support and returns true if IPv6 support is enabled.
// Results are cached, i.e. when called repeatedly this method returns result
// from the first probe for some time before probing again.
bool IsIPv6Reachable(const BoundNetLog& net_log);
// Records the result in cache if cache is present.
void CacheResult(const Key& key,
......@@ -284,6 +289,9 @@ class NET_EXPORT HostResolverImpl
// local IPv6 connectivity. Disables probing.
bool use_local_ipv6_;
base::TimeTicks last_ipv6_probe_time_;
bool last_ipv6_probe_result_;
// True iff ProcTask has successfully resolved a hostname known to have IPv6
// addresses using ADDRESS_FAMILY_UNSPECIFIED. Reset on IP address change.
bool resolved_known_ipv6_hostname_;
......
......@@ -25,6 +25,7 @@
#include "net/dns/dns_client.h"
#include "net/dns/dns_test_util.h"
#include "net/dns/mock_host_resolver.h"
#include "net/log/test_net_log.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace net {
......@@ -530,6 +531,10 @@ class HostResolverImplTest : public testing::Test {
return HostResolverImpl::kMaximumDnsFailures;
}
bool IsIPv6Reachable(const BoundNetLog& net_log) {
return resolver_->IsIPv6Reachable(net_log);
}
scoped_refptr<MockHostResolverProc> proc_;
scoped_ptr<HostResolverImpl> resolver_;
ScopedVector<Request> requests_;
......@@ -1397,6 +1402,33 @@ TEST_F(HostResolverImplTest, NameCollision127_0_53_53) {
EXPECT_EQ(OK, request->WaitForResult());
}
TEST_F(HostResolverImplTest, IsIPv6Reachable) {
// Verify that two consecutive calls return the same value.
TestNetLog net_log;
BoundNetLog bound_net_log = BoundNetLog::Make(&net_log, NetLog::SOURCE_NONE);
bool result1 = IsIPv6Reachable(bound_net_log);
bool result2 = IsIPv6Reachable(bound_net_log);
EXPECT_EQ(result1, result2);
// Filter reachability check events and verify that there are two of them.
TestNetLogEntry::List event_list;
net_log.GetEntries(&event_list);
TestNetLogEntry::List probe_event_list;
for (const auto& event : event_list) {
if (event.type == NetLog::TYPE_HOST_RESOLVER_IMPL_IPV6_REACHABILITY_CHECK) {
probe_event_list.push_back(event);
}
}
ASSERT_EQ(2U, probe_event_list.size());
// Verify that the first request was not cached and the second one was.
bool cached;
EXPECT_TRUE(probe_event_list[0].GetBooleanValue("cached", &cached));
EXPECT_FALSE(cached);
EXPECT_TRUE(probe_event_list[1].GetBooleanValue("cached", &cached));
EXPECT_TRUE(cached);
}
DnsConfig CreateValidDnsConfig() {
IPAddressNumber dns_ip;
bool rv = ParseIPLiteralToNumber("192.168.1.0", &dns_ip);
......
......@@ -54,6 +54,13 @@ bool TestNetLogEntry::GetIntegerValue(const std::string& name,
return params->GetInteger(name, value);
}
bool TestNetLogEntry::GetBooleanValue(const std::string& name,
bool* value) const {
if (!params)
return false;
return params->GetBoolean(name, value);
}
bool TestNetLogEntry::GetListValue(const std::string& name,
base::ListValue** value) const {
if (!params)
......
......@@ -47,6 +47,7 @@ struct TestNetLogEntry {
// modify |value| on failure.
bool GetStringValue(const std::string& name, std::string* value) const;
bool GetIntegerValue(const std::string& name, int* value) const;
bool GetBooleanValue(const std::string& name, bool* value) const;
bool GetListValue(const std::string& name, base::ListValue** value) const;
// Same as GetIntegerValue, but returns the error code associated with a
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment