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_RESPONSE,
343    STATE_NONE,
344  };
345
346  int DoLoop(int result) {
347    CHECK_NE(STATE_NONE, next_state_);
348    int rv = result;
349    do {
350      State state = next_state_;
351      next_state_ = STATE_NONE;
352      switch (state) {
353        case STATE_CONNECT_COMPLETE:
354          rv = DoConnectComplete(rv);
355          break;
356        case STATE_SEND_LENGTH:
357          rv = DoSendLength(rv);
358          break;
359        case STATE_SEND_QUERY:
360          rv = DoSendQuery(rv);
361          break;
362        case STATE_READ_LENGTH:
363          rv = DoReadLength(rv);
364          break;
365        case STATE_READ_RESPONSE:
366          rv = DoReadResponse(rv);
367          break;
368        default:
369          NOTREACHED();
370          break;
371      }
372    } while (rv != ERR_IO_PENDING && next_state_ != STATE_NONE);
373
374    set_result(rv);
375    if (rv == OK) {
376      DCHECK_EQ(STATE_NONE, next_state_);
377      DNS_HISTOGRAM("AsyncDNS.TCPAttemptSuccess",
378                    base::TimeTicks::Now() - start_time_);
379    } else if (rv != ERR_IO_PENDING) {
380      DNS_HISTOGRAM("AsyncDNS.TCPAttemptFail",
381                    base::TimeTicks::Now() - start_time_);
382    }
383    return rv;
384  }
385
386  int DoConnectComplete(int rv) {
387    DCHECK_NE(ERR_IO_PENDING, rv);
388    if (rv < 0)
389      return rv;
390
391    base::WriteBigEndian<uint16>(length_buffer_->data(),
392                                 query_->io_buffer()->size());
393    buffer_ =
394        new DrainableIOBuffer(length_buffer_.get(), length_buffer_->size());
395    next_state_ = STATE_SEND_LENGTH;
396    return OK;
397  }
398
399  int DoSendLength(int rv) {
400    DCHECK_NE(ERR_IO_PENDING, rv);
401    if (rv < 0)
402      return rv;
403
404    buffer_->DidConsume(rv);
405    if (buffer_->BytesRemaining() > 0) {
406      next_state_ = STATE_SEND_LENGTH;
407      return socket_->Write(
408          buffer_.get(),
409          buffer_->BytesRemaining(),
410          base::Bind(&DnsTCPAttempt::OnIOComplete, base::Unretained(this)));
411    }
412    buffer_ = new DrainableIOBuffer(query_->io_buffer(),
413                                    query_->io_buffer()->size());
414    next_state_ = STATE_SEND_QUERY;
415    return OK;
416  }
417
418  int DoSendQuery(int rv) {
419    DCHECK_NE(ERR_IO_PENDING, rv);
420    if (rv < 0)
421      return rv;
422
423    buffer_->DidConsume(rv);
424    if (buffer_->BytesRemaining() > 0) {
425      next_state_ = STATE_SEND_QUERY;
426      return socket_->Write(
427          buffer_.get(),
428          buffer_->BytesRemaining(),
429          base::Bind(&DnsTCPAttempt::OnIOComplete, base::Unretained(this)));
430    }
431    buffer_ =
432        new DrainableIOBuffer(length_buffer_.get(), length_buffer_->size());
433    next_state_ = STATE_READ_LENGTH;
434    return OK;
435  }
436
437  int DoReadLength(int rv) {
438    DCHECK_NE(ERR_IO_PENDING, rv);
439    if (rv < 0)
440      return rv;
441
442    buffer_->DidConsume(rv);
443    if (buffer_->BytesRemaining() > 0) {
444      next_state_ = STATE_READ_LENGTH;
445      return socket_->Read(
446          buffer_.get(),
447          buffer_->BytesRemaining(),
448          base::Bind(&DnsTCPAttempt::OnIOComplete, base::Unretained(this)));
449    }
450    base::ReadBigEndian<uint16>(length_buffer_->data(), &response_length_);
451    // Check if advertised response is too short. (Optimization only.)
452    if (response_length_ < query_->io_buffer()->size())
453      return ERR_DNS_MALFORMED_RESPONSE;
454    // Allocate more space so that DnsResponse::InitParse sanity check passes.
455    response_.reset(new DnsResponse(response_length_ + 1));
456    buffer_ = new DrainableIOBuffer(response_->io_buffer(), response_length_);
457    next_state_ = STATE_READ_RESPONSE;
458    return OK;
459  }
460
461  int DoReadResponse(int rv) {
462    DCHECK_NE(ERR_IO_PENDING, rv);
463    if (rv < 0)
464      return rv;
465
466    buffer_->DidConsume(rv);
467    if (buffer_->BytesRemaining() > 0) {
468      next_state_ = STATE_READ_RESPONSE;
469      return socket_->Read(
470          buffer_.get(),
471          buffer_->BytesRemaining(),
472          base::Bind(&DnsTCPAttempt::OnIOComplete, base::Unretained(this)));
473    }
474    if (!response_->InitParse(buffer_->BytesConsumed(), *query_))
475      return ERR_DNS_MALFORMED_RESPONSE;
476    if (response_->flags() & dns_protocol::kFlagTC)
477      return ERR_UNEXPECTED;
478    // TODO(szym): Frankly, none of these are expected.
479    if (response_->rcode() == dns_protocol::kRcodeNXDOMAIN)
480      return ERR_NAME_NOT_RESOLVED;
481    if (response_->rcode() != dns_protocol::kRcodeNOERROR)
482      return ERR_DNS_SERVER_FAILED;
483
484    return OK;
485  }
486
487  void OnIOComplete(int rv) {
488    rv = DoLoop(rv);
489    if (rv != ERR_IO_PENDING)
490      callback_.Run(rv);
491  }
492
493  State next_state_;
494  base::TimeTicks start_time_;
495
496  scoped_ptr<StreamSocket> socket_;
497  scoped_ptr<DnsQuery> query_;
498  scoped_refptr<IOBufferWithSize> length_buffer_;
499  scoped_refptr<DrainableIOBuffer> buffer_;
500
501  uint16 response_length_;
502  scoped_ptr<DnsResponse> response_;
503
504  CompletionCallback callback_;
505
506  DISALLOW_COPY_AND_ASSIGN(DnsTCPAttempt);
507};
508
509// ----------------------------------------------------------------------------
510
511// Implements DnsTransaction. Configuration is supplied by DnsSession.
512// The suffix list is built according to the DnsConfig from the session.
513// The timeout for each DnsUDPAttempt is given by DnsSession::NextTimeout.
514// The first server to attempt on each query is given by
515// DnsSession::NextFirstServerIndex, and the order is round-robin afterwards.
516// Each server is attempted DnsConfig::attempts times.
517class DnsTransactionImpl : public DnsTransaction,
518                           public base::NonThreadSafe,
519                           public base::SupportsWeakPtr<DnsTransactionImpl> {
520 public:
521  DnsTransactionImpl(DnsSession* session,
522                     const std::string& hostname,
523                     uint16 qtype,
524                     const DnsTransactionFactory::CallbackType& callback,
525                     const BoundNetLog& net_log)
526    : session_(session),
527      hostname_(hostname),
528      qtype_(qtype),
529      callback_(callback),
530      net_log_(net_log),
531      qnames_initial_size_(0),
532      attempts_count_(0),
533      had_tcp_attempt_(false),
534      first_server_index_(0) {
535    DCHECK(session_.get());
536    DCHECK(!hostname_.empty());
537    DCHECK(!callback_.is_null());
538    DCHECK(!IsIPLiteral(hostname_));
539  }
540
541  virtual ~DnsTransactionImpl() {
542    if (!callback_.is_null()) {
543      net_log_.EndEventWithNetErrorCode(NetLog::TYPE_DNS_TRANSACTION,
544                                        ERR_ABORTED);
545    }  // otherwise logged in DoCallback or Start
546  }
547
548  virtual const std::string& GetHostname() const OVERRIDE {
549    DCHECK(CalledOnValidThread());
550    return hostname_;
551  }
552
553  virtual uint16 GetType() const OVERRIDE {
554    DCHECK(CalledOnValidThread());
555    return qtype_;
556  }
557
558  virtual void Start() OVERRIDE {
559    DCHECK(!callback_.is_null());
560    DCHECK(attempts_.empty());
561    net_log_.BeginEvent(NetLog::TYPE_DNS_TRANSACTION,
562                        base::Bind(&NetLogStartCallback, &hostname_, qtype_));
563    AttemptResult result(PrepareSearch(), NULL);
564    if (result.rv == OK) {
565      qnames_initial_size_ = qnames_.size();
566      if (qtype_ == dns_protocol::kTypeA)
567        UMA_HISTOGRAM_COUNTS("AsyncDNS.SuffixSearchStart", qnames_.size());
568      result = ProcessAttemptResult(StartQuery());
569    }
570
571    // Must always return result asynchronously, to avoid reentrancy.
572    if (result.rv != ERR_IO_PENDING) {
573      base::MessageLoop::current()->PostTask(
574          FROM_HERE,
575          base::Bind(&DnsTransactionImpl::DoCallback, AsWeakPtr(), result));
576    }
577  }
578
579 private:
580  // Wrapper for the result of a DnsUDPAttempt.
581  struct AttemptResult {
582    AttemptResult(int rv, const DnsAttempt* attempt)
583        : rv(rv), attempt(attempt) {}
584
585    int rv;
586    const DnsAttempt* attempt;
587  };
588
589  // Prepares |qnames_| according to the DnsConfig.
590  int PrepareSearch() {
591    const DnsConfig& config = session_->config();
592
593    std::string labeled_hostname;
594    if (!DNSDomainFromDot(hostname_, &labeled_hostname))
595      return ERR_INVALID_ARGUMENT;
596
597    if (hostname_[hostname_.size() - 1] == '.') {
598      // It's a fully-qualified name, no suffix search.
599      qnames_.push_back(labeled_hostname);
600      return OK;
601    }
602
603    int ndots = CountLabels(labeled_hostname) - 1;
604
605    if (ndots > 0 && !config.append_to_multi_label_name) {
606      qnames_.push_back(labeled_hostname);
607      return OK;
608    }
609
610    // Set true when |labeled_hostname| is put on the list.
611    bool had_hostname = false;
612
613    if (ndots >= config.ndots) {
614      qnames_.push_back(labeled_hostname);
615      had_hostname = true;
616    }
617
618    std::string qname;
619    for (size_t i = 0; i < config.search.size(); ++i) {
620      // Ignore invalid (too long) combinations.
621      if (!DNSDomainFromDot(hostname_ + "." + config.search[i], &qname))
622        continue;
623      if (qname.size() == labeled_hostname.size()) {
624        if (had_hostname)
625          continue;
626        had_hostname = true;
627      }
628      qnames_.push_back(qname);
629    }
630
631    if (ndots > 0 && !had_hostname)
632      qnames_.push_back(labeled_hostname);
633
634    return qnames_.empty() ? ERR_DNS_SEARCH_EMPTY : OK;
635  }
636
637  void DoCallback(AttemptResult result) {
638    DCHECK(!callback_.is_null());
639    DCHECK_NE(ERR_IO_PENDING, result.rv);
640    const DnsResponse* response = result.attempt ?
641        result.attempt->GetResponse() : NULL;
642    CHECK(result.rv != OK || response != NULL);
643
644    timer_.Stop();
645    RecordLostPacketsIfAny();
646    if (result.rv == OK)
647      UMA_HISTOGRAM_COUNTS("AsyncDNS.AttemptCountSuccess", attempts_count_);
648    else
649      UMA_HISTOGRAM_COUNTS("AsyncDNS.AttemptCountFail", attempts_count_);
650
651    if (response && qtype_ == dns_protocol::kTypeA) {
652      UMA_HISTOGRAM_COUNTS("AsyncDNS.SuffixSearchRemain", qnames_.size());
653      UMA_HISTOGRAM_COUNTS("AsyncDNS.SuffixSearchDone",
654                           qnames_initial_size_ - qnames_.size());
655    }
656
657    DnsTransactionFactory::CallbackType callback = callback_;
658    callback_.Reset();
659
660    net_log_.EndEventWithNetErrorCode(NetLog::TYPE_DNS_TRANSACTION, result.rv);
661    callback.Run(this, result.rv, response);
662  }
663
664  // Makes another attempt at the current name, |qnames_.front()|, using the
665  // next nameserver.
666  AttemptResult MakeAttempt() {
667    unsigned attempt_number = attempts_.size();
668
669    uint16 id = session_->NextQueryId();
670    scoped_ptr<DnsQuery> query;
671    if (attempts_.empty()) {
672      query.reset(new DnsQuery(id, qnames_.front(), qtype_));
673    } else {
674      query.reset(attempts_[0]->GetQuery()->CloneWithNewId(id));
675    }
676
677    const DnsConfig& config = session_->config();
678
679    unsigned server_index =
680        (first_server_index_ + attempt_number) % config.nameservers.size();
681    // Skip over known failed servers.
682    server_index = session_->NextGoodServerIndex(server_index);
683
684    scoped_ptr<DnsSession::SocketLease> lease =
685        session_->AllocateSocket(server_index, net_log_.source());
686
687    bool got_socket = !!lease.get();
688
689    DnsUDPAttempt* attempt =
690        new DnsUDPAttempt(server_index, lease.Pass(), query.Pass());
691
692    attempts_.push_back(attempt);
693    ++attempts_count_;
694
695    if (!got_socket)
696      return AttemptResult(ERR_CONNECTION_REFUSED, NULL);
697
698    net_log_.AddEvent(
699        NetLog::TYPE_DNS_TRANSACTION_ATTEMPT,
700        attempt->GetSocketNetLog().source().ToEventParametersCallback());
701
702    int rv = attempt->Start(
703        base::Bind(&DnsTransactionImpl::OnUdpAttemptComplete,
704                   base::Unretained(this), attempt_number,
705                   base::TimeTicks::Now()));
706    if (rv == ERR_IO_PENDING) {
707      base::TimeDelta timeout = session_->NextTimeout(server_index,
708                                                      attempt_number);
709      timer_.Start(FROM_HERE, timeout, this, &DnsTransactionImpl::OnTimeout);
710    }
711    return AttemptResult(rv, attempt);
712  }
713
714  AttemptResult MakeTCPAttempt(const DnsAttempt* previous_attempt) {
715    DCHECK(previous_attempt);
716    DCHECK(!had_tcp_attempt_);
717
718    unsigned server_index = previous_attempt->server_index();
719
720    scoped_ptr<StreamSocket> socket(
721        session_->CreateTCPSocket(server_index, net_log_.source()));
722
723    // TODO(szym): Reuse the same id to help the server?
724    uint16 id = session_->NextQueryId();
725    scoped_ptr<DnsQuery> query(
726        previous_attempt->GetQuery()->CloneWithNewId(id));
727
728    RecordLostPacketsIfAny();
729    // Cancel all other attempts, no point waiting on them.
730    attempts_.clear();
731
732    unsigned attempt_number = attempts_.size();
733
734    DnsTCPAttempt* attempt = new DnsTCPAttempt(server_index, socket.Pass(),
735                                               query.Pass());
736
737    attempts_.push_back(attempt);
738    ++attempts_count_;
739    had_tcp_attempt_ = true;
740
741    net_log_.AddEvent(
742        NetLog::TYPE_DNS_TRANSACTION_TCP_ATTEMPT,
743        attempt->GetSocketNetLog().source().ToEventParametersCallback());
744
745    int rv = attempt->Start(base::Bind(&DnsTransactionImpl::OnAttemptComplete,
746                                       base::Unretained(this),
747                                       attempt_number));
748    if (rv == ERR_IO_PENDING) {
749      // Custom timeout for TCP attempt.
750      base::TimeDelta timeout = timer_.GetCurrentDelay() * 2;
751      timer_.Start(FROM_HERE, timeout, this, &DnsTransactionImpl::OnTimeout);
752    }
753    return AttemptResult(rv, attempt);
754  }
755
756  // Begins query for the current name. Makes the first attempt.
757  AttemptResult StartQuery() {
758    std::string dotted_qname = DNSDomainToString(qnames_.front());
759    net_log_.BeginEvent(NetLog::TYPE_DNS_TRANSACTION_QUERY,
760                        NetLog::StringCallback("qname", &dotted_qname));
761
762    first_server_index_ = session_->NextFirstServerIndex();
763    RecordLostPacketsIfAny();
764    attempts_.clear();
765    had_tcp_attempt_ = false;
766    return MakeAttempt();
767  }
768
769  void OnUdpAttemptComplete(unsigned attempt_number,
770                            base::TimeTicks start,
771                            int rv) {
772    DCHECK_LT(attempt_number, attempts_.size());
773    const DnsAttempt* attempt = attempts_[attempt_number];
774    if (attempt->GetResponse()) {
775      session_->RecordRTT(attempt->server_index(),
776                          base::TimeTicks::Now() - start);
777    }
778    OnAttemptComplete(attempt_number, rv);
779  }
780
781  void OnAttemptComplete(unsigned attempt_number, int rv) {
782    if (callback_.is_null())
783      return;
784    DCHECK_LT(attempt_number, attempts_.size());
785    const DnsAttempt* attempt = attempts_[attempt_number];
786    AttemptResult result = ProcessAttemptResult(AttemptResult(rv, attempt));
787    if (result.rv != ERR_IO_PENDING)
788      DoCallback(result);
789  }
790
791  // Record packet loss for any incomplete attempts.
792  void RecordLostPacketsIfAny() {
793    // Loop through attempts until we find first that is completed
794    size_t first_completed = 0;
795    for (first_completed = 0; first_completed < attempts_.size();
796        ++first_completed) {
797      if (attempts_[first_completed]->is_completed())
798        break;
799    }
800    // If there were no completed attempts, then we must be offline, so don't
801    // record any attempts as lost packets.
802    if (first_completed == attempts_.size())
803      return;
804
805    size_t num_servers = session_->config().nameservers.size();
806    std::vector<int> server_attempts(num_servers);
807    for (size_t i = 0; i < first_completed; ++i) {
808      unsigned server_index = attempts_[i]->server_index();
809      int server_attempt = server_attempts[server_index]++;
810      // Don't record lost packet unless attempt is in pending state.
811      if (!attempts_[i]->is_pending())
812        continue;
813      session_->RecordLostPacket(server_index, server_attempt);
814    }
815  }
816
817  void LogResponse(const DnsAttempt* attempt) {
818    if (attempt && attempt->GetResponse()) {
819      net_log_.AddEvent(
820          NetLog::TYPE_DNS_TRANSACTION_RESPONSE,
821          base::Bind(&DnsAttempt::NetLogResponseCallback,
822                     base::Unretained(attempt)));
823    }
824  }
825
826  bool MoreAttemptsAllowed() const {
827    if (had_tcp_attempt_)
828      return false;
829    const DnsConfig& config = session_->config();
830    return attempts_.size() < config.attempts * config.nameservers.size();
831  }
832
833  // Resolves the result of a DnsAttempt until a terminal result is reached
834  // or it will complete asynchronously (ERR_IO_PENDING).
835  AttemptResult ProcessAttemptResult(AttemptResult result) {
836    while (result.rv != ERR_IO_PENDING) {
837      LogResponse(result.attempt);
838
839      switch (result.rv) {
840        case OK:
841          session_->RecordServerSuccess(result.attempt->server_index());
842          net_log_.EndEventWithNetErrorCode(NetLog::TYPE_DNS_TRANSACTION_QUERY,
843                                            result.rv);
844          DCHECK(result.attempt);
845          DCHECK(result.attempt->GetResponse());
846          return result;
847        case ERR_NAME_NOT_RESOLVED:
848          session_->RecordServerSuccess(result.attempt->server_index());
849          net_log_.EndEventWithNetErrorCode(NetLog::TYPE_DNS_TRANSACTION_QUERY,
850                                            result.rv);
851          // Try next suffix.
852          qnames_.pop_front();
853          if (qnames_.empty()) {
854            return AttemptResult(ERR_NAME_NOT_RESOLVED, NULL);
855          } else {
856            result = StartQuery();
857          }
858          break;
859        case ERR_CONNECTION_REFUSED:
860        case ERR_DNS_TIMED_OUT:
861          if (result.attempt)
862            session_->RecordServerFailure(result.attempt->server_index());
863          if (MoreAttemptsAllowed()) {
864            result = MakeAttempt();
865          } else {
866            return result;
867          }
868          break;
869        case ERR_DNS_SERVER_REQUIRES_TCP:
870          result = MakeTCPAttempt(result.attempt);
871          break;
872        default:
873          // Server failure.
874          DCHECK(result.attempt);
875          if (result.attempt != attempts_.back()) {
876            // This attempt already timed out. Ignore it.
877            session_->RecordServerFailure(result.attempt->server_index());
878            return AttemptResult(ERR_IO_PENDING, NULL);
879          }
880          if (MoreAttemptsAllowed()) {
881            result = MakeAttempt();
882          } else if (result.rv == ERR_DNS_MALFORMED_RESPONSE &&
883                     !had_tcp_attempt_) {
884            // For UDP only, ignore the response and wait until the last attempt
885            // times out.
886            return AttemptResult(ERR_IO_PENDING, NULL);
887          } else {
888            return AttemptResult(result.rv, NULL);
889          }
890          break;
891      }
892    }
893    return result;
894  }
895
896  void OnTimeout() {
897    if (callback_.is_null())
898      return;
899    DCHECK(!attempts_.empty());
900    AttemptResult result = ProcessAttemptResult(
901        AttemptResult(ERR_DNS_TIMED_OUT, attempts_.back()));
902    if (result.rv != ERR_IO_PENDING)
903      DoCallback(result);
904  }
905
906  scoped_refptr<DnsSession> session_;
907  std::string hostname_;
908  uint16 qtype_;
909  // Cleared in DoCallback.
910  DnsTransactionFactory::CallbackType callback_;
911
912  BoundNetLog net_log_;
913
914  // Search list of fully-qualified DNS names to query next (in DNS format).
915  std::deque<std::string> qnames_;
916  size_t qnames_initial_size_;
917
918  // List of attempts for the current name.
919  ScopedVector<DnsAttempt> attempts_;
920  // Count of attempts, not reset when |attempts_| vector is cleared.
921  int  attempts_count_;
922  bool had_tcp_attempt_;
923
924  // Index of the first server to try on each search query.
925  int first_server_index_;
926
927  base::OneShotTimer<DnsTransactionImpl> timer_;
928
929  DISALLOW_COPY_AND_ASSIGN(DnsTransactionImpl);
930};
931
932// ----------------------------------------------------------------------------
933
934// Implementation of DnsTransactionFactory that returns instances of
935// DnsTransactionImpl.
936class DnsTransactionFactoryImpl : public DnsTransactionFactory {
937 public:
938  explicit DnsTransactionFactoryImpl(DnsSession* session) {
939    session_ = session;
940  }
941
942  virtual scoped_ptr<DnsTransaction> CreateTransaction(
943      const std::string& hostname,
944      uint16 qtype,
945      const CallbackType& callback,
946      const BoundNetLog& net_log) OVERRIDE {
947    return scoped_ptr<DnsTransaction>(new DnsTransactionImpl(
948        session_.get(), hostname, qtype, callback, net_log));
949  }
950
951 private:
952  scoped_refptr<DnsSession> session_;
953};
954
955}  // namespace
956
957// static
958scoped_ptr<DnsTransactionFactory> DnsTransactionFactory::CreateFactory(
959    DnsSession* session) {
960  return scoped_ptr<DnsTransactionFactory>(
961      new DnsTransactionFactoryImpl(session));
962}
963
964}  // namespace net
965