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

Unified Diff: net/dns/async_host_resolver.cc

Issue 9369045: [net] HostResolverImpl + DnsTransaction + DnsConfigService = Asynchronous DNS ready for experiments. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Denitted. Created 8 years, 10 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/async_host_resolver.h ('k') | net/dns/async_host_resolver_unittest.cc » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: net/dns/async_host_resolver.cc
diff --git a/net/dns/async_host_resolver.cc b/net/dns/async_host_resolver.cc
deleted file mode 100644
index 72e5472419daf4df4983a4a4c60b7b80b1350d6b..0000000000000000000000000000000000000000
--- a/net/dns/async_host_resolver.cc
+++ /dev/null
@@ -1,524 +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/async_host_resolver.h"
-
-#include <algorithm>
-
-#include "base/bind.h"
-#include "base/logging.h"
-#include "base/message_loop.h"
-#include "base/rand_util.h"
-#include "base/stl_util.h"
-#include "base/values.h"
-#include "net/base/address_list.h"
-#include "net/base/dns_util.h"
-#include "net/base/net_errors.h"
-#include "net/dns/dns_protocol.h"
-#include "net/dns/dns_response.h"
-#include "net/dns/dns_session.h"
-#include "net/socket/client_socket_factory.h"
-
-namespace net {
-
-namespace {
-
-// TODO(agayev): fix this when IPv6 support is added.
-uint16 QueryTypeFromAddressFamily(AddressFamily address_family) {
- return dns_protocol::kTypeA;
-}
-
-class RequestParameters : public NetLog::EventParameters {
- public:
- RequestParameters(const HostResolver::RequestInfo& info,
- const NetLog::Source& source)
- : info_(info), source_(source) {}
-
- virtual Value* ToValue() const {
- DictionaryValue* dict = new DictionaryValue();
- dict->SetString("hostname", info_.host_port_pair().ToString());
- dict->SetInteger("address_family",
- static_cast<int>(info_.address_family()));
- dict->SetBoolean("allow_cached_response", info_.allow_cached_response());
- dict->SetBoolean("is_speculative", info_.is_speculative());
- dict->SetInteger("priority", info_.priority());
-
- if (source_.is_valid())
- dict->Set("source_dependency", source_.ToValue());
-
- return dict;
- }
-
- private:
- const HostResolver::RequestInfo info_;
- const NetLog::Source source_;
-};
-
-} // namespace
-
-HostResolver* CreateAsyncHostResolver(size_t max_concurrent_resolves,
- const IPAddressNumber& dns_ip,
- NetLog* net_log) {
- size_t max_dns_requests = max_concurrent_resolves;
- if (max_dns_requests == 0)
- max_dns_requests = 20;
- size_t max_pending_requests = max_dns_requests * 100;
- DnsConfig config;
- config.nameservers.push_back(IPEndPoint(dns_ip, 53));
- DnsSession* session = new DnsSession(
- config,
- ClientSocketFactory::GetDefaultFactory(),
- base::Bind(&base::RandInt),
- net_log);
- HostResolver* resolver = new AsyncHostResolver(
- max_dns_requests,
- max_pending_requests,
- HostCache::CreateDefaultCache(),
- DnsTransactionFactory::CreateFactory(session),
- net_log);
- return resolver;
-}
-
-//-----------------------------------------------------------------------------
-// Every call to Resolve() results in Request object being created. Such a
-// call may complete either synchronously or asynchronously or it may get
-// cancelled, which can be either through specific CancelRequest call or by
-// the destruction of AsyncHostResolver, which would destruct pending or
-// in-progress requests, causing them to be cancelled. Synchronous
-// resolution sets |callback_| to NULL, thus, if in the destructor we still
-// have a non-NULL |callback_|, we are being cancelled.
-class AsyncHostResolver::Request {
- public:
- Request(AsyncHostResolver* resolver,
- const BoundNetLog& source_net_log,
- const BoundNetLog& request_net_log,
- const HostResolver::RequestInfo& info,
- const CompletionCallback& callback,
- AddressList* addresses)
- : resolver_(resolver),
- source_net_log_(source_net_log),
- request_net_log_(request_net_log),
- info_(info),
- callback_(callback),
- addresses_(addresses),
- result_(ERR_UNEXPECTED) {
- DCHECK(addresses_);
- DCHECK(resolver_);
- resolver_->OnStart(this);
- key_ = Key(info.hostname(),
- QueryTypeFromAddressFamily(info.address_family()));
- }
-
- ~Request() {
- if (!callback_.is_null())
- resolver_->OnCancel(this);
- }
-
- int result() const { return result_; }
- const Key& key() const {
- DCHECK(IsValid());
- return key_;
- }
- const HostResolver::RequestInfo& info() const { return info_; }
- RequestPriority priority() const { return info_.priority(); }
- const BoundNetLog& source_net_log() const { return source_net_log_; }
- const BoundNetLog& request_net_log() const { return request_net_log_; }
-
- bool ResolveAsIp() {
- IPAddressNumber ip_number;
- if (!ParseIPLiteralToNumber(info_.hostname(), &ip_number))
- return false;
-
- if (ip_number.size() != kIPv4AddressSize) {
- result_ = ERR_NAME_NOT_RESOLVED;
- } else {
- *addresses_ = AddressList::CreateFromIPAddressWithCname(
- ip_number,
- info_.port(),
- info_.host_resolver_flags() & HOST_RESOLVER_CANONNAME);
- result_ = OK;
- }
- return true;
- }
-
- bool ServeFromCache() {
- HostCache* cache = resolver_->cache_.get();
- if (!cache || !info_.allow_cached_response())
- return false;
-
- HostCache::Key key(info_.hostname(), info_.address_family(),
- info_.host_resolver_flags());
- const HostCache::Entry* cache_entry = cache->Lookup(
- key, base::TimeTicks::Now());
- if (cache_entry) {
- request_net_log_.AddEvent(
- NetLog::TYPE_ASYNC_HOST_RESOLVER_CACHE_HIT, NULL);
- DCHECK_EQ(OK, cache_entry->error);
- result_ = cache_entry->error;
- *addresses_ =
- CreateAddressListUsingPort(cache_entry->addrlist, info_.port());
- return true;
- }
- return false;
- }
-
- // Called when a request completes synchronously; we do not have an
- // AddressList argument, since in case of a successful synchronous
- // completion, either ResolveAsIp or ServerFromCache would set the
- // |addresses_| and in case of an unsuccessful synchronous completion, we
- // do not touch |addresses_|.
- void OnSyncComplete(int result) {
- callback_.Reset();
- resolver_->OnFinish(this, result);
- }
-
- // Called when a request completes asynchronously.
- void OnAsyncComplete(int result, const AddressList& addresses) {
- if (result == OK)
- *addresses_ = CreateAddressListUsingPort(addresses, info_.port());
- DCHECK_EQ(false, callback_.is_null());
- CompletionCallback callback = callback_;
- callback_.Reset();
- resolver_->OnFinish(this, result);
- callback.Run(result);
- }
-
- // Returns true if request has a validly formed hostname.
- bool IsValid() const {
- return !info_.hostname().empty() && !key_.first.empty();
- }
-
- private:
- AsyncHostResolver* resolver_;
- BoundNetLog source_net_log_;
- BoundNetLog request_net_log_;
- const HostResolver::RequestInfo info_;
- Key key_;
- CompletionCallback callback_;
- AddressList* addresses_;
- int result_;
-};
-
-//-----------------------------------------------------------------------------
-AsyncHostResolver::AsyncHostResolver(size_t max_dns_requests,
- size_t max_pending_requests,
- HostCache* cache,
- scoped_ptr<DnsTransactionFactory> client,
- NetLog* net_log)
- : max_dns_transactions_(max_dns_requests),
- max_pending_requests_(max_pending_requests),
- cache_(cache),
- client_(client.Pass()),
- net_log_(net_log) {
-}
-
-AsyncHostResolver::~AsyncHostResolver() {
- // Destroy request lists.
- for (KeyRequestListMap::iterator it = requestlist_map_.begin();
- it != requestlist_map_.end(); ++it)
- STLDeleteElements(&it->second);
-
- // Destroy DNS transactions.
- STLDeleteElements(&dns_transactions_);
-
- // Destroy pending requests.
- for (size_t i = 0; i < arraysize(pending_requests_); ++i)
- STLDeleteElements(&pending_requests_[i]);
-}
-
-int AsyncHostResolver::Resolve(const RequestInfo& info,
- AddressList* addresses,
- const CompletionCallback& callback,
- RequestHandle* out_req,
- const BoundNetLog& source_net_log) {
- DCHECK(addresses);
- DCHECK_EQ(false, callback.is_null());
- scoped_ptr<Request> request(
- CreateNewRequest(info, callback, addresses, source_net_log));
-
- int rv = ERR_UNEXPECTED;
- if (!request->IsValid())
- rv = ERR_NAME_NOT_RESOLVED;
- else if (request->ResolveAsIp() || request->ServeFromCache())
- rv = request->result();
- else if (AttachToRequestList(request.get()))
- rv = ERR_IO_PENDING;
- else if (dns_transactions_.size() < max_dns_transactions_)
- rv = StartNewDnsRequestFor(request.get());
- else
- rv = Enqueue(request.get());
-
- if (rv != ERR_IO_PENDING) {
- request->OnSyncComplete(rv);
- } else {
- Request* req = request.release();
- if (out_req)
- *out_req = reinterpret_cast<RequestHandle>(req);
- }
- return rv;
-}
-
-int AsyncHostResolver::ResolveFromCache(const RequestInfo& info,
- AddressList* addresses,
- const BoundNetLog& source_net_log) {
- scoped_ptr<Request> request(
- CreateNewRequest(info, CompletionCallback(), addresses, source_net_log));
- int rv = ERR_UNEXPECTED;
- if (!request->IsValid())
- rv = ERR_NAME_NOT_RESOLVED;
- else if (request->ResolveAsIp() || request->ServeFromCache())
- rv = request->result();
- else
- rv = ERR_DNS_CACHE_MISS;
- request->OnSyncComplete(rv);
- return rv;
-}
-
-void AsyncHostResolver::OnStart(Request* request) {
- DCHECK(request);
-
- request->source_net_log().BeginEvent(
- NetLog::TYPE_ASYNC_HOST_RESOLVER,
- make_scoped_refptr(new NetLogSourceParameter(
- "source_dependency", request->request_net_log().source())));
- request->request_net_log().BeginEvent(
- NetLog::TYPE_ASYNC_HOST_RESOLVER_REQUEST,
- make_scoped_refptr(new RequestParameters(
- request->info(), request->source_net_log().source())));
-}
-
-void AsyncHostResolver::OnFinish(Request* request, int result) {
- DCHECK(request);
- request->request_net_log().EndEventWithNetErrorCode(
- NetLog::TYPE_ASYNC_HOST_RESOLVER_REQUEST, result);
- request->source_net_log().EndEvent(
- NetLog::TYPE_ASYNC_HOST_RESOLVER, NULL);
-}
-
-void AsyncHostResolver::OnCancel(Request* request) {
- DCHECK(request);
-
- request->request_net_log().AddEvent(
- NetLog::TYPE_CANCELLED, NULL);
- request->request_net_log().EndEvent(
- NetLog::TYPE_ASYNC_HOST_RESOLVER_REQUEST, NULL);
- request->source_net_log().EndEvent(
- NetLog::TYPE_ASYNC_HOST_RESOLVER, NULL);
-}
-
-void AsyncHostResolver::CancelRequest(RequestHandle req_handle) {
- scoped_ptr<Request> request(reinterpret_cast<Request*>(req_handle));
- DCHECK(request.get());
-
- KeyRequestListMap::iterator it = requestlist_map_.find(request->key());
- if (it != requestlist_map_.end())
- it->second.remove(request.get());
- else
- pending_requests_[request->priority()].remove(request.get());
-}
-
-void AsyncHostResolver::SetDefaultAddressFamily(
- AddressFamily address_family) {
- NOTIMPLEMENTED();
-}
-
-AddressFamily AsyncHostResolver::GetDefaultAddressFamily() const {
- return ADDRESS_FAMILY_IPV4;
-}
-
-HostCache* AsyncHostResolver::GetHostCache() {
- return cache_.get();
-}
-
-void AsyncHostResolver::OnDnsTransactionComplete(
- DnsTransaction* transaction,
- int result,
- const DnsResponse* response) {
- DCHECK(std::find(dns_transactions_.begin(),
- dns_transactions_.end(),
- transaction) != dns_transactions_.end());
-
- // If by the time requests that caused |transaction| are cancelled, we do
- // not have a port number to associate with the result, therefore, we
- // assume the most common port, otherwise we use the port number of the
- // first request.
- KeyRequestListMap::iterator rit = requestlist_map_.find(
- std::make_pair(transaction->GetHostname(), transaction->GetType()));
- DCHECK(rit != requestlist_map_.end());
- RequestList& requests = rit->second;
- int port = requests.empty() ? 80 : requests.front()->info().port();
-
- // Extract AddressList and TTL out of DnsResponse.
- AddressList addr_list;
- uint32 ttl = kuint32max;
- if (result == OK) {
- IPAddressList ip_addresses;
- DnsRecordParser parser = response->Parser();
- DnsResourceRecord record;
- // TODO(szym): Add stricter checking of names, aliases and address lengths.
- while (parser.ParseRecord(&record)) {
- if (record.type == transaction->GetType() &&
- (record.rdata.size() == kIPv4AddressSize ||
- record.rdata.size() == kIPv6AddressSize)) {
- ip_addresses.push_back(IPAddressNumber(record.rdata.begin(),
- record.rdata.end()));
- ttl = std::min(ttl, record.ttl);
- }
- }
- if (!ip_addresses.empty())
- addr_list = AddressList::CreateFromIPAddressList(ip_addresses, port);
- else
- result = ERR_NAME_NOT_RESOLVED;
- }
-
- // Run callback of every request that was depending on this DNS request,
- // also notify observers.
- for (RequestList::iterator it = requests.begin(); it != requests.end(); ++it)
- (*it)->OnAsyncComplete(result, addr_list);
-
- // It is possible that the requests that caused |transaction| to be
- // created are cancelled by the time |transaction| completes. In that
- // case |requests| would be empty. We are knowingly throwing away the
- // result of a DNS resolution in that case, because (a) if there are no
- // requests, we do not have info to obtain a key from, (b) DnsTransaction
- // does not have info().
- // TODO(szym): Should DnsTransaction ignore HostResolverFlags or use defaults?
- if ((result == OK || result == ERR_NAME_NOT_RESOLVED) && cache_.get() &&
- !requests.empty()) {
- Request* request = requests.front();
- HostResolver::RequestInfo info = request->info();
- HostCache::Key key(
- info.hostname(), info.address_family(), info.host_resolver_flags());
- // Store negative results with TTL 0 to flush out the old entry.
- cache_->Set(key,
- result,
- addr_list,
- base::TimeTicks::Now(),
- (result == OK) ? base::TimeDelta::FromSeconds(ttl)
- : base::TimeDelta());
- }
-
- // Cleanup requests.
- STLDeleteElements(&requests);
- requestlist_map_.erase(rit);
-
- // Cleanup |transaction| and start a new one if there are pending requests.
- dns_transactions_.remove(transaction);
- delete transaction;
- ProcessPending();
-}
-
-AsyncHostResolver::Request* AsyncHostResolver::CreateNewRequest(
- const RequestInfo& info,
- const CompletionCallback& callback,
- AddressList* addresses,
- const BoundNetLog& source_net_log) {
- BoundNetLog request_net_log = BoundNetLog::Make(net_log_,
- NetLog::SOURCE_ASYNC_HOST_RESOLVER_REQUEST);
- return new Request(
- this, source_net_log, request_net_log, info, callback, addresses);
-}
-
-bool AsyncHostResolver::AttachToRequestList(Request* request) {
- KeyRequestListMap::iterator it = requestlist_map_.find(request->key());
- if (it == requestlist_map_.end())
- return false;
- it->second.push_back(request);
- return true;
-}
-
-int AsyncHostResolver::StartNewDnsRequestFor(Request* request) {
- DCHECK(requestlist_map_.find(request->key()) == requestlist_map_.end());
- DCHECK(dns_transactions_.size() < max_dns_transactions_);
-
- request->request_net_log().AddEvent(
- NetLog::TYPE_ASYNC_HOST_RESOLVER_CREATE_DNS_TRANSACTION, NULL);
-
- requestlist_map_[request->key()].push_back(request);
- scoped_ptr<DnsTransaction> transaction(client_->CreateTransaction(
- request->key().first,
- request->key().second,
- base::Bind(&AsyncHostResolver::OnDnsTransactionComplete,
- base::Unretained(this)),
- request->request_net_log()));
- int rv = transaction->Start();
- if (rv == ERR_IO_PENDING)
- dns_transactions_.push_back(transaction.release());
- return rv;
-}
-
-int AsyncHostResolver::Enqueue(Request* request) {
- Request* evicted_request = Insert(request);
- int rv = ERR_HOST_RESOLVER_QUEUE_TOO_LARGE;
- if (evicted_request == request)
- return rv;
- if (evicted_request != NULL) {
- evicted_request->OnAsyncComplete(rv, AddressList());
- delete evicted_request;
- }
- return ERR_IO_PENDING;
-}
-
-AsyncHostResolver::Request* AsyncHostResolver::Insert(Request* request) {
- pending_requests_[request->priority()].push_back(request);
- if (GetNumPending() > max_pending_requests_) {
- Request* req = RemoveLowest();
- DCHECK(req);
- return req;
- }
- return NULL;
-}
-
-size_t AsyncHostResolver::GetNumPending() const {
- size_t num_pending = 0;
- for (size_t i = 0; i < arraysize(pending_requests_); ++i)
- num_pending += pending_requests_[i].size();
- return num_pending;
-}
-
-AsyncHostResolver::Request* AsyncHostResolver::RemoveLowest() {
- for (int i = static_cast<int>(arraysize(pending_requests_)) - 1;
- i >= 0; --i) {
- RequestList& requests = pending_requests_[i];
- if (!requests.empty()) {
- Request* request = requests.front();
- requests.pop_front();
- return request;
- }
- }
- return NULL;
-}
-
-AsyncHostResolver::Request* AsyncHostResolver::RemoveHighest() {
- for (size_t i = 0; i < arraysize(pending_requests_) - 1; ++i) {
- RequestList& requests = pending_requests_[i];
- if (!requests.empty()) {
- Request* request = requests.front();
- requests.pop_front();
- return request;
- }
- }
- return NULL;
-}
-
-void AsyncHostResolver::ProcessPending() {
- Request* request = RemoveHighest();
- if (!request)
- return;
- for (size_t i = 0; i < arraysize(pending_requests_); ++i) {
- RequestList& requests = pending_requests_[i];
- RequestList::iterator it = requests.begin();
- while (it != requests.end()) {
- if (request->key() == (*it)->key()) {
- requestlist_map_[request->key()].push_back(*it);
- it = requests.erase(it);
- } else {
- ++it;
- }
- }
- }
- StartNewDnsRequestFor(request);
-}
-
-} // namespace net
« no previous file with comments | « net/dns/async_host_resolver.h ('k') | net/dns/async_host_resolver_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698