1 // Copyright 2013 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.
4
5 #include "chrome/browser/net/dns_probe_runner.h"
6
7 #include "base/bind.h"
8 #include "content/public/browser/browser_thread.h"
9 #include "net/base/address_list.h"
10 #include "net/base/ip_endpoint.h"
11 #include "net/base/net_errors.h"
12 #include "net/base/net_log.h"
13 #include "net/base/net_util.h"
14 #include "net/base/network_change_notifier.h"
15 #include "net/dns/dns_client.h"
16 #include "net/dns/dns_protocol.h"
17 #include "net/dns/dns_response.h"
18 #include "net/dns/dns_transaction.h"
19
20 using base::TimeDelta;
21 using content::BrowserThread;
22 using net::AddressList;
23 using net::BoundNetLog;
24 using net::DnsClient;
25 using net::DnsResponse;
26 using net::DnsTransaction;
27 using net::DnsTransactionFactory;
28 using net::IPAddressNumber;
29 using net::IPEndPoint;
30 using net::NetLog;
31 using net::NetworkChangeNotifier;
32 using net::ParseIPLiteralToNumber;
33
34 namespace chrome_browser_net {
35
36 const char* DnsProbeRunner::kKnownGoodHostname = "google.com";
37
38 namespace {
39
EvaluateResponse(int net_error,const DnsResponse * response)40 DnsProbeRunner::Result EvaluateResponse(
41 int net_error,
42 const DnsResponse* response) {
43 switch (net_error) {
44 case net::OK:
45 break;
46
47 // ERR_NAME_NOT_RESOLVED maps to NXDOMAIN, which means the server is working
48 // but returned a wrong answer.
49 case net::ERR_NAME_NOT_RESOLVED:
50 return DnsProbeRunner::INCORRECT;
51
52 // These results mean we heard *something* from the DNS server, but it was
53 // unsuccessful (SERVFAIL) or malformed.
54 case net::ERR_DNS_MALFORMED_RESPONSE:
55 case net::ERR_DNS_SERVER_REQUIRES_TCP: // Shouldn't happen; DnsTransaction
56 // will retry with TCP.
57 case net::ERR_DNS_SERVER_FAILED:
58 case net::ERR_DNS_SORT_ERROR: // Can only happen if the server responds.
59 return DnsProbeRunner::FAILING;
60
61 // Any other error means we never reached the DNS server in the first place.
62 case net::ERR_DNS_TIMED_OUT:
63 default:
64 // Something else happened, probably at a network level.
65 return DnsProbeRunner::UNREACHABLE;
66 }
67
68 AddressList addr_list;
69 TimeDelta ttl;
70 DnsResponse::Result result = response->ParseToAddressList(&addr_list, &ttl);
71
72 if (result != DnsResponse::DNS_PARSE_OK)
73 return DnsProbeRunner::FAILING;
74 else if (addr_list.empty())
75 return DnsProbeRunner::INCORRECT;
76 else
77 return DnsProbeRunner::CORRECT;
78 }
79
80 } // namespace
81
DnsProbeRunner()82 DnsProbeRunner::DnsProbeRunner() : weak_factory_(this), result_(UNKNOWN) {}
83
~DnsProbeRunner()84 DnsProbeRunner::~DnsProbeRunner() {}
85
SetClient(scoped_ptr<net::DnsClient> client)86 void DnsProbeRunner::SetClient(scoped_ptr<net::DnsClient> client) {
87 client_ = client.Pass();
88 }
89
RunProbe(const base::Closure & callback)90 void DnsProbeRunner::RunProbe(const base::Closure& callback) {
91 DCHECK(!callback.is_null());
92 DCHECK(client_.get());
93 DCHECK(callback_.is_null());
94 DCHECK(!transaction_.get());
95
96 callback_ = callback;
97 DnsTransactionFactory* factory = client_->GetTransactionFactory();
98 if (!factory) {
99 // If the DnsTransactionFactory is NULL, then the DnsConfig is invalid, so
100 // the runner can't run a transaction. Return UNKNOWN asynchronously.
101 result_ = UNKNOWN;
102 BrowserThread::PostTask(
103 BrowserThread::IO,
104 FROM_HERE,
105 base::Bind(&DnsProbeRunner::CallCallback,
106 weak_factory_.GetWeakPtr()));
107 return;
108 }
109
110 transaction_ = factory->CreateTransaction(
111 kKnownGoodHostname,
112 net::dns_protocol::kTypeA,
113 base::Bind(&DnsProbeRunner::OnTransactionComplete,
114 weak_factory_.GetWeakPtr()),
115 BoundNetLog());
116
117 transaction_->Start();
118 }
119
IsRunning() const120 bool DnsProbeRunner::IsRunning() const {
121 return !callback_.is_null();
122 }
123
OnTransactionComplete(DnsTransaction * transaction,int net_error,const DnsResponse * response)124 void DnsProbeRunner::OnTransactionComplete(
125 DnsTransaction* transaction,
126 int net_error,
127 const DnsResponse* response) {
128 DCHECK(!callback_.is_null());
129 DCHECK(transaction_.get());
130 DCHECK_EQ(transaction_.get(), transaction);
131
132 result_ = EvaluateResponse(net_error, response);
133 transaction_.reset();
134
135 BrowserThread::PostTask(
136 BrowserThread::IO,
137 FROM_HERE,
138 base::Bind(&DnsProbeRunner::CallCallback,
139 weak_factory_.GetWeakPtr()));
140 }
141
CallCallback()142 void DnsProbeRunner::CallCallback() {
143 DCHECK(!callback_.is_null());
144 DCHECK(!transaction_.get());
145
146 // Clear callback in case it starts a new probe immediately.
147 const base::Closure callback = callback_;
148 callback_.Reset();
149 callback.Run();
150 }
151
152 } // namespace chrome_browser_net
153