Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1986)

Unified Diff: chrome/browser/net/dns_probe_service.cc

Issue 13270005: Display DNS probe results. (Closed) Base URL: http://git.chromium.org/chromium/src.git@master
Patch Set: Created 7 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: chrome/browser/net/dns_probe_service.cc
diff --git a/chrome/browser/net/dns_probe_service.cc b/chrome/browser/net/dns_probe_service.cc
index 156313f796c4e1f560b8b4235bc30737c66c71aa..fb6b60760c1c2126f85c57da09da181aec8db8e5 100644
--- a/chrome/browser/net/dns_probe_service.cc
+++ b/chrome/browser/net/dns_probe_service.cc
@@ -7,8 +7,6 @@
#include "base/metrics/field_trial.h"
#include "base/metrics/histogram.h"
#include "base/strings/string_number_conversions.h"
-#include "chrome/browser/net/dns_probe_job.h"
-#include "chrome/common/net/net_error_info.h"
#include "net/base/ip_endpoint.h"
#include "net/base/net_util.h"
#include "net/dns/dns_client.h"
@@ -17,7 +15,7 @@
using base::FieldTrialList;
using base::StringToInt;
-using chrome_common_net::DnsProbeResult;
+using chrome_common_net::DnsProbeStatus;
using net::DnsClient;
using net::DnsConfig;
using net::IPAddressNumber;
@@ -36,8 +34,8 @@ const int kMaxResultAgeMs = 5000;
// The public DNS servers used by the DnsProbeService to verify internet
// connectivity.
-const char kPublicDnsPrimary[] = "8.8.8.8";
-const char kPublicDnsSecondary[] = "8.8.4.4";
+const char kGooglePublicDns1[] = "8.8.8.8";
+const char kGooglePublicDns2[] = "8.8.4.4";
IPEndPoint MakeDnsEndPoint(const std::string& dns_ip_literal) {
IPAddressNumber dns_ip_number;
@@ -46,299 +44,217 @@ IPEndPoint MakeDnsEndPoint(const std::string& dns_ip_literal) {
return IPEndPoint(dns_ip_number, net::dns_protocol::kDefaultPort);
}
-const int kAttemptsUseDefault = -1;
-
-const char kAttemptsFieldTrialName[] = "DnsProbe-Attempts";
+DnsProbeStatus EvaluateResults(DnsProbeRunner::Result system_result,
+ DnsProbeRunner::Result public_result) {
+ // If the system DNS is working, assume the domain doesn't exist.
+ if (system_result == DnsProbeRunner::CORRECT)
+ return chrome_common_net::DNS_PROBE_FINISHED_NXDOMAIN;
-int GetAttemptsFromFieldTrial() {
- std::string group = FieldTrialList::FindFullName(kAttemptsFieldTrialName);
- if (group == "" || group == "default")
- return kAttemptsUseDefault;
+ // If the system DNS is not working but another public server is, assume the
+ // DNS config is bad (or perhaps the DNS servers are down or broken).
+ if (public_result == DnsProbeRunner::CORRECT)
+ return chrome_common_net::DNS_PROBE_FINISHED_BAD_CONFIG;
- int attempts;
- if (!StringToInt(group, &attempts))
- return kAttemptsUseDefault;
+ // If the system DNS is not working and another public server is unreachable,
+ // assume the internet connection is down (note that system DNS may be a
+ // router on the LAN, so it may be reachable but returning errors.)
+ if (public_result == DnsProbeRunner::UNREACHABLE)
+ return chrome_common_net::DNS_PROBE_FINISHED_NO_INTERNET;
- return attempts;
+ // Otherwise: the system DNS is not working and another public server is
+ // responding but with errors or incorrect results. This is an awkward case;
+ // an invasive captive portal or a restrictive firewall may be intercepting
+ // or rewriting DNS traffic, or the public server may itself be failing or
+ // down.
+ return chrome_common_net::DNS_PROBE_FINISHED_UNKNOWN;
}
-bool IsLocalhost(const IPAddressNumber& ip) {
- return (ip.size() == net::kIPv4AddressSize)
- && (ip[0] == 127) && (ip[1] == 0) && (ip[2] == 0) && (ip[3] == 1);
-}
+void HistogramProbe(DnsProbeStatus status, base::TimeDelta elapsed) {
+ DCHECK(chrome_common_net::DnsProbeStatusIsFinished(status));
+
+ int result = status - chrome_common_net::DNS_PROBE_FINISHED_UNKNOWN;
+
+ const int kMaxResult = chrome_common_net::DNS_PROBE_MAX -
+ chrome_common_net::DNS_PROBE_FINISHED_UNKNOWN;
-// The maximum number of nameservers counted in histograms.
-const int kNameserverCountMax = 10;
+ UMA_HISTOGRAM_ENUMERATION("DnsProbe.Status", result, kMaxResult);
+ UMA_HISTOGRAM_MEDIUM_TIMES("DnsProbe.Elapsed", elapsed);
+
+ if (NetworkChangeNotifier::IsOffline()) {
+ UMA_HISTOGRAM_ENUMERATION("DnsProbe.Status_NcnOffline",
+ result, kMaxResult);
+ UMA_HISTOGRAM_MEDIUM_TIMES("DnsProbe.Elapsed_NcnOffline", elapsed);
+ } else {
+ UMA_HISTOGRAM_ENUMERATION("DnsProbe.Status_NcnOnline",
+ result, kMaxResult);
+ UMA_HISTOGRAM_MEDIUM_TIMES("DnsProbe.Elapsed_NcnOnline", elapsed);
+ }
+
+ switch (status) {
+ case chrome_common_net::DNS_PROBE_FINISHED_UNKNOWN:
+ UMA_HISTOGRAM_MEDIUM_TIMES("DnsProbe.Elapsed_Unknown",
+ elapsed);
+ break;
+ case chrome_common_net::DNS_PROBE_FINISHED_NO_INTERNET:
+ UMA_HISTOGRAM_MEDIUM_TIMES("DnsProbe.Elapsed_NoInternet",
+ elapsed);
+ break;
+ case chrome_common_net::DNS_PROBE_FINISHED_BAD_CONFIG:
+ UMA_HISTOGRAM_MEDIUM_TIMES("DnsProbe.Elapsed_BadConfig",
+ elapsed);
+ break;
+ case chrome_common_net::DNS_PROBE_FINISHED_NXDOMAIN:
+ UMA_HISTOGRAM_MEDIUM_TIMES("DnsProbe.Elapsed_Nxdomain",
+ elapsed);
+ break;
+
+ // These aren't actually results.
+ case chrome_common_net::DNS_PROBE_POSSIBLE:
+ case chrome_common_net::DNS_PROBE_NOT_RUN:
+ case chrome_common_net::DNS_PROBE_STARTED:
+ case chrome_common_net::DNS_PROBE_MAX:
+ NOTREACHED();
+ break;
+ }
+}
} // namespace
DnsProbeService::DnsProbeService()
- : system_result_(DnsProbeJob::SERVERS_UNKNOWN),
- public_result_(DnsProbeJob::SERVERS_UNKNOWN),
- state_(STATE_NO_RESULTS),
- result_(chrome_common_net::DNS_PROBE_UNKNOWN),
- dns_attempts_(GetAttemptsFromFieldTrial()) {
- NetworkChangeNotifier::AddIPAddressObserver(this);
+ : state_(STATE_NO_RESULT) {
+ NetworkChangeNotifier::AddDNSObserver(this);
+ SetSystemClientToCurrentConfig();
+ SetPublicClientToGooglePublicDns();
}
DnsProbeService::~DnsProbeService() {
- NetworkChangeNotifier::RemoveIPAddressObserver(this);
+ NetworkChangeNotifier::RemoveDNSObserver(this);
}
-void DnsProbeService::ProbeDns(const DnsProbeService::CallbackType& callback) {
- callbacks_.push_back(callback);
+void DnsProbeService::ProbeDns(const DnsProbeService::ProbeCallback& callback) {
+ pending_callbacks_.push_back(callback);
- if (state_ == STATE_RESULTS_CACHED && ResultsExpired())
- ExpireResults();
+ if (CachedResultIsExpired())
+ ClearCachedResult();
switch (state_) {
- case STATE_NO_RESULTS:
- StartProbes();
- break;
- case STATE_RESULTS_CACHED:
- CallCallbacks();
- break;
- case STATE_PROBE_RUNNING:
- // do nothing; probe is already running, and will call the callback
- break;
+ case STATE_NO_RESULT:
+ StartProbes();
+ break;
+ case STATE_RESULT_CACHED:
+ CallCallbacks();
+ break;
+ case STATE_PROBE_RUNNING:
+ // Do nothing; probe is already running, and will call the callback.
+ break;
}
}
-scoped_ptr<DnsProbeJob> DnsProbeService::CreateSystemProbeJob(
- const DnsProbeJob::CallbackType& job_callback) {
- DnsConfig system_config;
- GetSystemDnsConfig(&system_config);
- return CreateProbeJob(system_config, job_callback);
+void DnsProbeService::OnDNSChanged() {
+ ClearCachedResult();
+ SetSystemClientToCurrentConfig();
}
-scoped_ptr<DnsProbeJob> DnsProbeService::CreatePublicProbeJob(
- const DnsProbeJob::CallbackType& job_callback) {
- DnsConfig public_config;
- GetPublicDnsConfig(&public_config);
- return CreateProbeJob(public_config, job_callback);
+void DnsProbeService::SetSystemClientForTesting(
+ scoped_ptr<DnsClient> system_client) {
+ system_runner_.SetClient(system_client.Pass());
}
-void DnsProbeService::OnIPAddressChanged() {
- if (state_ == STATE_RESULTS_CACHED)
- ExpireResults();
+void DnsProbeService::SetPublicClientForTesting(
+ scoped_ptr<DnsClient> public_client) {
+ public_runner_.SetClient(public_client.Pass());
}
-void DnsProbeService::ExpireResults() {
- DCHECK_EQ(STATE_RESULTS_CACHED, state_);
-
- state_ = STATE_NO_RESULTS;
- result_ = chrome_common_net::DNS_PROBE_UNKNOWN;
+void DnsProbeService::ClearCachedResultForTesting() {
+ ClearCachedResult();
}
-void DnsProbeService::StartProbes() {
- DCHECK_NE(STATE_PROBE_RUNNING, state_);
- DCHECK(!system_job_.get());
- DCHECK(!public_job_.get());
-
- DnsProbeJob::CallbackType job_callback =
- base::Bind(&DnsProbeService::OnProbeJobComplete,
- base::Unretained(this));
-
- // TODO(ttuttle): Do we want to keep explicit flags for "job done"?
- // Or maybe DnsProbeJob should have a "finished" flag?
- system_result_ = DnsProbeJob::SERVERS_UNKNOWN;
- public_result_ = DnsProbeJob::SERVERS_UNKNOWN;
-
- system_job_ = CreateSystemProbeJob(job_callback);
- public_job_ = CreatePublicProbeJob(job_callback);
-
- // If we can't create one or both jobs, fail the probe immediately.
- if (!system_job_.get() || !public_job_.get()) {
- system_job_.reset();
- public_job_.reset();
- state_ = STATE_RESULTS_CACHED;
- // TODO(ttuttle): Should this be BAD_CONFIG? Currently I think it only
- // happens when the system DnsConfig has no servers.
- result_ = chrome_common_net::DNS_PROBE_UNKNOWN;
- CallCallbacks();
- return;
- }
+void DnsProbeService::SetSystemClientToCurrentConfig() {
+ DnsConfig system_config;
+ NetworkChangeNotifier::GetDnsConfig(&system_config);
+ system_config.search.clear();
+ system_config.attempts = 1;
+ system_config.randomize_ports = false;
- state_ = STATE_PROBE_RUNNING;
- probe_start_time_ = base::Time::Now();
-}
+ scoped_ptr<DnsClient> system_client(DnsClient::CreateClient(NULL));
+ system_client->SetConfig(system_config);
-void DnsProbeService::OnProbesComplete() {
- DCHECK_EQ(STATE_PROBE_RUNNING, state_);
+ system_runner_.SetClient(system_client.Pass());
+}
- state_ = STATE_RESULTS_CACHED;
- result_ = EvaluateResults();
+void DnsProbeService::SetPublicClientToGooglePublicDns() {
+ DnsConfig public_config;
+ public_config.nameservers.push_back(MakeDnsEndPoint(kGooglePublicDns1));
+ public_config.nameservers.push_back(MakeDnsEndPoint(kGooglePublicDns2));
+ public_config.attempts = 1;
+ public_config.randomize_ports = false;
- HistogramProbes();
+ scoped_ptr<DnsClient> public_client(DnsClient::CreateClient(NULL));
+ public_client->SetConfig(public_config);
- CallCallbacks();
+ public_runner_.SetClient(public_client.Pass());
}
-void DnsProbeService::HistogramProbes() const {
- const DnsProbeResult kMaxResult = chrome_common_net::DNS_PROBE_MAX;
-
- DCHECK_EQ(STATE_RESULTS_CACHED, state_);
- DCHECK_NE(kMaxResult, result_);
-
- base::TimeDelta elapsed = base::Time::Now() - probe_start_time_;
+void DnsProbeService::StartProbes() {
+ DCHECK_EQ(STATE_NO_RESULT, state_);
- UMA_HISTOGRAM_ENUMERATION("DnsProbe.Probe.Result", result_, kMaxResult);
- UMA_HISTOGRAM_MEDIUM_TIMES("DnsProbe.Probe.Elapsed", elapsed);
+ DCHECK(!system_runner_.IsRunning());
+ DCHECK(!public_runner_.IsRunning());
- if (NetworkChangeNotifier::IsOffline()) {
- UMA_HISTOGRAM_ENUMERATION("DnsProbe.Probe.NcnOffline.Result",
- result_, kMaxResult);
- UMA_HISTOGRAM_MEDIUM_TIMES("DnsProbe.Probe.NcnOffline.Elapsed", elapsed);
- } else {
- UMA_HISTOGRAM_ENUMERATION("DnsProbe.Probe.NcnOnline.Result",
- result_, kMaxResult);
- UMA_HISTOGRAM_MEDIUM_TIMES("DnsProbe.Probe.NcnOnline.Elapsed", elapsed);
- }
+ const base::Closure callback = base::Bind(&DnsProbeService::OnProbeComplete,
+ base::Unretained(this));
+ system_runner_.RunProbe(callback);
+ public_runner_.RunProbe(callback);
+ probe_start_time_ = base::Time::Now();
+ state_ = STATE_PROBE_RUNNING;
- switch (result_) {
- case chrome_common_net::DNS_PROBE_UNKNOWN:
- UMA_HISTOGRAM_MEDIUM_TIMES("DnsProbe.Probe.ResultUnknown.Elapsed",
- elapsed);
- break;
- case chrome_common_net::DNS_PROBE_NO_INTERNET:
- UMA_HISTOGRAM_MEDIUM_TIMES("DnsProbe.Probe.ResultNoInternet.Elapsed",
- elapsed);
- break;
- case chrome_common_net::DNS_PROBE_BAD_CONFIG:
- UMA_HISTOGRAM_MEDIUM_TIMES("DnsProbe.Probe.ResultBadConfig.Elapsed",
- elapsed);
-
- // Histogram some extra data to see why BAD_CONFIG is happening.
- UMA_HISTOGRAM_ENUMERATION(
- "DnsProbe.Probe.ResultBadConfig.SystemJobResult",
- system_result_,
- DnsProbeJob::MAX_RESULT);
- UMA_HISTOGRAM_CUSTOM_COUNTS(
- "DnsProbe.Probe.ResultBadConfig.SystemNameserverCount",
- system_nameserver_count_,
- 0, kNameserverCountMax, kNameserverCountMax + 1);
- UMA_HISTOGRAM_BOOLEAN(
- "DnsProbe.Probe.ResultBadConfig.SystemIsLocalhost",
- system_is_localhost_);
- break;
- case chrome_common_net::DNS_PROBE_NXDOMAIN:
- UMA_HISTOGRAM_MEDIUM_TIMES("DnsProbe.Probe.ResultNxdomain.Elapsed",
- elapsed);
- break;
- case chrome_common_net::DNS_PROBE_MAX:
- NOTREACHED();
- break;
- }
+ DCHECK(system_runner_.IsRunning());
+ DCHECK(public_runner_.IsRunning());
}
-DnsProbeResult DnsProbeService::EvaluateResults() const {
- DCHECK_NE(DnsProbeJob::SERVERS_UNKNOWN, system_result_);
- DCHECK_NE(DnsProbeJob::SERVERS_UNKNOWN, public_result_);
+void DnsProbeService::OnProbeComplete() {
+ DCHECK_EQ(STATE_PROBE_RUNNING, state_);
- // If the system DNS is working, assume the domain doesn't exist.
- if (system_result_ == DnsProbeJob::SERVERS_CORRECT)
- return chrome_common_net::DNS_PROBE_NXDOMAIN;
+ if (system_runner_.IsRunning() || public_runner_.IsRunning())
+ return;
- // If the system DNS is not working but another public server is, assume the
- // DNS config is bad (or perhaps the DNS servers are down or broken).
- if (public_result_ == DnsProbeJob::SERVERS_CORRECT)
- return chrome_common_net::DNS_PROBE_BAD_CONFIG;
+ cached_result_ = EvaluateResults(system_runner_.result(),
+ public_runner_.result());
+ state_ = STATE_RESULT_CACHED;
- // If the system DNS is not working and another public server is unreachable,
- // assume the internet connection is down (note that system DNS may be a
- // router on the LAN, so it may be reachable but returning errors.)
- if (public_result_ == DnsProbeJob::SERVERS_UNREACHABLE)
- return chrome_common_net::DNS_PROBE_NO_INTERNET;
+ HistogramProbe(cached_result_, base::Time::Now() - probe_start_time_);
- // Otherwise: the system DNS is not working and another public server is
- // responding but with errors or incorrect results. This is an awkward case;
- // an invasive captive portal or a restrictive firewall may be intercepting
- // or rewriting DNS traffic, or the public server may itself be failing or
- // down.
- return chrome_common_net::DNS_PROBE_UNKNOWN;
+ CallCallbacks();
}
void DnsProbeService::CallCallbacks() {
- DCHECK_EQ(STATE_RESULTS_CACHED, state_);
- DCHECK(!callbacks_.empty());
+ DCHECK_EQ(STATE_RESULT_CACHED, state_);
+ DCHECK(chrome_common_net::DnsProbeStatusIsFinished(cached_result_));
+ DCHECK(!pending_callbacks_.empty());
- std::vector<CallbackType> callbacks = callbacks_;
- callbacks_.clear();
+ std::vector<ProbeCallback> callbacks;
+ callbacks.swap(pending_callbacks_);
- for (std::vector<CallbackType>::const_iterator i = callbacks.begin();
+ for (std::vector<ProbeCallback>::const_iterator i = callbacks.begin();
i != callbacks.end(); ++i) {
- i->Run(result_);
+ i->Run(cached_result_);
}
}
-scoped_ptr<DnsProbeJob> DnsProbeService::CreateProbeJob(
- const DnsConfig& dns_config,
- const DnsProbeJob::CallbackType& job_callback) {
- if (!dns_config.IsValid())
- return scoped_ptr<DnsProbeJob>();
-
- scoped_ptr<DnsClient> dns_client(DnsClient::CreateClient(NULL));
- dns_client->SetConfig(dns_config);
- return DnsProbeJob::CreateJob(dns_client.Pass(), job_callback, NULL);
-}
-
-void DnsProbeService::OnProbeJobComplete(DnsProbeJob* job,
- DnsProbeJob::Result result) {
- DCHECK_EQ(STATE_PROBE_RUNNING, state_);
-
- if (job == system_job_.get()) {
- system_result_ = result;
- system_job_.reset();
- } else if (job == public_job_.get()) {
- public_result_ = result;
- public_job_.reset();
- } else {
- NOTREACHED();
- return;
- }
-
- if (system_result_ != DnsProbeJob::SERVERS_UNKNOWN &&
- public_result_ != DnsProbeJob::SERVERS_UNKNOWN) {
- OnProbesComplete();
+void DnsProbeService::ClearCachedResult() {
+ if (state_ == STATE_RESULT_CACHED) {
+ state_ = STATE_NO_RESULT;
+ cached_result_ = chrome_common_net::DNS_PROBE_MAX;
}
}
-void DnsProbeService::GetSystemDnsConfig(DnsConfig* config) {
- NetworkChangeNotifier::GetDnsConfig(config);
-
- // DNS probes don't need or want the suffix search list populated
- config->search.clear();
-
- if (dns_attempts_ != kAttemptsUseDefault)
- config->attempts = dns_attempts_;
-
- // Take notes in case the config turns out to be bad, so we can histogram
- // some useful data.
- system_nameserver_count_ = config->nameservers.size();
- system_is_localhost_ = (system_nameserver_count_ == 1)
- && IsLocalhost(config->nameservers[0].address());
-
- // Disable port randomization.
- config->randomize_ports = false;
-}
-
-void DnsProbeService::GetPublicDnsConfig(DnsConfig* config) {
- *config = DnsConfig();
-
- config->nameservers.push_back(MakeDnsEndPoint(kPublicDnsPrimary));
- config->nameservers.push_back(MakeDnsEndPoint(kPublicDnsSecondary));
-
- if (dns_attempts_ != kAttemptsUseDefault)
- config->attempts = dns_attempts_;
-
- // Disable port randomization.
- config->randomize_ports = false;
-}
+bool DnsProbeService::CachedResultIsExpired() const {
+ if (state_ != STATE_RESULT_CACHED)
+ return false;
-bool DnsProbeService::ResultsExpired() {
const base::TimeDelta kMaxResultAge =
base::TimeDelta::FromMilliseconds(kMaxResultAgeMs);
return base::Time::Now() - probe_start_time_ > kMaxResultAge;
}
-} // namespace chrome_browser_net
+} // namespace chrome_browser_net

Powered by Google App Engine
This is Rietveld 408576698