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

Unified Diff: net/base/host_resolver_impl.cc

Issue 9369045: [net] HostResolverImpl + DnsTransaction + DnsConfigService = Asynchronous DNS ready for experiments. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Denitted. Created 8 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « net/base/host_resolver_impl.h ('k') | net/base/host_resolver_impl_unittest.cc » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: net/base/host_resolver_impl.cc
diff --git a/net/base/host_resolver_impl.cc b/net/base/host_resolver_impl.cc
index d9330e213cebb1405002629e2fda5e6042329fac..02d20617be9bf20b33461cd2747335fe8f53042c 100644
--- a/net/base/host_resolver_impl.cc
+++ b/net/base/host_resolver_impl.cc
@@ -24,12 +24,14 @@
#include "base/message_loop_proxy.h"
#include "base/metrics/field_trial.h"
#include "base/metrics/histogram.h"
+#include "base/rand_util.h"
#include "base/stl_util.h"
#include "base/string_util.h"
#include "base/threading/worker_pool.h"
#include "base/time.h"
#include "base/utf_string_conversions.h"
#include "base/values.h"
+#include "net/base/address_family.h"
#include "net/base/address_list.h"
#include "net/base/address_list_net_log_param.h"
#include "net/base/dns_reloader.h"
@@ -38,6 +40,12 @@
#include "net/base/net_errors.h"
#include "net/base/net_log.h"
#include "net/base/net_util.h"
+#include "net/dns/dns_config_service.h"
+#include "net/dns/dns_protocol.h"
+#include "net/dns/dns_response.h"
+#include "net/dns/dns_session.h"
+#include "net/dns/dns_transaction.h"
+#include "net/socket/client_socket_factory.h"
#if defined(OS_WIN)
#include "net/base/winsock_init.h"
@@ -54,6 +62,9 @@ const size_t kMaxHostLength = 4096;
// Default TTL for successful resolutions with ProcTask.
const unsigned kCacheEntryTTLSeconds = 60;
+// Default TTL for unsuccessful resolutions with ProcTask.
+const unsigned kNegativeCacheEntryTTLSeconds = 0;
+
// Maximum of 8 concurrent resolver threads (excluding retries).
// Some routers (or resolvers) appear to start to provide host-not-found if
// too many simultaneous resolutions are pending. This number needs to be
@@ -66,9 +77,9 @@ static const size_t kDefaultMaxProcTasks = 8u;
//
// However since we allocated the AddressList ourselves we can safely
// do this optimization and avoid reallocating the list.
-void MutableSetPort(int port, AddressList* addrlist) {
+void MutableSetPort(int port, AddressList* addr_list) {
struct addrinfo* mutable_head =
- const_cast<struct addrinfo*>(addrlist->head());
+ const_cast<struct addrinfo*>(addr_list->head());
SetPortForAllAddrinfos(mutable_head, port);
}
@@ -144,22 +155,20 @@ class CallSystemHostResolverProc : public HostResolverProc {
virtual int Resolve(const std::string& hostname,
AddressFamily address_family,
HostResolverFlags host_resolver_flags,
- AddressList* addrlist,
+ AddressList* addr_list,
int* os_error) OVERRIDE {
return SystemHostResolverProc(hostname,
address_family,
host_resolver_flags,
- addrlist,
+ addr_list,
os_error);
}
};
// Extra parameters to attach to the NetLog when the resolve failed.
-class HostResolveFailedParams : public NetLog::EventParameters {
+class ProcTaskFailedParams : public NetLog::EventParameters {
public:
- HostResolveFailedParams(uint32 attempt_number,
- int net_error,
- int os_error)
+ ProcTaskFailedParams(uint32 attempt_number, int net_error, int os_error)
: attempt_number_(attempt_number),
net_error_(net_error),
os_error_(os_error) {
@@ -201,6 +210,26 @@ class HostResolveFailedParams : public NetLog::EventParameters {
const int os_error_;
};
+// Extra parameters to attach to the NetLog when the DnsTask failed.
+class DnsTaskFailedParams : public NetLog::EventParameters {
+ public:
+ DnsTaskFailedParams(int net_error, int dns_error)
+ : net_error_(net_error), dns_error_(dns_error) {
+ }
+
+ virtual Value* ToValue() const OVERRIDE {
+ DictionaryValue* dict = new DictionaryValue();
+ dict->SetInteger("net_error", net_error_);
+ if (dns_error_)
+ dict->SetInteger("dns_error", dns_error_);
+ return dict;
+ }
+
+ private:
+ const int net_error_;
+ const int dns_error_;
+};
+
// Parameters representing the information in a RequestInfo object, along with
// the associated NetLog::Source.
class RequestInfoParameters : public NetLog::EventParameters {
@@ -229,8 +258,7 @@ class RequestInfoParameters : public NetLog::EventParameters {
const NetLog::Source source_;
};
-// Parameters associated with the creation of a HostResolverImpl::Job
-// or a HostResolverImpl::ProcTask.
+// Parameters associated with the creation of a HostResolverImpl::Job.
class JobCreationParameters : public NetLog::EventParameters {
public:
JobCreationParameters(const std::string& host,
@@ -290,14 +318,9 @@ void LogStartRequest(const BoundNetLog& source_net_log,
void LogFinishRequest(const BoundNetLog& source_net_log,
const BoundNetLog& request_net_log,
const HostResolver::RequestInfo& info,
- int net_error,
- int os_error) {
- scoped_refptr<NetLog::EventParameters> params;
- if (net_error != OK) {
- params = new HostResolveFailedParams(0, net_error, os_error);
- }
-
- request_net_log.EndEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_REQUEST, params);
+ int net_error) {
+ request_net_log.EndEventWithNetErrorCode(
+ NetLog::TYPE_HOST_RESOLVER_IMPL_REQUEST, net_error);
source_net_log.EndEvent(NetLog::TYPE_HOST_RESOLVER_IMPL, NULL);
}
@@ -315,8 +338,8 @@ void LogCancelRequest(const BoundNetLog& source_net_log,
// Keeps track of the highest priority.
class PriorityTracker {
public:
- PriorityTracker()
- : highest_priority_(IDLE), total_count_(0) {
+ explicit PriorityTracker(RequestPriority priority)
+ : highest_priority_(priority), total_count_(0) {
memset(counts_, 0, sizeof(counts_));
}
@@ -361,7 +384,8 @@ class PriorityTracker {
HostResolver* CreateHostResolver(size_t max_concurrent_resolves,
size_t max_retry_attempts,
- bool use_cache,
+ HostCache* cache,
+ scoped_ptr<DnsConfigService> config_service,
NetLog* net_log) {
if (max_concurrent_resolves == HostResolver::kDefaultParallelism)
max_concurrent_resolves = kDefaultMaxProcTasks;
@@ -372,9 +396,10 @@ HostResolver* CreateHostResolver(size_t max_concurrent_resolves,
PrioritizedDispatcher::Limits limits(NUM_PRIORITIES, max_concurrent_resolves);
HostResolverImpl* resolver = new HostResolverImpl(
- use_cache ? HostCache::CreateDefaultCache() : NULL,
+ cache,
limits,
HostResolverImpl::ProcTaskParams(NULL, max_retry_attempts),
+ config_service.Pass(),
net_log);
return resolver;
@@ -389,7 +414,8 @@ HostResolver* CreateSystemHostResolver(size_t max_concurrent_resolves,
NetLog* net_log) {
return CreateHostResolver(max_concurrent_resolves,
max_retry_attempts,
- true /* use_cache */,
+ HostCache::CreateDefaultCache(),
+ scoped_ptr<DnsConfigService>(NULL),
net_log);
}
@@ -398,7 +424,21 @@ HostResolver* CreateNonCachingSystemHostResolver(size_t max_concurrent_resolves,
NetLog* net_log) {
return CreateHostResolver(max_concurrent_resolves,
max_retry_attempts,
- false /* use_cache */,
+ NULL,
+ scoped_ptr<DnsConfigService>(NULL),
+ net_log);
+}
+
+HostResolver* CreateAsyncHostResolver(size_t max_concurrent_resolves,
+ size_t max_retry_attempts,
+ NetLog* net_log) {
+ scoped_ptr<DnsConfigService> config_service =
+ DnsConfigService::CreateSystemService();
+ config_service->Watch();
+ return CreateHostResolver(max_concurrent_resolves,
+ max_retry_attempts,
+ HostCache::CreateDefaultCache(),
+ config_service.Pass(),
net_log);
}
@@ -440,9 +480,9 @@ class HostResolverImpl::Request {
}
// Prepare final AddressList and call completion callback.
- void OnComplete(int error, const AddressList& addrlist) {
+ void OnComplete(int error, const AddressList& addr_list) {
if (error == OK)
- *addresses_ = CreateAddressListUsingPort(addrlist, info_.port());
+ *addresses_ = CreateAddressListUsingPort(addr_list, info_.port());
CompletionCallback callback = callback_;
MarkAsCanceled();
callback.Run(error);
@@ -505,7 +545,8 @@ class HostResolverImpl::Request {
class HostResolverImpl::ProcTask
: public base::RefCountedThreadSafe<HostResolverImpl::ProcTask> {
public:
- typedef base::Callback<void(int, int, const AddressList&)> Callback;
+ typedef base::Callback<void(int net_error,
+ const AddressList& addr_list)> Callback;
ProcTask(const Key& key,
const ProcTaskParams& params,
@@ -519,22 +560,14 @@ class HostResolverImpl::ProcTask
completed_attempt_number_(0),
completed_attempt_error_(ERR_UNEXPECTED),
had_non_speculative_request_(false),
- net_log_(BoundNetLog::Make(
- job_net_log.net_log(),
- NetLog::SOURCE_HOST_RESOLVER_IMPL_PROC_TASK)) {
+ net_log_(job_net_log) {
if (!params_.resolver_proc)
params_.resolver_proc = HostResolverProc::GetDefault();
// If default is unset, use the system proc.
if (!params_.resolver_proc)
params_.resolver_proc = new CallSystemHostResolverProc();
- job_net_log.AddEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_CREATE_PROC_TASK,
- new NetLogSourceParameter("source_dependency",
- net_log_.source()));
-
- net_log_.BeginEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_PROC_TASK,
- new JobCreationParameters(key_.hostname,
- job_net_log.source()));
+ net_log_.BeginEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_PROC_TASK, NULL);
}
void Start() {
@@ -551,8 +584,6 @@ class HostResolverImpl::ProcTask
if (was_canceled())
return;
- net_log_.AddEvent(NetLog::TYPE_CANCELLED, NULL);
-
callback_.Reset();
net_log_.EndEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_PROC_TASK, NULL);
@@ -621,7 +652,6 @@ class HostResolverImpl::ProcTask
AddressList results;
int os_error = 0;
// Running on the worker thread
-
int error = params_.resolver_proc->Resolve(key_.hostname,
key_.address_family,
key_.host_resolver_flags,
@@ -657,14 +687,13 @@ class HostResolverImpl::ProcTask
bool was_retry_attempt = attempt_number > 1;
// Ideally the following code would be part of host_resolver_proc.cc,
- // however it isn't safe to call NetworkChangeNotifier from worker
- // threads. So we do it here on the IO thread instead.
+ // however it isn't safe to call NetworkChangeNotifier from worker threads.
+ // So we do it here on the IO thread instead.
if (error != OK && NetworkChangeNotifier::IsOffline())
error = ERR_INTERNET_DISCONNECTED;
- // If this is the first attempt that is finishing later, then record
- // data for the first attempt. Won't contaminate with retry attempt's
- // data.
+ // If this is the first attempt that is finishing later, then record data
+ // for the first attempt. Won't contaminate with retry attempt's data.
if (!was_retry_attempt)
RecordPerformanceHistograms(start_time, error, os_error);
@@ -675,7 +704,7 @@ class HostResolverImpl::ProcTask
scoped_refptr<NetLog::EventParameters> params;
if (error != OK) {
- params = new HostResolveFailedParams(attempt_number, error, os_error);
+ params = new ProcTaskFailedParams(attempt_number, error, os_error);
} else {
params = new NetLogIntegerParameter("attempt_number", attempt_number);
}
@@ -696,13 +725,13 @@ class HostResolverImpl::ProcTask
}
if (error != OK) {
- params = new HostResolveFailedParams(0, error, os_error);
+ params = new ProcTaskFailedParams(0, error, os_error);
} else {
params = new AddressListNetLogParam(results_);
}
net_log_.EndEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_PROC_TASK, params);
- callback_.Run(error, os_error, results_);
+ callback_.Run(error, results_);
}
void RecordPerformanceHistograms(const base::TimeTicks& start_time,
@@ -891,6 +920,8 @@ class HostResolverImpl::ProcTask
//-----------------------------------------------------------------------------
// Represents a request to the worker pool for a "probe for IPv6 support" call.
+//
+// TODO(szym): This could also be replaced with PostTaskAndReply and Callbacks.
class HostResolverImpl::IPv6ProbeJob
: public base::RefCountedThreadSafe<HostResolverImpl::IPv6ProbeJob> {
public:
@@ -958,61 +989,130 @@ class HostResolverImpl::IPv6ProbeJob
//-----------------------------------------------------------------------------
+// Resolves the hostname using DnsTransaction.
+// TODO(szym): This could be moved to separate source file as well.
+class HostResolverImpl::DnsTask {
+ public:
+ typedef base::Callback<void(int net_error,
+ const AddressList& addr_list,
+ base::TimeDelta ttl)> Callback;
+
+ DnsTask(DnsTransactionFactory* factory,
+ const Key& key,
+ const Callback& callback,
+ const BoundNetLog& job_net_log)
+ : callback_(callback), net_log_(job_net_log) {
+ DCHECK(factory);
+ DCHECK(!callback.is_null());
+
+ // For now we treat ADDRESS_FAMILY_UNSPEC as if it was IPV4.
+ uint16 qtype = (key.address_family == ADDRESS_FAMILY_IPV6)
+ ? dns_protocol::kTypeAAAA
+ : dns_protocol::kTypeA;
+ // TODO(szym): Implement "happy eyeballs".
+ transaction_ = factory->CreateTransaction(
+ key.hostname,
+ qtype,
+ base::Bind(&DnsTask::OnTransactionComplete, base::Unretained(this)),
+ net_log_);
+ DCHECK(transaction_.get());
+ }
+
+ int Start() {
+ net_log_.BeginEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_DNS_TASK, NULL);
+ return transaction_->Start();
+ }
+
+ void OnTransactionComplete(DnsTransaction* transaction,
+ int net_error,
+ const DnsResponse* response) {
+ // TODO(szym): Record performance histograms.
+ // Run |callback_| last since the owning Job will then delete this DnsTask.
+ DnsResponse::Result result = DnsResponse::DNS_SUCCESS;
+ if (net_error == OK) {
+ AddressList addr_list;
+ base::TimeDelta ttl;
+ result = response->ParseToAddressList(&addr_list, &ttl);
+ if (result == DnsResponse::DNS_SUCCESS) {
+ net_log_.EndEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_DNS_TASK,
+ new AddressListNetLogParam(addr_list));
+ callback_.Run(net_error, addr_list, ttl);
+ return;
+ }
+ net_error = ERR_DNS_MALFORMED_RESPONSE;
+ }
+ net_log_.EndEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_DNS_TASK,
+ new DnsTaskFailedParams(net_error, result));
+ callback_.Run(net_error, AddressList(), base::TimeDelta());
+ }
+
+ private:
+ // The listener to the results of this DnsTask.
+ Callback callback_;
+
+ const BoundNetLog net_log_;
+
+ scoped_ptr<DnsTransaction> transaction_;
+};
+
+//-----------------------------------------------------------------------------
+
// Aggregates all Requests for the same Key. Dispatched via PriorityDispatch.
-// Spawns ProcTask when started.
class HostResolverImpl::Job : public PrioritizedDispatcher::Job {
public:
// Creates new job for |key| where |request_net_log| is bound to the
- // request that spawned it.
+ // request that spawned it and |priority| is the initial priority.
Job(HostResolverImpl* resolver,
const Key& key,
- const BoundNetLog& request_net_log)
+ const BoundNetLog& request_net_log,
+ RequestPriority priority)
: resolver_(resolver->AsWeakPtr()),
key_(key),
+ priority_tracker_(priority),
had_non_speculative_request_(false),
net_log_(BoundNetLog::Make(request_net_log.net_log(),
- NetLog::SOURCE_HOST_RESOLVER_IMPL_JOB)),
- net_error_(ERR_IO_PENDING),
- os_error_(0) {
+ NetLog::SOURCE_HOST_RESOLVER_IMPL_JOB)) {
request_net_log.AddEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_CREATE_JOB, NULL);
net_log_.BeginEvent(
NetLog::TYPE_HOST_RESOLVER_IMPL_JOB,
make_scoped_refptr(new JobCreationParameters(
key_.hostname, request_net_log.source())));
+
+ handle_ = resolver_->dispatcher_.Add(this, priority);
}
virtual ~Job() {
- if (net_error_ == ERR_IO_PENDING) {
- if (is_running()) {
- DCHECK_EQ(ERR_IO_PENDING, net_error_);
+ if (is_running()) {
+ // |resolver_| was destroyed with this Job still in flight.
+ // Clean-up, record in the log, but don't run any callbacks.
+ if (is_proc_running()) {
proc_task_->Cancel();
proc_task_ = NULL;
- net_error_ = ERR_ABORTED;
- } else {
- net_log_.AddEvent(NetLog::TYPE_CANCELLED, NULL);
- net_error_ = OK; // For NetLog.
}
+ net_log_.EndEventWithNetErrorCode(NetLog::TYPE_HOST_RESOLVER_IMPL_JOB,
+ ERR_ABORTED);
+ } else if (is_queued()) {
+ // This Job was cancelled without running.
+ // TODO(szym): is there's any benefit in having this distinction?
+ net_log_.AddEvent(NetLog::TYPE_CANCELLED, NULL);
+ net_log_.EndEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_JOB, NULL);
+ }
+ // else CompleteRequests logged EndEvent.
- for (RequestsList::const_iterator it = requests_.begin();
- it != requests_.end(); ++it) {
- Request* req = *it;
- if (req->was_canceled())
- continue;
- DCHECK_EQ(this, req->job());
- LogCancelRequest(req->source_net_log(), req->request_net_log(),
- req->info());
- }
+ // Log any remaining Requests as cancelled.
+ for (RequestsList::const_iterator it = requests_.begin();
+ it != requests_.end(); ++it) {
+ Request* req = *it;
+ if (req->was_canceled())
+ continue;
+ DCHECK_EQ(this, req->job());
+ LogCancelRequest(req->source_net_log(), req->request_net_log(),
+ req->info());
}
- net_log_.EndEventWithNetErrorCode(NetLog::TYPE_HOST_RESOLVER_IMPL_JOB,
- net_error_);
STLDeleteElements(&requests_);
}
- HostResolverImpl* resolver() const {
- return resolver_;
- }
-
RequestPriority priority() const {
return priority_tracker_.highest_priority();
}
@@ -1026,26 +1126,14 @@ class HostResolverImpl::Job : public PrioritizedDispatcher::Job {
return key_;
}
- int net_error() const {
- return net_error_;
- }
-
- // Used by HostResolverImpl with |dispatcher_|.
- const PrioritizedDispatcher::Handle& handle() const {
- return handle_;
- }
-
- void set_handle(const PrioritizedDispatcher::Handle& handle) {
- handle_ = handle;
+ bool is_queued() const {
+ return !handle_.is_null();
}
- // The Job will own |req| and destroy it in ~Job.
- void AddRequest(Request* req) {
+ void AddRequest(scoped_ptr<Request> req) {
DCHECK_EQ(key_.hostname, req->info().hostname());
req->set_job(this);
- requests_.push_back(req);
-
priority_tracker_.Add(req->info().priority());
req->request_net_log().AddEvent(
@@ -1064,6 +1152,11 @@ class HostResolverImpl::Job : public PrioritizedDispatcher::Job {
if (proc_task_)
proc_task_->set_had_non_speculative_request();
}
+
+ requests_.push_back(req.release());
+
+ if (!handle_.is_null())
+ handle_ = resolver_->dispatcher_.ChangePriority(handle_, priority());
}
void CancelRequest(Request* req) {
@@ -1078,44 +1171,80 @@ class HostResolverImpl::Job : public PrioritizedDispatcher::Job {
NetLog::TYPE_HOST_RESOLVER_IMPL_JOB_REQUEST_DETACH,
make_scoped_refptr(new JobAttachParameters(
req->request_net_log().source(), priority())));
+
+ if (!handle_.is_null()) {
+ if (num_active_requests() > 0) {
+ handle_ = resolver_->dispatcher_.ChangePriority(handle_, priority());
+ } else {
+ resolver_->dispatcher_.Cancel(handle_);
+ handle_.Reset();
+ }
+ }
}
// Aborts and destroys the job, completes all requests as aborted.
+ // The caller should clean up.
void Abort() {
// Job should only be aborted if it's running.
DCHECK(is_running());
- proc_task_->Cancel();
- proc_task_ = NULL;
- net_error_ = ERR_ABORTED;
- os_error_ = 0;
- CompleteRequests(AddressList());
+ if (is_proc_running()) {
+ proc_task_->Cancel();
+ proc_task_ = NULL;
+ }
+ dns_task_.reset();
+ CompleteRequests(ERR_ABORTED, AddressList(), base::TimeDelta());
}
- bool is_running() const {
+ bool is_dns_running() const {
+ return dns_task_.get() != NULL;
+ }
+
+ bool is_proc_running() const {
return proc_task_.get() != NULL;
}
+ bool is_running() const {
+ return is_dns_running() || is_proc_running();
+ }
+
// Called by HostResolverImpl when this job is evicted due to queue overflow.
void OnEvicted() {
// Must not be running.
DCHECK(!is_running());
- handle_ = PrioritizedDispatcher::Handle();
+ handle_.Reset();
net_log_.AddEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_JOB_EVICTED, NULL);
+ scoped_ptr<Job> self_deleter(this);
+ resolver_->RemoveJob(this);
+
// This signals to CompleteRequests that this job never ran.
- net_error_ = ERR_HOST_RESOLVER_QUEUE_TOO_LARGE;
- os_error_ = 0;
- CompleteRequests(AddressList());
+ CompleteRequests(ERR_HOST_RESOLVER_QUEUE_TOO_LARGE,
+ AddressList(),
+ base::TimeDelta());
}
// PriorityDispatch::Job interface.
virtual void Start() OVERRIDE {
DCHECK(!is_running());
- handle_ = PrioritizedDispatcher::Handle();
+ handle_.Reset();
net_log_.AddEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_JOB_STARTED, NULL);
+ if (resolver_->dns_transaction_factory_.get()) {
+ StartDnsTask();
+ } else {
+ StartProcTask();
+ }
+ }
+
+ private:
+ // TODO(szym): Since DnsTransaction does not consume threads, we can increase
+ // the limits on |dispatcher_|. But in order to keep the number of WorkerPool
+ // threads low, we will need to use an "inner" PrioritizedDispatcher with
+ // tighter limits.
+ void StartProcTask() {
+ DCHECK(!dns_task_.get());
proc_task_ = new ProcTask(
key_,
resolver_->proc_params_,
@@ -1129,33 +1258,82 @@ class HostResolverImpl::Job : public PrioritizedDispatcher::Job {
proc_task_->Start();
}
- private:
// Called by ProcTask when it completes.
- void OnProcTaskComplete(int net_error, int os_error,
- const AddressList& addrlist) {
- DCHECK(is_running());
+ void OnProcTaskComplete(int net_error, const AddressList& addr_list) {
+ DCHECK(is_proc_running());
+ // |addr_list| will be destroyed once we destroy |proc_task_|.
+ AddressList list = addr_list;
proc_task_ = NULL;
- net_error_ = net_error;
- os_error_ = os_error;
- // We are the only consumer of |addrlist|, so we can safely change the port
- // without copy-on-write. This pays off, when job has only one request.
- AddressList list = addrlist;
- if (net_error == OK && !requests_.empty())
- MutableSetPort(requests_.front()->info().port(), &list);
- CompleteRequests(list);
- }
-
- // Completes all Requests. Calls OnJobFinished and deletes self.
- void CompleteRequests(const AddressList& addrlist) {
- CHECK(resolver_);
+ base::TimeDelta ttl = base::TimeDelta::FromSeconds(
+ kNegativeCacheEntryTTLSeconds);
+ if (net_error == OK)
+ ttl = base::TimeDelta::FromSeconds(kCacheEntryTTLSeconds);
// This job must be removed from resolver's |jobs_| now to make room for a
// new job with the same key in case one of the OnComplete callbacks decides
// to spawn one. Consequently, the job deletes itself when CompleteRequests
// is done.
scoped_ptr<Job> self_deleter(this);
- resolver_->OnJobFinished(this, addrlist);
+ resolver_->OnJobFinished(this, net_error, list, ttl);
+
+ CompleteRequests(net_error, list, ttl);
+ }
+
+ void StartDnsTask() {
+ dns_task_.reset(new DnsTask(
+ resolver_->dns_transaction_factory_.get(),
+ key_,
+ base::Bind(&Job::OnDnsTaskComplete, base::Unretained(this)),
+ net_log_));
+
+ int rv = dns_task_->Start();
+ if (rv != ERR_IO_PENDING) {
+ DCHECK_NE(OK, rv);
+ dns_task_.reset();
+ StartProcTask();
+ }
+ }
+
+ // Called by DnsTask when it completes.
+ void OnDnsTaskComplete(int net_error,
+ const AddressList& addr_list,
+ base::TimeDelta ttl) {
+ DCHECK(is_dns_running());
+ // |addr_list| will be destroyed once we destroy |dns_task_|.
+ AddressList list = addr_list;
+ dns_task_.reset();
+
+ if (net_error != OK) {
+ // TODO(szym): Some net errors indicate lack of connectivity. Starting
+ // ProcTask in that case is a waste of time.
+ StartProcTask();
+ return;
+ }
+
+ // As in OnProcTaskComplete
+ scoped_ptr<Job> self_deleter(this);
+ resolver_->OnJobFinished(this, net_error, list, ttl);
+
+ CompleteRequests(net_error, list, ttl);
+ }
+
+ // Completes all Requests. Calls OnJobFinished and deletes self.
+ void CompleteRequests(int net_error,
+ const AddressList& addr_list,
+ base::TimeDelta ttl) {
+ CHECK(resolver_);
+ DCHECK(!is_running());
+ DCHECK(!is_queued());
+
+ // We are the only consumer of |addr_list|, so we can safely change the port
+ // without copy-on-write. This pays off, when job has only one request.
+ AddressList list = addr_list;
+ if (net_error == OK && !requests_.empty())
+ MutableSetPort(requests_.front()->info().port(), &list);
+
+ net_log_.EndEventWithNetErrorCode(NetLog::TYPE_HOST_RESOLVER_IMPL_JOB,
+ net_error);
// Complete all of the requests that were attached to the job.
for (RequestsList::const_iterator it = requests_.begin();
@@ -1168,9 +1346,9 @@ class HostResolverImpl::Job : public PrioritizedDispatcher::Job {
DCHECK_EQ(this, req->job());
// Update the net log and notify registered observers.
LogFinishRequest(req->source_net_log(), req->request_net_log(),
- req->info(), net_error_, os_error_);
+ req->info(), net_error);
- req->OnComplete(net_error_, addrlist);
+ req->OnComplete(net_error, list);
// Check if the resolver was destroyed as a result of running the
// callback. If it was, we could continue, but we choose to bail.
@@ -1179,7 +1357,7 @@ class HostResolverImpl::Job : public PrioritizedDispatcher::Job {
}
}
- // Used to call OnJobFinished and RemoveJob.
+ // Used to call OnJobFinished.
base::WeakPtr<HostResolverImpl> resolver_;
Key key_;
@@ -1191,17 +1369,16 @@ class HostResolverImpl::Job : public PrioritizedDispatcher::Job {
BoundNetLog net_log_;
- // Store result here in case the job fails fast in Resolve().
- int net_error_;
- int os_error_;
-
- // A ProcTask created and started when this Job is dispatched..
+ // Resolves the host using a HostResolverProc.
scoped_refptr<ProcTask> proc_task_;
+ // Resolves the host using a DnsTransaction.
+ scoped_ptr<DnsTask> dns_task_;
+
// All Requests waiting for the result of this Job. Some can be canceled.
RequestsList requests_;
- // A handle used by HostResolverImpl in |dispatcher_|.
+ // A handle used by |HostResolverImpl::dispatcher_|.
PrioritizedDispatcher::Handle handle_;
};
@@ -1222,12 +1399,14 @@ HostResolverImpl::HostResolverImpl(
HostCache* cache,
const PrioritizedDispatcher::Limits& job_limits,
const ProcTaskParams& proc_params,
+ scoped_ptr<DnsConfigService> dns_config_service,
NetLog* net_log)
: cache_(cache),
dispatcher_(job_limits),
max_queued_jobs_(job_limits.total_jobs * 100u),
proc_params_(proc_params),
default_address_family_(ADDRESS_FAMILY_UNSPECIFIED),
+ dns_config_service_(dns_config_service.Pass()),
ipv6_probe_monitoring_(false),
additional_resolver_flags_(0),
net_log_(net_log) {
@@ -1254,6 +1433,9 @@ HostResolverImpl::HostResolverImpl(
#endif
NetworkChangeNotifier::AddDNSObserver(this);
#endif
+
+ if (dns_config_service_.get())
+ dns_config_service_->AddObserver(this);
}
HostResolverImpl::~HostResolverImpl() {
@@ -1295,8 +1477,7 @@ int HostResolverImpl::Resolve(const RequestInfo& info,
int rv = ResolveHelper(key, info, addresses, request_net_log);
if (rv != ERR_DNS_CACHE_MISS) {
- LogFinishRequest(source_net_log, request_net_log, info, rv,
- 0 /* os_error (unknown since from cache) */);
+ LogFinishRequest(source_net_log, request_net_log, info, rv);
return rv;
}
@@ -1307,8 +1488,7 @@ int HostResolverImpl::Resolve(const RequestInfo& info,
Job* job;
if (jobit == jobs_.end()) {
// Create new Job.
- job = new Job(this, key, request_net_log);
- job->set_handle(dispatcher_.Add(job, info.priority()));
+ job = new Job(this, key, request_net_log, info.priority());
// Check for queue overflow.
if (dispatcher_.num_queued_jobs() > max_queued_jobs_) {
@@ -1317,27 +1497,26 @@ int HostResolverImpl::Resolve(const RequestInfo& info,
if (evicted == job) {
delete job;
rv = ERR_HOST_RESOLVER_QUEUE_TOO_LARGE;
- LogFinishRequest(source_net_log, request_net_log, info, rv, 0);
+ LogFinishRequest(source_net_log, request_net_log, info, rv);
return rv;
}
evicted->OnEvicted(); // Deletes |evicted|.
}
-
jobs_.insert(jobit, std::make_pair(key, job));
} else {
job = jobit->second;
}
// Can't complete synchronously. Create and attach request.
- Request* req = new Request(source_net_log, request_net_log, info, callback,
- addresses);
- job->AddRequest(req);
- if (!job->handle().is_null())
- job->set_handle(dispatcher_.ChangePriority(job->handle(), job->priority()));
+ scoped_ptr<Request> req(new Request(source_net_log,
+ request_net_log,
+ info,
+ callback,
+ addresses));
if (out_req)
- *out_req = reinterpret_cast<RequestHandle>(req);
+ *out_req = reinterpret_cast<RequestHandle>(req.get());
- DCHECK_EQ(ERR_IO_PENDING, job->net_error());
+ job->AddRequest(req.Pass());
// Completion happens during Job::CompleteRequests().
return ERR_IO_PENDING;
}
@@ -1376,8 +1555,7 @@ int HostResolverImpl::ResolveFromCache(const RequestInfo& info,
Key key = GetEffectiveKeyForRequest(info);
int rv = ResolveHelper(key, info, addresses, request_net_log);
- LogFinishRequest(source_net_log, request_net_log, info, rv,
- 0 /* os_error (unknown since from cache) */);
+ LogFinishRequest(source_net_log, request_net_log, info, rv);
return rv;
}
@@ -1391,23 +1569,14 @@ void HostResolverImpl::CancelRequest(RequestHandle req_handle) {
job->CancelRequest(req);
- if (!job->handle().is_null()) {
- // Still in queue.
- if (job->num_active_requests()) {
- job->set_handle(dispatcher_.ChangePriority(job->handle(),
- job->priority()));
- } else {
- dispatcher_.Cancel(job->handle());
- RemoveJob(job);
- delete job;
- }
- } else {
- // Job is running (and could be in CompleteRequests right now).
- // But to be in Request::OnComplete we would have to have a non-canceled
- // request. So it is safe to Abort it if it has no more active requests.
- if (!job->num_active_requests()) {
+ if (job->num_active_requests() == 0) {
+ // If we were called from a Requests' callback within Job::CompleteRequests,
+ // that Request could not have been cancelled, so job->num_active_requests()
+ // could not be 0. Therefore, we are not in Job::CompleteRequests().
+ RemoveJob(job);
+ if (job->is_running())
job->Abort();
- }
+ delete job;
}
}
@@ -1482,23 +1651,21 @@ bool HostResolverImpl::ServeFromCache(const Key& key,
return true;
}
-void HostResolverImpl::OnJobFinished(Job* job, const AddressList& addrlist) {
+void HostResolverImpl::OnJobFinished(Job* job,
+ int net_error,
+ const AddressList& addr_list,
+ base::TimeDelta ttl) {
DCHECK(job);
- DCHECK(job->handle().is_null());
- RemoveJob(job);
- if (job->net_error() == ERR_HOST_RESOLVER_QUEUE_TOO_LARGE)
- return;
+ DCHECK(!job->is_queued());
+ DCHECK_NE(ERR_HOST_RESOLVER_QUEUE_TOO_LARGE, net_error);
+ DCHECK_NE(ERR_ABORTED, net_error);
+ RemoveJob(job);
// Signal dispatcher that a slot has opened.
dispatcher_.OnJobFinished();
- if (job->net_error() == ERR_ABORTED)
- return;
// Write result to the cache.
if (cache_.get()) {
- base::TimeDelta ttl = base::TimeDelta::FromSeconds(0);
- if (job->net_error() == OK)
- ttl = base::TimeDelta::FromSeconds(kCacheEntryTTLSeconds);
- cache_->Set(job->key(), job->net_error(), addrlist,
+ cache_->Set(job->key(), net_error, addr_list,
base::TimeTicks::Now(), ttl);
}
}
@@ -1545,21 +1712,26 @@ HostResolverImpl::Key HostResolverImpl::GetEffectiveKeyForRequest(
void HostResolverImpl::AbortAllInProgressJobs() {
base::WeakPtr<HostResolverImpl> self = AsWeakPtr();
- // Scan |jobs_| for running jobs and abort them.
+ // In Abort, a Request callback could spawn new Jobs with matching keys, so
+ // first collect and remove all running jobs from |jobs_|.
+ std::vector<Job*> jobs_to_abort;
for (JobMap::iterator it = jobs_.begin(); it != jobs_.end(); ) {
Job* job = it->second;
- // Advance the iterator before we might erase it.
- ++it;
if (job->is_running()) {
- job->Abort();
- // Check if resolver was deleted in a request callback.
- if (!self)
- return;
+ jobs_to_abort.push_back(job);
+ jobs_.erase(it++);
} else {
- // Keep it in |dispatch_|.
- DCHECK(!job->handle().is_null());
+ DCHECK(job->is_queued());
+ ++it;
}
}
+
+ // Then Abort them and dispatch new Jobs.
+ for (size_t i = 0; i < jobs_to_abort.size(); ++i) {
+ jobs_to_abort[i]->Abort();
+ dispatcher_.OnJobFinished();
+ }
+ STLDeleteElements(&jobs_to_abort);
}
void HostResolverImpl::OnIPAddressChanged() {
@@ -1594,4 +1766,23 @@ void HostResolverImpl::OnDNSChanged() {
// |this| may be deleted inside AbortAllInProgressJobs().
}
+void HostResolverImpl::OnConfigChanged(const DnsConfig& dns_config) {
+ // We want a new factory in place, before we Abort running Jobs, so that the
+ // newly started jobs use the new factory.
+ bool had_factory = (dns_transaction_factory_.get() != NULL);
+ if (dns_config.IsValid()) {
+ dns_transaction_factory_ = DnsTransactionFactory::CreateFactory(
+ new DnsSession(dns_config,
+ ClientSocketFactory::GetDefaultFactory(),
+ base::Bind(&base::RandInt),
+ net_log_));
+ } else {
+ dns_transaction_factory_.reset();
+ }
+ // Don't Abort running Jobs unless they were running on DnsTransaction.
+ // TODO(szym): This will change once http://crbug.com/114827 is fixed.
+ if (had_factory)
+ OnDNSChanged();
+}
+
} // namespace net
« no previous file with comments | « net/base/host_resolver_impl.h ('k') | net/base/host_resolver_impl_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698