Chromium Code Reviews| Index: chrome/browser/net/dns_probe_runner.cc |
| diff --git a/chrome/browser/net/dns_probe_runner.cc b/chrome/browser/net/dns_probe_runner.cc |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..74d91fb7091469433955772c5a7b5d50abee8548 |
| --- /dev/null |
| +++ b/chrome/browser/net/dns_probe_runner.cc |
| @@ -0,0 +1,258 @@ |
| +// Copyright (c) 2013 The Chromium Authors. All rights reserved. |
| +// Use of this source code is governed by a BSD-style license that can be |
| +// found in the LICENSE file. |
| + |
| +#include "chrome/browser/net/dns_probe_runner.h" |
| + |
| +#include "base/bind.h" |
| +#include "base/memory/scoped_ptr.h" |
| +#include "net/base/ip_endpoint.h" |
| +#include "net/base/net_errors.h" |
| +#include "net/base/net_log.h" |
| +#include "net/base/net_util.h" |
| +#include "net/base/network_change_notifier.h" |
| +#include "net/dns/dns_client.h" |
| +#include "net/dns/dns_config_service.h" |
| +#include "net/dns/dns_protocol.h" |
| +#include "net/dns/dns_response.h" |
| +#include "net/dns/dns_transaction.h" |
| + |
| +using base::TimeDelta; |
| +using net::AddressList; |
| +using net::BoundNetLog; |
| +using net::DnsClient; |
| +using net::DnsConfig; |
| +using net::DnsResponse; |
| +using net::DnsTransaction; |
| +using net::IPAddressNumber; |
| +using net::IPEndPoint; |
| +using net::NetLog; |
| +using net::NetworkChangeNotifier; |
| +using net::ParseIPLiteralToNumber; |
| + |
| +namespace { |
| + |
| +// 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"; |
| + |
| +IPEndPoint MakeDnsEndPoint(const std::string& dns_ip_literal) { |
| + IPAddressNumber dns_ip_number; |
| + bool rv = ParseIPLiteralToNumber(dns_ip_literal, &dns_ip_number); |
| + DCHECK(rv); |
| + return IPEndPoint(dns_ip_number, net::dns_protocol::kDefaultPort); |
| +} |
| + |
| +// Returns true if the given net_error indicates that we received a response |
| +// from the DNS server containing an error, or false if the given net_error |
| +// indicates that we never received a response. |
| +bool DidReceiveDnsResponse(int net_error) { |
| + switch (net_error) { |
| + case net::ERR_NAME_NOT_RESOLVED: // NXDOMAIN maps to this. |
| + case net::ERR_DNS_MALFORMED_RESPONSE: |
| + case net::ERR_DNS_SERVER_REQUIRES_TCP: |
| + case net::ERR_DNS_SERVER_FAILED: |
| + case net::ERR_DNS_SORT_ERROR: // Can only happen if the server responds. |
| + return true; |
| + default: |
| + return false; |
| + } |
| +} |
| + |
| +} // namespace |
| + |
| +DnsProbeRunner::ProbeInfo::ProbeInfo( |
| + DnsProbeRunner::Type type, |
| + const DnsProbeRunner::ProbeCallback& callback) |
| + : type(type), |
| + callback(callback) {} |
| + |
| +DnsProbeRunner::ProbeInfo::~ProbeInfo() {} |
| + |
| +DnsProbeRunner::DnsProbeRunner() |
| + : weak_factory_(this), |
| + bound_net_log_(BoundNetLog::Make(NULL, NetLog::SOURCE_DNS_PROBER)), |
| + mock_mode_(DnsProbeRunner::NO_MOCK) { |
| + NetworkChangeNotifier::AddDNSObserver(this); |
| + InitializeSystemClient(); |
| + InitializePublicClient(); |
| +} |
| + |
| +DnsProbeRunner::~DnsProbeRunner() { |
| + NetworkChangeNotifier::RemoveDNSObserver(this); |
| + for (TransactionMap::iterator it = pending_transactions_.begin(); |
| + it != pending_transactions_.end(); ++it) { |
| + delete it->first; |
| + } |
| +} |
| + |
| +void DnsProbeRunner::OnDNSChanged() { |
| + InitializeSystemClient(); |
|
szym
2013/06/07 19:31:28
Note that this does not affect any pending transac
Deprecated (see juliatuttle)
2013/06/11 01:07:34
That's okay; error pages can be obsolete for other
|
| +} |
| + |
| +void DnsProbeRunner::RunProbe(Type type, |
| + const ProbeCallback& callback) { |
| + if (mock_mode_ == MOCK_RESULTS) { |
| + callback.Run(type, GetMockResult(type)); |
| + return; |
| + } |
| + |
| + DnsTransaction* transaction = |
| + GetClient(type)->GetTransactionFactory()->CreateTransaction( |
| + "google.com", |
| + net::dns_protocol::kTypeA, |
| + base::Bind(&DnsProbeRunner::OnTransactionComplete, |
| + weak_factory_.GetWeakPtr(), |
| + true /* async */), |
| + bound_net_log_).release(); |
| + |
| + pending_transactions_.insert(std::pair<DnsTransaction*,ProbeInfo>( |
| + transaction, |
| + ProbeInfo(type, callback))); |
|
szym
2013/06/07 19:31:28
Instead bind ProbeInfo as an argument to OnTransac
Deprecated (see juliatuttle)
2013/06/11 01:07:34
Obsolete.
|
| + |
| + int rv = transaction->Start(); |
| + if (rv != net::ERR_IO_PENDING) { |
| + OnTransactionComplete(false /* not async */, |
| + transaction, |
| + rv, |
| + NULL); |
| + } |
| +} |
| + |
| +void DnsProbeRunner::SetClientsForTesting( |
| + scoped_ptr<DnsClient> mock_system_client, |
| + scoped_ptr<DnsClient> mock_public_client) { |
| + DCHECK_EQ(NO_MOCK, mock_mode_); |
| + DCHECK(mock_system_client.get()); |
| + DCHECK(mock_public_client.get()); |
| + |
| + mock_mode_ = MOCK_CLIENTS; |
| + mock_system_client_ = mock_system_client.Pass(); |
| + mock_public_client_ = mock_public_client.Pass(); |
| +} |
| + |
| +void DnsProbeRunner::SetResultsForTesting( |
| + Result system_result, |
| + Result public_result) { |
| + mock_mode_ = MOCK_RESULTS; |
| + mock_system_result_ = system_result; |
| + mock_public_result_ = public_result; |
| + mock_system_client_.reset(); |
| + mock_public_client_.reset(); |
| +} |
| + |
| +void DnsProbeRunner::InitializeSystemClient() { |
| + DnsConfig config; |
| + NetworkChangeNotifier::GetDnsConfig(&config); |
| + config.search.clear(); |
| + config.attempts = 1; |
| + config.randomize_ports = false; |
| + |
| + scoped_ptr<DnsClient> client = DnsClient::CreateClient(NULL); |
| + client->SetConfig(config); |
| + |
| + system_client_ = client.Pass(); |
| +} |
| + |
| +void DnsProbeRunner::InitializePublicClient() { |
| + DnsConfig config; |
| + config.nameservers.push_back(MakeDnsEndPoint(kPublicDnsPrimary)); |
| + config.nameservers.push_back(MakeDnsEndPoint(kPublicDnsSecondary)); |
| + config.search.clear(); |
| + config.attempts = 1; |
| + config.randomize_ports = false; |
| + |
| + scoped_ptr<DnsClient> client = DnsClient::CreateClient(NULL); |
| + client->SetConfig(config); |
| + |
| + public_client_ = client.Pass(); |
| +} |
| + |
| +DnsProbeRunner::Result DnsProbeRunner::GetMockResult(Type type) { |
| + DCHECK_EQ(MOCK_RESULTS, mock_mode_); |
| + |
| + switch (type) { |
| + case SYSTEM: |
| + return mock_system_result_; |
| + case PUBLIC: |
| + return mock_public_result_; |
| + } |
| + |
| + NOTREACHED(); |
| + return UNKNOWN; |
| +} |
| + |
| +DnsClient* DnsProbeRunner::GetClient(Type type) { |
| + DCHECK_NE(MOCK_RESULTS, mock_mode_); |
| + |
| + switch (mock_mode_) { |
| + case NO_MOCK: |
| + switch (type) { |
| + case SYSTEM: |
| + return system_client_.get(); |
| + case PUBLIC: |
| + return public_client_.get(); |
| + } |
| + case MOCK_CLIENTS: |
| + switch (type) { |
| + case SYSTEM: |
| + return mock_system_client_.get(); |
| + case PUBLIC: |
| + return mock_public_client_.get(); |
| + } |
| + case MOCK_RESULTS: |
| + NOTREACHED(); |
| + return NULL; |
| + } |
| + |
| + NOTREACHED(); |
| + return NULL; |
| +} |
| + |
| +void DnsProbeRunner::OnTransactionComplete( |
| + bool async, |
| + DnsTransaction* transaction, |
| + int net_error, |
| + const DnsResponse* response) { |
| + TransactionMap::iterator it = pending_transactions_.find(transaction); |
| + // I'd use DCHECK_NE, but it doesn't know how to print iterators. |
| + DCHECK(it != pending_transactions_.end()); |
| + |
| + const ProbeInfo& info = it->second; |
| + const Result result = EvaluateResponse(async, net_error, response); |
| + info.callback.Run(info.type, result); |
| + |
| + pending_transactions_.erase(it); |
| +} |
| + |
| +DnsProbeRunner::Result DnsProbeRunner::EvaluateResponse( |
| + bool async, |
| + int net_error, |
| + const DnsResponse* response) { |
| + if (!async) { |
|
szym
2013/06/07 19:31:28
I'm not sure you need this. The net_error returned
Deprecated (see juliatuttle)
2013/06/11 01:07:34
I don't *need* it, but I want to be explicit about
|
| + return UNREACHABLE; |
| + } |
| + |
| + if (net_error != net::OK) { |
| + if (DidReceiveDnsResponse(net_error)) { |
| + return FAILING; |
| + } else { |
| + return UNREACHABLE; |
| + } |
| + } |
| + |
| + AddressList addr_list; |
| + TimeDelta ttl; |
| + DnsResponse::Result result = response->ParseToAddressList(&addr_list, &ttl); |
| + |
| + if (result != DnsResponse::DNS_PARSE_OK) { |
| + return FAILING; |
| + } |
| + |
| + if (addr_list.empty()) { |
| + return INCORRECT; |
| + } |
| + |
| + return CORRECT; |
| +} |