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