summaryrefslogtreecommitdiffstats
path: root/net/dns
diff options
context:
space:
mode:
authorszym@chromium.org <szym@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-02-21 21:23:20 +0000
committerszym@chromium.org <szym@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-02-21 21:23:20 +0000
commitb3601bc27df66f4e58086defc5788fc6365e4601 (patch)
tree1a938a765e1386e784ff726c580cfa93502727c4 /net/dns
parentad48b7fbd53d9180b5b917dbf9142b7bd6fa6fa6 (diff)
downloadchromium_src-b3601bc27df66f4e58086defc5788fc6365e4601.zip
chromium_src-b3601bc27df66f4e58086defc5788fc6365e4601.tar.gz
chromium_src-b3601bc27df66f4e58086defc5788fc6365e4601.tar.bz2
[net] Asynchronous DNS ready for experiments.
If started with --enable-async-dns, HostResolverImpl will use DnsConfigService to determine system DNS configuration and DnsTransaction to resolve host names. It will fallback to HostResolverProc on failure. BUG=90881, 107880, 113829 TEST=./net_unittests --gtest_filter=HostResolverImpl*:Dns* Review URL: http://codereview.chromium.org/9369045 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@122878 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'net/dns')
-rw-r--r--net/dns/async_host_resolver.cc524
-rw-r--r--net/dns/async_host_resolver.h138
-rw-r--r--net/dns/async_host_resolver_unittest.cc544
-rw-r--r--net/dns/dns_config_service.h4
-rw-r--r--net/dns/dns_config_service_posix.cc4
-rw-r--r--net/dns/dns_config_service_posix_unittest.cc2
-rw-r--r--net/dns/dns_config_service_win.cc13
-rw-r--r--net/dns/dns_response.cc84
-rw-r--r--net/dns/dns_response.h28
-rw-r--r--net/dns/dns_response_unittest.cc272
-rw-r--r--net/dns/dns_session.h4
-rw-r--r--net/dns/dns_test_util.h43
-rw-r--r--net/dns/dns_transaction.cc47
-rw-r--r--net/dns/dns_transaction.h4
-rw-r--r--net/dns/dns_transaction_unittest.cc19
15 files changed, 417 insertions, 1313 deletions
diff --git a/net/dns/async_host_resolver.cc b/net/dns/async_host_resolver.cc
deleted file mode 100644
index 72e5472..0000000
--- 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
diff --git a/net/dns/async_host_resolver.h b/net/dns/async_host_resolver.h
deleted file mode 100644
index 23d9808..0000000
--- a/net/dns/async_host_resolver.h
+++ /dev/null
@@ -1,138 +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.
-
-#ifndef NET_DNS_ASYNC_HOST_RESOLVER_H_
-#define NET_DNS_ASYNC_HOST_RESOLVER_H_
-#pragma once
-
-#include <list>
-#include <map>
-#include <string>
-#include <utility>
-
-#include "base/threading/non_thread_safe.h"
-#include "net/base/address_family.h"
-#include "net/base/host_cache.h"
-#include "net/base/host_resolver.h"
-#include "net/base/ip_endpoint.h"
-#include "net/base/net_log.h"
-#include "net/dns/dns_transaction.h"
-
-namespace net {
-
-class NET_EXPORT AsyncHostResolver
- : public HostResolver,
- NON_EXPORTED_BASE(public base::NonThreadSafe) {
- public:
- AsyncHostResolver(size_t max_dns_requests,
- size_t max_pending_requests,
- HostCache* cache,
- scoped_ptr<DnsTransactionFactory> client,
- NetLog* net_log);
- virtual ~AsyncHostResolver();
-
- // HostResolver interface
- virtual int Resolve(const RequestInfo& info,
- AddressList* addresses,
- const CompletionCallback& callback,
- RequestHandle* out_req,
- const BoundNetLog& source_net_log) OVERRIDE;
- virtual int ResolveFromCache(const RequestInfo& info,
- AddressList* addresses,
- const BoundNetLog& source_net_log) OVERRIDE;
- virtual void CancelRequest(RequestHandle req_handle) OVERRIDE;
- virtual void SetDefaultAddressFamily(AddressFamily address_family) OVERRIDE;
- virtual AddressFamily GetDefaultAddressFamily() const OVERRIDE;
- virtual HostCache* GetHostCache() OVERRIDE;
-
- void OnDnsTransactionComplete(DnsTransaction* transaction,
- int result,
- const DnsResponse* response);
-
- private:
- FRIEND_TEST_ALL_PREFIXES(AsyncHostResolverTest, QueuedLookup);
- FRIEND_TEST_ALL_PREFIXES(AsyncHostResolverTest, CancelPendingLookup);
- FRIEND_TEST_ALL_PREFIXES(AsyncHostResolverTest,
- ResolverDestructionCancelsLookups);
- FRIEND_TEST_ALL_PREFIXES(AsyncHostResolverTest,
- OverflowQueueWithLowPriorityLookup);
- FRIEND_TEST_ALL_PREFIXES(AsyncHostResolverTest,
- OverflowQueueWithHighPriorityLookup);
-
- class Request;
-
- typedef std::pair<std::string, uint16> Key;
- typedef std::list<Request*> RequestList;
- typedef std::list<const DnsTransaction*> DnsTransactionList;
- typedef std::map<Key, RequestList> KeyRequestListMap;
-
- // Create a new request for the incoming Resolve() call.
- Request* CreateNewRequest(const RequestInfo& info,
- const CompletionCallback& callback,
- AddressList* addresses,
- const BoundNetLog& source_net_log);
-
- // Called when a request has just been started.
- void OnStart(Request* request);
-
- // Called when a request has just completed (before its callback is run).
- void OnFinish(Request* request, int result);
-
- // Called when a request has been cancelled.
- void OnCancel(Request* request);
-
- // If there is an in-progress transaction for Request->key(), this will
- // attach |request| to the respective list.
- bool AttachToRequestList(Request* request);
-
- // Will start a new DNS request for |request|, will insert a new key in
- // |requestlist_map_| and append |request| to the respective list.
- int StartNewDnsRequestFor(Request* request);
-
- // Will enqueue |request| in |pending_requests_|.
- int Enqueue(Request* request);
-
- // A helper used by Enqueue to insert |request| into |pending_requests_|.
- Request* Insert(Request* request);
-
- // Returns the number of pending requests.
- size_t GetNumPending() const;
-
- // Removes and returns a pointer to the lowest/highest priority request
- // from |pending_requests_|.
- Request* RemoveLowest();
- Request* RemoveHighest();
-
- // Once a transaction has completed, called to start a new transaction if
- // there are pending requests.
- void ProcessPending();
-
- // Maximum number of concurrent DNS transactions.
- size_t max_dns_transactions_;
-
- // List of current DNS transactions.
- DnsTransactionList dns_transactions_;
-
- // A map from Key to a list of requests waiting for the Key to resolve.
- KeyRequestListMap requestlist_map_;
-
- // Maximum number of pending requests.
- size_t max_pending_requests_;
-
- // Queues based on priority for putting pending requests.
- RequestList pending_requests_[NUM_PRIORITIES];
-
- // Cache of host resolution results.
- scoped_ptr<HostCache> cache_;
-
- scoped_ptr<DnsTransactionFactory> client_;
-
- NetLog* net_log_;
-
- DISALLOW_COPY_AND_ASSIGN(AsyncHostResolver);
-};
-
-} // namespace net
-
-#endif // NET_DNS_ASYNC_HOST_RESOLVER_H_
diff --git a/net/dns/async_host_resolver_unittest.cc b/net/dns/async_host_resolver_unittest.cc
deleted file mode 100644
index be57d49..0000000
--- a/net/dns/async_host_resolver_unittest.cc
+++ /dev/null
@@ -1,544 +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 "base/bind.h"
-#include "base/memory/scoped_ptr.h"
-#include "base/message_loop.h"
-#include "base/stl_util.h"
-#include "net/base/host_cache.h"
-#include "net/base/net_errors.h"
-#include "net/base/net_log.h"
-#include "net/base/sys_addrinfo.h"
-#include "net/base/test_completion_callback.h"
-#include "net/dns/dns_query.h"
-#include "net/dns/dns_response.h"
-#include "net/dns/dns_test_util.h"
-#include "net/dns/dns_transaction.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace net {
-
-namespace {
-
-const int kPortNum = 80;
-const size_t kMaxTransactions = 2;
-const size_t kMaxPendingRequests = 1;
-
-void VerifyAddressList(const std::vector<const char*>& ip_addresses,
- int port,
- const AddressList& addrlist) {
- ASSERT_LT(0u, ip_addresses.size());
- ASSERT_NE(static_cast<addrinfo*>(NULL), addrlist.head());
-
- IPAddressNumber ip_number;
- const struct addrinfo* ainfo = addrlist.head();
- for (std::vector<const char*>::const_iterator i = ip_addresses.begin();
- i != ip_addresses.end(); ++i, ainfo = ainfo->ai_next) {
- ASSERT_NE(static_cast<addrinfo*>(NULL), ainfo);
- EXPECT_EQ(sizeof(struct sockaddr_in),
- static_cast<size_t>(ainfo->ai_addrlen));
-
- const struct sockaddr* sa = ainfo->ai_addr;
- const struct sockaddr_in* sa_in = (const struct sockaddr_in*) sa;
- EXPECT_TRUE(htons(port) == sa_in->sin_port);
- EXPECT_STREQ(*i, NetAddressToString(sa, ainfo->ai_addrlen).c_str());
- }
- ASSERT_EQ(static_cast<addrinfo*>(NULL), ainfo);
-}
-
-class MockTransactionFactory : public DnsTransactionFactory,
- public base::SupportsWeakPtr<MockTransactionFactory> {
- public:
- // Using WeakPtr to support cancellation. All MockTransactions succeed unless
- // cancelled or MockTransactionFactory is destroyed.
- class MockTransaction : public DnsTransaction,
- public base::SupportsWeakPtr<MockTransaction> {
- public:
- MockTransaction(const std::string& hostname,
- uint16 qtype,
- const DnsTransactionFactory::CallbackType& callback,
- const base::WeakPtr<MockTransactionFactory>& factory)
- : hostname_(hostname),
- qtype_(qtype),
- callback_(callback),
- started_(false),
- factory_(factory) {
- EXPECT_FALSE(started_);
- started_ = true;
- MessageLoop::current()->PostTask(
- FROM_HERE,
- base::Bind(&MockTransaction::Finish, AsWeakPtr()));
- }
-
- virtual const std::string& GetHostname() const OVERRIDE {
- return hostname_;
- }
-
- virtual uint16 GetType() const OVERRIDE {
- return qtype_;
- }
-
- virtual int Start() OVERRIDE {
- return ERR_IO_PENDING;
- }
-
- private:
- void Finish() {
- if (!factory_) {
- callback_.Run(this, ERR_DNS_SERVER_FAILED, NULL);
- return;
- }
- callback_.Run(this,
- OK,
- factory_->responses_[Key(GetHostname(), GetType())]);
- }
-
- const std::string hostname_;
- const uint16 qtype_;
- DnsTransactionFactory::CallbackType callback_;
- bool started_;
- const base::WeakPtr<MockTransactionFactory> factory_;
- };
-
- typedef std::pair<std::string, uint16> Key;
-
- MockTransactionFactory() : num_requests_(0) {}
- ~MockTransactionFactory() {
- STLDeleteValues(&responses_);
- }
-
- scoped_ptr<DnsTransaction> CreateTransaction(
- const std::string& qname,
- uint16 qtype,
- const DnsTransactionFactory::CallbackType& callback,
- const BoundNetLog&) {
- ++num_requests_;
- return scoped_ptr<DnsTransaction>(
- new MockTransaction(qname, qtype, callback, AsWeakPtr()));
- }
-
- void AddResponse(const std::string& name, uint8 type, DnsResponse* response) {
- responses_[MockTransactionFactory::Key(name, type)] = response;
- }
-
- int num_requests() const { return num_requests_; }
-
- private:
- int num_requests_;
- std::map<Key, DnsResponse*> responses_;
-};
-
-} // namespace
-
-
-// The following fixture sets up an environment for four different lookups
-// with their data defined in dns_test_util.h. All tests make use of these
-// predefined variables instead of each defining their own, to avoid
-// boilerplate code in every test. Assuming every coming query is for a
-// distinct hostname, as |kMaxTransactions| is set to 2 and
-// |kMaxPendingRequests| is set to 1, first two queries start immediately
-// and the next one is sent to pending queue; as a result, the next query
-// should either fail itself or cause the pending query to fail depending
-// on its priority.
-class AsyncHostResolverTest : public testing::Test {
- public:
- AsyncHostResolverTest()
- : info0_(HostPortPair(kT0HostName, kPortNum)),
- info1_(HostPortPair(kT1HostName, kPortNum)),
- info2_(HostPortPair(kT2HostName, kPortNum)),
- info3_(HostPortPair(kT3HostName, kPortNum)),
- ip_addresses0_(kT0IpAddresses,
- kT0IpAddresses + arraysize(kT0IpAddresses)),
- ip_addresses1_(kT1IpAddresses,
- kT1IpAddresses + arraysize(kT1IpAddresses)),
- ip_addresses2_(kT2IpAddresses,
- kT2IpAddresses + arraysize(kT2IpAddresses)),
- ip_addresses3_(kT3IpAddresses,
- kT3IpAddresses + arraysize(kT3IpAddresses)) {
- // AF_INET only for now.
- info0_.set_address_family(ADDRESS_FAMILY_IPV4);
- info1_.set_address_family(ADDRESS_FAMILY_IPV4);
- info2_.set_address_family(ADDRESS_FAMILY_IPV4);
- info3_.set_address_family(ADDRESS_FAMILY_IPV4);
-
- client_ = new MockTransactionFactory();
-
- client_->AddResponse(kT0HostName, kT0Qtype,
- new DnsResponse(reinterpret_cast<const char*>(kT0ResponseDatagram),
- arraysize(kT0ResponseDatagram),
- arraysize(kT0QueryDatagram)));
-
- client_->AddResponse(kT1HostName, kT1Qtype,
- new DnsResponse(reinterpret_cast<const char*>(kT1ResponseDatagram),
- arraysize(kT1ResponseDatagram),
- arraysize(kT1QueryDatagram)));
-
- client_->AddResponse(kT2HostName, kT2Qtype,
- new DnsResponse(reinterpret_cast<const char*>(kT2ResponseDatagram),
- arraysize(kT2ResponseDatagram),
- arraysize(kT2QueryDatagram)));
-
- client_->AddResponse(kT3HostName, kT3Qtype,
- new DnsResponse(reinterpret_cast<const char*>(kT3ResponseDatagram),
- arraysize(kT3ResponseDatagram),
- arraysize(kT3QueryDatagram)));
-
- resolver_.reset(
- new AsyncHostResolver(kMaxTransactions, kMaxPendingRequests,
- HostCache::CreateDefaultCache(),
- scoped_ptr<DnsTransactionFactory>(client_), NULL));
- }
-
- protected:
- AddressList addrlist0_, addrlist1_, addrlist2_, addrlist3_;
- HostResolver::RequestInfo info0_, info1_, info2_, info3_;
- std::vector<const char*> ip_addresses0_, ip_addresses1_,
- ip_addresses2_, ip_addresses3_;
- scoped_ptr<HostResolver> resolver_;
- MockTransactionFactory* client_; // Owned by the AsyncHostResolver.
- TestCompletionCallback callback0_, callback1_, callback2_, callback3_;
-};
-
-TEST_F(AsyncHostResolverTest, EmptyHostLookup) {
- info0_.set_host_port_pair(HostPortPair("", kPortNum));
- int rv = resolver_->Resolve(info0_, &addrlist0_, callback0_.callback(), NULL,
- BoundNetLog());
- EXPECT_EQ(ERR_NAME_NOT_RESOLVED, rv);
-}
-
-TEST_F(AsyncHostResolverTest, IPv4LiteralLookup) {
- const char* kIPLiteral = "192.168.1.2";
- info0_.set_host_port_pair(HostPortPair(kIPLiteral, kPortNum));
- info0_.set_host_resolver_flags(HOST_RESOLVER_CANONNAME);
- int rv = resolver_->Resolve(info0_, &addrlist0_, callback0_.callback(), NULL,
- BoundNetLog());
- EXPECT_EQ(OK, rv);
- std::vector<const char*> ip_addresses(1, kIPLiteral);
- VerifyAddressList(ip_addresses, kPortNum, addrlist0_);
- EXPECT_STREQ(kIPLiteral, addrlist0_.head()->ai_canonname);
-}
-
-TEST_F(AsyncHostResolverTest, IPv6LiteralLookup) {
- info0_.set_host_port_pair(HostPortPair("2001:db8:0::42", kPortNum));
- int rv = resolver_->Resolve(info0_, &addrlist0_, callback0_.callback(), NULL,
- BoundNetLog());
- // When support for IPv6 is added, this should succeed.
- EXPECT_EQ(ERR_NAME_NOT_RESOLVED, rv);
-}
-
-TEST_F(AsyncHostResolverTest, CachedLookup) {
- int rv = resolver_->ResolveFromCache(info0_, &addrlist0_, BoundNetLog());
- EXPECT_EQ(ERR_DNS_CACHE_MISS, rv);
-
- // Cache the result of |info0_| lookup.
- rv = resolver_->Resolve(info0_, &addrlist0_, callback0_.callback(), NULL,
- BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
- rv = callback0_.WaitForResult();
- EXPECT_EQ(OK, rv);
- VerifyAddressList(ip_addresses0_, kPortNum, addrlist0_);
-
- // Now lookup |info0_| from cache only, store results in |addrlist1_|,
- // should succeed synchronously.
- rv = resolver_->ResolveFromCache(info0_, &addrlist1_, BoundNetLog());
- EXPECT_EQ(OK, rv);
- VerifyAddressList(ip_addresses0_, kPortNum, addrlist1_);
-}
-
-// TODO(szym): This tests DnsTransaction not AsyncHostResolver. Remove or move
-// to dns_transaction_unittest.cc
-TEST_F(AsyncHostResolverTest, DISABLED_InvalidHostNameLookup) {
- const std::string kHostName1(64, 'a');
- info0_.set_host_port_pair(HostPortPair(kHostName1, kPortNum));
- int rv = resolver_->Resolve(info0_, &addrlist0_, callback0_.callback(), NULL,
- BoundNetLog());
- EXPECT_EQ(ERR_INVALID_ARGUMENT, rv);
-
- const std::string kHostName2(4097, 'b');
- info0_.set_host_port_pair(HostPortPair(kHostName2, kPortNum));
- rv = resolver_->Resolve(info0_, &addrlist0_, callback0_.callback(), NULL,
- BoundNetLog());
- EXPECT_EQ(ERR_INVALID_ARGUMENT, rv);
-}
-
-TEST_F(AsyncHostResolverTest, Lookup) {
- int rv = resolver_->Resolve(info0_, &addrlist0_, callback0_.callback(), NULL,
- BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
- rv = callback0_.WaitForResult();
- EXPECT_EQ(OK, rv);
- VerifyAddressList(ip_addresses0_, kPortNum, addrlist0_);
-}
-
-TEST_F(AsyncHostResolverTest, ConcurrentLookup) {
- int rv0 = resolver_->Resolve(info0_, &addrlist0_, callback0_.callback(), NULL,
- BoundNetLog());
- int rv1 = resolver_->Resolve(info1_, &addrlist1_, callback1_.callback(), NULL,
- BoundNetLog());
- int rv2 = resolver_->Resolve(info2_, &addrlist2_, callback2_.callback(), NULL,
- BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv0);
- EXPECT_EQ(ERR_IO_PENDING, rv1);
- EXPECT_EQ(ERR_IO_PENDING, rv2);
-
- rv0 = callback0_.WaitForResult();
- EXPECT_EQ(OK, rv0);
- VerifyAddressList(ip_addresses0_, kPortNum, addrlist0_);
-
- rv1 = callback1_.WaitForResult();
- EXPECT_EQ(OK, rv1);
- VerifyAddressList(ip_addresses1_, kPortNum, addrlist1_);
-
- rv2 = callback2_.WaitForResult();
- EXPECT_EQ(OK, rv2);
- VerifyAddressList(ip_addresses2_, kPortNum, addrlist2_);
-
- EXPECT_EQ(3, client_->num_requests());
-}
-
-TEST_F(AsyncHostResolverTest, SameHostLookupsConsumeSingleTransaction) {
- // We pass the info0_ to all requests.
- int rv0 = resolver_->Resolve(info0_, &addrlist0_, callback0_.callback(), NULL,
- BoundNetLog());
- int rv1 = resolver_->Resolve(info0_, &addrlist1_, callback1_.callback(), NULL,
- BoundNetLog());
- int rv2 = resolver_->Resolve(info0_, &addrlist2_, callback2_.callback(), NULL,
- BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv0);
- EXPECT_EQ(ERR_IO_PENDING, rv1);
- EXPECT_EQ(ERR_IO_PENDING, rv2);
-
- rv0 = callback0_.WaitForResult();
- EXPECT_EQ(OK, rv0);
- VerifyAddressList(ip_addresses0_, kPortNum, addrlist0_);
-
- rv1 = callback1_.WaitForResult();
- EXPECT_EQ(OK, rv1);
- VerifyAddressList(ip_addresses0_, kPortNum, addrlist1_);
-
- rv2 = callback2_.WaitForResult();
- EXPECT_EQ(OK, rv2);
- VerifyAddressList(ip_addresses0_, kPortNum, addrlist2_);
-
- // Although we have three lookups, a single UDP socket was used.
- EXPECT_EQ(1, client_->num_requests());
-}
-
-TEST_F(AsyncHostResolverTest, CancelLookup) {
- HostResolver::RequestHandle req0 = NULL, req2 = NULL;
- int rv0 = resolver_->Resolve(info0_, &addrlist0_, callback0_.callback(),
- &req0, BoundNetLog());
- int rv1 = resolver_->Resolve(info1_, &addrlist1_, callback1_.callback(), NULL,
- BoundNetLog());
- int rv2 = resolver_->Resolve(info2_, &addrlist2_, callback2_.callback(),
- &req2, BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv0);
- EXPECT_EQ(ERR_IO_PENDING, rv1);
- EXPECT_EQ(ERR_IO_PENDING, rv2);
-
- resolver_->CancelRequest(req0);
- resolver_->CancelRequest(req2);
-
- MessageLoop::current()->RunAllPending();
-
- EXPECT_FALSE(callback0_.have_result());
- EXPECT_FALSE(callback2_.have_result());
-
- rv1 = callback1_.WaitForResult();
- EXPECT_EQ(OK, rv1);
- VerifyAddressList(ip_addresses1_, kPortNum, addrlist1_);
-}
-
-// Tests the following scenario: start two resolutions for the same host,
-// cancel one of them, make sure that the other one completes.
-TEST_F(AsyncHostResolverTest, CancelSameHostLookup) {
- HostResolver::RequestHandle req0 = NULL;
-
- // Pass the info0_ to both requests.
- int rv0 = resolver_->Resolve(info0_, &addrlist0_, callback0_.callback(),
- &req0, BoundNetLog());
- int rv1 = resolver_->Resolve(info0_, &addrlist1_, callback1_.callback(), NULL,
- BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv0);
- EXPECT_EQ(ERR_IO_PENDING, rv1);
-
- resolver_->CancelRequest(req0);
- MessageLoop::current()->RunAllPending();
- EXPECT_FALSE(callback0_.have_result());
-
- rv1 = callback1_.WaitForResult();
- EXPECT_EQ(OK, rv1);
- VerifyAddressList(ip_addresses0_, kPortNum, addrlist1_);
-
- EXPECT_EQ(1, client_->num_requests());
-}
-
-// Test that a queued lookup completes.
-TEST_F(AsyncHostResolverTest, QueuedLookup) {
- // kMaxTransactions is 2, thus the following requests consume all
- // available transactions.
- int rv0 = resolver_->Resolve(info0_, &addrlist0_, callback0_.callback(), NULL,
- BoundNetLog());
- int rv1 = resolver_->Resolve(info1_, &addrlist1_, callback1_.callback(), NULL,
- BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv0);
- EXPECT_EQ(ERR_IO_PENDING, rv1);
-
- // The following request will end up in queue.
- int rv2 = resolver_->Resolve(info2_, &addrlist2_, callback2_.callback(), NULL,
- BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv2);
- EXPECT_EQ(1u,
- static_cast<AsyncHostResolver*>(resolver_.get())->GetNumPending());
-
- // Make sure all requests complete.
- rv0 = callback0_.WaitForResult();
- EXPECT_EQ(OK, rv0);
- VerifyAddressList(ip_addresses0_, kPortNum, addrlist0_);
-
- rv1 = callback1_.WaitForResult();
- EXPECT_EQ(OK, rv1);
- VerifyAddressList(ip_addresses1_, kPortNum, addrlist1_);
-
- rv2 = callback2_.WaitForResult();
- EXPECT_EQ(OK, rv2);
- VerifyAddressList(ip_addresses2_, kPortNum, addrlist2_);
-}
-
-// Test that cancelling a queued lookup works.
-TEST_F(AsyncHostResolverTest, CancelPendingLookup) {
- // kMaxTransactions is 2, thus the following requests consume all
- // available transactions.
- int rv0 = resolver_->Resolve(info0_, &addrlist0_, callback0_.callback(), NULL,
- BoundNetLog());
- int rv1 = resolver_->Resolve(info1_, &addrlist1_, callback1_.callback(), NULL,
- BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv0);
- EXPECT_EQ(ERR_IO_PENDING, rv1);
-
- // The following request will end up in queue.
- HostResolver::RequestHandle req2 = NULL;
- int rv2 = resolver_->Resolve(info2_, &addrlist2_, callback2_.callback(),
- &req2, BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv2);
- EXPECT_EQ(1u,
- static_cast<AsyncHostResolver*>(resolver_.get())->GetNumPending());
-
- resolver_->CancelRequest(req2);
-
- // Make sure first two requests complete while the cancelled one doesn't.
- MessageLoop::current()->RunAllPending();
- EXPECT_FALSE(callback2_.have_result());
-
- rv0 = callback0_.WaitForResult();
- EXPECT_EQ(OK, rv0);
- VerifyAddressList(ip_addresses0_, kPortNum, addrlist0_);
-
- rv1 = callback1_.WaitForResult();
- EXPECT_EQ(OK, rv1);
- VerifyAddressList(ip_addresses1_, kPortNum, addrlist1_);
-}
-
-TEST_F(AsyncHostResolverTest, ResolverDestructionCancelsLookups) {
- int rv0 = resolver_->Resolve(info0_, &addrlist0_, callback0_.callback(), NULL,
- BoundNetLog());
- int rv1 = resolver_->Resolve(info1_, &addrlist1_, callback1_.callback(), NULL,
- BoundNetLog());
- // This one is queued.
- int rv2 = resolver_->Resolve(info2_, &addrlist2_, callback2_.callback(), NULL,
- BoundNetLog());
- EXPECT_EQ(1u,
- static_cast<AsyncHostResolver*>(resolver_.get())->GetNumPending());
-
- EXPECT_EQ(ERR_IO_PENDING, rv0);
- EXPECT_EQ(ERR_IO_PENDING, rv1);
- EXPECT_EQ(ERR_IO_PENDING, rv2);
-
- resolver_.reset();
-
- MessageLoop::current()->RunAllPending();
-
- EXPECT_FALSE(callback0_.have_result());
- EXPECT_FALSE(callback1_.have_result());
- EXPECT_FALSE(callback2_.have_result());
-}
-
-// Test that when the number of pending lookups is at max, a new lookup
-// with a priority lower than all of those in the queue fails.
-TEST_F(AsyncHostResolverTest, OverflowQueueWithLowPriorityLookup) {
- int rv0 = resolver_->Resolve(info0_, &addrlist0_, callback0_.callback(), NULL,
- BoundNetLog());
- int rv1 = resolver_->Resolve(info1_, &addrlist1_, callback1_.callback(), NULL,
- BoundNetLog());
- // This one is queued and fills up the queue since its size is 1.
- int rv2 = resolver_->Resolve(info2_, &addrlist2_, callback2_.callback(), NULL,
- BoundNetLog());
- EXPECT_EQ(1u,
- static_cast<AsyncHostResolver*>(resolver_.get())->GetNumPending());
-
- EXPECT_EQ(ERR_IO_PENDING, rv0);
- EXPECT_EQ(ERR_IO_PENDING, rv1);
- EXPECT_EQ(ERR_IO_PENDING, rv2);
-
- // This one fails.
- info3_.set_priority(LOWEST);
- int rv3 = resolver_->Resolve(info3_, &addrlist3_, callback3_.callback(), NULL,
- BoundNetLog());
- EXPECT_EQ(ERR_HOST_RESOLVER_QUEUE_TOO_LARGE, rv3);
-
- MessageLoop::current()->RunAllPending();
- EXPECT_FALSE(callback3_.have_result());
-}
-
-// Test that when the number of pending lookups is at max, a new lookup
-// with a priority higher than any of those in the queue succeeds and
-// causes the lowest priority lookup in the queue to fail.
-TEST_F(AsyncHostResolverTest, OverflowQueueWithHighPriorityLookup) {
- int rv0 = resolver_->Resolve(info0_, &addrlist0_, callback0_.callback(), NULL,
- BoundNetLog());
- int rv1 = resolver_->Resolve(info1_, &addrlist1_, callback1_.callback(), NULL,
- BoundNetLog());
-
- // Next lookup is queued. Since this will be ejected from the queue and
- // will not consume a socket from our factory, we are not passing it
- // predefined members.
- HostResolver::RequestInfo info(HostPortPair("cnn.com", 80));
- info.set_address_family(ADDRESS_FAMILY_IPV4);
- AddressList addrlist_fail;
- TestCompletionCallback callback_fail;
- int rv_fail = resolver_->Resolve(info, &addrlist_fail,
- callback_fail.callback(), NULL,
- BoundNetLog());
- EXPECT_EQ(1u,
- static_cast<AsyncHostResolver*>(resolver_.get())->GetNumPending());
-
- EXPECT_EQ(ERR_IO_PENDING, rv0);
- EXPECT_EQ(ERR_IO_PENDING, rv1);
- EXPECT_EQ(ERR_IO_PENDING, rv_fail);
-
- // Lookup 2 causes the above to fail, but itself should succeed.
- info2_.set_priority(HIGHEST);
- int rv2 = resolver_->Resolve(info2_, &addrlist2_, callback2_.callback(), NULL,
- BoundNetLog());
-
- rv0 = callback0_.WaitForResult();
- EXPECT_EQ(OK, rv0);
- VerifyAddressList(ip_addresses0_, kPortNum, addrlist0_);
-
- rv1 = callback1_.WaitForResult();
- EXPECT_EQ(OK, rv1);
- VerifyAddressList(ip_addresses1_, kPortNum, addrlist1_);
-
- rv_fail = callback_fail.WaitForResult();
- EXPECT_EQ(ERR_HOST_RESOLVER_QUEUE_TOO_LARGE, rv_fail);
- EXPECT_EQ(static_cast<addrinfo*>(NULL), addrlist_fail.head());
-
- rv2 = callback2_.WaitForResult();
- EXPECT_EQ(OK, rv2);
- VerifyAddressList(ip_addresses2_, kPortNum, addrlist2_);
-}
-
-} // namespace net
diff --git a/net/dns/dns_config_service.h b/net/dns/dns_config_service.h
index b3e151f..51e26b3 100644
--- a/net/dns/dns_config_service.h
+++ b/net/dns/dns_config_service.h
@@ -12,6 +12,7 @@
#include "base/file_path.h"
#include "base/gtest_prod_util.h"
+#include "base/memory/scoped_ptr.h"
#include "base/observer_list.h"
#include "base/threading/non_thread_safe.h"
#include "base/time.h"
@@ -64,6 +65,7 @@ struct NET_EXPORT_PRIVATE DnsConfig {
// Service for watching when the system DNS settings have changed.
// Depending on the platform, watches files in /etc/ or win registry.
+// This class also serves as the do-nothing mock implementation.
class NET_EXPORT_PRIVATE DnsConfigService
: NON_EXPORTED_BASE(public base::NonThreadSafe) {
public:
@@ -78,7 +80,7 @@ class NET_EXPORT_PRIVATE DnsConfigService
};
// Creates the platform-specific DnsConfigService.
- static DnsConfigService* CreateSystemService();
+ static scoped_ptr<DnsConfigService> CreateSystemService();
DnsConfigService();
virtual ~DnsConfigService();
diff --git a/net/dns/dns_config_service_posix.cc b/net/dns/dns_config_service_posix.cc
index 18a69cc..67df4e9 100644
--- a/net/dns/dns_config_service_posix.cc
+++ b/net/dns/dns_config_service_posix.cc
@@ -84,8 +84,8 @@ void DnsConfigServicePosix::Watch() {
}
// static
-DnsConfigService* DnsConfigService::CreateSystemService() {
- return new DnsConfigServicePosix();
+scoped_ptr<DnsConfigService> DnsConfigService::CreateSystemService() {
+ return scoped_ptr<DnsConfigService>(new DnsConfigServicePosix());
}
#if !defined(OS_ANDROID)
diff --git a/net/dns/dns_config_service_posix_unittest.cc b/net/dns/dns_config_service_posix_unittest.cc
index 58c71ac..f1ff015 100644
--- a/net/dns/dns_config_service_posix_unittest.cc
+++ b/net/dns/dns_config_service_posix_unittest.cc
@@ -110,7 +110,7 @@ void CloseResState(res_state res) {
} // namespace
-TEST(DnsConfigTest, ResolverConfigConvertAndEquals) {
+TEST(DnsConfigServicePosixTest, ConvertResStateToDnsConfig) {
struct __res_state res[2];
DnsConfig config[2];
for (unsigned i = 0; i < 2; ++i) {
diff --git a/net/dns/dns_config_service_win.cc b/net/dns/dns_config_service_win.cc
index d4a615f..14bb773 100644
--- a/net/dns/dns_config_service_win.cc
+++ b/net/dns/dns_config_service_win.cc
@@ -307,9 +307,6 @@ class DnsConfigServiceWin::ConfigReader : public SerialWorker {
bool StartWatch() {
DCHECK(loop()->BelongsToCurrentThread());
- // This is done only once per lifetime so open the keys on this thread.
- base::ThreadRestrictions::ScopedAllowIO allow_io;
-
base::Closure callback = base::Bind(&SerialWorker::WorkNow,
base::Unretained(this));
@@ -448,6 +445,12 @@ DnsConfigServiceWin::~DnsConfigServiceWin() {
void DnsConfigServiceWin::Watch() {
DCHECK(CalledOnValidThread());
+
+ // This is done only once per lifetime so open the keys and file watcher
+ // handles on this thread.
+ // TODO(szym): Should/can this be avoided? http://crbug.com/114223
+ base::ThreadRestrictions::ScopedAllowIO allow_io;
+
bool started = config_reader_->StartWatch();
// TODO(szym): handle possible failure
DCHECK(started);
@@ -461,8 +464,8 @@ void DnsConfigServiceWin::Watch() {
}
// static
-DnsConfigService* DnsConfigService::CreateSystemService() {
- return new DnsConfigServiceWin();
+scoped_ptr<DnsConfigService> DnsConfigService::CreateSystemService() {
+ return scoped_ptr<DnsConfigService>(new DnsConfigServiceWin());
}
} // namespace net
diff --git a/net/dns/dns_response.cc b/net/dns/dns_response.cc
index 760bd5b..9518095 100644
--- a/net/dns/dns_response.cc
+++ b/net/dns/dns_response.cc
@@ -4,7 +4,9 @@
#include "net/dns/dns_response.h"
+#include "base/string_util.h"
#include "base/sys_byteorder.h"
+#include "net/base/address_list.h"
#include "net/base/big_endian.h"
#include "net/base/dns_util.h"
#include "net/base/io_buffer.h"
@@ -32,7 +34,8 @@ DnsRecordParser::DnsRecordParser(const void* packet,
DCHECK_LE(offset, length);
}
-int DnsRecordParser::ParseName(const void* const vpos, std::string* out) const {
+unsigned DnsRecordParser::ReadName(const void* const vpos,
+ std::string* out) const {
const char* const pos = reinterpret_cast<const char*>(vpos);
DCHECK(packet_);
DCHECK_LE(packet_, pos);
@@ -41,9 +44,9 @@ int DnsRecordParser::ParseName(const void* const vpos, std::string* out) const {
const char* p = pos;
const char* end = packet_ + length_;
// Count number of seen bytes to detect loops.
- size_t seen = 0;
+ unsigned seen = 0;
// Remember how many bytes were consumed before first jump.
- size_t consumed = 0;
+ unsigned consumed = 0;
if (pos >= end)
return 0;
@@ -54,7 +57,7 @@ int DnsRecordParser::ParseName(const void* const vpos, std::string* out) const {
}
for (;;) {
- // The two couple of bits of the length give the type of the length. It's
+ // The first two bits of the length give the type of the length. It's
// either a direct length or a pointer to the remainder of the name.
switch (*p & dns_protocol::kLabelMask) {
case dns_protocol::kLabelPointer: {
@@ -105,9 +108,9 @@ int DnsRecordParser::ParseName(const void* const vpos, std::string* out) const {
}
}
-bool DnsRecordParser::ParseRecord(DnsResourceRecord* out) {
+bool DnsRecordParser::ReadRecord(DnsResourceRecord* out) {
DCHECK(packet_);
- size_t consumed = ParseName(cur_, &out->name);
+ size_t consumed = ReadName(cur_, &out->name);
if (!consumed)
return false;
BigEndianReader reader(cur_ + consumed,
@@ -182,7 +185,7 @@ uint8 DnsResponse::rcode() const {
return ntohs(header()->flags) & dns_protocol::kRcodeMask;
}
-int DnsResponse::answer_count() const {
+unsigned DnsResponse::answer_count() const {
DCHECK(parser_.IsValid());
return ntohs(header()->ancount);
}
@@ -220,4 +223,71 @@ const dns_protocol::Header* DnsResponse::header() const {
return reinterpret_cast<const dns_protocol::Header*>(io_buffer_->data());
}
+DnsResponse::Result DnsResponse::ParseToAddressList(
+ AddressList* addr_list,
+ base::TimeDelta* ttl) const {
+ DCHECK(IsValid());
+ // DnsTransaction already verified that |response| matches the issued query.
+ // We still need to determine if there is a valid chain of CNAMEs from the
+ // query name to the RR owner name.
+ // We err on the side of caution with the assumption that if we are too picky,
+ // we can always fall back to the system getaddrinfo.
+
+ // Expected owner of record. No trailing dot.
+ std::string expected_name = GetDottedName();
+
+ uint16 expected_type = qtype();
+ DCHECK(expected_type == dns_protocol::kTypeA ||
+ expected_type == dns_protocol::kTypeAAAA);
+
+ size_t expected_size = (expected_type == dns_protocol::kTypeAAAA)
+ ? kIPv6AddressSize : kIPv4AddressSize;
+
+ uint32 cname_ttl_sec = kuint32max;
+ uint32 addr_ttl_sec = kuint32max;
+ IPAddressList ip_addresses;
+ DnsRecordParser parser = Parser();
+ DnsResourceRecord record;
+ unsigned ancount = answer_count();
+ for (unsigned i = 0; i < ancount; ++i) {
+ if (!parser.ReadRecord(&record))
+ return DNS_MALFORMED_RESPONSE;
+
+ if (base::strcasecmp(record.name.c_str(), expected_name.c_str()) != 0)
+ return DNS_NAME_MISMATCH;
+ if (record.type == dns_protocol::kTypeCNAME) {
+ // Following the CNAME chain, only if no addresses seen.
+ if (!ip_addresses.empty())
+ return DNS_CNAME_AFTER_ADDRESS;
+
+ if (record.rdata.size() !=
+ parser.ReadName(record.rdata.begin(), &expected_name))
+ return DNS_MALFORMED_CNAME;
+
+ cname_ttl_sec = std::min(cname_ttl_sec, record.ttl);
+ } else if (record.type == expected_type) {
+ if (record.rdata.size() != expected_size)
+ return DNS_SIZE_MISMATCH;
+ if (ip_addresses.empty()) {
+ addr_ttl_sec = record.ttl;
+ } else {
+ if (addr_ttl_sec != record.ttl)
+ return DNS_ADDRESS_TTL_MISMATCH;
+ }
+ ip_addresses.push_back(IPAddressNumber(record.rdata.begin(),
+ record.rdata.end()));
+ }
+ }
+
+ if (ip_addresses.empty())
+ return DNS_NO_ADDRESSES;
+
+ // getcanonname in eglibc returns the first owner name of an A or AAAA RR.
+ // If the response passed all the checks so far, then |expected_name| is it.
+ *addr_list = AddressList::CreateFromIPAddressList(ip_addresses,
+ expected_name);
+ *ttl = base::TimeDelta::FromSeconds(std::min(cname_ttl_sec, addr_ttl_sec));
+ return DNS_SUCCESS;
+}
+
} // namespace net
diff --git a/net/dns/dns_response.h b/net/dns/dns_response.h
index 764517a..4866045 100644
--- a/net/dns/dns_response.h
+++ b/net/dns/dns_response.h
@@ -11,11 +11,13 @@
#include "base/basictypes.h"
#include "base/memory/ref_counted.h"
#include "base/string_piece.h"
+#include "base/time.h"
#include "net/base/net_export.h"
#include "net/base/net_util.h"
namespace net {
+class AddressList;
class DnsQuery;
class IOBufferWithSize;
@@ -61,10 +63,10 @@ class NET_EXPORT_PRIVATE DnsRecordParser {
// This is exposed to allow parsing compressed names within RRDATA for TYPEs
// such as NS, CNAME, PTR, MX, SOA.
// See RFC 1035 section 4.1.4.
- int ParseName(const void* pos, std::string* out) const;
+ unsigned ReadName(const void* pos, std::string* out) const;
- // Parses the next resource record. Returns true if succeeded.
- bool ParseRecord(DnsResourceRecord* record);
+ // Parses the next resource record into |record|. Returns true if succeeded.
+ bool ReadRecord(DnsResourceRecord* record);
private:
const char* packet_;
@@ -78,6 +80,20 @@ class NET_EXPORT_PRIVATE DnsRecordParser {
// position the RR parser.
class NET_EXPORT_PRIVATE DnsResponse {
public:
+ // Possible results from ParseToAddressList
+ enum Result {
+ DNS_SUCCESS = 0,
+ DNS_MALFORMED_RESPONSE, // DnsRecordParser failed before the end of
+ // packet.
+ DNS_MALFORMED_CNAME, // Could not parse CNAME out of RRDATA.
+ DNS_NAME_MISMATCH, // Got an address but no ordered chain of CNAMEs
+ // leads there.
+ DNS_SIZE_MISMATCH, // Got an address but size does not match.
+ DNS_CNAME_AFTER_ADDRESS, // Found CNAME after an address record.
+ DNS_ADDRESS_TTL_MISMATCH, // TTL of all address records are not identical.
+ DNS_NO_ADDRESSES, // No address records found.
+ };
+
// Constructs an object with an IOBuffer large enough to read
// one byte more than largest possible response, to detect malformed
// responses.
@@ -102,7 +118,7 @@ class NET_EXPORT_PRIVATE DnsResponse {
// Accessors for the header.
uint16 flags() const; // excluding rcode
uint8 rcode() const;
- int answer_count() const;
+ unsigned answer_count() const;
// Accessors to the question. The qname is unparsed.
base::StringPiece qname() const;
@@ -116,6 +132,10 @@ class NET_EXPORT_PRIVATE DnsResponse {
// This operation is idempotent.
DnsRecordParser Parser() const;
+ // Extracts an AddressList from this response. Returns SUCCESS if succeeded.
+ // Otherwise returns a detailed error number.
+ Result ParseToAddressList(AddressList* addr_list, base::TimeDelta* ttl) const;
+
private:
// Convenience for header access.
const dns_protocol::Header* header() const;
diff --git a/net/dns/dns_response_unittest.cc b/net/dns/dns_response_unittest.cc
index 41f3a72..6cbf6a1 100644
--- a/net/dns/dns_response_unittest.cc
+++ b/net/dns/dns_response_unittest.cc
@@ -4,9 +4,14 @@
#include "net/dns/dns_response.h"
+#include "base/time.h"
+#include "net/base/address_list.h"
#include "net/base/io_buffer.h"
+#include "net/base/net_util.h"
+#include "net/base/sys_addrinfo.h"
#include "net/dns/dns_protocol.h"
#include "net/dns/dns_query.h"
+#include "net/dns/dns_test_util.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace net {
@@ -24,7 +29,7 @@ TEST(DnsRecordParserTest, Constructor) {
EXPECT_TRUE(DnsRecordParser(data, 1, 1).AtEnd());
}
-TEST(DnsRecordParserTest, ParseName) {
+TEST(DnsRecordParserTest, ReadName) {
const uint8 data[] = {
// all labels "foo.example.com"
0x03, 'f', 'o', 'o',
@@ -46,31 +51,31 @@ TEST(DnsRecordParserTest, ParseName) {
DnsRecordParser parser(data, sizeof(data), 0);
ASSERT_TRUE(parser.IsValid());
- EXPECT_EQ(0x11, parser.ParseName(data + 0x00, &out));
+ EXPECT_EQ(0x11u, parser.ReadName(data + 0x00, &out));
EXPECT_EQ("foo.example.com", out);
// Check that the last "." is never stored.
out.clear();
- EXPECT_EQ(0x1, parser.ParseName(data + 0x10, &out));
+ EXPECT_EQ(0x1u, parser.ReadName(data + 0x10, &out));
EXPECT_EQ("", out);
out.clear();
- EXPECT_EQ(0x6, parser.ParseName(data + 0x11, &out));
+ EXPECT_EQ(0x6u, parser.ReadName(data + 0x11, &out));
EXPECT_EQ("bar.example.com", out);
out.clear();
- EXPECT_EQ(0x2, parser.ParseName(data + 0x17, &out));
+ EXPECT_EQ(0x2u, parser.ReadName(data + 0x17, &out));
EXPECT_EQ("bar.example.com", out);
// Parse name without storing it.
- EXPECT_EQ(0x11, parser.ParseName(data + 0x00, NULL));
- EXPECT_EQ(0x1, parser.ParseName(data + 0x10, NULL));
- EXPECT_EQ(0x6, parser.ParseName(data + 0x11, NULL));
- EXPECT_EQ(0x2, parser.ParseName(data + 0x17, NULL));
+ EXPECT_EQ(0x11u, parser.ReadName(data + 0x00, NULL));
+ EXPECT_EQ(0x1u, parser.ReadName(data + 0x10, NULL));
+ EXPECT_EQ(0x6u, parser.ReadName(data + 0x11, NULL));
+ EXPECT_EQ(0x2u, parser.ReadName(data + 0x17, NULL));
// Check that it works even if initial position is different.
parser = DnsRecordParser(data, sizeof(data), 0x12);
- EXPECT_EQ(0x6, parser.ParseName(data + 0x11, NULL));
+ EXPECT_EQ(0x6u, parser.ReadName(data + 0x11, NULL));
}
-TEST(DnsRecordParserTest, ParseNameFail) {
+TEST(DnsRecordParserTest, ReadNameFail) {
const uint8 data[] = {
// label length beyond packet
0x30, 'x', 'x',
@@ -90,15 +95,15 @@ TEST(DnsRecordParserTest, ParseNameFail) {
ASSERT_TRUE(parser.IsValid());
std::string out;
- EXPECT_EQ(0, parser.ParseName(data + 0x00, &out));
- EXPECT_EQ(0, parser.ParseName(data + 0x04, &out));
- EXPECT_EQ(0, parser.ParseName(data + 0x08, &out));
- EXPECT_EQ(0, parser.ParseName(data + 0x0a, &out));
- EXPECT_EQ(0, parser.ParseName(data + 0x0c, &out));
- EXPECT_EQ(0, parser.ParseName(data + 0x0e, &out));
+ EXPECT_EQ(0u, parser.ReadName(data + 0x00, &out));
+ EXPECT_EQ(0u, parser.ReadName(data + 0x04, &out));
+ EXPECT_EQ(0u, parser.ReadName(data + 0x08, &out));
+ EXPECT_EQ(0u, parser.ReadName(data + 0x0a, &out));
+ EXPECT_EQ(0u, parser.ReadName(data + 0x0c, &out));
+ EXPECT_EQ(0u, parser.ReadName(data + 0x0e, &out));
}
-TEST(DnsRecordParserTest, ParseRecord) {
+TEST(DnsRecordParserTest, ReadRecord) {
const uint8 data[] = {
// Type CNAME record.
0x07, 'e', 'x', 'a', 'm', 'p', 'l', 'e',
@@ -124,17 +129,17 @@ TEST(DnsRecordParserTest, ParseRecord) {
DnsRecordParser parser(data, sizeof(data), 0);
DnsResourceRecord record;
- EXPECT_TRUE(parser.ParseRecord(&record));
+ EXPECT_TRUE(parser.ReadRecord(&record));
EXPECT_EQ("example.com", record.name);
EXPECT_EQ(dns_protocol::kTypeCNAME, record.type);
EXPECT_EQ(dns_protocol::kClassIN, record.klass);
EXPECT_EQ(0x00012474u, record.ttl);
EXPECT_EQ(6u, record.rdata.length());
- EXPECT_EQ(6, parser.ParseName(record.rdata.data(), &out));
+ EXPECT_EQ(6u, parser.ReadName(record.rdata.data(), &out));
EXPECT_EQ("foo.example.com", out);
EXPECT_FALSE(parser.AtEnd());
- EXPECT_TRUE(parser.ParseRecord(&record));
+ EXPECT_TRUE(parser.ReadRecord(&record));
EXPECT_EQ("bar.example.com", record.name);
EXPECT_EQ(dns_protocol::kTypeA, record.type);
EXPECT_EQ(dns_protocol::kClassIN, record.klass);
@@ -145,9 +150,9 @@ TEST(DnsRecordParserTest, ParseRecord) {
// Test truncated record.
parser = DnsRecordParser(data, sizeof(data) - 2, 0);
- EXPECT_TRUE(parser.ParseRecord(&record));
+ EXPECT_TRUE(parser.ReadRecord(&record));
EXPECT_FALSE(parser.AtEnd());
- EXPECT_FALSE(parser.ParseRecord(&record));
+ EXPECT_FALSE(parser.ReadRecord(&record));
}
TEST(DnsResponseTest, InitParse) {
@@ -225,7 +230,7 @@ TEST(DnsResponseTest, InitParse) {
// Check header access.
EXPECT_EQ(0x8180, resp.flags());
EXPECT_EQ(0x0, resp.rcode());
- EXPECT_EQ(2, resp.answer_count());
+ EXPECT_EQ(2u, resp.answer_count());
// Check question access.
EXPECT_EQ(query->qname(), resp.qname());
@@ -234,11 +239,224 @@ TEST(DnsResponseTest, InitParse) {
DnsResourceRecord record;
DnsRecordParser parser = resp.Parser();
- EXPECT_TRUE(parser.ParseRecord(&record));
+ EXPECT_TRUE(parser.ReadRecord(&record));
EXPECT_FALSE(parser.AtEnd());
- EXPECT_TRUE(parser.ParseRecord(&record));
+ EXPECT_TRUE(parser.ReadRecord(&record));
EXPECT_TRUE(parser.AtEnd());
- EXPECT_FALSE(parser.ParseRecord(&record));
+ EXPECT_FALSE(parser.ReadRecord(&record));
+}
+
+void VerifyAddressList(const std::vector<const char*>& ip_addresses,
+ const AddressList& addrlist) {
+ ASSERT_GT(ip_addresses.size(), 0u);
+ ASSERT_NE(static_cast<addrinfo*>(NULL), addrlist.head());
+
+ IPAddressNumber ip_number;
+ const struct addrinfo* ainfo = addrlist.head();
+ for (std::vector<const char*>::const_iterator i = ip_addresses.begin();
+ i != ip_addresses.end(); ++i, ainfo = ainfo->ai_next) {
+ ASSERT_NE(static_cast<addrinfo*>(NULL), ainfo);
+ EXPECT_EQ(sizeof(struct sockaddr_in),
+ static_cast<size_t>(ainfo->ai_addrlen));
+
+ const struct sockaddr* sa = ainfo->ai_addr;
+ EXPECT_STREQ(*i, NetAddressToString(sa, ainfo->ai_addrlen).c_str());
+ }
+ ASSERT_EQ(static_cast<addrinfo*>(NULL), ainfo);
+}
+
+TEST(DnsResponseTest, ParseToAddressList) {
+ const struct TestCase {
+ size_t query_size;
+ const uint8* response_data;
+ size_t response_size;
+ const char* const* expected_addresses;
+ size_t num_expected_addresses;
+ const char* expected_cname;
+ int expected_ttl_sec;
+ } cases[] = {
+ {
+ kT0QuerySize,
+ kT0ResponseDatagram, arraysize(kT0ResponseDatagram),
+ kT0IpAddresses, arraysize(kT0IpAddresses),
+ kT0CanonName,
+ kT0TTL,
+ },
+ {
+ kT1QuerySize,
+ kT1ResponseDatagram, arraysize(kT1ResponseDatagram),
+ kT1IpAddresses, arraysize(kT1IpAddresses),
+ kT1CanonName,
+ kT1TTL,
+ },
+ {
+ kT2QuerySize,
+ kT2ResponseDatagram, arraysize(kT2ResponseDatagram),
+ kT2IpAddresses, arraysize(kT2IpAddresses),
+ kT2CanonName,
+ kT2TTL,
+ },
+ {
+ kT3QuerySize,
+ kT3ResponseDatagram, arraysize(kT3ResponseDatagram),
+ kT3IpAddresses, arraysize(kT3IpAddresses),
+ kT3CanonName,
+ kT3TTL,
+ },
+ };
+
+ for (size_t i = 0; i < ARRAYSIZE_UNSAFE(cases); ++i) {
+ const TestCase& t = cases[i];
+ DnsResponse response(t.response_data, t.response_size, t.query_size);
+ AddressList addr_list;
+ base::TimeDelta ttl;
+ EXPECT_EQ(DnsResponse::DNS_SUCCESS,
+ response.ParseToAddressList(&addr_list, &ttl));
+ std::vector<const char*> expected_addresses(
+ t.expected_addresses,
+ t.expected_addresses + t.num_expected_addresses);
+ VerifyAddressList(expected_addresses, addr_list);
+ std::string cname;
+ ASSERT_TRUE(addr_list.GetCanonicalName(&cname));
+ EXPECT_EQ(t.expected_cname, cname);
+ EXPECT_EQ(base::TimeDelta::FromSeconds(t.expected_ttl_sec), ttl);
+ }
+}
+
+const uint8 kResponseTruncatedRecord[] = {
+ // Header: 1 question, 1 answer RR
+ 0x00, 0x00, 0x81, 0x80, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
+ // Question: name = 'a', type = A (0x1)
+ 0x01, 'a', 0x00, 0x00, 0x01, 0x00, 0x01,
+ // Answer: name = 'a', type = A, TTL = 0xFF, RDATA = 10.10.10.10
+ 0x01, 'a', 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0xFF,
+ 0x00, 0x04, 0x0A, 0x0A, 0x0A, // Truncated RDATA.
+};
+
+const uint8 kResponseTruncatedCNAME[] = {
+ // Header: 1 question, 1 answer RR
+ 0x00, 0x00, 0x81, 0x80, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
+ // Question: name = 'a', type = A (0x1)
+ 0x01, 'a', 0x00, 0x00, 0x01, 0x00, 0x01,
+ // Answer: name = 'a', type = CNAME, TTL = 0xFF, RDATA = 'foo' (truncated)
+ 0x01, 'a', 0x00, 0x00, 0x05, 0x00, 0x01, 0x00, 0x00, 0x00, 0xFF,
+ 0x00, 0x03, 0x03, 'f', 'o', // Truncated name.
+};
+
+const uint8 kResponseNameMismatch[] = {
+ // Header: 1 question, 1 answer RR
+ 0x00, 0x00, 0x81, 0x80, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
+ // Question: name = 'a', type = A (0x1)
+ 0x01, 'a', 0x00, 0x00, 0x01, 0x00, 0x01,
+ // Answer: name = 'b', type = A, TTL = 0xFF, RDATA = 10.10.10.10
+ 0x01, 'b', 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0xFF,
+ 0x00, 0x04, 0x0A, 0x0A, 0x0A, 0x0A,
+};
+
+const uint8 kResponseNameMismatchInChain[] = {
+ // Header: 1 question, 3 answer RR
+ 0x00, 0x00, 0x81, 0x80, 0x00, 0x01, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00,
+ // Question: name = 'a', type = A (0x1)
+ 0x01, 'a', 0x00, 0x00, 0x01, 0x00, 0x01,
+ // Answer: name = 'a', type = CNAME, TTL = 0xFF, RDATA = "b"
+ 0x01, 'a', 0x00, 0x00, 0x05, 0x00, 0x01, 0x00, 0x00, 0x00, 0xFF,
+ 0x00, 0x03, 0x01, 'b', 0x00,
+ // Answer: name = 'b', type = A, TTL = 0xFF, RDATA = 10.10.10.10
+ 0x01, 'b', 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0xFF,
+ 0x00, 0x04, 0x0A, 0x0A, 0x0A, 0x0A,
+ // Answer: name = 'c', type = A, TTL = 0xFF, RDATA = 10.10.10.11
+ 0x01, 'c', 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0xFF,
+ 0x00, 0x04, 0x0A, 0x0A, 0x0A, 0x0B,
+};
+
+const uint8 kResponseSizeMismatch[] = {
+ // Header: 1 answer RR
+ 0x00, 0x00, 0x81, 0x80, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
+ // Question: name = 'a', type = AAAA (0x1c)
+ 0x01, 'a', 0x00, 0x00, 0x1c, 0x00, 0x01,
+ // Answer: name = 'a', type = AAAA, TTL = 0xFF, RDATA = 10.10.10.10
+ 0x01, 'a', 0x00, 0x00, 0x1c, 0x00, 0x01, 0x00, 0x00, 0x00, 0xFF,
+ 0x00, 0x04, 0x0A, 0x0A, 0x0A, 0x0A,
+};
+
+const uint8 kResponseCNAMEAfterAddress[] = {
+ // Header: 2 answer RR
+ 0x00, 0x00, 0x81, 0x80, 0x00, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00,
+ // Question: name = 'a', type = A (0x1)
+ 0x01, 'a', 0x00, 0x00, 0x01, 0x00, 0x01,
+ // Answer: name = 'a', type = A, TTL = 0xFF, RDATA = 10.10.10.10.
+ 0x01, 'a', 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0xFF,
+ 0x00, 0x04, 0x0A, 0x0A, 0x0A, 0x0A,
+ // Answer: name = 'a', type = CNAME, TTL = 0xFF, RDATA = "b"
+ 0x01, 'a', 0x00, 0x00, 0x05, 0x00, 0x01, 0x00, 0x00, 0x00, 0xFF,
+ 0x00, 0x03, 0x01, 'b', 0x00,
+};
+
+const uint8 kResponseTTLMismatch[] = {
+ // Header: 1 question, 3 answer RR
+ 0x00, 0x00, 0x81, 0x80, 0x00, 0x01, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00,
+ // Question: name = 'a', type = A (0x1)
+ 0x01, 'a', 0x00, 0x00, 0x01, 0x00, 0x01,
+ // Answer: name = 'a', type = CNAME, TTL = 0xFF, RDATA = "b"
+ 0x01, 'a', 0x00, 0x00, 0x05, 0x00, 0x01, 0x00, 0x00, 0x00, 0xFF,
+ 0x00, 0x03, 0x01, 'b', 0x00,
+ // Answer: name = 'b', type = A, TTL = 0xFF, RDATA = 10.10.10.10
+ 0x01, 'b', 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0xFF,
+ 0x00, 0x04, 0x0A, 0x0A, 0x0A, 0x0A,
+ // Answer: name = 'b', type = A, TTL = 0xBB, RDATA = 10.10.10.11
+ 0x01, 'b', 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0xBB,
+ 0x00, 0x04, 0x0A, 0x0A, 0x0A, 0x0B,
+};
+
+const uint8 kResponseNoAddresses[] = {
+ // Header: 1 question, 1 answer RR, 1 authority RR
+ 0x00, 0x00, 0x81, 0x80, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01,
+ // Question: name = 'a', type = A (0x1)
+ 0x01, 'a', 0x00, 0x00, 0x01, 0x00, 0x01,
+ // Answer: name = 'a', type = CNAME, TTL = 0xFF, RDATA = "b"
+ 0x01, 'a', 0x00, 0x00, 0x05, 0x00, 0x01, 0x00, 0x00, 0x00, 0xFF,
+ 0x00, 0x03, 0x01, 'b', 0x00,
+ // Authority section
+ // Answer: name = 'b', type = A, TTL = 0xFF, RDATA = 10.10.10.10
+ 0x01, 'b', 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0xFF,
+ 0x00, 0x04, 0x0A, 0x0A, 0x0A, 0x0A,
+};
+
+TEST(DnsResponseTest, ParseToAddressListFail) {
+ const struct TestCase {
+ const uint8* data;
+ size_t size;
+ DnsResponse::Result expected_result;
+ } cases[] = {
+ { kResponseTruncatedRecord, arraysize(kResponseTruncatedRecord),
+ DnsResponse::DNS_MALFORMED_RESPONSE },
+ { kResponseTruncatedCNAME, arraysize(kResponseTruncatedCNAME),
+ DnsResponse::DNS_MALFORMED_CNAME },
+ { kResponseNameMismatch, arraysize(kResponseNameMismatch),
+ DnsResponse::DNS_NAME_MISMATCH },
+ { kResponseNameMismatchInChain, arraysize(kResponseNameMismatchInChain),
+ DnsResponse::DNS_NAME_MISMATCH },
+ { kResponseSizeMismatch, arraysize(kResponseSizeMismatch),
+ DnsResponse::DNS_SIZE_MISMATCH },
+ { kResponseCNAMEAfterAddress, arraysize(kResponseCNAMEAfterAddress),
+ DnsResponse::DNS_CNAME_AFTER_ADDRESS },
+ { kResponseTTLMismatch, arraysize(kResponseTTLMismatch),
+ DnsResponse::DNS_ADDRESS_TTL_MISMATCH },
+ { kResponseNoAddresses, arraysize(kResponseNoAddresses),
+ DnsResponse::DNS_NO_ADDRESSES },
+ };
+
+ const size_t kQuerySize = 12 + 7;
+
+ for (size_t i = 0; i < ARRAYSIZE_UNSAFE(cases); ++i) {
+ const TestCase& t = cases[i];
+
+ DnsResponse response(t.data, t.size, kQuerySize);
+ AddressList addr_list;
+ base::TimeDelta ttl;
+ EXPECT_EQ(t.expected_result,
+ response.ParseToAddressList(&addr_list, &ttl));
+ }
}
} // namespace
diff --git a/net/dns/dns_session.h b/net/dns/dns_session.h
index 85aea0a..aa070ac 100644
--- a/net/dns/dns_session.h
+++ b/net/dns/dns_session.h
@@ -34,7 +34,7 @@ class NET_EXPORT_PRIVATE DnsSession
const DnsConfig& config() const { return config_; }
NetLog* net_log() const { return net_log_; }
- ClientSocketFactory* socket_factory() { return socket_factory_.get(); }
+ ClientSocketFactory* socket_factory() { return socket_factory_; }
// Return the next random query ID.
int NextQueryId() const;
@@ -50,7 +50,7 @@ class NET_EXPORT_PRIVATE DnsSession
~DnsSession();
const DnsConfig config_;
- scoped_ptr<ClientSocketFactory> socket_factory_;
+ ClientSocketFactory* socket_factory_;
RandCallback rand_callback_;
NetLog* net_log_;
diff --git a/net/dns/dns_test_util.h b/net/dns/dns_test_util.h
index 6c29058..8d8c0a6 100644
--- a/net/dns/dns_test_util.h
+++ b/net/dns/dns_test_util.h
@@ -21,13 +21,7 @@ static const char kT0DnsName[] = {
0x03, 'c', 'o', 'm',
0x00
};
-static const uint8 kT0QueryDatagram[] = {
- // query for www.google.com, type A.
- 0x00, 0x00, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x03, 0x77, 0x77, 0x77,
- 0x06, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x03,
- 0x63, 0x6f, 0x6d, 0x00, 0x00, 0x01, 0x00, 0x01
-};
+static const size_t kT0QuerySize = 32;
static const uint8 kT0ResponseDatagram[] = {
// response contains one CNAME for www.l.google.com and the following
// IP addresses: 74.125.226.{179,180,176,177,178}
@@ -53,6 +47,8 @@ static const char* const kT0IpAddresses[] = {
"74.125.226.179", "74.125.226.180", "74.125.226.176",
"74.125.226.177", "74.125.226.178"
};
+static const char kT0CanonName[] = "www.l.google.com";
+static const int kT0TTL = 0x000000e4;
//-----------------------------------------------------------------------------
// Query/response set for codereview.chromium.org, ID is fixed to 1.
@@ -64,15 +60,7 @@ static const char kT1DnsName[] = {
0x03, 'o', 'r', 'g',
0x00
};
-static const uint8 kT1QueryDatagram[] = {
- // query for codereview.chromium.org, type A.
- 0x00, 0x01, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x0a, 0x63, 0x6f, 0x64,
- 0x65, 0x72, 0x65, 0x76, 0x69, 0x65, 0x77, 0x08,
- 0x63, 0x68, 0x72, 0x6f, 0x6d, 0x69, 0x75, 0x6d,
- 0x03, 0x6f, 0x72, 0x67, 0x00, 0x00, 0x01, 0x00,
- 0x01
-};
+static const size_t kT1QuerySize = 41;
static const uint8 kT1ResponseDatagram[] = {
// response contains one CNAME for ghs.l.google.com and the following
// IP address: 64.233.169.121
@@ -91,6 +79,8 @@ static const uint8 kT1ResponseDatagram[] = {
static const char* const kT1IpAddresses[] = {
"64.233.169.121"
};
+static const char kT1CanonName[] = "ghs.l.google.com";
+static const int kT1TTL = 0x0000010b;
//-----------------------------------------------------------------------------
// Query/response set for www.ccs.neu.edu, ID is fixed to 2.
@@ -103,14 +93,7 @@ static const char kT2DnsName[] = {
0x03, 'e', 'd', 'u',
0x00
};
-static const uint8 kT2QueryDatagram[] = {
- // query for www.ccs.neu.edu, type A.
- 0x00, 0x02, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x03, 0x77, 0x77, 0x77,
- 0x03, 0x63, 0x63, 0x73, 0x03, 0x6e, 0x65, 0x75,
- 0x03, 0x65, 0x64, 0x75, 0x00, 0x00, 0x01, 0x00,
- 0x01
-};
+static const size_t kT2QuerySize = 33;
static const uint8 kT2ResponseDatagram[] = {
// response contains one CNAME for vulcan.ccs.neu.edu and the following
// IP address: 129.10.116.81
@@ -127,6 +110,8 @@ static const uint8 kT2ResponseDatagram[] = {
static const char* const kT2IpAddresses[] = {
"129.10.116.81"
};
+static const char kT2CanonName[] = "vulcan.ccs.neu.edu";
+static const int kT2TTL = 0x0000012c;
//-----------------------------------------------------------------------------
// Query/response set for www.google.az, ID is fixed to 3.
@@ -138,13 +123,7 @@ static const char kT3DnsName[] = {
0x02, 'a', 'z',
0x00
};
-static const uint8 kT3QueryDatagram[] = {
- // query for www.google.az, type A.
- 0x00, 0x03, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x03, 0x77, 0x77, 0x77,
- 0x06, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x02,
- 0x61, 0x7a, 0x00, 0x00, 0x01, 0x00, 0x01
-};
+static const size_t kT3QuerySize = 31;
static const uint8 kT3ResponseDatagram[] = {
// response contains www.google.com as CNAME for www.google.az and
// www.l.google.com as CNAME for www.google.com and the following
@@ -174,6 +153,8 @@ static const char* const kT3IpAddresses[] = {
"74.125.226.178", "74.125.226.179", "74.125.226.180",
"74.125.226.176", "74.125.226.177"
};
+static const char kT3CanonName[] = "www.l.google.com";
+static const int kT3TTL = 0x00000015;
} // namespace net
diff --git a/net/dns/dns_transaction.cc b/net/dns/dns_transaction.cc
index 6cd02a3..8bffa12 100644
--- a/net/dns/dns_transaction.cc
+++ b/net/dns/dns_transaction.cc
@@ -51,22 +51,19 @@ bool IsIPLiteral(const std::string& hostname) {
class StartParameters : public NetLog::EventParameters {
public:
StartParameters(const std::string& hostname,
- uint16 qtype,
- const NetLog::Source& source)
- : hostname_(hostname), qtype_(qtype), source_(source) {}
+ uint16 qtype)
+ : hostname_(hostname), qtype_(qtype) {}
virtual Value* ToValue() const OVERRIDE {
DictionaryValue* dict = new DictionaryValue();
dict->SetString("hostname", hostname_);
dict->SetInteger("query_type", qtype_);
- dict->Set("source_dependency", source_.ToValue());
return dict;
}
private:
const std::string hostname_;
const uint16 qtype_;
- const NetLog::Source source_;
};
class ResponseParameters : public NetLog::EventParameters {
@@ -78,7 +75,7 @@ class ResponseParameters : public NetLog::EventParameters {
DictionaryValue* dict = new DictionaryValue();
dict->SetInteger("rcode", rcode_);
dict->SetInteger("answer_count", answer_count_);
- dict->Set("socket_source", source_.ToValue());
+ dict->Set("source_dependency", source_.ToValue());
return dict;
}
@@ -211,8 +208,14 @@ class DnsUDPAttempt {
return rv;
DCHECK(rv);
- if (!response_->InitParse(rv, *query_))
+ if (!response_->InitParse(rv, *query_)) {
+ // TODO(szym): Consider making this reaction less aggressive.
+ // 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.
+ // http://crbug.com/107413
return ERR_DNS_MALFORMED_RESPONSE;
+ }
if (response_->flags() & dns_protocol::kFlagTC)
return ERR_DNS_SERVER_REQUIRES_TCP;
if (response_->rcode() != dns_protocol::kRcodeNOERROR &&
@@ -258,13 +261,12 @@ class DnsTransactionImpl : public DnsTransaction, public base::NonThreadSafe {
const std::string& hostname,
uint16 qtype,
const DnsTransactionFactory::CallbackType& callback,
- const BoundNetLog& source_net_log)
+ const BoundNetLog& net_log)
: session_(session),
hostname_(hostname),
qtype_(qtype),
callback_(callback),
- net_log_(BoundNetLog::Make(session->net_log(),
- NetLog::SOURCE_DNS_TRANSACTION)),
+ net_log_(net_log),
first_server_index_(0) {
DCHECK(session_);
DCHECK(!hostname_.empty());
@@ -273,7 +275,7 @@ class DnsTransactionImpl : public DnsTransaction, public base::NonThreadSafe {
DCHECK(!IsIPLiteral(hostname_));
net_log_.BeginEvent(NetLog::TYPE_DNS_TRANSACTION, make_scoped_refptr(
- new StartParameters(hostname_, qtype_, source_net_log.source())));
+ new StartParameters(hostname_, qtype_)));
}
virtual ~DnsTransactionImpl() {
@@ -299,7 +301,19 @@ class DnsTransactionImpl : public DnsTransaction, public base::NonThreadSafe {
int rv = PrepareSearch();
if (rv == OK)
rv = StartQuery();
- DCHECK_NE(OK, rv);
+ if (rv == OK) {
+ // In the very unlikely case that we immediately received the response, we
+ // cannot simply return OK nor run the callback, but instead complete
+ // asynchronously.
+ // TODO(szym): replace Unretained with WeakPtr factory.
+ MessageLoop::current()->PostTask(
+ FROM_HERE,
+ base::Bind(&DnsTransactionImpl::DoCallback,
+ base::Unretained(this),
+ OK,
+ attempts_.back()));
+ return ERR_IO_PENDING;
+ }
return rv;
}
@@ -387,7 +401,8 @@ class DnsTransactionImpl : public DnsTransaction, public base::NonThreadSafe {
}
net_log_.AddEvent(NetLog::TYPE_DNS_TRANSACTION_ATTEMPT, make_scoped_refptr(
- new NetLogSourceParameter("socket_source", socket->NetLog().source())));
+ new NetLogSourceParameter("source_dependency",
+ socket->NetLog().source())));
const DnsConfig& config = session_->config();
@@ -451,7 +466,7 @@ class DnsTransactionImpl : public DnsTransaction, public base::NonThreadSafe {
DoCallback(rv, attempt);
return;
default:
- // TODO(szym): Some nameservers could fail so try the next one.
+ // Some nameservers could fail so try the next one.
const DnsConfig& config = session_->config();
if (attempts_.size() < config.attempts * config.nameservers.size()) {
rv = MakeAttempt();
@@ -512,12 +527,12 @@ class DnsTransactionFactoryImpl : public DnsTransactionFactory {
const std::string& hostname,
uint16 qtype,
const CallbackType& callback,
- const BoundNetLog& source_net_log) OVERRIDE {
+ const BoundNetLog& net_log) OVERRIDE {
return scoped_ptr<DnsTransaction>(new DnsTransactionImpl(session_,
hostname,
qtype,
callback,
- source_net_log));
+ net_log));
}
private:
diff --git a/net/dns/dns_transaction.h b/net/dns/dns_transaction.h
index 038f4b2..383f4a5 100644
--- a/net/dns/dns_transaction.h
+++ b/net/dns/dns_transaction.h
@@ -61,12 +61,12 @@ class NET_EXPORT_PRIVATE DnsTransactionFactory {
// search. |hostname| should not be an IP literal.
//
// The transaction will run |callback| upon asynchronous completion.
- // The source of |source_net_log| is used as source dependency in log.
+ // The |net_log| is used as the parent log.
virtual scoped_ptr<DnsTransaction> CreateTransaction(
const std::string& hostname,
uint16 qtype,
const CallbackType& callback,
- const BoundNetLog& source_net_log) WARN_UNUSED_RESULT = 0;
+ const BoundNetLog& net_log) WARN_UNUSED_RESULT = 0;
// Creates a DnsTransactionFactory which creates DnsTransactionImpl using the
// |session|.
diff --git a/net/dns/dns_transaction_unittest.cc b/net/dns/dns_transaction_unittest.cc
index 8e0888a..b21eb794 100644
--- a/net/dns/dns_transaction_unittest.cc
+++ b/net/dns/dns_transaction_unittest.cc
@@ -141,14 +141,16 @@ class TransactionHelper {
if (expected_answer_count_ >= 0) {
EXPECT_EQ(OK, rv);
- EXPECT_EQ(expected_answer_count_, response->answer_count());
+ EXPECT_EQ(static_cast<unsigned>(expected_answer_count_),
+ response->answer_count());
EXPECT_EQ(qtype_, response->qtype());
DnsRecordParser parser = response->Parser();
DnsResourceRecord record;
for (int i = 0; i < expected_answer_count_; ++i) {
- EXPECT_TRUE(parser.ParseRecord(&record));
+ EXPECT_TRUE(parser.ReadRecord(&record));
}
+ // Technically, there could be additional RRs, but not in our test data.
EXPECT_TRUE(parser.AtEnd());
} else {
EXPECT_EQ(expected_answer_count_, rv);
@@ -212,10 +214,10 @@ class DnsTransactionTest : public testing::Test {
// Called after fully configuring |config|.
void ConfigureFactory() {
- socket_factory_ = new TestSocketFactory();
+ socket_factory_.reset(new TestSocketFactory());
session_ = new DnsSession(
config_,
- socket_factory_,
+ socket_factory_.get(),
base::Bind(&DnsTransactionTest::GetNextId, base::Unretained(this)),
NULL /* NetLog */);
transaction_factory_ = DnsTransactionFactory::CreateFactory(session_.get());
@@ -232,7 +234,7 @@ class DnsTransactionTest : public testing::Test {
uint16 id,
const char* data,
size_t data_length) {
- CHECK(socket_factory_);
+ CHECK(socket_factory_.get());
DnsQuery* query = new DnsQuery(id, DomainFromDot(dotted_name), qtype);
queries_.push_back(query);
@@ -252,7 +254,7 @@ class DnsTransactionTest : public testing::Test {
// Add expected query of |dotted_name| and |qtype| and no response.
void AddTimeout(const char* dotted_name, uint16 qtype) {
- CHECK(socket_factory_);
+ CHECK(socket_factory_.get());
uint16 id = base::RandInt(0, kuint16max);
DnsQuery* query = new DnsQuery(id, DomainFromDot(dotted_name), qtype);
queries_.push_back(query);
@@ -268,7 +270,7 @@ class DnsTransactionTest : public testing::Test {
// Add expected query of |dotted_name| and |qtype| and response with no answer
// and rcode set to |rcode|.
void AddRcode(const char* dotted_name, uint16 qtype, int rcode) {
- CHECK(socket_factory_);
+ CHECK(socket_factory_.get());
CHECK_NE(dns_protocol::kRcodeNOERROR, rcode);
uint16 id = base::RandInt(0, kuint16max);
DnsQuery* query = new DnsQuery(id, DomainFromDot(dotted_name), qtype);
@@ -360,8 +362,7 @@ class DnsTransactionTest : public testing::Test {
ScopedVector<DelayedSocketData> socket_data_;
std::deque<int> transaction_ids_;
- // Owned by |session_|.
- TestSocketFactory* socket_factory_;
+ scoped_ptr<TestSocketFactory> socket_factory_;
scoped_refptr<DnsSession> session_;
scoped_ptr<DnsTransactionFactory> transaction_factory_;
};