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

Side by Side Diff: net/base/host_resolver_impl.cc

Issue 12518036: net: move host_resolver files from net/base to net/dns (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 7 years, 9 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 unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
1 // Copyright (c) 2012 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.
4
5 #include "net/base/host_resolver_impl.h"
6
7 #if defined(OS_WIN)
8 #include <Winsock2.h>
9 #elif defined(OS_POSIX)
10 #include <netdb.h>
11 #endif
12
13 #include <cmath>
14 #include <utility>
15 #include <vector>
16
17 #include "base/basictypes.h"
18 #include "base/bind.h"
19 #include "base/bind_helpers.h"
20 #include "base/callback.h"
21 #include "base/compiler_specific.h"
22 #include "base/debug/debugger.h"
23 #include "base/debug/stack_trace.h"
24 #include "base/message_loop_proxy.h"
25 #include "base/metrics/field_trial.h"
26 #include "base/metrics/histogram.h"
27 #include "base/stl_util.h"
28 #include "base/string_util.h"
29 #include "base/threading/worker_pool.h"
30 #include "base/time.h"
31 #include "base/utf_string_conversions.h"
32 #include "base/values.h"
33 #include "net/base/address_family.h"
34 #include "net/base/address_list.h"
35 #include "net/base/dns_reloader.h"
36 #include "net/base/host_port_pair.h"
37 #include "net/base/host_resolver_proc.h"
38 #include "net/base/net_errors.h"
39 #include "net/base/net_log.h"
40 #include "net/base/net_util.h"
41 #include "net/dns/address_sorter.h"
42 #include "net/dns/dns_client.h"
43 #include "net/dns/dns_config_service.h"
44 #include "net/dns/dns_protocol.h"
45 #include "net/dns/dns_response.h"
46 #include "net/dns/dns_transaction.h"
47
48 #if defined(OS_WIN)
49 #include "net/base/winsock_init.h"
50 #endif
51
52 namespace net {
53
54 namespace {
55
56 // Limit the size of hostnames that will be resolved to combat issues in
57 // some platform's resolvers.
58 const size_t kMaxHostLength = 4096;
59
60 // Default TTL for successful resolutions with ProcTask.
61 const unsigned kCacheEntryTTLSeconds = 60;
62
63 // Default TTL for unsuccessful resolutions with ProcTask.
64 const unsigned kNegativeCacheEntryTTLSeconds = 0;
65
66 // Minimum TTL for successful resolutions with DnsTask.
67 const unsigned kMinimumTTLSeconds = kCacheEntryTTLSeconds;
68
69 // Number of consecutive failures of DnsTask (with successful fallback) before
70 // the DnsClient is disabled until the next DNS change.
71 const unsigned kMaximumDnsFailures = 16;
72
73 // We use a separate histogram name for each platform to facilitate the
74 // display of error codes by their symbolic name (since each platform has
75 // different mappings).
76 const char kOSErrorsForGetAddrinfoHistogramName[] =
77 #if defined(OS_WIN)
78 "Net.OSErrorsForGetAddrinfo_Win";
79 #elif defined(OS_MACOSX)
80 "Net.OSErrorsForGetAddrinfo_Mac";
81 #elif defined(OS_LINUX)
82 "Net.OSErrorsForGetAddrinfo_Linux";
83 #else
84 "Net.OSErrorsForGetAddrinfo";
85 #endif
86
87 // Gets a list of the likely error codes that getaddrinfo() can return
88 // (non-exhaustive). These are the error codes that we will track via
89 // a histogram.
90 std::vector<int> GetAllGetAddrinfoOSErrors() {
91 int os_errors[] = {
92 #if defined(OS_POSIX)
93 #if !defined(OS_FREEBSD)
94 #if !defined(OS_ANDROID)
95 // EAI_ADDRFAMILY has been declared obsolete in Android's and
96 // FreeBSD's netdb.h.
97 EAI_ADDRFAMILY,
98 #endif
99 // EAI_NODATA has been declared obsolete in FreeBSD's netdb.h.
100 EAI_NODATA,
101 #endif
102 EAI_AGAIN,
103 EAI_BADFLAGS,
104 EAI_FAIL,
105 EAI_FAMILY,
106 EAI_MEMORY,
107 EAI_NONAME,
108 EAI_SERVICE,
109 EAI_SOCKTYPE,
110 EAI_SYSTEM,
111 #elif defined(OS_WIN)
112 // See: http://msdn.microsoft.com/en-us/library/ms738520(VS.85).aspx
113 WSA_NOT_ENOUGH_MEMORY,
114 WSAEAFNOSUPPORT,
115 WSAEINVAL,
116 WSAESOCKTNOSUPPORT,
117 WSAHOST_NOT_FOUND,
118 WSANO_DATA,
119 WSANO_RECOVERY,
120 WSANOTINITIALISED,
121 WSATRY_AGAIN,
122 WSATYPE_NOT_FOUND,
123 // The following are not in doc, but might be to appearing in results :-(.
124 WSA_INVALID_HANDLE,
125 #endif
126 };
127
128 // Ensure all errors are positive, as histogram only tracks positive values.
129 for (size_t i = 0; i < arraysize(os_errors); ++i) {
130 os_errors[i] = std::abs(os_errors[i]);
131 }
132
133 return base::CustomHistogram::ArrayToCustomRanges(os_errors,
134 arraysize(os_errors));
135 }
136
137 enum DnsResolveStatus {
138 RESOLVE_STATUS_DNS_SUCCESS = 0,
139 RESOLVE_STATUS_PROC_SUCCESS,
140 RESOLVE_STATUS_FAIL,
141 RESOLVE_STATUS_SUSPECT_NETBIOS,
142 RESOLVE_STATUS_MAX
143 };
144
145 void UmaAsyncDnsResolveStatus(DnsResolveStatus result) {
146 UMA_HISTOGRAM_ENUMERATION("AsyncDNS.ResolveStatus",
147 result,
148 RESOLVE_STATUS_MAX);
149 }
150
151 bool ResemblesNetBIOSName(const std::string& hostname) {
152 return (hostname.size() < 16) && (hostname.find('.') == std::string::npos);
153 }
154
155 // True if |hostname| ends with either ".local" or ".local.".
156 bool ResemblesMulticastDNSName(const std::string& hostname) {
157 DCHECK(!hostname.empty());
158 const char kSuffix[] = ".local.";
159 const size_t kSuffixLen = sizeof(kSuffix) - 1;
160 const size_t kSuffixLenTrimmed = kSuffixLen - 1;
161 if (hostname[hostname.size() - 1] == '.') {
162 return hostname.size() > kSuffixLen &&
163 !hostname.compare(hostname.size() - kSuffixLen, kSuffixLen, kSuffix);
164 }
165 return hostname.size() > kSuffixLenTrimmed &&
166 !hostname.compare(hostname.size() - kSuffixLenTrimmed, kSuffixLenTrimmed,
167 kSuffix, kSuffixLenTrimmed);
168 }
169
170 // Provide a common macro to simplify code and readability. We must use a
171 // macro as the underlying HISTOGRAM macro creates static variables.
172 #define DNS_HISTOGRAM(name, time) UMA_HISTOGRAM_CUSTOM_TIMES(name, time, \
173 base::TimeDelta::FromMilliseconds(1), base::TimeDelta::FromHours(1), 100)
174
175 // A macro to simplify code and readability.
176 #define DNS_HISTOGRAM_BY_PRIORITY(basename, priority, time) \
177 do { \
178 switch (priority) { \
179 case HIGHEST: DNS_HISTOGRAM(basename "_HIGHEST", time); break; \
180 case MEDIUM: DNS_HISTOGRAM(basename "_MEDIUM", time); break; \
181 case LOW: DNS_HISTOGRAM(basename "_LOW", time); break; \
182 case LOWEST: DNS_HISTOGRAM(basename "_LOWEST", time); break; \
183 case IDLE: DNS_HISTOGRAM(basename "_IDLE", time); break; \
184 default: NOTREACHED(); break; \
185 } \
186 DNS_HISTOGRAM(basename, time); \
187 } while (0)
188
189 // Record time from Request creation until a valid DNS response.
190 void RecordTotalTime(bool had_dns_config,
191 bool speculative,
192 base::TimeDelta duration) {
193 if (had_dns_config) {
194 if (speculative) {
195 DNS_HISTOGRAM("AsyncDNS.TotalTime_speculative", duration);
196 } else {
197 DNS_HISTOGRAM("AsyncDNS.TotalTime", duration);
198 }
199 } else {
200 if (speculative) {
201 DNS_HISTOGRAM("DNS.TotalTime_speculative", duration);
202 } else {
203 DNS_HISTOGRAM("DNS.TotalTime", duration);
204 }
205 }
206 }
207
208 void RecordTTL(base::TimeDelta ttl) {
209 UMA_HISTOGRAM_CUSTOM_TIMES("AsyncDNS.TTL", ttl,
210 base::TimeDelta::FromSeconds(1),
211 base::TimeDelta::FromDays(1), 100);
212 }
213
214 //-----------------------------------------------------------------------------
215
216 // Wraps call to SystemHostResolverProc as an instance of HostResolverProc.
217 // TODO(szym): This should probably be declared in host_resolver_proc.h.
218 class CallSystemHostResolverProc : public HostResolverProc {
219 public:
220 CallSystemHostResolverProc() : HostResolverProc(NULL) {}
221 virtual int Resolve(const std::string& hostname,
222 AddressFamily address_family,
223 HostResolverFlags host_resolver_flags,
224 AddressList* addr_list,
225 int* os_error) OVERRIDE {
226 return SystemHostResolverProc(hostname,
227 address_family,
228 host_resolver_flags,
229 addr_list,
230 os_error);
231 }
232
233 protected:
234 virtual ~CallSystemHostResolverProc() {}
235 };
236
237 AddressList EnsurePortOnAddressList(const AddressList& list, uint16 port) {
238 if (list.empty() || list.front().port() == port)
239 return list;
240 return AddressList::CopyWithPort(list, port);
241 }
242
243 // Creates NetLog parameters when the resolve failed.
244 base::Value* NetLogProcTaskFailedCallback(uint32 attempt_number,
245 int net_error,
246 int os_error,
247 NetLog::LogLevel /* log_level */) {
248 DictionaryValue* dict = new DictionaryValue();
249 if (attempt_number)
250 dict->SetInteger("attempt_number", attempt_number);
251
252 dict->SetInteger("net_error", net_error);
253
254 if (os_error) {
255 dict->SetInteger("os_error", os_error);
256 #if defined(OS_POSIX)
257 dict->SetString("os_error_string", gai_strerror(os_error));
258 #elif defined(OS_WIN)
259 // Map the error code to a human-readable string.
260 LPWSTR error_string = NULL;
261 int size = FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
262 FORMAT_MESSAGE_FROM_SYSTEM,
263 0, // Use the internal message table.
264 os_error,
265 0, // Use default language.
266 (LPWSTR)&error_string,
267 0, // Buffer size.
268 0); // Arguments (unused).
269 dict->SetString("os_error_string", WideToUTF8(error_string));
270 LocalFree(error_string);
271 #endif
272 }
273
274 return dict;
275 }
276
277 // Creates NetLog parameters when the DnsTask failed.
278 base::Value* NetLogDnsTaskFailedCallback(int net_error,
279 int dns_error,
280 NetLog::LogLevel /* log_level */) {
281 DictionaryValue* dict = new DictionaryValue();
282 dict->SetInteger("net_error", net_error);
283 if (dns_error)
284 dict->SetInteger("dns_error", dns_error);
285 return dict;
286 };
287
288 // Creates NetLog parameters containing the information in a RequestInfo object,
289 // along with the associated NetLog::Source.
290 base::Value* NetLogRequestInfoCallback(const NetLog::Source& source,
291 const HostResolver::RequestInfo* info,
292 NetLog::LogLevel /* log_level */) {
293 DictionaryValue* dict = new DictionaryValue();
294 source.AddToEventParameters(dict);
295
296 dict->SetString("host", info->host_port_pair().ToString());
297 dict->SetInteger("address_family",
298 static_cast<int>(info->address_family()));
299 dict->SetBoolean("allow_cached_response", info->allow_cached_response());
300 dict->SetBoolean("is_speculative", info->is_speculative());
301 dict->SetInteger("priority", info->priority());
302 return dict;
303 }
304
305 // Creates NetLog parameters for the creation of a HostResolverImpl::Job.
306 base::Value* NetLogJobCreationCallback(const NetLog::Source& source,
307 const std::string* host,
308 NetLog::LogLevel /* log_level */) {
309 DictionaryValue* dict = new DictionaryValue();
310 source.AddToEventParameters(dict);
311 dict->SetString("host", *host);
312 return dict;
313 }
314
315 // Creates NetLog parameters for HOST_RESOLVER_IMPL_JOB_ATTACH/DETACH events.
316 base::Value* NetLogJobAttachCallback(const NetLog::Source& source,
317 RequestPriority priority,
318 NetLog::LogLevel /* log_level */) {
319 DictionaryValue* dict = new DictionaryValue();
320 source.AddToEventParameters(dict);
321 dict->SetInteger("priority", priority);
322 return dict;
323 }
324
325 // Creates NetLog parameters for the DNS_CONFIG_CHANGED event.
326 base::Value* NetLogDnsConfigCallback(const DnsConfig* config,
327 NetLog::LogLevel /* log_level */) {
328 return config->ToValue();
329 }
330
331 // The logging routines are defined here because some requests are resolved
332 // without a Request object.
333
334 // Logs when a request has just been started.
335 void LogStartRequest(const BoundNetLog& source_net_log,
336 const BoundNetLog& request_net_log,
337 const HostResolver::RequestInfo& info) {
338 source_net_log.BeginEvent(
339 NetLog::TYPE_HOST_RESOLVER_IMPL,
340 request_net_log.source().ToEventParametersCallback());
341
342 request_net_log.BeginEvent(
343 NetLog::TYPE_HOST_RESOLVER_IMPL_REQUEST,
344 base::Bind(&NetLogRequestInfoCallback, source_net_log.source(), &info));
345 }
346
347 // Logs when a request has just completed (before its callback is run).
348 void LogFinishRequest(const BoundNetLog& source_net_log,
349 const BoundNetLog& request_net_log,
350 const HostResolver::RequestInfo& info,
351 int net_error) {
352 request_net_log.EndEventWithNetErrorCode(
353 NetLog::TYPE_HOST_RESOLVER_IMPL_REQUEST, net_error);
354 source_net_log.EndEvent(NetLog::TYPE_HOST_RESOLVER_IMPL);
355 }
356
357 // Logs when a request has been cancelled.
358 void LogCancelRequest(const BoundNetLog& source_net_log,
359 const BoundNetLog& request_net_log,
360 const HostResolverImpl::RequestInfo& info) {
361 request_net_log.AddEvent(NetLog::TYPE_CANCELLED);
362 request_net_log.EndEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_REQUEST);
363 source_net_log.EndEvent(NetLog::TYPE_HOST_RESOLVER_IMPL);
364 }
365
366 //-----------------------------------------------------------------------------
367
368 // Keeps track of the highest priority.
369 class PriorityTracker {
370 public:
371 explicit PriorityTracker(RequestPriority initial_priority)
372 : highest_priority_(initial_priority), total_count_(0) {
373 memset(counts_, 0, sizeof(counts_));
374 }
375
376 RequestPriority highest_priority() const {
377 return highest_priority_;
378 }
379
380 size_t total_count() const {
381 return total_count_;
382 }
383
384 void Add(RequestPriority req_priority) {
385 ++total_count_;
386 ++counts_[req_priority];
387 if (highest_priority_ < req_priority)
388 highest_priority_ = req_priority;
389 }
390
391 void Remove(RequestPriority req_priority) {
392 DCHECK_GT(total_count_, 0u);
393 DCHECK_GT(counts_[req_priority], 0u);
394 --total_count_;
395 --counts_[req_priority];
396 size_t i;
397 for (i = highest_priority_; i > MINIMUM_PRIORITY && !counts_[i]; --i);
398 highest_priority_ = static_cast<RequestPriority>(i);
399
400 // In absence of requests, default to MINIMUM_PRIORITY.
401 if (total_count_ == 0)
402 DCHECK_EQ(MINIMUM_PRIORITY, highest_priority_);
403 }
404
405 private:
406 RequestPriority highest_priority_;
407 size_t total_count_;
408 size_t counts_[NUM_PRIORITIES];
409 };
410
411 } // namespace
412
413 //-----------------------------------------------------------------------------
414
415 // Holds the data for a request that could not be completed synchronously.
416 // It is owned by a Job. Canceled Requests are only marked as canceled rather
417 // than removed from the Job's |requests_| list.
418 class HostResolverImpl::Request {
419 public:
420 Request(const BoundNetLog& source_net_log,
421 const BoundNetLog& request_net_log,
422 const RequestInfo& info,
423 const CompletionCallback& callback,
424 AddressList* addresses)
425 : source_net_log_(source_net_log),
426 request_net_log_(request_net_log),
427 info_(info),
428 job_(NULL),
429 callback_(callback),
430 addresses_(addresses),
431 request_time_(base::TimeTicks::Now()) {
432 }
433
434 // Mark the request as canceled.
435 void MarkAsCanceled() {
436 job_ = NULL;
437 addresses_ = NULL;
438 callback_.Reset();
439 }
440
441 bool was_canceled() const {
442 return callback_.is_null();
443 }
444
445 void set_job(Job* job) {
446 DCHECK(job);
447 // Identify which job the request is waiting on.
448 job_ = job;
449 }
450
451 // Prepare final AddressList and call completion callback.
452 void OnComplete(int error, const AddressList& addr_list) {
453 DCHECK(!was_canceled());
454 if (error == OK)
455 *addresses_ = EnsurePortOnAddressList(addr_list, info_.port());
456 CompletionCallback callback = callback_;
457 MarkAsCanceled();
458 callback.Run(error);
459 }
460
461 Job* job() const {
462 return job_;
463 }
464
465 // NetLog for the source, passed in HostResolver::Resolve.
466 const BoundNetLog& source_net_log() {
467 return source_net_log_;
468 }
469
470 // NetLog for this request.
471 const BoundNetLog& request_net_log() {
472 return request_net_log_;
473 }
474
475 const RequestInfo& info() const {
476 return info_;
477 }
478
479 base::TimeTicks request_time() const {
480 return request_time_;
481 }
482
483 private:
484 BoundNetLog source_net_log_;
485 BoundNetLog request_net_log_;
486
487 // The request info that started the request.
488 RequestInfo info_;
489
490 // The resolve job that this request is dependent on.
491 Job* job_;
492
493 // The user's callback to invoke when the request completes.
494 CompletionCallback callback_;
495
496 // The address list to save result into.
497 AddressList* addresses_;
498
499 const base::TimeTicks request_time_;
500
501 DISALLOW_COPY_AND_ASSIGN(Request);
502 };
503
504 //------------------------------------------------------------------------------
505
506 // Calls HostResolverProc on the WorkerPool. Performs retries if necessary.
507 //
508 // Whenever we try to resolve the host, we post a delayed task to check if host
509 // resolution (OnLookupComplete) is completed or not. If the original attempt
510 // hasn't completed, then we start another attempt for host resolution. We take
511 // the results from the first attempt that finishes and ignore the results from
512 // all other attempts.
513 //
514 // TODO(szym): Move to separate source file for testing and mocking.
515 //
516 class HostResolverImpl::ProcTask
517 : public base::RefCountedThreadSafe<HostResolverImpl::ProcTask> {
518 public:
519 typedef base::Callback<void(int net_error,
520 const AddressList& addr_list)> Callback;
521
522 ProcTask(const Key& key,
523 const ProcTaskParams& params,
524 const Callback& callback,
525 const BoundNetLog& job_net_log)
526 : key_(key),
527 params_(params),
528 callback_(callback),
529 origin_loop_(base::MessageLoopProxy::current()),
530 attempt_number_(0),
531 completed_attempt_number_(0),
532 completed_attempt_error_(ERR_UNEXPECTED),
533 had_non_speculative_request_(false),
534 net_log_(job_net_log) {
535 if (!params_.resolver_proc)
536 params_.resolver_proc = HostResolverProc::GetDefault();
537 // If default is unset, use the system proc.
538 if (!params_.resolver_proc)
539 params_.resolver_proc = new CallSystemHostResolverProc();
540 }
541
542 void Start() {
543 DCHECK(origin_loop_->BelongsToCurrentThread());
544 net_log_.BeginEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_PROC_TASK);
545 StartLookupAttempt();
546 }
547
548 // Cancels this ProcTask. It will be orphaned. Any outstanding resolve
549 // attempts running on worker threads will continue running. Only once all the
550 // attempts complete will the final reference to this ProcTask be released.
551 void Cancel() {
552 DCHECK(origin_loop_->BelongsToCurrentThread());
553
554 if (was_canceled() || was_completed())
555 return;
556
557 callback_.Reset();
558 net_log_.EndEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_PROC_TASK);
559 }
560
561 void set_had_non_speculative_request() {
562 DCHECK(origin_loop_->BelongsToCurrentThread());
563 had_non_speculative_request_ = true;
564 }
565
566 bool was_canceled() const {
567 DCHECK(origin_loop_->BelongsToCurrentThread());
568 return callback_.is_null();
569 }
570
571 bool was_completed() const {
572 DCHECK(origin_loop_->BelongsToCurrentThread());
573 return completed_attempt_number_ > 0;
574 }
575
576 private:
577 friend class base::RefCountedThreadSafe<ProcTask>;
578 ~ProcTask() {}
579
580 void StartLookupAttempt() {
581 DCHECK(origin_loop_->BelongsToCurrentThread());
582 base::TimeTicks start_time = base::TimeTicks::Now();
583 ++attempt_number_;
584 // Dispatch the lookup attempt to a worker thread.
585 if (!base::WorkerPool::PostTask(
586 FROM_HERE,
587 base::Bind(&ProcTask::DoLookup, this, start_time, attempt_number_),
588 true)) {
589 NOTREACHED();
590
591 // Since we could be running within Resolve() right now, we can't just
592 // call OnLookupComplete(). Instead we must wait until Resolve() has
593 // returned (IO_PENDING).
594 origin_loop_->PostTask(
595 FROM_HERE,
596 base::Bind(&ProcTask::OnLookupComplete, this, AddressList(),
597 start_time, attempt_number_, ERR_UNEXPECTED, 0));
598 return;
599 }
600
601 net_log_.AddEvent(
602 NetLog::TYPE_HOST_RESOLVER_IMPL_ATTEMPT_STARTED,
603 NetLog::IntegerCallback("attempt_number", attempt_number_));
604
605 // If we don't get the results within a given time, RetryIfNotComplete
606 // will start a new attempt on a different worker thread if none of our
607 // outstanding attempts have completed yet.
608 if (attempt_number_ <= params_.max_retry_attempts) {
609 origin_loop_->PostDelayedTask(
610 FROM_HERE,
611 base::Bind(&ProcTask::RetryIfNotComplete, this),
612 params_.unresponsive_delay);
613 }
614 }
615
616 // WARNING: This code runs inside a worker pool. The shutdown code cannot
617 // wait for it to finish, so we must be very careful here about using other
618 // objects (like MessageLoops, Singletons, etc). During shutdown these objects
619 // may no longer exist. Multiple DoLookups() could be running in parallel, so
620 // any state inside of |this| must not mutate .
621 void DoLookup(const base::TimeTicks& start_time,
622 const uint32 attempt_number) {
623 AddressList results;
624 int os_error = 0;
625 // Running on the worker thread
626 int error = params_.resolver_proc->Resolve(key_.hostname,
627 key_.address_family,
628 key_.host_resolver_flags,
629 &results,
630 &os_error);
631
632 origin_loop_->PostTask(
633 FROM_HERE,
634 base::Bind(&ProcTask::OnLookupComplete, this, results, start_time,
635 attempt_number, error, os_error));
636 }
637
638 // Makes next attempt if DoLookup() has not finished (runs on origin thread).
639 void RetryIfNotComplete() {
640 DCHECK(origin_loop_->BelongsToCurrentThread());
641
642 if (was_completed() || was_canceled())
643 return;
644
645 params_.unresponsive_delay *= params_.retry_factor;
646 StartLookupAttempt();
647 }
648
649 // Callback for when DoLookup() completes (runs on origin thread).
650 void OnLookupComplete(const AddressList& results,
651 const base::TimeTicks& start_time,
652 const uint32 attempt_number,
653 int error,
654 const int os_error) {
655 DCHECK(origin_loop_->BelongsToCurrentThread());
656 DCHECK(error || !results.empty());
657
658 bool was_retry_attempt = attempt_number > 1;
659
660 // Ideally the following code would be part of host_resolver_proc.cc,
661 // however it isn't safe to call NetworkChangeNotifier from worker threads.
662 // So we do it here on the IO thread instead.
663 if (error != OK && NetworkChangeNotifier::IsOffline())
664 error = ERR_INTERNET_DISCONNECTED;
665
666 // If this is the first attempt that is finishing later, then record data
667 // for the first attempt. Won't contaminate with retry attempt's data.
668 if (!was_retry_attempt)
669 RecordPerformanceHistograms(start_time, error, os_error);
670
671 RecordAttemptHistograms(start_time, attempt_number, error, os_error);
672
673 if (was_canceled())
674 return;
675
676 NetLog::ParametersCallback net_log_callback;
677 if (error != OK) {
678 net_log_callback = base::Bind(&NetLogProcTaskFailedCallback,
679 attempt_number,
680 error,
681 os_error);
682 } else {
683 net_log_callback = NetLog::IntegerCallback("attempt_number",
684 attempt_number);
685 }
686 net_log_.AddEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_ATTEMPT_FINISHED,
687 net_log_callback);
688
689 if (was_completed())
690 return;
691
692 // Copy the results from the first worker thread that resolves the host.
693 results_ = results;
694 completed_attempt_number_ = attempt_number;
695 completed_attempt_error_ = error;
696
697 if (was_retry_attempt) {
698 // If retry attempt finishes before 1st attempt, then get stats on how
699 // much time is saved by having spawned an extra attempt.
700 retry_attempt_finished_time_ = base::TimeTicks::Now();
701 }
702
703 if (error != OK) {
704 net_log_callback = base::Bind(&NetLogProcTaskFailedCallback,
705 0, error, os_error);
706 } else {
707 net_log_callback = results_.CreateNetLogCallback();
708 }
709 net_log_.EndEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_PROC_TASK,
710 net_log_callback);
711
712 callback_.Run(error, results_);
713 }
714
715 void RecordPerformanceHistograms(const base::TimeTicks& start_time,
716 const int error,
717 const int os_error) const {
718 DCHECK(origin_loop_->BelongsToCurrentThread());
719 enum Category { // Used in HISTOGRAM_ENUMERATION.
720 RESOLVE_SUCCESS,
721 RESOLVE_FAIL,
722 RESOLVE_SPECULATIVE_SUCCESS,
723 RESOLVE_SPECULATIVE_FAIL,
724 RESOLVE_MAX, // Bounding value.
725 };
726 int category = RESOLVE_MAX; // Illegal value for later DCHECK only.
727
728 base::TimeDelta duration = base::TimeTicks::Now() - start_time;
729 if (error == OK) {
730 if (had_non_speculative_request_) {
731 category = RESOLVE_SUCCESS;
732 DNS_HISTOGRAM("DNS.ResolveSuccess", duration);
733 } else {
734 category = RESOLVE_SPECULATIVE_SUCCESS;
735 DNS_HISTOGRAM("DNS.ResolveSpeculativeSuccess", duration);
736 }
737
738 // Log DNS lookups based on |address_family|. This will help us determine
739 // if IPv4 or IPv4/6 lookups are faster or slower.
740 switch(key_.address_family) {
741 case ADDRESS_FAMILY_IPV4:
742 DNS_HISTOGRAM("DNS.ResolveSuccess_FAMILY_IPV4", duration);
743 break;
744 case ADDRESS_FAMILY_IPV6:
745 DNS_HISTOGRAM("DNS.ResolveSuccess_FAMILY_IPV6", duration);
746 break;
747 case ADDRESS_FAMILY_UNSPECIFIED:
748 DNS_HISTOGRAM("DNS.ResolveSuccess_FAMILY_UNSPEC", duration);
749 break;
750 }
751 } else {
752 if (had_non_speculative_request_) {
753 category = RESOLVE_FAIL;
754 DNS_HISTOGRAM("DNS.ResolveFail", duration);
755 } else {
756 category = RESOLVE_SPECULATIVE_FAIL;
757 DNS_HISTOGRAM("DNS.ResolveSpeculativeFail", duration);
758 }
759 // Log DNS lookups based on |address_family|. This will help us determine
760 // if IPv4 or IPv4/6 lookups are faster or slower.
761 switch(key_.address_family) {
762 case ADDRESS_FAMILY_IPV4:
763 DNS_HISTOGRAM("DNS.ResolveFail_FAMILY_IPV4", duration);
764 break;
765 case ADDRESS_FAMILY_IPV6:
766 DNS_HISTOGRAM("DNS.ResolveFail_FAMILY_IPV6", duration);
767 break;
768 case ADDRESS_FAMILY_UNSPECIFIED:
769 DNS_HISTOGRAM("DNS.ResolveFail_FAMILY_UNSPEC", duration);
770 break;
771 }
772 UMA_HISTOGRAM_CUSTOM_ENUMERATION(kOSErrorsForGetAddrinfoHistogramName,
773 std::abs(os_error),
774 GetAllGetAddrinfoOSErrors());
775 }
776 DCHECK_LT(category, static_cast<int>(RESOLVE_MAX)); // Be sure it was set.
777
778 UMA_HISTOGRAM_ENUMERATION("DNS.ResolveCategory", category, RESOLVE_MAX);
779
780 static const bool show_parallelism_experiment_histograms =
781 base::FieldTrialList::TrialExists("DnsParallelism");
782 if (show_parallelism_experiment_histograms) {
783 UMA_HISTOGRAM_ENUMERATION(
784 base::FieldTrial::MakeName("DNS.ResolveCategory", "DnsParallelism"),
785 category, RESOLVE_MAX);
786 if (RESOLVE_SUCCESS == category) {
787 DNS_HISTOGRAM(base::FieldTrial::MakeName("DNS.ResolveSuccess",
788 "DnsParallelism"), duration);
789 }
790 }
791 }
792
793 void RecordAttemptHistograms(const base::TimeTicks& start_time,
794 const uint32 attempt_number,
795 const int error,
796 const int os_error) const {
797 DCHECK(origin_loop_->BelongsToCurrentThread());
798 bool first_attempt_to_complete =
799 completed_attempt_number_ == attempt_number;
800 bool is_first_attempt = (attempt_number == 1);
801
802 if (first_attempt_to_complete) {
803 // If this was first attempt to complete, then record the resolution
804 // status of the attempt.
805 if (completed_attempt_error_ == OK) {
806 UMA_HISTOGRAM_ENUMERATION(
807 "DNS.AttemptFirstSuccess", attempt_number, 100);
808 } else {
809 UMA_HISTOGRAM_ENUMERATION(
810 "DNS.AttemptFirstFailure", attempt_number, 100);
811 }
812 }
813
814 if (error == OK)
815 UMA_HISTOGRAM_ENUMERATION("DNS.AttemptSuccess", attempt_number, 100);
816 else
817 UMA_HISTOGRAM_ENUMERATION("DNS.AttemptFailure", attempt_number, 100);
818
819 // If first attempt didn't finish before retry attempt, then calculate stats
820 // on how much time is saved by having spawned an extra attempt.
821 if (!first_attempt_to_complete && is_first_attempt && !was_canceled()) {
822 DNS_HISTOGRAM("DNS.AttemptTimeSavedByRetry",
823 base::TimeTicks::Now() - retry_attempt_finished_time_);
824 }
825
826 if (was_canceled() || !first_attempt_to_complete) {
827 // Count those attempts which completed after the job was already canceled
828 // OR after the job was already completed by an earlier attempt (so in
829 // effect).
830 UMA_HISTOGRAM_ENUMERATION("DNS.AttemptDiscarded", attempt_number, 100);
831
832 // Record if job is canceled.
833 if (was_canceled())
834 UMA_HISTOGRAM_ENUMERATION("DNS.AttemptCancelled", attempt_number, 100);
835 }
836
837 base::TimeDelta duration = base::TimeTicks::Now() - start_time;
838 if (error == OK)
839 DNS_HISTOGRAM("DNS.AttemptSuccessDuration", duration);
840 else
841 DNS_HISTOGRAM("DNS.AttemptFailDuration", duration);
842 }
843
844 // Set on the origin thread, read on the worker thread.
845 Key key_;
846
847 // Holds an owning reference to the HostResolverProc that we are going to use.
848 // This may not be the current resolver procedure by the time we call
849 // ResolveAddrInfo, but that's OK... we'll use it anyways, and the owning
850 // reference ensures that it remains valid until we are done.
851 ProcTaskParams params_;
852
853 // The listener to the results of this ProcTask.
854 Callback callback_;
855
856 // Used to post ourselves onto the origin thread.
857 scoped_refptr<base::MessageLoopProxy> origin_loop_;
858
859 // Keeps track of the number of attempts we have made so far to resolve the
860 // host. Whenever we start an attempt to resolve the host, we increase this
861 // number.
862 uint32 attempt_number_;
863
864 // The index of the attempt which finished first (or 0 if the job is still in
865 // progress).
866 uint32 completed_attempt_number_;
867
868 // The result (a net error code) from the first attempt to complete.
869 int completed_attempt_error_;
870
871 // The time when retry attempt was finished.
872 base::TimeTicks retry_attempt_finished_time_;
873
874 // True if a non-speculative request was ever attached to this job
875 // (regardless of whether or not it was later canceled.
876 // This boolean is used for histogramming the duration of jobs used to
877 // service non-speculative requests.
878 bool had_non_speculative_request_;
879
880 AddressList results_;
881
882 BoundNetLog net_log_;
883
884 DISALLOW_COPY_AND_ASSIGN(ProcTask);
885 };
886
887 //-----------------------------------------------------------------------------
888
889 // Wraps a call to TestIPv6Support to be executed on the WorkerPool as it takes
890 // 40-100ms.
891 class HostResolverImpl::IPv6ProbeJob {
892 public:
893 IPv6ProbeJob(const base::WeakPtr<HostResolverImpl>& resolver, NetLog* net_log)
894 : resolver_(resolver),
895 net_log_(BoundNetLog::Make(net_log, NetLog::SOURCE_IPV6_PROBE_JOB)),
896 result_(false, IPV6_SUPPORT_MAX, OK) {
897 DCHECK(resolver);
898 net_log_.BeginEvent(NetLog::TYPE_IPV6_PROBE_RUNNING);
899 const bool kIsSlow = true;
900 base::WorkerPool::PostTaskAndReply(
901 FROM_HERE,
902 base::Bind(&IPv6ProbeJob::DoProbe, base::Unretained(this)),
903 base::Bind(&IPv6ProbeJob::OnProbeComplete, base::Owned(this)),
904 kIsSlow);
905 }
906
907 virtual ~IPv6ProbeJob() {}
908
909 private:
910 // Runs on worker thread.
911 void DoProbe() {
912 result_ = TestIPv6Support();
913 }
914
915 void OnProbeComplete() {
916 net_log_.EndEvent(NetLog::TYPE_IPV6_PROBE_RUNNING,
917 base::Bind(&IPv6SupportResult::ToNetLogValue,
918 base::Unretained(&result_)));
919 if (!resolver_)
920 return;
921 resolver_->IPv6ProbeSetDefaultAddressFamily(
922 result_.ipv6_supported ? ADDRESS_FAMILY_UNSPECIFIED
923 : ADDRESS_FAMILY_IPV4);
924 }
925
926 // Used/set only on origin thread.
927 base::WeakPtr<HostResolverImpl> resolver_;
928
929 BoundNetLog net_log_;
930
931 IPv6SupportResult result_;
932
933 DISALLOW_COPY_AND_ASSIGN(IPv6ProbeJob);
934 };
935
936 // Wraps a call to HaveOnlyLoopbackAddresses to be executed on the WorkerPool as
937 // it takes 40-100ms and should not block initialization.
938 class HostResolverImpl::LoopbackProbeJob {
939 public:
940 explicit LoopbackProbeJob(const base::WeakPtr<HostResolverImpl>& resolver)
941 : resolver_(resolver),
942 result_(false) {
943 DCHECK(resolver);
944 const bool kIsSlow = true;
945 base::WorkerPool::PostTaskAndReply(
946 FROM_HERE,
947 base::Bind(&LoopbackProbeJob::DoProbe, base::Unretained(this)),
948 base::Bind(&LoopbackProbeJob::OnProbeComplete, base::Owned(this)),
949 kIsSlow);
950 }
951
952 virtual ~LoopbackProbeJob() {}
953
954 private:
955 // Runs on worker thread.
956 void DoProbe() {
957 result_ = HaveOnlyLoopbackAddresses();
958 }
959
960 void OnProbeComplete() {
961 if (!resolver_)
962 return;
963 resolver_->SetHaveOnlyLoopbackAddresses(result_);
964 }
965
966 // Used/set only on origin thread.
967 base::WeakPtr<HostResolverImpl> resolver_;
968
969 bool result_;
970
971 DISALLOW_COPY_AND_ASSIGN(LoopbackProbeJob);
972 };
973
974 //-----------------------------------------------------------------------------
975
976 // Resolves the hostname using DnsTransaction.
977 // TODO(szym): This could be moved to separate source file as well.
978 class HostResolverImpl::DnsTask : public base::SupportsWeakPtr<DnsTask> {
979 public:
980 typedef base::Callback<void(int net_error,
981 const AddressList& addr_list,
982 base::TimeDelta ttl)> Callback;
983
984 DnsTask(DnsClient* client,
985 const Key& key,
986 const Callback& callback,
987 const BoundNetLog& job_net_log)
988 : client_(client),
989 family_(key.address_family),
990 callback_(callback),
991 net_log_(job_net_log) {
992 DCHECK(client);
993 DCHECK(!callback.is_null());
994
995 // If unspecified, do IPv4 first, because suffix search will be faster.
996 uint16 qtype = (family_ == ADDRESS_FAMILY_IPV6) ?
997 dns_protocol::kTypeAAAA :
998 dns_protocol::kTypeA;
999 transaction_ = client_->GetTransactionFactory()->CreateTransaction(
1000 key.hostname,
1001 qtype,
1002 base::Bind(&DnsTask::OnTransactionComplete, base::Unretained(this),
1003 true /* first_query */, base::TimeTicks::Now()),
1004 net_log_);
1005 }
1006
1007 int Start() {
1008 net_log_.BeginEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_DNS_TASK);
1009 return transaction_->Start();
1010 }
1011
1012 private:
1013 void OnTransactionComplete(bool first_query,
1014 const base::TimeTicks& start_time,
1015 DnsTransaction* transaction,
1016 int net_error,
1017 const DnsResponse* response) {
1018 DCHECK(transaction);
1019 base::TimeDelta duration = base::TimeTicks::Now() - start_time;
1020 // Run |callback_| last since the owning Job will then delete this DnsTask.
1021 if (net_error != OK) {
1022 DNS_HISTOGRAM("AsyncDNS.TransactionFailure", duration);
1023 OnFailure(net_error, DnsResponse::DNS_PARSE_OK);
1024 return;
1025 }
1026
1027 CHECK(response);
1028 DNS_HISTOGRAM("AsyncDNS.TransactionSuccess", duration);
1029 switch (transaction->GetType()) {
1030 case dns_protocol::kTypeA:
1031 DNS_HISTOGRAM("AsyncDNS.TransactionSuccess_A", duration);
1032 break;
1033 case dns_protocol::kTypeAAAA:
1034 DNS_HISTOGRAM("AsyncDNS.TransactionSuccess_AAAA", duration);
1035 break;
1036 }
1037 AddressList addr_list;
1038 base::TimeDelta ttl;
1039 DnsResponse::Result result = response->ParseToAddressList(&addr_list, &ttl);
1040 UMA_HISTOGRAM_ENUMERATION("AsyncDNS.ParseToAddressList",
1041 result,
1042 DnsResponse::DNS_PARSE_RESULT_MAX);
1043 if (result != DnsResponse::DNS_PARSE_OK) {
1044 // Fail even if the other query succeeds.
1045 OnFailure(ERR_DNS_MALFORMED_RESPONSE, result);
1046 return;
1047 }
1048
1049 bool needs_sort = false;
1050 if (first_query) {
1051 DCHECK(client_->GetConfig()) <<
1052 "Transaction should have been aborted when config changed!";
1053 if (family_ == ADDRESS_FAMILY_IPV6) {
1054 needs_sort = (addr_list.size() > 1);
1055 } else if (family_ == ADDRESS_FAMILY_UNSPECIFIED) {
1056 first_addr_list_ = addr_list;
1057 first_ttl_ = ttl;
1058 // Use fully-qualified domain name to avoid search.
1059 transaction_ = client_->GetTransactionFactory()->CreateTransaction(
1060 response->GetDottedName() + ".",
1061 dns_protocol::kTypeAAAA,
1062 base::Bind(&DnsTask::OnTransactionComplete, base::Unretained(this),
1063 false /* first_query */, base::TimeTicks::Now()),
1064 net_log_);
1065 net_error = transaction_->Start();
1066 if (net_error != ERR_IO_PENDING)
1067 OnFailure(net_error, DnsResponse::DNS_PARSE_OK);
1068 return;
1069 }
1070 } else {
1071 DCHECK_EQ(ADDRESS_FAMILY_UNSPECIFIED, family_);
1072 bool has_ipv6_addresses = !addr_list.empty();
1073 if (!first_addr_list_.empty()) {
1074 ttl = std::min(ttl, first_ttl_);
1075 // Place IPv4 addresses after IPv6.
1076 addr_list.insert(addr_list.end(), first_addr_list_.begin(),
1077 first_addr_list_.end());
1078 }
1079 needs_sort = (has_ipv6_addresses && addr_list.size() > 1);
1080 }
1081
1082 if (addr_list.empty()) {
1083 // TODO(szym): Don't fallback to ProcTask in this case.
1084 OnFailure(ERR_NAME_NOT_RESOLVED, DnsResponse::DNS_PARSE_OK);
1085 return;
1086 }
1087
1088 if (needs_sort) {
1089 // Sort could complete synchronously.
1090 client_->GetAddressSorter()->Sort(
1091 addr_list,
1092 base::Bind(&DnsTask::OnSortComplete,
1093 AsWeakPtr(),
1094 base::TimeTicks::Now(),
1095 ttl));
1096 } else {
1097 OnSuccess(addr_list, ttl);
1098 }
1099 }
1100
1101 void OnSortComplete(base::TimeTicks start_time,
1102 base::TimeDelta ttl,
1103 bool success,
1104 const AddressList& addr_list) {
1105 if (!success) {
1106 DNS_HISTOGRAM("AsyncDNS.SortFailure",
1107 base::TimeTicks::Now() - start_time);
1108 OnFailure(ERR_DNS_SORT_ERROR, DnsResponse::DNS_PARSE_OK);
1109 return;
1110 }
1111
1112 DNS_HISTOGRAM("AsyncDNS.SortSuccess",
1113 base::TimeTicks::Now() - start_time);
1114
1115 // AddressSorter prunes unusable destinations.
1116 if (addr_list.empty()) {
1117 LOG(WARNING) << "Address list empty after RFC3484 sort";
1118 OnFailure(ERR_NAME_NOT_RESOLVED, DnsResponse::DNS_PARSE_OK);
1119 return;
1120 }
1121
1122 OnSuccess(addr_list, ttl);
1123 }
1124
1125 void OnFailure(int net_error, DnsResponse::Result result) {
1126 DCHECK_NE(OK, net_error);
1127 net_log_.EndEvent(
1128 NetLog::TYPE_HOST_RESOLVER_IMPL_DNS_TASK,
1129 base::Bind(&NetLogDnsTaskFailedCallback, net_error, result));
1130 callback_.Run(net_error, AddressList(), base::TimeDelta());
1131 }
1132
1133 void OnSuccess(const AddressList& addr_list, base::TimeDelta ttl) {
1134 net_log_.EndEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_DNS_TASK,
1135 addr_list.CreateNetLogCallback());
1136 callback_.Run(OK, addr_list, ttl);
1137 }
1138
1139 DnsClient* client_;
1140 AddressFamily family_;
1141 // The listener to the results of this DnsTask.
1142 Callback callback_;
1143 const BoundNetLog net_log_;
1144
1145 scoped_ptr<DnsTransaction> transaction_;
1146
1147 // Results from the first transaction. Used only if |family_| is unspecified.
1148 AddressList first_addr_list_;
1149 base::TimeDelta first_ttl_;
1150
1151 DISALLOW_COPY_AND_ASSIGN(DnsTask);
1152 };
1153
1154 //-----------------------------------------------------------------------------
1155
1156 // Aggregates all Requests for the same Key. Dispatched via PriorityDispatch.
1157 class HostResolverImpl::Job : public PrioritizedDispatcher::Job {
1158 public:
1159 // Creates new job for |key| where |request_net_log| is bound to the
1160 // request that spawned it.
1161 Job(const base::WeakPtr<HostResolverImpl>& resolver,
1162 const Key& key,
1163 RequestPriority priority,
1164 const BoundNetLog& request_net_log)
1165 : resolver_(resolver),
1166 key_(key),
1167 priority_tracker_(priority),
1168 had_non_speculative_request_(false),
1169 had_dns_config_(false),
1170 dns_task_error_(OK),
1171 creation_time_(base::TimeTicks::Now()),
1172 priority_change_time_(creation_time_),
1173 net_log_(BoundNetLog::Make(request_net_log.net_log(),
1174 NetLog::SOURCE_HOST_RESOLVER_IMPL_JOB)) {
1175 request_net_log.AddEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_CREATE_JOB);
1176
1177 net_log_.BeginEvent(
1178 NetLog::TYPE_HOST_RESOLVER_IMPL_JOB,
1179 base::Bind(&NetLogJobCreationCallback,
1180 request_net_log.source(),
1181 &key_.hostname));
1182 }
1183
1184 virtual ~Job() {
1185 if (is_running()) {
1186 // |resolver_| was destroyed with this Job still in flight.
1187 // Clean-up, record in the log, but don't run any callbacks.
1188 if (is_proc_running()) {
1189 proc_task_->Cancel();
1190 proc_task_ = NULL;
1191 }
1192 // Clean up now for nice NetLog.
1193 dns_task_.reset(NULL);
1194 net_log_.EndEventWithNetErrorCode(NetLog::TYPE_HOST_RESOLVER_IMPL_JOB,
1195 ERR_ABORTED);
1196 } else if (is_queued()) {
1197 // |resolver_| was destroyed without running this Job.
1198 // TODO(szym): is there any benefit in having this distinction?
1199 net_log_.AddEvent(NetLog::TYPE_CANCELLED);
1200 net_log_.EndEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_JOB);
1201 }
1202 // else CompleteRequests logged EndEvent.
1203
1204 // Log any remaining Requests as cancelled.
1205 for (RequestsList::const_iterator it = requests_.begin();
1206 it != requests_.end(); ++it) {
1207 Request* req = *it;
1208 if (req->was_canceled())
1209 continue;
1210 DCHECK_EQ(this, req->job());
1211 LogCancelRequest(req->source_net_log(), req->request_net_log(),
1212 req->info());
1213 }
1214 }
1215
1216 // Add this job to the dispatcher.
1217 void Schedule() {
1218 handle_ = resolver_->dispatcher_.Add(this, priority());
1219 }
1220
1221 void AddRequest(scoped_ptr<Request> req) {
1222 DCHECK_EQ(key_.hostname, req->info().hostname());
1223
1224 req->set_job(this);
1225 priority_tracker_.Add(req->info().priority());
1226
1227 req->request_net_log().AddEvent(
1228 NetLog::TYPE_HOST_RESOLVER_IMPL_JOB_ATTACH,
1229 net_log_.source().ToEventParametersCallback());
1230
1231 net_log_.AddEvent(
1232 NetLog::TYPE_HOST_RESOLVER_IMPL_JOB_REQUEST_ATTACH,
1233 base::Bind(&NetLogJobAttachCallback,
1234 req->request_net_log().source(),
1235 priority()));
1236
1237 // TODO(szym): Check if this is still needed.
1238 if (!req->info().is_speculative()) {
1239 had_non_speculative_request_ = true;
1240 if (proc_task_)
1241 proc_task_->set_had_non_speculative_request();
1242 }
1243
1244 requests_.push_back(req.release());
1245
1246 UpdatePriority();
1247 }
1248
1249 // Marks |req| as cancelled. If it was the last active Request, also finishes
1250 // this Job, marking it as cancelled, and deletes it.
1251 void CancelRequest(Request* req) {
1252 DCHECK_EQ(key_.hostname, req->info().hostname());
1253 DCHECK(!req->was_canceled());
1254
1255 // Don't remove it from |requests_| just mark it canceled.
1256 req->MarkAsCanceled();
1257 LogCancelRequest(req->source_net_log(), req->request_net_log(),
1258 req->info());
1259
1260 priority_tracker_.Remove(req->info().priority());
1261 net_log_.AddEvent(
1262 NetLog::TYPE_HOST_RESOLVER_IMPL_JOB_REQUEST_DETACH,
1263 base::Bind(&NetLogJobAttachCallback,
1264 req->request_net_log().source(),
1265 priority()));
1266
1267 if (num_active_requests() > 0) {
1268 UpdatePriority();
1269 } else {
1270 // If we were called from a Request's callback within CompleteRequests,
1271 // that Request could not have been cancelled, so num_active_requests()
1272 // could not be 0. Therefore, we are not in CompleteRequests().
1273 CompleteRequestsWithError(OK /* cancelled */);
1274 }
1275 }
1276
1277 // Called from AbortAllInProgressJobs. Completes all requests and destroys
1278 // the job. This currently assumes the abort is due to a network change.
1279 void Abort() {
1280 DCHECK(is_running());
1281 CompleteRequestsWithError(ERR_NETWORK_CHANGED);
1282 }
1283
1284 // If DnsTask present, abort it and fall back to ProcTask.
1285 void AbortDnsTask() {
1286 if (dns_task_) {
1287 dns_task_.reset();
1288 dns_task_error_ = OK;
1289 StartProcTask();
1290 }
1291 }
1292
1293 // Called by HostResolverImpl when this job is evicted due to queue overflow.
1294 // Completes all requests and destroys the job.
1295 void OnEvicted() {
1296 DCHECK(!is_running());
1297 DCHECK(is_queued());
1298 handle_.Reset();
1299
1300 net_log_.AddEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_JOB_EVICTED);
1301
1302 // This signals to CompleteRequests that this job never ran.
1303 CompleteRequestsWithError(ERR_HOST_RESOLVER_QUEUE_TOO_LARGE);
1304 }
1305
1306 // Attempts to serve the job from HOSTS. Returns true if succeeded and
1307 // this Job was destroyed.
1308 bool ServeFromHosts() {
1309 DCHECK_GT(num_active_requests(), 0u);
1310 AddressList addr_list;
1311 if (resolver_->ServeFromHosts(key(),
1312 requests_.front()->info(),
1313 &addr_list)) {
1314 // This will destroy the Job.
1315 CompleteRequests(
1316 HostCache::Entry(OK, MakeAddressListForRequest(addr_list)),
1317 base::TimeDelta());
1318 return true;
1319 }
1320 return false;
1321 }
1322
1323 const Key key() const {
1324 return key_;
1325 }
1326
1327 bool is_queued() const {
1328 return !handle_.is_null();
1329 }
1330
1331 bool is_running() const {
1332 return is_dns_running() || is_proc_running();
1333 }
1334
1335 private:
1336 void UpdatePriority() {
1337 if (is_queued()) {
1338 if (priority() != static_cast<RequestPriority>(handle_.priority()))
1339 priority_change_time_ = base::TimeTicks::Now();
1340 handle_ = resolver_->dispatcher_.ChangePriority(handle_, priority());
1341 }
1342 }
1343
1344 AddressList MakeAddressListForRequest(const AddressList& list) const {
1345 if (requests_.empty())
1346 return list;
1347 return AddressList::CopyWithPort(list, requests_.front()->info().port());
1348 }
1349
1350 // PriorityDispatch::Job:
1351 virtual void Start() OVERRIDE {
1352 DCHECK(!is_running());
1353 handle_.Reset();
1354
1355 net_log_.AddEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_JOB_STARTED);
1356
1357 had_dns_config_ = resolver_->HaveDnsConfig();
1358
1359 base::TimeTicks now = base::TimeTicks::Now();
1360 base::TimeDelta queue_time = now - creation_time_;
1361 base::TimeDelta queue_time_after_change = now - priority_change_time_;
1362
1363 if (had_dns_config_) {
1364 DNS_HISTOGRAM_BY_PRIORITY("AsyncDNS.JobQueueTime", priority(),
1365 queue_time);
1366 DNS_HISTOGRAM_BY_PRIORITY("AsyncDNS.JobQueueTimeAfterChange", priority(),
1367 queue_time_after_change);
1368 } else {
1369 DNS_HISTOGRAM_BY_PRIORITY("DNS.JobQueueTime", priority(), queue_time);
1370 DNS_HISTOGRAM_BY_PRIORITY("DNS.JobQueueTimeAfterChange", priority(),
1371 queue_time_after_change);
1372 }
1373
1374 // Caution: Job::Start must not complete synchronously.
1375 if (had_dns_config_ && !ResemblesMulticastDNSName(key_.hostname)) {
1376 StartDnsTask();
1377 } else {
1378 StartProcTask();
1379 }
1380 }
1381
1382 // TODO(szym): Since DnsTransaction does not consume threads, we can increase
1383 // the limits on |dispatcher_|. But in order to keep the number of WorkerPool
1384 // threads low, we will need to use an "inner" PrioritizedDispatcher with
1385 // tighter limits.
1386 void StartProcTask() {
1387 DCHECK(!is_dns_running());
1388 proc_task_ = new ProcTask(
1389 key_,
1390 resolver_->proc_params_,
1391 base::Bind(&Job::OnProcTaskComplete, base::Unretained(this),
1392 base::TimeTicks::Now()),
1393 net_log_);
1394
1395 if (had_non_speculative_request_)
1396 proc_task_->set_had_non_speculative_request();
1397 // Start() could be called from within Resolve(), hence it must NOT directly
1398 // call OnProcTaskComplete, for example, on synchronous failure.
1399 proc_task_->Start();
1400 }
1401
1402 // Called by ProcTask when it completes.
1403 void OnProcTaskComplete(base::TimeTicks start_time,
1404 int net_error,
1405 const AddressList& addr_list) {
1406 DCHECK(is_proc_running());
1407
1408 if (!resolver_->resolved_known_ipv6_hostname_ &&
1409 net_error == OK &&
1410 key_.address_family == ADDRESS_FAMILY_UNSPECIFIED) {
1411 if (key_.hostname == "www.google.com") {
1412 resolver_->resolved_known_ipv6_hostname_ = true;
1413 bool got_ipv6_address = false;
1414 for (size_t i = 0; i < addr_list.size(); ++i) {
1415 if (addr_list[i].GetFamily() == ADDRESS_FAMILY_IPV6)
1416 got_ipv6_address = true;
1417 }
1418 UMA_HISTOGRAM_BOOLEAN("Net.UnspecResolvedIPv6", got_ipv6_address);
1419 }
1420 }
1421
1422 if (dns_task_error_ != OK) {
1423 base::TimeDelta duration = base::TimeTicks::Now() - start_time;
1424 if (net_error == OK) {
1425 DNS_HISTOGRAM("AsyncDNS.FallbackSuccess", duration);
1426 if ((dns_task_error_ == ERR_NAME_NOT_RESOLVED) &&
1427 ResemblesNetBIOSName(key_.hostname)) {
1428 UmaAsyncDnsResolveStatus(RESOLVE_STATUS_SUSPECT_NETBIOS);
1429 } else {
1430 UmaAsyncDnsResolveStatus(RESOLVE_STATUS_PROC_SUCCESS);
1431 }
1432 UMA_HISTOGRAM_CUSTOM_ENUMERATION("AsyncDNS.ResolveError",
1433 std::abs(dns_task_error_),
1434 GetAllErrorCodesForUma());
1435 resolver_->OnDnsTaskResolve(dns_task_error_);
1436 } else {
1437 DNS_HISTOGRAM("AsyncDNS.FallbackFail", duration);
1438 UmaAsyncDnsResolveStatus(RESOLVE_STATUS_FAIL);
1439 }
1440 }
1441
1442 base::TimeDelta ttl =
1443 base::TimeDelta::FromSeconds(kNegativeCacheEntryTTLSeconds);
1444 if (net_error == OK)
1445 ttl = base::TimeDelta::FromSeconds(kCacheEntryTTLSeconds);
1446
1447 // Don't store the |ttl| in cache since it's not obtained from the server.
1448 CompleteRequests(
1449 HostCache::Entry(net_error, MakeAddressListForRequest(addr_list)),
1450 ttl);
1451 }
1452
1453 void StartDnsTask() {
1454 DCHECK(resolver_->HaveDnsConfig());
1455 dns_task_.reset(new DnsTask(
1456 resolver_->dns_client_.get(),
1457 key_,
1458 base::Bind(&Job::OnDnsTaskComplete, base::Unretained(this),
1459 base::TimeTicks::Now()),
1460 net_log_));
1461
1462 int rv = dns_task_->Start();
1463 if (rv != ERR_IO_PENDING) {
1464 DCHECK_NE(OK, rv);
1465 dns_task_error_ = rv;
1466 dns_task_.reset();
1467 StartProcTask();
1468 }
1469 }
1470
1471 // Called by DnsTask when it completes.
1472 void OnDnsTaskComplete(base::TimeTicks start_time,
1473 int net_error,
1474 const AddressList& addr_list,
1475 base::TimeDelta ttl) {
1476 DCHECK(is_dns_running());
1477
1478 base::TimeDelta duration = base::TimeTicks::Now() - start_time;
1479 if (net_error != OK) {
1480 DNS_HISTOGRAM("AsyncDNS.ResolveFail", duration);
1481
1482 dns_task_error_ = net_error;
1483 dns_task_.reset();
1484
1485 // TODO(szym): Run ServeFromHosts now if nsswitch.conf says so.
1486 // http://crbug.com/117655
1487
1488 // TODO(szym): Some net errors indicate lack of connectivity. Starting
1489 // ProcTask in that case is a waste of time.
1490 StartProcTask();
1491 return;
1492 }
1493 DNS_HISTOGRAM("AsyncDNS.ResolveSuccess", duration);
1494 // Log DNS lookups based on |address_family|.
1495 switch(key_.address_family) {
1496 case ADDRESS_FAMILY_IPV4:
1497 DNS_HISTOGRAM("AsyncDNS.ResolveSuccess_FAMILY_IPV4", duration);
1498 break;
1499 case ADDRESS_FAMILY_IPV6:
1500 DNS_HISTOGRAM("AsyncDNS.ResolveSuccess_FAMILY_IPV6", duration);
1501 break;
1502 case ADDRESS_FAMILY_UNSPECIFIED:
1503 DNS_HISTOGRAM("AsyncDNS.ResolveSuccess_FAMILY_UNSPEC", duration);
1504 break;
1505 }
1506
1507 UmaAsyncDnsResolveStatus(RESOLVE_STATUS_DNS_SUCCESS);
1508 RecordTTL(ttl);
1509
1510 resolver_->OnDnsTaskResolve(OK);
1511
1512 base::TimeDelta bounded_ttl =
1513 std::max(ttl, base::TimeDelta::FromSeconds(kMinimumTTLSeconds));
1514
1515 CompleteRequests(
1516 HostCache::Entry(net_error, MakeAddressListForRequest(addr_list), ttl),
1517 bounded_ttl);
1518 }
1519
1520 // Performs Job's last rites. Completes all Requests. Deletes this.
1521 void CompleteRequests(const HostCache::Entry& entry,
1522 base::TimeDelta ttl) {
1523 CHECK(resolver_);
1524
1525 // This job must be removed from resolver's |jobs_| now to make room for a
1526 // new job with the same key in case one of the OnComplete callbacks decides
1527 // to spawn one. Consequently, the job deletes itself when CompleteRequests
1528 // is done.
1529 scoped_ptr<Job> self_deleter(this);
1530
1531 resolver_->RemoveJob(this);
1532
1533 if (is_running()) {
1534 DCHECK(!is_queued());
1535 if (is_proc_running()) {
1536 proc_task_->Cancel();
1537 proc_task_ = NULL;
1538 }
1539 dns_task_.reset();
1540
1541 // Signal dispatcher that a slot has opened.
1542 resolver_->dispatcher_.OnJobFinished();
1543 } else if (is_queued()) {
1544 resolver_->dispatcher_.Cancel(handle_);
1545 handle_.Reset();
1546 }
1547
1548 if (num_active_requests() == 0) {
1549 net_log_.AddEvent(NetLog::TYPE_CANCELLED);
1550 net_log_.EndEventWithNetErrorCode(NetLog::TYPE_HOST_RESOLVER_IMPL_JOB,
1551 OK);
1552 return;
1553 }
1554
1555 net_log_.EndEventWithNetErrorCode(NetLog::TYPE_HOST_RESOLVER_IMPL_JOB,
1556 entry.error);
1557
1558 DCHECK(!requests_.empty());
1559
1560 if (entry.error == OK) {
1561 // Record this histogram here, when we know the system has a valid DNS
1562 // configuration.
1563 UMA_HISTOGRAM_BOOLEAN("AsyncDNS.HaveDnsConfig",
1564 resolver_->received_dns_config_);
1565 }
1566
1567 bool did_complete = (entry.error != ERR_NETWORK_CHANGED) &&
1568 (entry.error != ERR_HOST_RESOLVER_QUEUE_TOO_LARGE);
1569 if (did_complete)
1570 resolver_->CacheResult(key_, entry, ttl);
1571
1572 // Complete all of the requests that were attached to the job.
1573 for (RequestsList::const_iterator it = requests_.begin();
1574 it != requests_.end(); ++it) {
1575 Request* req = *it;
1576
1577 if (req->was_canceled())
1578 continue;
1579
1580 DCHECK_EQ(this, req->job());
1581 // Update the net log and notify registered observers.
1582 LogFinishRequest(req->source_net_log(), req->request_net_log(),
1583 req->info(), entry.error);
1584 if (did_complete) {
1585 // Record effective total time from creation to completion.
1586 RecordTotalTime(had_dns_config_, req->info().is_speculative(),
1587 base::TimeTicks::Now() - req->request_time());
1588 }
1589 req->OnComplete(entry.error, entry.addrlist);
1590
1591 // Check if the resolver was destroyed as a result of running the
1592 // callback. If it was, we could continue, but we choose to bail.
1593 if (!resolver_)
1594 return;
1595 }
1596 }
1597
1598 // Convenience wrapper for CompleteRequests in case of failure.
1599 void CompleteRequestsWithError(int net_error) {
1600 CompleteRequests(HostCache::Entry(net_error, AddressList()),
1601 base::TimeDelta());
1602 }
1603
1604 RequestPriority priority() const {
1605 return priority_tracker_.highest_priority();
1606 }
1607
1608 // Number of non-canceled requests in |requests_|.
1609 size_t num_active_requests() const {
1610 return priority_tracker_.total_count();
1611 }
1612
1613 bool is_dns_running() const {
1614 return dns_task_.get() != NULL;
1615 }
1616
1617 bool is_proc_running() const {
1618 return proc_task_.get() != NULL;
1619 }
1620
1621 base::WeakPtr<HostResolverImpl> resolver_;
1622
1623 Key key_;
1624
1625 // Tracks the highest priority across |requests_|.
1626 PriorityTracker priority_tracker_;
1627
1628 bool had_non_speculative_request_;
1629
1630 // Distinguishes measurements taken while DnsClient was fully configured.
1631 bool had_dns_config_;
1632
1633 // Result of DnsTask.
1634 int dns_task_error_;
1635
1636 const base::TimeTicks creation_time_;
1637 base::TimeTicks priority_change_time_;
1638
1639 BoundNetLog net_log_;
1640
1641 // Resolves the host using a HostResolverProc.
1642 scoped_refptr<ProcTask> proc_task_;
1643
1644 // Resolves the host using a DnsTransaction.
1645 scoped_ptr<DnsTask> dns_task_;
1646
1647 // All Requests waiting for the result of this Job. Some can be canceled.
1648 RequestsList requests_;
1649
1650 // A handle used in |HostResolverImpl::dispatcher_|.
1651 PrioritizedDispatcher::Handle handle_;
1652 };
1653
1654 //-----------------------------------------------------------------------------
1655
1656 HostResolverImpl::ProcTaskParams::ProcTaskParams(
1657 HostResolverProc* resolver_proc,
1658 size_t max_retry_attempts)
1659 : resolver_proc(resolver_proc),
1660 max_retry_attempts(max_retry_attempts),
1661 unresponsive_delay(base::TimeDelta::FromMilliseconds(6000)),
1662 retry_factor(2) {
1663 }
1664
1665 HostResolverImpl::ProcTaskParams::~ProcTaskParams() {}
1666
1667 HostResolverImpl::HostResolverImpl(
1668 scoped_ptr<HostCache> cache,
1669 const PrioritizedDispatcher::Limits& job_limits,
1670 const ProcTaskParams& proc_params,
1671 NetLog* net_log)
1672 : cache_(cache.Pass()),
1673 dispatcher_(job_limits),
1674 max_queued_jobs_(job_limits.total_jobs * 100u),
1675 proc_params_(proc_params),
1676 net_log_(net_log),
1677 default_address_family_(ADDRESS_FAMILY_UNSPECIFIED),
1678 weak_ptr_factory_(this),
1679 probe_weak_ptr_factory_(this),
1680 received_dns_config_(false),
1681 num_dns_failures_(0),
1682 ipv6_probe_monitoring_(false),
1683 resolved_known_ipv6_hostname_(false),
1684 additional_resolver_flags_(0) {
1685
1686 DCHECK_GE(dispatcher_.num_priorities(), static_cast<size_t>(NUM_PRIORITIES));
1687
1688 // Maximum of 4 retry attempts for host resolution.
1689 static const size_t kDefaultMaxRetryAttempts = 4u;
1690
1691 if (proc_params_.max_retry_attempts == HostResolver::kDefaultRetryAttempts)
1692 proc_params_.max_retry_attempts = kDefaultMaxRetryAttempts;
1693
1694 #if defined(OS_WIN)
1695 EnsureWinsockInit();
1696 #endif
1697 #if defined(OS_POSIX) && !defined(OS_MACOSX)
1698 new LoopbackProbeJob(weak_ptr_factory_.GetWeakPtr());
1699 #endif
1700 NetworkChangeNotifier::AddIPAddressObserver(this);
1701 NetworkChangeNotifier::AddDNSObserver(this);
1702 #if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_OPENBSD) && \
1703 !defined(OS_ANDROID)
1704 EnsureDnsReloaderInit();
1705 #endif
1706
1707 // TODO(szym): Remove when received_dns_config_ is removed, once
1708 // http://crbug.com/137914 is resolved.
1709 {
1710 DnsConfig dns_config;
1711 NetworkChangeNotifier::GetDnsConfig(&dns_config);
1712 received_dns_config_ = dns_config.IsValid();
1713 }
1714 }
1715
1716 HostResolverImpl::~HostResolverImpl() {
1717 // This will also cancel all outstanding requests.
1718 STLDeleteValues(&jobs_);
1719
1720 NetworkChangeNotifier::RemoveIPAddressObserver(this);
1721 NetworkChangeNotifier::RemoveDNSObserver(this);
1722 }
1723
1724 void HostResolverImpl::SetMaxQueuedJobs(size_t value) {
1725 DCHECK_EQ(0u, dispatcher_.num_queued_jobs());
1726 DCHECK_GT(value, 0u);
1727 max_queued_jobs_ = value;
1728 }
1729
1730 int HostResolverImpl::Resolve(const RequestInfo& info,
1731 AddressList* addresses,
1732 const CompletionCallback& callback,
1733 RequestHandle* out_req,
1734 const BoundNetLog& source_net_log) {
1735 DCHECK(addresses);
1736 DCHECK(CalledOnValidThread());
1737 DCHECK_EQ(false, callback.is_null());
1738
1739 // Make a log item for the request.
1740 BoundNetLog request_net_log = BoundNetLog::Make(net_log_,
1741 NetLog::SOURCE_HOST_RESOLVER_IMPL_REQUEST);
1742
1743 LogStartRequest(source_net_log, request_net_log, info);
1744
1745 // Build a key that identifies the request in the cache and in the
1746 // outstanding jobs map.
1747 Key key = GetEffectiveKeyForRequest(info);
1748
1749 int rv = ResolveHelper(key, info, addresses, request_net_log);
1750 if (rv != ERR_DNS_CACHE_MISS) {
1751 LogFinishRequest(source_net_log, request_net_log, info, rv);
1752 RecordTotalTime(HaveDnsConfig(), info.is_speculative(), base::TimeDelta());
1753 return rv;
1754 }
1755
1756 // Next we need to attach our request to a "job". This job is responsible for
1757 // calling "getaddrinfo(hostname)" on a worker thread.
1758
1759 JobMap::iterator jobit = jobs_.find(key);
1760 Job* job;
1761 if (jobit == jobs_.end()) {
1762 job = new Job(weak_ptr_factory_.GetWeakPtr(), key, info.priority(),
1763 request_net_log);
1764 job->Schedule();
1765
1766 // Check for queue overflow.
1767 if (dispatcher_.num_queued_jobs() > max_queued_jobs_) {
1768 Job* evicted = static_cast<Job*>(dispatcher_.EvictOldestLowest());
1769 DCHECK(evicted);
1770 evicted->OnEvicted(); // Deletes |evicted|.
1771 if (evicted == job) {
1772 rv = ERR_HOST_RESOLVER_QUEUE_TOO_LARGE;
1773 LogFinishRequest(source_net_log, request_net_log, info, rv);
1774 return rv;
1775 }
1776 }
1777 jobs_.insert(jobit, std::make_pair(key, job));
1778 } else {
1779 job = jobit->second;
1780 }
1781
1782 // Can't complete synchronously. Create and attach request.
1783 scoped_ptr<Request> req(new Request(source_net_log,
1784 request_net_log,
1785 info,
1786 callback,
1787 addresses));
1788 if (out_req)
1789 *out_req = reinterpret_cast<RequestHandle>(req.get());
1790
1791 job->AddRequest(req.Pass());
1792 // Completion happens during Job::CompleteRequests().
1793 return ERR_IO_PENDING;
1794 }
1795
1796 int HostResolverImpl::ResolveHelper(const Key& key,
1797 const RequestInfo& info,
1798 AddressList* addresses,
1799 const BoundNetLog& request_net_log) {
1800 // The result of |getaddrinfo| for empty hosts is inconsistent across systems.
1801 // On Windows it gives the default interface's address, whereas on Linux it
1802 // gives an error. We will make it fail on all platforms for consistency.
1803 if (info.hostname().empty() || info.hostname().size() > kMaxHostLength)
1804 return ERR_NAME_NOT_RESOLVED;
1805
1806 int net_error = ERR_UNEXPECTED;
1807 if (ResolveAsIP(key, info, &net_error, addresses))
1808 return net_error;
1809 if (ServeFromCache(key, info, &net_error, addresses)) {
1810 request_net_log.AddEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_CACHE_HIT);
1811 return net_error;
1812 }
1813 // TODO(szym): Do not do this if nsswitch.conf instructs not to.
1814 // http://crbug.com/117655
1815 if (ServeFromHosts(key, info, addresses)) {
1816 request_net_log.AddEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_HOSTS_HIT);
1817 return OK;
1818 }
1819 return ERR_DNS_CACHE_MISS;
1820 }
1821
1822 int HostResolverImpl::ResolveFromCache(const RequestInfo& info,
1823 AddressList* addresses,
1824 const BoundNetLog& source_net_log) {
1825 DCHECK(CalledOnValidThread());
1826 DCHECK(addresses);
1827
1828 // Make a log item for the request.
1829 BoundNetLog request_net_log = BoundNetLog::Make(net_log_,
1830 NetLog::SOURCE_HOST_RESOLVER_IMPL_REQUEST);
1831
1832 // Update the net log and notify registered observers.
1833 LogStartRequest(source_net_log, request_net_log, info);
1834
1835 Key key = GetEffectiveKeyForRequest(info);
1836
1837 int rv = ResolveHelper(key, info, addresses, request_net_log);
1838 LogFinishRequest(source_net_log, request_net_log, info, rv);
1839 return rv;
1840 }
1841
1842 void HostResolverImpl::CancelRequest(RequestHandle req_handle) {
1843 DCHECK(CalledOnValidThread());
1844 Request* req = reinterpret_cast<Request*>(req_handle);
1845 DCHECK(req);
1846 Job* job = req->job();
1847 DCHECK(job);
1848 job->CancelRequest(req);
1849 }
1850
1851 void HostResolverImpl::SetDefaultAddressFamily(AddressFamily address_family) {
1852 DCHECK(CalledOnValidThread());
1853 default_address_family_ = address_family;
1854 ipv6_probe_monitoring_ = false;
1855 }
1856
1857 AddressFamily HostResolverImpl::GetDefaultAddressFamily() const {
1858 return default_address_family_;
1859 }
1860
1861 void HostResolverImpl::ProbeIPv6Support() {
1862 DCHECK(CalledOnValidThread());
1863 DCHECK(!ipv6_probe_monitoring_);
1864 ipv6_probe_monitoring_ = true;
1865 OnIPAddressChanged();
1866 }
1867
1868 void HostResolverImpl::SetDnsClientEnabled(bool enabled) {
1869 DCHECK(CalledOnValidThread());
1870 #if defined(ENABLE_BUILT_IN_DNS)
1871 if (enabled && !dns_client_) {
1872 SetDnsClient(DnsClient::CreateClient(net_log_));
1873 } else if (!enabled && dns_client_) {
1874 SetDnsClient(scoped_ptr<DnsClient>());
1875 }
1876 #endif
1877 }
1878
1879 HostCache* HostResolverImpl::GetHostCache() {
1880 return cache_.get();
1881 }
1882
1883 base::Value* HostResolverImpl::GetDnsConfigAsValue() const {
1884 // Check if async DNS is disabled.
1885 if (!dns_client_.get())
1886 return NULL;
1887
1888 // Check if async DNS is enabled, but we currently have no configuration
1889 // for it.
1890 const DnsConfig* dns_config = dns_client_->GetConfig();
1891 if (dns_config == NULL)
1892 return new DictionaryValue();
1893
1894 return dns_config->ToValue();
1895 }
1896
1897 bool HostResolverImpl::ResolveAsIP(const Key& key,
1898 const RequestInfo& info,
1899 int* net_error,
1900 AddressList* addresses) {
1901 DCHECK(addresses);
1902 DCHECK(net_error);
1903 IPAddressNumber ip_number;
1904 if (!ParseIPLiteralToNumber(key.hostname, &ip_number))
1905 return false;
1906
1907 DCHECK_EQ(key.host_resolver_flags &
1908 ~(HOST_RESOLVER_CANONNAME | HOST_RESOLVER_LOOPBACK_ONLY |
1909 HOST_RESOLVER_DEFAULT_FAMILY_SET_DUE_TO_NO_IPV6),
1910 0) << " Unhandled flag";
1911 bool ipv6_disabled = (default_address_family_ == ADDRESS_FAMILY_IPV4) &&
1912 !ipv6_probe_monitoring_;
1913 *net_error = OK;
1914 if ((ip_number.size() == kIPv6AddressSize) && ipv6_disabled) {
1915 *net_error = ERR_NAME_NOT_RESOLVED;
1916 } else {
1917 *addresses = AddressList::CreateFromIPAddress(ip_number, info.port());
1918 if (key.host_resolver_flags & HOST_RESOLVER_CANONNAME)
1919 addresses->SetDefaultCanonicalName();
1920 }
1921 return true;
1922 }
1923
1924 bool HostResolverImpl::ServeFromCache(const Key& key,
1925 const RequestInfo& info,
1926 int* net_error,
1927 AddressList* addresses) {
1928 DCHECK(addresses);
1929 DCHECK(net_error);
1930 if (!info.allow_cached_response() || !cache_.get())
1931 return false;
1932
1933 const HostCache::Entry* cache_entry = cache_->Lookup(
1934 key, base::TimeTicks::Now());
1935 if (!cache_entry)
1936 return false;
1937
1938 *net_error = cache_entry->error;
1939 if (*net_error == OK) {
1940 if (cache_entry->has_ttl())
1941 RecordTTL(cache_entry->ttl);
1942 *addresses = EnsurePortOnAddressList(cache_entry->addrlist, info.port());
1943 }
1944 return true;
1945 }
1946
1947 bool HostResolverImpl::ServeFromHosts(const Key& key,
1948 const RequestInfo& info,
1949 AddressList* addresses) {
1950 DCHECK(addresses);
1951 if (!HaveDnsConfig())
1952 return false;
1953
1954 // HOSTS lookups are case-insensitive.
1955 std::string hostname = StringToLowerASCII(key.hostname);
1956
1957 // If |address_family| is ADDRESS_FAMILY_UNSPECIFIED other implementations
1958 // (glibc and c-ares) return the first matching line. We have more
1959 // flexibility, but lose implicit ordering.
1960 // TODO(szym) http://crbug.com/117850
1961 const DnsHosts& hosts = dns_client_->GetConfig()->hosts;
1962 DnsHosts::const_iterator it = hosts.find(
1963 DnsHostsKey(hostname,
1964 key.address_family == ADDRESS_FAMILY_UNSPECIFIED ?
1965 ADDRESS_FAMILY_IPV4 : key.address_family));
1966
1967 if (it == hosts.end()) {
1968 if (key.address_family != ADDRESS_FAMILY_UNSPECIFIED)
1969 return false;
1970
1971 it = hosts.find(DnsHostsKey(hostname, ADDRESS_FAMILY_IPV6));
1972 if (it == hosts.end())
1973 return false;
1974 }
1975
1976 *addresses = AddressList::CreateFromIPAddress(it->second, info.port());
1977 return true;
1978 }
1979
1980 void HostResolverImpl::CacheResult(const Key& key,
1981 const HostCache::Entry& entry,
1982 base::TimeDelta ttl) {
1983 if (cache_.get())
1984 cache_->Set(key, entry, base::TimeTicks::Now(), ttl);
1985 }
1986
1987 void HostResolverImpl::RemoveJob(Job* job) {
1988 DCHECK(job);
1989 JobMap::iterator it = jobs_.find(job->key());
1990 if (it != jobs_.end() && it->second == job)
1991 jobs_.erase(it);
1992 }
1993
1994 void HostResolverImpl::IPv6ProbeSetDefaultAddressFamily(
1995 AddressFamily address_family) {
1996 DCHECK(address_family == ADDRESS_FAMILY_UNSPECIFIED ||
1997 address_family == ADDRESS_FAMILY_IPV4);
1998 if (!ipv6_probe_monitoring_)
1999 return;
2000 if (default_address_family_ != address_family) {
2001 VLOG(1) << "IPv6Probe forced AddressFamily setting to "
2002 << ((address_family == ADDRESS_FAMILY_UNSPECIFIED) ?
2003 "ADDRESS_FAMILY_UNSPECIFIED" : "ADDRESS_FAMILY_IPV4");
2004 }
2005 default_address_family_ = address_family;
2006 }
2007
2008 void HostResolverImpl::SetHaveOnlyLoopbackAddresses(bool result) {
2009 if (result) {
2010 additional_resolver_flags_ |= HOST_RESOLVER_LOOPBACK_ONLY;
2011 } else {
2012 additional_resolver_flags_ &= ~HOST_RESOLVER_LOOPBACK_ONLY;
2013 }
2014 }
2015
2016 HostResolverImpl::Key HostResolverImpl::GetEffectiveKeyForRequest(
2017 const RequestInfo& info) const {
2018 HostResolverFlags effective_flags =
2019 info.host_resolver_flags() | additional_resolver_flags_;
2020 AddressFamily effective_address_family = info.address_family();
2021 if (effective_address_family == ADDRESS_FAMILY_UNSPECIFIED &&
2022 default_address_family_ != ADDRESS_FAMILY_UNSPECIFIED) {
2023 effective_address_family = default_address_family_;
2024 if (ipv6_probe_monitoring_)
2025 effective_flags |= HOST_RESOLVER_DEFAULT_FAMILY_SET_DUE_TO_NO_IPV6;
2026 }
2027 return Key(info.hostname(), effective_address_family, effective_flags);
2028 }
2029
2030 void HostResolverImpl::AbortAllInProgressJobs() {
2031 // In Abort, a Request callback could spawn new Jobs with matching keys, so
2032 // first collect and remove all running jobs from |jobs_|.
2033 ScopedVector<Job> jobs_to_abort;
2034 for (JobMap::iterator it = jobs_.begin(); it != jobs_.end(); ) {
2035 Job* job = it->second;
2036 if (job->is_running()) {
2037 jobs_to_abort.push_back(job);
2038 jobs_.erase(it++);
2039 } else {
2040 DCHECK(job->is_queued());
2041 ++it;
2042 }
2043 }
2044
2045 // Check if no dispatcher slots leaked out.
2046 DCHECK_EQ(dispatcher_.num_running_jobs(), jobs_to_abort.size());
2047
2048 // Life check to bail once |this| is deleted.
2049 base::WeakPtr<HostResolverImpl> self = weak_ptr_factory_.GetWeakPtr();
2050
2051 // Then Abort them.
2052 for (size_t i = 0; self && i < jobs_to_abort.size(); ++i) {
2053 jobs_to_abort[i]->Abort();
2054 jobs_to_abort[i] = NULL;
2055 }
2056 }
2057
2058 void HostResolverImpl::TryServingAllJobsFromHosts() {
2059 if (!HaveDnsConfig())
2060 return;
2061
2062 // TODO(szym): Do not do this if nsswitch.conf instructs not to.
2063 // http://crbug.com/117655
2064
2065 // Life check to bail once |this| is deleted.
2066 base::WeakPtr<HostResolverImpl> self = weak_ptr_factory_.GetWeakPtr();
2067
2068 for (JobMap::iterator it = jobs_.begin(); self && it != jobs_.end(); ) {
2069 Job* job = it->second;
2070 ++it;
2071 // This could remove |job| from |jobs_|, but iterator will remain valid.
2072 job->ServeFromHosts();
2073 }
2074 }
2075
2076 void HostResolverImpl::OnIPAddressChanged() {
2077 resolved_known_ipv6_hostname_ = false;
2078 // Abandon all ProbeJobs.
2079 probe_weak_ptr_factory_.InvalidateWeakPtrs();
2080 if (cache_.get())
2081 cache_->clear();
2082 if (ipv6_probe_monitoring_)
2083 new IPv6ProbeJob(probe_weak_ptr_factory_.GetWeakPtr(), net_log_);
2084 #if defined(OS_POSIX) && !defined(OS_MACOSX)
2085 new LoopbackProbeJob(probe_weak_ptr_factory_.GetWeakPtr());
2086 #endif
2087 AbortAllInProgressJobs();
2088 // |this| may be deleted inside AbortAllInProgressJobs().
2089 }
2090
2091 void HostResolverImpl::OnDNSChanged() {
2092 DnsConfig dns_config;
2093 NetworkChangeNotifier::GetDnsConfig(&dns_config);
2094 if (net_log_) {
2095 net_log_->AddGlobalEntry(
2096 NetLog::TYPE_DNS_CONFIG_CHANGED,
2097 base::Bind(&NetLogDnsConfigCallback, &dns_config));
2098 }
2099
2100 // TODO(szym): Remove once http://crbug.com/137914 is resolved.
2101 received_dns_config_ = dns_config.IsValid();
2102
2103 num_dns_failures_ = 0;
2104
2105 // We want a new DnsSession in place, before we Abort running Jobs, so that
2106 // the newly started jobs use the new config.
2107 if (dns_client_.get()) {
2108 dns_client_->SetConfig(dns_config);
2109 if (dns_config.IsValid())
2110 UMA_HISTOGRAM_BOOLEAN("AsyncDNS.DnsClientEnabled", true);
2111 }
2112
2113 // If the DNS server has changed, existing cached info could be wrong so we
2114 // have to drop our internal cache :( Note that OS level DNS caches, such
2115 // as NSCD's cache should be dropped automatically by the OS when
2116 // resolv.conf changes so we don't need to do anything to clear that cache.
2117 if (cache_.get())
2118 cache_->clear();
2119
2120 // Life check to bail once |this| is deleted.
2121 base::WeakPtr<HostResolverImpl> self = weak_ptr_factory_.GetWeakPtr();
2122
2123 // Existing jobs will have been sent to the original server so they need to
2124 // be aborted.
2125 AbortAllInProgressJobs();
2126
2127 // |this| may be deleted inside AbortAllInProgressJobs().
2128 if (self)
2129 TryServingAllJobsFromHosts();
2130 }
2131
2132 bool HostResolverImpl::HaveDnsConfig() const {
2133 // Use DnsClient only if it's fully configured and there is no override by
2134 // ScopedDefaultHostResolverProc.
2135 // The alternative is to use NetworkChangeNotifier to override DnsConfig,
2136 // but that would introduce construction order requirements for NCN and SDHRP.
2137 return (dns_client_.get() != NULL) &&
2138 (dns_client_->GetConfig() != NULL) &&
2139 !(proc_params_.resolver_proc == NULL &&
2140 HostResolverProc::GetDefault() != NULL);
2141 }
2142
2143 void HostResolverImpl::OnDnsTaskResolve(int net_error) {
2144 DCHECK(dns_client_);
2145 if (net_error == OK) {
2146 num_dns_failures_ = 0;
2147 return;
2148 }
2149 ++num_dns_failures_;
2150 if (num_dns_failures_ < kMaximumDnsFailures)
2151 return;
2152 // Disable DnsClient until the next DNS change.
2153 for (JobMap::iterator it = jobs_.begin(); it != jobs_.end(); ++it)
2154 it->second->AbortDnsTask();
2155 dns_client_->SetConfig(DnsConfig());
2156 UMA_HISTOGRAM_BOOLEAN("AsyncDNS.DnsClientEnabled", false);
2157 UMA_HISTOGRAM_CUSTOM_ENUMERATION("AsyncDNS.DnsClientDisabledReason",
2158 std::abs(net_error),
2159 GetAllErrorCodesForUma());
2160 }
2161
2162 void HostResolverImpl::SetDnsClient(scoped_ptr<DnsClient> dns_client) {
2163 if (HaveDnsConfig()) {
2164 for (JobMap::iterator it = jobs_.begin(); it != jobs_.end(); ++it)
2165 it->second->AbortDnsTask();
2166 }
2167 dns_client_ = dns_client.Pass();
2168 if (!dns_client_ || dns_client_->GetConfig() ||
2169 num_dns_failures_ >= kMaximumDnsFailures) {
2170 return;
2171 }
2172 DnsConfig dns_config;
2173 NetworkChangeNotifier::GetDnsConfig(&dns_config);
2174 dns_client_->SetConfig(dns_config);
2175 num_dns_failures_ = 0;
2176 if (dns_config.IsValid())
2177 UMA_HISTOGRAM_BOOLEAN("AsyncDNS.DnsClientEnabled", true);
2178 }
2179
2180 } // namespace net
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698