OLD | NEW |
| (Empty) |
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. | |
4 | |
5 #include "chrome/browser/net/dns_probe_job.h" | |
6 | |
7 #include "base/compiler_specific.h" | |
8 #include "base/memory/scoped_ptr.h" | |
9 #include "base/memory/weak_ptr.h" | |
10 #include "base/message_loop.h" | |
11 #include "base/time/time.h" | |
12 #include "net/base/address_list.h" | |
13 #include "net/base/net_errors.h" | |
14 #include "net/base/net_log.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 net::AddressList; | |
22 using net::BoundNetLog; | |
23 using net::DnsClient; | |
24 using net::DnsResponse; | |
25 using net::DnsTransaction; | |
26 using net::NetLog; | |
27 | |
28 namespace chrome_browser_net { | |
29 | |
30 namespace { | |
31 | |
32 // Returns true if the given net_error indicates that we received a response | |
33 // from the DNS server containing an error, or false if the given net_error | |
34 // indicates that we never received a response. | |
35 bool DidReceiveDnsResponse(int net_error) { | |
36 switch (net_error) { | |
37 case net::ERR_NAME_NOT_RESOLVED: // NXDOMAIN maps to this. | |
38 case net::ERR_DNS_MALFORMED_RESPONSE: | |
39 case net::ERR_DNS_SERVER_REQUIRES_TCP: | |
40 case net::ERR_DNS_SERVER_FAILED: | |
41 case net::ERR_DNS_SORT_ERROR: // Can only happen if the server responds. | |
42 return true; | |
43 default: | |
44 return false; | |
45 } | |
46 } | |
47 | |
48 class DnsProbeJobImpl : public DnsProbeJob { | |
49 public: | |
50 DnsProbeJobImpl(scoped_ptr<DnsClient> dns_client, | |
51 const DnsProbeJob::CallbackType& callback, | |
52 NetLog* net_log); | |
53 virtual ~DnsProbeJobImpl(); | |
54 | |
55 private: | |
56 enum QueryResult { | |
57 QUERY_UNKNOWN, | |
58 QUERY_CORRECT, | |
59 QUERY_INCORRECT, | |
60 QUERY_DNS_ERROR, | |
61 QUERY_NET_ERROR, | |
62 }; | |
63 | |
64 void Start(); | |
65 | |
66 scoped_ptr<DnsTransaction> CreateTransaction( | |
67 const std::string& hostname); | |
68 void StartTransaction(DnsTransaction* transaction); | |
69 // Checks that |net_error| is OK, |response| parses, and has at least one | |
70 // address. | |
71 QueryResult EvaluateGoodResponse(int net_error, const DnsResponse* response); | |
72 // Checks that |net_error| is OK, |response| parses but has no addresses. | |
73 QueryResult EvaluateBadResponse(int net_error, const DnsResponse* response); | |
74 DnsProbeJob::Result EvaluateQueryResults(); | |
75 void OnTransactionComplete(DnsTransaction* transaction, | |
76 int net_error, | |
77 const DnsResponse* response); | |
78 | |
79 BoundNetLog bound_net_log_; | |
80 scoped_ptr<DnsClient> dns_client_; | |
81 const DnsProbeJob::CallbackType callback_; | |
82 scoped_ptr<DnsTransaction> good_transaction_; | |
83 scoped_ptr<DnsTransaction> bad_transaction_; | |
84 bool good_running_; | |
85 bool bad_running_; | |
86 QueryResult good_result_; | |
87 QueryResult bad_result_; | |
88 base::WeakPtrFactory<DnsProbeJobImpl> weak_factory_; | |
89 | |
90 DISALLOW_COPY_AND_ASSIGN(DnsProbeJobImpl); | |
91 }; | |
92 | |
93 DnsProbeJobImpl::DnsProbeJobImpl(scoped_ptr<DnsClient> dns_client, | |
94 const DnsProbeJob::CallbackType& callback, | |
95 NetLog* net_log) | |
96 : bound_net_log_( | |
97 BoundNetLog::Make(net_log, NetLog::SOURCE_DNS_PROBER)), | |
98 dns_client_(dns_client.Pass()), | |
99 callback_(callback), | |
100 good_running_(false), | |
101 bad_running_(false), | |
102 good_result_(QUERY_UNKNOWN), | |
103 bad_result_(QUERY_UNKNOWN), | |
104 weak_factory_(this) { | |
105 DCHECK(dns_client_.get()); | |
106 DCHECK(dns_client_->GetConfig()); | |
107 | |
108 base::MessageLoop::current()->PostTask( | |
109 FROM_HERE, | |
110 base::Bind(&DnsProbeJobImpl::Start, | |
111 weak_factory_.GetWeakPtr())); | |
112 } | |
113 | |
114 DnsProbeJobImpl::~DnsProbeJobImpl() { | |
115 } | |
116 | |
117 void DnsProbeJobImpl::Start() { | |
118 // TODO(ttuttle): Pick a good random hostname for the bad case. | |
119 // Consider running transactions in series? | |
120 good_transaction_ = CreateTransaction("google.com"); | |
121 bad_transaction_ = CreateTransaction("thishostname.doesnotresolve"); | |
122 | |
123 // StartTransaction may call the callback synchrononously, so set these | |
124 // before we call it. | |
125 good_running_ = true; | |
126 bad_running_ = true; | |
127 | |
128 // TODO(ttuttle): Log probe started. | |
129 | |
130 StartTransaction(good_transaction_.get()); | |
131 StartTransaction(bad_transaction_.get()); | |
132 } | |
133 | |
134 scoped_ptr<DnsTransaction> DnsProbeJobImpl::CreateTransaction( | |
135 const std::string& hostname) { | |
136 return dns_client_->GetTransactionFactory()->CreateTransaction( | |
137 hostname, | |
138 net::dns_protocol::kTypeA, | |
139 base::Bind(&DnsProbeJobImpl::OnTransactionComplete, | |
140 base::Unretained(this)), | |
141 bound_net_log_); | |
142 } | |
143 | |
144 void DnsProbeJobImpl::StartTransaction(DnsTransaction* transaction) { | |
145 int rv = transaction->Start(); | |
146 if (rv != net::ERR_IO_PENDING) { | |
147 // TODO(ttuttle): Make sure this counts as unreachable, not error. | |
148 OnTransactionComplete(transaction, rv, NULL); | |
149 } | |
150 | |
151 // TODO(ttuttle): Log transaction started. | |
152 } | |
153 | |
154 DnsProbeJobImpl::QueryResult DnsProbeJobImpl::EvaluateGoodResponse( | |
155 int net_error, | |
156 const DnsResponse* response) { | |
157 if (net_error != net::OK) | |
158 return DidReceiveDnsResponse(net_error) ? QUERY_DNS_ERROR : QUERY_NET_ERROR; | |
159 | |
160 AddressList addr_list; | |
161 TimeDelta ttl; | |
162 DnsResponse::Result result = response->ParseToAddressList(&addr_list, &ttl); | |
163 | |
164 if (result != DnsResponse::DNS_PARSE_OK) | |
165 return QUERY_DNS_ERROR; | |
166 | |
167 if (addr_list.empty()) | |
168 return QUERY_INCORRECT; | |
169 | |
170 return QUERY_CORRECT; | |
171 } | |
172 | |
173 DnsProbeJobImpl::QueryResult DnsProbeJobImpl::EvaluateBadResponse( | |
174 int net_error, | |
175 const DnsResponse* response) { | |
176 if (net_error == net::ERR_NAME_NOT_RESOLVED) // NXDOMAIN maps to this | |
177 return QUERY_CORRECT; | |
178 | |
179 if (net_error != net::OK) | |
180 return DidReceiveDnsResponse(net_error) ? QUERY_DNS_ERROR : QUERY_NET_ERROR; | |
181 | |
182 return QUERY_INCORRECT; | |
183 } | |
184 | |
185 DnsProbeJob::Result DnsProbeJobImpl::EvaluateQueryResults() { | |
186 if (good_result_ == QUERY_NET_ERROR || bad_result_ == QUERY_NET_ERROR) | |
187 return SERVERS_UNREACHABLE; | |
188 | |
189 if (good_result_ == QUERY_DNS_ERROR || bad_result_ == QUERY_DNS_ERROR) | |
190 return SERVERS_FAILING; | |
191 | |
192 // Ignore incorrect responses to known-bad query to avoid flagging domain | |
193 // helpers. | |
194 if (good_result_ == QUERY_INCORRECT) | |
195 return SERVERS_INCORRECT; | |
196 | |
197 return SERVERS_CORRECT; | |
198 } | |
199 | |
200 void DnsProbeJobImpl::OnTransactionComplete(DnsTransaction* transaction, | |
201 int net_error, | |
202 const DnsResponse* response) { | |
203 if (transaction == good_transaction_.get()) { | |
204 DCHECK(good_running_); | |
205 DCHECK_EQ(QUERY_UNKNOWN, good_result_); | |
206 good_result_ = EvaluateGoodResponse(net_error, response); | |
207 good_running_ = false; | |
208 } else if (transaction == bad_transaction_.get()) { | |
209 DCHECK(bad_running_); | |
210 DCHECK_EQ(QUERY_UNKNOWN, bad_result_); | |
211 bad_result_ = EvaluateBadResponse(net_error, response); | |
212 bad_running_ = false; | |
213 } else { | |
214 NOTREACHED(); | |
215 return; | |
216 } | |
217 | |
218 if (good_running_ || bad_running_) | |
219 return; | |
220 | |
221 callback_.Run(this, EvaluateQueryResults()); | |
222 | |
223 // TODO(ttuttle): Log probe finished. | |
224 } | |
225 | |
226 } // namespace | |
227 | |
228 scoped_ptr<DnsProbeJob> DnsProbeJob::CreateJob( | |
229 scoped_ptr<DnsClient> dns_client, | |
230 const CallbackType& callback, | |
231 NetLog* net_log) { | |
232 return scoped_ptr<DnsProbeJob>( | |
233 new DnsProbeJobImpl(dns_client.Pass(), callback, net_log)); | |
234 } | |
235 | |
236 } // namespace chrome_browser_net | |
OLD | NEW |