summaryrefslogtreecommitdiffstats
path: root/net/dns/dns_transaction.cc
diff options
context:
space:
mode:
authoragayev@chromium.org <agayev@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-07-22 15:58:20 +0000
committeragayev@chromium.org <agayev@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-07-22 15:58:20 +0000
commit4b0112ab742b96585b897269dd27cc7818b3f129 (patch)
tree0ea379258252b88f5e323b9c6f547f8b3c2500fa /net/dns/dns_transaction.cc
parent17bf5d37a85eff17c372db57ef37cc4b57f28b53 (diff)
downloadchromium_src-4b0112ab742b96585b897269dd27cc7818b3f129.zip
chromium_src-4b0112ab742b96585b897269dd27cc7818b3f129.tar.gz
chromium_src-4b0112ab742b96585b897269dd27cc7818b3f129.tar.bz2
File reorganization: move AsyncHostResolver files to net/dns.
BUG=60149 TEST=net_unittest --gtest_filter="AsyncHostResolver*" Review URL: http://codereview.chromium.org/7484012 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@93644 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'net/dns/dns_transaction.cc')
-rw-r--r--net/dns/dns_transaction.cc336
1 files changed, 336 insertions, 0 deletions
diff --git a/net/dns/dns_transaction.cc b/net/dns/dns_transaction.cc
new file mode 100644
index 0000000..6e287c8
--- /dev/null
+++ b/net/dns/dns_transaction.cc
@@ -0,0 +1,336 @@
+// Copyright (c) 2011 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 "base/bind.h"
+#include "base/rand_util.h"
+#include "base/values.h"
+#include "net/base/dns_util.h"
+#include "net/base/io_buffer.h"
+#include "net/base/net_errors.h"
+#include "net/dns/dns_query.h"
+#include "net/dns/dns_response.h"
+#include "net/socket/client_socket_factory.h"
+#include "net/udp/datagram_client_socket.h"
+
+namespace net {
+
+namespace {
+
+// Retry timeouts.
+const int kTimeoutsMs[] = {3000, 5000, 11000};
+const int kMaxAttempts = arraysize(kTimeoutsMs);
+
+// Returns the string representation of an IPAddressNumber.
+std::string IPAddressToString(const IPAddressNumber& ip_address) {
+ IPEndPoint ip_endpoint(ip_address, 0);
+ struct sockaddr_storage addr;
+ size_t addr_len = sizeof(addr);
+ struct sockaddr* sockaddr = reinterpret_cast<struct sockaddr*>(&addr);
+ if (!ip_endpoint.ToSockAddr(sockaddr, &addr_len))
+ return "";
+ return NetAddressToString(sockaddr, addr_len);
+}
+
+}
+
+DnsTransaction::Delegate::Delegate() {
+}
+
+DnsTransaction::Delegate::~Delegate() {
+ while (!registered_transactions_.empty()) {
+ DnsTransaction* transaction = *registered_transactions_.begin();
+ transaction->SetDelegate(NULL);
+ }
+ DCHECK(registered_transactions_.empty());
+}
+
+void DnsTransaction::Delegate::OnTransactionComplete(
+ int result,
+ const DnsTransaction* transaction,
+ const IPAddressList& ip_addresses) {
+}
+
+void DnsTransaction::Delegate::Attach(DnsTransaction* transaction) {
+ DCHECK(registered_transactions_.find(transaction) ==
+ registered_transactions_.end());
+ registered_transactions_.insert(transaction);
+}
+
+void DnsTransaction::Delegate::Detach(DnsTransaction* transaction) {
+ DCHECK(registered_transactions_.find(transaction) !=
+ registered_transactions_.end());
+ registered_transactions_.erase(transaction);
+}
+
+namespace {
+
+class DnsTransactionStartParameters : public NetLog::EventParameters {
+ public:
+ DnsTransactionStartParameters(const IPEndPoint& dns_server,
+ const DnsTransaction::Key& key,
+ const NetLog::Source& source)
+ : dns_server_(dns_server), key_(key), source_(source) {}
+
+ virtual Value* ToValue() const {
+ std::string hostname;
+ DnsResponseBuffer(
+ reinterpret_cast<const uint8*>(key_.first.c_str()), key_.first.size()).
+ DNSName(&hostname);
+
+ DictionaryValue* dict = new DictionaryValue();
+ dict->SetString("dns_server", dns_server_.ToString());
+ dict->SetString("hostname", hostname);
+ dict->SetInteger("query_type", key_.second);
+ dict->Set("source_dependency", source_.ToValue());
+ return dict;
+ }
+
+ private:
+ const IPEndPoint dns_server_;
+ const DnsTransaction::Key key_;
+ const NetLog::Source source_;
+};
+
+class DnsTransactionFinishParameters : public NetLog::EventParameters {
+ public:
+ DnsTransactionFinishParameters(int net_error,
+ const IPAddressList& ip_address_list)
+ : net_error_(net_error), ip_address_list_(ip_address_list) {}
+
+ virtual Value* ToValue() const {
+ ListValue* list = new ListValue();
+ for (IPAddressList::const_iterator it = ip_address_list_.begin();
+ it != ip_address_list_.end(); ++it)
+ list->Append(Value::CreateStringValue(IPAddressToString(*it)));
+
+ DictionaryValue* dict = new DictionaryValue();
+ dict->SetInteger("net_error", net_error_);
+ dict->Set("address_list", list);
+ return dict;
+ }
+
+ private:
+ const int net_error_;
+ const IPAddressList ip_address_list_;
+};
+
+class DnsTransactionRetryParameters : public NetLog::EventParameters {
+ public:
+ DnsTransactionRetryParameters(int attempt_number,
+ const NetLog::Source& source)
+ : attempt_number_(attempt_number), source_(source) {}
+
+ virtual Value* ToValue() const {
+ DictionaryValue* dict = new DictionaryValue();
+ dict->SetInteger("attempt_number", attempt_number_);
+ dict->Set("source_dependency", source_.ToValue());
+ return dict;
+ }
+
+ private:
+ const int attempt_number_;
+ const NetLog::Source source_;
+};
+
+} // namespace
+
+DnsTransaction::DnsTransaction(const IPEndPoint& dns_server,
+ const std::string& dns_name,
+ uint16 query_type,
+ const RandIntCallback& rand_int,
+ ClientSocketFactory* socket_factory,
+ const BoundNetLog& source_net_log,
+ NetLog* net_log)
+ : dns_server_(dns_server),
+ key_(dns_name, query_type),
+ delegate_(NULL),
+ query_(new DnsQuery(dns_name, query_type, rand_int)),
+ attempts_(0),
+ next_state_(STATE_NONE),
+ socket_factory_(socket_factory ? socket_factory :
+ ClientSocketFactory::GetDefaultFactory()),
+ ALLOW_THIS_IN_INITIALIZER_LIST(
+ io_callback_(this, &DnsTransaction::OnIOComplete)),
+ net_log_(BoundNetLog::Make(net_log, NetLog::SOURCE_DNS_TRANSACTION)) {
+ DCHECK(!rand_int.is_null());
+ for (size_t i = 0; i < arraysize(kTimeoutsMs); ++i)
+ timeouts_ms_.push_back(base::TimeDelta::FromMilliseconds(kTimeoutsMs[i]));
+ net_log_.BeginEvent(
+ NetLog::TYPE_DNS_TRANSACTION,
+ make_scoped_refptr(
+ new DnsTransactionStartParameters(dns_server_, key_,
+ source_net_log.source())));
+}
+
+DnsTransaction::~DnsTransaction() {
+ SetDelegate(NULL);
+}
+
+void DnsTransaction::SetDelegate(Delegate* delegate) {
+ if (delegate == delegate_)
+ return;
+ if (delegate_)
+ delegate_->Detach(this);
+ delegate_ = delegate;
+ if (delegate_)
+ delegate_->Attach(this);
+}
+
+int DnsTransaction::Start() {
+ DCHECK_EQ(STATE_NONE, next_state_);
+ next_state_ = STATE_CONNECT;
+ return DoLoop(OK);
+}
+
+int DnsTransaction::DoLoop(int result) {
+ DCHECK_NE(STATE_NONE, next_state_);
+ int rv = result;
+ do {
+ State state = next_state_;
+ next_state_ = STATE_NONE;
+ switch (state) {
+ case STATE_CONNECT:
+ rv = DoConnect();
+ break;
+ case STATE_CONNECT_COMPLETE:
+ rv = DoConnectComplete(rv);
+ break;
+ 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);
+
+ return rv;
+}
+
+void DnsTransaction::DoCallback(int result) {
+ DCHECK_NE(result, ERR_IO_PENDING);
+ net_log_.EndEvent(
+ NetLog::TYPE_DNS_TRANSACTION,
+ make_scoped_refptr(
+ new DnsTransactionFinishParameters(result, ip_addresses_)));
+ if (delegate_)
+ delegate_->OnTransactionComplete(result, this, ip_addresses_);
+}
+
+void DnsTransaction::OnIOComplete(int result) {
+ int rv = DoLoop(result);
+ if (rv != ERR_IO_PENDING)
+ DoCallback(rv);
+}
+
+int DnsTransaction::DoConnect() {
+ next_state_ = STATE_CONNECT_COMPLETE;
+
+ DCHECK_LT(attempts_, timeouts_ms_.size());
+ StartTimer(timeouts_ms_[attempts_]);
+ attempts_++;
+
+ // TODO(agayev): keep all sockets around in case the server responds
+ // after its timeout; state machine will need to change to handle that.
+ socket_.reset(socket_factory_->CreateDatagramClientSocket(
+ DatagramSocket::RANDOM_BIND,
+ base::Bind(&base::RandInt),
+ NULL,
+ net_log_.source()));
+
+ net_log_.AddEvent(
+ NetLog::TYPE_DNS_TRANSACTION_ATTEMPT_STARTED,
+ make_scoped_refptr(
+ new DnsTransactionRetryParameters(attempts_,
+ socket_->NetLog().source())));
+
+ return socket_->Connect(dns_server_);
+}
+
+int DnsTransaction::DoConnectComplete(int rv) {
+ if (rv < 0)
+ return rv;
+ next_state_ = STATE_SEND_QUERY;
+ return OK;
+}
+
+int DnsTransaction::DoSendQuery() {
+ next_state_ = STATE_SEND_QUERY_COMPLETE;
+ return socket_->Write(query_->io_buffer(),
+ query_->io_buffer()->size(),
+ &io_callback_);
+}
+
+int DnsTransaction::DoSendQueryComplete(int rv) {
+ if (rv < 0)
+ return rv;
+
+ // Writing to UDP should not result in a partial datagram.
+ if (rv != query_->io_buffer()->size())
+ return ERR_NAME_NOT_RESOLVED;
+
+ next_state_ = STATE_READ_RESPONSE;
+ return OK;
+}
+
+int DnsTransaction::DoReadResponse() {
+ next_state_ = STATE_READ_RESPONSE_COMPLETE;
+ response_.reset(new DnsResponse(query_.get()));
+ return socket_->Read(response_->io_buffer(),
+ response_->io_buffer()->size(),
+ &io_callback_);
+}
+
+int DnsTransaction::DoReadResponseComplete(int rv) {
+ DCHECK_NE(ERR_IO_PENDING, rv);
+ RevokeTimer();
+ if (rv < 0)
+ return rv;
+
+ DCHECK(rv);
+ // TODO(agayev): when supporting EDNS0 we may need to do multiple reads
+ // to read the whole response.
+ return response_->Parse(rv, &ip_addresses_);
+}
+
+void DnsTransaction::StartTimer(base::TimeDelta delay) {
+ timer_.Start(delay, this, &DnsTransaction::OnTimeout);
+}
+
+void DnsTransaction::RevokeTimer() {
+ timer_.Stop();
+}
+
+void DnsTransaction::OnTimeout() {
+ DCHECK(next_state_ == STATE_SEND_QUERY_COMPLETE ||
+ next_state_ == STATE_READ_RESPONSE_COMPLETE);
+ if (attempts_ == timeouts_ms_.size()) {
+ DoCallback(ERR_DNS_TIMED_OUT);
+ return;
+ }
+ next_state_ = STATE_CONNECT;
+ query_.reset(query_->CloneWithNewId());
+ int rv = DoLoop(OK);
+ if (rv != ERR_IO_PENDING)
+ DoCallback(rv);
+}
+
+void DnsTransaction::set_timeouts_ms(
+ const std::vector<base::TimeDelta>& timeouts_ms) {
+ DCHECK_EQ(0u, attempts_);
+ timeouts_ms_ = timeouts_ms;
+}
+
+} // namespace net