dns_transaction.cc revision 5f1c94371a64b3196d4be9466099bb892df9b88e
15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/dns/dns_transaction.h"
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <deque>
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <string>
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <vector>
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "base/big_endian.h"
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/bind.h"
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/memory/ref_counted.h"
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/memory/scoped_ptr.h"
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/memory/scoped_vector.h"
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/memory/weak_ptr.h"
179ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch#include "base/message_loop/message_loop.h"
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/metrics/histogram.h"
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/rand_util.h"
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/stl_util.h"
21c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "base/strings/string_piece.h"
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/threading/non_thread_safe.h"
23eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "base/timer/timer.h"
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/values.h"
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/base/completion_callback.h"
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/base/dns_util.h"
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/base/io_buffer.h"
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/base/ip_endpoint.h"
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/base/net_errors.h"
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/base/net_log.h"
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/dns/dns_protocol.h"
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/dns/dns_query.h"
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/dns/dns_response.h"
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/dns/dns_session.h"
352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "net/socket/stream_socket.h"
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/udp/datagram_client_socket.h"
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace net {
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace {
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Provide a common macro to simplify code and readability. We must use a
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// macro as the underlying HISTOGRAM macro creates static variables.
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define DNS_HISTOGRAM(name, time) UMA_HISTOGRAM_CUSTOM_TIMES(name, time, \
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    base::TimeDelta::FromMilliseconds(1), base::TimeDelta::FromHours(1), 100)
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Count labels in the fully-qualified name in DNS format.
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int CountLabels(const std::string& name) {
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  size_t count = 0;
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (size_t i = 0; i < name.size() && name[i]; i += name[i] + 1)
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ++count;
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return count;
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool IsIPLiteral(const std::string& hostname) {
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  IPAddressNumber ip;
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return ParseIPLiteralToNumber(hostname, &ip);
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
607d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)base::Value* NetLogStartCallback(const std::string* hostname,
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                           uint16 qtype,
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                           NetLog::LogLevel /* log_level */) {
637d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  base::DictionaryValue* dict = new base::DictionaryValue();
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  dict->SetString("hostname", *hostname);
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  dict->SetInteger("query_type", qtype);
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return dict;
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// ----------------------------------------------------------------------------
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// A single asynchronous DNS exchange, which consists of sending out a
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// DNS query, waiting for a response, and returning the response that it
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// matches. Logging is done in the socket and in the outer DnsTransaction.
742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)class DnsAttempt {
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public:
76868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  explicit DnsAttempt(unsigned server_index)
77868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      : result_(ERR_FAILED), server_index_(server_index) {}
7890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  virtual ~DnsAttempt() {}
802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Starts the attempt. Returns ERR_IO_PENDING if cannot complete synchronously
812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // and calls |callback| upon completion.
822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  virtual int Start(const CompletionCallback& callback) = 0;
832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Returns the query of this attempt.
852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  virtual const DnsQuery* GetQuery() const = 0;
862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Returns the response or NULL if has not received a matching response from
882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // the server.
892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  virtual const DnsResponse* GetResponse() const = 0;
902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Returns the net log bound to the source of the socket.
922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  virtual const BoundNetLog& GetSocketNetLog() const = 0;
932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Returns the index of the destination server within DnsConfig::nameservers.
95868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  unsigned server_index() const { return server_index_; }
962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Returns a Value representing the received response, along with a reference
982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // to the NetLog source source of the UDP socket used.  The request must have
992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // completed before this is called.
100eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  base::Value* NetLogResponseCallback(NetLog::LogLevel log_level) const {
1012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    DCHECK(GetResponse()->IsValid());
1022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1037d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    base::DictionaryValue* dict = new base::DictionaryValue();
1042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    dict->SetInteger("rcode", GetResponse()->rcode());
1052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    dict->SetInteger("answer_count", GetResponse()->answer_count());
1062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    GetSocketNetLog().source().AddToEventParameters(dict);
1072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return dict;
1082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
10990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
11090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  void set_result(int result) {
11190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    result_ = result;
11290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  }
11390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
11490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  // True if current attempt is pending (waiting for server response).
11590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  bool is_pending() const {
11690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    return result_ == ERR_IO_PENDING;
11790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  }
11890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
11990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  // True if attempt is completed (received server response).
12090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  bool is_completed() const {
12190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    return (result_ == OK) || (result_ == ERR_NAME_NOT_RESOLVED) ||
12290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        (result_ == ERR_DNS_SERVER_REQUIRES_TCP);
12390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  }
12490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
12590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) private:
12690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  // Result of last operation.
12790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  int result_;
128868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
129868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  const unsigned server_index_;
1302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)};
1312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)class DnsUDPAttempt : public DnsAttempt {
1332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) public:
134868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  DnsUDPAttempt(unsigned server_index,
135868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                scoped_ptr<DnsSession::SocketLease> socket_lease,
1362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                scoped_ptr<DnsQuery> query)
137868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      : DnsAttempt(server_index),
138868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        next_state_(STATE_NONE),
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        received_malformed_response_(false),
1402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        socket_lease_(socket_lease.Pass()),
141868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        query_(query.Pass()) {}
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // DnsAttempt:
1442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  virtual int Start(const CompletionCallback& callback) OVERRIDE {
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK_EQ(STATE_NONE, next_state_);
1462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    callback_ = callback;
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    start_time_ = base::TimeTicks::Now();
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    next_state_ = STATE_SEND_QUERY;
1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return DoLoop(OK);
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  virtual const DnsQuery* GetQuery() const OVERRIDE {
1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return query_.get();
1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  virtual const DnsResponse* GetResponse() const OVERRIDE {
1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const DnsResponse* resp = response_.get();
1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return (resp != NULL && resp->IsValid()) ? resp : NULL;
1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  virtual const BoundNetLog& GetSocketNetLog() const OVERRIDE {
1622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return socket_lease_->socket()->NetLog();
1632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private:
1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  enum State {
1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    STATE_SEND_QUERY,
1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    STATE_SEND_QUERY_COMPLETE,
1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    STATE_READ_RESPONSE,
1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    STATE_READ_RESPONSE_COMPLETE,
1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    STATE_NONE,
1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  };
1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DatagramClientSocket* socket() {
1752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return socket_lease_->socket();
1762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
1772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int DoLoop(int result) {
1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    CHECK_NE(STATE_NONE, next_state_);
1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int rv = result;
1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    do {
1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      State state = next_state_;
1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      next_state_ = STATE_NONE;
1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      switch (state) {
1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        case STATE_SEND_QUERY:
1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          rv = DoSendQuery();
1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          break;
1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        case STATE_SEND_QUERY_COMPLETE:
1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          rv = DoSendQueryComplete(rv);
1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          break;
1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        case STATE_READ_RESPONSE:
1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          rv = DoReadResponse();
1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          break;
1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        case STATE_READ_RESPONSE_COMPLETE:
1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          rv = DoReadResponseComplete(rv);
1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          break;
1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        default:
1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          NOTREACHED();
1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          break;
2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } while (rv != ERR_IO_PENDING && next_state_ != STATE_NONE);
20290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
20390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    set_result(rv);
2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // If we received a malformed response, and are now waiting for another one,
2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // indicate to the transaction that the server might be misbehaving.
2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (rv == ERR_IO_PENDING && received_malformed_response_)
2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return ERR_DNS_MALFORMED_RESPONSE;
2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (rv == OK) {
2092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      DCHECK_EQ(STATE_NONE, next_state_);
2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      DNS_HISTOGRAM("AsyncDNS.UDPAttemptSuccess",
2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    base::TimeTicks::Now() - start_time_);
2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } else if (rv != ERR_IO_PENDING) {
2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      DNS_HISTOGRAM("AsyncDNS.UDPAttemptFail",
2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    base::TimeTicks::Now() - start_time_);
2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return rv;
2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int DoSendQuery() {
2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    next_state_ = STATE_SEND_QUERY_COMPLETE;
2212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return socket()->Write(query_->io_buffer(),
22290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                           query_->io_buffer()->size(),
22390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                           base::Bind(&DnsUDPAttempt::OnIOComplete,
22490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                                      base::Unretained(this)));
2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int DoSendQueryComplete(int rv) {
2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK_NE(ERR_IO_PENDING, rv);
2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (rv < 0)
2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return rv;
2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Writing to UDP should not result in a partial datagram.
2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (rv != query_->io_buffer()->size())
2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return ERR_MSG_TOO_BIG;
2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    next_state_ = STATE_READ_RESPONSE;
2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return OK;
2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int DoReadResponse() {
2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    next_state_ = STATE_READ_RESPONSE_COMPLETE;
2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    response_.reset(new DnsResponse());
2432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return socket()->Read(response_->io_buffer(),
24490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                          response_->io_buffer()->size(),
24590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                          base::Bind(&DnsUDPAttempt::OnIOComplete,
24690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                                     base::Unretained(this)));
2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int DoReadResponseComplete(int rv) {
2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK_NE(ERR_IO_PENDING, rv);
2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (rv < 0)
2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return rv;
2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK(rv);
2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!response_->InitParse(rv, *query_)) {
2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // Other implementations simply ignore mismatched responses. Since each
2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // DnsUDPAttempt binds to a different port, we might find that responses
2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // to previously timed out queries lead to failures in the future.
2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // Our solution is to make another attempt, in case the query truly
2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // failed, but keep this attempt alive, in case it was a false alarm.
2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      received_malformed_response_ = true;
2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      next_state_ = STATE_READ_RESPONSE;
2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return OK;
2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (response_->flags() & dns_protocol::kFlagTC)
2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return ERR_DNS_SERVER_REQUIRES_TCP;
2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // TODO(szym): Extract TTL for NXDOMAIN results. http://crbug.com/115051
2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (response_->rcode() == dns_protocol::kRcodeNXDOMAIN)
2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return ERR_NAME_NOT_RESOLVED;
2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (response_->rcode() != dns_protocol::kRcodeNOERROR)
2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return ERR_DNS_SERVER_FAILED;
2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return OK;
2745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void OnIOComplete(int rv) {
2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    rv = DoLoop(rv);
2785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (rv != ERR_IO_PENDING)
2795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      callback_.Run(rv);
2805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  State next_state_;
2835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool received_malformed_response_;
2845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::TimeTicks start_time_;
2855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  scoped_ptr<DnsSession::SocketLease> socket_lease_;
2875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_ptr<DnsQuery> query_;
2885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_ptr<DnsResponse> response_;
2905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CompletionCallback callback_;
2925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DISALLOW_COPY_AND_ASSIGN(DnsUDPAttempt);
2945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
2955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)class DnsTCPAttempt : public DnsAttempt {
2972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) public:
29890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  DnsTCPAttempt(unsigned server_index,
29990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                scoped_ptr<StreamSocket> socket,
3002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                scoped_ptr<DnsQuery> query)
301868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      : DnsAttempt(server_index),
302868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        next_state_(STATE_NONE),
3032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        socket_(socket.Pass()),
3042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        query_(query.Pass()),
3052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        length_buffer_(new IOBufferWithSize(sizeof(uint16))),
306868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        response_length_(0) {}
3072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // DnsAttempt:
3092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  virtual int Start(const CompletionCallback& callback) OVERRIDE {
3102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    DCHECK_EQ(STATE_NONE, next_state_);
3112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    callback_ = callback;
3122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    start_time_ = base::TimeTicks::Now();
3132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    next_state_ = STATE_CONNECT_COMPLETE;
3142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    int rv = socket_->Connect(base::Bind(&DnsTCPAttempt::OnIOComplete,
3152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                         base::Unretained(this)));
31690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    if (rv == ERR_IO_PENDING) {
31790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      set_result(rv);
3182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      return rv;
31990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    }
3202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return DoLoop(rv);
3212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
3222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  virtual const DnsQuery* GetQuery() const OVERRIDE {
3242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return query_.get();
3252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
3262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  virtual const DnsResponse* GetResponse() const OVERRIDE {
3282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const DnsResponse* resp = response_.get();
3292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return (resp != NULL && resp->IsValid()) ? resp : NULL;
3302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
3312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  virtual const BoundNetLog& GetSocketNetLog() const OVERRIDE {
3332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return socket_->NetLog();
3342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
3352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) private:
3372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  enum State {
3382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    STATE_CONNECT_COMPLETE,
3392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    STATE_SEND_LENGTH,
3402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    STATE_SEND_QUERY,
3412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    STATE_READ_LENGTH,
3425f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    STATE_READ_LENGTH_COMPLETE,
3432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    STATE_READ_RESPONSE,
3445f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    STATE_READ_RESPONSE_COMPLETE,
3452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    STATE_NONE,
3462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  };
3472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  int DoLoop(int result) {
3492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    CHECK_NE(STATE_NONE, next_state_);
3502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    int rv = result;
3512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    do {
3522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      State state = next_state_;
3532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      next_state_ = STATE_NONE;
3542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      switch (state) {
3552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        case STATE_CONNECT_COMPLETE:
3562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          rv = DoConnectComplete(rv);
3572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          break;
3582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        case STATE_SEND_LENGTH:
3592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          rv = DoSendLength(rv);
3602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          break;
3612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        case STATE_SEND_QUERY:
3622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          rv = DoSendQuery(rv);
3632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          break;
3642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        case STATE_READ_LENGTH:
3652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          rv = DoReadLength(rv);
3662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          break;
3675f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        case STATE_READ_LENGTH_COMPLETE:
3685f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)          rv = DoReadLengthComplete(rv);
3695f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)          break;
3702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        case STATE_READ_RESPONSE:
3712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          rv = DoReadResponse(rv);
3722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          break;
3735f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        case STATE_READ_RESPONSE_COMPLETE:
3745f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)          rv = DoReadResponseComplete(rv);
3755f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)          break;
3762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        default:
3772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          NOTREACHED();
3782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          break;
3792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      }
3802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    } while (rv != ERR_IO_PENDING && next_state_ != STATE_NONE);
38190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
38290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    set_result(rv);
3832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (rv == OK) {
3842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      DCHECK_EQ(STATE_NONE, next_state_);
3852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      DNS_HISTOGRAM("AsyncDNS.TCPAttemptSuccess",
3862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                    base::TimeTicks::Now() - start_time_);
3872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    } else if (rv != ERR_IO_PENDING) {
3882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      DNS_HISTOGRAM("AsyncDNS.TCPAttemptFail",
3892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                    base::TimeTicks::Now() - start_time_);
3902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
3912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return rv;
3922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
3932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  int DoConnectComplete(int rv) {
3952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    DCHECK_NE(ERR_IO_PENDING, rv);
3962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (rv < 0)
3972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      return rv;
3982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
399a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    base::WriteBigEndian<uint16>(length_buffer_->data(),
400a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                                 query_->io_buffer()->size());
401868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    buffer_ =
402868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        new DrainableIOBuffer(length_buffer_.get(), length_buffer_->size());
4032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    next_state_ = STATE_SEND_LENGTH;
4042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return OK;
4052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
4062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  int DoSendLength(int rv) {
4082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    DCHECK_NE(ERR_IO_PENDING, rv);
4092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (rv < 0)
4102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      return rv;
4112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    buffer_->DidConsume(rv);
4132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (buffer_->BytesRemaining() > 0) {
4142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      next_state_ = STATE_SEND_LENGTH;
415868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      return socket_->Write(
416868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)          buffer_.get(),
417868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)          buffer_->BytesRemaining(),
418868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)          base::Bind(&DnsTCPAttempt::OnIOComplete, base::Unretained(this)));
4192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
4202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    buffer_ = new DrainableIOBuffer(query_->io_buffer(),
4212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                    query_->io_buffer()->size());
4222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    next_state_ = STATE_SEND_QUERY;
4232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return OK;
4242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
4252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  int DoSendQuery(int rv) {
4272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    DCHECK_NE(ERR_IO_PENDING, rv);
4282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (rv < 0)
4292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      return rv;
4302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    buffer_->DidConsume(rv);
4322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (buffer_->BytesRemaining() > 0) {
4332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      next_state_ = STATE_SEND_QUERY;
434868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      return socket_->Write(
435868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)          buffer_.get(),
436868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)          buffer_->BytesRemaining(),
437868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)          base::Bind(&DnsTCPAttempt::OnIOComplete, base::Unretained(this)));
4382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
439868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    buffer_ =
440868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        new DrainableIOBuffer(length_buffer_.get(), length_buffer_->size());
4412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    next_state_ = STATE_READ_LENGTH;
4422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return OK;
4432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
4442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  int DoReadLength(int rv) {
4465f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    DCHECK_EQ(OK, rv);
4475f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
4485f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    next_state_ = STATE_READ_LENGTH_COMPLETE;
4495f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    return ReadIntoBuffer();
4505f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  }
4515f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
4525f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  int DoReadLengthComplete(int rv) {
4532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    DCHECK_NE(ERR_IO_PENDING, rv);
4542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (rv < 0)
4552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      return rv;
4565f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    if (rv == 0)
4575f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      return ERR_CONNECTION_CLOSED;
4582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    buffer_->DidConsume(rv);
4602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (buffer_->BytesRemaining() > 0) {
4612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      next_state_ = STATE_READ_LENGTH;
4625f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      return OK;
4632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
4645f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
465a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    base::ReadBigEndian<uint16>(length_buffer_->data(), &response_length_);
4662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // Check if advertised response is too short. (Optimization only.)
4672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (response_length_ < query_->io_buffer()->size())
4682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      return ERR_DNS_MALFORMED_RESPONSE;
4692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // Allocate more space so that DnsResponse::InitParse sanity check passes.
4702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    response_.reset(new DnsResponse(response_length_ + 1));
4712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    buffer_ = new DrainableIOBuffer(response_->io_buffer(), response_length_);
4722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    next_state_ = STATE_READ_RESPONSE;
4732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return OK;
4742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
4752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  int DoReadResponse(int rv) {
4775f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    DCHECK_EQ(OK, rv);
4785f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
4795f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    next_state_ = STATE_READ_RESPONSE_COMPLETE;
4805f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    return ReadIntoBuffer();
4815f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  }
4825f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
4835f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  int DoReadResponseComplete(int rv) {
4842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    DCHECK_NE(ERR_IO_PENDING, rv);
4852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (rv < 0)
4862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      return rv;
4875f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    if (rv == 0)
4885f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      return ERR_CONNECTION_CLOSED;
4892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    buffer_->DidConsume(rv);
4912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (buffer_->BytesRemaining() > 0) {
4922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      next_state_ = STATE_READ_RESPONSE;
4935f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      return OK;
4942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
4955f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
4962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (!response_->InitParse(buffer_->BytesConsumed(), *query_))
4972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      return ERR_DNS_MALFORMED_RESPONSE;
4982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (response_->flags() & dns_protocol::kFlagTC)
4992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      return ERR_UNEXPECTED;
5002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // TODO(szym): Frankly, none of these are expected.
5012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (response_->rcode() == dns_protocol::kRcodeNXDOMAIN)
5022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      return ERR_NAME_NOT_RESOLVED;
5032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (response_->rcode() != dns_protocol::kRcodeNOERROR)
5042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      return ERR_DNS_SERVER_FAILED;
5052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
5062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return OK;
5072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
5082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
5092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  void OnIOComplete(int rv) {
5102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    rv = DoLoop(rv);
5112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (rv != ERR_IO_PENDING)
5122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      callback_.Run(rv);
5132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
5142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
5155f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  int ReadIntoBuffer() {
5165f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    return socket_->Read(
5175f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        buffer_.get(),
5185f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        buffer_->BytesRemaining(),
5195f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        base::Bind(&DnsTCPAttempt::OnIOComplete, base::Unretained(this)));
5205f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  }
5215f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
5222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  State next_state_;
5232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::TimeTicks start_time_;
5242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
5252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  scoped_ptr<StreamSocket> socket_;
5262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  scoped_ptr<DnsQuery> query_;
5272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  scoped_refptr<IOBufferWithSize> length_buffer_;
5282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  scoped_refptr<DrainableIOBuffer> buffer_;
5292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
5302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  uint16 response_length_;
5312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  scoped_ptr<DnsResponse> response_;
5322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
5332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  CompletionCallback callback_;
5342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
5352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DISALLOW_COPY_AND_ASSIGN(DnsTCPAttempt);
5362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)};
5372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
5385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// ----------------------------------------------------------------------------
5395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Implements DnsTransaction. Configuration is supplied by DnsSession.
5415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// The suffix list is built according to the DnsConfig from the session.
5425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// The timeout for each DnsUDPAttempt is given by DnsSession::NextTimeout.
5435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// The first server to attempt on each query is given by
5445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// DnsSession::NextFirstServerIndex, and the order is round-robin afterwards.
5455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Each server is attempted DnsConfig::attempts times.
5465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class DnsTransactionImpl : public DnsTransaction,
5475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                           public base::NonThreadSafe,
5485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                           public base::SupportsWeakPtr<DnsTransactionImpl> {
5495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public:
5505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DnsTransactionImpl(DnsSession* session,
5515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                     const std::string& hostname,
5525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                     uint16 qtype,
5535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                     const DnsTransactionFactory::CallbackType& callback,
5545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                     const BoundNetLog& net_log)
5555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    : session_(session),
5565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      hostname_(hostname),
5575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      qtype_(qtype),
5585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      callback_(callback),
5595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      net_log_(net_log),
5602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      qnames_initial_size_(0),
561ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch      attempts_count_(0),
5622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      had_tcp_attempt_(false),
5635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      first_server_index_(0) {
564868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    DCHECK(session_.get());
5655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK(!hostname_.empty());
5665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK(!callback_.is_null());
5675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK(!IsIPLiteral(hostname_));
5685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
5695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual ~DnsTransactionImpl() {
5715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!callback_.is_null()) {
5725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      net_log_.EndEventWithNetErrorCode(NetLog::TYPE_DNS_TRANSACTION,
5735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                        ERR_ABORTED);
5745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }  // otherwise logged in DoCallback or Start
5755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
5765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual const std::string& GetHostname() const OVERRIDE {
5785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK(CalledOnValidThread());
5795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return hostname_;
5805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
5815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual uint16 GetType() const OVERRIDE {
5835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK(CalledOnValidThread());
5845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return qtype_;
5855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
5865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
587ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  virtual void Start() OVERRIDE {
5885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK(!callback_.is_null());
5895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK(attempts_.empty());
5905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    net_log_.BeginEvent(NetLog::TYPE_DNS_TRANSACTION,
5915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        base::Bind(&NetLogStartCallback, &hostname_, qtype_));
592ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    AttemptResult result(PrepareSearch(), NULL);
593ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    if (result.rv == OK) {
5942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      qnames_initial_size_ = qnames_.size();
5952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      if (qtype_ == dns_protocol::kTypeA)
5962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        UMA_HISTOGRAM_COUNTS("AsyncDNS.SuffixSearchStart", qnames_.size());
597ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch      result = ProcessAttemptResult(StartQuery());
5985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
599ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
600ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    // Must always return result asynchronously, to avoid reentrancy.
601ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    if (result.rv != ERR_IO_PENDING) {
602ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch      base::MessageLoop::current()->PostTask(
603ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch          FROM_HERE,
604ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch          base::Bind(&DnsTransactionImpl::DoCallback, AsWeakPtr(), result));
6055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
6065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
6075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private:
6095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Wrapper for the result of a DnsUDPAttempt.
6105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  struct AttemptResult {
6112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    AttemptResult(int rv, const DnsAttempt* attempt)
6125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        : rv(rv), attempt(attempt) {}
6135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int rv;
6152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const DnsAttempt* attempt;
6165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  };
6175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Prepares |qnames_| according to the DnsConfig.
6195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int PrepareSearch() {
6205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const DnsConfig& config = session_->config();
6215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    std::string labeled_hostname;
6235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!DNSDomainFromDot(hostname_, &labeled_hostname))
6245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return ERR_INVALID_ARGUMENT;
6255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (hostname_[hostname_.size() - 1] == '.') {
6275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // It's a fully-qualified name, no suffix search.
6285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      qnames_.push_back(labeled_hostname);
6295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return OK;
6305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
6315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int ndots = CountLabels(labeled_hostname) - 1;
6335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (ndots > 0 && !config.append_to_multi_label_name) {
6355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      qnames_.push_back(labeled_hostname);
6365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return OK;
6375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
6385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Set true when |labeled_hostname| is put on the list.
6405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    bool had_hostname = false;
6415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (ndots >= config.ndots) {
6435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      qnames_.push_back(labeled_hostname);
6445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      had_hostname = true;
6455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
6465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    std::string qname;
6485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for (size_t i = 0; i < config.search.size(); ++i) {
6495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // Ignore invalid (too long) combinations.
6505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (!DNSDomainFromDot(hostname_ + "." + config.search[i], &qname))
6515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        continue;
6525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (qname.size() == labeled_hostname.size()) {
6535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if (had_hostname)
6545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          continue;
6555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        had_hostname = true;
6565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
6575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      qnames_.push_back(qname);
6585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
6595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (ndots > 0 && !had_hostname)
6615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      qnames_.push_back(labeled_hostname);
6625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return qnames_.empty() ? ERR_DNS_SEARCH_EMPTY : OK;
6645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
6655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void DoCallback(AttemptResult result) {
6675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK(!callback_.is_null());
6685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK_NE(ERR_IO_PENDING, result.rv);
6695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const DnsResponse* response = result.attempt ?
6702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        result.attempt->GetResponse() : NULL;
6715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    CHECK(result.rv != OK || response != NULL);
6725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    timer_.Stop();
67490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    RecordLostPacketsIfAny();
675ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    if (result.rv == OK)
676ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch      UMA_HISTOGRAM_COUNTS("AsyncDNS.AttemptCountSuccess", attempts_count_);
677ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    else
678ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch      UMA_HISTOGRAM_COUNTS("AsyncDNS.AttemptCountFail", attempts_count_);
6795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (response && qtype_ == dns_protocol::kTypeA) {
6812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      UMA_HISTOGRAM_COUNTS("AsyncDNS.SuffixSearchRemain", qnames_.size());
6822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      UMA_HISTOGRAM_COUNTS("AsyncDNS.SuffixSearchDone",
6832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                           qnames_initial_size_ - qnames_.size());
6842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
6852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
6865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DnsTransactionFactory::CallbackType callback = callback_;
6875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    callback_.Reset();
6885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    net_log_.EndEventWithNetErrorCode(NetLog::TYPE_DNS_TRANSACTION, result.rv);
6905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    callback.Run(this, result.rv, response);
6915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
6925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Makes another attempt at the current name, |qnames_.front()|, using the
6945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // next nameserver.
6955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  AttemptResult MakeAttempt() {
6965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    unsigned attempt_number = attempts_.size();
6975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    uint16 id = session_->NextQueryId();
6995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    scoped_ptr<DnsQuery> query;
7005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (attempts_.empty()) {
7015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      query.reset(new DnsQuery(id, qnames_.front(), qtype_));
7025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } else {
7032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      query.reset(attempts_[0]->GetQuery()->CloneWithNewId(id));
7045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
7055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const DnsConfig& config = session_->config();
7075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
708b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    unsigned server_index =
709b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)        (first_server_index_ + attempt_number) % config.nameservers.size();
710868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    // Skip over known failed servers.
711868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    server_index = session_->NextGoodServerIndex(server_index);
7125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    scoped_ptr<DnsSession::SocketLease> lease =
7142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        session_->AllocateSocket(server_index, net_log_.source());
7152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
7162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    bool got_socket = !!lease.get();
7172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
718868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    DnsUDPAttempt* attempt =
719868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        new DnsUDPAttempt(server_index, lease.Pass(), query.Pass());
7205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    attempts_.push_back(attempt);
722ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    ++attempts_count_;
7235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (!got_socket)
7252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      return AttemptResult(ERR_CONNECTION_REFUSED, NULL);
7262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
7272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    net_log_.AddEvent(
7282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        NetLog::TYPE_DNS_TRANSACTION_ATTEMPT,
7292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        attempt->GetSocketNetLog().source().ToEventParametersCallback());
7302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
73190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    int rv = attempt->Start(
73290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        base::Bind(&DnsTransactionImpl::OnUdpAttemptComplete,
73390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                   base::Unretained(this), attempt_number,
73490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                   base::TimeTicks::Now()));
7355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (rv == ERR_IO_PENDING) {
73690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      base::TimeDelta timeout = session_->NextTimeout(server_index,
73790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                                                      attempt_number);
7385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      timer_.Start(FROM_HERE, timeout, this, &DnsTransactionImpl::OnTimeout);
7395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
7405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return AttemptResult(rv, attempt);
7415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
7425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  AttemptResult MakeTCPAttempt(const DnsAttempt* previous_attempt) {
7442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    DCHECK(previous_attempt);
7452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    DCHECK(!had_tcp_attempt_);
7462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
747868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    unsigned server_index = previous_attempt->server_index();
74890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
7492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    scoped_ptr<StreamSocket> socket(
75090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        session_->CreateTCPSocket(server_index, net_log_.source()));
7512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
7522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // TODO(szym): Reuse the same id to help the server?
7532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    uint16 id = session_->NextQueryId();
7542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    scoped_ptr<DnsQuery> query(
7552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        previous_attempt->GetQuery()->CloneWithNewId(id));
7562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
75790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    RecordLostPacketsIfAny();
7582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // Cancel all other attempts, no point waiting on them.
7592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    attempts_.clear();
7602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
7612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    unsigned attempt_number = attempts_.size();
7622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
76390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    DnsTCPAttempt* attempt = new DnsTCPAttempt(server_index, socket.Pass(),
76490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                                               query.Pass());
7652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
7662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    attempts_.push_back(attempt);
767ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    ++attempts_count_;
7682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    had_tcp_attempt_ = true;
7692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
7702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    net_log_.AddEvent(
7712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        NetLog::TYPE_DNS_TRANSACTION_TCP_ATTEMPT,
7722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        attempt->GetSocketNetLog().source().ToEventParametersCallback());
7732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
7742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    int rv = attempt->Start(base::Bind(&DnsTransactionImpl::OnAttemptComplete,
7752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                       base::Unretained(this),
7762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                       attempt_number));
7772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (rv == ERR_IO_PENDING) {
7782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      // Custom timeout for TCP attempt.
7792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      base::TimeDelta timeout = timer_.GetCurrentDelay() * 2;
7802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      timer_.Start(FROM_HERE, timeout, this, &DnsTransactionImpl::OnTimeout);
7812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
7822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return AttemptResult(rv, attempt);
7832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
7842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
7855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Begins query for the current name. Makes the first attempt.
7865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  AttemptResult StartQuery() {
7875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    std::string dotted_qname = DNSDomainToString(qnames_.front());
7885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    net_log_.BeginEvent(NetLog::TYPE_DNS_TRANSACTION_QUERY,
7895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        NetLog::StringCallback("qname", &dotted_qname));
7905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    first_server_index_ = session_->NextFirstServerIndex();
79290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    RecordLostPacketsIfAny();
7935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    attempts_.clear();
7942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    had_tcp_attempt_ = false;
7955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return MakeAttempt();
7965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
7975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
79890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  void OnUdpAttemptComplete(unsigned attempt_number,
79990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                            base::TimeTicks start,
80090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                            int rv) {
80190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    DCHECK_LT(attempt_number, attempts_.size());
80290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    const DnsAttempt* attempt = attempts_[attempt_number];
80390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    if (attempt->GetResponse()) {
804868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      session_->RecordRTT(attempt->server_index(),
80590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                          base::TimeTicks::Now() - start);
80690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    }
80790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    OnAttemptComplete(attempt_number, rv);
80890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  }
80990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
8105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void OnAttemptComplete(unsigned attempt_number, int rv) {
8115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (callback_.is_null())
8125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return;
8135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK_LT(attempt_number, attempts_.size());
8142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const DnsAttempt* attempt = attempts_[attempt_number];
8155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    AttemptResult result = ProcessAttemptResult(AttemptResult(rv, attempt));
8165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (result.rv != ERR_IO_PENDING)
8175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      DoCallback(result);
8185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
8195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
82090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  // Record packet loss for any incomplete attempts.
82190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  void RecordLostPacketsIfAny() {
82290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    // Loop through attempts until we find first that is completed
82390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    size_t first_completed = 0;
82490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    for (first_completed = 0; first_completed < attempts_.size();
82590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        ++first_completed) {
82690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      if (attempts_[first_completed]->is_completed())
82790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        break;
82890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    }
82990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    // If there were no completed attempts, then we must be offline, so don't
83090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    // record any attempts as lost packets.
83190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    if (first_completed == attempts_.size())
83290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      return;
83390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
834868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    size_t num_servers = session_->config().nameservers.size();
835868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    std::vector<int> server_attempts(num_servers);
83690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    for (size_t i = 0; i < first_completed; ++i) {
837868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      unsigned server_index = attempts_[i]->server_index();
838868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      int server_attempt = server_attempts[server_index]++;
83990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      // Don't record lost packet unless attempt is in pending state.
84090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      if (!attempts_[i]->is_pending())
84190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        continue;
842868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      session_->RecordLostPacket(server_index, server_attempt);
84390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    }
84490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  }
84590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
8462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  void LogResponse(const DnsAttempt* attempt) {
8472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (attempt && attempt->GetResponse()) {
8485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      net_log_.AddEvent(
8495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          NetLog::TYPE_DNS_TRANSACTION_RESPONSE,
8502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          base::Bind(&DnsAttempt::NetLogResponseCallback,
8515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                     base::Unretained(attempt)));
8525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
8535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
8545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool MoreAttemptsAllowed() const {
8562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (had_tcp_attempt_)
8572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      return false;
8585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const DnsConfig& config = session_->config();
8595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return attempts_.size() < config.attempts * config.nameservers.size();
8605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
8615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Resolves the result of a DnsAttempt until a terminal result is reached
8635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // or it will complete asynchronously (ERR_IO_PENDING).
8645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  AttemptResult ProcessAttemptResult(AttemptResult result) {
8655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    while (result.rv != ERR_IO_PENDING) {
8665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      LogResponse(result.attempt);
8675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      switch (result.rv) {
8695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        case OK:
870868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)          session_->RecordServerSuccess(result.attempt->server_index());
871868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)          net_log_.EndEventWithNetErrorCode(NetLog::TYPE_DNS_TRANSACTION_QUERY,
872868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                                            result.rv);
8735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          DCHECK(result.attempt);
8742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          DCHECK(result.attempt->GetResponse());
8755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          return result;
8765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        case ERR_NAME_NOT_RESOLVED:
877868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)          session_->RecordServerSuccess(result.attempt->server_index());
878868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)          net_log_.EndEventWithNetErrorCode(NetLog::TYPE_DNS_TRANSACTION_QUERY,
879868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                                            result.rv);
8805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          // Try next suffix.
8815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          qnames_.pop_front();
8825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          if (qnames_.empty()) {
8835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            return AttemptResult(ERR_NAME_NOT_RESOLVED, NULL);
8845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          } else {
8855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            result = StartQuery();
8865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          }
8875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          break;
8882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        case ERR_CONNECTION_REFUSED:
8895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        case ERR_DNS_TIMED_OUT:
890868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)          if (result.attempt)
891868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)            session_->RecordServerFailure(result.attempt->server_index());
8925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          if (MoreAttemptsAllowed()) {
8935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            result = MakeAttempt();
8945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          } else {
8955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            return result;
8965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          }
8975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          break;
8982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        case ERR_DNS_SERVER_REQUIRES_TCP:
8992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          result = MakeTCPAttempt(result.attempt);
9002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          break;
9015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        default:
9025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          // Server failure.
9035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          DCHECK(result.attempt);
9045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          if (result.attempt != attempts_.back()) {
9055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            // This attempt already timed out. Ignore it.
906868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)            session_->RecordServerFailure(result.attempt->server_index());
9075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            return AttemptResult(ERR_IO_PENDING, NULL);
9085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          }
9095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          if (MoreAttemptsAllowed()) {
9105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            result = MakeAttempt();
9112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          } else if (result.rv == ERR_DNS_MALFORMED_RESPONSE &&
9122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                     !had_tcp_attempt_) {
9132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            // For UDP only, ignore the response and wait until the last attempt
9142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            // times out.
9155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            return AttemptResult(ERR_IO_PENDING, NULL);
9165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          } else {
9175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            return AttemptResult(result.rv, NULL);
9185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          }
9195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          break;
9205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
9215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
9225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return result;
9235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
9245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void OnTimeout() {
9265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (callback_.is_null())
9275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return;
928ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    DCHECK(!attempts_.empty());
9295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    AttemptResult result = ProcessAttemptResult(
930ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch        AttemptResult(ERR_DNS_TIMED_OUT, attempts_.back()));
9315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (result.rv != ERR_IO_PENDING)
9325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      DoCallback(result);
9335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
9345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_refptr<DnsSession> session_;
9365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string hostname_;
9375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  uint16 qtype_;
9385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Cleared in DoCallback.
9395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DnsTransactionFactory::CallbackType callback_;
9405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  BoundNetLog net_log_;
9425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Search list of fully-qualified DNS names to query next (in DNS format).
9445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::deque<std::string> qnames_;
9452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  size_t qnames_initial_size_;
9465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // List of attempts for the current name.
9482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ScopedVector<DnsAttempt> attempts_;
949ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  // Count of attempts, not reset when |attempts_| vector is cleared.
950ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  int  attempts_count_;
9512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  bool had_tcp_attempt_;
9525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Index of the first server to try on each search query.
9545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int first_server_index_;
9555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::OneShotTimer<DnsTransactionImpl> timer_;
9575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DISALLOW_COPY_AND_ASSIGN(DnsTransactionImpl);
9595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
9605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// ----------------------------------------------------------------------------
9625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Implementation of DnsTransactionFactory that returns instances of
9645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// DnsTransactionImpl.
9655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class DnsTransactionFactoryImpl : public DnsTransactionFactory {
9665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public:
9675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  explicit DnsTransactionFactoryImpl(DnsSession* session) {
9685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    session_ = session;
9695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
9705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual scoped_ptr<DnsTransaction> CreateTransaction(
9725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      const std::string& hostname,
9735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      uint16 qtype,
9745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      const CallbackType& callback,
9755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      const BoundNetLog& net_log) OVERRIDE {
976868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    return scoped_ptr<DnsTransaction>(new DnsTransactionImpl(
977868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        session_.get(), hostname, qtype, callback, net_log));
9785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
9795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private:
9815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_refptr<DnsSession> session_;
9825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
9835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace
9855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
9875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)scoped_ptr<DnsTransactionFactory> DnsTransactionFactory::CreateFactory(
9885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DnsSession* session) {
9895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return scoped_ptr<DnsTransactionFactory>(
9905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      new DnsTransactionFactoryImpl(session));
9915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
9925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace net
994