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 |