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
38namespace net {
39
40namespace {
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.
48int 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
55bool IsIPLiteral(const std::string& hostname) {
56  IPAddressNumber ip;
57  return ParseIPLiteralToNumber(hostname, &ip);
58}
59
60base::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.
74class 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
132class 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
296class 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.
546class 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.
965class 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
987scoped_ptr<DnsTransactionFactory> DnsTransactionFactory::CreateFactory(
988    DnsSession* session) {
989  return scoped_ptr<DnsTransactionFactory>(
990      new DnsTransactionFactoryImpl(session));
991}
992
993}  // namespace net
994