Popular sites on the NTP: re-download popular suggestions once per Chrome run
[chromium-blink-merge.git] / chrome / browser / net / dns_probe_service.cc
blob91545354f13fe340c93b0cd5a94e3365d88ea91e
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "chrome/browser/net/dns_probe_service.h"
7 #include "base/metrics/field_trial.h"
8 #include "base/metrics/histogram.h"
9 #include "base/strings/string_number_conversions.h"
10 #include "net/base/ip_endpoint.h"
11 #include "net/base/net_util.h"
12 #include "net/dns/dns_client.h"
13 #include "net/dns/dns_config_service.h"
14 #include "net/dns/dns_protocol.h"
16 using base::FieldTrialList;
17 using base::StringToInt;
18 using error_page::DnsProbeStatus;
19 using net::DnsClient;
20 using net::DnsConfig;
21 using net::IPAddressNumber;
22 using net::ParseIPLiteralToNumber;
23 using net::NetworkChangeNotifier;
25 namespace chrome_browser_net {
27 namespace {
29 // How long the DnsProbeService will cache the probe result for.
30 // If it's older than this and we get a probe request, the service expires it
31 // and starts a new probe.
32 const int kMaxResultAgeMs = 5000;
34 // The public DNS servers used by the DnsProbeService to verify internet
35 // connectivity.
36 const char kGooglePublicDns1[] = "8.8.8.8";
37 const char kGooglePublicDns2[] = "8.8.4.4";
39 net::IPEndPoint MakeDnsEndPoint(const std::string& dns_ip_literal) {
40 IPAddressNumber dns_ip_number;
41 bool rv = ParseIPLiteralToNumber(dns_ip_literal, &dns_ip_number);
42 DCHECK(rv);
43 return net::IPEndPoint(dns_ip_number, net::dns_protocol::kDefaultPort);
46 DnsProbeStatus EvaluateResults(DnsProbeRunner::Result system_result,
47 DnsProbeRunner::Result public_result) {
48 // If the system DNS is working, assume the domain doesn't exist.
49 if (system_result == DnsProbeRunner::CORRECT)
50 return error_page::DNS_PROBE_FINISHED_NXDOMAIN;
52 // If the system DNS is unknown (e.g. on Android), but the public server is
53 // reachable, assume the domain doesn't exist.
54 if (system_result == DnsProbeRunner::UNKNOWN &&
55 public_result == DnsProbeRunner::CORRECT) {
56 return error_page::DNS_PROBE_FINISHED_NXDOMAIN;
59 // If the system DNS is not working but another public server is, assume the
60 // DNS config is bad (or perhaps the DNS servers are down or broken).
61 if (public_result == DnsProbeRunner::CORRECT)
62 return error_page::DNS_PROBE_FINISHED_BAD_CONFIG;
64 // If the system DNS is not working and another public server is unreachable,
65 // assume the internet connection is down (note that system DNS may be a
66 // router on the LAN, so it may be reachable but returning errors.)
67 if (public_result == DnsProbeRunner::UNREACHABLE)
68 return error_page::DNS_PROBE_FINISHED_NO_INTERNET;
70 // Otherwise: the system DNS is not working and another public server is
71 // responding but with errors or incorrect results. This is an awkward case;
72 // an invasive captive portal or a restrictive firewall may be intercepting
73 // or rewriting DNS traffic, or the public server may itself be failing or
74 // down.
75 return error_page::DNS_PROBE_FINISHED_INCONCLUSIVE;
78 void HistogramProbe(DnsProbeStatus status, base::TimeDelta elapsed) {
79 DCHECK(error_page::DnsProbeStatusIsFinished(status));
81 UMA_HISTOGRAM_ENUMERATION("DnsProbe.ProbeResult", status,
82 error_page::DNS_PROBE_MAX);
83 UMA_HISTOGRAM_MEDIUM_TIMES("DnsProbe.ProbeDuration", elapsed);
86 } // namespace
88 DnsProbeService::DnsProbeService()
89 : state_(STATE_NO_RESULT) {
90 NetworkChangeNotifier::AddDNSObserver(this);
91 SetSystemClientToCurrentConfig();
92 SetPublicClientToGooglePublicDns();
95 DnsProbeService::~DnsProbeService() {
96 NetworkChangeNotifier::RemoveDNSObserver(this);
99 void DnsProbeService::ProbeDns(const DnsProbeService::ProbeCallback& callback) {
100 pending_callbacks_.push_back(callback);
102 if (CachedResultIsExpired())
103 ClearCachedResult();
105 switch (state_) {
106 case STATE_NO_RESULT:
107 StartProbes();
108 break;
109 case STATE_RESULT_CACHED:
110 CallCallbacks();
111 break;
112 case STATE_PROBE_RUNNING:
113 // Do nothing; probe is already running, and will call the callback.
114 break;
118 void DnsProbeService::OnDNSChanged() {
119 ClearCachedResult();
120 SetSystemClientToCurrentConfig();
123 void DnsProbeService::OnInitialDNSConfigRead() {
124 OnDNSChanged();
127 void DnsProbeService::SetSystemClientForTesting(
128 scoped_ptr<DnsClient> system_client) {
129 system_runner_.SetClient(system_client.Pass());
132 void DnsProbeService::SetPublicClientForTesting(
133 scoped_ptr<DnsClient> public_client) {
134 public_runner_.SetClient(public_client.Pass());
137 void DnsProbeService::ClearCachedResultForTesting() {
138 ClearCachedResult();
141 void DnsProbeService::SetSystemClientToCurrentConfig() {
142 DnsConfig system_config;
143 NetworkChangeNotifier::GetDnsConfig(&system_config);
144 system_config.search.clear();
145 system_config.attempts = 1;
146 system_config.randomize_ports = false;
148 scoped_ptr<DnsClient> system_client(DnsClient::CreateClient(NULL));
149 system_client->SetConfig(system_config);
151 system_runner_.SetClient(system_client.Pass());
154 void DnsProbeService::SetPublicClientToGooglePublicDns() {
155 DnsConfig public_config;
156 public_config.nameservers.push_back(MakeDnsEndPoint(kGooglePublicDns1));
157 public_config.nameservers.push_back(MakeDnsEndPoint(kGooglePublicDns2));
158 public_config.attempts = 1;
159 public_config.randomize_ports = false;
161 scoped_ptr<DnsClient> public_client(DnsClient::CreateClient(NULL));
162 public_client->SetConfig(public_config);
164 public_runner_.SetClient(public_client.Pass());
167 void DnsProbeService::StartProbes() {
168 DCHECK_EQ(STATE_NO_RESULT, state_);
170 DCHECK(!system_runner_.IsRunning());
171 DCHECK(!public_runner_.IsRunning());
173 const base::Closure callback = base::Bind(&DnsProbeService::OnProbeComplete,
174 base::Unretained(this));
175 system_runner_.RunProbe(callback);
176 public_runner_.RunProbe(callback);
177 probe_start_time_ = base::Time::Now();
178 state_ = STATE_PROBE_RUNNING;
180 DCHECK(system_runner_.IsRunning());
181 DCHECK(public_runner_.IsRunning());
184 void DnsProbeService::OnProbeComplete() {
185 DCHECK_EQ(STATE_PROBE_RUNNING, state_);
187 if (system_runner_.IsRunning() || public_runner_.IsRunning())
188 return;
190 cached_result_ = EvaluateResults(system_runner_.result(),
191 public_runner_.result());
192 state_ = STATE_RESULT_CACHED;
194 HistogramProbe(cached_result_, base::Time::Now() - probe_start_time_);
196 CallCallbacks();
199 void DnsProbeService::CallCallbacks() {
200 DCHECK_EQ(STATE_RESULT_CACHED, state_);
201 DCHECK(error_page::DnsProbeStatusIsFinished(cached_result_));
202 DCHECK(!pending_callbacks_.empty());
204 std::vector<ProbeCallback> callbacks;
205 callbacks.swap(pending_callbacks_);
207 for (std::vector<ProbeCallback>::const_iterator i = callbacks.begin();
208 i != callbacks.end(); ++i) {
209 i->Run(cached_result_);
213 void DnsProbeService::ClearCachedResult() {
214 if (state_ == STATE_RESULT_CACHED) {
215 state_ = STATE_NO_RESULT;
216 cached_result_ = error_page::DNS_PROBE_MAX;
220 bool DnsProbeService::CachedResultIsExpired() const {
221 if (state_ != STATE_RESULT_CACHED)
222 return false;
224 const base::TimeDelta kMaxResultAge =
225 base::TimeDelta::FromMilliseconds(kMaxResultAgeMs);
226 return base::Time::Now() - probe_start_time_ > kMaxResultAge;
229 } // namespace chrome_browser_net