Upstream version 9.38.198.0
[platform/framework/web/crosswalk.git] / src / net / dns / dns_transaction.cc
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 "net/dns/dns_transaction.h"
6
7 #include <deque>
8 #include <string>
9 #include <vector>
10
11 #include "base/big_endian.h"
12 #include "base/bind.h"
13 #include "base/memory/ref_counted.h"
14 #include "base/memory/scoped_ptr.h"
15 #include "base/memory/scoped_vector.h"
16 #include "base/memory/weak_ptr.h"
17 #include "base/message_loop/message_loop.h"
18 #include "base/metrics/histogram.h"
19 #include "base/rand_util.h"
20 #include "base/stl_util.h"
21 #include "base/strings/string_piece.h"
22 #include "base/threading/non_thread_safe.h"
23 #include "base/timer/timer.h"
24 #include "base/values.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"
37
38 namespace net {
39
40 namespace {
41
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)
46
47 // Count labels in the fully-qualified name in DNS format.
48 int CountLabels(const std::string& name) {
49   size_t count = 0;
50   for (size_t i = 0; i < name.size() && name[i]; i += name[i] + 1)
51     ++count;
52   return count;
53 }
54
55 bool IsIPLiteral(const std::string& hostname) {
56   IPAddressNumber ip;
57   return ParseIPLiteralToNumber(hostname, &ip);
58 }
59
60 base::Value* NetLogStartCallback(const std::string* hostname,
61                            uint16 qtype,
62                            NetLog::LogLevel /* log_level */) {
63   base::DictionaryValue* dict = new base::DictionaryValue();
64   dict->SetString("hostname", *hostname);
65   dict->SetInteger("query_type", qtype);
66   return dict;
67 };
68
69 // ----------------------------------------------------------------------------
70
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.
74 class DnsAttempt {
75  public:
76   explicit DnsAttempt(unsigned server_index)
77       : result_(ERR_FAILED), server_index_(server_index) {}
78
79   virtual ~DnsAttempt() {}
80   // Starts the attempt. Returns ERR_IO_PENDING if cannot complete synchronously
81   // and calls |callback| upon completion.
82   virtual int Start(const CompletionCallback& callback) = 0;
83
84   // Returns the query of this attempt.
85   virtual const DnsQuery* GetQuery() const = 0;
86
87   // Returns the response or NULL if has not received a matching response from
88   // the server.
89   virtual const DnsResponse* GetResponse() const = 0;
90
91   // Returns the net log bound to the source of the socket.
92   virtual const BoundNetLog& GetSocketNetLog() const = 0;
93
94   // Returns the index of the destination server within DnsConfig::nameservers.
95   unsigned server_index() const { return server_index_; }
96
97   // Returns a Value representing the received response, along with a reference
98   // to the NetLog source source of the UDP socket used.  The request must have
99   // completed before this is called.
100   base::Value* NetLogResponseCallback(NetLog::LogLevel log_level) const {
101     DCHECK(GetResponse()->IsValid());
102
103     base::DictionaryValue* dict = new base::DictionaryValue();
104     dict->SetInteger("rcode", GetResponse()->rcode());
105     dict->SetInteger("answer_count", GetResponse()->answer_count());
106     GetSocketNetLog().source().AddToEventParameters(dict);
107     return dict;
108   }
109
110   void set_result(int result) {
111     result_ = result;
112   }
113
114   // True if current attempt is pending (waiting for server response).
115   bool is_pending() const {
116     return result_ == ERR_IO_PENDING;
117   }
118
119   // True if attempt is completed (received server response).
120   bool is_completed() const {
121     return (result_ == OK) || (result_ == ERR_NAME_NOT_RESOLVED) ||
122         (result_ == ERR_DNS_SERVER_REQUIRES_TCP);
123   }
124
125  private:
126   // Result of last operation.
127   int result_;
128
129   const unsigned server_index_;
130 };
131
132 class DnsUDPAttempt : public DnsAttempt {
133  public:
134   DnsUDPAttempt(unsigned server_index,
135                 scoped_ptr<DnsSession::SocketLease> socket_lease,
136                 scoped_ptr<DnsQuery> query)
137       : DnsAttempt(server_index),
138         next_state_(STATE_NONE),
139         received_malformed_response_(false),
140         socket_lease_(socket_lease.Pass()),
141         query_(query.Pass()) {}
142
143   // DnsAttempt:
144   virtual int Start(const CompletionCallback& callback) OVERRIDE {
145     DCHECK_EQ(STATE_NONE, next_state_);
146     callback_ = callback;
147     start_time_ = base::TimeTicks::Now();
148     next_state_ = STATE_SEND_QUERY;
149     return DoLoop(OK);
150   }
151
152   virtual const DnsQuery* GetQuery() const OVERRIDE {
153     return query_.get();
154   }
155
156   virtual const DnsResponse* GetResponse() const OVERRIDE {
157     const DnsResponse* resp = response_.get();
158     return (resp != NULL && resp->IsValid()) ? resp : NULL;
159   }
160
161   virtual const BoundNetLog& GetSocketNetLog() const OVERRIDE {
162     return socket_lease_->socket()->NetLog();
163   }
164
165  private:
166   enum State {
167     STATE_SEND_QUERY,
168     STATE_SEND_QUERY_COMPLETE,
169     STATE_READ_RESPONSE,
170     STATE_READ_RESPONSE_COMPLETE,
171     STATE_NONE,
172   };
173
174   DatagramClientSocket* socket() {
175     return socket_lease_->socket();
176   }
177
178   int DoLoop(int result) {
179     CHECK_NE(STATE_NONE, next_state_);
180     int rv = result;
181     do {
182       State state = next_state_;
183       next_state_ = STATE_NONE;
184       switch (state) {
185         case STATE_SEND_QUERY:
186           rv = DoSendQuery();
187           break;
188         case STATE_SEND_QUERY_COMPLETE:
189           rv = DoSendQueryComplete(rv);
190           break;
191         case STATE_READ_RESPONSE:
192           rv = DoReadResponse();
193           break;
194         case STATE_READ_RESPONSE_COMPLETE:
195           rv = DoReadResponseComplete(rv);
196           break;
197         default:
198           NOTREACHED();
199           break;
200       }
201     } while (rv != ERR_IO_PENDING && next_state_ != STATE_NONE);
202
203     set_result(rv);
204     // If we received a malformed response, and are now waiting for another one,
205     // indicate to the transaction that the server might be misbehaving.
206     if (rv == ERR_IO_PENDING && received_malformed_response_)
207       return ERR_DNS_MALFORMED_RESPONSE;
208     if (rv == OK) {
209       DCHECK_EQ(STATE_NONE, next_state_);
210       DNS_HISTOGRAM("AsyncDNS.UDPAttemptSuccess",
211                     base::TimeTicks::Now() - start_time_);
212     } else if (rv != ERR_IO_PENDING) {
213       DNS_HISTOGRAM("AsyncDNS.UDPAttemptFail",
214                     base::TimeTicks::Now() - start_time_);
215     }
216     return rv;
217   }
218
219   int DoSendQuery() {
220     next_state_ = STATE_SEND_QUERY_COMPLETE;
221     return socket()->Write(query_->io_buffer(),
222                            query_->io_buffer()->size(),
223                            base::Bind(&DnsUDPAttempt::OnIOComplete,
224                                       base::Unretained(this)));
225   }
226
227   int DoSendQueryComplete(int rv) {
228     DCHECK_NE(ERR_IO_PENDING, rv);
229     if (rv < 0)
230       return rv;
231
232     // Writing to UDP should not result in a partial datagram.
233     if (rv != query_->io_buffer()->size())
234       return ERR_MSG_TOO_BIG;
235
236     next_state_ = STATE_READ_RESPONSE;
237     return OK;
238   }
239
240   int DoReadResponse() {
241     next_state_ = STATE_READ_RESPONSE_COMPLETE;
242     response_.reset(new DnsResponse());
243     return socket()->Read(response_->io_buffer(),
244                           response_->io_buffer()->size(),
245                           base::Bind(&DnsUDPAttempt::OnIOComplete,
246                                      base::Unretained(this)));
247   }
248
249   int DoReadResponseComplete(int rv) {
250     DCHECK_NE(ERR_IO_PENDING, rv);
251     if (rv < 0)
252       return rv;
253
254     DCHECK(rv);
255     if (!response_->InitParse(rv, *query_)) {
256       // Other implementations simply ignore mismatched responses. Since each
257       // DnsUDPAttempt binds to a different port, we might find that responses
258       // to previously timed out queries lead to failures in the future.
259       // Our solution is to make another attempt, in case the query truly
260       // failed, but keep this attempt alive, in case it was a false alarm.
261       received_malformed_response_ = true;
262       next_state_ = STATE_READ_RESPONSE;
263       return OK;
264     }
265     if (response_->flags() & dns_protocol::kFlagTC)
266       return ERR_DNS_SERVER_REQUIRES_TCP;
267     // TODO(szym): Extract TTL for NXDOMAIN results. http://crbug.com/115051
268     if (response_->rcode() == dns_protocol::kRcodeNXDOMAIN)
269       return ERR_NAME_NOT_RESOLVED;
270     if (response_->rcode() != dns_protocol::kRcodeNOERROR)
271       return ERR_DNS_SERVER_FAILED;
272
273     return OK;
274   }
275
276   void OnIOComplete(int rv) {
277     rv = DoLoop(rv);
278     if (rv != ERR_IO_PENDING)
279       callback_.Run(rv);
280   }
281
282   State next_state_;
283   bool received_malformed_response_;
284   base::TimeTicks start_time_;
285
286   scoped_ptr<DnsSession::SocketLease> socket_lease_;
287   scoped_ptr<DnsQuery> query_;
288
289   scoped_ptr<DnsResponse> response_;
290
291   CompletionCallback callback_;
292
293   DISALLOW_COPY_AND_ASSIGN(DnsUDPAttempt);
294 };
295
296 class DnsTCPAttempt : public DnsAttempt {
297  public:
298   DnsTCPAttempt(unsigned server_index,
299                 scoped_ptr<StreamSocket> socket,
300                 scoped_ptr<DnsQuery> query)
301       : DnsAttempt(server_index),
302         next_state_(STATE_NONE),
303         socket_(socket.Pass()),
304         query_(query.Pass()),
305         length_buffer_(new IOBufferWithSize(sizeof(uint16))),
306         response_length_(0) {}
307
308   // DnsAttempt:
309   virtual int Start(const CompletionCallback& callback) OVERRIDE {
310     DCHECK_EQ(STATE_NONE, next_state_);
311     callback_ = callback;
312     start_time_ = base::TimeTicks::Now();
313     next_state_ = STATE_CONNECT_COMPLETE;
314     int rv = socket_->Connect(base::Bind(&DnsTCPAttempt::OnIOComplete,
315                                          base::Unretained(this)));
316     if (rv == ERR_IO_PENDING) {
317       set_result(rv);
318       return rv;
319     }
320     return DoLoop(rv);
321   }
322
323   virtual const DnsQuery* GetQuery() const OVERRIDE {
324     return query_.get();
325   }
326
327   virtual const DnsResponse* GetResponse() const OVERRIDE {
328     const DnsResponse* resp = response_.get();
329     return (resp != NULL && resp->IsValid()) ? resp : NULL;
330   }
331
332   virtual const BoundNetLog& GetSocketNetLog() const OVERRIDE {
333     return socket_->NetLog();
334   }
335
336  private:
337   enum State {
338     STATE_CONNECT_COMPLETE,
339     STATE_SEND_LENGTH,
340     STATE_SEND_QUERY,
341     STATE_READ_LENGTH,
342     STATE_READ_LENGTH_COMPLETE,
343     STATE_READ_RESPONSE,
344     STATE_READ_RESPONSE_COMPLETE,
345     STATE_NONE,
346   };
347
348   int DoLoop(int result) {
349     CHECK_NE(STATE_NONE, next_state_);
350     int rv = result;
351     do {
352       State state = next_state_;
353       next_state_ = STATE_NONE;
354       switch (state) {
355         case STATE_CONNECT_COMPLETE:
356           rv = DoConnectComplete(rv);
357           break;
358         case STATE_SEND_LENGTH:
359           rv = DoSendLength(rv);
360           break;
361         case STATE_SEND_QUERY:
362           rv = DoSendQuery(rv);
363           break;
364         case STATE_READ_LENGTH:
365           rv = DoReadLength(rv);
366           break;
367         case STATE_READ_LENGTH_COMPLETE:
368           rv = DoReadLengthComplete(rv);
369           break;
370         case STATE_READ_RESPONSE:
371           rv = DoReadResponse(rv);
372           break;
373         case STATE_READ_RESPONSE_COMPLETE:
374           rv = DoReadResponseComplete(rv);
375           break;
376         default:
377           NOTREACHED();
378           break;
379       }
380     } while (rv != ERR_IO_PENDING && next_state_ != STATE_NONE);
381
382     set_result(rv);
383     if (rv == OK) {
384       DCHECK_EQ(STATE_NONE, next_state_);
385       DNS_HISTOGRAM("AsyncDNS.TCPAttemptSuccess",
386                     base::TimeTicks::Now() - start_time_);
387     } else if (rv != ERR_IO_PENDING) {
388       DNS_HISTOGRAM("AsyncDNS.TCPAttemptFail",
389                     base::TimeTicks::Now() - start_time_);
390     }
391     return rv;
392   }
393
394   int DoConnectComplete(int rv) {
395     DCHECK_NE(ERR_IO_PENDING, rv);
396     if (rv < 0)
397       return rv;
398
399     base::WriteBigEndian<uint16>(length_buffer_->data(),
400                                  query_->io_buffer()->size());
401     buffer_ =
402         new DrainableIOBuffer(length_buffer_.get(), length_buffer_->size());
403     next_state_ = STATE_SEND_LENGTH;
404     return OK;
405   }
406
407   int DoSendLength(int rv) {
408     DCHECK_NE(ERR_IO_PENDING, rv);
409     if (rv < 0)
410       return rv;
411
412     buffer_->DidConsume(rv);
413     if (buffer_->BytesRemaining() > 0) {
414       next_state_ = STATE_SEND_LENGTH;
415       return socket_->Write(
416           buffer_.get(),
417           buffer_->BytesRemaining(),
418           base::Bind(&DnsTCPAttempt::OnIOComplete, base::Unretained(this)));
419     }
420     buffer_ = new DrainableIOBuffer(query_->io_buffer(),
421                                     query_->io_buffer()->size());
422     next_state_ = STATE_SEND_QUERY;
423     return OK;
424   }
425
426   int DoSendQuery(int rv) {
427     DCHECK_NE(ERR_IO_PENDING, rv);
428     if (rv < 0)
429       return rv;
430
431     buffer_->DidConsume(rv);
432     if (buffer_->BytesRemaining() > 0) {
433       next_state_ = STATE_SEND_QUERY;
434       return socket_->Write(
435           buffer_.get(),
436           buffer_->BytesRemaining(),
437           base::Bind(&DnsTCPAttempt::OnIOComplete, base::Unretained(this)));
438     }
439     buffer_ =
440         new DrainableIOBuffer(length_buffer_.get(), length_buffer_->size());
441     next_state_ = STATE_READ_LENGTH;
442     return OK;
443   }
444
445   int DoReadLength(int rv) {
446     DCHECK_EQ(OK, rv);
447
448     next_state_ = STATE_READ_LENGTH_COMPLETE;
449     return ReadIntoBuffer();
450   }
451
452   int DoReadLengthComplete(int rv) {
453     DCHECK_NE(ERR_IO_PENDING, rv);
454     if (rv < 0)
455       return rv;
456     if (rv == 0)
457       return ERR_CONNECTION_CLOSED;
458
459     buffer_->DidConsume(rv);
460     if (buffer_->BytesRemaining() > 0) {
461       next_state_ = STATE_READ_LENGTH;
462       return OK;
463     }
464
465     base::ReadBigEndian<uint16>(length_buffer_->data(), &response_length_);
466     // Check if advertised response is too short. (Optimization only.)
467     if (response_length_ < query_->io_buffer()->size())
468       return ERR_DNS_MALFORMED_RESPONSE;
469     // Allocate more space so that DnsResponse::InitParse sanity check passes.
470     response_.reset(new DnsResponse(response_length_ + 1));
471     buffer_ = new DrainableIOBuffer(response_->io_buffer(), response_length_);
472     next_state_ = STATE_READ_RESPONSE;
473     return OK;
474   }
475
476   int DoReadResponse(int rv) {
477     DCHECK_EQ(OK, rv);
478
479     next_state_ = STATE_READ_RESPONSE_COMPLETE;
480     return ReadIntoBuffer();
481   }
482
483   int DoReadResponseComplete(int rv) {
484     DCHECK_NE(ERR_IO_PENDING, rv);
485     if (rv < 0)
486       return rv;
487     if (rv == 0)
488       return ERR_CONNECTION_CLOSED;
489
490     buffer_->DidConsume(rv);
491     if (buffer_->BytesRemaining() > 0) {
492       next_state_ = STATE_READ_RESPONSE;
493       return OK;
494     }
495
496     if (!response_->InitParse(buffer_->BytesConsumed(), *query_))
497       return ERR_DNS_MALFORMED_RESPONSE;
498     if (response_->flags() & dns_protocol::kFlagTC)
499       return ERR_UNEXPECTED;
500     // TODO(szym): Frankly, none of these are expected.
501     if (response_->rcode() == dns_protocol::kRcodeNXDOMAIN)
502       return ERR_NAME_NOT_RESOLVED;
503     if (response_->rcode() != dns_protocol::kRcodeNOERROR)
504       return ERR_DNS_SERVER_FAILED;
505
506     return OK;
507   }
508
509   void OnIOComplete(int rv) {
510     rv = DoLoop(rv);
511     if (rv != ERR_IO_PENDING)
512       callback_.Run(rv);
513   }
514
515   int ReadIntoBuffer() {
516     return socket_->Read(
517         buffer_.get(),
518         buffer_->BytesRemaining(),
519         base::Bind(&DnsTCPAttempt::OnIOComplete, base::Unretained(this)));
520   }
521
522   State next_state_;
523   base::TimeTicks start_time_;
524
525   scoped_ptr<StreamSocket> socket_;
526   scoped_ptr<DnsQuery> query_;
527   scoped_refptr<IOBufferWithSize> length_buffer_;
528   scoped_refptr<DrainableIOBuffer> buffer_;
529
530   uint16 response_length_;
531   scoped_ptr<DnsResponse> response_;
532
533   CompletionCallback callback_;
534
535   DISALLOW_COPY_AND_ASSIGN(DnsTCPAttempt);
536 };
537
538 // ----------------------------------------------------------------------------
539
540 // Implements DnsTransaction. Configuration is supplied by DnsSession.
541 // The suffix list is built according to the DnsConfig from the session.
542 // The timeout for each DnsUDPAttempt is given by DnsSession::NextTimeout.
543 // The first server to attempt on each query is given by
544 // DnsSession::NextFirstServerIndex, and the order is round-robin afterwards.
545 // Each server is attempted DnsConfig::attempts times.
546 class DnsTransactionImpl : public DnsTransaction,
547                            public base::NonThreadSafe,
548                            public base::SupportsWeakPtr<DnsTransactionImpl> {
549  public:
550   DnsTransactionImpl(DnsSession* session,
551                      const std::string& hostname,
552                      uint16 qtype,
553                      const DnsTransactionFactory::CallbackType& callback,
554                      const BoundNetLog& net_log)
555     : session_(session),
556       hostname_(hostname),
557       qtype_(qtype),
558       callback_(callback),
559       net_log_(net_log),
560       qnames_initial_size_(0),
561       attempts_count_(0),
562       had_tcp_attempt_(false),
563       first_server_index_(0) {
564     DCHECK(session_.get());
565     DCHECK(!hostname_.empty());
566     DCHECK(!callback_.is_null());
567     DCHECK(!IsIPLiteral(hostname_));
568   }
569
570   virtual ~DnsTransactionImpl() {
571     if (!callback_.is_null()) {
572       net_log_.EndEventWithNetErrorCode(NetLog::TYPE_DNS_TRANSACTION,
573                                         ERR_ABORTED);
574     }  // otherwise logged in DoCallback or Start
575   }
576
577   virtual const std::string& GetHostname() const OVERRIDE {
578     DCHECK(CalledOnValidThread());
579     return hostname_;
580   }
581
582   virtual uint16 GetType() const OVERRIDE {
583     DCHECK(CalledOnValidThread());
584     return qtype_;
585   }
586
587   virtual void Start() OVERRIDE {
588     DCHECK(!callback_.is_null());
589     DCHECK(attempts_.empty());
590     net_log_.BeginEvent(NetLog::TYPE_DNS_TRANSACTION,
591                         base::Bind(&NetLogStartCallback, &hostname_, qtype_));
592     AttemptResult result(PrepareSearch(), NULL);
593     if (result.rv == OK) {
594       qnames_initial_size_ = qnames_.size();
595       if (qtype_ == dns_protocol::kTypeA)
596         UMA_HISTOGRAM_COUNTS("AsyncDNS.SuffixSearchStart", qnames_.size());
597       result = ProcessAttemptResult(StartQuery());
598     }
599
600     // Must always return result asynchronously, to avoid reentrancy.
601     if (result.rv != ERR_IO_PENDING) {
602       base::MessageLoop::current()->PostTask(
603           FROM_HERE,
604           base::Bind(&DnsTransactionImpl::DoCallback, AsWeakPtr(), result));
605     }
606   }
607
608  private:
609   // Wrapper for the result of a DnsUDPAttempt.
610   struct AttemptResult {
611     AttemptResult(int rv, const DnsAttempt* attempt)
612         : rv(rv), attempt(attempt) {}
613
614     int rv;
615     const DnsAttempt* attempt;
616   };
617
618   // Prepares |qnames_| according to the DnsConfig.
619   int PrepareSearch() {
620     const DnsConfig& config = session_->config();
621
622     std::string labeled_hostname;
623     if (!DNSDomainFromDot(hostname_, &labeled_hostname))
624       return ERR_INVALID_ARGUMENT;
625
626     if (hostname_[hostname_.size() - 1] == '.') {
627       // It's a fully-qualified name, no suffix search.
628       qnames_.push_back(labeled_hostname);
629       return OK;
630     }
631
632     int ndots = CountLabels(labeled_hostname) - 1;
633
634     if (ndots > 0 && !config.append_to_multi_label_name) {
635       qnames_.push_back(labeled_hostname);
636       return OK;
637     }
638
639     // Set true when |labeled_hostname| is put on the list.
640     bool had_hostname = false;
641
642     if (ndots >= config.ndots) {
643       qnames_.push_back(labeled_hostname);
644       had_hostname = true;
645     }
646
647     std::string qname;
648     for (size_t i = 0; i < config.search.size(); ++i) {
649       // Ignore invalid (too long) combinations.
650       if (!DNSDomainFromDot(hostname_ + "." + config.search[i], &qname))
651         continue;
652       if (qname.size() == labeled_hostname.size()) {
653         if (had_hostname)
654           continue;
655         had_hostname = true;
656       }
657       qnames_.push_back(qname);
658     }
659
660     if (ndots > 0 && !had_hostname)
661       qnames_.push_back(labeled_hostname);
662
663     return qnames_.empty() ? ERR_DNS_SEARCH_EMPTY : OK;
664   }
665
666   void DoCallback(AttemptResult result) {
667     DCHECK(!callback_.is_null());
668     DCHECK_NE(ERR_IO_PENDING, result.rv);
669     const DnsResponse* response = result.attempt ?
670         result.attempt->GetResponse() : NULL;
671     CHECK(result.rv != OK || response != NULL);
672
673     timer_.Stop();
674     RecordLostPacketsIfAny();
675     if (result.rv == OK)
676       UMA_HISTOGRAM_COUNTS("AsyncDNS.AttemptCountSuccess", attempts_count_);
677     else
678       UMA_HISTOGRAM_COUNTS("AsyncDNS.AttemptCountFail", attempts_count_);
679
680     if (response && qtype_ == dns_protocol::kTypeA) {
681       UMA_HISTOGRAM_COUNTS("AsyncDNS.SuffixSearchRemain", qnames_.size());
682       UMA_HISTOGRAM_COUNTS("AsyncDNS.SuffixSearchDone",
683                            qnames_initial_size_ - qnames_.size());
684     }
685
686     DnsTransactionFactory::CallbackType callback = callback_;
687     callback_.Reset();
688
689     net_log_.EndEventWithNetErrorCode(NetLog::TYPE_DNS_TRANSACTION, result.rv);
690     callback.Run(this, result.rv, response);
691   }
692
693   // Makes another attempt at the current name, |qnames_.front()|, using the
694   // next nameserver.
695   AttemptResult MakeAttempt() {
696     unsigned attempt_number = attempts_.size();
697
698     uint16 id = session_->NextQueryId();
699     scoped_ptr<DnsQuery> query;
700     if (attempts_.empty()) {
701       query.reset(new DnsQuery(id, qnames_.front(), qtype_));
702     } else {
703       query.reset(attempts_[0]->GetQuery()->CloneWithNewId(id));
704     }
705
706     const DnsConfig& config = session_->config();
707
708     unsigned server_index =
709         (first_server_index_ + attempt_number) % config.nameservers.size();
710     // Skip over known failed servers.
711     server_index = session_->NextGoodServerIndex(server_index);
712
713     scoped_ptr<DnsSession::SocketLease> lease =
714         session_->AllocateSocket(server_index, net_log_.source());
715
716     bool got_socket = !!lease.get();
717
718     DnsUDPAttempt* attempt =
719         new DnsUDPAttempt(server_index, lease.Pass(), query.Pass());
720
721     attempts_.push_back(attempt);
722     ++attempts_count_;
723
724     if (!got_socket)
725       return AttemptResult(ERR_CONNECTION_REFUSED, NULL);
726
727     net_log_.AddEvent(
728         NetLog::TYPE_DNS_TRANSACTION_ATTEMPT,
729         attempt->GetSocketNetLog().source().ToEventParametersCallback());
730
731     int rv = attempt->Start(
732         base::Bind(&DnsTransactionImpl::OnUdpAttemptComplete,
733                    base::Unretained(this), attempt_number,
734                    base::TimeTicks::Now()));
735     if (rv == ERR_IO_PENDING) {
736       base::TimeDelta timeout = session_->NextTimeout(server_index,
737                                                       attempt_number);
738       timer_.Start(FROM_HERE, timeout, this, &DnsTransactionImpl::OnTimeout);
739     }
740     return AttemptResult(rv, attempt);
741   }
742
743   AttemptResult MakeTCPAttempt(const DnsAttempt* previous_attempt) {
744     DCHECK(previous_attempt);
745     DCHECK(!had_tcp_attempt_);
746
747     unsigned server_index = previous_attempt->server_index();
748
749     scoped_ptr<StreamSocket> socket(
750         session_->CreateTCPSocket(server_index, net_log_.source()));
751
752     // TODO(szym): Reuse the same id to help the server?
753     uint16 id = session_->NextQueryId();
754     scoped_ptr<DnsQuery> query(
755         previous_attempt->GetQuery()->CloneWithNewId(id));
756
757     RecordLostPacketsIfAny();
758     // Cancel all other attempts, no point waiting on them.
759     attempts_.clear();
760
761     unsigned attempt_number = attempts_.size();
762
763     DnsTCPAttempt* attempt = new DnsTCPAttempt(server_index, socket.Pass(),
764                                                query.Pass());
765
766     attempts_.push_back(attempt);
767     ++attempts_count_;
768     had_tcp_attempt_ = true;
769
770     net_log_.AddEvent(
771         NetLog::TYPE_DNS_TRANSACTION_TCP_ATTEMPT,
772         attempt->GetSocketNetLog().source().ToEventParametersCallback());
773
774     int rv = attempt->Start(base::Bind(&DnsTransactionImpl::OnAttemptComplete,
775                                        base::Unretained(this),
776                                        attempt_number));
777     if (rv == ERR_IO_PENDING) {
778       // Custom timeout for TCP attempt.
779       base::TimeDelta timeout = timer_.GetCurrentDelay() * 2;
780       timer_.Start(FROM_HERE, timeout, this, &DnsTransactionImpl::OnTimeout);
781     }
782     return AttemptResult(rv, attempt);
783   }
784
785   // Begins query for the current name. Makes the first attempt.
786   AttemptResult StartQuery() {
787     std::string dotted_qname = DNSDomainToString(qnames_.front());
788     net_log_.BeginEvent(NetLog::TYPE_DNS_TRANSACTION_QUERY,
789                         NetLog::StringCallback("qname", &dotted_qname));
790
791     first_server_index_ = session_->NextFirstServerIndex();
792     RecordLostPacketsIfAny();
793     attempts_.clear();
794     had_tcp_attempt_ = false;
795     return MakeAttempt();
796   }
797
798   void OnUdpAttemptComplete(unsigned attempt_number,
799                             base::TimeTicks start,
800                             int rv) {
801     DCHECK_LT(attempt_number, attempts_.size());
802     const DnsAttempt* attempt = attempts_[attempt_number];
803     if (attempt->GetResponse()) {
804       session_->RecordRTT(attempt->server_index(),
805                           base::TimeTicks::Now() - start);
806     }
807     OnAttemptComplete(attempt_number, rv);
808   }
809
810   void OnAttemptComplete(unsigned attempt_number, int rv) {
811     if (callback_.is_null())
812       return;
813     DCHECK_LT(attempt_number, attempts_.size());
814     const DnsAttempt* attempt = attempts_[attempt_number];
815     AttemptResult result = ProcessAttemptResult(AttemptResult(rv, attempt));
816     if (result.rv != ERR_IO_PENDING)
817       DoCallback(result);
818   }
819
820   // Record packet loss for any incomplete attempts.
821   void RecordLostPacketsIfAny() {
822     // Loop through attempts until we find first that is completed
823     size_t first_completed = 0;
824     for (first_completed = 0; first_completed < attempts_.size();
825         ++first_completed) {
826       if (attempts_[first_completed]->is_completed())
827         break;
828     }
829     // If there were no completed attempts, then we must be offline, so don't
830     // record any attempts as lost packets.
831     if (first_completed == attempts_.size())
832       return;
833
834     size_t num_servers = session_->config().nameservers.size();
835     std::vector<int> server_attempts(num_servers);
836     for (size_t i = 0; i < first_completed; ++i) {
837       unsigned server_index = attempts_[i]->server_index();
838       int server_attempt = server_attempts[server_index]++;
839       // Don't record lost packet unless attempt is in pending state.
840       if (!attempts_[i]->is_pending())
841         continue;
842       session_->RecordLostPacket(server_index, server_attempt);
843     }
844   }
845
846   void LogResponse(const DnsAttempt* attempt) {
847     if (attempt && attempt->GetResponse()) {
848       net_log_.AddEvent(
849           NetLog::TYPE_DNS_TRANSACTION_RESPONSE,
850           base::Bind(&DnsAttempt::NetLogResponseCallback,
851                      base::Unretained(attempt)));
852     }
853   }
854
855   bool MoreAttemptsAllowed() const {
856     if (had_tcp_attempt_)
857       return false;
858     const DnsConfig& config = session_->config();
859     return attempts_.size() < config.attempts * config.nameservers.size();
860   }
861
862   // Resolves the result of a DnsAttempt until a terminal result is reached
863   // or it will complete asynchronously (ERR_IO_PENDING).
864   AttemptResult ProcessAttemptResult(AttemptResult result) {
865     while (result.rv != ERR_IO_PENDING) {
866       LogResponse(result.attempt);
867
868       switch (result.rv) {
869         case OK:
870           session_->RecordServerSuccess(result.attempt->server_index());
871           net_log_.EndEventWithNetErrorCode(NetLog::TYPE_DNS_TRANSACTION_QUERY,
872                                             result.rv);
873           DCHECK(result.attempt);
874           DCHECK(result.attempt->GetResponse());
875           return result;
876         case ERR_NAME_NOT_RESOLVED:
877           session_->RecordServerSuccess(result.attempt->server_index());
878           net_log_.EndEventWithNetErrorCode(NetLog::TYPE_DNS_TRANSACTION_QUERY,
879                                             result.rv);
880           // Try next suffix.
881           qnames_.pop_front();
882           if (qnames_.empty()) {
883             return AttemptResult(ERR_NAME_NOT_RESOLVED, NULL);
884           } else {
885             result = StartQuery();
886           }
887           break;
888         case ERR_CONNECTION_REFUSED:
889         case ERR_DNS_TIMED_OUT:
890           if (result.attempt)
891             session_->RecordServerFailure(result.attempt->server_index());
892           if (MoreAttemptsAllowed()) {
893             result = MakeAttempt();
894           } else {
895             return result;
896           }
897           break;
898         case ERR_DNS_SERVER_REQUIRES_TCP:
899           result = MakeTCPAttempt(result.attempt);
900           break;
901         default:
902           // Server failure.
903           DCHECK(result.attempt);
904           if (result.attempt != attempts_.back()) {
905             // This attempt already timed out. Ignore it.
906             session_->RecordServerFailure(result.attempt->server_index());
907             return AttemptResult(ERR_IO_PENDING, NULL);
908           }
909           if (MoreAttemptsAllowed()) {
910             result = MakeAttempt();
911           } else if (result.rv == ERR_DNS_MALFORMED_RESPONSE &&
912                      !had_tcp_attempt_) {
913             // For UDP only, ignore the response and wait until the last attempt
914             // times out.
915             return AttemptResult(ERR_IO_PENDING, NULL);
916           } else {
917             return AttemptResult(result.rv, NULL);
918           }
919           break;
920       }
921     }
922     return result;
923   }
924
925   void OnTimeout() {
926     if (callback_.is_null())
927       return;
928     DCHECK(!attempts_.empty());
929     AttemptResult result = ProcessAttemptResult(
930         AttemptResult(ERR_DNS_TIMED_OUT, attempts_.back()));
931     if (result.rv != ERR_IO_PENDING)
932       DoCallback(result);
933   }
934
935   scoped_refptr<DnsSession> session_;
936   std::string hostname_;
937   uint16 qtype_;
938   // Cleared in DoCallback.
939   DnsTransactionFactory::CallbackType callback_;
940
941   BoundNetLog net_log_;
942
943   // Search list of fully-qualified DNS names to query next (in DNS format).
944   std::deque<std::string> qnames_;
945   size_t qnames_initial_size_;
946
947   // List of attempts for the current name.
948   ScopedVector<DnsAttempt> attempts_;
949   // Count of attempts, not reset when |attempts_| vector is cleared.
950   int  attempts_count_;
951   bool had_tcp_attempt_;
952
953   // Index of the first server to try on each search query.
954   int first_server_index_;
955
956   base::OneShotTimer<DnsTransactionImpl> timer_;
957
958   DISALLOW_COPY_AND_ASSIGN(DnsTransactionImpl);
959 };
960
961 // ----------------------------------------------------------------------------
962
963 // Implementation of DnsTransactionFactory that returns instances of
964 // DnsTransactionImpl.
965 class DnsTransactionFactoryImpl : public DnsTransactionFactory {
966  public:
967   explicit DnsTransactionFactoryImpl(DnsSession* session) {
968     session_ = session;
969   }
970
971   virtual scoped_ptr<DnsTransaction> CreateTransaction(
972       const std::string& hostname,
973       uint16 qtype,
974       const CallbackType& callback,
975       const BoundNetLog& net_log) OVERRIDE {
976     return scoped_ptr<DnsTransaction>(new DnsTransactionImpl(
977         session_.get(), hostname, qtype, callback, net_log));
978   }
979
980  private:
981   scoped_refptr<DnsSession> session_;
982 };
983
984 }  // namespace
985
986 // static
987 scoped_ptr<DnsTransactionFactory> DnsTransactionFactory::CreateFactory(
988     DnsSession* session) {
989   return scoped_ptr<DnsTransactionFactory>(
990       new DnsTransactionFactoryImpl(session));
991 }
992
993 }  // namespace net