blob: 63b191ea5498be26d3e0576e4b7b03b9a9b8dc01 [file] [log] [blame]
[email protected]a2730882012-01-21 00:56:271// Copyright (c) 2012 The Chromium Authors. All rights reserved.
[email protected]b59ff372009-07-15 22:04:322// 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
[email protected]21526002010-05-16 19:42:467#if defined(OS_WIN)
8#include <Winsock2.h>
9#elif defined(OS_POSIX)
10#include <netdb.h>
11#endif
12
[email protected]68ad3ee2010-01-30 03:45:3913#include <cmath>
[email protected]0f292de02012-02-01 22:28:2014#include <utility>
[email protected]21526002010-05-16 19:42:4615#include <vector>
[email protected]68ad3ee2010-01-30 03:45:3916
17#include "base/basictypes.h"
[email protected]33152acc2011-10-20 23:37:1218#include "base/bind.h"
[email protected]aa22b242011-11-16 18:58:2919#include "base/bind_helpers.h"
[email protected]0f292de02012-02-01 22:28:2020#include "base/callback.h"
[email protected]b59ff372009-07-15 22:04:3221#include "base/compiler_specific.h"
[email protected]58580352010-10-26 04:07:5022#include "base/debug/debugger.h"
23#include "base/debug/stack_trace.h"
[email protected]3e9d9cc2011-05-03 21:08:1524#include "base/message_loop_proxy.h"
[email protected]1e9bbd22010-10-15 16:42:4525#include "base/metrics/field_trial.h"
[email protected]835d7c82010-10-14 04:38:3826#include "base/metrics/histogram.h"
[email protected]7286e3fc2011-07-19 22:13:2427#include "base/stl_util.h"
[email protected]b59ff372009-07-15 22:04:3228#include "base/string_util.h"
[email protected]ac9ba8fe2010-12-30 18:08:3629#include "base/threading/worker_pool.h"
[email protected]b59ff372009-07-15 22:04:3230#include "base/time.h"
[email protected]ccaff652010-07-31 06:28:2031#include "base/utf_string_conversions.h"
[email protected]21526002010-05-16 19:42:4632#include "base/values.h"
[email protected]b3601bc22012-02-21 21:23:2033#include "net/base/address_family.h"
[email protected]b59ff372009-07-15 22:04:3234#include "net/base/address_list.h"
[email protected]46018c9d2011-09-06 03:42:3435#include "net/base/dns_reloader.h"
[email protected]ee094b82010-08-24 15:55:5136#include "net/base/host_port_pair.h"
[email protected]b59ff372009-07-15 22:04:3237#include "net/base/host_resolver_proc.h"
[email protected]2bb04442010-08-18 18:01:1538#include "net/base/net_errors.h"
[email protected]ee094b82010-08-24 15:55:5139#include "net/base/net_log.h"
[email protected]0f8f1b432010-03-16 19:06:0340#include "net/base/net_util.h"
[email protected]0adcb2b2012-08-15 21:30:4641#include "net/dns/address_sorter.h"
[email protected]78eac2a2012-03-14 19:09:2742#include "net/dns/dns_client.h"
[email protected]b3601bc22012-02-21 21:23:2043#include "net/dns/dns_config_service.h"
44#include "net/dns/dns_protocol.h"
45#include "net/dns/dns_response.h"
[email protected]b3601bc22012-02-21 21:23:2046#include "net/dns/dns_transaction.h"
[email protected]b59ff372009-07-15 22:04:3247
48#if defined(OS_WIN)
49#include "net/base/winsock_init.h"
50#endif
51
52namespace net {
53
[email protected]e95d3aca2010-01-11 22:47:4354namespace {
55
[email protected]6e78dfb2011-07-28 21:34:4756// Limit the size of hostnames that will be resolved to combat issues in
57// some platform's resolvers.
58const size_t kMaxHostLength = 4096;
59
[email protected]a2730882012-01-21 00:56:2760// Default TTL for successful resolutions with ProcTask.
61const unsigned kCacheEntryTTLSeconds = 60;
62
[email protected]b3601bc22012-02-21 21:23:2063// Default TTL for unsuccessful resolutions with ProcTask.
64const unsigned kNegativeCacheEntryTTLSeconds = 0;
65
[email protected]24f4bab2010-10-15 01:27:1166// We use a separate histogram name for each platform to facilitate the
67// display of error codes by their symbolic name (since each platform has
68// different mappings).
69const char kOSErrorsForGetAddrinfoHistogramName[] =
70#if defined(OS_WIN)
71 "Net.OSErrorsForGetAddrinfo_Win";
72#elif defined(OS_MACOSX)
73 "Net.OSErrorsForGetAddrinfo_Mac";
74#elif defined(OS_LINUX)
75 "Net.OSErrorsForGetAddrinfo_Linux";
76#else
77 "Net.OSErrorsForGetAddrinfo";
78#endif
79
[email protected]c89b2442011-05-26 14:28:2780// Gets a list of the likely error codes that getaddrinfo() can return
81// (non-exhaustive). These are the error codes that we will track via
82// a histogram.
83std::vector<int> GetAllGetAddrinfoOSErrors() {
84 int os_errors[] = {
85#if defined(OS_POSIX)
[email protected]23f771162011-06-02 18:37:5186#if !defined(OS_FREEBSD)
[email protected]39588992011-07-11 19:54:3787#if !defined(OS_ANDROID)
[email protected]c48aef92011-11-22 23:41:4588 // EAI_ADDRFAMILY has been declared obsolete in Android's and
89 // FreeBSD's netdb.h.
[email protected]c89b2442011-05-26 14:28:2790 EAI_ADDRFAMILY,
[email protected]39588992011-07-11 19:54:3791#endif
[email protected]c48aef92011-11-22 23:41:4592 // EAI_NODATA has been declared obsolete in FreeBSD's netdb.h.
[email protected]23f771162011-06-02 18:37:5193 EAI_NODATA,
94#endif
[email protected]c89b2442011-05-26 14:28:2795 EAI_AGAIN,
96 EAI_BADFLAGS,
97 EAI_FAIL,
98 EAI_FAMILY,
99 EAI_MEMORY,
[email protected]c89b2442011-05-26 14:28:27100 EAI_NONAME,
101 EAI_SERVICE,
102 EAI_SOCKTYPE,
103 EAI_SYSTEM,
104#elif defined(OS_WIN)
105 // See: http://msdn.microsoft.com/en-us/library/ms738520(VS.85).aspx
106 WSA_NOT_ENOUGH_MEMORY,
107 WSAEAFNOSUPPORT,
108 WSAEINVAL,
109 WSAESOCKTNOSUPPORT,
110 WSAHOST_NOT_FOUND,
111 WSANO_DATA,
112 WSANO_RECOVERY,
113 WSANOTINITIALISED,
114 WSATRY_AGAIN,
115 WSATYPE_NOT_FOUND,
116 // The following are not in doc, but might be to appearing in results :-(.
117 WSA_INVALID_HANDLE,
118#endif
119 };
120
121 // Ensure all errors are positive, as histogram only tracks positive values.
122 for (size_t i = 0; i < arraysize(os_errors); ++i) {
123 os_errors[i] = std::abs(os_errors[i]);
124 }
125
126 return base::CustomHistogram::ArrayToCustomRanges(os_errors,
127 arraysize(os_errors));
128}
129
[email protected]1def74c2012-03-22 20:07:00130enum DnsResolveStatus {
131 RESOLVE_STATUS_DNS_SUCCESS = 0,
132 RESOLVE_STATUS_PROC_SUCCESS,
133 RESOLVE_STATUS_FAIL,
[email protected]1d932852012-06-19 19:40:33134 RESOLVE_STATUS_SUSPECT_NETBIOS,
[email protected]1def74c2012-03-22 20:07:00135 RESOLVE_STATUS_MAX
136};
137
138void UmaAsyncDnsResolveStatus(DnsResolveStatus result) {
139 UMA_HISTOGRAM_ENUMERATION("AsyncDNS.ResolveStatus",
140 result,
141 RESOLVE_STATUS_MAX);
142}
143
[email protected]1d932852012-06-19 19:40:33144bool ResemblesNetBIOSName(const std::string& hostname) {
145 return (hostname.size() < 16) && (hostname.find('.') == std::string::npos);
146}
147
148// True if |hostname| ends with either ".local" or ".local.".
149bool ResemblesMulticastDNSName(const std::string& hostname) {
150 DCHECK(!hostname.empty());
151 const char kSuffix[] = ".local.";
152 const size_t kSuffixLen = sizeof(kSuffix) - 1;
153 const size_t kSuffixLenTrimmed = kSuffixLen - 1;
154 if (hostname[hostname.size() - 1] == '.') {
155 return hostname.size() > kSuffixLen &&
156 !hostname.compare(hostname.size() - kSuffixLen, kSuffixLen, kSuffix);
157 }
158 return hostname.size() > kSuffixLenTrimmed &&
159 !hostname.compare(hostname.size() - kSuffixLenTrimmed, kSuffixLenTrimmed,
160 kSuffix, kSuffixLenTrimmed);
161}
162
[email protected]51b9a6b2012-06-25 21:50:29163// Provide a common macro to simplify code and readability. We must use a
164// macro as the underlying HISTOGRAM macro creates static variables.
165#define DNS_HISTOGRAM(name, time) UMA_HISTOGRAM_CUSTOM_TIMES(name, time, \
166 base::TimeDelta::FromMilliseconds(1), base::TimeDelta::FromHours(1), 100)
167
168// A macro to simplify code and readability.
169#define DNS_HISTOGRAM_BY_PRIORITY(basename, priority, time) \
170 do { \
171 switch (priority) { \
172 case HIGHEST: DNS_HISTOGRAM(basename "_HIGHEST", time); break; \
173 case MEDIUM: DNS_HISTOGRAM(basename "_MEDIUM", time); break; \
174 case LOW: DNS_HISTOGRAM(basename "_LOW", time); break; \
175 case LOWEST: DNS_HISTOGRAM(basename "_LOWEST", time); break; \
176 case IDLE: DNS_HISTOGRAM(basename "_IDLE", time); break; \
177 default: NOTREACHED(); break; \
178 } \
179 DNS_HISTOGRAM(basename, time); \
180 } while (0)
181
182// Record time from Request creation until a valid DNS response.
183void RecordTotalTime(bool had_dns_config,
184 bool speculative,
185 base::TimeDelta duration) {
186 if (had_dns_config) {
187 if (speculative) {
188 DNS_HISTOGRAM("AsyncDNS.TotalTime_speculative", duration);
189 } else {
190 DNS_HISTOGRAM("AsyncDNS.TotalTime", duration);
191 }
192 } else {
193 if (speculative) {
194 DNS_HISTOGRAM("DNS.TotalTime_speculative", duration);
195 } else {
196 DNS_HISTOGRAM("DNS.TotalTime", duration);
197 }
198 }
199}
200
[email protected]1339a2a22012-10-17 08:39:43201void RecordTTL(base::TimeDelta ttl) {
202 UMA_HISTOGRAM_CUSTOM_TIMES("AsyncDNS.TTL", ttl,
203 base::TimeDelta::FromSeconds(1),
204 base::TimeDelta::FromDays(1), 100);
205}
206
[email protected]d7b9a2b2012-05-31 22:31:19207//-----------------------------------------------------------------------------
208
[email protected]0f292de02012-02-01 22:28:20209// Wraps call to SystemHostResolverProc as an instance of HostResolverProc.
210// TODO(szym): This should probably be declared in host_resolver_proc.h.
211class CallSystemHostResolverProc : public HostResolverProc {
212 public:
213 CallSystemHostResolverProc() : HostResolverProc(NULL) {}
214 virtual int Resolve(const std::string& hostname,
215 AddressFamily address_family,
216 HostResolverFlags host_resolver_flags,
[email protected]b3601bc22012-02-21 21:23:20217 AddressList* addr_list,
[email protected]0f292de02012-02-01 22:28:20218 int* os_error) OVERRIDE {
219 return SystemHostResolverProc(hostname,
220 address_family,
221 host_resolver_flags,
[email protected]b3601bc22012-02-21 21:23:20222 addr_list,
[email protected]0f292de02012-02-01 22:28:20223 os_error);
[email protected]b59ff372009-07-15 22:04:32224 }
[email protected]a9813302012-04-28 09:29:28225
226 protected:
227 virtual ~CallSystemHostResolverProc() {}
[email protected]0f292de02012-02-01 22:28:20228};
[email protected]b59ff372009-07-15 22:04:32229
[email protected]7054e78f2012-05-07 21:44:56230void EnsurePortOnAddressList(uint16 port, AddressList* list) {
231 DCHECK(list);
232 if (list->empty() || list->front().port() == port)
233 return;
234 SetPortOnAddressList(port, list);
235}
236
[email protected]cd565142012-06-12 16:21:45237// Creates NetLog parameters when the resolve failed.
238base::Value* NetLogProcTaskFailedCallback(uint32 attempt_number,
239 int net_error,
240 int os_error,
241 NetLog::LogLevel /* log_level */) {
242 DictionaryValue* dict = new DictionaryValue();
243 if (attempt_number)
244 dict->SetInteger("attempt_number", attempt_number);
[email protected]21526002010-05-16 19:42:46245
[email protected]cd565142012-06-12 16:21:45246 dict->SetInteger("net_error", net_error);
[email protected]13024882011-05-18 23:19:16247
[email protected]cd565142012-06-12 16:21:45248 if (os_error) {
249 dict->SetInteger("os_error", os_error);
[email protected]21526002010-05-16 19:42:46250#if defined(OS_POSIX)
[email protected]cd565142012-06-12 16:21:45251 dict->SetString("os_error_string", gai_strerror(os_error));
[email protected]21526002010-05-16 19:42:46252#elif defined(OS_WIN)
[email protected]cd565142012-06-12 16:21:45253 // Map the error code to a human-readable string.
254 LPWSTR error_string = NULL;
255 int size = FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
256 FORMAT_MESSAGE_FROM_SYSTEM,
257 0, // Use the internal message table.
258 os_error,
259 0, // Use default language.
260 (LPWSTR)&error_string,
261 0, // Buffer size.
262 0); // Arguments (unused).
263 dict->SetString("os_error_string", WideToUTF8(error_string));
264 LocalFree(error_string);
[email protected]21526002010-05-16 19:42:46265#endif
[email protected]21526002010-05-16 19:42:46266 }
267
[email protected]cd565142012-06-12 16:21:45268 return dict;
269}
[email protected]a9813302012-04-28 09:29:28270
[email protected]cd565142012-06-12 16:21:45271// Creates NetLog parameters when the DnsTask failed.
272base::Value* NetLogDnsTaskFailedCallback(int net_error,
273 int dns_error,
274 NetLog::LogLevel /* log_level */) {
275 DictionaryValue* dict = new DictionaryValue();
276 dict->SetInteger("net_error", net_error);
277 if (dns_error)
278 dict->SetInteger("dns_error", dns_error);
279 return dict;
[email protected]ee094b82010-08-24 15:55:51280};
281
[email protected]cd565142012-06-12 16:21:45282// Creates NetLog parameters containing the information in a RequestInfo object,
283// along with the associated NetLog::Source.
284base::Value* NetLogRequestInfoCallback(const NetLog::Source& source,
285 const HostResolver::RequestInfo* info,
286 NetLog::LogLevel /* log_level */) {
287 DictionaryValue* dict = new DictionaryValue();
288 source.AddToEventParameters(dict);
[email protected]b3601bc22012-02-21 21:23:20289
[email protected]cd565142012-06-12 16:21:45290 dict->SetString("host", info->host_port_pair().ToString());
291 dict->SetInteger("address_family",
292 static_cast<int>(info->address_family()));
293 dict->SetBoolean("allow_cached_response", info->allow_cached_response());
294 dict->SetBoolean("is_speculative", info->is_speculative());
295 dict->SetInteger("priority", info->priority());
296 return dict;
297}
[email protected]b3601bc22012-02-21 21:23:20298
[email protected]cd565142012-06-12 16:21:45299// Creates NetLog parameters for the creation of a HostResolverImpl::Job.
300base::Value* NetLogJobCreationCallback(const NetLog::Source& source,
301 const std::string* host,
302 NetLog::LogLevel /* log_level */) {
303 DictionaryValue* dict = new DictionaryValue();
304 source.AddToEventParameters(dict);
305 dict->SetString("host", *host);
306 return dict;
307}
[email protected]a9813302012-04-28 09:29:28308
[email protected]cd565142012-06-12 16:21:45309// Creates NetLog parameters for HOST_RESOLVER_IMPL_JOB_ATTACH/DETACH events.
310base::Value* NetLogJobAttachCallback(const NetLog::Source& source,
311 RequestPriority priority,
312 NetLog::LogLevel /* log_level */) {
313 DictionaryValue* dict = new DictionaryValue();
314 source.AddToEventParameters(dict);
315 dict->SetInteger("priority", priority);
316 return dict;
317}
[email protected]b3601bc22012-02-21 21:23:20318
[email protected]cd565142012-06-12 16:21:45319// Creates NetLog parameters for the DNS_CONFIG_CHANGED event.
320base::Value* NetLogDnsConfigCallback(const DnsConfig* config,
321 NetLog::LogLevel /* log_level */) {
322 return config->ToValue();
323}
[email protected]b4481b222012-03-16 17:13:11324
[email protected]0f292de02012-02-01 22:28:20325// The logging routines are defined here because some requests are resolved
326// without a Request object.
327
328// Logs when a request has just been started.
329void LogStartRequest(const BoundNetLog& source_net_log,
330 const BoundNetLog& request_net_log,
331 const HostResolver::RequestInfo& info) {
332 source_net_log.BeginEvent(
333 NetLog::TYPE_HOST_RESOLVER_IMPL,
[email protected]cd565142012-06-12 16:21:45334 request_net_log.source().ToEventParametersCallback());
[email protected]0f292de02012-02-01 22:28:20335
336 request_net_log.BeginEvent(
337 NetLog::TYPE_HOST_RESOLVER_IMPL_REQUEST,
[email protected]cd565142012-06-12 16:21:45338 base::Bind(&NetLogRequestInfoCallback, source_net_log.source(), &info));
[email protected]0f292de02012-02-01 22:28:20339}
340
341// Logs when a request has just completed (before its callback is run).
342void LogFinishRequest(const BoundNetLog& source_net_log,
343 const BoundNetLog& request_net_log,
344 const HostResolver::RequestInfo& info,
[email protected]b3601bc22012-02-21 21:23:20345 int net_error) {
346 request_net_log.EndEventWithNetErrorCode(
347 NetLog::TYPE_HOST_RESOLVER_IMPL_REQUEST, net_error);
[email protected]4da911f2012-06-14 19:45:20348 source_net_log.EndEvent(NetLog::TYPE_HOST_RESOLVER_IMPL);
[email protected]0f292de02012-02-01 22:28:20349}
350
351// Logs when a request has been cancelled.
352void LogCancelRequest(const BoundNetLog& source_net_log,
353 const BoundNetLog& request_net_log,
354 const HostResolverImpl::RequestInfo& info) {
[email protected]4da911f2012-06-14 19:45:20355 request_net_log.AddEvent(NetLog::TYPE_CANCELLED);
356 request_net_log.EndEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_REQUEST);
357 source_net_log.EndEvent(NetLog::TYPE_HOST_RESOLVER_IMPL);
[email protected]0f292de02012-02-01 22:28:20358}
359
[email protected]b59ff372009-07-15 22:04:32360//-----------------------------------------------------------------------------
361
[email protected]0f292de02012-02-01 22:28:20362// Keeps track of the highest priority.
363class PriorityTracker {
364 public:
[email protected]8c98d002012-07-18 19:02:27365 explicit PriorityTracker(RequestPriority initial_priority)
366 : highest_priority_(initial_priority), total_count_(0) {
[email protected]0f292de02012-02-01 22:28:20367 memset(counts_, 0, sizeof(counts_));
368 }
369
370 RequestPriority highest_priority() const {
371 return highest_priority_;
372 }
373
374 size_t total_count() const {
375 return total_count_;
376 }
377
378 void Add(RequestPriority req_priority) {
379 ++total_count_;
380 ++counts_[req_priority];
[email protected]31ae7ab2012-04-24 21:09:05381 if (highest_priority_ < req_priority)
[email protected]0f292de02012-02-01 22:28:20382 highest_priority_ = req_priority;
383 }
384
385 void Remove(RequestPriority req_priority) {
386 DCHECK_GT(total_count_, 0u);
387 DCHECK_GT(counts_[req_priority], 0u);
388 --total_count_;
389 --counts_[req_priority];
390 size_t i;
[email protected]31ae7ab2012-04-24 21:09:05391 for (i = highest_priority_; i > MINIMUM_PRIORITY && !counts_[i]; --i);
[email protected]0f292de02012-02-01 22:28:20392 highest_priority_ = static_cast<RequestPriority>(i);
393
[email protected]31ae7ab2012-04-24 21:09:05394 // In absence of requests, default to MINIMUM_PRIORITY.
395 if (total_count_ == 0)
396 DCHECK_EQ(MINIMUM_PRIORITY, highest_priority_);
[email protected]0f292de02012-02-01 22:28:20397 }
398
399 private:
400 RequestPriority highest_priority_;
401 size_t total_count_;
402 size_t counts_[NUM_PRIORITIES];
403};
404
[email protected]c54a8912012-10-22 22:09:43405} // namespace
[email protected]0f292de02012-02-01 22:28:20406
407//-----------------------------------------------------------------------------
408
409// Holds the data for a request that could not be completed synchronously.
410// It is owned by a Job. Canceled Requests are only marked as canceled rather
411// than removed from the Job's |requests_| list.
[email protected]b59ff372009-07-15 22:04:32412class HostResolverImpl::Request {
413 public:
[email protected]ee094b82010-08-24 15:55:51414 Request(const BoundNetLog& source_net_log,
415 const BoundNetLog& request_net_log,
[email protected]54e13772009-08-14 03:01:09416 const RequestInfo& info,
[email protected]aa22b242011-11-16 18:58:29417 const CompletionCallback& callback,
[email protected]b59ff372009-07-15 22:04:32418 AddressList* addresses)
[email protected]ee094b82010-08-24 15:55:51419 : source_net_log_(source_net_log),
420 request_net_log_(request_net_log),
[email protected]54e13772009-08-14 03:01:09421 info_(info),
422 job_(NULL),
423 callback_(callback),
[email protected]51b9a6b2012-06-25 21:50:29424 addresses_(addresses),
425 request_time_(base::TimeTicks::Now()) {
[email protected]54e13772009-08-14 03:01:09426 }
[email protected]b59ff372009-07-15 22:04:32427
[email protected]0f292de02012-02-01 22:28:20428 // Mark the request as canceled.
429 void MarkAsCanceled() {
[email protected]b59ff372009-07-15 22:04:32430 job_ = NULL;
[email protected]b59ff372009-07-15 22:04:32431 addresses_ = NULL;
[email protected]aa22b242011-11-16 18:58:29432 callback_.Reset();
[email protected]b59ff372009-07-15 22:04:32433 }
434
[email protected]0f292de02012-02-01 22:28:20435 bool was_canceled() const {
[email protected]aa22b242011-11-16 18:58:29436 return callback_.is_null();
[email protected]b59ff372009-07-15 22:04:32437 }
438
439 void set_job(Job* job) {
[email protected]0f292de02012-02-01 22:28:20440 DCHECK(job);
[email protected]b59ff372009-07-15 22:04:32441 // Identify which job the request is waiting on.
442 job_ = job;
443 }
444
[email protected]0f292de02012-02-01 22:28:20445 // Prepare final AddressList and call completion callback.
[email protected]b3601bc22012-02-21 21:23:20446 void OnComplete(int error, const AddressList& addr_list) {
[email protected]51b9a6b2012-06-25 21:50:29447 DCHECK(!was_canceled());
[email protected]7054e78f2012-05-07 21:44:56448 if (error == OK) {
449 *addresses_ = addr_list;
450 EnsurePortOnAddressList(info_.port(), addresses_);
451 }
[email protected]aa22b242011-11-16 18:58:29452 CompletionCallback callback = callback_;
[email protected]0f292de02012-02-01 22:28:20453 MarkAsCanceled();
[email protected]aa22b242011-11-16 18:58:29454 callback.Run(error);
[email protected]b59ff372009-07-15 22:04:32455 }
456
[email protected]b59ff372009-07-15 22:04:32457 Job* job() const {
458 return job_;
459 }
460
[email protected]0f292de02012-02-01 22:28:20461 // NetLog for the source, passed in HostResolver::Resolve.
[email protected]ee094b82010-08-24 15:55:51462 const BoundNetLog& source_net_log() {
463 return source_net_log_;
464 }
465
[email protected]0f292de02012-02-01 22:28:20466 // NetLog for this request.
[email protected]ee094b82010-08-24 15:55:51467 const BoundNetLog& request_net_log() {
468 return request_net_log_;
[email protected]54e13772009-08-14 03:01:09469 }
470
[email protected]b59ff372009-07-15 22:04:32471 const RequestInfo& info() const {
472 return info_;
473 }
474
[email protected]51b9a6b2012-06-25 21:50:29475 base::TimeTicks request_time() const {
476 return request_time_;
477 }
478
[email protected]b59ff372009-07-15 22:04:32479 private:
[email protected]ee094b82010-08-24 15:55:51480 BoundNetLog source_net_log_;
481 BoundNetLog request_net_log_;
[email protected]54e13772009-08-14 03:01:09482
[email protected]b59ff372009-07-15 22:04:32483 // The request info that started the request.
484 RequestInfo info_;
485
[email protected]0f292de02012-02-01 22:28:20486 // The resolve job that this request is dependent on.
[email protected]b59ff372009-07-15 22:04:32487 Job* job_;
488
489 // The user's callback to invoke when the request completes.
[email protected]aa22b242011-11-16 18:58:29490 CompletionCallback callback_;
[email protected]b59ff372009-07-15 22:04:32491
492 // The address list to save result into.
493 AddressList* addresses_;
494
[email protected]51b9a6b2012-06-25 21:50:29495 const base::TimeTicks request_time_;
496
[email protected]b59ff372009-07-15 22:04:32497 DISALLOW_COPY_AND_ASSIGN(Request);
498};
499
[email protected]1e9bbd22010-10-15 16:42:45500//------------------------------------------------------------------------------
501
[email protected]0f292de02012-02-01 22:28:20502// Calls HostResolverProc on the WorkerPool. Performs retries if necessary.
503//
504// Whenever we try to resolve the host, we post a delayed task to check if host
505// resolution (OnLookupComplete) is completed or not. If the original attempt
506// hasn't completed, then we start another attempt for host resolution. We take
507// the results from the first attempt that finishes and ignore the results from
508// all other attempts.
509//
510// TODO(szym): Move to separate source file for testing and mocking.
511//
512class HostResolverImpl::ProcTask
513 : public base::RefCountedThreadSafe<HostResolverImpl::ProcTask> {
[email protected]b59ff372009-07-15 22:04:32514 public:
[email protected]b3601bc22012-02-21 21:23:20515 typedef base::Callback<void(int net_error,
516 const AddressList& addr_list)> Callback;
[email protected]b59ff372009-07-15 22:04:32517
[email protected]0f292de02012-02-01 22:28:20518 ProcTask(const Key& key,
519 const ProcTaskParams& params,
520 const Callback& callback,
521 const BoundNetLog& job_net_log)
522 : key_(key),
523 params_(params),
524 callback_(callback),
525 origin_loop_(base::MessageLoopProxy::current()),
526 attempt_number_(0),
527 completed_attempt_number_(0),
528 completed_attempt_error_(ERR_UNEXPECTED),
529 had_non_speculative_request_(false),
[email protected]b3601bc22012-02-21 21:23:20530 net_log_(job_net_log) {
[email protected]0f292de02012-02-01 22:28:20531 if (!params_.resolver_proc)
532 params_.resolver_proc = HostResolverProc::GetDefault();
533 // If default is unset, use the system proc.
534 if (!params_.resolver_proc)
535 params_.resolver_proc = new CallSystemHostResolverProc();
[email protected]b59ff372009-07-15 22:04:32536 }
537
[email protected]b59ff372009-07-15 22:04:32538 void Start() {
[email protected]3e9d9cc2011-05-03 21:08:15539 DCHECK(origin_loop_->BelongsToCurrentThread());
[email protected]4da911f2012-06-14 19:45:20540 net_log_.BeginEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_PROC_TASK);
[email protected]189163e2011-05-11 01:48:54541 StartLookupAttempt();
542 }
[email protected]252b699b2010-02-05 21:38:06543
[email protected]0f292de02012-02-01 22:28:20544 // Cancels this ProcTask. It will be orphaned. Any outstanding resolve
545 // attempts running on worker threads will continue running. Only once all the
546 // attempts complete will the final reference to this ProcTask be released.
547 void Cancel() {
548 DCHECK(origin_loop_->BelongsToCurrentThread());
549
[email protected]0adcb2b2012-08-15 21:30:46550 if (was_canceled() || was_completed())
[email protected]0f292de02012-02-01 22:28:20551 return;
552
[email protected]0f292de02012-02-01 22:28:20553 callback_.Reset();
[email protected]4da911f2012-06-14 19:45:20554 net_log_.EndEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_PROC_TASK);
[email protected]0f292de02012-02-01 22:28:20555 }
556
557 void set_had_non_speculative_request() {
558 DCHECK(origin_loop_->BelongsToCurrentThread());
559 had_non_speculative_request_ = true;
560 }
561
562 bool was_canceled() const {
563 DCHECK(origin_loop_->BelongsToCurrentThread());
564 return callback_.is_null();
565 }
566
567 bool was_completed() const {
568 DCHECK(origin_loop_->BelongsToCurrentThread());
569 return completed_attempt_number_ > 0;
570 }
571
572 private:
[email protected]a9813302012-04-28 09:29:28573 friend class base::RefCountedThreadSafe<ProcTask>;
574 ~ProcTask() {}
575
[email protected]189163e2011-05-11 01:48:54576 void StartLookupAttempt() {
577 DCHECK(origin_loop_->BelongsToCurrentThread());
578 base::TimeTicks start_time = base::TimeTicks::Now();
579 ++attempt_number_;
580 // Dispatch the lookup attempt to a worker thread.
581 if (!base::WorkerPool::PostTask(
582 FROM_HERE,
[email protected]0f292de02012-02-01 22:28:20583 base::Bind(&ProcTask::DoLookup, this, start_time, attempt_number_),
[email protected]189163e2011-05-11 01:48:54584 true)) {
[email protected]b59ff372009-07-15 22:04:32585 NOTREACHED();
586
587 // Since we could be running within Resolve() right now, we can't just
588 // call OnLookupComplete(). Instead we must wait until Resolve() has
589 // returned (IO_PENDING).
[email protected]3e9d9cc2011-05-03 21:08:15590 origin_loop_->PostTask(
[email protected]189163e2011-05-11 01:48:54591 FROM_HERE,
[email protected]0f292de02012-02-01 22:28:20592 base::Bind(&ProcTask::OnLookupComplete, this, AddressList(),
[email protected]33152acc2011-10-20 23:37:12593 start_time, attempt_number_, ERR_UNEXPECTED, 0));
[email protected]189163e2011-05-11 01:48:54594 return;
[email protected]b59ff372009-07-15 22:04:32595 }
[email protected]13024882011-05-18 23:19:16596
597 net_log_.AddEvent(
598 NetLog::TYPE_HOST_RESOLVER_IMPL_ATTEMPT_STARTED,
[email protected]cd565142012-06-12 16:21:45599 NetLog::IntegerCallback("attempt_number", attempt_number_));
[email protected]13024882011-05-18 23:19:16600
[email protected]0f292de02012-02-01 22:28:20601 // If we don't get the results within a given time, RetryIfNotComplete
602 // will start a new attempt on a different worker thread if none of our
603 // outstanding attempts have completed yet.
604 if (attempt_number_ <= params_.max_retry_attempts) {
[email protected]06ef6d92011-05-19 04:24:58605 origin_loop_->PostDelayedTask(
606 FROM_HERE,
[email protected]0f292de02012-02-01 22:28:20607 base::Bind(&ProcTask::RetryIfNotComplete, this),
[email protected]7e560102012-03-08 20:58:42608 params_.unresponsive_delay);
[email protected]06ef6d92011-05-19 04:24:58609 }
[email protected]b59ff372009-07-15 22:04:32610 }
611
[email protected]6c710ee2010-05-07 07:51:16612 // WARNING: This code runs inside a worker pool. The shutdown code cannot
613 // wait for it to finish, so we must be very careful here about using other
614 // objects (like MessageLoops, Singletons, etc). During shutdown these objects
[email protected]189163e2011-05-11 01:48:54615 // may no longer exist. Multiple DoLookups() could be running in parallel, so
616 // any state inside of |this| must not mutate .
617 void DoLookup(const base::TimeTicks& start_time,
618 const uint32 attempt_number) {
619 AddressList results;
620 int os_error = 0;
[email protected]b59ff372009-07-15 22:04:32621 // Running on the worker thread
[email protected]0f292de02012-02-01 22:28:20622 int error = params_.resolver_proc->Resolve(key_.hostname,
623 key_.address_family,
624 key_.host_resolver_flags,
625 &results,
626 &os_error);
[email protected]b59ff372009-07-15 22:04:32627
[email protected]189163e2011-05-11 01:48:54628 origin_loop_->PostTask(
629 FROM_HERE,
[email protected]0f292de02012-02-01 22:28:20630 base::Bind(&ProcTask::OnLookupComplete, this, results, start_time,
[email protected]33152acc2011-10-20 23:37:12631 attempt_number, error, os_error));
[email protected]189163e2011-05-11 01:48:54632 }
633
[email protected]0f292de02012-02-01 22:28:20634 // Makes next attempt if DoLookup() has not finished (runs on origin thread).
635 void RetryIfNotComplete() {
[email protected]189163e2011-05-11 01:48:54636 DCHECK(origin_loop_->BelongsToCurrentThread());
637
[email protected]0f292de02012-02-01 22:28:20638 if (was_completed() || was_canceled())
[email protected]189163e2011-05-11 01:48:54639 return;
640
[email protected]0f292de02012-02-01 22:28:20641 params_.unresponsive_delay *= params_.retry_factor;
[email protected]189163e2011-05-11 01:48:54642 StartLookupAttempt();
[email protected]b59ff372009-07-15 22:04:32643 }
644
645 // Callback for when DoLookup() completes (runs on origin thread).
[email protected]189163e2011-05-11 01:48:54646 void OnLookupComplete(const AddressList& results,
647 const base::TimeTicks& start_time,
648 const uint32 attempt_number,
649 int error,
650 const int os_error) {
[email protected]3e9d9cc2011-05-03 21:08:15651 DCHECK(origin_loop_->BelongsToCurrentThread());
[email protected]7054e78f2012-05-07 21:44:56652 DCHECK(error || !results.empty());
[email protected]189163e2011-05-11 01:48:54653
654 bool was_retry_attempt = attempt_number > 1;
655
[email protected]2d3b7762010-10-09 00:35:47656 // Ideally the following code would be part of host_resolver_proc.cc,
[email protected]b3601bc22012-02-21 21:23:20657 // however it isn't safe to call NetworkChangeNotifier from worker threads.
658 // So we do it here on the IO thread instead.
[email protected]189163e2011-05-11 01:48:54659 if (error != OK && NetworkChangeNotifier::IsOffline())
660 error = ERR_INTERNET_DISCONNECTED;
[email protected]2d3b7762010-10-09 00:35:47661
[email protected]b3601bc22012-02-21 21:23:20662 // If this is the first attempt that is finishing later, then record data
663 // for the first attempt. Won't contaminate with retry attempt's data.
[email protected]189163e2011-05-11 01:48:54664 if (!was_retry_attempt)
665 RecordPerformanceHistograms(start_time, error, os_error);
666
667 RecordAttemptHistograms(start_time, attempt_number, error, os_error);
[email protected]f2d8c4212010-02-02 00:56:35668
[email protected]0f292de02012-02-01 22:28:20669 if (was_canceled())
[email protected]b59ff372009-07-15 22:04:32670 return;
671
[email protected]cd565142012-06-12 16:21:45672 NetLog::ParametersCallback net_log_callback;
[email protected]0f292de02012-02-01 22:28:20673 if (error != OK) {
[email protected]cd565142012-06-12 16:21:45674 net_log_callback = base::Bind(&NetLogProcTaskFailedCallback,
675 attempt_number,
676 error,
677 os_error);
[email protected]0f292de02012-02-01 22:28:20678 } else {
[email protected]cd565142012-06-12 16:21:45679 net_log_callback = NetLog::IntegerCallback("attempt_number",
680 attempt_number);
[email protected]0f292de02012-02-01 22:28:20681 }
[email protected]cd565142012-06-12 16:21:45682 net_log_.AddEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_ATTEMPT_FINISHED,
683 net_log_callback);
[email protected]0f292de02012-02-01 22:28:20684
685 if (was_completed())
686 return;
687
688 // Copy the results from the first worker thread that resolves the host.
689 results_ = results;
690 completed_attempt_number_ = attempt_number;
691 completed_attempt_error_ = error;
692
[email protected]e87b8b512011-06-14 22:12:52693 if (was_retry_attempt) {
694 // If retry attempt finishes before 1st attempt, then get stats on how
695 // much time is saved by having spawned an extra attempt.
696 retry_attempt_finished_time_ = base::TimeTicks::Now();
697 }
698
[email protected]189163e2011-05-11 01:48:54699 if (error != OK) {
[email protected]cd565142012-06-12 16:21:45700 net_log_callback = base::Bind(&NetLogProcTaskFailedCallback,
701 0, error, os_error);
[email protected]ee094b82010-08-24 15:55:51702 } else {
[email protected]cd565142012-06-12 16:21:45703 net_log_callback = results_.CreateNetLogCallback();
[email protected]ee094b82010-08-24 15:55:51704 }
[email protected]cd565142012-06-12 16:21:45705 net_log_.EndEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_PROC_TASK,
706 net_log_callback);
[email protected]ee094b82010-08-24 15:55:51707
[email protected]b3601bc22012-02-21 21:23:20708 callback_.Run(error, results_);
[email protected]b59ff372009-07-15 22:04:32709 }
710
[email protected]189163e2011-05-11 01:48:54711 void RecordPerformanceHistograms(const base::TimeTicks& start_time,
712 const int error,
713 const int os_error) const {
[email protected]3e9d9cc2011-05-03 21:08:15714 DCHECK(origin_loop_->BelongsToCurrentThread());
[email protected]1e9bbd22010-10-15 16:42:45715 enum Category { // Used in HISTOGRAM_ENUMERATION.
716 RESOLVE_SUCCESS,
717 RESOLVE_FAIL,
718 RESOLVE_SPECULATIVE_SUCCESS,
719 RESOLVE_SPECULATIVE_FAIL,
720 RESOLVE_MAX, // Bounding value.
721 };
722 int category = RESOLVE_MAX; // Illegal value for later DCHECK only.
723
[email protected]189163e2011-05-11 01:48:54724 base::TimeDelta duration = base::TimeTicks::Now() - start_time;
725 if (error == OK) {
[email protected]1e9bbd22010-10-15 16:42:45726 if (had_non_speculative_request_) {
727 category = RESOLVE_SUCCESS;
728 DNS_HISTOGRAM("DNS.ResolveSuccess", duration);
729 } else {
730 category = RESOLVE_SPECULATIVE_SUCCESS;
731 DNS_HISTOGRAM("DNS.ResolveSpeculativeSuccess", duration);
732 }
[email protected]7e96d792011-06-10 17:08:23733
[email protected]78eac2a2012-03-14 19:09:27734 // Log DNS lookups based on |address_family|. This will help us determine
[email protected]7e96d792011-06-10 17:08:23735 // if IPv4 or IPv4/6 lookups are faster or slower.
736 switch(key_.address_family) {
737 case ADDRESS_FAMILY_IPV4:
738 DNS_HISTOGRAM("DNS.ResolveSuccess_FAMILY_IPV4", duration);
739 break;
740 case ADDRESS_FAMILY_IPV6:
741 DNS_HISTOGRAM("DNS.ResolveSuccess_FAMILY_IPV6", duration);
742 break;
743 case ADDRESS_FAMILY_UNSPECIFIED:
744 DNS_HISTOGRAM("DNS.ResolveSuccess_FAMILY_UNSPEC", duration);
745 break;
746 }
[email protected]1e9bbd22010-10-15 16:42:45747 } else {
748 if (had_non_speculative_request_) {
749 category = RESOLVE_FAIL;
750 DNS_HISTOGRAM("DNS.ResolveFail", duration);
751 } else {
752 category = RESOLVE_SPECULATIVE_FAIL;
753 DNS_HISTOGRAM("DNS.ResolveSpeculativeFail", duration);
754 }
[email protected]78eac2a2012-03-14 19:09:27755 // Log DNS lookups based on |address_family|. This will help us determine
[email protected]7e96d792011-06-10 17:08:23756 // if IPv4 or IPv4/6 lookups are faster or slower.
757 switch(key_.address_family) {
758 case ADDRESS_FAMILY_IPV4:
759 DNS_HISTOGRAM("DNS.ResolveFail_FAMILY_IPV4", duration);
760 break;
761 case ADDRESS_FAMILY_IPV6:
762 DNS_HISTOGRAM("DNS.ResolveFail_FAMILY_IPV6", duration);
763 break;
764 case ADDRESS_FAMILY_UNSPECIFIED:
765 DNS_HISTOGRAM("DNS.ResolveFail_FAMILY_UNSPEC", duration);
766 break;
767 }
[email protected]c833e322010-10-16 23:51:36768 UMA_HISTOGRAM_CUSTOM_ENUMERATION(kOSErrorsForGetAddrinfoHistogramName,
[email protected]189163e2011-05-11 01:48:54769 std::abs(os_error),
[email protected]1e9bbd22010-10-15 16:42:45770 GetAllGetAddrinfoOSErrors());
771 }
[email protected]051b6ab2010-10-18 16:50:46772 DCHECK_LT(category, static_cast<int>(RESOLVE_MAX)); // Be sure it was set.
[email protected]1e9bbd22010-10-15 16:42:45773
774 UMA_HISTOGRAM_ENUMERATION("DNS.ResolveCategory", category, RESOLVE_MAX);
775
[email protected]edafd4c2011-05-10 17:18:53776 static const bool show_speculative_experiment_histograms =
777 base::FieldTrialList::TrialExists("DnsImpact");
[email protected]ecd95ae2010-10-20 23:58:17778 if (show_speculative_experiment_histograms) {
[email protected]1e9bbd22010-10-15 16:42:45779 UMA_HISTOGRAM_ENUMERATION(
780 base::FieldTrial::MakeName("DNS.ResolveCategory", "DnsImpact"),
781 category, RESOLVE_MAX);
782 if (RESOLVE_SUCCESS == category) {
783 DNS_HISTOGRAM(base::FieldTrial::MakeName("DNS.ResolveSuccess",
784 "DnsImpact"), duration);
785 }
786 }
[email protected]edafd4c2011-05-10 17:18:53787 static const bool show_parallelism_experiment_histograms =
788 base::FieldTrialList::TrialExists("DnsParallelism");
[email protected]ecd95ae2010-10-20 23:58:17789 if (show_parallelism_experiment_histograms) {
790 UMA_HISTOGRAM_ENUMERATION(
791 base::FieldTrial::MakeName("DNS.ResolveCategory", "DnsParallelism"),
792 category, RESOLVE_MAX);
793 if (RESOLVE_SUCCESS == category) {
794 DNS_HISTOGRAM(base::FieldTrial::MakeName("DNS.ResolveSuccess",
795 "DnsParallelism"), duration);
796 }
797 }
[email protected]1e9bbd22010-10-15 16:42:45798 }
799
[email protected]189163e2011-05-11 01:48:54800 void RecordAttemptHistograms(const base::TimeTicks& start_time,
801 const uint32 attempt_number,
802 const int error,
803 const int os_error) const {
[email protected]0f292de02012-02-01 22:28:20804 DCHECK(origin_loop_->BelongsToCurrentThread());
[email protected]189163e2011-05-11 01:48:54805 bool first_attempt_to_complete =
806 completed_attempt_number_ == attempt_number;
[email protected]e87b8b512011-06-14 22:12:52807 bool is_first_attempt = (attempt_number == 1);
[email protected]1e9bbd22010-10-15 16:42:45808
[email protected]189163e2011-05-11 01:48:54809 if (first_attempt_to_complete) {
810 // If this was first attempt to complete, then record the resolution
811 // status of the attempt.
812 if (completed_attempt_error_ == OK) {
813 UMA_HISTOGRAM_ENUMERATION(
814 "DNS.AttemptFirstSuccess", attempt_number, 100);
815 } else {
816 UMA_HISTOGRAM_ENUMERATION(
817 "DNS.AttemptFirstFailure", attempt_number, 100);
818 }
819 }
820
821 if (error == OK)
822 UMA_HISTOGRAM_ENUMERATION("DNS.AttemptSuccess", attempt_number, 100);
823 else
824 UMA_HISTOGRAM_ENUMERATION("DNS.AttemptFailure", attempt_number, 100);
825
[email protected]e87b8b512011-06-14 22:12:52826 // If first attempt didn't finish before retry attempt, then calculate stats
827 // on how much time is saved by having spawned an extra attempt.
[email protected]0f292de02012-02-01 22:28:20828 if (!first_attempt_to_complete && is_first_attempt && !was_canceled()) {
[email protected]e87b8b512011-06-14 22:12:52829 DNS_HISTOGRAM("DNS.AttemptTimeSavedByRetry",
830 base::TimeTicks::Now() - retry_attempt_finished_time_);
831 }
832
[email protected]0f292de02012-02-01 22:28:20833 if (was_canceled() || !first_attempt_to_complete) {
[email protected]189163e2011-05-11 01:48:54834 // Count those attempts which completed after the job was already canceled
835 // OR after the job was already completed by an earlier attempt (so in
836 // effect).
837 UMA_HISTOGRAM_ENUMERATION("DNS.AttemptDiscarded", attempt_number, 100);
838
[email protected]0f292de02012-02-01 22:28:20839 // Record if job is canceled.
840 if (was_canceled())
[email protected]189163e2011-05-11 01:48:54841 UMA_HISTOGRAM_ENUMERATION("DNS.AttemptCancelled", attempt_number, 100);
842 }
843
844 base::TimeDelta duration = base::TimeTicks::Now() - start_time;
845 if (error == OK)
846 DNS_HISTOGRAM("DNS.AttemptSuccessDuration", duration);
847 else
848 DNS_HISTOGRAM("DNS.AttemptFailDuration", duration);
849 }
[email protected]1e9bbd22010-10-15 16:42:45850
[email protected]b59ff372009-07-15 22:04:32851 // Set on the origin thread, read on the worker thread.
[email protected]123ab1e32009-10-21 19:12:57852 Key key_;
[email protected]b59ff372009-07-15 22:04:32853
[email protected]0f292de02012-02-01 22:28:20854 // Holds an owning reference to the HostResolverProc that we are going to use.
[email protected]b59ff372009-07-15 22:04:32855 // This may not be the current resolver procedure by the time we call
856 // ResolveAddrInfo, but that's OK... we'll use it anyways, and the owning
857 // reference ensures that it remains valid until we are done.
[email protected]0f292de02012-02-01 22:28:20858 ProcTaskParams params_;
[email protected]b59ff372009-07-15 22:04:32859
[email protected]0f292de02012-02-01 22:28:20860 // The listener to the results of this ProcTask.
861 Callback callback_;
862
863 // Used to post ourselves onto the origin thread.
864 scoped_refptr<base::MessageLoopProxy> origin_loop_;
[email protected]189163e2011-05-11 01:48:54865
866 // Keeps track of the number of attempts we have made so far to resolve the
867 // host. Whenever we start an attempt to resolve the host, we increase this
868 // number.
869 uint32 attempt_number_;
870
871 // The index of the attempt which finished first (or 0 if the job is still in
872 // progress).
873 uint32 completed_attempt_number_;
874
875 // The result (a net error code) from the first attempt to complete.
876 int completed_attempt_error_;
[email protected]252b699b2010-02-05 21:38:06877
[email protected]e87b8b512011-06-14 22:12:52878 // The time when retry attempt was finished.
879 base::TimeTicks retry_attempt_finished_time_;
880
[email protected]252b699b2010-02-05 21:38:06881 // True if a non-speculative request was ever attached to this job
[email protected]0f292de02012-02-01 22:28:20882 // (regardless of whether or not it was later canceled.
[email protected]252b699b2010-02-05 21:38:06883 // This boolean is used for histogramming the duration of jobs used to
884 // service non-speculative requests.
885 bool had_non_speculative_request_;
886
[email protected]b59ff372009-07-15 22:04:32887 AddressList results_;
888
[email protected]ee094b82010-08-24 15:55:51889 BoundNetLog net_log_;
890
[email protected]0f292de02012-02-01 22:28:20891 DISALLOW_COPY_AND_ASSIGN(ProcTask);
[email protected]b59ff372009-07-15 22:04:32892};
893
894//-----------------------------------------------------------------------------
895
[email protected]0f292de02012-02-01 22:28:20896// Represents a request to the worker pool for a "probe for IPv6 support" call.
[email protected]b3601bc22012-02-21 21:23:20897//
898// TODO(szym): This could also be replaced with PostTaskAndReply and Callbacks.
[email protected]0f8f1b432010-03-16 19:06:03899class HostResolverImpl::IPv6ProbeJob
900 : public base::RefCountedThreadSafe<HostResolverImpl::IPv6ProbeJob> {
901 public:
[email protected]ae8e80f2012-07-19 21:08:33902 IPv6ProbeJob(HostResolverImpl* resolver, NetLog* net_log)
[email protected]0f8f1b432010-03-16 19:06:03903 : resolver_(resolver),
[email protected]ae8e80f2012-07-19 21:08:33904 origin_loop_(base::MessageLoopProxy::current()),
905 net_log_(BoundNetLog::Make(net_log, NetLog::SOURCE_IPV6_PROBE_JOB)) {
[email protected]3e9d9cc2011-05-03 21:08:15906 DCHECK(resolver);
[email protected]0f8f1b432010-03-16 19:06:03907 }
908
909 void Start() {
[email protected]3e9d9cc2011-05-03 21:08:15910 DCHECK(origin_loop_->BelongsToCurrentThread());
[email protected]0f292de02012-02-01 22:28:20911 if (was_canceled())
[email protected]a9af7112010-05-08 00:56:01912 return;
[email protected]ae8e80f2012-07-19 21:08:33913 net_log_.BeginEvent(NetLog::TYPE_IPV6_PROBE_RUNNING);
[email protected]f092e64b2010-03-17 00:39:18914 const bool kIsSlow = true;
[email protected]ac9ba8fe2010-12-30 18:08:36915 base::WorkerPool::PostTask(
[email protected]33152acc2011-10-20 23:37:12916 FROM_HERE, base::Bind(&IPv6ProbeJob::DoProbe, this), kIsSlow);
[email protected]0f8f1b432010-03-16 19:06:03917 }
918
919 // Cancels the current job.
920 void Cancel() {
[email protected]3e9d9cc2011-05-03 21:08:15921 DCHECK(origin_loop_->BelongsToCurrentThread());
[email protected]0f292de02012-02-01 22:28:20922 if (was_canceled())
[email protected]a9af7112010-05-08 00:56:01923 return;
[email protected]ae8e80f2012-07-19 21:08:33924 net_log_.AddEvent(NetLog::TYPE_CANCELLED);
[email protected]0f8f1b432010-03-16 19:06:03925 resolver_ = NULL; // Read/write ONLY on origin thread.
[email protected]0f8f1b432010-03-16 19:06:03926 }
927
[email protected]0f8f1b432010-03-16 19:06:03928 private:
929 friend class base::RefCountedThreadSafe<HostResolverImpl::IPv6ProbeJob>;
930
931 ~IPv6ProbeJob() {
932 }
933
[email protected]ae8e80f2012-07-19 21:08:33934 // Returns true if cancelled or if probe results have already been received
935 // on the origin thread.
[email protected]0f292de02012-02-01 22:28:20936 bool was_canceled() const {
[email protected]3e9d9cc2011-05-03 21:08:15937 DCHECK(origin_loop_->BelongsToCurrentThread());
938 return !resolver_;
[email protected]a9af7112010-05-08 00:56:01939 }
940
[email protected]0f8f1b432010-03-16 19:06:03941 // Run on worker thread.
942 void DoProbe() {
943 // Do actual testing on this thread, as it takes 40-100ms.
[email protected]3e9d9cc2011-05-03 21:08:15944 origin_loop_->PostTask(
945 FROM_HERE,
[email protected]ae8e80f2012-07-19 21:08:33946 base::Bind(&IPv6ProbeJob::OnProbeComplete, this, TestIPv6Support()));
[email protected]0f8f1b432010-03-16 19:06:03947 }
948
[email protected]3e9d9cc2011-05-03 21:08:15949 // Callback for when DoProbe() completes.
[email protected]ae8e80f2012-07-19 21:08:33950 void OnProbeComplete(const IPv6SupportResult& support_result) {
[email protected]3e9d9cc2011-05-03 21:08:15951 DCHECK(origin_loop_->BelongsToCurrentThread());
[email protected]ae8e80f2012-07-19 21:08:33952 net_log_.EndEvent(
953 NetLog::TYPE_IPV6_PROBE_RUNNING,
954 base::Bind(&IPv6SupportResult::ToNetLogValue,
955 base::Unretained(&support_result)));
[email protected]0f292de02012-02-01 22:28:20956 if (was_canceled())
[email protected]a9af7112010-05-08 00:56:01957 return;
[email protected]ae8e80f2012-07-19 21:08:33958
959 // Clear |resolver_| so that no cancel event is logged.
960 HostResolverImpl* resolver = resolver_;
961 resolver_ = NULL;
962
963 resolver->IPv6ProbeSetDefaultAddressFamily(
964 support_result.ipv6_supported ? ADDRESS_FAMILY_UNSPECIFIED
965 : ADDRESS_FAMILY_IPV4);
[email protected]0f8f1b432010-03-16 19:06:03966 }
967
[email protected]0f8f1b432010-03-16 19:06:03968 // Used/set only on origin thread.
969 HostResolverImpl* resolver_;
970
971 // Used to post ourselves onto the origin thread.
[email protected]3e9d9cc2011-05-03 21:08:15972 scoped_refptr<base::MessageLoopProxy> origin_loop_;
[email protected]0f8f1b432010-03-16 19:06:03973
[email protected]ae8e80f2012-07-19 21:08:33974 BoundNetLog net_log_;
975
[email protected]0f8f1b432010-03-16 19:06:03976 DISALLOW_COPY_AND_ASSIGN(IPv6ProbeJob);
977};
978
979//-----------------------------------------------------------------------------
980
[email protected]b3601bc22012-02-21 21:23:20981// Resolves the hostname using DnsTransaction.
982// TODO(szym): This could be moved to separate source file as well.
[email protected]0adcb2b2012-08-15 21:30:46983class HostResolverImpl::DnsTask : public base::SupportsWeakPtr<DnsTask> {
[email protected]b3601bc22012-02-21 21:23:20984 public:
985 typedef base::Callback<void(int net_error,
986 const AddressList& addr_list,
987 base::TimeDelta ttl)> Callback;
988
[email protected]0adcb2b2012-08-15 21:30:46989 DnsTask(DnsClient* client,
[email protected]b3601bc22012-02-21 21:23:20990 const Key& key,
991 const Callback& callback,
992 const BoundNetLog& job_net_log)
[email protected]0adcb2b2012-08-15 21:30:46993 : client_(client),
994 family_(key.address_family),
995 callback_(callback),
996 net_log_(job_net_log) {
997 DCHECK(client);
[email protected]b3601bc22012-02-21 21:23:20998 DCHECK(!callback.is_null());
999
[email protected]0adcb2b2012-08-15 21:30:461000 // If unspecified, do IPv4 first, because suffix search will be faster.
1001 uint16 qtype = (family_ == ADDRESS_FAMILY_IPV6) ?
1002 dns_protocol::kTypeAAAA :
1003 dns_protocol::kTypeA;
1004 transaction_ = client_->GetTransactionFactory()->CreateTransaction(
[email protected]b3601bc22012-02-21 21:23:201005 key.hostname,
1006 qtype,
[email protected]1def74c2012-03-22 20:07:001007 base::Bind(&DnsTask::OnTransactionComplete, base::Unretained(this),
[email protected]0adcb2b2012-08-15 21:30:461008 true /* first_query */, base::TimeTicks::Now()),
[email protected]b3601bc22012-02-21 21:23:201009 net_log_);
[email protected]b3601bc22012-02-21 21:23:201010 }
1011
1012 int Start() {
[email protected]4da911f2012-06-14 19:45:201013 net_log_.BeginEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_DNS_TASK);
[email protected]b3601bc22012-02-21 21:23:201014 return transaction_->Start();
1015 }
1016
[email protected]0adcb2b2012-08-15 21:30:461017 private:
1018 void OnTransactionComplete(bool first_query,
1019 const base::TimeTicks& start_time,
[email protected]1def74c2012-03-22 20:07:001020 DnsTransaction* transaction,
[email protected]b3601bc22012-02-21 21:23:201021 int net_error,
1022 const DnsResponse* response) {
[email protected]add76532012-03-30 14:47:471023 DCHECK(transaction);
[email protected]b3601bc22012-02-21 21:23:201024 // Run |callback_| last since the owning Job will then delete this DnsTask.
[email protected]0adcb2b2012-08-15 21:30:461025 if (net_error != OK) {
[email protected]708d0cc2012-08-14 23:32:291026 DNS_HISTOGRAM("AsyncDNS.TransactionFailure",
[email protected]6c411902012-08-14 22:36:361027 base::TimeTicks::Now() - start_time);
[email protected]0adcb2b2012-08-15 21:30:461028 OnFailure(net_error, DnsResponse::DNS_PARSE_OK);
1029 return;
[email protected]6c411902012-08-14 22:36:361030 }
[email protected]0adcb2b2012-08-15 21:30:461031
1032 CHECK(response);
1033 DNS_HISTOGRAM("AsyncDNS.TransactionSuccess",
1034 base::TimeTicks::Now() - start_time);
1035 AddressList addr_list;
1036 base::TimeDelta ttl;
1037 DnsResponse::Result result = response->ParseToAddressList(&addr_list, &ttl);
1038 UMA_HISTOGRAM_ENUMERATION("AsyncDNS.ParseToAddressList",
1039 result,
1040 DnsResponse::DNS_PARSE_RESULT_MAX);
1041 if (result != DnsResponse::DNS_PARSE_OK) {
1042 // Fail even if the other query succeeds.
1043 OnFailure(ERR_DNS_MALFORMED_RESPONSE, result);
1044 return;
1045 }
1046
1047 bool needs_sort = false;
1048 if (first_query) {
1049 DCHECK(client_->GetConfig()) <<
1050 "Transaction should have been aborted when config changed!";
1051 if (family_ == ADDRESS_FAMILY_IPV6) {
1052 needs_sort = (addr_list.size() > 1);
1053 } else if (family_ == ADDRESS_FAMILY_UNSPECIFIED) {
1054 first_addr_list_ = addr_list;
1055 first_ttl_ = ttl;
1056 // Use fully-qualified domain name to avoid search.
1057 transaction_ = client_->GetTransactionFactory()->CreateTransaction(
1058 response->GetDottedName() + ".",
1059 dns_protocol::kTypeAAAA,
1060 base::Bind(&DnsTask::OnTransactionComplete, base::Unretained(this),
1061 false /* first_query */, base::TimeTicks::Now()),
1062 net_log_);
1063 net_error = transaction_->Start();
1064 if (net_error != ERR_IO_PENDING)
1065 OnFailure(net_error, DnsResponse::DNS_PARSE_OK);
1066 return;
1067 }
1068 } else {
1069 DCHECK_EQ(ADDRESS_FAMILY_UNSPECIFIED, family_);
1070 bool has_ipv6_addresses = !addr_list.empty();
1071 if (!first_addr_list_.empty()) {
1072 ttl = std::min(ttl, first_ttl_);
1073 // Place IPv4 addresses after IPv6.
1074 addr_list.insert(addr_list.end(), first_addr_list_.begin(),
1075 first_addr_list_.end());
1076 }
1077 needs_sort = (has_ipv6_addresses && addr_list.size() > 1);
1078 }
1079
1080 if (addr_list.empty()) {
1081 // TODO(szym): Don't fallback to ProcTask in this case.
1082 OnFailure(ERR_NAME_NOT_RESOLVED, DnsResponse::DNS_PARSE_OK);
1083 return;
1084 }
1085
1086 if (needs_sort) {
1087 // Sort could complete synchronously.
1088 client_->GetAddressSorter()->Sort(
1089 addr_list,
[email protected]4589a3a2012-09-20 20:57:071090 base::Bind(&DnsTask::OnSortComplete,
1091 AsWeakPtr(),
[email protected]0adcb2b2012-08-15 21:30:461092 base::TimeTicks::Now(),
1093 ttl));
1094 } else {
1095 OnSuccess(addr_list, ttl);
1096 }
1097 }
1098
1099 void OnSortComplete(base::TimeTicks start_time,
1100 base::TimeDelta ttl,
1101 bool success,
1102 const AddressList& addr_list) {
1103 if (!success) {
1104 DNS_HISTOGRAM("AsyncDNS.SortFailure",
1105 base::TimeTicks::Now() - start_time);
1106 OnFailure(ERR_DNS_SORT_ERROR, DnsResponse::DNS_PARSE_OK);
1107 return;
1108 }
1109
1110 DNS_HISTOGRAM("AsyncDNS.SortSuccess",
1111 base::TimeTicks::Now() - start_time);
1112
1113 // AddressSorter prunes unusable destinations.
1114 if (addr_list.empty()) {
1115 LOG(WARNING) << "Address list empty after RFC3484 sort";
1116 OnFailure(ERR_NAME_NOT_RESOLVED, DnsResponse::DNS_PARSE_OK);
1117 return;
1118 }
1119
1120 OnSuccess(addr_list, ttl);
1121 }
1122
1123 void OnFailure(int net_error, DnsResponse::Result result) {
1124 DCHECK_NE(OK, net_error);
[email protected]cd565142012-06-12 16:21:451125 net_log_.EndEvent(
1126 NetLog::TYPE_HOST_RESOLVER_IMPL_DNS_TASK,
1127 base::Bind(&NetLogDnsTaskFailedCallback, net_error, result));
[email protected]b3601bc22012-02-21 21:23:201128 callback_.Run(net_error, AddressList(), base::TimeDelta());
1129 }
1130
[email protected]0adcb2b2012-08-15 21:30:461131 void OnSuccess(const AddressList& addr_list, base::TimeDelta ttl) {
1132 net_log_.EndEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_DNS_TASK,
1133 addr_list.CreateNetLogCallback());
1134 callback_.Run(OK, addr_list, ttl);
1135 }
1136
1137 DnsClient* client_;
1138 AddressFamily family_;
[email protected]b3601bc22012-02-21 21:23:201139 // The listener to the results of this DnsTask.
1140 Callback callback_;
[email protected]b3601bc22012-02-21 21:23:201141 const BoundNetLog net_log_;
1142
1143 scoped_ptr<DnsTransaction> transaction_;
[email protected]0adcb2b2012-08-15 21:30:461144
1145 // Results from the first transaction. Used only if |family_| is unspecified.
1146 AddressList first_addr_list_;
1147 base::TimeDelta first_ttl_;
1148
1149 DISALLOW_COPY_AND_ASSIGN(DnsTask);
[email protected]b3601bc22012-02-21 21:23:201150};
1151
1152//-----------------------------------------------------------------------------
1153
[email protected]0f292de02012-02-01 22:28:201154// Aggregates all Requests for the same Key. Dispatched via PriorityDispatch.
[email protected]0f292de02012-02-01 22:28:201155class HostResolverImpl::Job : public PrioritizedDispatcher::Job {
[email protected]68ad3ee2010-01-30 03:45:391156 public:
[email protected]0f292de02012-02-01 22:28:201157 // Creates new job for |key| where |request_net_log| is bound to the
[email protected]16ee26d2012-03-08 03:34:351158 // request that spawned it.
[email protected]0f292de02012-02-01 22:28:201159 Job(HostResolverImpl* resolver,
1160 const Key& key,
[email protected]8c98d002012-07-18 19:02:271161 RequestPriority priority,
[email protected]16ee26d2012-03-08 03:34:351162 const BoundNetLog& request_net_log)
[email protected]4589a3a2012-09-20 20:57:071163 : resolver_(resolver->weak_ptr_factory_.GetWeakPtr()),
[email protected]0f292de02012-02-01 22:28:201164 key_(key),
[email protected]8c98d002012-07-18 19:02:271165 priority_tracker_(priority),
[email protected]0f292de02012-02-01 22:28:201166 had_non_speculative_request_(false),
[email protected]51b9a6b2012-06-25 21:50:291167 had_dns_config_(false),
[email protected]1d932852012-06-19 19:40:331168 dns_task_error_(OK),
[email protected]51b9a6b2012-06-25 21:50:291169 creation_time_(base::TimeTicks::Now()),
1170 priority_change_time_(creation_time_),
[email protected]0f292de02012-02-01 22:28:201171 net_log_(BoundNetLog::Make(request_net_log.net_log(),
[email protected]b3601bc22012-02-21 21:23:201172 NetLog::SOURCE_HOST_RESOLVER_IMPL_JOB)) {
[email protected]4da911f2012-06-14 19:45:201173 request_net_log.AddEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_CREATE_JOB);
[email protected]0f292de02012-02-01 22:28:201174
1175 net_log_.BeginEvent(
1176 NetLog::TYPE_HOST_RESOLVER_IMPL_JOB,
[email protected]cd565142012-06-12 16:21:451177 base::Bind(&NetLogJobCreationCallback,
1178 request_net_log.source(),
1179 &key_.hostname));
[email protected]68ad3ee2010-01-30 03:45:391180 }
1181
[email protected]0f292de02012-02-01 22:28:201182 virtual ~Job() {
[email protected]b3601bc22012-02-21 21:23:201183 if (is_running()) {
1184 // |resolver_| was destroyed with this Job still in flight.
1185 // Clean-up, record in the log, but don't run any callbacks.
1186 if (is_proc_running()) {
[email protected]0f292de02012-02-01 22:28:201187 proc_task_->Cancel();
1188 proc_task_ = NULL;
[email protected]0f292de02012-02-01 22:28:201189 }
[email protected]16ee26d2012-03-08 03:34:351190 // Clean up now for nice NetLog.
1191 dns_task_.reset(NULL);
[email protected]b3601bc22012-02-21 21:23:201192 net_log_.EndEventWithNetErrorCode(NetLog::TYPE_HOST_RESOLVER_IMPL_JOB,
1193 ERR_ABORTED);
1194 } else if (is_queued()) {
[email protected]57a48d32012-03-03 00:04:551195 // |resolver_| was destroyed without running this Job.
[email protected]16ee26d2012-03-08 03:34:351196 // TODO(szym): is there any benefit in having this distinction?
[email protected]4da911f2012-06-14 19:45:201197 net_log_.AddEvent(NetLog::TYPE_CANCELLED);
1198 net_log_.EndEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_JOB);
[email protected]68ad3ee2010-01-30 03:45:391199 }
[email protected]b3601bc22012-02-21 21:23:201200 // else CompleteRequests logged EndEvent.
[email protected]68ad3ee2010-01-30 03:45:391201
[email protected]b3601bc22012-02-21 21:23:201202 // Log any remaining Requests as cancelled.
1203 for (RequestsList::const_iterator it = requests_.begin();
1204 it != requests_.end(); ++it) {
1205 Request* req = *it;
1206 if (req->was_canceled())
1207 continue;
1208 DCHECK_EQ(this, req->job());
1209 LogCancelRequest(req->source_net_log(), req->request_net_log(),
1210 req->info());
1211 }
[email protected]68ad3ee2010-01-30 03:45:391212 }
1213
[email protected]16ee26d2012-03-08 03:34:351214 // Add this job to the dispatcher.
[email protected]8c98d002012-07-18 19:02:271215 void Schedule() {
1216 handle_ = resolver_->dispatcher_.Add(this, priority());
[email protected]16ee26d2012-03-08 03:34:351217 }
1218
[email protected]b3601bc22012-02-21 21:23:201219 void AddRequest(scoped_ptr<Request> req) {
[email protected]0f292de02012-02-01 22:28:201220 DCHECK_EQ(key_.hostname, req->info().hostname());
1221
1222 req->set_job(this);
[email protected]0f292de02012-02-01 22:28:201223 priority_tracker_.Add(req->info().priority());
1224
1225 req->request_net_log().AddEvent(
1226 NetLog::TYPE_HOST_RESOLVER_IMPL_JOB_ATTACH,
[email protected]cd565142012-06-12 16:21:451227 net_log_.source().ToEventParametersCallback());
[email protected]0f292de02012-02-01 22:28:201228
1229 net_log_.AddEvent(
1230 NetLog::TYPE_HOST_RESOLVER_IMPL_JOB_REQUEST_ATTACH,
[email protected]cd565142012-06-12 16:21:451231 base::Bind(&NetLogJobAttachCallback,
1232 req->request_net_log().source(),
1233 priority()));
[email protected]0f292de02012-02-01 22:28:201234
1235 // TODO(szym): Check if this is still needed.
1236 if (!req->info().is_speculative()) {
1237 had_non_speculative_request_ = true;
1238 if (proc_task_)
1239 proc_task_->set_had_non_speculative_request();
[email protected]68ad3ee2010-01-30 03:45:391240 }
[email protected]b3601bc22012-02-21 21:23:201241
1242 requests_.push_back(req.release());
1243
[email protected]51b9a6b2012-06-25 21:50:291244 UpdatePriority();
[email protected]68ad3ee2010-01-30 03:45:391245 }
1246
[email protected]16ee26d2012-03-08 03:34:351247 // Marks |req| as cancelled. If it was the last active Request, also finishes
[email protected]0adcb2b2012-08-15 21:30:461248 // this Job, marking it as cancelled, and deletes it.
[email protected]0f292de02012-02-01 22:28:201249 void CancelRequest(Request* req) {
1250 DCHECK_EQ(key_.hostname, req->info().hostname());
1251 DCHECK(!req->was_canceled());
[email protected]16ee26d2012-03-08 03:34:351252
[email protected]0f292de02012-02-01 22:28:201253 // Don't remove it from |requests_| just mark it canceled.
1254 req->MarkAsCanceled();
1255 LogCancelRequest(req->source_net_log(), req->request_net_log(),
1256 req->info());
[email protected]16ee26d2012-03-08 03:34:351257
[email protected]0f292de02012-02-01 22:28:201258 priority_tracker_.Remove(req->info().priority());
1259 net_log_.AddEvent(
1260 NetLog::TYPE_HOST_RESOLVER_IMPL_JOB_REQUEST_DETACH,
[email protected]cd565142012-06-12 16:21:451261 base::Bind(&NetLogJobAttachCallback,
1262 req->request_net_log().source(),
1263 priority()));
[email protected]b3601bc22012-02-21 21:23:201264
[email protected]16ee26d2012-03-08 03:34:351265 if (num_active_requests() > 0) {
[email protected]51b9a6b2012-06-25 21:50:291266 UpdatePriority();
[email protected]16ee26d2012-03-08 03:34:351267 } else {
1268 // If we were called from a Request's callback within CompleteRequests,
1269 // that Request could not have been cancelled, so num_active_requests()
1270 // could not be 0. Therefore, we are not in CompleteRequests().
[email protected]1339a2a22012-10-17 08:39:431271 CompleteRequestsWithError(OK /* cancelled */);
[email protected]b3601bc22012-02-21 21:23:201272 }
[email protected]68ad3ee2010-01-30 03:45:391273 }
1274
[email protected]16ee26d2012-03-08 03:34:351275 // Called from AbortAllInProgressJobs. Completes all requests as aborted
1276 // and destroys the job.
[email protected]0f292de02012-02-01 22:28:201277 void Abort() {
[email protected]0f292de02012-02-01 22:28:201278 DCHECK(is_running());
[email protected]1339a2a22012-10-17 08:39:431279 CompleteRequestsWithError(ERR_ABORTED);
[email protected]b3601bc22012-02-21 21:23:201280 }
1281
[email protected]16ee26d2012-03-08 03:34:351282 // Called by HostResolverImpl when this job is evicted due to queue overflow.
1283 // Completes all requests and destroys the job.
1284 void OnEvicted() {
1285 DCHECK(!is_running());
1286 DCHECK(is_queued());
1287 handle_.Reset();
1288
[email protected]4da911f2012-06-14 19:45:201289 net_log_.AddEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_JOB_EVICTED);
[email protected]16ee26d2012-03-08 03:34:351290
1291 // This signals to CompleteRequests that this job never ran.
[email protected]1339a2a22012-10-17 08:39:431292 CompleteRequestsWithError(ERR_HOST_RESOLVER_QUEUE_TOO_LARGE);
[email protected]16ee26d2012-03-08 03:34:351293 }
1294
[email protected]78eac2a2012-03-14 19:09:271295 // Attempts to serve the job from HOSTS. Returns true if succeeded and
1296 // this Job was destroyed.
1297 bool ServeFromHosts() {
1298 DCHECK_GT(num_active_requests(), 0u);
1299 AddressList addr_list;
1300 if (resolver_->ServeFromHosts(key(),
[email protected]3cb676a12012-06-30 15:46:031301 requests_.front()->info(),
[email protected]78eac2a2012-03-14 19:09:271302 &addr_list)) {
1303 // This will destroy the Job.
[email protected]1339a2a22012-10-17 08:39:431304 CompleteRequests(OK, addr_list, base::TimeDelta(), false /* true_ttl */);
[email protected]78eac2a2012-03-14 19:09:271305 return true;
1306 }
1307 return false;
1308 }
1309
[email protected]b4481b222012-03-16 17:13:111310 const Key key() const {
1311 return key_;
1312 }
1313
1314 bool is_queued() const {
1315 return !handle_.is_null();
1316 }
1317
1318 bool is_running() const {
1319 return is_dns_running() || is_proc_running();
1320 }
1321
[email protected]16ee26d2012-03-08 03:34:351322 private:
[email protected]51b9a6b2012-06-25 21:50:291323 void UpdatePriority() {
1324 if (is_queued()) {
1325 if (priority() != static_cast<RequestPriority>(handle_.priority()))
1326 priority_change_time_ = base::TimeTicks::Now();
1327 handle_ = resolver_->dispatcher_.ChangePriority(handle_, priority());
1328 }
1329 }
1330
[email protected]16ee26d2012-03-08 03:34:351331 // PriorityDispatch::Job:
[email protected]0f292de02012-02-01 22:28:201332 virtual void Start() OVERRIDE {
1333 DCHECK(!is_running());
[email protected]b3601bc22012-02-21 21:23:201334 handle_.Reset();
[email protected]0f292de02012-02-01 22:28:201335
[email protected]4da911f2012-06-14 19:45:201336 net_log_.AddEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_JOB_STARTED);
[email protected]0f292de02012-02-01 22:28:201337
[email protected]51b9a6b2012-06-25 21:50:291338 had_dns_config_ = resolver_->HaveDnsConfig();
1339
1340 base::TimeTicks now = base::TimeTicks::Now();
1341 base::TimeDelta queue_time = now - creation_time_;
1342 base::TimeDelta queue_time_after_change = now - priority_change_time_;
1343
1344 if (had_dns_config_) {
1345 DNS_HISTOGRAM_BY_PRIORITY("AsyncDNS.JobQueueTime", priority(),
1346 queue_time);
1347 DNS_HISTOGRAM_BY_PRIORITY("AsyncDNS.JobQueueTimeAfterChange", priority(),
1348 queue_time_after_change);
1349 } else {
1350 DNS_HISTOGRAM_BY_PRIORITY("DNS.JobQueueTime", priority(), queue_time);
1351 DNS_HISTOGRAM_BY_PRIORITY("DNS.JobQueueTimeAfterChange", priority(),
1352 queue_time_after_change);
1353 }
1354
[email protected]1d932852012-06-19 19:40:331355 // Caution: Job::Start must not complete synchronously.
[email protected]51b9a6b2012-06-25 21:50:291356 if (had_dns_config_ && !ResemblesMulticastDNSName(key_.hostname)) {
[email protected]b3601bc22012-02-21 21:23:201357 StartDnsTask();
1358 } else {
1359 StartProcTask();
1360 }
1361 }
1362
[email protected]b3601bc22012-02-21 21:23:201363 // TODO(szym): Since DnsTransaction does not consume threads, we can increase
1364 // the limits on |dispatcher_|. But in order to keep the number of WorkerPool
1365 // threads low, we will need to use an "inner" PrioritizedDispatcher with
1366 // tighter limits.
1367 void StartProcTask() {
[email protected]16ee26d2012-03-08 03:34:351368 DCHECK(!is_dns_running());
[email protected]0f292de02012-02-01 22:28:201369 proc_task_ = new ProcTask(
1370 key_,
1371 resolver_->proc_params_,
[email protected]e3bd4822012-10-23 18:01:371372 base::Bind(&Job::OnProcTaskComplete, base::Unretained(this),
1373 base::TimeTicks::Now()),
[email protected]0f292de02012-02-01 22:28:201374 net_log_);
1375
1376 if (had_non_speculative_request_)
1377 proc_task_->set_had_non_speculative_request();
1378 // Start() could be called from within Resolve(), hence it must NOT directly
1379 // call OnProcTaskComplete, for example, on synchronous failure.
1380 proc_task_->Start();
[email protected]68ad3ee2010-01-30 03:45:391381 }
1382
[email protected]0f292de02012-02-01 22:28:201383 // Called by ProcTask when it completes.
[email protected]e3bd4822012-10-23 18:01:371384 void OnProcTaskComplete(base::TimeTicks start_time,
1385 int net_error,
1386 const AddressList& addr_list) {
[email protected]b3601bc22012-02-21 21:23:201387 DCHECK(is_proc_running());
[email protected]68ad3ee2010-01-30 03:45:391388
[email protected]1d932852012-06-19 19:40:331389 if (dns_task_error_ != OK) {
[email protected]e3bd4822012-10-23 18:01:371390 base::TimeDelta duration = base::TimeTicks::Now() - start_time;
[email protected]1def74c2012-03-22 20:07:001391 if (net_error == OK) {
[email protected]e3bd4822012-10-23 18:01:371392 DNS_HISTOGRAM("AsyncDNS.FallbackSuccess", duration);
[email protected]1d932852012-06-19 19:40:331393 if ((dns_task_error_ == ERR_NAME_NOT_RESOLVED) &&
1394 ResemblesNetBIOSName(key_.hostname)) {
1395 UmaAsyncDnsResolveStatus(RESOLVE_STATUS_SUSPECT_NETBIOS);
1396 } else {
1397 UmaAsyncDnsResolveStatus(RESOLVE_STATUS_PROC_SUCCESS);
1398 }
1399 UMA_HISTOGRAM_CUSTOM_ENUMERATION("AsyncDNS.ResolveError",
1400 std::abs(dns_task_error_),
1401 GetAllErrorCodesForUma());
[email protected]1def74c2012-03-22 20:07:001402 } else {
[email protected]e3bd4822012-10-23 18:01:371403 DNS_HISTOGRAM("AsyncDNS.FallbackFail", duration);
[email protected]1def74c2012-03-22 20:07:001404 UmaAsyncDnsResolveStatus(RESOLVE_STATUS_FAIL);
1405 }
1406 }
1407
[email protected]1339a2a22012-10-17 08:39:431408 base::TimeDelta ttl =
1409 base::TimeDelta::FromSeconds(kNegativeCacheEntryTTLSeconds);
[email protected]b3601bc22012-02-21 21:23:201410 if (net_error == OK)
1411 ttl = base::TimeDelta::FromSeconds(kCacheEntryTTLSeconds);
[email protected]68ad3ee2010-01-30 03:45:391412
[email protected]1339a2a22012-10-17 08:39:431413 CompleteRequests(net_error, addr_list, ttl, false /* true_ttl */);
[email protected]b3601bc22012-02-21 21:23:201414 }
1415
1416 void StartDnsTask() {
[email protected]78eac2a2012-03-14 19:09:271417 DCHECK(resolver_->HaveDnsConfig());
[email protected]b3601bc22012-02-21 21:23:201418 dns_task_.reset(new DnsTask(
[email protected]0adcb2b2012-08-15 21:30:461419 resolver_->dns_client_.get(),
[email protected]b3601bc22012-02-21 21:23:201420 key_,
[email protected]e3bd4822012-10-23 18:01:371421 base::Bind(&Job::OnDnsTaskComplete, base::Unretained(this),
1422 base::TimeTicks::Now()),
[email protected]b3601bc22012-02-21 21:23:201423 net_log_));
1424
1425 int rv = dns_task_->Start();
1426 if (rv != ERR_IO_PENDING) {
1427 DCHECK_NE(OK, rv);
[email protected]51b9a6b2012-06-25 21:50:291428 dns_task_error_ = rv;
[email protected]b3601bc22012-02-21 21:23:201429 dns_task_.reset();
1430 StartProcTask();
1431 }
1432 }
1433
1434 // Called by DnsTask when it completes.
[email protected]e3bd4822012-10-23 18:01:371435 void OnDnsTaskComplete(base::TimeTicks start_time,
1436 int net_error,
[email protected]b3601bc22012-02-21 21:23:201437 const AddressList& addr_list,
1438 base::TimeDelta ttl) {
1439 DCHECK(is_dns_running());
[email protected]b3601bc22012-02-21 21:23:201440
[email protected]e3bd4822012-10-23 18:01:371441 base::TimeDelta duration = base::TimeTicks::Now() - start_time;
[email protected]b3601bc22012-02-21 21:23:201442 if (net_error != OK) {
[email protected]e3bd4822012-10-23 18:01:371443 DNS_HISTOGRAM("AsyncDNS.ResolveFail", duration);
1444
[email protected]1d932852012-06-19 19:40:331445 dns_task_error_ = net_error;
[email protected]16ee26d2012-03-08 03:34:351446 dns_task_.reset();
[email protected]78eac2a2012-03-14 19:09:271447
1448 // TODO(szym): Run ServeFromHosts now if nsswitch.conf says so.
1449 // http://crbug.com/117655
1450
[email protected]b3601bc22012-02-21 21:23:201451 // TODO(szym): Some net errors indicate lack of connectivity. Starting
1452 // ProcTask in that case is a waste of time.
1453 StartProcTask();
1454 return;
1455 }
[email protected]e3bd4822012-10-23 18:01:371456 DNS_HISTOGRAM("AsyncDNS.ResolveSuccess", duration);
[email protected]b3601bc22012-02-21 21:23:201457
[email protected]1def74c2012-03-22 20:07:001458 UmaAsyncDnsResolveStatus(RESOLVE_STATUS_DNS_SUCCESS);
[email protected]1339a2a22012-10-17 08:39:431459 RecordTTL(ttl);
[email protected]0adcb2b2012-08-15 21:30:461460
[email protected]1339a2a22012-10-17 08:39:431461 CompleteRequests(net_error, addr_list, ttl, true /* true_ttl */);
[email protected]b3601bc22012-02-21 21:23:201462 }
1463
[email protected]16ee26d2012-03-08 03:34:351464 // Performs Job's last rites. Completes all Requests. Deletes this.
[email protected]b3601bc22012-02-21 21:23:201465 void CompleteRequests(int net_error,
1466 const AddressList& addr_list,
[email protected]1339a2a22012-10-17 08:39:431467 base::TimeDelta ttl,
1468 bool true_ttl) {
[email protected]b3601bc22012-02-21 21:23:201469 CHECK(resolver_);
[email protected]b3601bc22012-02-21 21:23:201470
[email protected]16ee26d2012-03-08 03:34:351471 // This job must be removed from resolver's |jobs_| now to make room for a
1472 // new job with the same key in case one of the OnComplete callbacks decides
1473 // to spawn one. Consequently, the job deletes itself when CompleteRequests
1474 // is done.
1475 scoped_ptr<Job> self_deleter(this);
1476
1477 resolver_->RemoveJob(this);
1478
[email protected]1339a2a22012-10-17 08:39:431479 // |addr_list| will be destroyed with |proc_task_| and |dns_task_|.
[email protected]b3601bc22012-02-21 21:23:201480 AddressList list = addr_list;
[email protected]16ee26d2012-03-08 03:34:351481
1482 if (is_running()) {
1483 DCHECK(!is_queued());
1484 if (is_proc_running()) {
1485 proc_task_->Cancel();
1486 proc_task_ = NULL;
1487 }
1488 dns_task_.reset();
1489
1490 // Signal dispatcher that a slot has opened.
1491 resolver_->dispatcher_.OnJobFinished();
1492 } else if (is_queued()) {
1493 resolver_->dispatcher_.Cancel(handle_);
1494 handle_.Reset();
1495 }
1496
1497 if (num_active_requests() == 0) {
[email protected]4da911f2012-06-14 19:45:201498 net_log_.AddEvent(NetLog::TYPE_CANCELLED);
[email protected]16ee26d2012-03-08 03:34:351499 net_log_.EndEventWithNetErrorCode(NetLog::TYPE_HOST_RESOLVER_IMPL_JOB,
1500 OK);
1501 return;
1502 }
[email protected]b3601bc22012-02-21 21:23:201503
1504 net_log_.EndEventWithNetErrorCode(NetLog::TYPE_HOST_RESOLVER_IMPL_JOB,
1505 net_error);
[email protected]68ad3ee2010-01-30 03:45:391506
[email protected]78eac2a2012-03-14 19:09:271507 DCHECK(!requests_.empty());
1508
[email protected]d7b9a2b2012-05-31 22:31:191509 if (net_error == OK) {
[email protected]3cb676a12012-06-30 15:46:031510 SetPortOnAddressList(requests_.front()->info().port(), &list);
[email protected]d7b9a2b2012-05-31 22:31:191511 // Record this histogram here, when we know the system has a valid DNS
1512 // configuration.
[email protected]539df6c2012-06-19 21:21:291513 UMA_HISTOGRAM_BOOLEAN("AsyncDNS.HaveDnsConfig",
1514 resolver_->received_dns_config_);
[email protected]d7b9a2b2012-05-31 22:31:191515 }
[email protected]16ee26d2012-03-08 03:34:351516
[email protected]51b9a6b2012-06-25 21:50:291517 bool did_complete = (net_error != ERR_ABORTED) &&
1518 (net_error != ERR_HOST_RESOLVER_QUEUE_TOO_LARGE);
[email protected]1339a2a22012-10-17 08:39:431519 if (did_complete) {
1520 HostCache::Entry entry = true_ttl ?
1521 HostCache::Entry(net_error, list, ttl) :
1522 HostCache::Entry(net_error, list);
1523 resolver_->CacheResult(key_, entry, ttl);
1524 }
[email protected]16ee26d2012-03-08 03:34:351525
[email protected]0f292de02012-02-01 22:28:201526 // Complete all of the requests that were attached to the job.
1527 for (RequestsList::const_iterator it = requests_.begin();
1528 it != requests_.end(); ++it) {
1529 Request* req = *it;
1530
1531 if (req->was_canceled())
1532 continue;
1533
1534 DCHECK_EQ(this, req->job());
1535 // Update the net log and notify registered observers.
1536 LogFinishRequest(req->source_net_log(), req->request_net_log(),
[email protected]b3601bc22012-02-21 21:23:201537 req->info(), net_error);
[email protected]51b9a6b2012-06-25 21:50:291538 if (did_complete) {
1539 // Record effective total time from creation to completion.
1540 RecordTotalTime(had_dns_config_, req->info().is_speculative(),
1541 base::TimeTicks::Now() - req->request_time());
1542 }
[email protected]b3601bc22012-02-21 21:23:201543 req->OnComplete(net_error, list);
[email protected]0f292de02012-02-01 22:28:201544
1545 // Check if the resolver was destroyed as a result of running the
1546 // callback. If it was, we could continue, but we choose to bail.
1547 if (!resolver_)
1548 return;
1549 }
1550 }
1551
[email protected]1339a2a22012-10-17 08:39:431552 // Convenience wrapper for CompleteRequests in case of failure.
1553 void CompleteRequestsWithError(int net_error) {
1554 CompleteRequests(net_error, AddressList(), base::TimeDelta(), false);
1555 }
1556
[email protected]b4481b222012-03-16 17:13:111557 RequestPriority priority() const {
1558 return priority_tracker_.highest_priority();
1559 }
1560
1561 // Number of non-canceled requests in |requests_|.
1562 size_t num_active_requests() const {
1563 return priority_tracker_.total_count();
1564 }
1565
1566 bool is_dns_running() const {
1567 return dns_task_.get() != NULL;
1568 }
1569
1570 bool is_proc_running() const {
1571 return proc_task_.get() != NULL;
1572 }
1573
[email protected]0f292de02012-02-01 22:28:201574 base::WeakPtr<HostResolverImpl> resolver_;
1575
1576 Key key_;
1577
1578 // Tracks the highest priority across |requests_|.
1579 PriorityTracker priority_tracker_;
1580
1581 bool had_non_speculative_request_;
1582
[email protected]51b9a6b2012-06-25 21:50:291583 // Distinguishes measurements taken while DnsClient was fully configured.
1584 bool had_dns_config_;
1585
[email protected]1d932852012-06-19 19:40:331586 // Result of DnsTask.
1587 int dns_task_error_;
[email protected]1def74c2012-03-22 20:07:001588
[email protected]51b9a6b2012-06-25 21:50:291589 const base::TimeTicks creation_time_;
1590 base::TimeTicks priority_change_time_;
1591
[email protected]0f292de02012-02-01 22:28:201592 BoundNetLog net_log_;
1593
[email protected]b3601bc22012-02-21 21:23:201594 // Resolves the host using a HostResolverProc.
[email protected]0f292de02012-02-01 22:28:201595 scoped_refptr<ProcTask> proc_task_;
1596
[email protected]b3601bc22012-02-21 21:23:201597 // Resolves the host using a DnsTransaction.
1598 scoped_ptr<DnsTask> dns_task_;
1599
[email protected]0f292de02012-02-01 22:28:201600 // All Requests waiting for the result of this Job. Some can be canceled.
1601 RequestsList requests_;
1602
[email protected]16ee26d2012-03-08 03:34:351603 // A handle used in |HostResolverImpl::dispatcher_|.
[email protected]0f292de02012-02-01 22:28:201604 PrioritizedDispatcher::Handle handle_;
[email protected]68ad3ee2010-01-30 03:45:391605};
1606
1607//-----------------------------------------------------------------------------
1608
[email protected]0f292de02012-02-01 22:28:201609HostResolverImpl::ProcTaskParams::ProcTaskParams(
[email protected]e95d3aca2010-01-11 22:47:431610 HostResolverProc* resolver_proc,
[email protected]0f292de02012-02-01 22:28:201611 size_t max_retry_attempts)
1612 : resolver_proc(resolver_proc),
1613 max_retry_attempts(max_retry_attempts),
1614 unresponsive_delay(base::TimeDelta::FromMilliseconds(6000)),
1615 retry_factor(2) {
1616}
1617
1618HostResolverImpl::ProcTaskParams::~ProcTaskParams() {}
1619
1620HostResolverImpl::HostResolverImpl(
[email protected]c54a8912012-10-22 22:09:431621 scoped_ptr<HostCache> cache,
[email protected]0f292de02012-02-01 22:28:201622 const PrioritizedDispatcher::Limits& job_limits,
1623 const ProcTaskParams& proc_params,
[email protected]d7b9a2b2012-05-31 22:31:191624 scoped_ptr<DnsClient> dns_client,
[email protected]ee094b82010-08-24 15:55:511625 NetLog* net_log)
[email protected]c54a8912012-10-22 22:09:431626 : cache_(cache.Pass()),
[email protected]0f292de02012-02-01 22:28:201627 dispatcher_(job_limits),
1628 max_queued_jobs_(job_limits.total_jobs * 100u),
1629 proc_params_(proc_params),
[email protected]0c7798452009-10-26 17:59:511630 default_address_family_(ADDRESS_FAMILY_UNSPECIFIED),
[email protected]4589a3a2012-09-20 20:57:071631 weak_ptr_factory_(this),
[email protected]d7b9a2b2012-05-31 22:31:191632 dns_client_(dns_client.Pass()),
1633 received_dns_config_(false),
[email protected]2f3bc65c2010-07-23 17:47:101634 ipv6_probe_monitoring_(false),
[email protected]ee094b82010-08-24 15:55:511635 additional_resolver_flags_(0),
1636 net_log_(net_log) {
[email protected]0f292de02012-02-01 22:28:201637
1638 DCHECK_GE(dispatcher_.num_priorities(), static_cast<size_t>(NUM_PRIORITIES));
[email protected]68ad3ee2010-01-30 03:45:391639
[email protected]06ef6d92011-05-19 04:24:581640 // Maximum of 4 retry attempts for host resolution.
1641 static const size_t kDefaultMaxRetryAttempts = 4u;
1642
[email protected]0f292de02012-02-01 22:28:201643 if (proc_params_.max_retry_attempts == HostResolver::kDefaultRetryAttempts)
1644 proc_params_.max_retry_attempts = kDefaultMaxRetryAttempts;
[email protected]68ad3ee2010-01-30 03:45:391645
[email protected]b59ff372009-07-15 22:04:321646#if defined(OS_WIN)
1647 EnsureWinsockInit();
1648#endif
[email protected]23f771162011-06-02 18:37:511649#if defined(OS_POSIX) && !defined(OS_MACOSX)
[email protected]2f3bc65c2010-07-23 17:47:101650 if (HaveOnlyLoopbackAddresses())
1651 additional_resolver_flags_ |= HOST_RESOLVER_LOOPBACK_ONLY;
1652#endif
[email protected]232a5812011-03-04 22:42:081653 NetworkChangeNotifier::AddIPAddressObserver(this);
[email protected]bb0e34542012-08-31 19:52:401654 NetworkChangeNotifier::AddDNSObserver(this);
[email protected]3399b072012-09-11 19:40:261655 if (!HaveDnsConfig())
1656 OnDNSChanged();
[email protected]d7b9a2b2012-05-31 22:31:191657#if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_OPENBSD) && \
1658 !defined(OS_ANDROID)
[email protected]d7b9a2b2012-05-31 22:31:191659 EnsureDnsReloaderInit();
[email protected]46018c9d2011-09-06 03:42:341660#endif
[email protected]b59ff372009-07-15 22:04:321661}
1662
1663HostResolverImpl::~HostResolverImpl() {
[email protected]0f8f1b432010-03-16 19:06:031664 DiscardIPv6ProbeJob();
1665
[email protected]0f292de02012-02-01 22:28:201666 // This will also cancel all outstanding requests.
1667 STLDeleteValues(&jobs_);
[email protected]e95d3aca2010-01-11 22:47:431668
[email protected]232a5812011-03-04 22:42:081669 NetworkChangeNotifier::RemoveIPAddressObserver(this);
[email protected]bb0e34542012-08-31 19:52:401670 NetworkChangeNotifier::RemoveDNSObserver(this);
[email protected]b59ff372009-07-15 22:04:321671}
1672
[email protected]0f292de02012-02-01 22:28:201673void HostResolverImpl::SetMaxQueuedJobs(size_t value) {
1674 DCHECK_EQ(0u, dispatcher_.num_queued_jobs());
1675 DCHECK_GT(value, 0u);
1676 max_queued_jobs_ = value;
[email protected]be1a48b2011-01-20 00:12:131677}
1678
[email protected]684970b2009-08-14 04:54:461679int HostResolverImpl::Resolve(const RequestInfo& info,
[email protected]b59ff372009-07-15 22:04:321680 AddressList* addresses,
[email protected]aa22b242011-11-16 18:58:291681 const CompletionCallback& callback,
[email protected]684970b2009-08-14 04:54:461682 RequestHandle* out_req,
[email protected]ee094b82010-08-24 15:55:511683 const BoundNetLog& source_net_log) {
[email protected]95a214c2011-08-04 21:50:401684 DCHECK(addresses);
[email protected]1ac6af92010-06-03 21:00:141685 DCHECK(CalledOnValidThread());
[email protected]aa22b242011-11-16 18:58:291686 DCHECK_EQ(false, callback.is_null());
[email protected]1ac6af92010-06-03 21:00:141687
[email protected]ee094b82010-08-24 15:55:511688 // Make a log item for the request.
1689 BoundNetLog request_net_log = BoundNetLog::Make(net_log_,
1690 NetLog::SOURCE_HOST_RESOLVER_IMPL_REQUEST);
1691
[email protected]0f292de02012-02-01 22:28:201692 LogStartRequest(source_net_log, request_net_log, info);
[email protected]b59ff372009-07-15 22:04:321693
[email protected]123ab1e32009-10-21 19:12:571694 // Build a key that identifies the request in the cache and in the
1695 // outstanding jobs map.
[email protected]137af622010-02-05 02:14:351696 Key key = GetEffectiveKeyForRequest(info);
[email protected]123ab1e32009-10-21 19:12:571697
[email protected]287d7c22011-11-15 17:34:251698 int rv = ResolveHelper(key, info, addresses, request_net_log);
[email protected]95a214c2011-08-04 21:50:401699 if (rv != ERR_DNS_CACHE_MISS) {
[email protected]b3601bc22012-02-21 21:23:201700 LogFinishRequest(source_net_log, request_net_log, info, rv);
[email protected]51b9a6b2012-06-25 21:50:291701 RecordTotalTime(HaveDnsConfig(), info.is_speculative(), base::TimeDelta());
[email protected]95a214c2011-08-04 21:50:401702 return rv;
[email protected]38368712011-03-02 08:09:401703 }
1704
[email protected]0f292de02012-02-01 22:28:201705 // Next we need to attach our request to a "job". This job is responsible for
1706 // calling "getaddrinfo(hostname)" on a worker thread.
1707
1708 JobMap::iterator jobit = jobs_.find(key);
1709 Job* job;
1710 if (jobit == jobs_.end()) {
[email protected]407a30ab2012-08-15 17:16:101711 // If we couldn't find the desired address family, check to see if the
1712 // other family is in the cache or another job, which indicates waste,
1713 // and we should fix crbug.com/139811.
1714 {
1715 bool ipv4 = key.address_family == ADDRESS_FAMILY_IPV4;
1716 Key other_family_key = key;
1717 other_family_key.address_family = ipv4 ?
1718 ADDRESS_FAMILY_UNSPECIFIED : ADDRESS_FAMILY_IPV4;
1719 bool found_other_family_cache = false;
1720 bool found_other_family_job = false;
1721 if (default_address_family_ == ADDRESS_FAMILY_UNSPECIFIED) {
1722 found_other_family_cache = cache_.get() &&
1723 cache_->Lookup(other_family_key, base::TimeTicks::Now()) != NULL;
1724 if (!found_other_family_cache)
1725 found_other_family_job = jobs_.count(other_family_key) > 0;
1726 }
1727 enum { // Used in UMA_HISTOGRAM_ENUMERATION.
1728 AF_WASTE_IPV4_ONLY,
1729 AF_WASTE_CACHE_IPV4,
1730 AF_WASTE_CACHE_UNSPEC,
1731 AF_WASTE_JOB_IPV4,
1732 AF_WASTE_JOB_UNSPEC,
1733 AF_WASTE_NONE_IPV4,
1734 AF_WASTE_NONE_UNSPEC,
1735 AF_WASTE_MAX, // Bounding value.
1736 } category = AF_WASTE_MAX;
1737 if (default_address_family_ != ADDRESS_FAMILY_UNSPECIFIED) {
1738 category = AF_WASTE_IPV4_ONLY;
1739 } else if (found_other_family_cache) {
1740 category = ipv4 ? AF_WASTE_CACHE_IPV4 : AF_WASTE_CACHE_UNSPEC;
1741 } else if (found_other_family_job) {
1742 category = ipv4 ? AF_WASTE_JOB_IPV4 : AF_WASTE_JOB_UNSPEC;
1743 } else {
1744 category = ipv4 ? AF_WASTE_NONE_IPV4 : AF_WASTE_NONE_UNSPEC;
1745 }
1746 UMA_HISTOGRAM_ENUMERATION("DNS.ResolveUnspecWaste", category,
1747 AF_WASTE_MAX);
1748 }
1749
[email protected]0f292de02012-02-01 22:28:201750 // Create new Job.
[email protected]8c98d002012-07-18 19:02:271751 job = new Job(this, key, info.priority(), request_net_log);
1752 job->Schedule();
[email protected]0f292de02012-02-01 22:28:201753
1754 // Check for queue overflow.
1755 if (dispatcher_.num_queued_jobs() > max_queued_jobs_) {
1756 Job* evicted = static_cast<Job*>(dispatcher_.EvictOldestLowest());
1757 DCHECK(evicted);
[email protected]16ee26d2012-03-08 03:34:351758 evicted->OnEvicted(); // Deletes |evicted|.
[email protected]0f292de02012-02-01 22:28:201759 if (evicted == job) {
[email protected]0f292de02012-02-01 22:28:201760 rv = ERR_HOST_RESOLVER_QUEUE_TOO_LARGE;
[email protected]b3601bc22012-02-21 21:23:201761 LogFinishRequest(source_net_log, request_net_log, info, rv);
[email protected]0f292de02012-02-01 22:28:201762 return rv;
1763 }
[email protected]0f292de02012-02-01 22:28:201764 }
[email protected]0f292de02012-02-01 22:28:201765 jobs_.insert(jobit, std::make_pair(key, job));
1766 } else {
1767 job = jobit->second;
1768 }
1769
1770 // Can't complete synchronously. Create and attach request.
[email protected]b3601bc22012-02-21 21:23:201771 scoped_ptr<Request> req(new Request(source_net_log,
1772 request_net_log,
1773 info,
1774 callback,
1775 addresses));
[email protected]b59ff372009-07-15 22:04:321776 if (out_req)
[email protected]b3601bc22012-02-21 21:23:201777 *out_req = reinterpret_cast<RequestHandle>(req.get());
[email protected]b59ff372009-07-15 22:04:321778
[email protected]b3601bc22012-02-21 21:23:201779 job->AddRequest(req.Pass());
[email protected]0f292de02012-02-01 22:28:201780 // Completion happens during Job::CompleteRequests().
[email protected]b59ff372009-07-15 22:04:321781 return ERR_IO_PENDING;
1782}
1783
[email protected]287d7c22011-11-15 17:34:251784int HostResolverImpl::ResolveHelper(const Key& key,
[email protected]95a214c2011-08-04 21:50:401785 const RequestInfo& info,
1786 AddressList* addresses,
[email protected]20cd5332011-10-12 22:38:001787 const BoundNetLog& request_net_log) {
[email protected]95a214c2011-08-04 21:50:401788 // The result of |getaddrinfo| for empty hosts is inconsistent across systems.
1789 // On Windows it gives the default interface's address, whereas on Linux it
1790 // gives an error. We will make it fail on all platforms for consistency.
1791 if (info.hostname().empty() || info.hostname().size() > kMaxHostLength)
1792 return ERR_NAME_NOT_RESOLVED;
1793
1794 int net_error = ERR_UNEXPECTED;
1795 if (ResolveAsIP(key, info, &net_error, addresses))
1796 return net_error;
[email protected]78eac2a2012-03-14 19:09:271797 if (ServeFromCache(key, info, &net_error, addresses)) {
[email protected]4da911f2012-06-14 19:45:201798 request_net_log.AddEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_CACHE_HIT);
[email protected]78eac2a2012-03-14 19:09:271799 return net_error;
1800 }
1801 // TODO(szym): Do not do this if nsswitch.conf instructs not to.
1802 // http://crbug.com/117655
1803 if (ServeFromHosts(key, info, addresses)) {
[email protected]4da911f2012-06-14 19:45:201804 request_net_log.AddEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_HOSTS_HIT);
[email protected]78eac2a2012-03-14 19:09:271805 return OK;
1806 }
1807 return ERR_DNS_CACHE_MISS;
[email protected]95a214c2011-08-04 21:50:401808}
1809
1810int HostResolverImpl::ResolveFromCache(const RequestInfo& info,
1811 AddressList* addresses,
1812 const BoundNetLog& source_net_log) {
1813 DCHECK(CalledOnValidThread());
1814 DCHECK(addresses);
1815
[email protected]95a214c2011-08-04 21:50:401816 // Make a log item for the request.
1817 BoundNetLog request_net_log = BoundNetLog::Make(net_log_,
1818 NetLog::SOURCE_HOST_RESOLVER_IMPL_REQUEST);
1819
1820 // Update the net log and notify registered observers.
[email protected]0f292de02012-02-01 22:28:201821 LogStartRequest(source_net_log, request_net_log, info);
[email protected]95a214c2011-08-04 21:50:401822
[email protected]95a214c2011-08-04 21:50:401823 Key key = GetEffectiveKeyForRequest(info);
1824
[email protected]287d7c22011-11-15 17:34:251825 int rv = ResolveHelper(key, info, addresses, request_net_log);
[email protected]b3601bc22012-02-21 21:23:201826 LogFinishRequest(source_net_log, request_net_log, info, rv);
[email protected]95a214c2011-08-04 21:50:401827 return rv;
1828}
1829
[email protected]b59ff372009-07-15 22:04:321830void HostResolverImpl::CancelRequest(RequestHandle req_handle) {
[email protected]1ac6af92010-06-03 21:00:141831 DCHECK(CalledOnValidThread());
[email protected]b59ff372009-07-15 22:04:321832 Request* req = reinterpret_cast<Request*>(req_handle);
1833 DCHECK(req);
[email protected]0f292de02012-02-01 22:28:201834 Job* job = req->job();
1835 DCHECK(job);
[email protected]0f292de02012-02-01 22:28:201836 job->CancelRequest(req);
[email protected]b59ff372009-07-15 22:04:321837}
1838
[email protected]0f8f1b432010-03-16 19:06:031839void HostResolverImpl::SetDefaultAddressFamily(AddressFamily address_family) {
[email protected]1ac6af92010-06-03 21:00:141840 DCHECK(CalledOnValidThread());
[email protected]0f8f1b432010-03-16 19:06:031841 ipv6_probe_monitoring_ = false;
1842 DiscardIPv6ProbeJob();
1843 default_address_family_ = address_family;
1844}
1845
[email protected]f7d310e2010-10-07 16:25:111846AddressFamily HostResolverImpl::GetDefaultAddressFamily() const {
1847 return default_address_family_;
1848}
1849
[email protected]a78f4272011-10-21 19:16:331850void HostResolverImpl::ProbeIPv6Support() {
1851 DCHECK(CalledOnValidThread());
1852 DCHECK(!ipv6_probe_monitoring_);
1853 ipv6_probe_monitoring_ = true;
1854 OnIPAddressChanged(); // Give initial setup call.
[email protected]ddb1e5a2010-12-13 20:10:451855}
1856
[email protected]489d1a82011-10-12 03:09:111857HostCache* HostResolverImpl::GetHostCache() {
1858 return cache_.get();
1859}
[email protected]95a214c2011-08-04 21:50:401860
[email protected]17e92032012-03-29 00:56:241861base::Value* HostResolverImpl::GetDnsConfigAsValue() const {
1862 // Check if async DNS is disabled.
1863 if (!dns_client_.get())
1864 return NULL;
1865
1866 // Check if async DNS is enabled, but we currently have no configuration
1867 // for it.
1868 const DnsConfig* dns_config = dns_client_->GetConfig();
1869 if (dns_config == NULL)
1870 return new DictionaryValue();
1871
1872 return dns_config->ToValue();
1873}
1874
[email protected]95a214c2011-08-04 21:50:401875bool HostResolverImpl::ResolveAsIP(const Key& key,
1876 const RequestInfo& info,
1877 int* net_error,
1878 AddressList* addresses) {
1879 DCHECK(addresses);
1880 DCHECK(net_error);
1881 IPAddressNumber ip_number;
1882 if (!ParseIPLiteralToNumber(key.hostname, &ip_number))
1883 return false;
1884
1885 DCHECK_EQ(key.host_resolver_flags &
1886 ~(HOST_RESOLVER_CANONNAME | HOST_RESOLVER_LOOPBACK_ONLY |
1887 HOST_RESOLVER_DEFAULT_FAMILY_SET_DUE_TO_NO_IPV6),
1888 0) << " Unhandled flag";
[email protected]0f292de02012-02-01 22:28:201889 bool ipv6_disabled = (default_address_family_ == ADDRESS_FAMILY_IPV4) &&
1890 !ipv6_probe_monitoring_;
[email protected]95a214c2011-08-04 21:50:401891 *net_error = OK;
[email protected]0f292de02012-02-01 22:28:201892 if ((ip_number.size() == kIPv6AddressSize) && ipv6_disabled) {
[email protected]95a214c2011-08-04 21:50:401893 *net_error = ERR_NAME_NOT_RESOLVED;
1894 } else {
[email protected]7054e78f2012-05-07 21:44:561895 *addresses = AddressList::CreateFromIPAddress(ip_number, info.port());
1896 if (key.host_resolver_flags & HOST_RESOLVER_CANONNAME)
1897 addresses->SetDefaultCanonicalName();
[email protected]95a214c2011-08-04 21:50:401898 }
1899 return true;
1900}
1901
1902bool HostResolverImpl::ServeFromCache(const Key& key,
1903 const RequestInfo& info,
[email protected]95a214c2011-08-04 21:50:401904 int* net_error,
1905 AddressList* addresses) {
1906 DCHECK(addresses);
1907 DCHECK(net_error);
1908 if (!info.allow_cached_response() || !cache_.get())
1909 return false;
1910
[email protected]407a30ab2012-08-15 17:16:101911 const HostCache::Entry* cache_entry = cache_->Lookup(
1912 key, base::TimeTicks::Now());
[email protected]95a214c2011-08-04 21:50:401913 if (!cache_entry)
1914 return false;
1915
[email protected]95a214c2011-08-04 21:50:401916 *net_error = cache_entry->error;
[email protected]7054e78f2012-05-07 21:44:561917 if (*net_error == OK) {
[email protected]1339a2a22012-10-17 08:39:431918 if (cache_entry->has_ttl())
1919 RecordTTL(cache_entry->ttl);
[email protected]7054e78f2012-05-07 21:44:561920 *addresses = cache_entry->addrlist;
1921 EnsurePortOnAddressList(info.port(), addresses);
1922 }
[email protected]95a214c2011-08-04 21:50:401923 return true;
1924}
1925
[email protected]78eac2a2012-03-14 19:09:271926bool HostResolverImpl::ServeFromHosts(const Key& key,
1927 const RequestInfo& info,
1928 AddressList* addresses) {
1929 DCHECK(addresses);
1930 if (!HaveDnsConfig())
1931 return false;
1932
[email protected]cb507622012-03-23 16:17:061933 // HOSTS lookups are case-insensitive.
1934 std::string hostname = StringToLowerASCII(key.hostname);
1935
[email protected]78eac2a2012-03-14 19:09:271936 // If |address_family| is ADDRESS_FAMILY_UNSPECIFIED other implementations
1937 // (glibc and c-ares) return the first matching line. We have more
1938 // flexibility, but lose implicit ordering.
1939 // TODO(szym) http://crbug.com/117850
1940 const DnsHosts& hosts = dns_client_->GetConfig()->hosts;
1941 DnsHosts::const_iterator it = hosts.find(
[email protected]cb507622012-03-23 16:17:061942 DnsHostsKey(hostname,
[email protected]78eac2a2012-03-14 19:09:271943 key.address_family == ADDRESS_FAMILY_UNSPECIFIED ?
1944 ADDRESS_FAMILY_IPV4 : key.address_family));
1945
1946 if (it == hosts.end()) {
1947 if (key.address_family != ADDRESS_FAMILY_UNSPECIFIED)
1948 return false;
1949
[email protected]cb507622012-03-23 16:17:061950 it = hosts.find(DnsHostsKey(hostname, ADDRESS_FAMILY_IPV6));
[email protected]78eac2a2012-03-14 19:09:271951 if (it == hosts.end())
1952 return false;
1953 }
1954
1955 *addresses = AddressList::CreateFromIPAddress(it->second, info.port());
1956 return true;
1957}
1958
[email protected]16ee26d2012-03-08 03:34:351959void HostResolverImpl::CacheResult(const Key& key,
[email protected]1339a2a22012-10-17 08:39:431960 const HostCache::Entry& entry,
[email protected]16ee26d2012-03-08 03:34:351961 base::TimeDelta ttl) {
1962 if (cache_.get())
[email protected]1339a2a22012-10-17 08:39:431963 cache_->Set(key, entry, base::TimeTicks::Now(), ttl);
[email protected]ef4c40c2010-09-01 14:42:031964}
1965
[email protected]0f292de02012-02-01 22:28:201966void HostResolverImpl::RemoveJob(Job* job) {
1967 DCHECK(job);
[email protected]16ee26d2012-03-08 03:34:351968 JobMap::iterator it = jobs_.find(job->key());
1969 if (it != jobs_.end() && it->second == job)
1970 jobs_.erase(it);
[email protected]b59ff372009-07-15 22:04:321971}
1972
[email protected]0f8f1b432010-03-16 19:06:031973void HostResolverImpl::DiscardIPv6ProbeJob() {
1974 if (ipv6_probe_job_.get()) {
1975 ipv6_probe_job_->Cancel();
1976 ipv6_probe_job_ = NULL;
1977 }
1978}
1979
1980void HostResolverImpl::IPv6ProbeSetDefaultAddressFamily(
1981 AddressFamily address_family) {
1982 DCHECK(address_family == ADDRESS_FAMILY_UNSPECIFIED ||
1983 address_family == ADDRESS_FAMILY_IPV4);
[email protected]f092e64b2010-03-17 00:39:181984 if (default_address_family_ != address_family) {
[email protected]b30a3f52010-10-16 01:05:461985 VLOG(1) << "IPv6Probe forced AddressFamily setting to "
1986 << ((address_family == ADDRESS_FAMILY_UNSPECIFIED) ?
1987 "ADDRESS_FAMILY_UNSPECIFIED" : "ADDRESS_FAMILY_IPV4");
[email protected]f092e64b2010-03-17 00:39:181988 }
[email protected]0f8f1b432010-03-16 19:06:031989 default_address_family_ = address_family;
1990 // Drop reference since the job has called us back.
1991 DiscardIPv6ProbeJob();
[email protected]e95d3aca2010-01-11 22:47:431992}
1993
[email protected]137af622010-02-05 02:14:351994HostResolverImpl::Key HostResolverImpl::GetEffectiveKeyForRequest(
1995 const RequestInfo& info) const {
[email protected]eaf3a3b2010-09-03 20:34:271996 HostResolverFlags effective_flags =
1997 info.host_resolver_flags() | additional_resolver_flags_;
[email protected]137af622010-02-05 02:14:351998 AddressFamily effective_address_family = info.address_family();
[email protected]eaf3a3b2010-09-03 20:34:271999 if (effective_address_family == ADDRESS_FAMILY_UNSPECIFIED &&
2000 default_address_family_ != ADDRESS_FAMILY_UNSPECIFIED) {
[email protected]137af622010-02-05 02:14:352001 effective_address_family = default_address_family_;
[email protected]eaf3a3b2010-09-03 20:34:272002 if (ipv6_probe_monitoring_)
2003 effective_flags |= HOST_RESOLVER_DEFAULT_FAMILY_SET_DUE_TO_NO_IPV6;
2004 }
2005 return Key(info.hostname(), effective_address_family, effective_flags);
[email protected]137af622010-02-05 02:14:352006}
2007
[email protected]35ddc282010-09-21 23:42:062008void HostResolverImpl::AbortAllInProgressJobs() {
[email protected]b3601bc22012-02-21 21:23:202009 // In Abort, a Request callback could spawn new Jobs with matching keys, so
2010 // first collect and remove all running jobs from |jobs_|.
[email protected]c143d892012-04-06 07:56:542011 ScopedVector<Job> jobs_to_abort;
[email protected]0f292de02012-02-01 22:28:202012 for (JobMap::iterator it = jobs_.begin(); it != jobs_.end(); ) {
2013 Job* job = it->second;
[email protected]0f292de02012-02-01 22:28:202014 if (job->is_running()) {
[email protected]b3601bc22012-02-21 21:23:202015 jobs_to_abort.push_back(job);
2016 jobs_.erase(it++);
[email protected]0f292de02012-02-01 22:28:202017 } else {
[email protected]b3601bc22012-02-21 21:23:202018 DCHECK(job->is_queued());
2019 ++it;
[email protected]0f292de02012-02-01 22:28:202020 }
[email protected]ef4c40c2010-09-01 14:42:032021 }
[email protected]b3601bc22012-02-21 21:23:202022
[email protected]57a48d32012-03-03 00:04:552023 // Check if no dispatcher slots leaked out.
2024 DCHECK_EQ(dispatcher_.num_running_jobs(), jobs_to_abort.size());
2025
2026 // Life check to bail once |this| is deleted.
[email protected]4589a3a2012-09-20 20:57:072027 base::WeakPtr<HostResolverImpl> self = weak_ptr_factory_.GetWeakPtr();
[email protected]57a48d32012-03-03 00:04:552028
[email protected]16ee26d2012-03-08 03:34:352029 // Then Abort them.
[email protected]57a48d32012-03-03 00:04:552030 for (size_t i = 0; self && i < jobs_to_abort.size(); ++i) {
[email protected]57a48d32012-03-03 00:04:552031 jobs_to_abort[i]->Abort();
[email protected]c143d892012-04-06 07:56:542032 jobs_to_abort[i] = NULL;
[email protected]b3601bc22012-02-21 21:23:202033 }
[email protected]ef4c40c2010-09-01 14:42:032034}
2035
[email protected]78eac2a2012-03-14 19:09:272036void HostResolverImpl::TryServingAllJobsFromHosts() {
2037 if (!HaveDnsConfig())
2038 return;
2039
2040 // TODO(szym): Do not do this if nsswitch.conf instructs not to.
2041 // http://crbug.com/117655
2042
2043 // Life check to bail once |this| is deleted.
[email protected]4589a3a2012-09-20 20:57:072044 base::WeakPtr<HostResolverImpl> self = weak_ptr_factory_.GetWeakPtr();
[email protected]78eac2a2012-03-14 19:09:272045
2046 for (JobMap::iterator it = jobs_.begin(); self && it != jobs_.end(); ) {
2047 Job* job = it->second;
2048 ++it;
2049 // This could remove |job| from |jobs_|, but iterator will remain valid.
2050 job->ServeFromHosts();
2051 }
2052}
2053
[email protected]be1a48b2011-01-20 00:12:132054void HostResolverImpl::OnIPAddressChanged() {
2055 if (cache_.get())
2056 cache_->clear();
2057 if (ipv6_probe_monitoring_) {
[email protected]be1a48b2011-01-20 00:12:132058 DiscardIPv6ProbeJob();
[email protected]ae8e80f2012-07-19 21:08:332059 ipv6_probe_job_ = new IPv6ProbeJob(this, net_log_);
[email protected]be1a48b2011-01-20 00:12:132060 ipv6_probe_job_->Start();
2061 }
[email protected]23f771162011-06-02 18:37:512062#if defined(OS_POSIX) && !defined(OS_MACOSX)
[email protected]be1a48b2011-01-20 00:12:132063 if (HaveOnlyLoopbackAddresses()) {
2064 additional_resolver_flags_ |= HOST_RESOLVER_LOOPBACK_ONLY;
2065 } else {
2066 additional_resolver_flags_ &= ~HOST_RESOLVER_LOOPBACK_ONLY;
2067 }
2068#endif
2069 AbortAllInProgressJobs();
2070 // |this| may be deleted inside AbortAllInProgressJobs().
2071}
2072
[email protected]bb0e34542012-08-31 19:52:402073void HostResolverImpl::OnDNSChanged() {
2074 DnsConfig dns_config;
2075 NetworkChangeNotifier::GetDnsConfig(&dns_config);
[email protected]b4481b222012-03-16 17:13:112076 if (net_log_) {
2077 net_log_->AddGlobalEntry(
2078 NetLog::TYPE_DNS_CONFIG_CHANGED,
[email protected]cd565142012-06-12 16:21:452079 base::Bind(&NetLogDnsConfigCallback, &dns_config));
[email protected]b4481b222012-03-16 17:13:112080 }
2081
[email protected]01b3b9d2012-08-13 16:18:142082 // TODO(szym): Remove once http://crbug.com/137914 is resolved.
[email protected]d7b9a2b2012-05-31 22:31:192083 received_dns_config_ = dns_config.IsValid();
[email protected]78eac2a2012-03-14 19:09:272084
2085 // Life check to bail once |this| is deleted.
[email protected]4589a3a2012-09-20 20:57:072086 base::WeakPtr<HostResolverImpl> self = weak_ptr_factory_.GetWeakPtr();
[email protected]78eac2a2012-03-14 19:09:272087
[email protected]01b3b9d2012-08-13 16:18:142088 // We want a new DnsSession in place, before we Abort running Jobs, so that
2089 // the newly started jobs use the new config.
2090 if (dns_client_.get())
[email protected]d7b9a2b2012-05-31 22:31:192091 dns_client_->SetConfig(dns_config);
[email protected]01b3b9d2012-08-13 16:18:142092
2093 // If the DNS server has changed, existing cached info could be wrong so we
2094 // have to drop our internal cache :( Note that OS level DNS caches, such
2095 // as NSCD's cache should be dropped automatically by the OS when
2096 // resolv.conf changes so we don't need to do anything to clear that cache.
2097 if (cache_.get())
2098 cache_->clear();
2099
2100 // Existing jobs will have been sent to the original server so they need to
2101 // be aborted.
2102 AbortAllInProgressJobs();
2103
2104 // |this| may be deleted inside AbortAllInProgressJobs().
2105 if (self)
2106 TryServingAllJobsFromHosts();
[email protected]78eac2a2012-03-14 19:09:272107}
2108
2109bool HostResolverImpl::HaveDnsConfig() const {
2110 return (dns_client_.get() != NULL) && (dns_client_->GetConfig() != NULL);
[email protected]b3601bc22012-02-21 21:23:202111}
2112
[email protected]b59ff372009-07-15 22:04:322113} // namespace net