Updating trunk VERSION from 1014.0 to 1015.0
[chromium-blink-merge.git] / net / base / host_resolver_impl.cc
blob217f1e1329e678e0500a337fbc45cf9a33e165e1
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "net/base/host_resolver_impl.h"
7 #if defined(OS_WIN)
8 #include <Winsock2.h>
9 #elif defined(OS_POSIX)
10 #include <netdb.h>
11 #endif
13 #include <cmath>
14 #include <deque>
15 #include <vector>
17 #include "base/basictypes.h"
18 #include "base/bind.h"
19 #include "base/bind_helpers.h"
20 #include "base/compiler_specific.h"
21 #include "base/debug/debugger.h"
22 #include "base/debug/stack_trace.h"
23 #include "base/message_loop_proxy.h"
24 #include "base/metrics/field_trial.h"
25 #include "base/metrics/histogram.h"
26 #include "base/stl_util.h"
27 #include "base/string_util.h"
28 #include "base/threading/worker_pool.h"
29 #include "base/time.h"
30 #include "base/utf_string_conversions.h"
31 #include "base/values.h"
32 #include "net/base/address_list.h"
33 #include "net/base/address_list_net_log_param.h"
34 #include "net/base/dns_reloader.h"
35 #include "net/base/host_port_pair.h"
36 #include "net/base/host_resolver_proc.h"
37 #include "net/base/net_errors.h"
38 #include "net/base/net_log.h"
39 #include "net/base/net_util.h"
41 #if defined(OS_WIN)
42 #include "net/base/winsock_init.h"
43 #endif
45 namespace net {
47 namespace {
49 // Limit the size of hostnames that will be resolved to combat issues in
50 // some platform's resolvers.
51 const size_t kMaxHostLength = 4096;
53 // Helper to mutate the linked list contained by AddressList to the given
54 // port. Note that in general this is dangerous since the AddressList's
55 // data might be shared (and you should use AddressList::SetPort).
57 // However since we allocated the AddressList ourselves we can safely
58 // do this optimization and avoid reallocating the list.
59 void MutableSetPort(int port, AddressList* addrlist) {
60 struct addrinfo* mutable_head =
61 const_cast<struct addrinfo*>(addrlist->head());
62 SetPortForAllAddrinfos(mutable_head, port);
65 // We use a separate histogram name for each platform to facilitate the
66 // display of error codes by their symbolic name (since each platform has
67 // different mappings).
68 const char kOSErrorsForGetAddrinfoHistogramName[] =
69 #if defined(OS_WIN)
70 "Net.OSErrorsForGetAddrinfo_Win";
71 #elif defined(OS_MACOSX)
72 "Net.OSErrorsForGetAddrinfo_Mac";
73 #elif defined(OS_LINUX)
74 "Net.OSErrorsForGetAddrinfo_Linux";
75 #else
76 "Net.OSErrorsForGetAddrinfo";
77 #endif
79 // Gets a list of the likely error codes that getaddrinfo() can return
80 // (non-exhaustive). These are the error codes that we will track via
81 // a histogram.
82 std::vector<int> GetAllGetAddrinfoOSErrors() {
83 int os_errors[] = {
84 #if defined(OS_POSIX)
85 #if !defined(OS_FREEBSD)
86 #if !defined(OS_ANDROID)
87 // EAI_ADDRFAMILY has been declared obsolete in Android's and
88 // FreeBSD's netdb.h.
89 EAI_ADDRFAMILY,
90 #endif
91 // EAI_NODATA has been declared obsolete in FreeBSD's netdb.h.
92 EAI_NODATA,
93 #endif
94 EAI_AGAIN,
95 EAI_BADFLAGS,
96 EAI_FAIL,
97 EAI_FAMILY,
98 EAI_MEMORY,
99 EAI_NONAME,
100 EAI_SERVICE,
101 EAI_SOCKTYPE,
102 EAI_SYSTEM,
103 #elif defined(OS_WIN)
104 // See: http://msdn.microsoft.com/en-us/library/ms738520(VS.85).aspx
105 WSA_NOT_ENOUGH_MEMORY,
106 WSAEAFNOSUPPORT,
107 WSAEINVAL,
108 WSAESOCKTNOSUPPORT,
109 WSAHOST_NOT_FOUND,
110 WSANO_DATA,
111 WSANO_RECOVERY,
112 WSANOTINITIALISED,
113 WSATRY_AGAIN,
114 WSATYPE_NOT_FOUND,
115 // The following are not in doc, but might be to appearing in results :-(.
116 WSA_INVALID_HANDLE,
117 #endif
120 // Ensure all errors are positive, as histogram only tracks positive values.
121 for (size_t i = 0; i < arraysize(os_errors); ++i) {
122 os_errors[i] = std::abs(os_errors[i]);
125 return base::CustomHistogram::ArrayToCustomRanges(os_errors,
126 arraysize(os_errors));
129 } // anonymous namespace
131 // static
132 HostResolver* CreateSystemHostResolver(size_t max_concurrent_resolves,
133 size_t max_retry_attempts,
134 NetLog* net_log) {
135 // Maximum of 8 concurrent resolver threads.
136 // Some routers (or resolvers) appear to start to provide host-not-found if
137 // too many simultaneous resolutions are pending. This number needs to be
138 // further optimized, but 8 is what FF currently does.
139 static const size_t kDefaultMaxJobs = 8u;
141 if (max_concurrent_resolves == HostResolver::kDefaultParallelism)
142 max_concurrent_resolves = kDefaultMaxJobs;
144 HostResolverImpl* resolver =
145 new HostResolverImpl(NULL, HostCache::CreateDefaultCache(),
146 max_concurrent_resolves, max_retry_attempts, net_log);
148 return resolver;
151 static int ResolveAddrInfo(HostResolverProc* resolver_proc,
152 const std::string& host,
153 AddressFamily address_family,
154 HostResolverFlags host_resolver_flags,
155 AddressList* out,
156 int* os_error) {
157 if (resolver_proc) {
158 // Use the custom procedure.
159 return resolver_proc->Resolve(host, address_family,
160 host_resolver_flags, out, os_error);
161 } else {
162 // Use the system procedure (getaddrinfo).
163 return SystemHostResolverProc(host, address_family,
164 host_resolver_flags, out, os_error);
168 // Extra parameters to attach to the NetLog when the resolve failed.
169 class HostResolveFailedParams : public NetLog::EventParameters {
170 public:
171 HostResolveFailedParams(uint32 attempt_number,
172 int net_error,
173 int os_error)
174 : attempt_number_(attempt_number),
175 net_error_(net_error),
176 os_error_(os_error) {
179 virtual Value* ToValue() const {
180 DictionaryValue* dict = new DictionaryValue();
181 if (attempt_number_)
182 dict->SetInteger("attempt_number", attempt_number_);
184 dict->SetInteger("net_error", net_error_);
186 if (os_error_) {
187 dict->SetInteger("os_error", os_error_);
188 #if defined(OS_POSIX)
189 dict->SetString("os_error_string", gai_strerror(os_error_));
190 #elif defined(OS_WIN)
191 // Map the error code to a human-readable string.
192 LPWSTR error_string = NULL;
193 int size = FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
194 FORMAT_MESSAGE_FROM_SYSTEM,
195 0, // Use the internal message table.
196 os_error_,
197 0, // Use default language.
198 (LPWSTR)&error_string,
199 0, // Buffer size.
200 0); // Arguments (unused).
201 dict->SetString("os_error_string", WideToUTF8(error_string));
202 LocalFree(error_string);
203 #endif
206 return dict;
209 private:
210 const uint32 attempt_number_;
211 const int net_error_;
212 const int os_error_;
215 // Parameters representing the information in a RequestInfo object, along with
216 // the associated NetLog::Source.
217 class RequestInfoParameters : public NetLog::EventParameters {
218 public:
219 RequestInfoParameters(const HostResolver::RequestInfo& info,
220 const NetLog::Source& source)
221 : info_(info), source_(source) {}
223 virtual Value* ToValue() const {
224 DictionaryValue* dict = new DictionaryValue();
225 dict->SetString("host", info_.host_port_pair().ToString());
226 dict->SetInteger("address_family",
227 static_cast<int>(info_.address_family()));
228 dict->SetBoolean("allow_cached_response", info_.allow_cached_response());
229 dict->SetBoolean("is_speculative", info_.is_speculative());
230 dict->SetInteger("priority", info_.priority());
232 if (source_.is_valid())
233 dict->Set("source_dependency", source_.ToValue());
235 return dict;
238 private:
239 const HostResolver::RequestInfo info_;
240 const NetLog::Source source_;
243 // Parameters associated with the creation of a HostResolverImpl::Job.
244 class JobCreationParameters : public NetLog::EventParameters {
245 public:
246 JobCreationParameters(const std::string& host, const NetLog::Source& source)
247 : host_(host), source_(source) {}
249 virtual Value* ToValue() const {
250 DictionaryValue* dict = new DictionaryValue();
251 dict->SetString("host", host_);
252 dict->Set("source_dependency", source_.ToValue());
253 return dict;
256 private:
257 const std::string host_;
258 const NetLog::Source source_;
261 //-----------------------------------------------------------------------------
263 class HostResolverImpl::Request {
264 public:
265 Request(const BoundNetLog& source_net_log,
266 const BoundNetLog& request_net_log,
267 const RequestInfo& info,
268 const CompletionCallback& callback,
269 AddressList* addresses)
270 : source_net_log_(source_net_log),
271 request_net_log_(request_net_log),
272 info_(info),
273 job_(NULL),
274 callback_(callback),
275 addresses_(addresses) {
278 // Mark the request as cancelled.
279 void MarkAsCancelled() {
280 job_ = NULL;
281 addresses_ = NULL;
282 callback_.Reset();
285 bool was_cancelled() const {
286 return callback_.is_null();
289 void set_job(Job* job) {
290 DCHECK(job != NULL);
291 // Identify which job the request is waiting on.
292 job_ = job;
295 void OnComplete(int error, const AddressList& addrlist) {
296 if (error == OK)
297 *addresses_ = CreateAddressListUsingPort(addrlist, port());
298 CompletionCallback callback = callback_;
299 MarkAsCancelled();
300 callback.Run(error);
303 int port() const {
304 return info_.port();
307 Job* job() const {
308 return job_;
311 const BoundNetLog& source_net_log() {
312 return source_net_log_;
315 const BoundNetLog& request_net_log() {
316 return request_net_log_;
319 const RequestInfo& info() const {
320 return info_;
323 private:
324 BoundNetLog source_net_log_;
325 BoundNetLog request_net_log_;
327 // The request info that started the request.
328 RequestInfo info_;
330 // The resolve job (running in worker pool) that this request is dependent on.
331 Job* job_;
333 // The user's callback to invoke when the request completes.
334 CompletionCallback callback_;
336 // The address list to save result into.
337 AddressList* addresses_;
339 DISALLOW_COPY_AND_ASSIGN(Request);
342 //------------------------------------------------------------------------------
344 // Provide a common macro to simplify code and readability. We must use a
345 // macros as the underlying HISTOGRAM macro creates static varibles.
346 #define DNS_HISTOGRAM(name, time) UMA_HISTOGRAM_CUSTOM_TIMES(name, time, \
347 base::TimeDelta::FromMicroseconds(1), base::TimeDelta::FromHours(1), 100)
349 // This class represents a request to the worker pool for a "getaddrinfo()"
350 // call.
351 class HostResolverImpl::Job
352 : public base::RefCountedThreadSafe<HostResolverImpl::Job> {
353 public:
354 Job(int id,
355 HostResolverImpl* resolver,
356 const Key& key,
357 const BoundNetLog& source_net_log,
358 NetLog* net_log)
359 : id_(id),
360 key_(key),
361 resolver_(resolver),
362 origin_loop_(base::MessageLoopProxy::current()),
363 resolver_proc_(resolver->effective_resolver_proc()),
364 unresponsive_delay_(resolver->unresponsive_delay()),
365 attempt_number_(0),
366 completed_attempt_number_(0),
367 completed_attempt_error_(ERR_UNEXPECTED),
368 had_non_speculative_request_(false),
369 net_log_(BoundNetLog::Make(net_log,
370 NetLog::SOURCE_HOST_RESOLVER_IMPL_JOB)) {
371 DCHECK(resolver);
372 net_log_.BeginEvent(
373 NetLog::TYPE_HOST_RESOLVER_IMPL_JOB,
374 make_scoped_refptr(
375 new JobCreationParameters(key.hostname, source_net_log.source())));
378 // Attaches a request to this job. The job takes ownership of |req| and will
379 // take care to delete it.
380 void AddRequest(Request* req) {
381 DCHECK(origin_loop_->BelongsToCurrentThread());
382 req->request_net_log().BeginEvent(
383 NetLog::TYPE_HOST_RESOLVER_IMPL_JOB_ATTACH,
384 make_scoped_refptr(new NetLogSourceParameter(
385 "source_dependency", net_log_.source())));
387 req->set_job(this);
388 requests_.push_back(req);
390 if (!req->info().is_speculative())
391 had_non_speculative_request_ = true;
394 void Start() {
395 DCHECK(origin_loop_->BelongsToCurrentThread());
396 StartLookupAttempt();
399 void StartLookupAttempt() {
400 DCHECK(origin_loop_->BelongsToCurrentThread());
401 base::TimeTicks start_time = base::TimeTicks::Now();
402 ++attempt_number_;
403 // Dispatch the lookup attempt to a worker thread.
404 if (!base::WorkerPool::PostTask(
405 FROM_HERE,
406 base::Bind(&Job::DoLookup, this, start_time, attempt_number_),
407 true)) {
408 NOTREACHED();
410 // Since we could be running within Resolve() right now, we can't just
411 // call OnLookupComplete(). Instead we must wait until Resolve() has
412 // returned (IO_PENDING).
413 origin_loop_->PostTask(
414 FROM_HERE,
415 base::Bind(&Job::OnLookupComplete, this, AddressList(),
416 start_time, attempt_number_, ERR_UNEXPECTED, 0));
417 return;
420 net_log_.AddEvent(
421 NetLog::TYPE_HOST_RESOLVER_IMPL_ATTEMPT_STARTED,
422 make_scoped_refptr(new NetLogIntegerParameter(
423 "attempt_number", attempt_number_)));
425 // Post a task to check if we get the results within a given time.
426 // OnCheckForComplete has the potential for starting a new attempt on a
427 // different worker thread if none of our outstanding attempts have
428 // completed yet.
429 if (attempt_number_ <= resolver_->max_retry_attempts()) {
430 origin_loop_->PostDelayedTask(
431 FROM_HERE,
432 base::Bind(&Job::OnCheckForComplete, this),
433 unresponsive_delay_.InMilliseconds());
437 // Cancels the current job. The Job will be orphaned. Any outstanding resolve
438 // attempts running on worker threads will continue running. Only once all the
439 // attempts complete will the final reference to this Job be released.
440 void Cancel() {
441 DCHECK(origin_loop_->BelongsToCurrentThread());
442 net_log_.AddEvent(NetLog::TYPE_CANCELLED, NULL);
444 HostResolver* resolver = resolver_;
445 resolver_ = NULL;
447 // End here to prevent issues when a Job outlives the HostResolver that
448 // spawned it.
449 net_log_.EndEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_JOB, NULL);
451 // We will call HostResolverImpl::CancelRequest(Request*) on each one
452 // in order to notify any observers.
453 for (RequestsList::const_iterator it = requests_.begin();
454 it != requests_.end(); ++it) {
455 HostResolverImpl::Request* req = *it;
456 if (!req->was_cancelled())
457 resolver->CancelRequest(req);
461 bool was_cancelled() const {
462 DCHECK(origin_loop_->BelongsToCurrentThread());
463 return resolver_ == NULL;
466 bool was_completed() const {
467 DCHECK(origin_loop_->BelongsToCurrentThread());
468 return completed_attempt_number_ > 0;
471 const Key& key() const {
472 DCHECK(origin_loop_->BelongsToCurrentThread());
473 return key_;
476 int id() const {
477 DCHECK(origin_loop_->BelongsToCurrentThread());
478 return id_;
481 const RequestsList& requests() const {
482 DCHECK(origin_loop_->BelongsToCurrentThread());
483 return requests_;
486 // Returns the first request attached to the job.
487 const Request* initial_request() const {
488 DCHECK(origin_loop_->BelongsToCurrentThread());
489 DCHECK(!requests_.empty());
490 return requests_[0];
493 // Returns true if |req_info| can be fulfilled by this job.
494 bool CanServiceRequest(const RequestInfo& req_info) const {
495 DCHECK(origin_loop_->BelongsToCurrentThread());
496 return key_ == resolver_->GetEffectiveKeyForRequest(req_info);
499 private:
500 friend class base::RefCountedThreadSafe<HostResolverImpl::Job>;
502 ~Job() {
503 // Free the requests attached to this job.
504 STLDeleteElements(&requests_);
507 // WARNING: This code runs inside a worker pool. The shutdown code cannot
508 // wait for it to finish, so we must be very careful here about using other
509 // objects (like MessageLoops, Singletons, etc). During shutdown these objects
510 // may no longer exist. Multiple DoLookups() could be running in parallel, so
511 // any state inside of |this| must not mutate .
512 void DoLookup(const base::TimeTicks& start_time,
513 const uint32 attempt_number) {
514 AddressList results;
515 int os_error = 0;
516 // Running on the worker thread
517 int error = ResolveAddrInfo(resolver_proc_,
518 key_.hostname,
519 key_.address_family,
520 key_.host_resolver_flags,
521 &results,
522 &os_error);
524 origin_loop_->PostTask(
525 FROM_HERE,
526 base::Bind(&Job::OnLookupComplete, this, results, start_time,
527 attempt_number, error, os_error));
530 // Callback to see if DoLookup() has finished or not (runs on origin thread).
531 void OnCheckForComplete() {
532 DCHECK(origin_loop_->BelongsToCurrentThread());
534 if (was_completed() || was_cancelled())
535 return;
537 DCHECK(resolver_);
538 unresponsive_delay_ *= resolver_->retry_factor();
539 StartLookupAttempt();
542 // Callback for when DoLookup() completes (runs on origin thread).
543 void OnLookupComplete(const AddressList& results,
544 const base::TimeTicks& start_time,
545 const uint32 attempt_number,
546 int error,
547 const int os_error) {
548 DCHECK(origin_loop_->BelongsToCurrentThread());
549 DCHECK(error || results.head());
551 bool was_retry_attempt = attempt_number > 1;
553 if (!was_cancelled()) {
554 scoped_refptr<NetLog::EventParameters> params;
555 if (error != OK) {
556 params = new HostResolveFailedParams(attempt_number, error, os_error);
557 } else {
558 params = new NetLogIntegerParameter("attempt_number", attempt_number_);
560 net_log_.AddEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_ATTEMPT_FINISHED,
561 params);
563 // If host is already resolved, then record data and return.
564 if (was_completed()) {
565 // If this is the first attempt that is finishing later, then record
566 // data for the first attempt. Won't contaminate with retry attempt's
567 // data.
568 if (!was_retry_attempt)
569 RecordPerformanceHistograms(start_time, error, os_error);
571 RecordAttemptHistograms(start_time, attempt_number, error, os_error);
572 return;
575 // Copy the results from the first worker thread that resolves the host.
576 results_ = results;
577 completed_attempt_number_ = attempt_number;
578 completed_attempt_error_ = error;
581 // Ideally the following code would be part of host_resolver_proc.cc,
582 // however it isn't safe to call NetworkChangeNotifier from worker
583 // threads. So we do it here on the IO thread instead.
584 if (error != OK && NetworkChangeNotifier::IsOffline())
585 error = ERR_INTERNET_DISCONNECTED;
587 // We will record data for the first attempt. Don't contaminate with retry
588 // attempt's data.
589 if (!was_retry_attempt)
590 RecordPerformanceHistograms(start_time, error, os_error);
592 RecordAttemptHistograms(start_time, attempt_number, error, os_error);
594 if (was_cancelled())
595 return;
597 if (was_retry_attempt) {
598 // If retry attempt finishes before 1st attempt, then get stats on how
599 // much time is saved by having spawned an extra attempt.
600 retry_attempt_finished_time_ = base::TimeTicks::Now();
603 scoped_refptr<NetLog::EventParameters> params;
604 if (error != OK) {
605 params = new HostResolveFailedParams(0, error, os_error);
606 } else {
607 params = new AddressListNetLogParam(results_);
610 // End here to prevent issues when a Job outlives the HostResolver that
611 // spawned it.
612 net_log_.EndEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_JOB, params);
614 DCHECK(!requests_.empty());
616 // Use the port number of the first request.
617 if (error == OK)
618 MutableSetPort(requests_[0]->port(), &results_);
620 resolver_->OnJobComplete(this, error, os_error, results_);
623 void RecordPerformanceHistograms(const base::TimeTicks& start_time,
624 const int error,
625 const int os_error) const {
626 DCHECK(origin_loop_->BelongsToCurrentThread());
627 enum Category { // Used in HISTOGRAM_ENUMERATION.
628 RESOLVE_SUCCESS,
629 RESOLVE_FAIL,
630 RESOLVE_SPECULATIVE_SUCCESS,
631 RESOLVE_SPECULATIVE_FAIL,
632 RESOLVE_MAX, // Bounding value.
634 int category = RESOLVE_MAX; // Illegal value for later DCHECK only.
636 base::TimeDelta duration = base::TimeTicks::Now() - start_time;
637 if (error == OK) {
638 if (had_non_speculative_request_) {
639 category = RESOLVE_SUCCESS;
640 DNS_HISTOGRAM("DNS.ResolveSuccess", duration);
641 } else {
642 category = RESOLVE_SPECULATIVE_SUCCESS;
643 DNS_HISTOGRAM("DNS.ResolveSpeculativeSuccess", duration);
646 // Log DNS lookups based on address_family. This will help us determine
647 // if IPv4 or IPv4/6 lookups are faster or slower.
648 switch(key_.address_family) {
649 case ADDRESS_FAMILY_IPV4:
650 DNS_HISTOGRAM("DNS.ResolveSuccess_FAMILY_IPV4", duration);
651 break;
652 case ADDRESS_FAMILY_IPV6:
653 DNS_HISTOGRAM("DNS.ResolveSuccess_FAMILY_IPV6", duration);
654 break;
655 case ADDRESS_FAMILY_UNSPECIFIED:
656 DNS_HISTOGRAM("DNS.ResolveSuccess_FAMILY_UNSPEC", duration);
657 break;
659 } else {
660 if (had_non_speculative_request_) {
661 category = RESOLVE_FAIL;
662 DNS_HISTOGRAM("DNS.ResolveFail", duration);
663 } else {
664 category = RESOLVE_SPECULATIVE_FAIL;
665 DNS_HISTOGRAM("DNS.ResolveSpeculativeFail", duration);
667 // Log DNS lookups based on address_family. This will help us determine
668 // if IPv4 or IPv4/6 lookups are faster or slower.
669 switch(key_.address_family) {
670 case ADDRESS_FAMILY_IPV4:
671 DNS_HISTOGRAM("DNS.ResolveFail_FAMILY_IPV4", duration);
672 break;
673 case ADDRESS_FAMILY_IPV6:
674 DNS_HISTOGRAM("DNS.ResolveFail_FAMILY_IPV6", duration);
675 break;
676 case ADDRESS_FAMILY_UNSPECIFIED:
677 DNS_HISTOGRAM("DNS.ResolveFail_FAMILY_UNSPEC", duration);
678 break;
680 UMA_HISTOGRAM_CUSTOM_ENUMERATION(kOSErrorsForGetAddrinfoHistogramName,
681 std::abs(os_error),
682 GetAllGetAddrinfoOSErrors());
684 DCHECK_LT(category, static_cast<int>(RESOLVE_MAX)); // Be sure it was set.
686 UMA_HISTOGRAM_ENUMERATION("DNS.ResolveCategory", category, RESOLVE_MAX);
688 static const bool show_speculative_experiment_histograms =
689 base::FieldTrialList::TrialExists("DnsImpact");
690 if (show_speculative_experiment_histograms) {
691 UMA_HISTOGRAM_ENUMERATION(
692 base::FieldTrial::MakeName("DNS.ResolveCategory", "DnsImpact"),
693 category, RESOLVE_MAX);
694 if (RESOLVE_SUCCESS == category) {
695 DNS_HISTOGRAM(base::FieldTrial::MakeName("DNS.ResolveSuccess",
696 "DnsImpact"), duration);
699 static const bool show_parallelism_experiment_histograms =
700 base::FieldTrialList::TrialExists("DnsParallelism");
701 if (show_parallelism_experiment_histograms) {
702 UMA_HISTOGRAM_ENUMERATION(
703 base::FieldTrial::MakeName("DNS.ResolveCategory", "DnsParallelism"),
704 category, RESOLVE_MAX);
705 if (RESOLVE_SUCCESS == category) {
706 DNS_HISTOGRAM(base::FieldTrial::MakeName("DNS.ResolveSuccess",
707 "DnsParallelism"), duration);
712 void RecordAttemptHistograms(const base::TimeTicks& start_time,
713 const uint32 attempt_number,
714 const int error,
715 const int os_error) const {
716 bool first_attempt_to_complete =
717 completed_attempt_number_ == attempt_number;
718 bool is_first_attempt = (attempt_number == 1);
720 if (first_attempt_to_complete) {
721 // If this was first attempt to complete, then record the resolution
722 // status of the attempt.
723 if (completed_attempt_error_ == OK) {
724 UMA_HISTOGRAM_ENUMERATION(
725 "DNS.AttemptFirstSuccess", attempt_number, 100);
726 } else {
727 UMA_HISTOGRAM_ENUMERATION(
728 "DNS.AttemptFirstFailure", attempt_number, 100);
732 if (error == OK)
733 UMA_HISTOGRAM_ENUMERATION("DNS.AttemptSuccess", attempt_number, 100);
734 else
735 UMA_HISTOGRAM_ENUMERATION("DNS.AttemptFailure", attempt_number, 100);
737 // If first attempt didn't finish before retry attempt, then calculate stats
738 // on how much time is saved by having spawned an extra attempt.
739 if (!first_attempt_to_complete && is_first_attempt && !was_cancelled()) {
740 DNS_HISTOGRAM("DNS.AttemptTimeSavedByRetry",
741 base::TimeTicks::Now() - retry_attempt_finished_time_);
744 if (was_cancelled() || !first_attempt_to_complete) {
745 // Count those attempts which completed after the job was already canceled
746 // OR after the job was already completed by an earlier attempt (so in
747 // effect).
748 UMA_HISTOGRAM_ENUMERATION("DNS.AttemptDiscarded", attempt_number, 100);
750 // Record if job is cancelled.
751 if (was_cancelled())
752 UMA_HISTOGRAM_ENUMERATION("DNS.AttemptCancelled", attempt_number, 100);
755 base::TimeDelta duration = base::TimeTicks::Now() - start_time;
756 if (error == OK)
757 DNS_HISTOGRAM("DNS.AttemptSuccessDuration", duration);
758 else
759 DNS_HISTOGRAM("DNS.AttemptFailDuration", duration);
762 // Immutable. Can be read from either thread,
763 const int id_;
765 // Set on the origin thread, read on the worker thread.
766 Key key_;
768 // Only used on the origin thread (where Resolve was called).
769 HostResolverImpl* resolver_;
770 RequestsList requests_; // The requests waiting on this job.
772 // Used to post ourselves onto the origin thread.
773 scoped_refptr<base::MessageLoopProxy> origin_loop_;
775 // Hold an owning reference to the HostResolverProc that we are going to use.
776 // This may not be the current resolver procedure by the time we call
777 // ResolveAddrInfo, but that's OK... we'll use it anyways, and the owning
778 // reference ensures that it remains valid until we are done.
779 scoped_refptr<HostResolverProc> resolver_proc_;
781 // The amount of time after starting a resolution attempt until deciding to
782 // retry.
783 base::TimeDelta unresponsive_delay_;
785 // Keeps track of the number of attempts we have made so far to resolve the
786 // host. Whenever we start an attempt to resolve the host, we increase this
787 // number.
788 uint32 attempt_number_;
790 // The index of the attempt which finished first (or 0 if the job is still in
791 // progress).
792 uint32 completed_attempt_number_;
794 // The result (a net error code) from the first attempt to complete.
795 int completed_attempt_error_;
797 // The time when retry attempt was finished.
798 base::TimeTicks retry_attempt_finished_time_;
800 // True if a non-speculative request was ever attached to this job
801 // (regardless of whether or not it was later cancelled.
802 // This boolean is used for histogramming the duration of jobs used to
803 // service non-speculative requests.
804 bool had_non_speculative_request_;
806 AddressList results_;
808 BoundNetLog net_log_;
810 DISALLOW_COPY_AND_ASSIGN(Job);
813 //-----------------------------------------------------------------------------
815 // This class represents a request to the worker pool for a "probe for IPv6
816 // support" call.
817 class HostResolverImpl::IPv6ProbeJob
818 : public base::RefCountedThreadSafe<HostResolverImpl::IPv6ProbeJob> {
819 public:
820 explicit IPv6ProbeJob(HostResolverImpl* resolver)
821 : resolver_(resolver),
822 origin_loop_(base::MessageLoopProxy::current()) {
823 DCHECK(resolver);
826 void Start() {
827 DCHECK(origin_loop_->BelongsToCurrentThread());
828 if (was_cancelled())
829 return;
830 const bool kIsSlow = true;
831 base::WorkerPool::PostTask(
832 FROM_HERE, base::Bind(&IPv6ProbeJob::DoProbe, this), kIsSlow);
835 // Cancels the current job.
836 void Cancel() {
837 DCHECK(origin_loop_->BelongsToCurrentThread());
838 if (was_cancelled())
839 return;
840 resolver_ = NULL; // Read/write ONLY on origin thread.
843 private:
844 friend class base::RefCountedThreadSafe<HostResolverImpl::IPv6ProbeJob>;
846 ~IPv6ProbeJob() {
849 bool was_cancelled() const {
850 DCHECK(origin_loop_->BelongsToCurrentThread());
851 return !resolver_;
854 // Run on worker thread.
855 void DoProbe() {
856 // Do actual testing on this thread, as it takes 40-100ms.
857 AddressFamily family = IPv6Supported() ? ADDRESS_FAMILY_UNSPECIFIED
858 : ADDRESS_FAMILY_IPV4;
860 origin_loop_->PostTask(
861 FROM_HERE,
862 base::Bind(&IPv6ProbeJob::OnProbeComplete, this, family));
865 // Callback for when DoProbe() completes.
866 void OnProbeComplete(AddressFamily address_family) {
867 DCHECK(origin_loop_->BelongsToCurrentThread());
868 if (was_cancelled())
869 return;
870 resolver_->IPv6ProbeSetDefaultAddressFamily(address_family);
873 // Used/set only on origin thread.
874 HostResolverImpl* resolver_;
876 // Used to post ourselves onto the origin thread.
877 scoped_refptr<base::MessageLoopProxy> origin_loop_;
879 DISALLOW_COPY_AND_ASSIGN(IPv6ProbeJob);
882 //-----------------------------------------------------------------------------
884 // We rely on the priority enum values being sequential having starting at 0,
885 // and increasing for lower priorities.
886 COMPILE_ASSERT(HIGHEST == 0u &&
887 LOWEST > HIGHEST &&
888 IDLE > LOWEST &&
889 NUM_PRIORITIES > IDLE,
890 priority_indexes_incompatible);
892 // JobPool contains all the information relating to queued requests, including
893 // the limits on how many jobs are allowed to be used for this category of
894 // requests.
895 class HostResolverImpl::JobPool {
896 public:
897 JobPool(size_t max_outstanding_jobs, size_t max_pending_requests)
898 : num_outstanding_jobs_(0u) {
899 SetConstraints(max_outstanding_jobs, max_pending_requests);
902 ~JobPool() {
903 // Free the pending requests.
904 for (size_t i = 0; i < arraysize(pending_requests_); ++i)
905 STLDeleteElements(&pending_requests_[i]);
908 // Sets the constraints for this pool. See SetPoolConstraints() for the
909 // specific meaning of these parameters.
910 void SetConstraints(size_t max_outstanding_jobs,
911 size_t max_pending_requests) {
912 CHECK_NE(max_outstanding_jobs, 0u);
913 max_outstanding_jobs_ = max_outstanding_jobs;
914 max_pending_requests_ = max_pending_requests;
917 // Returns the number of pending requests enqueued to this pool.
918 // A pending request is one waiting to be attached to a job.
919 size_t GetNumPendingRequests() const {
920 size_t total = 0u;
921 for (size_t i = 0u; i < arraysize(pending_requests_); ++i)
922 total += pending_requests_[i].size();
923 return total;
926 bool HasPendingRequests() const {
927 return GetNumPendingRequests() > 0u;
930 // Enqueues a request to this pool. As a result of enqueing this request,
931 // the queue may have reached its maximum size. In this case, a request is
932 // evicted from the queue, and returned. Otherwise returns NULL. The caller
933 // is responsible for freeing the evicted request.
934 Request* InsertPendingRequest(Request* req) {
935 req->request_net_log().BeginEvent(
936 NetLog::TYPE_HOST_RESOLVER_IMPL_JOB_POOL_QUEUE,
937 NULL);
939 PendingRequestsQueue& q = pending_requests_[req->info().priority()];
940 q.push_back(req);
942 // If the queue is too big, kick out the lowest priority oldest request.
943 if (GetNumPendingRequests() > max_pending_requests_) {
944 // Iterate over the queues from lowest priority to highest priority.
945 for (int i = static_cast<int>(arraysize(pending_requests_)) - 1;
946 i >= 0; --i) {
947 PendingRequestsQueue& q = pending_requests_[i];
948 if (!q.empty()) {
949 Request* req = q.front();
950 q.pop_front();
951 req->request_net_log().AddEvent(
952 NetLog::TYPE_HOST_RESOLVER_IMPL_JOB_POOL_QUEUE_EVICTED, NULL);
953 req->request_net_log().EndEvent(
954 NetLog::TYPE_HOST_RESOLVER_IMPL_JOB_POOL_QUEUE, NULL);
955 return req;
960 return NULL;
963 // Erases |req| from this container. Caller is responsible for freeing
964 // |req| afterwards.
965 void RemovePendingRequest(Request* req) {
966 PendingRequestsQueue& q = pending_requests_[req->info().priority()];
967 PendingRequestsQueue::iterator it = std::find(q.begin(), q.end(), req);
968 DCHECK(it != q.end());
969 q.erase(it);
970 req->request_net_log().EndEvent(
971 NetLog::TYPE_HOST_RESOLVER_IMPL_JOB_POOL_QUEUE, NULL);
974 // Removes and returns the highest priority pending request.
975 Request* RemoveTopPendingRequest() {
976 DCHECK(HasPendingRequests());
978 for (size_t i = 0u; i < arraysize(pending_requests_); ++i) {
979 PendingRequestsQueue& q = pending_requests_[i];
980 if (!q.empty()) {
981 Request* req = q.front();
982 q.pop_front();
983 req->request_net_log().EndEvent(
984 NetLog::TYPE_HOST_RESOLVER_IMPL_JOB_POOL_QUEUE, NULL);
985 return req;
989 NOTREACHED();
990 return NULL;
993 // Keeps track of a job that was just added/removed, and belongs to this pool.
994 void AdjustNumOutstandingJobs(int offset) {
995 DCHECK(offset == 1 || (offset == -1 && num_outstanding_jobs_ > 0u));
996 num_outstanding_jobs_ += offset;
999 void ResetNumOutstandingJobs() {
1000 num_outstanding_jobs_ = 0;
1003 // Returns true if a new job can be created for this pool.
1004 bool CanCreateJob() const {
1005 return num_outstanding_jobs_ + 1u <= max_outstanding_jobs_;
1008 // Removes any pending requests from the queue which are for the
1009 // same (hostname / effective address-family) as |job|, and attaches them to
1010 // |job|.
1011 void MoveRequestsToJob(Job* job) {
1012 for (size_t i = 0u; i < arraysize(pending_requests_); ++i) {
1013 PendingRequestsQueue& q = pending_requests_[i];
1014 PendingRequestsQueue::iterator req_it = q.begin();
1015 while (req_it != q.end()) {
1016 Request* req = *req_it;
1017 if (job->CanServiceRequest(req->info())) {
1018 // Job takes ownership of |req|.
1019 job->AddRequest(req);
1020 req_it = q.erase(req_it);
1021 } else {
1022 ++req_it;
1028 private:
1029 typedef std::deque<Request*> PendingRequestsQueue;
1031 // Maximum number of concurrent jobs allowed to be started for requests
1032 // belonging to this pool.
1033 size_t max_outstanding_jobs_;
1035 // The current number of running jobs that were started for requests
1036 // belonging to this pool.
1037 size_t num_outstanding_jobs_;
1039 // The maximum number of requests we allow to be waiting on a job,
1040 // for this pool.
1041 size_t max_pending_requests_;
1043 // The requests which are waiting to be started for this pool.
1044 PendingRequestsQueue pending_requests_[NUM_PRIORITIES];
1047 //-----------------------------------------------------------------------------
1049 HostResolverImpl::HostResolverImpl(
1050 HostResolverProc* resolver_proc,
1051 HostCache* cache,
1052 size_t max_jobs,
1053 size_t max_retry_attempts,
1054 NetLog* net_log)
1055 : cache_(cache),
1056 max_jobs_(max_jobs),
1057 max_retry_attempts_(max_retry_attempts),
1058 unresponsive_delay_(base::TimeDelta::FromMilliseconds(6000)),
1059 retry_factor_(2),
1060 next_job_id_(0),
1061 resolver_proc_(resolver_proc),
1062 default_address_family_(ADDRESS_FAMILY_UNSPECIFIED),
1063 ipv6_probe_monitoring_(false),
1064 additional_resolver_flags_(0),
1065 net_log_(net_log) {
1066 DCHECK_GT(max_jobs, 0u);
1068 // Maximum of 4 retry attempts for host resolution.
1069 static const size_t kDefaultMaxRetryAttempts = 4u;
1071 if (max_retry_attempts_ == HostResolver::kDefaultRetryAttempts)
1072 max_retry_attempts_ = kDefaultMaxRetryAttempts;
1074 // It is cumbersome to expose all of the constraints in the constructor,
1075 // so we choose some defaults, which users can override later.
1076 job_pools_[POOL_NORMAL] = new JobPool(max_jobs, 100u * max_jobs);
1078 #if defined(OS_WIN)
1079 EnsureWinsockInit();
1080 #endif
1081 #if defined(OS_POSIX) && !defined(OS_MACOSX)
1082 if (HaveOnlyLoopbackAddresses())
1083 additional_resolver_flags_ |= HOST_RESOLVER_LOOPBACK_ONLY;
1084 #endif
1085 NetworkChangeNotifier::AddIPAddressObserver(this);
1086 #if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_OPENBSD)
1087 #if !defined(OS_ANDROID)
1088 EnsureDnsReloaderInit();
1089 #endif
1090 NetworkChangeNotifier::AddDNSObserver(this);
1091 #endif
1094 HostResolverImpl::~HostResolverImpl() {
1095 // Cancel the outstanding jobs. Those jobs may contain several attached
1096 // requests, which will also be cancelled.
1097 DiscardIPv6ProbeJob();
1099 CancelAllJobs();
1101 // In case we are being deleted during the processing of a callback.
1102 if (cur_completing_job_)
1103 cur_completing_job_->Cancel();
1105 NetworkChangeNotifier::RemoveIPAddressObserver(this);
1106 #if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_OPENBSD)
1107 NetworkChangeNotifier::RemoveDNSObserver(this);
1108 #endif
1110 // Delete the job pools.
1111 for (size_t i = 0u; i < arraysize(job_pools_); ++i)
1112 delete job_pools_[i];
1115 void HostResolverImpl::SetPoolConstraints(JobPoolIndex pool_index,
1116 size_t max_outstanding_jobs,
1117 size_t max_pending_requests) {
1118 DCHECK(CalledOnValidThread());
1119 CHECK_GE(pool_index, 0);
1120 CHECK_LT(pool_index, POOL_COUNT);
1121 CHECK(jobs_.empty()) << "Can only set constraints during setup";
1122 JobPool* pool = job_pools_[pool_index];
1123 pool->SetConstraints(max_outstanding_jobs, max_pending_requests);
1126 int HostResolverImpl::Resolve(const RequestInfo& info,
1127 AddressList* addresses,
1128 const CompletionCallback& callback,
1129 RequestHandle* out_req,
1130 const BoundNetLog& source_net_log) {
1131 DCHECK(addresses);
1132 DCHECK(CalledOnValidThread());
1133 DCHECK_EQ(false, callback.is_null());
1135 // Make a log item for the request.
1136 BoundNetLog request_net_log = BoundNetLog::Make(net_log_,
1137 NetLog::SOURCE_HOST_RESOLVER_IMPL_REQUEST);
1139 // Update the net log and notify registered observers.
1140 OnStartRequest(source_net_log, request_net_log, info);
1142 // Build a key that identifies the request in the cache and in the
1143 // outstanding jobs map.
1144 Key key = GetEffectiveKeyForRequest(info);
1146 int rv = ResolveHelper(key, info, addresses, request_net_log);
1147 if (rv != ERR_DNS_CACHE_MISS) {
1148 OnFinishRequest(source_net_log, request_net_log, info,
1150 0 /* os_error (unknown since from cache) */);
1151 return rv;
1154 // Create a handle for this request, and pass it back to the user if they
1155 // asked for it (out_req != NULL).
1156 Request* req = new Request(source_net_log, request_net_log, info,
1157 callback, addresses);
1158 if (out_req)
1159 *out_req = reinterpret_cast<RequestHandle>(req);
1161 // Next we need to attach our request to a "job". This job is responsible for
1162 // calling "getaddrinfo(hostname)" on a worker thread.
1163 scoped_refptr<Job> job;
1165 // If there is already an outstanding job to resolve |key|, use
1166 // it. This prevents starting concurrent resolves for the same hostname.
1167 job = FindOutstandingJob(key);
1168 if (job) {
1169 job->AddRequest(req);
1170 } else {
1171 JobPool* pool = GetPoolForRequest(req);
1172 if (CanCreateJobForPool(*pool)) {
1173 CreateAndStartJob(req);
1174 } else {
1175 return EnqueueRequest(pool, req);
1179 // Completion happens during OnJobComplete(Job*).
1180 return ERR_IO_PENDING;
1183 int HostResolverImpl::ResolveHelper(const Key& key,
1184 const RequestInfo& info,
1185 AddressList* addresses,
1186 const BoundNetLog& request_net_log) {
1187 // The result of |getaddrinfo| for empty hosts is inconsistent across systems.
1188 // On Windows it gives the default interface's address, whereas on Linux it
1189 // gives an error. We will make it fail on all platforms for consistency.
1190 if (info.hostname().empty() || info.hostname().size() > kMaxHostLength)
1191 return ERR_NAME_NOT_RESOLVED;
1193 int net_error = ERR_UNEXPECTED;
1194 if (ResolveAsIP(key, info, &net_error, addresses))
1195 return net_error;
1196 net_error = ERR_DNS_CACHE_MISS;
1197 ServeFromCache(key, info, request_net_log, &net_error, addresses);
1198 return net_error;
1201 int HostResolverImpl::ResolveFromCache(const RequestInfo& info,
1202 AddressList* addresses,
1203 const BoundNetLog& source_net_log) {
1204 DCHECK(CalledOnValidThread());
1205 DCHECK(addresses);
1207 // Make a log item for the request.
1208 BoundNetLog request_net_log = BoundNetLog::Make(net_log_,
1209 NetLog::SOURCE_HOST_RESOLVER_IMPL_REQUEST);
1211 // Update the net log and notify registered observers.
1212 OnStartRequest(source_net_log, request_net_log, info);
1214 // Build a key that identifies the request in the cache and in the
1215 // outstanding jobs map.
1216 Key key = GetEffectiveKeyForRequest(info);
1218 int rv = ResolveHelper(key, info, addresses, request_net_log);
1219 OnFinishRequest(source_net_log, request_net_log, info,
1221 0 /* os_error (unknown since from cache) */);
1222 return rv;
1225 // See OnJobComplete(Job*) for why it is important not to clean out
1226 // cancelled requests from Job::requests_.
1227 void HostResolverImpl::CancelRequest(RequestHandle req_handle) {
1228 DCHECK(CalledOnValidThread());
1229 Request* req = reinterpret_cast<Request*>(req_handle);
1230 DCHECK(req);
1232 scoped_ptr<Request> request_deleter; // Frees at end of function.
1234 if (!req->job()) {
1235 // If the request was not attached to a job yet, it must have been
1236 // enqueued into a pool. Remove it from that pool's queue.
1237 // Otherwise if it was attached to a job, the job is responsible for
1238 // deleting it.
1239 JobPool* pool = GetPoolForRequest(req);
1240 pool->RemovePendingRequest(req);
1241 request_deleter.reset(req);
1242 } else {
1243 req->request_net_log().EndEvent(
1244 NetLog::TYPE_HOST_RESOLVER_IMPL_JOB_ATTACH, NULL);
1247 // NULL out the fields of req, to mark it as cancelled.
1248 req->MarkAsCancelled();
1249 OnCancelRequest(req->source_net_log(), req->request_net_log(), req->info());
1252 void HostResolverImpl::SetDefaultAddressFamily(AddressFamily address_family) {
1253 DCHECK(CalledOnValidThread());
1254 ipv6_probe_monitoring_ = false;
1255 DiscardIPv6ProbeJob();
1256 default_address_family_ = address_family;
1259 AddressFamily HostResolverImpl::GetDefaultAddressFamily() const {
1260 return default_address_family_;
1263 void HostResolverImpl::ProbeIPv6Support() {
1264 DCHECK(CalledOnValidThread());
1265 DCHECK(!ipv6_probe_monitoring_);
1266 ipv6_probe_monitoring_ = true;
1267 OnIPAddressChanged(); // Give initial setup call.
1270 HostCache* HostResolverImpl::GetHostCache() {
1271 return cache_.get();
1274 bool HostResolverImpl::ResolveAsIP(const Key& key,
1275 const RequestInfo& info,
1276 int* net_error,
1277 AddressList* addresses) {
1278 DCHECK(addresses);
1279 DCHECK(net_error);
1280 IPAddressNumber ip_number;
1281 if (!ParseIPLiteralToNumber(key.hostname, &ip_number))
1282 return false;
1284 DCHECK_EQ(key.host_resolver_flags &
1285 ~(HOST_RESOLVER_CANONNAME | HOST_RESOLVER_LOOPBACK_ONLY |
1286 HOST_RESOLVER_DEFAULT_FAMILY_SET_DUE_TO_NO_IPV6),
1287 0) << " Unhandled flag";
1288 bool ipv6_disabled = default_address_family_ == ADDRESS_FAMILY_IPV4 &&
1289 !ipv6_probe_monitoring_;
1290 *net_error = OK;
1291 if (ip_number.size() == 16 && ipv6_disabled) {
1292 *net_error = ERR_NAME_NOT_RESOLVED;
1293 } else {
1294 *addresses = AddressList::CreateFromIPAddressWithCname(
1295 ip_number, info.port(),
1296 (key.host_resolver_flags & HOST_RESOLVER_CANONNAME));
1298 return true;
1301 bool HostResolverImpl::ServeFromCache(const Key& key,
1302 const RequestInfo& info,
1303 const BoundNetLog& request_net_log,
1304 int* net_error,
1305 AddressList* addresses) {
1306 DCHECK(addresses);
1307 DCHECK(net_error);
1308 if (!info.allow_cached_response() || !cache_.get())
1309 return false;
1311 const HostCache::Entry* cache_entry = cache_->Lookup(
1312 key, base::TimeTicks::Now());
1313 if (!cache_entry)
1314 return false;
1316 request_net_log.AddEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_CACHE_HIT, NULL);
1317 *net_error = cache_entry->error;
1318 if (*net_error == OK)
1319 *addresses = CreateAddressListUsingPort(cache_entry->addrlist, info.port());
1320 return true;
1323 void HostResolverImpl::AddOutstandingJob(Job* job) {
1324 scoped_refptr<Job>& found_job = jobs_[job->key()];
1325 DCHECK(!found_job);
1326 found_job = job;
1328 JobPool* pool = GetPoolForRequest(job->initial_request());
1329 pool->AdjustNumOutstandingJobs(1);
1332 HostResolverImpl::Job* HostResolverImpl::FindOutstandingJob(const Key& key) {
1333 JobMap::iterator it = jobs_.find(key);
1334 if (it != jobs_.end())
1335 return it->second;
1336 return NULL;
1339 void HostResolverImpl::RemoveOutstandingJob(Job* job) {
1340 JobMap::iterator it = jobs_.find(job->key());
1341 DCHECK(it != jobs_.end());
1342 DCHECK_EQ(it->second.get(), job);
1343 jobs_.erase(it);
1345 JobPool* pool = GetPoolForRequest(job->initial_request());
1346 pool->AdjustNumOutstandingJobs(-1);
1349 void HostResolverImpl::OnJobComplete(Job* job,
1350 int net_error,
1351 int os_error,
1352 const AddressList& addrlist) {
1353 RemoveOutstandingJob(job);
1355 // Write result to the cache.
1356 if (cache_.get())
1357 cache_->Set(job->key(), net_error, addrlist, base::TimeTicks::Now());
1359 OnJobCompleteInternal(job, net_error, os_error, addrlist);
1362 void HostResolverImpl::AbortJob(Job* job) {
1363 OnJobCompleteInternal(job, ERR_ABORTED, 0 /* no os_error */, AddressList());
1366 void HostResolverImpl::OnJobCompleteInternal(
1367 Job* job,
1368 int net_error,
1369 int os_error,
1370 const AddressList& addrlist) {
1371 // Make a note that we are executing within OnJobComplete() in case the
1372 // HostResolver is deleted by a callback invocation.
1373 DCHECK(!cur_completing_job_);
1374 cur_completing_job_ = job;
1376 // Try to start any queued requests now that a job-slot has freed up.
1377 ProcessQueuedRequests();
1379 // Complete all of the requests that were attached to the job.
1380 for (RequestsList::const_iterator it = job->requests().begin();
1381 it != job->requests().end(); ++it) {
1382 Request* req = *it;
1383 if (!req->was_cancelled()) {
1384 DCHECK_EQ(job, req->job());
1385 req->request_net_log().EndEvent(
1386 NetLog::TYPE_HOST_RESOLVER_IMPL_JOB_ATTACH, NULL);
1388 // Update the net log and notify registered observers.
1389 OnFinishRequest(req->source_net_log(), req->request_net_log(),
1390 req->info(), net_error, os_error);
1392 req->OnComplete(net_error, addrlist);
1394 // Check if the job was cancelled as a result of running the callback.
1395 // (Meaning that |this| was deleted).
1396 if (job->was_cancelled())
1397 return;
1401 cur_completing_job_ = NULL;
1404 void HostResolverImpl::OnStartRequest(const BoundNetLog& source_net_log,
1405 const BoundNetLog& request_net_log,
1406 const RequestInfo& info) {
1407 source_net_log.BeginEvent(
1408 NetLog::TYPE_HOST_RESOLVER_IMPL,
1409 make_scoped_refptr(new NetLogSourceParameter(
1410 "source_dependency", request_net_log.source())));
1412 request_net_log.BeginEvent(
1413 NetLog::TYPE_HOST_RESOLVER_IMPL_REQUEST,
1414 make_scoped_refptr(new RequestInfoParameters(
1415 info, source_net_log.source())));
1418 void HostResolverImpl::OnFinishRequest(const BoundNetLog& source_net_log,
1419 const BoundNetLog& request_net_log,
1420 const RequestInfo& info,
1421 int net_error,
1422 int os_error) {
1423 bool was_resolved = net_error == OK;
1425 // Log some extra parameters on failure for synchronous requests.
1426 scoped_refptr<NetLog::EventParameters> params;
1427 if (!was_resolved) {
1428 params = new HostResolveFailedParams(0, net_error, os_error);
1431 request_net_log.EndEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_REQUEST, params);
1432 source_net_log.EndEvent(NetLog::TYPE_HOST_RESOLVER_IMPL, NULL);
1435 void HostResolverImpl::OnCancelRequest(const BoundNetLog& source_net_log,
1436 const BoundNetLog& request_net_log,
1437 const RequestInfo& info) {
1438 request_net_log.AddEvent(NetLog::TYPE_CANCELLED, NULL);
1439 request_net_log.EndEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_REQUEST, NULL);
1440 source_net_log.EndEvent(NetLog::TYPE_HOST_RESOLVER_IMPL, NULL);
1443 void HostResolverImpl::DiscardIPv6ProbeJob() {
1444 if (ipv6_probe_job_.get()) {
1445 ipv6_probe_job_->Cancel();
1446 ipv6_probe_job_ = NULL;
1450 void HostResolverImpl::IPv6ProbeSetDefaultAddressFamily(
1451 AddressFamily address_family) {
1452 DCHECK(address_family == ADDRESS_FAMILY_UNSPECIFIED ||
1453 address_family == ADDRESS_FAMILY_IPV4);
1454 if (default_address_family_ != address_family) {
1455 VLOG(1) << "IPv6Probe forced AddressFamily setting to "
1456 << ((address_family == ADDRESS_FAMILY_UNSPECIFIED) ?
1457 "ADDRESS_FAMILY_UNSPECIFIED" : "ADDRESS_FAMILY_IPV4");
1459 default_address_family_ = address_family;
1460 // Drop reference since the job has called us back.
1461 DiscardIPv6ProbeJob();
1464 bool HostResolverImpl::CanCreateJobForPool(const JobPool& pool) const {
1465 DCHECK_LE(jobs_.size(), max_jobs_);
1467 // We can't create another job if it would exceed the global total.
1468 if (jobs_.size() + 1 > max_jobs_)
1469 return false;
1471 // Check whether the pool's constraints are met.
1472 return pool.CanCreateJob();
1475 // static
1476 HostResolverImpl::JobPoolIndex HostResolverImpl::GetJobPoolIndexForRequest(
1477 const Request* req) {
1478 return POOL_NORMAL;
1481 void HostResolverImpl::ProcessQueuedRequests() {
1482 // Find the highest priority request that can be scheduled.
1483 Request* top_req = NULL;
1484 for (size_t i = 0; i < arraysize(job_pools_); ++i) {
1485 JobPool* pool = job_pools_[i];
1486 if (pool->HasPendingRequests() && CanCreateJobForPool(*pool)) {
1487 top_req = pool->RemoveTopPendingRequest();
1488 break;
1492 if (!top_req)
1493 return;
1495 scoped_refptr<Job> job(CreateAndStartJob(top_req));
1497 // Search for any other pending request which can piggy-back off this job.
1498 for (size_t pool_i = 0; pool_i < POOL_COUNT; ++pool_i) {
1499 JobPool* pool = job_pools_[pool_i];
1500 pool->MoveRequestsToJob(job);
1504 HostResolverImpl::Key HostResolverImpl::GetEffectiveKeyForRequest(
1505 const RequestInfo& info) const {
1506 HostResolverFlags effective_flags =
1507 info.host_resolver_flags() | additional_resolver_flags_;
1508 AddressFamily effective_address_family = info.address_family();
1509 if (effective_address_family == ADDRESS_FAMILY_UNSPECIFIED &&
1510 default_address_family_ != ADDRESS_FAMILY_UNSPECIFIED) {
1511 effective_address_family = default_address_family_;
1512 if (ipv6_probe_monitoring_)
1513 effective_flags |= HOST_RESOLVER_DEFAULT_FAMILY_SET_DUE_TO_NO_IPV6;
1515 return Key(info.hostname(), effective_address_family, effective_flags);
1518 HostResolverImpl::Job* HostResolverImpl::CreateAndStartJob(Request* req) {
1519 DCHECK(CanCreateJobForPool(*GetPoolForRequest(req)));
1520 Key key = GetEffectiveKeyForRequest(req->info());
1522 req->request_net_log().AddEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_CREATE_JOB,
1523 NULL);
1525 scoped_refptr<Job> job(new Job(next_job_id_++, this, key,
1526 req->request_net_log(), net_log_));
1527 job->AddRequest(req);
1528 AddOutstandingJob(job);
1529 job->Start();
1531 return job.get();
1534 int HostResolverImpl::EnqueueRequest(JobPool* pool, Request* req) {
1535 scoped_ptr<Request> req_evicted_from_queue(
1536 pool->InsertPendingRequest(req));
1538 // If the queue has become too large, we need to kick something out.
1539 if (req_evicted_from_queue.get()) {
1540 Request* r = req_evicted_from_queue.get();
1541 int error = ERR_HOST_RESOLVER_QUEUE_TOO_LARGE;
1543 OnFinishRequest(r->source_net_log(), r->request_net_log(), r->info(), error,
1544 0 /* os_error (not applicable) */);
1546 if (r == req)
1547 return error;
1549 r->OnComplete(error, AddressList());
1552 return ERR_IO_PENDING;
1555 void HostResolverImpl::CancelAllJobs() {
1556 JobMap jobs;
1557 jobs.swap(jobs_);
1558 for (JobMap::iterator it = jobs.begin(); it != jobs.end(); ++it)
1559 it->second->Cancel();
1562 void HostResolverImpl::AbortAllInProgressJobs() {
1563 for (size_t i = 0; i < arraysize(job_pools_); ++i)
1564 job_pools_[i]->ResetNumOutstandingJobs();
1565 JobMap jobs;
1566 jobs.swap(jobs_);
1567 for (JobMap::iterator it = jobs.begin(); it != jobs.end(); ++it) {
1568 AbortJob(it->second);
1569 it->second->Cancel();
1573 void HostResolverImpl::OnIPAddressChanged() {
1574 if (cache_.get())
1575 cache_->clear();
1576 if (ipv6_probe_monitoring_) {
1577 DiscardIPv6ProbeJob();
1578 ipv6_probe_job_ = new IPv6ProbeJob(this);
1579 ipv6_probe_job_->Start();
1581 #if defined(OS_POSIX) && !defined(OS_MACOSX)
1582 if (HaveOnlyLoopbackAddresses()) {
1583 additional_resolver_flags_ |= HOST_RESOLVER_LOOPBACK_ONLY;
1584 } else {
1585 additional_resolver_flags_ &= ~HOST_RESOLVER_LOOPBACK_ONLY;
1587 #endif
1588 AbortAllInProgressJobs();
1589 // |this| may be deleted inside AbortAllInProgressJobs().
1592 void HostResolverImpl::OnDNSChanged() {
1593 // If the DNS server has changed, existing cached info could be wrong so we
1594 // have to drop our internal cache :( Note that OS level DNS caches, such
1595 // as NSCD's cache should be dropped automatically by the OS when
1596 // resolv.conf changes so we don't need to do anything to clear that cache.
1597 if (cache_.get())
1598 cache_->clear();
1599 // Existing jobs will have been sent to the original server so they need to
1600 // be aborted. TODO(Craig): Should these jobs be restarted?
1601 AbortAllInProgressJobs();
1602 // |this| may be deleted inside AbortAllInProgressJobs().
1605 } // namespace net