NaCl: Update revision in DEPS, r12770 -> r12773
[chromium-blink-merge.git] / chrome / browser / net / dns_probe_service.cc
blob46b23afb4ca7a366c47c059404141d85b5daaba1
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 chrome_common_net::DnsProbeStatus;
19 using net::DnsClient;
20 using net::DnsConfig;
21 using net::IPAddressNumber;
22 using net::IPEndPoint;
23 using net::ParseIPLiteralToNumber;
24 using net::NetworkChangeNotifier;
26 namespace chrome_browser_net {
28 namespace {
30 // How long the DnsProbeService will cache the probe result for.
31 // If it's older than this and we get a probe request, the service expires it
32 // and starts a new probe.
33 const int kMaxResultAgeMs = 5000;
35 // The public DNS servers used by the DnsProbeService to verify internet
36 // connectivity.
37 const char kGooglePublicDns1[] = "8.8.8.8";
38 const char kGooglePublicDns2[] = "8.8.4.4";
40 IPEndPoint MakeDnsEndPoint(const std::string& dns_ip_literal) {
41 IPAddressNumber dns_ip_number;
42 bool rv = ParseIPLiteralToNumber(dns_ip_literal, &dns_ip_number);
43 DCHECK(rv);
44 return IPEndPoint(dns_ip_number, net::dns_protocol::kDefaultPort);
47 DnsProbeStatus EvaluateResults(DnsProbeRunner::Result system_result,
48 DnsProbeRunner::Result public_result) {
49 // If the system DNS is working, assume the domain doesn't exist.
50 if (system_result == DnsProbeRunner::CORRECT)
51 return chrome_common_net::DNS_PROBE_FINISHED_NXDOMAIN;
53 // If the system DNS is unknown (e.g. on Android), but the public server is
54 // reachable, assume the domain doesn't exist.
55 if (system_result == DnsProbeRunner::UNKNOWN &&
56 public_result == DnsProbeRunner::CORRECT) {
57 return chrome_common_net::DNS_PROBE_FINISHED_NXDOMAIN;
60 // If the system DNS is not working but another public server is, assume the
61 // DNS config is bad (or perhaps the DNS servers are down or broken).
62 if (public_result == DnsProbeRunner::CORRECT)
63 return chrome_common_net::DNS_PROBE_FINISHED_BAD_CONFIG;
65 // If the system DNS is not working and another public server is unreachable,
66 // assume the internet connection is down (note that system DNS may be a
67 // router on the LAN, so it may be reachable but returning errors.)
68 if (public_result == DnsProbeRunner::UNREACHABLE)
69 return chrome_common_net::DNS_PROBE_FINISHED_NO_INTERNET;
71 // Otherwise: the system DNS is not working and another public server is
72 // responding but with errors or incorrect results. This is an awkward case;
73 // an invasive captive portal or a restrictive firewall may be intercepting
74 // or rewriting DNS traffic, or the public server may itself be failing or
75 // down.
76 return chrome_common_net::DNS_PROBE_FINISHED_INCONCLUSIVE;
79 void HistogramProbe(DnsProbeStatus status, base::TimeDelta elapsed) {
80 DCHECK(chrome_common_net::DnsProbeStatusIsFinished(status));
82 UMA_HISTOGRAM_ENUMERATION("DnsProbe.ProbeResult", status,
83 chrome_common_net::DNS_PROBE_MAX);
84 UMA_HISTOGRAM_MEDIUM_TIMES("DnsProbe.ProbeDuration", elapsed);
87 } // namespace
89 DnsProbeService::DnsProbeService()
90 : state_(STATE_NO_RESULT) {
91 NetworkChangeNotifier::AddDNSObserver(this);
92 SetSystemClientToCurrentConfig();
93 SetPublicClientToGooglePublicDns();
96 DnsProbeService::~DnsProbeService() {
97 NetworkChangeNotifier::RemoveDNSObserver(this);
100 void DnsProbeService::ProbeDns(const DnsProbeService::ProbeCallback& callback) {
101 pending_callbacks_.push_back(callback);
103 if (CachedResultIsExpired())
104 ClearCachedResult();
106 switch (state_) {
107 case STATE_NO_RESULT:
108 StartProbes();
109 break;
110 case STATE_RESULT_CACHED:
111 CallCallbacks();
112 break;
113 case STATE_PROBE_RUNNING:
114 // Do nothing; probe is already running, and will call the callback.
115 break;
119 void DnsProbeService::OnDNSChanged() {
120 ClearCachedResult();
121 SetSystemClientToCurrentConfig();
124 void DnsProbeService::SetSystemClientForTesting(
125 scoped_ptr<DnsClient> system_client) {
126 system_runner_.SetClient(system_client.Pass());
129 void DnsProbeService::SetPublicClientForTesting(
130 scoped_ptr<DnsClient> public_client) {
131 public_runner_.SetClient(public_client.Pass());
134 void DnsProbeService::ClearCachedResultForTesting() {
135 ClearCachedResult();
138 void DnsProbeService::SetSystemClientToCurrentConfig() {
139 DnsConfig system_config;
140 NetworkChangeNotifier::GetDnsConfig(&system_config);
141 system_config.search.clear();
142 system_config.attempts = 1;
143 system_config.randomize_ports = false;
145 scoped_ptr<DnsClient> system_client(DnsClient::CreateClient(NULL));
146 system_client->SetConfig(system_config);
148 system_runner_.SetClient(system_client.Pass());
151 void DnsProbeService::SetPublicClientToGooglePublicDns() {
152 DnsConfig public_config;
153 public_config.nameservers.push_back(MakeDnsEndPoint(kGooglePublicDns1));
154 public_config.nameservers.push_back(MakeDnsEndPoint(kGooglePublicDns2));
155 public_config.attempts = 1;
156 public_config.randomize_ports = false;
158 scoped_ptr<DnsClient> public_client(DnsClient::CreateClient(NULL));
159 public_client->SetConfig(public_config);
161 public_runner_.SetClient(public_client.Pass());
164 void DnsProbeService::StartProbes() {
165 DCHECK_EQ(STATE_NO_RESULT, state_);
167 DCHECK(!system_runner_.IsRunning());
168 DCHECK(!public_runner_.IsRunning());
170 const base::Closure callback = base::Bind(&DnsProbeService::OnProbeComplete,
171 base::Unretained(this));
172 system_runner_.RunProbe(callback);
173 public_runner_.RunProbe(callback);
174 probe_start_time_ = base::Time::Now();
175 state_ = STATE_PROBE_RUNNING;
177 DCHECK(system_runner_.IsRunning());
178 DCHECK(public_runner_.IsRunning());
181 void DnsProbeService::OnProbeComplete() {
182 DCHECK_EQ(STATE_PROBE_RUNNING, state_);
184 if (system_runner_.IsRunning() || public_runner_.IsRunning())
185 return;
187 cached_result_ = EvaluateResults(system_runner_.result(),
188 public_runner_.result());
189 state_ = STATE_RESULT_CACHED;
191 HistogramProbe(cached_result_, base::Time::Now() - probe_start_time_);
193 CallCallbacks();
196 void DnsProbeService::CallCallbacks() {
197 DCHECK_EQ(STATE_RESULT_CACHED, state_);
198 DCHECK(chrome_common_net::DnsProbeStatusIsFinished(cached_result_));
199 DCHECK(!pending_callbacks_.empty());
201 std::vector<ProbeCallback> callbacks;
202 callbacks.swap(pending_callbacks_);
204 for (std::vector<ProbeCallback>::const_iterator i = callbacks.begin();
205 i != callbacks.end(); ++i) {
206 i->Run(cached_result_);
210 void DnsProbeService::ClearCachedResult() {
211 if (state_ == STATE_RESULT_CACHED) {
212 state_ = STATE_NO_RESULT;
213 cached_result_ = chrome_common_net::DNS_PROBE_MAX;
217 bool DnsProbeService::CachedResultIsExpired() const {
218 if (state_ != STATE_RESULT_CACHED)
219 return false;
221 const base::TimeDelta kMaxResultAge =
222 base::TimeDelta::FromMilliseconds(kMaxResultAgeMs);
223 return base::Time::Now() - probe_start_time_ > kMaxResultAge;
226 } // namespace chrome_browser_net