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.
5 #include "net/dns/dns_transaction.h"
11 #include "base/bind.h"
12 #include "base/memory/ref_counted.h"
13 #include "base/memory/scoped_ptr.h"
14 #include "base/memory/scoped_vector.h"
15 #include "base/memory/weak_ptr.h"
16 #include "base/message_loop.h"
17 #include "base/metrics/histogram.h"
18 #include "base/rand_util.h"
19 #include "base/stl_util.h"
20 #include "base/string_piece.h"
21 #include "base/threading/non_thread_safe.h"
22 #include "base/timer.h"
23 #include "base/values.h"
24 #include "net/base/big_endian.h"
25 #include "net/base/completion_callback.h"
26 #include "net/base/dns_util.h"
27 #include "net/base/io_buffer.h"
28 #include "net/base/ip_endpoint.h"
29 #include "net/base/net_errors.h"
30 #include "net/base/net_log.h"
31 #include "net/dns/dns_protocol.h"
32 #include "net/dns/dns_query.h"
33 #include "net/dns/dns_response.h"
34 #include "net/dns/dns_session.h"
35 #include "net/socket/stream_socket.h"
36 #include "net/udp/datagram_client_socket.h"
42 // Provide a common macro to simplify code and readability. We must use a
43 // macro as the underlying HISTOGRAM macro creates static variables.
44 #define DNS_HISTOGRAM(name, time) UMA_HISTOGRAM_CUSTOM_TIMES(name, time, \
45 base::TimeDelta::FromMilliseconds(1), base::TimeDelta::FromHours(1), 100)
47 // Count labels in the fully-qualified name in DNS format.
48 int CountLabels(const std::string
& name
) {
50 for (size_t i
= 0; i
< name
.size() && name
[i
]; i
+= name
[i
] + 1)
55 bool IsIPLiteral(const std::string
& hostname
) {
57 return ParseIPLiteralToNumber(hostname
, &ip
);
60 Value
* NetLogStartCallback(const std::string
* hostname
,
62 NetLog::LogLevel
/* log_level */) {
63 DictionaryValue
* dict
= new DictionaryValue();
64 dict
->SetString("hostname", *hostname
);
65 dict
->SetInteger("query_type", qtype
);
69 // ----------------------------------------------------------------------------
71 // A single asynchronous DNS exchange, which consists of sending out a
72 // DNS query, waiting for a response, and returning the response that it
73 // matches. Logging is done in the socket and in the outer DnsTransaction.
76 virtual ~DnsAttempt() {}
77 // Starts the attempt. Returns ERR_IO_PENDING if cannot complete synchronously
78 // and calls |callback| upon completion.
79 virtual int Start(const CompletionCallback
& callback
) = 0;
81 // Returns the query of this attempt.
82 virtual const DnsQuery
* GetQuery() const = 0;
84 // Returns the response or NULL if has not received a matching response from
86 virtual const DnsResponse
* GetResponse() const = 0;
88 // Returns the net log bound to the source of the socket.
89 virtual const BoundNetLog
& GetSocketNetLog() const = 0;
91 // Returns the index of the destination server within DnsConfig::nameservers.
92 virtual unsigned GetServerIndex() const = 0;
94 // Returns a Value representing the received response, along with a reference
95 // to the NetLog source source of the UDP socket used. The request must have
96 // completed before this is called.
97 Value
* NetLogResponseCallback(NetLog::LogLevel log_level
) const {
98 DCHECK(GetResponse()->IsValid());
100 DictionaryValue
* dict
= new DictionaryValue();
101 dict
->SetInteger("rcode", GetResponse()->rcode());
102 dict
->SetInteger("answer_count", GetResponse()->answer_count());
103 GetSocketNetLog().source().AddToEventParameters(dict
);
108 class DnsUDPAttempt
: public DnsAttempt
{
110 DnsUDPAttempt(scoped_ptr
<DnsSession::SocketLease
> socket_lease
,
111 scoped_ptr
<DnsQuery
> query
)
112 : next_state_(STATE_NONE
),
113 received_malformed_response_(false),
114 socket_lease_(socket_lease
.Pass()),
115 query_(query
.Pass()) {
119 virtual int Start(const CompletionCallback
& callback
) OVERRIDE
{
120 DCHECK_EQ(STATE_NONE
, next_state_
);
121 callback_
= callback
;
122 start_time_
= base::TimeTicks::Now();
123 next_state_
= STATE_SEND_QUERY
;
127 virtual const DnsQuery
* GetQuery() const OVERRIDE
{
131 virtual const DnsResponse
* GetResponse() const OVERRIDE
{
132 const DnsResponse
* resp
= response_
.get();
133 return (resp
!= NULL
&& resp
->IsValid()) ? resp
: NULL
;
136 virtual const BoundNetLog
& GetSocketNetLog() const OVERRIDE
{
137 return socket_lease_
->socket()->NetLog();
140 virtual unsigned GetServerIndex() const OVERRIDE
{
141 return socket_lease_
->server_index();
147 STATE_SEND_QUERY_COMPLETE
,
149 STATE_READ_RESPONSE_COMPLETE
,
153 DatagramClientSocket
* socket() {
154 return socket_lease_
->socket();
157 int DoLoop(int result
) {
158 CHECK_NE(STATE_NONE
, next_state_
);
161 State state
= next_state_
;
162 next_state_
= STATE_NONE
;
164 case STATE_SEND_QUERY
:
167 case STATE_SEND_QUERY_COMPLETE
:
168 rv
= DoSendQueryComplete(rv
);
170 case STATE_READ_RESPONSE
:
171 rv
= DoReadResponse();
173 case STATE_READ_RESPONSE_COMPLETE
:
174 rv
= DoReadResponseComplete(rv
);
180 } while (rv
!= ERR_IO_PENDING
&& next_state_
!= STATE_NONE
);
181 // If we received a malformed response, and are now waiting for another one,
182 // indicate to the transaction that the server might be misbehaving.
183 if (rv
== ERR_IO_PENDING
&& received_malformed_response_
)
184 return ERR_DNS_MALFORMED_RESPONSE
;
186 DCHECK_EQ(STATE_NONE
, next_state_
);
187 DNS_HISTOGRAM("AsyncDNS.UDPAttemptSuccess",
188 base::TimeTicks::Now() - start_time_
);
189 } else if (rv
!= ERR_IO_PENDING
) {
190 DNS_HISTOGRAM("AsyncDNS.UDPAttemptFail",
191 base::TimeTicks::Now() - start_time_
);
197 next_state_
= STATE_SEND_QUERY_COMPLETE
;
198 return socket()->Write(query_
->io_buffer(),
199 query_
->io_buffer()->size(),
200 base::Bind(&DnsUDPAttempt::OnIOComplete
,
201 base::Unretained(this)));
204 int DoSendQueryComplete(int rv
) {
205 DCHECK_NE(ERR_IO_PENDING
, rv
);
209 // Writing to UDP should not result in a partial datagram.
210 if (rv
!= query_
->io_buffer()->size())
211 return ERR_MSG_TOO_BIG
;
213 next_state_
= STATE_READ_RESPONSE
;
217 int DoReadResponse() {
218 next_state_
= STATE_READ_RESPONSE_COMPLETE
;
219 response_
.reset(new DnsResponse());
220 return socket()->Read(response_
->io_buffer(),
221 response_
->io_buffer()->size(),
222 base::Bind(&DnsUDPAttempt::OnIOComplete
,
223 base::Unretained(this)));
226 int DoReadResponseComplete(int rv
) {
227 DCHECK_NE(ERR_IO_PENDING
, rv
);
232 if (!response_
->InitParse(rv
, *query_
)) {
233 // Other implementations simply ignore mismatched responses. Since each
234 // DnsUDPAttempt binds to a different port, we might find that responses
235 // to previously timed out queries lead to failures in the future.
236 // Our solution is to make another attempt, in case the query truly
237 // failed, but keep this attempt alive, in case it was a false alarm.
238 received_malformed_response_
= true;
239 next_state_
= STATE_READ_RESPONSE
;
242 if (response_
->flags() & dns_protocol::kFlagTC
)
243 return ERR_DNS_SERVER_REQUIRES_TCP
;
244 // TODO(szym): Extract TTL for NXDOMAIN results. http://crbug.com/115051
245 if (response_
->rcode() == dns_protocol::kRcodeNXDOMAIN
)
246 return ERR_NAME_NOT_RESOLVED
;
247 if (response_
->rcode() != dns_protocol::kRcodeNOERROR
)
248 return ERR_DNS_SERVER_FAILED
;
253 void OnIOComplete(int rv
) {
255 if (rv
!= ERR_IO_PENDING
)
260 bool received_malformed_response_
;
261 base::TimeTicks start_time_
;
263 scoped_ptr
<DnsSession::SocketLease
> socket_lease_
;
264 scoped_ptr
<DnsQuery
> query_
;
266 scoped_ptr
<DnsResponse
> response_
;
268 CompletionCallback callback_
;
270 DISALLOW_COPY_AND_ASSIGN(DnsUDPAttempt
);
273 class DnsTCPAttempt
: public DnsAttempt
{
275 DnsTCPAttempt(scoped_ptr
<StreamSocket
> socket
,
276 scoped_ptr
<DnsQuery
> query
)
277 : next_state_(STATE_NONE
),
278 socket_(socket
.Pass()),
279 query_(query
.Pass()),
280 length_buffer_(new IOBufferWithSize(sizeof(uint16
))),
281 response_length_(0) {
285 virtual int Start(const CompletionCallback
& callback
) OVERRIDE
{
286 DCHECK_EQ(STATE_NONE
, next_state_
);
287 callback_
= callback
;
288 start_time_
= base::TimeTicks::Now();
289 next_state_
= STATE_CONNECT_COMPLETE
;
290 int rv
= socket_
->Connect(base::Bind(&DnsTCPAttempt::OnIOComplete
,
291 base::Unretained(this)));
292 if (rv
== ERR_IO_PENDING
)
297 virtual const DnsQuery
* GetQuery() const OVERRIDE
{
301 virtual const DnsResponse
* GetResponse() const OVERRIDE
{
302 const DnsResponse
* resp
= response_
.get();
303 return (resp
!= NULL
&& resp
->IsValid()) ? resp
: NULL
;
306 virtual const BoundNetLog
& GetSocketNetLog() const OVERRIDE
{
307 return socket_
->NetLog();
310 virtual unsigned GetServerIndex() const OVERRIDE
{
317 STATE_CONNECT_COMPLETE
,
325 int DoLoop(int result
) {
326 CHECK_NE(STATE_NONE
, next_state_
);
329 State state
= next_state_
;
330 next_state_
= STATE_NONE
;
332 case STATE_CONNECT_COMPLETE
:
333 rv
= DoConnectComplete(rv
);
335 case STATE_SEND_LENGTH
:
336 rv
= DoSendLength(rv
);
338 case STATE_SEND_QUERY
:
339 rv
= DoSendQuery(rv
);
341 case STATE_READ_LENGTH
:
342 rv
= DoReadLength(rv
);
344 case STATE_READ_RESPONSE
:
345 rv
= DoReadResponse(rv
);
351 } while (rv
!= ERR_IO_PENDING
&& next_state_
!= STATE_NONE
);
353 DCHECK_EQ(STATE_NONE
, next_state_
);
354 DNS_HISTOGRAM("AsyncDNS.TCPAttemptSuccess",
355 base::TimeTicks::Now() - start_time_
);
356 } else if (rv
!= ERR_IO_PENDING
) {
357 DNS_HISTOGRAM("AsyncDNS.TCPAttemptFail",
358 base::TimeTicks::Now() - start_time_
);
363 int DoConnectComplete(int rv
) {
364 DCHECK_NE(ERR_IO_PENDING
, rv
);
368 WriteBigEndian
<uint16
>(length_buffer_
->data(), query_
->io_buffer()->size());
369 buffer_
= new DrainableIOBuffer(length_buffer_
, length_buffer_
->size());
370 next_state_
= STATE_SEND_LENGTH
;
374 int DoSendLength(int rv
) {
375 DCHECK_NE(ERR_IO_PENDING
, rv
);
379 buffer_
->DidConsume(rv
);
380 if (buffer_
->BytesRemaining() > 0) {
381 next_state_
= STATE_SEND_LENGTH
;
382 return socket_
->Write(buffer_
,
383 buffer_
->BytesRemaining(),
384 base::Bind(&DnsTCPAttempt::OnIOComplete
,
385 base::Unretained(this)));
387 buffer_
= new DrainableIOBuffer(query_
->io_buffer(),
388 query_
->io_buffer()->size());
389 next_state_
= STATE_SEND_QUERY
;
393 int DoSendQuery(int rv
) {
394 DCHECK_NE(ERR_IO_PENDING
, rv
);
398 buffer_
->DidConsume(rv
);
399 if (buffer_
->BytesRemaining() > 0) {
400 next_state_
= STATE_SEND_QUERY
;
401 return socket_
->Write(buffer_
,
402 buffer_
->BytesRemaining(),
403 base::Bind(&DnsTCPAttempt::OnIOComplete
,
404 base::Unretained(this)));
406 buffer_
= new DrainableIOBuffer(length_buffer_
, length_buffer_
->size());
407 next_state_
= STATE_READ_LENGTH
;
411 int DoReadLength(int rv
) {
412 DCHECK_NE(ERR_IO_PENDING
, rv
);
416 buffer_
->DidConsume(rv
);
417 if (buffer_
->BytesRemaining() > 0) {
418 next_state_
= STATE_READ_LENGTH
;
419 return socket_
->Read(buffer_
,
420 buffer_
->BytesRemaining(),
421 base::Bind(&DnsTCPAttempt::OnIOComplete
,
422 base::Unretained(this)));
424 ReadBigEndian
<uint16
>(length_buffer_
->data(), &response_length_
);
425 // Check if advertised response is too short. (Optimization only.)
426 if (response_length_
< query_
->io_buffer()->size())
427 return ERR_DNS_MALFORMED_RESPONSE
;
428 // Allocate more space so that DnsResponse::InitParse sanity check passes.
429 response_
.reset(new DnsResponse(response_length_
+ 1));
430 buffer_
= new DrainableIOBuffer(response_
->io_buffer(), response_length_
);
431 next_state_
= STATE_READ_RESPONSE
;
435 int DoReadResponse(int rv
) {
436 DCHECK_NE(ERR_IO_PENDING
, rv
);
440 buffer_
->DidConsume(rv
);
441 if (buffer_
->BytesRemaining() > 0) {
442 next_state_
= STATE_READ_RESPONSE
;
443 return socket_
->Read(buffer_
,
444 buffer_
->BytesRemaining(),
445 base::Bind(&DnsTCPAttempt::OnIOComplete
,
446 base::Unretained(this)));
448 if (!response_
->InitParse(buffer_
->BytesConsumed(), *query_
))
449 return ERR_DNS_MALFORMED_RESPONSE
;
450 if (response_
->flags() & dns_protocol::kFlagTC
)
451 return ERR_UNEXPECTED
;
452 // TODO(szym): Frankly, none of these are expected.
453 if (response_
->rcode() == dns_protocol::kRcodeNXDOMAIN
)
454 return ERR_NAME_NOT_RESOLVED
;
455 if (response_
->rcode() != dns_protocol::kRcodeNOERROR
)
456 return ERR_DNS_SERVER_FAILED
;
461 void OnIOComplete(int rv
) {
463 if (rv
!= ERR_IO_PENDING
)
468 base::TimeTicks start_time_
;
470 scoped_ptr
<StreamSocket
> socket_
;
471 scoped_ptr
<DnsQuery
> query_
;
472 scoped_refptr
<IOBufferWithSize
> length_buffer_
;
473 scoped_refptr
<DrainableIOBuffer
> buffer_
;
475 uint16 response_length_
;
476 scoped_ptr
<DnsResponse
> response_
;
478 CompletionCallback callback_
;
480 DISALLOW_COPY_AND_ASSIGN(DnsTCPAttempt
);
483 // ----------------------------------------------------------------------------
485 // Implements DnsTransaction. Configuration is supplied by DnsSession.
486 // The suffix list is built according to the DnsConfig from the session.
487 // The timeout for each DnsUDPAttempt is given by DnsSession::NextTimeout.
488 // The first server to attempt on each query is given by
489 // DnsSession::NextFirstServerIndex, and the order is round-robin afterwards.
490 // Each server is attempted DnsConfig::attempts times.
491 class DnsTransactionImpl
: public DnsTransaction
,
492 public base::NonThreadSafe
,
493 public base::SupportsWeakPtr
<DnsTransactionImpl
> {
495 DnsTransactionImpl(DnsSession
* session
,
496 const std::string
& hostname
,
498 const DnsTransactionFactory::CallbackType
& callback
,
499 const BoundNetLog
& net_log
)
505 had_tcp_attempt_(false),
506 first_server_index_(0) {
508 DCHECK(!hostname_
.empty());
509 DCHECK(!callback_
.is_null());
510 DCHECK(!IsIPLiteral(hostname_
));
513 virtual ~DnsTransactionImpl() {
514 if (!callback_
.is_null()) {
515 net_log_
.EndEventWithNetErrorCode(NetLog::TYPE_DNS_TRANSACTION
,
517 } // otherwise logged in DoCallback or Start
520 virtual const std::string
& GetHostname() const OVERRIDE
{
521 DCHECK(CalledOnValidThread());
525 virtual uint16
GetType() const OVERRIDE
{
526 DCHECK(CalledOnValidThread());
530 virtual int Start() OVERRIDE
{
531 DCHECK(!callback_
.is_null());
532 DCHECK(attempts_
.empty());
533 net_log_
.BeginEvent(NetLog::TYPE_DNS_TRANSACTION
,
534 base::Bind(&NetLogStartCallback
, &hostname_
, qtype_
));
535 int rv
= PrepareSearch();
537 AttemptResult result
= ProcessAttemptResult(StartQuery());
538 if (result
.rv
== OK
) {
539 // DnsTransaction must never succeed synchronously.
540 MessageLoop::current()->PostTask(
542 base::Bind(&DnsTransactionImpl::DoCallback
, AsWeakPtr(), result
));
543 return ERR_IO_PENDING
;
547 if (rv
!= ERR_IO_PENDING
) {
549 net_log_
.EndEventWithNetErrorCode(NetLog::TYPE_DNS_TRANSACTION
, rv
);
556 // Wrapper for the result of a DnsUDPAttempt.
557 struct AttemptResult
{
558 AttemptResult(int rv
, const DnsAttempt
* attempt
)
559 : rv(rv
), attempt(attempt
) {}
562 const DnsAttempt
* attempt
;
565 // Prepares |qnames_| according to the DnsConfig.
566 int PrepareSearch() {
567 const DnsConfig
& config
= session_
->config();
569 std::string labeled_hostname
;
570 if (!DNSDomainFromDot(hostname_
, &labeled_hostname
))
571 return ERR_INVALID_ARGUMENT
;
573 if (hostname_
[hostname_
.size() - 1] == '.') {
574 // It's a fully-qualified name, no suffix search.
575 qnames_
.push_back(labeled_hostname
);
579 int ndots
= CountLabels(labeled_hostname
) - 1;
581 if (ndots
> 0 && !config
.append_to_multi_label_name
) {
582 qnames_
.push_back(labeled_hostname
);
586 // Set true when |labeled_hostname| is put on the list.
587 bool had_hostname
= false;
589 if (ndots
>= config
.ndots
) {
590 qnames_
.push_back(labeled_hostname
);
595 for (size_t i
= 0; i
< config
.search
.size(); ++i
) {
596 // Ignore invalid (too long) combinations.
597 if (!DNSDomainFromDot(hostname_
+ "." + config
.search
[i
], &qname
))
599 if (qname
.size() == labeled_hostname
.size()) {
604 qnames_
.push_back(qname
);
607 if (ndots
> 0 && !had_hostname
)
608 qnames_
.push_back(labeled_hostname
);
610 return qnames_
.empty() ? ERR_DNS_SEARCH_EMPTY
: OK
;
613 void DoCallback(AttemptResult result
) {
614 DCHECK(!callback_
.is_null());
615 DCHECK_NE(ERR_IO_PENDING
, result
.rv
);
616 const DnsResponse
* response
= result
.attempt
?
617 result
.attempt
->GetResponse() : NULL
;
618 CHECK(result
.rv
!= OK
|| response
!= NULL
);
622 DnsTransactionFactory::CallbackType callback
= callback_
;
625 net_log_
.EndEventWithNetErrorCode(NetLog::TYPE_DNS_TRANSACTION
, result
.rv
);
626 callback
.Run(this, result
.rv
, response
);
629 // Makes another attempt at the current name, |qnames_.front()|, using the
631 AttemptResult
MakeAttempt() {
632 unsigned attempt_number
= attempts_
.size();
634 uint16 id
= session_
->NextQueryId();
635 scoped_ptr
<DnsQuery
> query
;
636 if (attempts_
.empty()) {
637 query
.reset(new DnsQuery(id
, qnames_
.front(), qtype_
));
639 query
.reset(attempts_
[0]->GetQuery()->CloneWithNewId(id
));
642 const DnsConfig
& config
= session_
->config();
644 unsigned server_index
= first_server_index_
+
645 (attempt_number
% config
.nameservers
.size());
647 scoped_ptr
<DnsSession::SocketLease
> lease
=
648 session_
->AllocateSocket(server_index
, net_log_
.source());
650 bool got_socket
= !!lease
.get();
652 DnsUDPAttempt
* attempt
= new DnsUDPAttempt(lease
.Pass(), query
.Pass());
654 attempts_
.push_back(attempt
);
657 return AttemptResult(ERR_CONNECTION_REFUSED
, NULL
);
660 NetLog::TYPE_DNS_TRANSACTION_ATTEMPT
,
661 attempt
->GetSocketNetLog().source().ToEventParametersCallback());
663 int rv
= attempt
->Start(base::Bind(&DnsTransactionImpl::OnAttemptComplete
,
664 base::Unretained(this),
666 if (rv
== ERR_IO_PENDING
) {
667 base::TimeDelta timeout
= session_
->NextTimeout(attempt_number
);
668 timer_
.Start(FROM_HERE
, timeout
, this, &DnsTransactionImpl::OnTimeout
);
670 return AttemptResult(rv
, attempt
);
673 AttemptResult
MakeTCPAttempt(const DnsAttempt
* previous_attempt
) {
674 DCHECK(previous_attempt
);
675 DCHECK(!had_tcp_attempt_
);
677 scoped_ptr
<StreamSocket
> socket(
678 session_
->CreateTCPSocket(previous_attempt
->GetServerIndex(),
681 // TODO(szym): Reuse the same id to help the server?
682 uint16 id
= session_
->NextQueryId();
683 scoped_ptr
<DnsQuery
> query(
684 previous_attempt
->GetQuery()->CloneWithNewId(id
));
686 // Cancel all other attempts, no point waiting on them.
689 unsigned attempt_number
= attempts_
.size();
691 DnsTCPAttempt
* attempt
= new DnsTCPAttempt(socket
.Pass(), query
.Pass());
693 attempts_
.push_back(attempt
);
694 had_tcp_attempt_
= true;
697 NetLog::TYPE_DNS_TRANSACTION_TCP_ATTEMPT
,
698 attempt
->GetSocketNetLog().source().ToEventParametersCallback());
700 int rv
= attempt
->Start(base::Bind(&DnsTransactionImpl::OnAttemptComplete
,
701 base::Unretained(this),
703 if (rv
== ERR_IO_PENDING
) {
704 // Custom timeout for TCP attempt.
705 base::TimeDelta timeout
= timer_
.GetCurrentDelay() * 2;
706 timer_
.Start(FROM_HERE
, timeout
, this, &DnsTransactionImpl::OnTimeout
);
708 return AttemptResult(rv
, attempt
);
711 // Begins query for the current name. Makes the first attempt.
712 AttemptResult
StartQuery() {
713 std::string dotted_qname
= DNSDomainToString(qnames_
.front());
714 net_log_
.BeginEvent(NetLog::TYPE_DNS_TRANSACTION_QUERY
,
715 NetLog::StringCallback("qname", &dotted_qname
));
717 first_server_index_
= session_
->NextFirstServerIndex();
720 had_tcp_attempt_
= false;
721 return MakeAttempt();
724 void OnAttemptComplete(unsigned attempt_number
, int rv
) {
725 if (callback_
.is_null())
727 DCHECK_LT(attempt_number
, attempts_
.size());
728 const DnsAttempt
* attempt
= attempts_
[attempt_number
];
729 AttemptResult result
= ProcessAttemptResult(AttemptResult(rv
, attempt
));
730 if (result
.rv
!= ERR_IO_PENDING
)
734 void LogResponse(const DnsAttempt
* attempt
) {
735 if (attempt
&& attempt
->GetResponse()) {
737 NetLog::TYPE_DNS_TRANSACTION_RESPONSE
,
738 base::Bind(&DnsAttempt::NetLogResponseCallback
,
739 base::Unretained(attempt
)));
743 bool MoreAttemptsAllowed() const {
744 if (had_tcp_attempt_
)
746 const DnsConfig
& config
= session_
->config();
747 return attempts_
.size() < config
.attempts
* config
.nameservers
.size();
750 // Resolves the result of a DnsAttempt until a terminal result is reached
751 // or it will complete asynchronously (ERR_IO_PENDING).
752 AttemptResult
ProcessAttemptResult(AttemptResult result
) {
753 while (result
.rv
!= ERR_IO_PENDING
) {
754 LogResponse(result
.attempt
);
758 net_log_
.EndEventWithNetErrorCode(
759 NetLog::TYPE_DNS_TRANSACTION_QUERY
, result
.rv
);
760 DCHECK(result
.attempt
);
761 DCHECK(result
.attempt
->GetResponse());
763 case ERR_NAME_NOT_RESOLVED
:
764 net_log_
.EndEventWithNetErrorCode(
765 NetLog::TYPE_DNS_TRANSACTION_QUERY
, result
.rv
);
768 if (qnames_
.empty()) {
769 return AttemptResult(ERR_NAME_NOT_RESOLVED
, NULL
);
771 result
= StartQuery();
774 case ERR_CONNECTION_REFUSED
:
775 case ERR_DNS_TIMED_OUT
:
776 if (MoreAttemptsAllowed()) {
777 result
= MakeAttempt();
782 case ERR_DNS_SERVER_REQUIRES_TCP
:
783 result
= MakeTCPAttempt(result
.attempt
);
787 DCHECK(result
.attempt
);
788 if (result
.attempt
!= attempts_
.back()) {
789 // This attempt already timed out. Ignore it.
790 return AttemptResult(ERR_IO_PENDING
, NULL
);
792 if (MoreAttemptsAllowed()) {
793 result
= MakeAttempt();
794 } else if (result
.rv
== ERR_DNS_MALFORMED_RESPONSE
&&
796 // For UDP only, ignore the response and wait until the last attempt
798 return AttemptResult(ERR_IO_PENDING
, NULL
);
800 return AttemptResult(result
.rv
, NULL
);
809 if (callback_
.is_null())
811 AttemptResult result
= ProcessAttemptResult(
812 AttemptResult(ERR_DNS_TIMED_OUT
, NULL
));
813 if (result
.rv
!= ERR_IO_PENDING
)
817 scoped_refptr
<DnsSession
> session_
;
818 std::string hostname_
;
820 // Cleared in DoCallback.
821 DnsTransactionFactory::CallbackType callback_
;
823 BoundNetLog net_log_
;
825 // Search list of fully-qualified DNS names to query next (in DNS format).
826 std::deque
<std::string
> qnames_
;
828 // List of attempts for the current name.
829 ScopedVector
<DnsAttempt
> attempts_
;
830 bool had_tcp_attempt_
;
832 // Index of the first server to try on each search query.
833 int first_server_index_
;
835 base::OneShotTimer
<DnsTransactionImpl
> timer_
;
837 DISALLOW_COPY_AND_ASSIGN(DnsTransactionImpl
);
840 // ----------------------------------------------------------------------------
842 // Implementation of DnsTransactionFactory that returns instances of
843 // DnsTransactionImpl.
844 class DnsTransactionFactoryImpl
: public DnsTransactionFactory
{
846 explicit DnsTransactionFactoryImpl(DnsSession
* session
) {
850 virtual scoped_ptr
<DnsTransaction
> CreateTransaction(
851 const std::string
& hostname
,
853 const CallbackType
& callback
,
854 const BoundNetLog
& net_log
) OVERRIDE
{
855 return scoped_ptr
<DnsTransaction
>(new DnsTransactionImpl(session_
,
863 scoped_refptr
<DnsSession
> session_
;
869 scoped_ptr
<DnsTransactionFactory
> DnsTransactionFactory::CreateFactory(
870 DnsSession
* session
) {
871 return scoped_ptr
<DnsTransactionFactory
>(
872 new DnsTransactionFactoryImpl(session
));