diff options
Diffstat (limited to 'net/dns/dns_transaction.cc')
-rw-r--r-- | net/dns/dns_transaction.cc | 184 |
1 files changed, 122 insertions, 62 deletions
diff --git a/net/dns/dns_transaction.cc b/net/dns/dns_transaction.cc index 5cbe39a..a7fa922 100644 --- a/net/dns/dns_transaction.cc +++ b/net/dns/dns_transaction.cc @@ -7,12 +7,11 @@ #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_protocol.h" #include "net/dns/dns_query.h" #include "net/dns/dns_response.h" -#include "net/dns/dns_session.h" #include "net/socket/client_socket_factory.h" #include "net/udp/datagram_client_socket.h" @@ -20,51 +19,104 @@ 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 base::StringPiece& qname, - uint16 qtype, + const DnsTransaction::Key& key, const NetLog::Source& source) - : dns_server_(dns_server), - qname_(qname.data(), qname.length()), - qtype_(qtype), - 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", qname_); - dict->SetInteger("query_type", qtype_); + dict->SetString("hostname", hostname); + dict->SetInteger("query_type", key_.second); if (source_.is_valid()) dict->Set("source_dependency", source_.ToValue()); return dict; } private: - IPEndPoint dns_server_; - std::string qname_; - uint16 qtype_; + const IPEndPoint dns_server_; + const DnsTransaction::Key key_; const NetLog::Source source_; }; class DnsTransactionFinishParameters : public NetLog::EventParameters { public: - // TODO(szym): add rcode ? - DnsTransactionFinishParameters(int net_error, int answer_count) - : net_error_(net_error), answer_count_(answer_count) {} + 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(); if (net_error_) dict->SetInteger("net_error", net_error_); - dict->SetInteger("answer_count", answer_count_); + dict->Set("address_list", list); return dict; } private: const int net_error_; - const int answer_count_; + const IPAddressList ip_address_list_; }; class DnsTransactionRetryParameters : public NetLog::EventParameters { @@ -87,32 +139,47 @@ class DnsTransactionRetryParameters : public NetLog::EventParameters { } // namespace - -DnsTransaction::DnsTransaction(DnsSession* session, - const base::StringPiece& qname, - uint16 qtype, - const ResultCallback& callback, - const BoundNetLog& source_net_log) - : session_(session), - dns_server_(session->NextServer()), - query_(new DnsQuery(session->NextId(), qname, qtype)), - callback_(callback), +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(session->net_log(), - NetLog::SOURCE_DNS_TRANSACTION)) { + 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_, - qname, - qtype, + new DnsTransactionStartParameters(dns_server_, key_, source_net_log.source()))); } -DnsTransaction::~DnsTransaction() {} +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_); @@ -156,12 +223,12 @@ int DnsTransaction::DoLoop(int result) { void DnsTransaction::DoCallback(int result) { DCHECK_NE(result, ERR_IO_PENDING); - int answer_count = (result == OK) ? response()->answer_count() : 0; net_log_.EndEvent( NetLog::TYPE_DNS_TRANSACTION, make_scoped_refptr( - new DnsTransactionFinishParameters(result, answer_count))); - callback_.Run(this, result); + new DnsTransactionFinishParameters(result, ip_addresses_))); + if (delegate_) + delegate_->OnTransactionComplete(result, this, ip_addresses_); } void DnsTransaction::OnIOComplete(int result) { @@ -173,14 +240,13 @@ void DnsTransaction::OnIOComplete(int result) { int DnsTransaction::DoConnect() { next_state_ = STATE_CONNECT_COMPLETE; - StartTimer(session_->NextTimeout(attempts_)); - ++attempts_; + DCHECK_LT(attempts_, timeouts_ms_.size()); + StartTimer(timeouts_ms_[attempts_]); + attempts_++; - // TODO(szym): keep all sockets around in case the server responds + // TODO(agayev): keep all sockets around in case the server responds // after its timeout; state machine will need to change to handle that. - // The current plan is to move socket management out to DnsSession. - // Hence also move retransmissions to DnsClient::Request. - socket_.reset(session_->socket_factory()->CreateDatagramClientSocket( + socket_.reset(socket_factory_->CreateDatagramClientSocket( DatagramSocket::RANDOM_BIND, base::Bind(&base::RandInt), net_log_.net_log(), @@ -215,7 +281,7 @@ int DnsTransaction::DoSendQueryComplete(int rv) { // Writing to UDP should not result in a partial datagram. if (rv != query_->io_buffer()->size()) - return ERR_MSG_TOO_BIG; + return ERR_NAME_NOT_RESOLVED; next_state_ = STATE_READ_RESPONSE; return OK; @@ -223,7 +289,7 @@ int DnsTransaction::DoSendQueryComplete(int rv) { int DnsTransaction::DoReadResponse() { next_state_ = STATE_READ_RESPONSE_COMPLETE; - response_.reset(new DnsResponse()); + response_.reset(new DnsResponse(query_.get())); return socket_->Read(response_->io_buffer(), response_->io_buffer()->size(), &io_callback_); @@ -236,21 +302,9 @@ int DnsTransaction::DoReadResponseComplete(int rv) { return rv; DCHECK(rv); - if (!response_->InitParse(rv, *query_)) - return ERR_DNS_MALFORMED_RESPONSE; - // TODO(szym): define this flag value in dns_protocol - if (response_->flags1() & 2) - return ERR_DNS_SERVER_REQUIRES_TCP; - // TODO(szym): move this handling out of DnsTransaction? - if (response_->rcode() != dns_protocol::kRcodeNOERROR && - response_->rcode() != dns_protocol::kRcodeNXDOMAIN) { - return ERR_DNS_SERVER_FAILED; - } - // TODO(szym): add ERR_DNS_RR_NOT_FOUND? - if (response_->answer_count() == 0) - return ERR_NAME_NOT_RESOLVED; - - return OK; + // 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) { @@ -264,15 +318,21 @@ void DnsTransaction::RevokeTimer() { void DnsTransaction::OnTimeout() { DCHECK(next_state_ == STATE_SEND_QUERY_COMPLETE || next_state_ == STATE_READ_RESPONSE_COMPLETE); - if (attempts_ == session_->config().attempts) { + if (attempts_ == timeouts_ms_.size()) { DoCallback(ERR_DNS_TIMED_OUT); return; } next_state_ = STATE_CONNECT; - query_.reset(query_->CloneWithNewId(session_->NextId())); + 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 |