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

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

Issue 11567031: [net/dns] Handle TC bit on DNS response in DnsTransaction. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: add test for timeout and fix timeout logic Created 8 years 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) 2012 The Chromium Authors. All rights reserved. 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 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> 7 #include <deque>
8 #include <string> 8 #include <string>
9 #include <vector> 9 #include <vector>
10 10
11 #include "base/bind.h" 11 #include "base/bind.h"
12 #include "base/memory/ref_counted.h" 12 #include "base/memory/ref_counted.h"
13 #include "base/memory/scoped_ptr.h" 13 #include "base/memory/scoped_ptr.h"
14 #include "base/memory/scoped_vector.h" 14 #include "base/memory/scoped_vector.h"
15 #include "base/memory/weak_ptr.h" 15 #include "base/memory/weak_ptr.h"
16 #include "base/message_loop.h" 16 #include "base/message_loop.h"
17 #include "base/metrics/histogram.h" 17 #include "base/metrics/histogram.h"
18 #include "base/rand_util.h" 18 #include "base/rand_util.h"
19 #include "base/stl_util.h" 19 #include "base/stl_util.h"
20 #include "base/string_piece.h" 20 #include "base/string_piece.h"
21 #include "base/threading/non_thread_safe.h" 21 #include "base/threading/non_thread_safe.h"
22 #include "base/timer.h" 22 #include "base/timer.h"
23 #include "base/values.h" 23 #include "base/values.h"
24 #include "net/base/big_endian.h"
24 #include "net/base/completion_callback.h" 25 #include "net/base/completion_callback.h"
25 #include "net/base/dns_util.h" 26 #include "net/base/dns_util.h"
26 #include "net/base/io_buffer.h" 27 #include "net/base/io_buffer.h"
27 #include "net/base/ip_endpoint.h" 28 #include "net/base/ip_endpoint.h"
28 #include "net/base/net_errors.h" 29 #include "net/base/net_errors.h"
29 #include "net/base/net_log.h" 30 #include "net/base/net_log.h"
30 #include "net/dns/dns_protocol.h" 31 #include "net/dns/dns_protocol.h"
31 #include "net/dns/dns_query.h" 32 #include "net/dns/dns_query.h"
32 #include "net/dns/dns_response.h" 33 #include "net/dns/dns_response.h"
33 #include "net/dns/dns_session.h" 34 #include "net/dns/dns_session.h"
35 #include "net/socket/stream_socket.h"
34 #include "net/udp/datagram_client_socket.h" 36 #include "net/udp/datagram_client_socket.h"
35 37
36 namespace net { 38 namespace net {
37 39
38 namespace { 40 namespace {
39 41
40 // Provide a common macro to simplify code and readability. We must use a 42 // Provide a common macro to simplify code and readability. We must use a
41 // macro as the underlying HISTOGRAM macro creates static variables. 43 // macro as the underlying HISTOGRAM macro creates static variables.
42 #define DNS_HISTOGRAM(name, time) UMA_HISTOGRAM_CUSTOM_TIMES(name, time, \ 44 #define DNS_HISTOGRAM(name, time) UMA_HISTOGRAM_CUSTOM_TIMES(name, time, \
43 base::TimeDelta::FromMilliseconds(1), base::TimeDelta::FromHours(1), 100) 45 base::TimeDelta::FromMilliseconds(1), base::TimeDelta::FromHours(1), 100)
(...skipping 15 matching lines...) Expand all
59 uint16 qtype, 61 uint16 qtype,
60 NetLog::LogLevel /* log_level */) { 62 NetLog::LogLevel /* log_level */) {
61 DictionaryValue* dict = new DictionaryValue(); 63 DictionaryValue* dict = new DictionaryValue();
62 dict->SetString("hostname", *hostname); 64 dict->SetString("hostname", *hostname);
63 dict->SetInteger("query_type", qtype); 65 dict->SetInteger("query_type", qtype);
64 return dict; 66 return dict;
65 }; 67 };
66 68
67 // ---------------------------------------------------------------------------- 69 // ----------------------------------------------------------------------------
68 70
69 // A single asynchronous DNS exchange over UDP, which consists of sending out a 71 // A single asynchronous DNS exchange, which consists of sending out a
70 // DNS query, waiting for a response, and returning the response that it 72 // DNS query, waiting for a response, and returning the response that it
71 // matches. Logging is done in the socket and in the outer DnsTransaction. 73 // matches. Logging is done in the socket and in the outer DnsTransaction.
72 class DnsUDPAttempt { 74 class DnsAttempt {
75 public:
76 virtual ~DnsAttempt() {}
77 // Starts the attempt. Returns ERR_IO_PENDING if cannot complete synchronously
78 // and calls |callback| upon completion.
mmenke 2012/12/19 16:44:09 There's no |callback| defined here.
szym 2012/12/19 23:35:56 Changed so that CompletionCallback is passed to St
79 virtual int Start() = 0;
80
81 virtual const DnsQuery* query() const = 0;
82
83 // Returns the response or NULL if has not received a matching response from
84 // the server.
85 virtual const DnsResponse* response() const = 0;
86
87 virtual const BoundNetLog& socket_net_log() const = 0;
88
89 virtual unsigned server_index() const = 0;
mmenke 2012/12/19 16:44:09 Virtual methods should use CamelCase.
mmenke 2012/12/19 16:44:09 While these methods do fairly obvious things, stil
szym 2012/12/19 23:35:56 Done. Done.
90
91 // Returns a Value representing the received response, along with a reference
92 // to the NetLog source source of the UDP socket used. The request must have
93 // completed before this is called.
94 Value* NetLogResponseCallback(NetLog::LogLevel) const {
95 DCHECK(response()->IsValid());
96
97 DictionaryValue* dict = new DictionaryValue();
98 dict->SetInteger("rcode", response()->rcode());
99 dict->SetInteger("answer_count", response()->answer_count());
100 socket_net_log().source().AddToEventParameters(dict);
101 return dict;
102 }
103 };
104
105 class DnsUDPAttempt : public DnsAttempt {
73 public: 106 public:
74 DnsUDPAttempt(scoped_ptr<DnsSession::SocketLease> socket_lease, 107 DnsUDPAttempt(scoped_ptr<DnsSession::SocketLease> socket_lease,
75 scoped_ptr<DnsQuery> query, 108 scoped_ptr<DnsQuery> query,
76 const CompletionCallback& callback) 109 const CompletionCallback& callback)
77 : next_state_(STATE_NONE), 110 : next_state_(STATE_NONE),
78 received_malformed_response_(false), 111 received_malformed_response_(false),
79 socket_lease_(socket_lease.Pass()), 112 socket_lease_(socket_lease.Pass()),
80 query_(query.Pass()), 113 query_(query.Pass()),
81 callback_(callback) { 114 callback_(callback) {
82 } 115 }
83 116
mmenke 2012/12/19 16:44:09 nit: "DnsAttempt:" or "DnsAttempt implementation:
szym 2012/12/19 23:35:56 Done.
84 // Starts the attempt. Returns ERR_IO_PENDING if cannot complete synchronously 117 virtual int Start() OVERRIDE {
85 // and calls |callback| upon completion.
86 int Start() {
87 DCHECK_EQ(STATE_NONE, next_state_); 118 DCHECK_EQ(STATE_NONE, next_state_);
88 start_time_ = base::TimeTicks::Now(); 119 start_time_ = base::TimeTicks::Now();
89 next_state_ = STATE_SEND_QUERY; 120 next_state_ = STATE_SEND_QUERY;
90 return DoLoop(OK); 121 return DoLoop(OK);
91 } 122 }
92 123
93 const DnsQuery* query() const { 124 virtual const DnsQuery* query() const OVERRIDE {
94 return query_.get(); 125 return query_.get();
95 } 126 }
96 127
97 const BoundNetLog& socket_net_log() const { 128 virtual const DnsResponse* response() const OVERRIDE {
98 return socket_lease_->socket()->NetLog();
99 }
100
101 // Returns the response or NULL if has not received a matching response from
102 // the server.
103 const DnsResponse* response() const {
104 const DnsResponse* resp = response_.get(); 129 const DnsResponse* resp = response_.get();
105 return (resp != NULL && resp->IsValid()) ? resp : NULL; 130 return (resp != NULL && resp->IsValid()) ? resp : NULL;
106 } 131 }
107 132
108 // Returns a Value representing the received response, along with a reference 133 virtual const BoundNetLog& socket_net_log() const OVERRIDE {
109 // to the NetLog source source of the UDP socket used. The request must have 134 return socket_lease_->socket()->NetLog();
110 // completed before this is called. 135 }
111 Value* NetLogResponseCallback(NetLog::LogLevel /* log_level */) const {
112 DCHECK(response_->IsValid());
113 136
114 DictionaryValue* dict = new DictionaryValue(); 137 virtual unsigned server_index() const OVERRIDE {
115 dict->SetInteger("rcode", response_->rcode()); 138 return socket_lease_->server_index();
116 dict->SetInteger("answer_count", response_->answer_count());
117 socket_net_log().source().AddToEventParameters(dict);
118 return dict;
119 } 139 }
120 140
121 private: 141 private:
122 enum State { 142 enum State {
123 STATE_SEND_QUERY, 143 STATE_SEND_QUERY,
124 STATE_SEND_QUERY_COMPLETE, 144 STATE_SEND_QUERY_COMPLETE,
125 STATE_READ_RESPONSE, 145 STATE_READ_RESPONSE,
126 STATE_READ_RESPONSE_COMPLETE, 146 STATE_READ_RESPONSE_COMPLETE,
127 STATE_NONE, 147 STATE_NONE,
128 }; 148 };
(...skipping 111 matching lines...) Expand 10 before | Expand all | Expand 10 after
240 scoped_ptr<DnsSession::SocketLease> socket_lease_; 260 scoped_ptr<DnsSession::SocketLease> socket_lease_;
241 scoped_ptr<DnsQuery> query_; 261 scoped_ptr<DnsQuery> query_;
242 262
243 scoped_ptr<DnsResponse> response_; 263 scoped_ptr<DnsResponse> response_;
244 264
245 CompletionCallback callback_; 265 CompletionCallback callback_;
246 266
247 DISALLOW_COPY_AND_ASSIGN(DnsUDPAttempt); 267 DISALLOW_COPY_AND_ASSIGN(DnsUDPAttempt);
248 }; 268 };
249 269
270 class DnsTCPAttempt : public DnsAttempt {
271 public:
272 DnsTCPAttempt(scoped_ptr<StreamSocket> socket,
273 scoped_ptr<DnsQuery> query,
274 const CompletionCallback& callback)
275 : next_state_(STATE_NONE),
276 socket_(socket.Pass()),
277 query_(query.Pass()),
278 length_buffer_(new IOBufferWithSize(sizeof(uint16))),
279 response_length_(0),
280 callback_(callback) {
281 }
282
mmenke 2012/12/19 16:44:09 nit: "DnsAttempt:" or "DnsAttempt implementation:
szym 2012/12/19 23:35:56 Done.
283 virtual int Start() OVERRIDE {
284 DCHECK_EQ(STATE_NONE, next_state_);
285 start_time_ = base::TimeTicks::Now();
286 // TODO(szym): allow sockets to be pre-connected.
287 next_state_ = STATE_CONNECT_COMPLETE;
288 int rv = socket_->Connect(base::Bind(&DnsTCPAttempt::OnIOComplete,
289 base::Unretained(this)));
290 if (rv == ERR_IO_PENDING)
291 return rv;
292 return DoLoop(rv);
293 }
294
295 virtual const DnsQuery* query() const OVERRIDE {
296 return query_.get();
297 }
298
299 virtual const DnsResponse* response() const OVERRIDE {
300 const DnsResponse* resp = response_.get();
301 return (resp != NULL && resp->IsValid()) ? resp : NULL;
302 }
303
304 virtual const BoundNetLog& socket_net_log() const OVERRIDE {
305 return socket_->NetLog();
306 }
307
308 virtual unsigned server_index() const OVERRIDE {
309 NOTREACHED();
310 return 0;
311 }
312
313 private:
314 enum State {
315 STATE_CONNECT_COMPLETE,
316 STATE_SEND_LENGTH,
317 STATE_SEND_QUERY,
318 STATE_READ_LENGTH,
319 STATE_READ_RESPONSE,
320 STATE_NONE,
321 };
322
323 int DoLoop(int result) {
324 CHECK_NE(STATE_NONE, next_state_);
325 int rv = result;
326 do {
327 State state = next_state_;
328 next_state_ = STATE_NONE;
329 switch (state) {
330 case STATE_CONNECT_COMPLETE:
331 rv = DoConnectComplete(rv);
332 break;
333 case STATE_SEND_LENGTH:
334 rv = DoSendLength(rv);
335 break;
336 case STATE_SEND_QUERY:
337 rv = DoSendQuery(rv);
338 break;
339 case STATE_READ_LENGTH:
340 rv = DoReadLength(rv);
341 break;
342 case STATE_READ_RESPONSE:
343 rv = DoReadResponse(rv);
344 break;
345 default:
346 NOTREACHED();
347 break;
348 }
349 } while (rv != ERR_IO_PENDING && next_state_ != STATE_NONE);
350 if (rv == OK) {
mmenke 2012/12/19 16:44:09 Maybe a DCHECK_EQ(STATE_NONE, next_state_);?
szym 2012/12/19 23:35:56 Done.
351 DNS_HISTOGRAM("AsyncDNS.TCPAttemptSuccess",
352 base::TimeTicks::Now() - start_time_);
353 } else if (rv != ERR_IO_PENDING) {
354 DNS_HISTOGRAM("AsyncDNS.TCPAttemptFail",
355 base::TimeTicks::Now() - start_time_);
356 }
357 return rv;
358 }
359
360 int DoConnectComplete(int rv) {
361 DCHECK_NE(ERR_IO_PENDING, rv);
362 if (rv < 0)
363 return rv;
364
365 WriteBigEndian<uint16>(length_buffer_->data(), query_->io_buffer()->size());
366 buffer_ = new DrainableIOBuffer(length_buffer_, length_buffer_->size());
367 next_state_ = STATE_SEND_LENGTH;
368 return OK;
369 }
370
371 int DoSendLength(int rv) {
372 DCHECK_NE(ERR_IO_PENDING, rv);
373 if (rv < 0)
374 return rv;
375
376 buffer_->DidConsume(rv);
377 if (buffer_->BytesRemaining() > 0) {
378 next_state_ = STATE_SEND_LENGTH;
379 return socket_->Write(buffer_,
380 buffer_->BytesRemaining(),
381 base::Bind(&DnsTCPAttempt::OnIOComplete,
382 base::Unretained(this)));
383 }
384 buffer_ = new DrainableIOBuffer(query_->io_buffer(),
385 query_->io_buffer()->size());
386 next_state_ = STATE_SEND_QUERY;
387 return OK;
388 }
389
390 int DoSendQuery(int rv) {
391 DCHECK_NE(ERR_IO_PENDING, rv);
392 if (rv < 0)
393 return rv;
394
395 buffer_->DidConsume(rv);
396 if (buffer_->BytesRemaining() > 0) {
397 next_state_ = STATE_SEND_QUERY;
398 return socket_->Write(buffer_,
399 buffer_->BytesRemaining(),
400 base::Bind(&DnsTCPAttempt::OnIOComplete,
401 base::Unretained(this)));
402 }
403 buffer_ = new DrainableIOBuffer(length_buffer_, length_buffer_->size());
404 next_state_ = STATE_READ_LENGTH;
405 return OK;
406 }
407
408 int DoReadLength(int rv) {
409 DCHECK_NE(ERR_IO_PENDING, rv);
410 if (rv < 0)
411 return rv;
412
413 buffer_->DidConsume(rv);
414 if (buffer_->BytesRemaining() > 0) {
415 next_state_ = STATE_READ_LENGTH;
416 return socket_->Read(buffer_,
417 buffer_->BytesRemaining(),
418 base::Bind(&DnsTCPAttempt::OnIOComplete,
419 base::Unretained(this)));
420 }
421 ReadBigEndian<uint16>(length_buffer_->data(), &response_length_);
422 // Allocate more space so that DnsResponse's sanity check passes.
mmenke 2012/12/19 16:44:09 Which check is that?
szym 2012/12/19 17:01:17 size check for |nbytes| in DnsResponse::InitParse.
423 response_.reset(new DnsResponse(response_length_ + 1));
mmenke 2012/12/19 16:44:09 That +1 could trigger overflow. Also, may want to
mmenke 2012/12/19 16:44:09 Speaking of which, we may want to fuzz test this,
mmenke 2012/12/19 16:58:46 Oops - that "test" comment was meant for the secon
szym 2012/12/19 17:01:17 I don't think so. Because |response_length_| will
mmenke 2012/12/19 17:13:51 You're right - I had been incorrectly assuming pro
szym 2012/12/19 23:35:56 Done.
424 buffer_ = new DrainableIOBuffer(response_->io_buffer(), response_length_);
425 next_state_ = STATE_READ_RESPONSE;
426 return OK;
427 }
428
429 int DoReadResponse(int rv) {
430 DCHECK_NE(ERR_IO_PENDING, rv);
431 if (rv < 0)
432 return rv;
433
434 buffer_->DidConsume(rv);
435 if (buffer_->BytesRemaining() > 0) {
436 next_state_ = STATE_READ_RESPONSE;
437 return socket_->Read(buffer_,
438 buffer_->BytesRemaining(),
439 base::Bind(&DnsTCPAttempt::OnIOComplete,
440 base::Unretained(this)));
441 }
442 if (!response_->InitParse(buffer_->BytesConsumed(), *query_)) {
443 return ERR_DNS_MALFORMED_RESPONSE;
444 }
445 if (response_->flags() & dns_protocol::kFlagTC)
446 return ERR_UNEXPECTED;
447 // TODO(szym): Frankly, none of these are expected.
448 if (response_->rcode() == dns_protocol::kRcodeNXDOMAIN)
449 return ERR_NAME_NOT_RESOLVED;
450 if (response_->rcode() != dns_protocol::kRcodeNOERROR)
451 return ERR_DNS_SERVER_FAILED;
452
453 CHECK(response());
454 return OK;
455 }
456
457 void OnIOComplete(int rv) {
458 rv = DoLoop(rv);
459 if (rv != ERR_IO_PENDING)
460 callback_.Run(rv);
461 }
462
463 State next_state_;
464 base::TimeTicks start_time_;
465
466 scoped_ptr<StreamSocket> socket_;
467 scoped_ptr<DnsQuery> query_;
468 scoped_refptr<IOBufferWithSize> length_buffer_;
469 scoped_refptr<DrainableIOBuffer> buffer_;
470
471 uint16 response_length_;
472 scoped_ptr<DnsResponse> response_;
473
474 CompletionCallback callback_;
475
476 DISALLOW_COPY_AND_ASSIGN(DnsTCPAttempt);
477 };
478
250 // ---------------------------------------------------------------------------- 479 // ----------------------------------------------------------------------------
251 480
252 // Implements DnsTransaction. Configuration is supplied by DnsSession. 481 // Implements DnsTransaction. Configuration is supplied by DnsSession.
253 // The suffix list is built according to the DnsConfig from the session. 482 // The suffix list is built according to the DnsConfig from the session.
254 // The timeout for each DnsUDPAttempt is given by DnsSession::NextTimeout. 483 // The timeout for each DnsUDPAttempt is given by DnsSession::NextTimeout.
255 // The first server to attempt on each query is given by 484 // The first server to attempt on each query is given by
256 // DnsSession::NextFirstServerIndex, and the order is round-robin afterwards. 485 // DnsSession::NextFirstServerIndex, and the order is round-robin afterwards.
257 // Each server is attempted DnsConfig::attempts times. 486 // Each server is attempted DnsConfig::attempts times.
258 class DnsTransactionImpl : public DnsTransaction, 487 class DnsTransactionImpl : public DnsTransaction,
259 public base::NonThreadSafe, 488 public base::NonThreadSafe,
260 public base::SupportsWeakPtr<DnsTransactionImpl> { 489 public base::SupportsWeakPtr<DnsTransactionImpl> {
261 public: 490 public:
262 DnsTransactionImpl(DnsSession* session, 491 DnsTransactionImpl(DnsSession* session,
263 const std::string& hostname, 492 const std::string& hostname,
264 uint16 qtype, 493 uint16 qtype,
265 const DnsTransactionFactory::CallbackType& callback, 494 const DnsTransactionFactory::CallbackType& callback,
266 const BoundNetLog& net_log) 495 const BoundNetLog& net_log)
267 : session_(session), 496 : session_(session),
268 hostname_(hostname), 497 hostname_(hostname),
269 qtype_(qtype), 498 qtype_(qtype),
270 callback_(callback), 499 callback_(callback),
271 net_log_(net_log), 500 net_log_(net_log),
501 had_tcp_attempt_(false),
272 first_server_index_(0) { 502 first_server_index_(0) {
273 DCHECK(session_); 503 DCHECK(session_);
274 DCHECK(!hostname_.empty()); 504 DCHECK(!hostname_.empty());
275 DCHECK(!callback_.is_null()); 505 DCHECK(!callback_.is_null());
276 DCHECK(!IsIPLiteral(hostname_)); 506 DCHECK(!IsIPLiteral(hostname_));
277 } 507 }
278 508
279 virtual ~DnsTransactionImpl() { 509 virtual ~DnsTransactionImpl() {
280 if (!callback_.is_null()) { 510 if (!callback_.is_null()) {
281 net_log_.EndEventWithNetErrorCode(NetLog::TYPE_DNS_TRANSACTION, 511 net_log_.EndEventWithNetErrorCode(NetLog::TYPE_DNS_TRANSACTION,
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after
314 callback_.Reset(); 544 callback_.Reset();
315 net_log_.EndEventWithNetErrorCode(NetLog::TYPE_DNS_TRANSACTION, rv); 545 net_log_.EndEventWithNetErrorCode(NetLog::TYPE_DNS_TRANSACTION, rv);
316 } 546 }
317 DCHECK_NE(OK, rv); 547 DCHECK_NE(OK, rv);
318 return rv; 548 return rv;
319 } 549 }
320 550
321 private: 551 private:
322 // Wrapper for the result of a DnsUDPAttempt. 552 // Wrapper for the result of a DnsUDPAttempt.
323 struct AttemptResult { 553 struct AttemptResult {
324 AttemptResult(int rv, const DnsUDPAttempt* attempt) 554 AttemptResult(int rv, const DnsAttempt* attempt)
325 : rv(rv), attempt(attempt) {} 555 : rv(rv), attempt(attempt) {}
326 556
327 int rv; 557 int rv;
328 const DnsUDPAttempt* attempt; 558 const DnsAttempt* attempt;
329 }; 559 };
330 560
331 // Prepares |qnames_| according to the DnsConfig. 561 // Prepares |qnames_| according to the DnsConfig.
332 int PrepareSearch() { 562 int PrepareSearch() {
333 const DnsConfig& config = session_->config(); 563 const DnsConfig& config = session_->config();
334 564
335 std::string labeled_hostname; 565 std::string labeled_hostname;
336 if (!DNSDomainFromDot(hostname_, &labeled_hostname)) 566 if (!DNSDomainFromDot(hostname_, &labeled_hostname))
337 return ERR_INVALID_ARGUMENT; 567 return ERR_INVALID_ARGUMENT;
338 568
(...skipping 87 matching lines...) Expand 10 before | Expand all | Expand 10 after
426 656
427 if (!got_socket) 657 if (!got_socket)
428 return AttemptResult(ERR_CONNECTION_REFUSED, NULL); 658 return AttemptResult(ERR_CONNECTION_REFUSED, NULL);
429 659
430 net_log_.AddEvent( 660 net_log_.AddEvent(
431 NetLog::TYPE_DNS_TRANSACTION_ATTEMPT, 661 NetLog::TYPE_DNS_TRANSACTION_ATTEMPT,
432 attempt->socket_net_log().source().ToEventParametersCallback()); 662 attempt->socket_net_log().source().ToEventParametersCallback());
433 663
434 int rv = attempt->Start(); 664 int rv = attempt->Start();
435 if (rv == ERR_IO_PENDING) { 665 if (rv == ERR_IO_PENDING) {
436 timer_.Stop();
437 base::TimeDelta timeout = session_->NextTimeout(attempt_number); 666 base::TimeDelta timeout = session_->NextTimeout(attempt_number);
438 timer_.Start(FROM_HERE, timeout, this, &DnsTransactionImpl::OnTimeout); 667 timer_.Start(FROM_HERE, timeout, this, &DnsTransactionImpl::OnTimeout);
439 } 668 }
440 return AttemptResult(rv, attempt); 669 return AttemptResult(rv, attempt);
441 } 670 }
442 671
672 AttemptResult MakeTCPAttempt(const DnsAttempt* previous_attempt) {
673 DCHECK(previous_attempt);
674 DCHECK(!had_tcp_attempt_);
675
676 scoped_ptr<StreamSocket> socket(
677 session_->AllocateTCPSocket(previous_attempt->server_index(),
678 net_log_.source()));
679
680 // TODO(szym): Reuse the same id to help the server?
681 uint16 id = session_->NextQueryId();
682 scoped_ptr<DnsQuery> query(previous_attempt->query()->CloneWithNewId(id));
683
684 net_log_.AddEvent(NetLog::TYPE_DNS_TRANSACTION_TCP_ATTEMPT,
685 socket->NetLog().source().ToEventParametersCallback());
686
687 // Cancel all other attempts, no point waiting on them.
mmenke 2012/12/19 16:44:09 No point, even if there are multiple servers?
szym 2012/12/19 17:01:17 We don't really anticipate getting substantially d
688 attempts_.clear();
689
690 DnsTCPAttempt* attempt = new DnsTCPAttempt(
691 socket.Pass(),
692 query.Pass(),
693 base::Bind(&DnsTransactionImpl::OnAttemptComplete,
694 base::Unretained(this),
695 attempts_.size()));
696
697 attempts_.push_back(attempt);
698 had_tcp_attempt_ = true;
699
700 int rv = attempt->Start();
701 if (rv == ERR_IO_PENDING) {
702 // Custom timeout for TCP attempt.
703 base::TimeDelta timeout = timer_.GetCurrentDelay() * 2;
704 timer_.Start(FROM_HERE, timeout, this, &DnsTransactionImpl::OnTimeout);
705 }
706 return AttemptResult(rv, attempt);
707 }
708
443 // Begins query for the current name. Makes the first attempt. 709 // Begins query for the current name. Makes the first attempt.
444 AttemptResult StartQuery() { 710 AttemptResult StartQuery() {
445 std::string dotted_qname = DNSDomainToString(qnames_.front()); 711 std::string dotted_qname = DNSDomainToString(qnames_.front());
446 net_log_.BeginEvent(NetLog::TYPE_DNS_TRANSACTION_QUERY, 712 net_log_.BeginEvent(NetLog::TYPE_DNS_TRANSACTION_QUERY,
447 NetLog::StringCallback("qname", &dotted_qname)); 713 NetLog::StringCallback("qname", &dotted_qname));
448 714
449 first_server_index_ = session_->NextFirstServerIndex(); 715 first_server_index_ = session_->NextFirstServerIndex();
450 716
451 attempts_.clear(); 717 attempts_.clear();
718 had_tcp_attempt_ = false;
452 return MakeAttempt(); 719 return MakeAttempt();
453 } 720 }
454 721
455 void OnAttemptComplete(unsigned attempt_number, int rv) { 722 void OnAttemptComplete(unsigned attempt_number, int rv) {
456 if (callback_.is_null()) 723 if (callback_.is_null())
457 return; 724 return;
458 DCHECK_LT(attempt_number, attempts_.size()); 725 DCHECK_LT(attempt_number, attempts_.size());
459 const DnsUDPAttempt* attempt = attempts_[attempt_number]; 726 const DnsAttempt* attempt = attempts_[attempt_number];
460 AttemptResult result = ProcessAttemptResult(AttemptResult(rv, attempt)); 727 AttemptResult result = ProcessAttemptResult(AttemptResult(rv, attempt));
461 if (result.rv != ERR_IO_PENDING) 728 if (result.rv != ERR_IO_PENDING)
462 DoCallback(result); 729 DoCallback(result);
463 } 730 }
464 731
465 void LogResponse(const DnsUDPAttempt* attempt) { 732 void LogResponse(const DnsAttempt* attempt) {
466 if (attempt && attempt->response()) { 733 if (attempt && attempt->response()) {
467 net_log_.AddEvent( 734 net_log_.AddEvent(
468 NetLog::TYPE_DNS_TRANSACTION_RESPONSE, 735 NetLog::TYPE_DNS_TRANSACTION_RESPONSE,
469 base::Bind(&DnsUDPAttempt::NetLogResponseCallback, 736 base::Bind(&DnsAttempt::NetLogResponseCallback,
470 base::Unretained(attempt))); 737 base::Unretained(attempt)));
471 } 738 }
472 } 739 }
473 740
474 bool MoreAttemptsAllowed() const { 741 bool MoreAttemptsAllowed() const {
742 if (had_tcp_attempt_)
743 return false;
475 const DnsConfig& config = session_->config(); 744 const DnsConfig& config = session_->config();
476 return attempts_.size() < config.attempts * config.nameservers.size(); 745 return attempts_.size() < config.attempts * config.nameservers.size();
477 } 746 }
478 747
479 // Resolves the result of a DnsUDPAttempt until a terminal result is reached 748 // Resolves the result of a DnsAttempt until a terminal result is reached
480 // or it will complete asynchronously (ERR_IO_PENDING). 749 // or it will complete asynchronously (ERR_IO_PENDING).
481 AttemptResult ProcessAttemptResult(AttemptResult result) { 750 AttemptResult ProcessAttemptResult(AttemptResult result) {
482 while (result.rv != ERR_IO_PENDING) { 751 while (result.rv != ERR_IO_PENDING) {
483 LogResponse(result.attempt); 752 LogResponse(result.attempt);
484 753
485 switch (result.rv) { 754 switch (result.rv) {
486 case OK: 755 case OK:
487 net_log_.EndEventWithNetErrorCode( 756 net_log_.EndEventWithNetErrorCode(
488 NetLog::TYPE_DNS_TRANSACTION_QUERY, result.rv); 757 NetLog::TYPE_DNS_TRANSACTION_QUERY, result.rv);
489 DCHECK(result.attempt); 758 DCHECK(result.attempt);
(...skipping 11 matching lines...) Expand all
501 } 770 }
502 break; 771 break;
503 case ERR_CONNECTION_REFUSED: 772 case ERR_CONNECTION_REFUSED:
504 case ERR_DNS_TIMED_OUT: 773 case ERR_DNS_TIMED_OUT:
505 if (MoreAttemptsAllowed()) { 774 if (MoreAttemptsAllowed()) {
506 result = MakeAttempt(); 775 result = MakeAttempt();
507 } else { 776 } else {
508 return result; 777 return result;
509 } 778 }
510 break; 779 break;
780 case ERR_DNS_SERVER_REQUIRES_TCP:
781 result = MakeTCPAttempt(result.attempt);
mmenke 2012/12/19 16:44:09 Should we be remembering this somewhere? Or might
szym 2012/12/19 17:01:17 This is characteristic to the query more than the
mmenke 2012/12/19 17:13:51 If it's just for the query, I agree that it's not
782 break;
511 default: 783 default:
512 // Server failure. 784 // Server failure.
513 DCHECK(result.attempt); 785 DCHECK(result.attempt);
514 if (result.attempt != attempts_.back()) { 786 if (result.attempt != attempts_.back()) {
515 // This attempt already timed out. Ignore it. 787 // This attempt already timed out. Ignore it.
516 return AttemptResult(ERR_IO_PENDING, NULL); 788 return AttemptResult(ERR_IO_PENDING, NULL);
517 } 789 }
518 if (MoreAttemptsAllowed()) { 790 if (MoreAttemptsAllowed()) {
519 result = MakeAttempt(); 791 result = MakeAttempt();
520 } else if (result.rv == ERR_DNS_MALFORMED_RESPONSE) { 792 } else if (result.rv == ERR_DNS_MALFORMED_RESPONSE) {
(...skipping 22 matching lines...) Expand all
543 uint16 qtype_; 815 uint16 qtype_;
544 // Cleared in DoCallback. 816 // Cleared in DoCallback.
545 DnsTransactionFactory::CallbackType callback_; 817 DnsTransactionFactory::CallbackType callback_;
546 818
547 BoundNetLog net_log_; 819 BoundNetLog net_log_;
548 820
549 // Search list of fully-qualified DNS names to query next (in DNS format). 821 // Search list of fully-qualified DNS names to query next (in DNS format).
550 std::deque<std::string> qnames_; 822 std::deque<std::string> qnames_;
551 823
552 // List of attempts for the current name. 824 // List of attempts for the current name.
553 ScopedVector<DnsUDPAttempt> attempts_; 825 ScopedVector<DnsAttempt> attempts_;
826 bool had_tcp_attempt_;
554 827
555 // Index of the first server to try on each search query. 828 // Index of the first server to try on each search query.
556 int first_server_index_; 829 int first_server_index_;
557 830
558 base::OneShotTimer<DnsTransactionImpl> timer_; 831 base::OneShotTimer<DnsTransactionImpl> timer_;
559 832
560 DISALLOW_COPY_AND_ASSIGN(DnsTransactionImpl); 833 DISALLOW_COPY_AND_ASSIGN(DnsTransactionImpl);
561 }; 834 };
562 835
563 // ---------------------------------------------------------------------------- 836 // ----------------------------------------------------------------------------
(...skipping 25 matching lines...) Expand all
589 } // namespace 862 } // namespace
590 863
591 // static 864 // static
592 scoped_ptr<DnsTransactionFactory> DnsTransactionFactory::CreateFactory( 865 scoped_ptr<DnsTransactionFactory> DnsTransactionFactory::CreateFactory(
593 DnsSession* session) { 866 DnsSession* session) {
594 return scoped_ptr<DnsTransactionFactory>( 867 return scoped_ptr<DnsTransactionFactory>(
595 new DnsTransactionFactoryImpl(session)); 868 new DnsTransactionFactoryImpl(session));
596 } 869 }
597 870
598 } // namespace net 871 } // namespace net
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698