Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(947)

Unified Diff: net/dns/dns_transaction.cc

Issue 992733002: Remove //net (except for Android test stuff) and sdch (Closed) Base URL: git@github.com:domokit/mojo.git@master
Patch Set: Created 5 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « net/dns/dns_transaction.h ('k') | net/dns/dns_transaction_unittest.cc » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: net/dns/dns_transaction.cc
diff --git a/net/dns/dns_transaction.cc b/net/dns/dns_transaction.cc
deleted file mode 100644
index beb2197dd55b7bc50d39c71cb70d46c29bfd2a77..0000000000000000000000000000000000000000
--- a/net/dns/dns_transaction.cc
+++ /dev/null
@@ -1,991 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "net/dns/dns_transaction.h"
-
-#include <deque>
-#include <string>
-#include <vector>
-
-#include "base/big_endian.h"
-#include "base/bind.h"
-#include "base/memory/ref_counted.h"
-#include "base/memory/scoped_ptr.h"
-#include "base/memory/scoped_vector.h"
-#include "base/memory/weak_ptr.h"
-#include "base/message_loop/message_loop.h"
-#include "base/metrics/histogram.h"
-#include "base/rand_util.h"
-#include "base/stl_util.h"
-#include "base/strings/string_piece.h"
-#include "base/threading/non_thread_safe.h"
-#include "base/timer/timer.h"
-#include "base/values.h"
-#include "net/base/completion_callback.h"
-#include "net/base/dns_util.h"
-#include "net/base/io_buffer.h"
-#include "net/base/ip_endpoint.h"
-#include "net/base/net_errors.h"
-#include "net/base/net_log.h"
-#include "net/dns/dns_protocol.h"
-#include "net/dns/dns_query.h"
-#include "net/dns/dns_response.h"
-#include "net/dns/dns_session.h"
-#include "net/socket/stream_socket.h"
-#include "net/udp/datagram_client_socket.h"
-
-namespace net {
-
-namespace {
-
-// Provide a common macro to simplify code and readability. We must use a
-// macro as the underlying HISTOGRAM macro creates static variables.
-#define DNS_HISTOGRAM(name, time) UMA_HISTOGRAM_CUSTOM_TIMES(name, time, \
- base::TimeDelta::FromMilliseconds(1), base::TimeDelta::FromHours(1), 100)
-
-// Count labels in the fully-qualified name in DNS format.
-int CountLabels(const std::string& name) {
- size_t count = 0;
- for (size_t i = 0; i < name.size() && name[i]; i += name[i] + 1)
- ++count;
- return count;
-}
-
-bool IsIPLiteral(const std::string& hostname) {
- IPAddressNumber ip;
- return ParseIPLiteralToNumber(hostname, &ip);
-}
-
-base::Value* NetLogStartCallback(const std::string* hostname,
- uint16 qtype,
- NetLog::LogLevel /* log_level */) {
- base::DictionaryValue* dict = new base::DictionaryValue();
- dict->SetString("hostname", *hostname);
- dict->SetInteger("query_type", qtype);
- return dict;
-};
-
-// ----------------------------------------------------------------------------
-
-// A single asynchronous DNS exchange, which consists of sending out a
-// DNS query, waiting for a response, and returning the response that it
-// matches. Logging is done in the socket and in the outer DnsTransaction.
-class DnsAttempt {
- public:
- explicit DnsAttempt(unsigned server_index)
- : result_(ERR_FAILED), server_index_(server_index) {}
-
- virtual ~DnsAttempt() {}
- // Starts the attempt. Returns ERR_IO_PENDING if cannot complete synchronously
- // and calls |callback| upon completion.
- virtual int Start(const CompletionCallback& callback) = 0;
-
- // Returns the query of this attempt.
- virtual const DnsQuery* GetQuery() const = 0;
-
- // Returns the response or NULL if has not received a matching response from
- // the server.
- virtual const DnsResponse* GetResponse() const = 0;
-
- // Returns the net log bound to the source of the socket.
- virtual const BoundNetLog& GetSocketNetLog() const = 0;
-
- // Returns the index of the destination server within DnsConfig::nameservers.
- unsigned server_index() const { return server_index_; }
-
- // Returns a Value representing the received response, along with a reference
- // to the NetLog source source of the UDP socket used. The request must have
- // completed before this is called.
- base::Value* NetLogResponseCallback(NetLog::LogLevel log_level) const {
- DCHECK(GetResponse()->IsValid());
-
- base::DictionaryValue* dict = new base::DictionaryValue();
- dict->SetInteger("rcode", GetResponse()->rcode());
- dict->SetInteger("answer_count", GetResponse()->answer_count());
- GetSocketNetLog().source().AddToEventParameters(dict);
- return dict;
- }
-
- void set_result(int result) {
- result_ = result;
- }
-
- // True if current attempt is pending (waiting for server response).
- bool is_pending() const {
- return result_ == ERR_IO_PENDING;
- }
-
- // True if attempt is completed (received server response).
- bool is_completed() const {
- return (result_ == OK) || (result_ == ERR_NAME_NOT_RESOLVED) ||
- (result_ == ERR_DNS_SERVER_REQUIRES_TCP);
- }
-
- private:
- // Result of last operation.
- int result_;
-
- const unsigned server_index_;
-};
-
-class DnsUDPAttempt : public DnsAttempt {
- public:
- DnsUDPAttempt(unsigned server_index,
- scoped_ptr<DnsSession::SocketLease> socket_lease,
- scoped_ptr<DnsQuery> query)
- : DnsAttempt(server_index),
- next_state_(STATE_NONE),
- received_malformed_response_(false),
- socket_lease_(socket_lease.Pass()),
- query_(query.Pass()) {}
-
- // DnsAttempt:
- int Start(const CompletionCallback& callback) override {
- DCHECK_EQ(STATE_NONE, next_state_);
- callback_ = callback;
- start_time_ = base::TimeTicks::Now();
- next_state_ = STATE_SEND_QUERY;
- return DoLoop(OK);
- }
-
- const DnsQuery* GetQuery() const override { return query_.get(); }
-
- const DnsResponse* GetResponse() const override {
- const DnsResponse* resp = response_.get();
- return (resp != NULL && resp->IsValid()) ? resp : NULL;
- }
-
- const BoundNetLog& GetSocketNetLog() const override {
- return socket_lease_->socket()->NetLog();
- }
-
- private:
- enum State {
- STATE_SEND_QUERY,
- STATE_SEND_QUERY_COMPLETE,
- STATE_READ_RESPONSE,
- STATE_READ_RESPONSE_COMPLETE,
- STATE_NONE,
- };
-
- DatagramClientSocket* socket() {
- return socket_lease_->socket();
- }
-
- int DoLoop(int result) {
- CHECK_NE(STATE_NONE, next_state_);
- int rv = result;
- do {
- State state = next_state_;
- next_state_ = STATE_NONE;
- switch (state) {
- case STATE_SEND_QUERY:
- rv = DoSendQuery();
- break;
- case STATE_SEND_QUERY_COMPLETE:
- rv = DoSendQueryComplete(rv);
- break;
- case STATE_READ_RESPONSE:
- rv = DoReadResponse();
- break;
- case STATE_READ_RESPONSE_COMPLETE:
- rv = DoReadResponseComplete(rv);
- break;
- default:
- NOTREACHED();
- break;
- }
- } while (rv != ERR_IO_PENDING && next_state_ != STATE_NONE);
-
- set_result(rv);
- // If we received a malformed response, and are now waiting for another one,
- // indicate to the transaction that the server might be misbehaving.
- if (rv == ERR_IO_PENDING && received_malformed_response_)
- return ERR_DNS_MALFORMED_RESPONSE;
- if (rv == OK) {
- DCHECK_EQ(STATE_NONE, next_state_);
- DNS_HISTOGRAM("AsyncDNS.UDPAttemptSuccess",
- base::TimeTicks::Now() - start_time_);
- } else if (rv != ERR_IO_PENDING) {
- DNS_HISTOGRAM("AsyncDNS.UDPAttemptFail",
- base::TimeTicks::Now() - start_time_);
- }
- return rv;
- }
-
- int DoSendQuery() {
- next_state_ = STATE_SEND_QUERY_COMPLETE;
- return socket()->Write(query_->io_buffer(),
- query_->io_buffer()->size(),
- base::Bind(&DnsUDPAttempt::OnIOComplete,
- base::Unretained(this)));
- }
-
- int DoSendQueryComplete(int rv) {
- DCHECK_NE(ERR_IO_PENDING, rv);
- if (rv < 0)
- return rv;
-
- // Writing to UDP should not result in a partial datagram.
- if (rv != query_->io_buffer()->size())
- return ERR_MSG_TOO_BIG;
-
- next_state_ = STATE_READ_RESPONSE;
- return OK;
- }
-
- int DoReadResponse() {
- next_state_ = STATE_READ_RESPONSE_COMPLETE;
- response_.reset(new DnsResponse());
- return socket()->Read(response_->io_buffer(),
- response_->io_buffer()->size(),
- base::Bind(&DnsUDPAttempt::OnIOComplete,
- base::Unretained(this)));
- }
-
- int DoReadResponseComplete(int rv) {
- DCHECK_NE(ERR_IO_PENDING, rv);
- if (rv < 0)
- return rv;
-
- DCHECK(rv);
- if (!response_->InitParse(rv, *query_)) {
- // Other implementations simply ignore mismatched responses. Since each
- // DnsUDPAttempt binds to a different port, we might find that responses
- // to previously timed out queries lead to failures in the future.
- // Our solution is to make another attempt, in case the query truly
- // failed, but keep this attempt alive, in case it was a false alarm.
- received_malformed_response_ = true;
- next_state_ = STATE_READ_RESPONSE;
- return OK;
- }
- if (response_->flags() & dns_protocol::kFlagTC)
- return ERR_DNS_SERVER_REQUIRES_TCP;
- // TODO(szym): Extract TTL for NXDOMAIN results. http://crbug.com/115051
- if (response_->rcode() == dns_protocol::kRcodeNXDOMAIN)
- return ERR_NAME_NOT_RESOLVED;
- if (response_->rcode() != dns_protocol::kRcodeNOERROR)
- return ERR_DNS_SERVER_FAILED;
-
- return OK;
- }
-
- void OnIOComplete(int rv) {
- rv = DoLoop(rv);
- if (rv != ERR_IO_PENDING)
- callback_.Run(rv);
- }
-
- State next_state_;
- bool received_malformed_response_;
- base::TimeTicks start_time_;
-
- scoped_ptr<DnsSession::SocketLease> socket_lease_;
- scoped_ptr<DnsQuery> query_;
-
- scoped_ptr<DnsResponse> response_;
-
- CompletionCallback callback_;
-
- DISALLOW_COPY_AND_ASSIGN(DnsUDPAttempt);
-};
-
-class DnsTCPAttempt : public DnsAttempt {
- public:
- DnsTCPAttempt(unsigned server_index,
- scoped_ptr<StreamSocket> socket,
- scoped_ptr<DnsQuery> query)
- : DnsAttempt(server_index),
- next_state_(STATE_NONE),
- socket_(socket.Pass()),
- query_(query.Pass()),
- length_buffer_(new IOBufferWithSize(sizeof(uint16))),
- response_length_(0) {}
-
- // DnsAttempt:
- int Start(const CompletionCallback& callback) override {
- DCHECK_EQ(STATE_NONE, next_state_);
- callback_ = callback;
- start_time_ = base::TimeTicks::Now();
- next_state_ = STATE_CONNECT_COMPLETE;
- int rv = socket_->Connect(base::Bind(&DnsTCPAttempt::OnIOComplete,
- base::Unretained(this)));
- if (rv == ERR_IO_PENDING) {
- set_result(rv);
- return rv;
- }
- return DoLoop(rv);
- }
-
- const DnsQuery* GetQuery() const override { return query_.get(); }
-
- const DnsResponse* GetResponse() const override {
- const DnsResponse* resp = response_.get();
- return (resp != NULL && resp->IsValid()) ? resp : NULL;
- }
-
- const BoundNetLog& GetSocketNetLog() const override {
- return socket_->NetLog();
- }
-
- private:
- enum State {
- STATE_CONNECT_COMPLETE,
- STATE_SEND_LENGTH,
- STATE_SEND_QUERY,
- STATE_READ_LENGTH,
- STATE_READ_LENGTH_COMPLETE,
- STATE_READ_RESPONSE,
- STATE_READ_RESPONSE_COMPLETE,
- STATE_NONE,
- };
-
- int DoLoop(int result) {
- CHECK_NE(STATE_NONE, next_state_);
- int rv = result;
- do {
- State state = next_state_;
- next_state_ = STATE_NONE;
- switch (state) {
- case STATE_CONNECT_COMPLETE:
- rv = DoConnectComplete(rv);
- break;
- case STATE_SEND_LENGTH:
- rv = DoSendLength(rv);
- break;
- case STATE_SEND_QUERY:
- rv = DoSendQuery(rv);
- break;
- case STATE_READ_LENGTH:
- rv = DoReadLength(rv);
- break;
- case STATE_READ_LENGTH_COMPLETE:
- rv = DoReadLengthComplete(rv);
- break;
- case STATE_READ_RESPONSE:
- rv = DoReadResponse(rv);
- break;
- case STATE_READ_RESPONSE_COMPLETE:
- rv = DoReadResponseComplete(rv);
- break;
- default:
- NOTREACHED();
- break;
- }
- } while (rv != ERR_IO_PENDING && next_state_ != STATE_NONE);
-
- set_result(rv);
- if (rv == OK) {
- DCHECK_EQ(STATE_NONE, next_state_);
- DNS_HISTOGRAM("AsyncDNS.TCPAttemptSuccess",
- base::TimeTicks::Now() - start_time_);
- } else if (rv != ERR_IO_PENDING) {
- DNS_HISTOGRAM("AsyncDNS.TCPAttemptFail",
- base::TimeTicks::Now() - start_time_);
- }
- return rv;
- }
-
- int DoConnectComplete(int rv) {
- DCHECK_NE(ERR_IO_PENDING, rv);
- if (rv < 0)
- return rv;
-
- uint16 query_size = static_cast<uint16>(query_->io_buffer()->size());
- if (static_cast<int>(query_size) != query_->io_buffer()->size())
- return ERR_FAILED;
- base::WriteBigEndian<uint16>(length_buffer_->data(), query_size);
- buffer_ =
- new DrainableIOBuffer(length_buffer_.get(), length_buffer_->size());
- next_state_ = STATE_SEND_LENGTH;
- return OK;
- }
-
- int DoSendLength(int rv) {
- DCHECK_NE(ERR_IO_PENDING, rv);
- if (rv < 0)
- return rv;
-
- buffer_->DidConsume(rv);
- if (buffer_->BytesRemaining() > 0) {
- next_state_ = STATE_SEND_LENGTH;
- return socket_->Write(
- buffer_.get(),
- buffer_->BytesRemaining(),
- base::Bind(&DnsTCPAttempt::OnIOComplete, base::Unretained(this)));
- }
- buffer_ = new DrainableIOBuffer(query_->io_buffer(),
- query_->io_buffer()->size());
- next_state_ = STATE_SEND_QUERY;
- return OK;
- }
-
- int DoSendQuery(int rv) {
- DCHECK_NE(ERR_IO_PENDING, rv);
- if (rv < 0)
- return rv;
-
- buffer_->DidConsume(rv);
- if (buffer_->BytesRemaining() > 0) {
- next_state_ = STATE_SEND_QUERY;
- return socket_->Write(
- buffer_.get(),
- buffer_->BytesRemaining(),
- base::Bind(&DnsTCPAttempt::OnIOComplete, base::Unretained(this)));
- }
- buffer_ =
- new DrainableIOBuffer(length_buffer_.get(), length_buffer_->size());
- next_state_ = STATE_READ_LENGTH;
- return OK;
- }
-
- int DoReadLength(int rv) {
- DCHECK_EQ(OK, rv);
-
- next_state_ = STATE_READ_LENGTH_COMPLETE;
- return ReadIntoBuffer();
- }
-
- int DoReadLengthComplete(int rv) {
- DCHECK_NE(ERR_IO_PENDING, rv);
- if (rv < 0)
- return rv;
- if (rv == 0)
- return ERR_CONNECTION_CLOSED;
-
- buffer_->DidConsume(rv);
- if (buffer_->BytesRemaining() > 0) {
- next_state_ = STATE_READ_LENGTH;
- return OK;
- }
-
- base::ReadBigEndian<uint16>(length_buffer_->data(), &response_length_);
- // Check if advertised response is too short. (Optimization only.)
- if (response_length_ < query_->io_buffer()->size())
- return ERR_DNS_MALFORMED_RESPONSE;
- // Allocate more space so that DnsResponse::InitParse sanity check passes.
- response_.reset(new DnsResponse(response_length_ + 1));
- buffer_ = new DrainableIOBuffer(response_->io_buffer(), response_length_);
- next_state_ = STATE_READ_RESPONSE;
- return OK;
- }
-
- int DoReadResponse(int rv) {
- DCHECK_EQ(OK, rv);
-
- next_state_ = STATE_READ_RESPONSE_COMPLETE;
- return ReadIntoBuffer();
- }
-
- int DoReadResponseComplete(int rv) {
- DCHECK_NE(ERR_IO_PENDING, rv);
- if (rv < 0)
- return rv;
- if (rv == 0)
- return ERR_CONNECTION_CLOSED;
-
- buffer_->DidConsume(rv);
- if (buffer_->BytesRemaining() > 0) {
- next_state_ = STATE_READ_RESPONSE;
- return OK;
- }
-
- if (!response_->InitParse(buffer_->BytesConsumed(), *query_))
- return ERR_DNS_MALFORMED_RESPONSE;
- if (response_->flags() & dns_protocol::kFlagTC)
- return ERR_UNEXPECTED;
- // TODO(szym): Frankly, none of these are expected.
- if (response_->rcode() == dns_protocol::kRcodeNXDOMAIN)
- return ERR_NAME_NOT_RESOLVED;
- if (response_->rcode() != dns_protocol::kRcodeNOERROR)
- return ERR_DNS_SERVER_FAILED;
-
- return OK;
- }
-
- void OnIOComplete(int rv) {
- rv = DoLoop(rv);
- if (rv != ERR_IO_PENDING)
- callback_.Run(rv);
- }
-
- int ReadIntoBuffer() {
- return socket_->Read(
- buffer_.get(),
- buffer_->BytesRemaining(),
- base::Bind(&DnsTCPAttempt::OnIOComplete, base::Unretained(this)));
- }
-
- State next_state_;
- base::TimeTicks start_time_;
-
- scoped_ptr<StreamSocket> socket_;
- scoped_ptr<DnsQuery> query_;
- scoped_refptr<IOBufferWithSize> length_buffer_;
- scoped_refptr<DrainableIOBuffer> buffer_;
-
- uint16 response_length_;
- scoped_ptr<DnsResponse> response_;
-
- CompletionCallback callback_;
-
- DISALLOW_COPY_AND_ASSIGN(DnsTCPAttempt);
-};
-
-// ----------------------------------------------------------------------------
-
-// Implements DnsTransaction. Configuration is supplied by DnsSession.
-// The suffix list is built according to the DnsConfig from the session.
-// The timeout for each DnsUDPAttempt is given by DnsSession::NextTimeout.
-// The first server to attempt on each query is given by
-// DnsSession::NextFirstServerIndex, and the order is round-robin afterwards.
-// Each server is attempted DnsConfig::attempts times.
-class DnsTransactionImpl : public DnsTransaction,
- public base::NonThreadSafe,
- public base::SupportsWeakPtr<DnsTransactionImpl> {
- public:
- DnsTransactionImpl(DnsSession* session,
- const std::string& hostname,
- uint16 qtype,
- const DnsTransactionFactory::CallbackType& callback,
- const BoundNetLog& net_log)
- : session_(session),
- hostname_(hostname),
- qtype_(qtype),
- callback_(callback),
- net_log_(net_log),
- qnames_initial_size_(0),
- attempts_count_(0),
- had_tcp_attempt_(false),
- first_server_index_(0) {
- DCHECK(session_.get());
- DCHECK(!hostname_.empty());
- DCHECK(!callback_.is_null());
- DCHECK(!IsIPLiteral(hostname_));
- }
-
- ~DnsTransactionImpl() override {
- if (!callback_.is_null()) {
- net_log_.EndEventWithNetErrorCode(NetLog::TYPE_DNS_TRANSACTION,
- ERR_ABORTED);
- } // otherwise logged in DoCallback or Start
- }
-
- const std::string& GetHostname() const override {
- DCHECK(CalledOnValidThread());
- return hostname_;
- }
-
- uint16 GetType() const override {
- DCHECK(CalledOnValidThread());
- return qtype_;
- }
-
- void Start() override {
- DCHECK(!callback_.is_null());
- DCHECK(attempts_.empty());
- net_log_.BeginEvent(NetLog::TYPE_DNS_TRANSACTION,
- base::Bind(&NetLogStartCallback, &hostname_, qtype_));
- AttemptResult result(PrepareSearch(), NULL);
- if (result.rv == OK) {
- qnames_initial_size_ = qnames_.size();
- if (qtype_ == dns_protocol::kTypeA)
- UMA_HISTOGRAM_COUNTS("AsyncDNS.SuffixSearchStart", qnames_.size());
- result = ProcessAttemptResult(StartQuery());
- }
-
- // Must always return result asynchronously, to avoid reentrancy.
- if (result.rv != ERR_IO_PENDING) {
- base::MessageLoop::current()->PostTask(
- FROM_HERE,
- base::Bind(&DnsTransactionImpl::DoCallback, AsWeakPtr(), result));
- }
- }
-
- private:
- // Wrapper for the result of a DnsUDPAttempt.
- struct AttemptResult {
- AttemptResult(int rv, const DnsAttempt* attempt)
- : rv(rv), attempt(attempt) {}
-
- int rv;
- const DnsAttempt* attempt;
- };
-
- // Prepares |qnames_| according to the DnsConfig.
- int PrepareSearch() {
- const DnsConfig& config = session_->config();
-
- std::string labeled_hostname;
- if (!DNSDomainFromDot(hostname_, &labeled_hostname))
- return ERR_INVALID_ARGUMENT;
-
- if (hostname_[hostname_.size() - 1] == '.') {
- // It's a fully-qualified name, no suffix search.
- qnames_.push_back(labeled_hostname);
- return OK;
- }
-
- int ndots = CountLabels(labeled_hostname) - 1;
-
- if (ndots > 0 && !config.append_to_multi_label_name) {
- qnames_.push_back(labeled_hostname);
- return OK;
- }
-
- // Set true when |labeled_hostname| is put on the list.
- bool had_hostname = false;
-
- if (ndots >= config.ndots) {
- qnames_.push_back(labeled_hostname);
- had_hostname = true;
- }
-
- std::string qname;
- for (size_t i = 0; i < config.search.size(); ++i) {
- // Ignore invalid (too long) combinations.
- if (!DNSDomainFromDot(hostname_ + "." + config.search[i], &qname))
- continue;
- if (qname.size() == labeled_hostname.size()) {
- if (had_hostname)
- continue;
- had_hostname = true;
- }
- qnames_.push_back(qname);
- }
-
- if (ndots > 0 && !had_hostname)
- qnames_.push_back(labeled_hostname);
-
- return qnames_.empty() ? ERR_DNS_SEARCH_EMPTY : OK;
- }
-
- void DoCallback(AttemptResult result) {
- DCHECK(!callback_.is_null());
- DCHECK_NE(ERR_IO_PENDING, result.rv);
- const DnsResponse* response = result.attempt ?
- result.attempt->GetResponse() : NULL;
- CHECK(result.rv != OK || response != NULL);
-
- timer_.Stop();
- RecordLostPacketsIfAny();
- if (result.rv == OK)
- UMA_HISTOGRAM_COUNTS("AsyncDNS.AttemptCountSuccess", attempts_count_);
- else
- UMA_HISTOGRAM_COUNTS("AsyncDNS.AttemptCountFail", attempts_count_);
-
- if (response && qtype_ == dns_protocol::kTypeA) {
- UMA_HISTOGRAM_COUNTS("AsyncDNS.SuffixSearchRemain", qnames_.size());
- UMA_HISTOGRAM_COUNTS("AsyncDNS.SuffixSearchDone",
- qnames_initial_size_ - qnames_.size());
- }
-
- DnsTransactionFactory::CallbackType callback = callback_;
- callback_.Reset();
-
- net_log_.EndEventWithNetErrorCode(NetLog::TYPE_DNS_TRANSACTION, result.rv);
- callback.Run(this, result.rv, response);
- }
-
- // Makes another attempt at the current name, |qnames_.front()|, using the
- // next nameserver.
- AttemptResult MakeAttempt() {
- unsigned attempt_number = attempts_.size();
-
- uint16 id = session_->NextQueryId();
- scoped_ptr<DnsQuery> query;
- if (attempts_.empty()) {
- query.reset(new DnsQuery(id, qnames_.front(), qtype_));
- } else {
- query.reset(attempts_[0]->GetQuery()->CloneWithNewId(id));
- }
-
- const DnsConfig& config = session_->config();
-
- unsigned server_index =
- (first_server_index_ + attempt_number) % config.nameservers.size();
- // Skip over known failed servers.
- server_index = session_->NextGoodServerIndex(server_index);
-
- scoped_ptr<DnsSession::SocketLease> lease =
- session_->AllocateSocket(server_index, net_log_.source());
-
- bool got_socket = !!lease.get();
-
- DnsUDPAttempt* attempt =
- new DnsUDPAttempt(server_index, lease.Pass(), query.Pass());
-
- attempts_.push_back(attempt);
- ++attempts_count_;
-
- if (!got_socket)
- return AttemptResult(ERR_CONNECTION_REFUSED, NULL);
-
- net_log_.AddEvent(
- NetLog::TYPE_DNS_TRANSACTION_ATTEMPT,
- attempt->GetSocketNetLog().source().ToEventParametersCallback());
-
- int rv = attempt->Start(
- base::Bind(&DnsTransactionImpl::OnUdpAttemptComplete,
- base::Unretained(this), attempt_number,
- base::TimeTicks::Now()));
- if (rv == ERR_IO_PENDING) {
- base::TimeDelta timeout = session_->NextTimeout(server_index,
- attempt_number);
- timer_.Start(FROM_HERE, timeout, this, &DnsTransactionImpl::OnTimeout);
- }
- return AttemptResult(rv, attempt);
- }
-
- AttemptResult MakeTCPAttempt(const DnsAttempt* previous_attempt) {
- DCHECK(previous_attempt);
- DCHECK(!had_tcp_attempt_);
-
- unsigned server_index = previous_attempt->server_index();
-
- scoped_ptr<StreamSocket> socket(
- session_->CreateTCPSocket(server_index, net_log_.source()));
-
- // TODO(szym): Reuse the same id to help the server?
- uint16 id = session_->NextQueryId();
- scoped_ptr<DnsQuery> query(
- previous_attempt->GetQuery()->CloneWithNewId(id));
-
- RecordLostPacketsIfAny();
- // Cancel all other attempts, no point waiting on them.
- attempts_.clear();
-
- unsigned attempt_number = attempts_.size();
-
- DnsTCPAttempt* attempt = new DnsTCPAttempt(server_index, socket.Pass(),
- query.Pass());
-
- attempts_.push_back(attempt);
- ++attempts_count_;
- had_tcp_attempt_ = true;
-
- net_log_.AddEvent(
- NetLog::TYPE_DNS_TRANSACTION_TCP_ATTEMPT,
- attempt->GetSocketNetLog().source().ToEventParametersCallback());
-
- int rv = attempt->Start(base::Bind(&DnsTransactionImpl::OnAttemptComplete,
- base::Unretained(this),
- attempt_number));
- if (rv == ERR_IO_PENDING) {
- // Custom timeout for TCP attempt.
- base::TimeDelta timeout = timer_.GetCurrentDelay() * 2;
- timer_.Start(FROM_HERE, timeout, this, &DnsTransactionImpl::OnTimeout);
- }
- return AttemptResult(rv, attempt);
- }
-
- // Begins query for the current name. Makes the first attempt.
- AttemptResult StartQuery() {
- std::string dotted_qname = DNSDomainToString(qnames_.front());
- net_log_.BeginEvent(NetLog::TYPE_DNS_TRANSACTION_QUERY,
- NetLog::StringCallback("qname", &dotted_qname));
-
- first_server_index_ = session_->NextFirstServerIndex();
- RecordLostPacketsIfAny();
- attempts_.clear();
- had_tcp_attempt_ = false;
- return MakeAttempt();
- }
-
- void OnUdpAttemptComplete(unsigned attempt_number,
- base::TimeTicks start,
- int rv) {
- DCHECK_LT(attempt_number, attempts_.size());
- const DnsAttempt* attempt = attempts_[attempt_number];
- if (attempt->GetResponse()) {
- session_->RecordRTT(attempt->server_index(),
- base::TimeTicks::Now() - start);
- }
- OnAttemptComplete(attempt_number, rv);
- }
-
- void OnAttemptComplete(unsigned attempt_number, int rv) {
- if (callback_.is_null())
- return;
- DCHECK_LT(attempt_number, attempts_.size());
- const DnsAttempt* attempt = attempts_[attempt_number];
- AttemptResult result = ProcessAttemptResult(AttemptResult(rv, attempt));
- if (result.rv != ERR_IO_PENDING)
- DoCallback(result);
- }
-
- // Record packet loss for any incomplete attempts.
- void RecordLostPacketsIfAny() {
- // Loop through attempts until we find first that is completed
- size_t first_completed = 0;
- for (first_completed = 0; first_completed < attempts_.size();
- ++first_completed) {
- if (attempts_[first_completed]->is_completed())
- break;
- }
- // If there were no completed attempts, then we must be offline, so don't
- // record any attempts as lost packets.
- if (first_completed == attempts_.size())
- return;
-
- size_t num_servers = session_->config().nameservers.size();
- std::vector<int> server_attempts(num_servers);
- for (size_t i = 0; i < first_completed; ++i) {
- unsigned server_index = attempts_[i]->server_index();
- int server_attempt = server_attempts[server_index]++;
- // Don't record lost packet unless attempt is in pending state.
- if (!attempts_[i]->is_pending())
- continue;
- session_->RecordLostPacket(server_index, server_attempt);
- }
- }
-
- void LogResponse(const DnsAttempt* attempt) {
- if (attempt && attempt->GetResponse()) {
- net_log_.AddEvent(
- NetLog::TYPE_DNS_TRANSACTION_RESPONSE,
- base::Bind(&DnsAttempt::NetLogResponseCallback,
- base::Unretained(attempt)));
- }
- }
-
- bool MoreAttemptsAllowed() const {
- if (had_tcp_attempt_)
- return false;
- const DnsConfig& config = session_->config();
- return attempts_.size() < config.attempts * config.nameservers.size();
- }
-
- // Resolves the result of a DnsAttempt until a terminal result is reached
- // or it will complete asynchronously (ERR_IO_PENDING).
- AttemptResult ProcessAttemptResult(AttemptResult result) {
- while (result.rv != ERR_IO_PENDING) {
- LogResponse(result.attempt);
-
- switch (result.rv) {
- case OK:
- session_->RecordServerSuccess(result.attempt->server_index());
- net_log_.EndEventWithNetErrorCode(NetLog::TYPE_DNS_TRANSACTION_QUERY,
- result.rv);
- DCHECK(result.attempt);
- DCHECK(result.attempt->GetResponse());
- return result;
- case ERR_NAME_NOT_RESOLVED:
- session_->RecordServerSuccess(result.attempt->server_index());
- net_log_.EndEventWithNetErrorCode(NetLog::TYPE_DNS_TRANSACTION_QUERY,
- result.rv);
- // Try next suffix.
- qnames_.pop_front();
- if (qnames_.empty()) {
- return AttemptResult(ERR_NAME_NOT_RESOLVED, NULL);
- } else {
- result = StartQuery();
- }
- break;
- case ERR_CONNECTION_REFUSED:
- case ERR_DNS_TIMED_OUT:
- if (result.attempt)
- session_->RecordServerFailure(result.attempt->server_index());
- if (MoreAttemptsAllowed()) {
- result = MakeAttempt();
- } else {
- return result;
- }
- break;
- case ERR_DNS_SERVER_REQUIRES_TCP:
- result = MakeTCPAttempt(result.attempt);
- break;
- default:
- // Server failure.
- DCHECK(result.attempt);
- if (result.attempt != attempts_.back()) {
- // This attempt already timed out. Ignore it.
- session_->RecordServerFailure(result.attempt->server_index());
- return AttemptResult(ERR_IO_PENDING, NULL);
- }
- if (MoreAttemptsAllowed()) {
- result = MakeAttempt();
- } else if (result.rv == ERR_DNS_MALFORMED_RESPONSE &&
- !had_tcp_attempt_) {
- // For UDP only, ignore the response and wait until the last attempt
- // times out.
- return AttemptResult(ERR_IO_PENDING, NULL);
- } else {
- return AttemptResult(result.rv, NULL);
- }
- break;
- }
- }
- return result;
- }
-
- void OnTimeout() {
- if (callback_.is_null())
- return;
- DCHECK(!attempts_.empty());
- AttemptResult result = ProcessAttemptResult(
- AttemptResult(ERR_DNS_TIMED_OUT, attempts_.back()));
- if (result.rv != ERR_IO_PENDING)
- DoCallback(result);
- }
-
- scoped_refptr<DnsSession> session_;
- std::string hostname_;
- uint16 qtype_;
- // Cleared in DoCallback.
- DnsTransactionFactory::CallbackType callback_;
-
- BoundNetLog net_log_;
-
- // Search list of fully-qualified DNS names to query next (in DNS format).
- std::deque<std::string> qnames_;
- size_t qnames_initial_size_;
-
- // List of attempts for the current name.
- ScopedVector<DnsAttempt> attempts_;
- // Count of attempts, not reset when |attempts_| vector is cleared.
- int attempts_count_;
- bool had_tcp_attempt_;
-
- // Index of the first server to try on each search query.
- int first_server_index_;
-
- base::OneShotTimer<DnsTransactionImpl> timer_;
-
- DISALLOW_COPY_AND_ASSIGN(DnsTransactionImpl);
-};
-
-// ----------------------------------------------------------------------------
-
-// Implementation of DnsTransactionFactory that returns instances of
-// DnsTransactionImpl.
-class DnsTransactionFactoryImpl : public DnsTransactionFactory {
- public:
- explicit DnsTransactionFactoryImpl(DnsSession* session) {
- session_ = session;
- }
-
- scoped_ptr<DnsTransaction> CreateTransaction(
- const std::string& hostname,
- uint16 qtype,
- const CallbackType& callback,
- const BoundNetLog& net_log) override {
- return scoped_ptr<DnsTransaction>(new DnsTransactionImpl(
- session_.get(), hostname, qtype, callback, net_log));
- }
-
- private:
- scoped_refptr<DnsSession> session_;
-};
-
-} // namespace
-
-// static
-scoped_ptr<DnsTransactionFactory> DnsTransactionFactory::CreateFactory(
- DnsSession* session) {
- return scoped_ptr<DnsTransactionFactory>(
- new DnsTransactionFactoryImpl(session));
-}
-
-} // namespace net
« no previous file with comments | « net/dns/dns_transaction.h ('k') | net/dns/dns_transaction_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698