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; |
+} |