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

Side by Side Diff: net/dns/dns_transaction.cc

Issue 9190031: DnsClient refactoring + features (timeout, suffix search, server rotation). (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Added unit tests. Depends on CL 9251019 Created 8 years, 11 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 unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "net/dns/dns_transaction.h" 5 #include "net/dns/dns_transaction.h"
6 6
7 #include <deque>
8 #include <string>
9 #include <vector>
10
7 #include "base/bind.h" 11 #include "base/bind.h"
12 #include "base/memory/ref_counted.h"
13 #include "base/memory/scoped_ptr.h"
14 #include "base/memory/weak_ptr.h"
15 #include "base/message_loop.h"
8 #include "base/rand_util.h" 16 #include "base/rand_util.h"
9 #include "base/values.h" 17 #include "base/stl_util.h"
18 #include "base/string_piece.h"
19 #include "base/threading/non_thread_safe.h"
20 #include "base/timer.h"
21 #include "net/base/completion_callback.h"
22 #include "net/base/dns_util.h"
10 #include "net/base/io_buffer.h" 23 #include "net/base/io_buffer.h"
24 #include "net/base/ip_endpoint.h"
11 #include "net/base/net_errors.h" 25 #include "net/base/net_errors.h"
26 #include "net/base/net_log.h"
12 #include "net/dns/dns_protocol.h" 27 #include "net/dns/dns_protocol.h"
13 #include "net/dns/dns_query.h" 28 #include "net/dns/dns_query.h"
14 #include "net/dns/dns_response.h" 29 #include "net/dns/dns_response.h"
15 #include "net/dns/dns_session.h" 30 #include "net/dns/dns_session.h"
16 #include "net/socket/client_socket_factory.h" 31 #include "net/socket/client_socket_factory.h"
17 #include "net/udp/datagram_client_socket.h" 32 #include "net/udp/datagram_client_socket.h"
18 33
19 namespace net { 34 namespace net {
20 35
21 namespace { 36 namespace {
22 37
23 class DnsTransactionStartParameters : public NetLog::EventParameters { 38 // Count labels in the fully-qualified name in DNS format.
39 int CountLabels(const std::string& name) {
40 size_t count = 0;
41 for (size_t i = 0; i < name.size() && name[i]; i += name[i] + 1)
42 ++count;
43 return count;
44 }
45
46 bool IsIPLiteral(const std::string& hostname) {
47 IPAddressNumber ip;
48 return ParseIPLiteralToNumber(hostname, &ip);
49 }
50
51 class StartParameters : public NetLog::EventParameters {
24 public: 52 public:
25 DnsTransactionStartParameters(const IPEndPoint& dns_server, 53 StartParameters(const std::string& hostname,
26 const base::StringPiece& qname, 54 uint16 qtype,
27 uint16 qtype, 55 const NetLog::Source& source)
28 const NetLog::Source& source) 56 : hostname_(hostname), qtype_(qtype), source_(source) {}
29 : dns_server_(dns_server), 57
30 qname_(qname.data(), qname.length()), 58 virtual Value* ToValue() const OVERRIDE {
31 qtype_(qtype),
32 source_(source) {}
33
34 virtual Value* ToValue() const {
35 DictionaryValue* dict = new DictionaryValue(); 59 DictionaryValue* dict = new DictionaryValue();
36 dict->SetString("dns_server", dns_server_.ToString()); 60 dict->SetString("hostname", hostname_);
37 dict->SetString("hostname", qname_);
38 dict->SetInteger("query_type", qtype_); 61 dict->SetInteger("query_type", qtype_);
39 if (source_.is_valid()) 62 dict->Set("source_dependency", source_.ToValue());
40 dict->Set("source_dependency", source_.ToValue());
41 return dict; 63 return dict;
42 } 64 }
43 65
44 private: 66 private:
45 IPEndPoint dns_server_; 67 const std::string hostname_;
46 std::string qname_; 68 const uint16 qtype_;
47 uint16 qtype_;
48 const NetLog::Source source_; 69 const NetLog::Source source_;
49 }; 70 };
50 71
51 class DnsTransactionFinishParameters : public NetLog::EventParameters { 72 class ResponseParameters : public NetLog::EventParameters {
52 public: 73 public:
53 // TODO(szym): add rcode ? 74 ResponseParameters(int rcode, int answer_count, const NetLog::Source& source)
54 DnsTransactionFinishParameters(int net_error, int answer_count) 75 : rcode_(rcode), answer_count_(answer_count), source_(source) {}
55 : net_error_(net_error), answer_count_(answer_count) {} 76
56 77 virtual Value* ToValue() const OVERRIDE {
57 virtual Value* ToValue() const {
58 DictionaryValue* dict = new DictionaryValue(); 78 DictionaryValue* dict = new DictionaryValue();
59 if (net_error_) 79 dict->SetInteger("rcode", rcode_);
60 dict->SetInteger("net_error", net_error_);
61 dict->SetInteger("answer_count", answer_count_); 80 dict->SetInteger("answer_count", answer_count_);
81 dict->Set("socket_source", source_.ToValue());
62 return dict; 82 return dict;
63 } 83 }
64 84
65 private: 85 private:
66 const int net_error_; 86 const int rcode_;
67 const int answer_count_; 87 const int answer_count_;
68 };
69
70 class DnsTransactionRetryParameters : public NetLog::EventParameters {
71 public:
72 DnsTransactionRetryParameters(int attempt_number,
73 const NetLog::Source& source)
74 : attempt_number_(attempt_number), source_(source) {}
75
76 virtual Value* ToValue() const {
77 DictionaryValue* dict = new DictionaryValue();
78 dict->SetInteger("attempt_number", attempt_number_);
79 dict->Set("source_dependency", source_.ToValue());
80 return dict;
81 }
82
83 private:
84 const int attempt_number_;
85 const NetLog::Source source_; 88 const NetLog::Source source_;
86 }; 89 };
87 90
91 // ----------------------------------------------------------------------------
92
93 // A single asynchronous DNS exchange over UDP, which consists of sending out a
94 // DNS query, waiting for a response, and returning the response that it
95 // matches. Logging is done in the socket and in the outer DnsTransaction.
96 class DnsUDPAttempt {
97 public:
98 DnsUDPAttempt(scoped_ptr<DatagramClientSocket> socket,
99 const IPEndPoint& server,
100 scoped_ptr<DnsQuery> query,
101 const CompletionCallback& callback)
102 : next_state_(STATE_NONE),
103 socket_(socket.Pass()),
104 server_(server),
105 query_(query.Pass()),
106 callback_(callback) {
107 }
108
109 // Starts the attempt. Returns ERR_IO_PENDING if cannot complete synchronously
110 // and calls |callback| upon completion.
111 int Start() {
112 DCHECK_EQ(STATE_NONE, next_state_);
113 next_state_ = STATE_CONNECT;
114 return DoLoop(OK);
115 }
116
117 const DnsQuery* query() const {
118 return query_.get();
119 }
120
121 const DatagramClientSocket* socket() const {
122 return socket_.get();
123 }
124
125 // Returns the response or NULL if has not received a matching response from
126 // the server.
127 const DnsResponse* response() const {
128 const DnsResponse* resp = response_.get();
129 return (resp != NULL && resp->IsValid()) ? resp : NULL;
130 }
131
132 private:
133 enum State {
134 STATE_CONNECT,
135 STATE_SEND_QUERY,
136 STATE_SEND_QUERY_COMPLETE,
137 STATE_READ_RESPONSE,
138 STATE_READ_RESPONSE_COMPLETE,
139 STATE_NONE,
140 };
141
142 int DoLoop(int result) {
143 DCHECK_NE(STATE_NONE, next_state_);
144 int rv = result;
145 do {
146 State state = next_state_;
147 next_state_ = STATE_NONE;
148 switch (state) {
149 case STATE_CONNECT:
150 rv = DoConnect();
151 break;
152 case STATE_SEND_QUERY:
153 rv = DoSendQuery();
154 break;
155 case STATE_SEND_QUERY_COMPLETE:
156 rv = DoSendQueryComplete(rv);
157 break;
158 case STATE_READ_RESPONSE:
159 rv = DoReadResponse();
160 break;
161 case STATE_READ_RESPONSE_COMPLETE:
162 rv = DoReadResponseComplete(rv);
163 break;
164 default:
165 NOTREACHED();
166 break;
167 }
168 } while (rv != ERR_IO_PENDING && next_state_ != STATE_NONE);
169
170 return rv;
171 }
172
173 int DoConnect() {
174 next_state_ = STATE_SEND_QUERY;
175 return socket_->Connect(server_);
176 }
177
178 int DoSendQuery() {
179 next_state_ = STATE_SEND_QUERY_COMPLETE;
180 return socket_->Write(query_->io_buffer(),
181 query_->io_buffer()->size(),
182 base::Bind(&DnsUDPAttempt::OnIOComplete,
183 base::Unretained(this)));
184 }
185
186 int DoSendQueryComplete(int rv) {
187 DCHECK_NE(ERR_IO_PENDING, rv);
188 if (rv < 0)
189 return rv;
190
191 // Writing to UDP should not result in a partial datagram.
192 if (rv != query_->io_buffer()->size())
193 return ERR_MSG_TOO_BIG;
194
195 next_state_ = STATE_READ_RESPONSE;
196 return OK;
197 }
198
199 int DoReadResponse() {
200 next_state_ = STATE_READ_RESPONSE_COMPLETE;
201 response_.reset(new DnsResponse());
202 return socket_->Read(response_->io_buffer(),
203 response_->io_buffer()->size(),
204 base::Bind(&DnsUDPAttempt::OnIOComplete,
205 base::Unretained(this)));
206 }
207
208 int DoReadResponseComplete(int rv) {
209 DCHECK_NE(ERR_IO_PENDING, rv);
210 if (rv < 0)
211 return rv;
212
213 DCHECK(rv);
214 if (!response_->InitParse(rv, *query_))
215 return ERR_DNS_MALFORMED_RESPONSE;
216 if (response_->flags() & dns_protocol::kFlagTC)
217 return ERR_DNS_SERVER_REQUIRES_TCP;
218 if (response_->rcode() != dns_protocol::kRcodeNOERROR &&
219 response_->rcode() != dns_protocol::kRcodeNXDOMAIN) {
220 return ERR_DNS_SERVER_FAILED;
221 }
222 if (response_->answer_count() == 0)
223 return ERR_NAME_NOT_RESOLVED;
224
225 return OK;
226 }
227
228 void OnIOComplete(int rv) {
229 rv = DoLoop(rv);
230 if (rv != ERR_IO_PENDING)
231 callback_.Run(rv);
232 }
233
234 State next_state_;
235
236 scoped_ptr<DatagramClientSocket> socket_;
237 IPEndPoint server_;
238 scoped_ptr<DnsQuery> query_;
239
240 scoped_ptr<DnsResponse> response_;
241
242 CompletionCallback callback_;
243
244 DISALLOW_COPY_AND_ASSIGN(DnsUDPAttempt);
245 };
246
247 // ----------------------------------------------------------------------------
248
249 // Implements DnsTransaction. Configuration is supplied by DnsSession.
250 // The suffix list is built according to the DnsConfig from the session.
251 // The timeout for each DnsUDPAttempt is given by DnsSession::NextTimeout.
252 // The first server to attempt on each query is given by
253 // DnsSession::NextFirstServerIndex, and the order is round-robin afterwards.
254 // Each server is attempted DnsConfig::attempts times.
255 class DnsTransactionImpl : public DnsTransaction, public base::NonThreadSafe {
256 public:
257 DnsTransactionImpl(DnsSession* session,
258 const std::string& hostname,
259 uint16 qtype,
260 const DnsTransactionFactory::CallbackType& callback,
261 const BoundNetLog& source_net_log)
262 : session_(session),
263 hostname_(hostname),
264 qtype_(qtype),
265 callback_(callback),
266 net_log_(BoundNetLog::Make(session->net_log(),
267 NetLog::SOURCE_DNS_TRANSACTION)),
268 first_server_index_(0) {
269 DCHECK(session_);
270 DCHECK(!hostname_.empty());
271 DCHECK(!callback_.is_null());
272
273 DCHECK(!IsIPLiteral(hostname_));
274
275 net_log_.BeginEvent(NetLog::TYPE_DNS_TRANSACTION, make_scoped_refptr(
276 new StartParameters(hostname_, qtype_, source_net_log.source())));
277 }
278
279 virtual ~DnsTransactionImpl() {
280 STLDeleteElements(&attempts_);
281 if (!callback_.is_null()) {
282 net_log_.AddEvent(NetLog::TYPE_CANCELLED, NULL);
283 net_log_.EndEventWithNetErrorCode(NetLog::TYPE_DNS_TRANSACTION,
284 ERR_ABORTED);
285 }
286 }
287
288 virtual const std::string& GetHostname() const OVERRIDE {
289 DCHECK(CalledOnValidThread());
290 return hostname_;
291 }
292
293 virtual uint16 GetType() const OVERRIDE {
294 DCHECK(CalledOnValidThread());
295 return qtype_;
296 }
297
298 virtual int Start() OVERRIDE {
299 int rv = PrepareSearch();
300 if (rv == OK)
301 rv = StartQuery();
302 DCHECK_NE(OK, rv);
303 return rv;
304 }
305
306 private:
307 // Prepares |qnames_| according to the DnsConfig.
308 int PrepareSearch() {
309 const DnsConfig& config = session_->config();
310
311 std::string labelled_hostname;
mmenke 2012/01/19 17:24:47 nit: "labeled" is preferred in the US, technicall
312 if (!DNSDomainFromDot(hostname_, &labelled_hostname))
313 return ERR_INVALID_ARGUMENT;
314
315 if (hostname_[hostname_.size() - 1] == '.') {
316 // It's a fully-qualified name, no suffix search.
317 qnames_.push_back(labelled_hostname);
318 return OK;
319 }
320
321 // Set true when |labelled_hostname| is put on the list.
322 bool had_hostname = false;
323
324 int ndots = CountLabels(labelled_hostname) - 1;
325 if (ndots >= config.ndots) {
326 qnames_.push_back(labelled_hostname);
327 had_hostname = true;
328 }
329
330 std::string qname;
331 for (size_t i = 0; i < config.search.size(); ++i) {
332 // Ignore invalid (too long) combinations.
333 if (!DNSDomainFromDot(hostname_ + "." + config.search[i], &qname))
334 continue;
335 if (qname.size() == labelled_hostname.size()) {
336 if (had_hostname)
337 continue;
338 had_hostname = true;
339 }
340 qnames_.push_back(qname);
341 }
342
343 if (!had_hostname)
344 qnames_.push_back(labelled_hostname);
345
346 return OK;
347 }
348
349 void DoCallback(int rv, const DnsUDPAttempt* successful_attempt) {
350 if (callback_.is_null())
351 return;
352 DCHECK_NE(ERR_IO_PENDING, rv);
353 DCHECK(rv != OK || successful_attempt != NULL);
354
355 DnsTransactionFactory::CallbackType callback = callback_;
356 callback_.Reset();
357 net_log_.EndEventWithNetErrorCode(NetLog::TYPE_DNS_TRANSACTION, rv);
358 callback.Run(this,
359 rv,
360 successful_attempt ? successful_attempt->response() : NULL);
361 }
362
363 // Makes another attempt at the current name, |qnames_.front()|, using the
364 // next nameserver.
365 int MakeAttempt() {
366 unsigned attempt_number = attempts_.size();
367
368 scoped_ptr<DatagramClientSocket> socket(
369 session_->socket_factory()->CreateDatagramClientSocket(
370 DatagramSocket::RANDOM_BIND,
371 base::Bind(&base::RandInt),
372 net_log_.net_log(),
373 net_log_.source()));
374
375 uint16 id = session_->NextQueryId();
376 scoped_ptr<DnsQuery> query;
377 if (attempts_.empty()) {
378 query.reset(new DnsQuery(id, qnames_.front(), qtype_));
379 } else {
380 query.reset(attempts_[0]->query()->CloneWithNewId(id));
381 }
382
383 net_log_.AddEvent(NetLog::TYPE_DNS_TRANSACTION_ATTEMPT, make_scoped_refptr(
384 new NetLogSourceParameter("socket_source", socket->NetLog().source())));
385
386 const DnsConfig& config = session_->config();
387
388 unsigned server_index = first_server_index_ +
389 (attempt_number % config.nameservers.size());
390
391 DnsUDPAttempt* attempt = new DnsUDPAttempt(
392 socket.Pass(),
393 config.nameservers[server_index],
394 query.Pass(),
395 base::Bind(&DnsTransactionImpl::OnAttemptComplete,
396 base::Unretained(this),
397 attempt_number));
398
399 base::TimeDelta timeout = session_->NextTimeout(attempt_number);
400 timer_.Start(FROM_HERE, timeout, this, &DnsTransactionImpl::OnTimeout);
401 attempts_.push_back(attempt);
402 return attempt->Start();
403 }
404
405 // Begins query for the current name. Makes the first attempt.
406 int StartQuery() {
407 std::string dotted_qname = DNSDomainToString(qnames_.front());
408 net_log_.BeginEvent(
409 NetLog::TYPE_DNS_TRANSACTION_QUERY,
410 make_scoped_refptr(new NetLogStringParameter("qname", dotted_qname)));
411
412 first_server_index_ = session_->NextFirstServerIndex();
413
414 STLDeleteElements(&attempts_);
415 return MakeAttempt();
416 }
417
418 void OnAttemptComplete(unsigned attempt_number, int rv) {
419 DCHECK_LT(attempt_number, attempts_.size());
420 timer_.Stop();
421
422 const DnsUDPAttempt* attempt = attempts_[attempt_number];
423
424 if (attempt->response()) {
425 net_log_.AddEvent(
426 NetLog::TYPE_DNS_TRANSACTION_RESPONSE,
427 make_scoped_refptr(
428 new ResponseParameters(attempt->response()->rcode(),
429 attempt->response()->answer_count(),
430 attempt->socket()->NetLog().source())));
431 }
432
433 net_log_.EndEventWithNetErrorCode(NetLog::TYPE_DNS_TRANSACTION_QUERY, rv);
434
435 switch (rv) {
436 case ERR_NAME_NOT_RESOLVED:
437 // Try next suffix.
438 qnames_.pop_front();
439 if (qnames_.empty())
440 rv = ERR_NAME_NOT_RESOLVED;
441 else
442 rv = StartQuery();
443 break;
444 case OK:
445 DoCallback(rv, attempt);
446 return;
447 default:
448 // TODO(szym): Some nameservers could fail so try the next one.
449 const DnsConfig& config = session_->config();
450 if (attempts_.size() < config.attempts * config.nameservers.size()) {
451 rv = MakeAttempt();
452 } else {
453 // TODO(szym): Should this be different than the timeout case?
454 rv = ERR_DNS_SERVER_FAILED;
455 }
456 break;
457 }
458 if (rv != ERR_IO_PENDING)
459 DoCallback(rv, NULL);
460 }
461
462 void OnTimeout() {
463 const DnsConfig& config = session_->config();
464 if (attempts_.size() == config.attempts * config.nameservers.size()) {
465 DoCallback(ERR_DNS_TIMED_OUT, NULL);
466 return;
467 }
468 int rv = MakeAttempt();
469 if (rv != ERR_IO_PENDING)
470 DoCallback(rv, NULL);
471 }
472
473 scoped_refptr<DnsSession> session_;
474 std::string hostname_;
475 uint16 qtype_;
476 // Set to null once the transaction completes.
477 DnsTransactionFactory::CallbackType callback_;
478
479 BoundNetLog net_log_;
480
481 // Search list of fully-qualified DNS names to query next (in DNS format).
482 std::deque<std::string> qnames_;
483
484 // List of attempts for the current name.
485 std::vector<DnsUDPAttempt*> attempts_;
486
487 // Index of the first server to try on each search query.
488 int first_server_index_;
489
490 base::OneShotTimer<DnsTransactionImpl> timer_;
491
492 DISALLOW_COPY_AND_ASSIGN(DnsTransactionImpl);
493 };
494
495 // ----------------------------------------------------------------------------
496
497 // Implementation of DnsTransactionFactory that returns instances of
498 // DnsTransactionImpl.
499 class DnsTransactionFactoryImpl : public DnsTransactionFactory {
500 public:
501 explicit DnsTransactionFactoryImpl(DnsSession* session) {
502 session_ = session;
503 }
504
505 virtual scoped_ptr<DnsTransaction> CreateTransaction(
506 const std::string& hostname,
507 uint16 qtype,
508 const CallbackType& callback,
509 const BoundNetLog& source_net_log) OVERRIDE {
510 return scoped_ptr<DnsTransaction>(new DnsTransactionImpl(session_,
511 hostname,
512 qtype,
513 callback,
514 source_net_log));
515 }
516
517 private:
518 scoped_refptr<DnsSession> session_;
519 };
520
88 } // namespace 521 } // namespace
89 522
90 523 // static
91 DnsTransaction::DnsTransaction(DnsSession* session, 524 scoped_ptr<DnsTransactionFactory> DnsTransactionFactory::CreateFactory(
92 const base::StringPiece& qname, 525 DnsSession* session) {
93 uint16 qtype, 526 return scoped_ptr<DnsTransactionFactory>(
94 const ResultCallback& callback, 527 new DnsTransactionFactoryImpl(session));
95 const BoundNetLog& source_net_log)
96 : session_(session),
97 dns_server_(session->NextServer()),
98 query_(new DnsQuery(session->NextId(), qname, qtype)),
99 callback_(callback),
100 attempts_(0),
101 next_state_(STATE_NONE),
102 net_log_(BoundNetLog::Make(session->net_log(),
103 NetLog::SOURCE_DNS_TRANSACTION)) {
104 net_log_.BeginEvent(
105 NetLog::TYPE_DNS_TRANSACTION,
106 make_scoped_refptr(
107 new DnsTransactionStartParameters(dns_server_,
108 qname,
109 qtype,
110 source_net_log.source())));
111 } 528 }
112 529
113 DnsTransaction::~DnsTransaction() {}
114
115 int DnsTransaction::Start() {
116 DCHECK_EQ(STATE_NONE, next_state_);
117 next_state_ = STATE_CONNECT;
118 return DoLoop(OK);
119 }
120
121 int DnsTransaction::DoLoop(int result) {
122 DCHECK_NE(STATE_NONE, next_state_);
123 int rv = result;
124 do {
125 State state = next_state_;
126 next_state_ = STATE_NONE;
127 switch (state) {
128 case STATE_CONNECT:
129 rv = DoConnect();
130 break;
131 case STATE_CONNECT_COMPLETE:
132 rv = DoConnectComplete(rv);
133 break;
134 case STATE_SEND_QUERY:
135 rv = DoSendQuery();
136 break;
137 case STATE_SEND_QUERY_COMPLETE:
138 rv = DoSendQueryComplete(rv);
139 break;
140 case STATE_READ_RESPONSE:
141 rv = DoReadResponse();
142 break;
143 case STATE_READ_RESPONSE_COMPLETE:
144 rv = DoReadResponseComplete(rv);
145 break;
146 default:
147 NOTREACHED();
148 break;
149 }
150 } while (rv != ERR_IO_PENDING && next_state_ != STATE_NONE);
151
152 return rv;
153 }
154
155 void DnsTransaction::DoCallback(int result) {
156 DCHECK_NE(result, ERR_IO_PENDING);
157 int answer_count = (result == OK) ? response()->answer_count() : 0;
158 net_log_.EndEvent(
159 NetLog::TYPE_DNS_TRANSACTION,
160 make_scoped_refptr(
161 new DnsTransactionFinishParameters(result, answer_count)));
162 callback_.Run(this, result);
163 }
164
165 void DnsTransaction::OnIOComplete(int result) {
166 int rv = DoLoop(result);
167 if (rv != ERR_IO_PENDING)
168 DoCallback(rv);
169 }
170
171 int DnsTransaction::DoConnect() {
172 next_state_ = STATE_CONNECT_COMPLETE;
173
174 StartTimer(session_->NextTimeout(attempts_));
175 ++attempts_;
176
177 // TODO(szym): keep all sockets around in case the server responds
178 // after its timeout; state machine will need to change to handle that.
179 // The current plan is to move socket management out to DnsSession.
180 // Hence also move retransmissions to DnsClient::Request.
181 socket_.reset(session_->socket_factory()->CreateDatagramClientSocket(
182 DatagramSocket::RANDOM_BIND,
183 base::Bind(&base::RandInt),
184 net_log_.net_log(),
185 net_log_.source()));
186
187 net_log_.AddEvent(
188 NetLog::TYPE_DNS_TRANSACTION_ATTEMPT_STARTED,
189 make_scoped_refptr(
190 new DnsTransactionRetryParameters(attempts_,
191 socket_->NetLog().source())));
192
193 return socket_->Connect(dns_server_);
194 }
195
196 int DnsTransaction::DoConnectComplete(int rv) {
197 if (rv < 0)
198 return rv;
199 next_state_ = STATE_SEND_QUERY;
200 return OK;
201 }
202
203 int DnsTransaction::DoSendQuery() {
204 next_state_ = STATE_SEND_QUERY_COMPLETE;
205 return socket_->Write(query_->io_buffer(),
206 query_->io_buffer()->size(),
207 base::Bind(&DnsTransaction::OnIOComplete,
208 base::Unretained(this)));
209 }
210
211 int DnsTransaction::DoSendQueryComplete(int rv) {
212 if (rv < 0)
213 return rv;
214
215 // Writing to UDP should not result in a partial datagram.
216 if (rv != query_->io_buffer()->size())
217 return ERR_MSG_TOO_BIG;
218
219 next_state_ = STATE_READ_RESPONSE;
220 return OK;
221 }
222
223 int DnsTransaction::DoReadResponse() {
224 next_state_ = STATE_READ_RESPONSE_COMPLETE;
225 response_.reset(new DnsResponse());
226 return socket_->Read(response_->io_buffer(),
227 response_->io_buffer()->size(),
228 base::Bind(&DnsTransaction::OnIOComplete,
229 base::Unretained(this)));
230 }
231
232 int DnsTransaction::DoReadResponseComplete(int rv) {
233 DCHECK_NE(ERR_IO_PENDING, rv);
234 RevokeTimer();
235 if (rv < 0)
236 return rv;
237
238 DCHECK(rv);
239 if (!response_->InitParse(rv, *query_))
240 return ERR_DNS_MALFORMED_RESPONSE;
241 // TODO(szym): define this flag value in dns_protocol
242 if (response_->flags1() & 2)
243 return ERR_DNS_SERVER_REQUIRES_TCP;
244 // TODO(szym): move this handling out of DnsTransaction?
245 if (response_->rcode() != dns_protocol::kRcodeNOERROR &&
246 response_->rcode() != dns_protocol::kRcodeNXDOMAIN) {
247 return ERR_DNS_SERVER_FAILED;
248 }
249 // TODO(szym): add ERR_DNS_RR_NOT_FOUND?
250 if (response_->answer_count() == 0)
251 return ERR_NAME_NOT_RESOLVED;
252
253 return OK;
254 }
255
256 void DnsTransaction::StartTimer(base::TimeDelta delay) {
257 timer_.Start(FROM_HERE, delay, this, &DnsTransaction::OnTimeout);
258 }
259
260 void DnsTransaction::RevokeTimer() {
261 timer_.Stop();
262 }
263
264 void DnsTransaction::OnTimeout() {
265 DCHECK(next_state_ == STATE_SEND_QUERY_COMPLETE ||
266 next_state_ == STATE_READ_RESPONSE_COMPLETE);
267 if (attempts_ == session_->config().attempts) {
268 DoCallback(ERR_DNS_TIMED_OUT);
269 return;
270 }
271 next_state_ = STATE_CONNECT;
272 query_.reset(query_->CloneWithNewId(session_->NextId()));
273 int rv = DoLoop(OK);
274 if (rv != ERR_IO_PENDING)
275 DoCallback(rv);
276 }
277
278 } // namespace net 530 } // namespace net
531
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698