blob: e18a9e5b6eb8ac8cf22b654bba941e83bc3d6433 [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]78eac2a2012-03-14 19:09:2741#include "net/dns/dns_client.h"
[email protected]b3601bc22012-02-21 21:23:2042#include "net/dns/dns_config_service.h"
43#include "net/dns/dns_protocol.h"
44#include "net/dns/dns_response.h"
[email protected]b3601bc22012-02-21 21:23:2045#include "net/dns/dns_transaction.h"
[email protected]b59ff372009-07-15 22:04:3246
47#if defined(OS_WIN)
48#include "net/base/winsock_init.h"
49#endif
50
51namespace net {
52
[email protected]e95d3aca2010-01-11 22:47:4353namespace {
54
[email protected]6e78dfb2011-07-28 21:34:4755// Limit the size of hostnames that will be resolved to combat issues in
56// some platform's resolvers.
57const size_t kMaxHostLength = 4096;
58
[email protected]a2730882012-01-21 00:56:2759// Default TTL for successful resolutions with ProcTask.
60const unsigned kCacheEntryTTLSeconds = 60;
61
[email protected]b3601bc22012-02-21 21:23:2062// Default TTL for unsuccessful resolutions with ProcTask.
63const unsigned kNegativeCacheEntryTTLSeconds = 0;
64
[email protected]4f8a16a2012-04-07 23:59:2065// Maximum of 6 concurrent resolver threads (excluding retries).
[email protected]0f292de02012-02-01 22:28:2066// Some routers (or resolvers) appear to start to provide host-not-found if
67// too many simultaneous resolutions are pending. This number needs to be
[email protected]4f8a16a2012-04-07 23:59:2068// further optimized, but 8 is what FF currently does. We found some routers
69// that limit this to 6, so we're temporarily holding it at that level.
70static const size_t kDefaultMaxProcTasks = 6u;
[email protected]0f292de02012-02-01 22:28:2071
[email protected]24f4bab2010-10-15 01:27:1172// We use a separate histogram name for each platform to facilitate the
73// display of error codes by their symbolic name (since each platform has
74// different mappings).
75const char kOSErrorsForGetAddrinfoHistogramName[] =
76#if defined(OS_WIN)
77 "Net.OSErrorsForGetAddrinfo_Win";
78#elif defined(OS_MACOSX)
79 "Net.OSErrorsForGetAddrinfo_Mac";
80#elif defined(OS_LINUX)
81 "Net.OSErrorsForGetAddrinfo_Linux";
82#else
83 "Net.OSErrorsForGetAddrinfo";
84#endif
85
[email protected]c89b2442011-05-26 14:28:2786// Gets a list of the likely error codes that getaddrinfo() can return
87// (non-exhaustive). These are the error codes that we will track via
88// a histogram.
89std::vector<int> GetAllGetAddrinfoOSErrors() {
90 int os_errors[] = {
91#if defined(OS_POSIX)
[email protected]23f771162011-06-02 18:37:5192#if !defined(OS_FREEBSD)
[email protected]39588992011-07-11 19:54:3793#if !defined(OS_ANDROID)
[email protected]c48aef92011-11-22 23:41:4594 // EAI_ADDRFAMILY has been declared obsolete in Android's and
95 // FreeBSD's netdb.h.
[email protected]c89b2442011-05-26 14:28:2796 EAI_ADDRFAMILY,
[email protected]39588992011-07-11 19:54:3797#endif
[email protected]c48aef92011-11-22 23:41:4598 // EAI_NODATA has been declared obsolete in FreeBSD's netdb.h.
[email protected]23f771162011-06-02 18:37:5199 EAI_NODATA,
100#endif
[email protected]c89b2442011-05-26 14:28:27101 EAI_AGAIN,
102 EAI_BADFLAGS,
103 EAI_FAIL,
104 EAI_FAMILY,
105 EAI_MEMORY,
[email protected]c89b2442011-05-26 14:28:27106 EAI_NONAME,
107 EAI_SERVICE,
108 EAI_SOCKTYPE,
109 EAI_SYSTEM,
110#elif defined(OS_WIN)
111 // See: http://msdn.microsoft.com/en-us/library/ms738520(VS.85).aspx
112 WSA_NOT_ENOUGH_MEMORY,
113 WSAEAFNOSUPPORT,
114 WSAEINVAL,
115 WSAESOCKTNOSUPPORT,
116 WSAHOST_NOT_FOUND,
117 WSANO_DATA,
118 WSANO_RECOVERY,
119 WSANOTINITIALISED,
120 WSATRY_AGAIN,
121 WSATYPE_NOT_FOUND,
122 // The following are not in doc, but might be to appearing in results :-(.
123 WSA_INVALID_HANDLE,
124#endif
125 };
126
127 // Ensure all errors are positive, as histogram only tracks positive values.
128 for (size_t i = 0; i < arraysize(os_errors); ++i) {
129 os_errors[i] = std::abs(os_errors[i]);
130 }
131
132 return base::CustomHistogram::ArrayToCustomRanges(os_errors,
133 arraysize(os_errors));
134}
135
[email protected]1def74c2012-03-22 20:07:00136enum DnsResolveStatus {
137 RESOLVE_STATUS_DNS_SUCCESS = 0,
138 RESOLVE_STATUS_PROC_SUCCESS,
139 RESOLVE_STATUS_FAIL,
[email protected]1d932852012-06-19 19:40:33140 RESOLVE_STATUS_SUSPECT_NETBIOS,
[email protected]1def74c2012-03-22 20:07:00141 RESOLVE_STATUS_MAX
142};
143
144void UmaAsyncDnsResolveStatus(DnsResolveStatus result) {
145 UMA_HISTOGRAM_ENUMERATION("AsyncDNS.ResolveStatus",
146 result,
147 RESOLVE_STATUS_MAX);
148}
149
[email protected]1d932852012-06-19 19:40:33150bool ResemblesNetBIOSName(const std::string& hostname) {
151 return (hostname.size() < 16) && (hostname.find('.') == std::string::npos);
152}
153
154// True if |hostname| ends with either ".local" or ".local.".
155bool ResemblesMulticastDNSName(const std::string& hostname) {
156 DCHECK(!hostname.empty());
157 const char kSuffix[] = ".local.";
158 const size_t kSuffixLen = sizeof(kSuffix) - 1;
159 const size_t kSuffixLenTrimmed = kSuffixLen - 1;
160 if (hostname[hostname.size() - 1] == '.') {
161 return hostname.size() > kSuffixLen &&
162 !hostname.compare(hostname.size() - kSuffixLen, kSuffixLen, kSuffix);
163 }
164 return hostname.size() > kSuffixLenTrimmed &&
165 !hostname.compare(hostname.size() - kSuffixLenTrimmed, kSuffixLenTrimmed,
166 kSuffix, kSuffixLenTrimmed);
167}
168
[email protected]51b9a6b2012-06-25 21:50:29169// Provide a common macro to simplify code and readability. We must use a
170// macro as the underlying HISTOGRAM macro creates static variables.
171#define DNS_HISTOGRAM(name, time) UMA_HISTOGRAM_CUSTOM_TIMES(name, time, \
172 base::TimeDelta::FromMilliseconds(1), base::TimeDelta::FromHours(1), 100)
173
174// A macro to simplify code and readability.
175#define DNS_HISTOGRAM_BY_PRIORITY(basename, priority, time) \
176 do { \
177 switch (priority) { \
178 case HIGHEST: DNS_HISTOGRAM(basename "_HIGHEST", time); break; \
179 case MEDIUM: DNS_HISTOGRAM(basename "_MEDIUM", time); break; \
180 case LOW: DNS_HISTOGRAM(basename "_LOW", time); break; \
181 case LOWEST: DNS_HISTOGRAM(basename "_LOWEST", time); break; \
182 case IDLE: DNS_HISTOGRAM(basename "_IDLE", time); break; \
183 default: NOTREACHED(); break; \
184 } \
185 DNS_HISTOGRAM(basename, time); \
186 } while (0)
187
188// Record time from Request creation until a valid DNS response.
189void RecordTotalTime(bool had_dns_config,
190 bool speculative,
191 base::TimeDelta duration) {
192 if (had_dns_config) {
193 if (speculative) {
194 DNS_HISTOGRAM("AsyncDNS.TotalTime_speculative", duration);
195 } else {
196 DNS_HISTOGRAM("AsyncDNS.TotalTime", duration);
197 }
198 } else {
199 if (speculative) {
200 DNS_HISTOGRAM("DNS.TotalTime_speculative", duration);
201 } else {
202 DNS_HISTOGRAM("DNS.TotalTime", duration);
203 }
204 }
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
405//-----------------------------------------------------------------------------
406
407HostResolver* CreateHostResolver(size_t max_concurrent_resolves,
408 size_t max_retry_attempts,
[email protected]b3601bc22012-02-21 21:23:20409 HostCache* cache,
410 scoped_ptr<DnsConfigService> config_service,
[email protected]d7b9a2b2012-05-31 22:31:19411 scoped_ptr<DnsClient> dns_client,
[email protected]0f292de02012-02-01 22:28:20412 NetLog* net_log) {
413 if (max_concurrent_resolves == HostResolver::kDefaultParallelism)
414 max_concurrent_resolves = kDefaultMaxProcTasks;
415
416 // TODO(szym): Add experiments with reserved slots for higher priority
417 // requests.
418
419 PrioritizedDispatcher::Limits limits(NUM_PRIORITIES, max_concurrent_resolves);
420
421 HostResolverImpl* resolver = new HostResolverImpl(
[email protected]b3601bc22012-02-21 21:23:20422 cache,
[email protected]0f292de02012-02-01 22:28:20423 limits,
424 HostResolverImpl::ProcTaskParams(NULL, max_retry_attempts),
[email protected]b3601bc22012-02-21 21:23:20425 config_service.Pass(),
[email protected]d7b9a2b2012-05-31 22:31:19426 dns_client.Pass(),
[email protected]0f292de02012-02-01 22:28:20427 net_log);
428
429 return resolver;
430}
431
432} // anonymous namespace
433
434//-----------------------------------------------------------------------------
435
436HostResolver* CreateSystemHostResolver(size_t max_concurrent_resolves,
437 size_t max_retry_attempts,
438 NetLog* net_log) {
439 return CreateHostResolver(max_concurrent_resolves,
440 max_retry_attempts,
[email protected]b3601bc22012-02-21 21:23:20441 HostCache::CreateDefaultCache(),
[email protected]d7b9a2b2012-05-31 22:31:19442 DnsConfigService::CreateSystemService(),
443 scoped_ptr<DnsClient>(NULL),
[email protected]0f292de02012-02-01 22:28:20444 net_log);
445}
446
447HostResolver* CreateNonCachingSystemHostResolver(size_t max_concurrent_resolves,
448 size_t max_retry_attempts,
449 NetLog* net_log) {
450 return CreateHostResolver(max_concurrent_resolves,
451 max_retry_attempts,
[email protected]b3601bc22012-02-21 21:23:20452 NULL,
453 scoped_ptr<DnsConfigService>(NULL),
[email protected]d7b9a2b2012-05-31 22:31:19454 scoped_ptr<DnsClient>(NULL),
[email protected]b3601bc22012-02-21 21:23:20455 net_log);
456}
457
458HostResolver* CreateAsyncHostResolver(size_t max_concurrent_resolves,
459 size_t max_retry_attempts,
460 NetLog* net_log) {
[email protected]b3601bc22012-02-21 21:23:20461 return CreateHostResolver(max_concurrent_resolves,
462 max_retry_attempts,
463 HostCache::CreateDefaultCache(),
[email protected]d7b9a2b2012-05-31 22:31:19464 DnsConfigService::CreateSystemService(),
465 DnsClient::CreateClient(net_log),
[email protected]0f292de02012-02-01 22:28:20466 net_log);
467}
468
469//-----------------------------------------------------------------------------
470
471// Holds the data for a request that could not be completed synchronously.
472// It is owned by a Job. Canceled Requests are only marked as canceled rather
473// than removed from the Job's |requests_| list.
[email protected]b59ff372009-07-15 22:04:32474class HostResolverImpl::Request {
475 public:
[email protected]ee094b82010-08-24 15:55:51476 Request(const BoundNetLog& source_net_log,
477 const BoundNetLog& request_net_log,
[email protected]54e13772009-08-14 03:01:09478 const RequestInfo& info,
[email protected]aa22b242011-11-16 18:58:29479 const CompletionCallback& callback,
[email protected]b59ff372009-07-15 22:04:32480 AddressList* addresses)
[email protected]ee094b82010-08-24 15:55:51481 : source_net_log_(source_net_log),
482 request_net_log_(request_net_log),
[email protected]54e13772009-08-14 03:01:09483 info_(info),
484 job_(NULL),
485 callback_(callback),
[email protected]51b9a6b2012-06-25 21:50:29486 addresses_(addresses),
487 request_time_(base::TimeTicks::Now()) {
[email protected]54e13772009-08-14 03:01:09488 }
[email protected]b59ff372009-07-15 22:04:32489
[email protected]0f292de02012-02-01 22:28:20490 // Mark the request as canceled.
491 void MarkAsCanceled() {
[email protected]b59ff372009-07-15 22:04:32492 job_ = NULL;
[email protected]b59ff372009-07-15 22:04:32493 addresses_ = NULL;
[email protected]aa22b242011-11-16 18:58:29494 callback_.Reset();
[email protected]b59ff372009-07-15 22:04:32495 }
496
[email protected]0f292de02012-02-01 22:28:20497 bool was_canceled() const {
[email protected]aa22b242011-11-16 18:58:29498 return callback_.is_null();
[email protected]b59ff372009-07-15 22:04:32499 }
500
501 void set_job(Job* job) {
[email protected]0f292de02012-02-01 22:28:20502 DCHECK(job);
[email protected]b59ff372009-07-15 22:04:32503 // Identify which job the request is waiting on.
504 job_ = job;
505 }
506
[email protected]0f292de02012-02-01 22:28:20507 // Prepare final AddressList and call completion callback.
[email protected]b3601bc22012-02-21 21:23:20508 void OnComplete(int error, const AddressList& addr_list) {
[email protected]51b9a6b2012-06-25 21:50:29509 DCHECK(!was_canceled());
[email protected]7054e78f2012-05-07 21:44:56510 if (error == OK) {
511 *addresses_ = addr_list;
512 EnsurePortOnAddressList(info_.port(), addresses_);
513 }
[email protected]aa22b242011-11-16 18:58:29514 CompletionCallback callback = callback_;
[email protected]0f292de02012-02-01 22:28:20515 MarkAsCanceled();
[email protected]aa22b242011-11-16 18:58:29516 callback.Run(error);
[email protected]b59ff372009-07-15 22:04:32517 }
518
[email protected]b59ff372009-07-15 22:04:32519 Job* job() const {
520 return job_;
521 }
522
[email protected]0f292de02012-02-01 22:28:20523 // NetLog for the source, passed in HostResolver::Resolve.
[email protected]ee094b82010-08-24 15:55:51524 const BoundNetLog& source_net_log() {
525 return source_net_log_;
526 }
527
[email protected]0f292de02012-02-01 22:28:20528 // NetLog for this request.
[email protected]ee094b82010-08-24 15:55:51529 const BoundNetLog& request_net_log() {
530 return request_net_log_;
[email protected]54e13772009-08-14 03:01:09531 }
532
[email protected]b59ff372009-07-15 22:04:32533 const RequestInfo& info() const {
534 return info_;
535 }
536
[email protected]51b9a6b2012-06-25 21:50:29537 base::TimeTicks request_time() const {
538 return request_time_;
539 }
540
[email protected]b59ff372009-07-15 22:04:32541 private:
[email protected]ee094b82010-08-24 15:55:51542 BoundNetLog source_net_log_;
543 BoundNetLog request_net_log_;
[email protected]54e13772009-08-14 03:01:09544
[email protected]b59ff372009-07-15 22:04:32545 // The request info that started the request.
546 RequestInfo info_;
547
[email protected]0f292de02012-02-01 22:28:20548 // The resolve job that this request is dependent on.
[email protected]b59ff372009-07-15 22:04:32549 Job* job_;
550
551 // The user's callback to invoke when the request completes.
[email protected]aa22b242011-11-16 18:58:29552 CompletionCallback callback_;
[email protected]b59ff372009-07-15 22:04:32553
554 // The address list to save result into.
555 AddressList* addresses_;
556
[email protected]51b9a6b2012-06-25 21:50:29557 const base::TimeTicks request_time_;
558
[email protected]b59ff372009-07-15 22:04:32559 DISALLOW_COPY_AND_ASSIGN(Request);
560};
561
[email protected]1e9bbd22010-10-15 16:42:45562//------------------------------------------------------------------------------
563
[email protected]0f292de02012-02-01 22:28:20564// Calls HostResolverProc on the WorkerPool. Performs retries if necessary.
565//
566// Whenever we try to resolve the host, we post a delayed task to check if host
567// resolution (OnLookupComplete) is completed or not. If the original attempt
568// hasn't completed, then we start another attempt for host resolution. We take
569// the results from the first attempt that finishes and ignore the results from
570// all other attempts.
571//
572// TODO(szym): Move to separate source file for testing and mocking.
573//
574class HostResolverImpl::ProcTask
575 : public base::RefCountedThreadSafe<HostResolverImpl::ProcTask> {
[email protected]b59ff372009-07-15 22:04:32576 public:
[email protected]b3601bc22012-02-21 21:23:20577 typedef base::Callback<void(int net_error,
578 const AddressList& addr_list)> Callback;
[email protected]b59ff372009-07-15 22:04:32579
[email protected]0f292de02012-02-01 22:28:20580 ProcTask(const Key& key,
581 const ProcTaskParams& params,
582 const Callback& callback,
583 const BoundNetLog& job_net_log)
584 : key_(key),
585 params_(params),
586 callback_(callback),
587 origin_loop_(base::MessageLoopProxy::current()),
588 attempt_number_(0),
589 completed_attempt_number_(0),
590 completed_attempt_error_(ERR_UNEXPECTED),
591 had_non_speculative_request_(false),
[email protected]b3601bc22012-02-21 21:23:20592 net_log_(job_net_log) {
[email protected]0f292de02012-02-01 22:28:20593 if (!params_.resolver_proc)
594 params_.resolver_proc = HostResolverProc::GetDefault();
595 // If default is unset, use the system proc.
596 if (!params_.resolver_proc)
597 params_.resolver_proc = new CallSystemHostResolverProc();
[email protected]b59ff372009-07-15 22:04:32598 }
599
[email protected]b59ff372009-07-15 22:04:32600 void Start() {
[email protected]3e9d9cc2011-05-03 21:08:15601 DCHECK(origin_loop_->BelongsToCurrentThread());
[email protected]4da911f2012-06-14 19:45:20602 net_log_.BeginEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_PROC_TASK);
[email protected]189163e2011-05-11 01:48:54603 StartLookupAttempt();
604 }
[email protected]252b699b2010-02-05 21:38:06605
[email protected]0f292de02012-02-01 22:28:20606 // Cancels this ProcTask. It will be orphaned. Any outstanding resolve
607 // attempts running on worker threads will continue running. Only once all the
608 // attempts complete will the final reference to this ProcTask be released.
609 void Cancel() {
610 DCHECK(origin_loop_->BelongsToCurrentThread());
611
612 if (was_canceled())
613 return;
614
[email protected]0f292de02012-02-01 22:28:20615 callback_.Reset();
[email protected]4da911f2012-06-14 19:45:20616 net_log_.EndEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_PROC_TASK);
[email protected]0f292de02012-02-01 22:28:20617 }
618
619 void set_had_non_speculative_request() {
620 DCHECK(origin_loop_->BelongsToCurrentThread());
621 had_non_speculative_request_ = true;
622 }
623
624 bool was_canceled() const {
625 DCHECK(origin_loop_->BelongsToCurrentThread());
626 return callback_.is_null();
627 }
628
629 bool was_completed() const {
630 DCHECK(origin_loop_->BelongsToCurrentThread());
631 return completed_attempt_number_ > 0;
632 }
633
634 private:
[email protected]a9813302012-04-28 09:29:28635 friend class base::RefCountedThreadSafe<ProcTask>;
636 ~ProcTask() {}
637
[email protected]189163e2011-05-11 01:48:54638 void StartLookupAttempt() {
639 DCHECK(origin_loop_->BelongsToCurrentThread());
640 base::TimeTicks start_time = base::TimeTicks::Now();
641 ++attempt_number_;
642 // Dispatch the lookup attempt to a worker thread.
643 if (!base::WorkerPool::PostTask(
644 FROM_HERE,
[email protected]0f292de02012-02-01 22:28:20645 base::Bind(&ProcTask::DoLookup, this, start_time, attempt_number_),
[email protected]189163e2011-05-11 01:48:54646 true)) {
[email protected]b59ff372009-07-15 22:04:32647 NOTREACHED();
648
649 // Since we could be running within Resolve() right now, we can't just
650 // call OnLookupComplete(). Instead we must wait until Resolve() has
651 // returned (IO_PENDING).
[email protected]3e9d9cc2011-05-03 21:08:15652 origin_loop_->PostTask(
[email protected]189163e2011-05-11 01:48:54653 FROM_HERE,
[email protected]0f292de02012-02-01 22:28:20654 base::Bind(&ProcTask::OnLookupComplete, this, AddressList(),
[email protected]33152acc2011-10-20 23:37:12655 start_time, attempt_number_, ERR_UNEXPECTED, 0));
[email protected]189163e2011-05-11 01:48:54656 return;
[email protected]b59ff372009-07-15 22:04:32657 }
[email protected]13024882011-05-18 23:19:16658
659 net_log_.AddEvent(
660 NetLog::TYPE_HOST_RESOLVER_IMPL_ATTEMPT_STARTED,
[email protected]cd565142012-06-12 16:21:45661 NetLog::IntegerCallback("attempt_number", attempt_number_));
[email protected]13024882011-05-18 23:19:16662
[email protected]0f292de02012-02-01 22:28:20663 // If we don't get the results within a given time, RetryIfNotComplete
664 // will start a new attempt on a different worker thread if none of our
665 // outstanding attempts have completed yet.
666 if (attempt_number_ <= params_.max_retry_attempts) {
[email protected]06ef6d92011-05-19 04:24:58667 origin_loop_->PostDelayedTask(
668 FROM_HERE,
[email protected]0f292de02012-02-01 22:28:20669 base::Bind(&ProcTask::RetryIfNotComplete, this),
[email protected]7e560102012-03-08 20:58:42670 params_.unresponsive_delay);
[email protected]06ef6d92011-05-19 04:24:58671 }
[email protected]b59ff372009-07-15 22:04:32672 }
673
[email protected]6c710ee2010-05-07 07:51:16674 // WARNING: This code runs inside a worker pool. The shutdown code cannot
675 // wait for it to finish, so we must be very careful here about using other
676 // objects (like MessageLoops, Singletons, etc). During shutdown these objects
[email protected]189163e2011-05-11 01:48:54677 // may no longer exist. Multiple DoLookups() could be running in parallel, so
678 // any state inside of |this| must not mutate .
679 void DoLookup(const base::TimeTicks& start_time,
680 const uint32 attempt_number) {
681 AddressList results;
682 int os_error = 0;
[email protected]b59ff372009-07-15 22:04:32683 // Running on the worker thread
[email protected]0f292de02012-02-01 22:28:20684 int error = params_.resolver_proc->Resolve(key_.hostname,
685 key_.address_family,
686 key_.host_resolver_flags,
687 &results,
688 &os_error);
[email protected]b59ff372009-07-15 22:04:32689
[email protected]189163e2011-05-11 01:48:54690 origin_loop_->PostTask(
691 FROM_HERE,
[email protected]0f292de02012-02-01 22:28:20692 base::Bind(&ProcTask::OnLookupComplete, this, results, start_time,
[email protected]33152acc2011-10-20 23:37:12693 attempt_number, error, os_error));
[email protected]189163e2011-05-11 01:48:54694 }
695
[email protected]0f292de02012-02-01 22:28:20696 // Makes next attempt if DoLookup() has not finished (runs on origin thread).
697 void RetryIfNotComplete() {
[email protected]189163e2011-05-11 01:48:54698 DCHECK(origin_loop_->BelongsToCurrentThread());
699
[email protected]0f292de02012-02-01 22:28:20700 if (was_completed() || was_canceled())
[email protected]189163e2011-05-11 01:48:54701 return;
702
[email protected]0f292de02012-02-01 22:28:20703 params_.unresponsive_delay *= params_.retry_factor;
[email protected]189163e2011-05-11 01:48:54704 StartLookupAttempt();
[email protected]b59ff372009-07-15 22:04:32705 }
706
707 // Callback for when DoLookup() completes (runs on origin thread).
[email protected]189163e2011-05-11 01:48:54708 void OnLookupComplete(const AddressList& results,
709 const base::TimeTicks& start_time,
710 const uint32 attempt_number,
711 int error,
712 const int os_error) {
[email protected]3e9d9cc2011-05-03 21:08:15713 DCHECK(origin_loop_->BelongsToCurrentThread());
[email protected]7054e78f2012-05-07 21:44:56714 DCHECK(error || !results.empty());
[email protected]189163e2011-05-11 01:48:54715
716 bool was_retry_attempt = attempt_number > 1;
717
[email protected]2d3b7762010-10-09 00:35:47718 // Ideally the following code would be part of host_resolver_proc.cc,
[email protected]b3601bc22012-02-21 21:23:20719 // however it isn't safe to call NetworkChangeNotifier from worker threads.
720 // So we do it here on the IO thread instead.
[email protected]189163e2011-05-11 01:48:54721 if (error != OK && NetworkChangeNotifier::IsOffline())
722 error = ERR_INTERNET_DISCONNECTED;
[email protected]2d3b7762010-10-09 00:35:47723
[email protected]b3601bc22012-02-21 21:23:20724 // If this is the first attempt that is finishing later, then record data
725 // for the first attempt. Won't contaminate with retry attempt's data.
[email protected]189163e2011-05-11 01:48:54726 if (!was_retry_attempt)
727 RecordPerformanceHistograms(start_time, error, os_error);
728
729 RecordAttemptHistograms(start_time, attempt_number, error, os_error);
[email protected]f2d8c4212010-02-02 00:56:35730
[email protected]0f292de02012-02-01 22:28:20731 if (was_canceled())
[email protected]b59ff372009-07-15 22:04:32732 return;
733
[email protected]cd565142012-06-12 16:21:45734 NetLog::ParametersCallback net_log_callback;
[email protected]0f292de02012-02-01 22:28:20735 if (error != OK) {
[email protected]cd565142012-06-12 16:21:45736 net_log_callback = base::Bind(&NetLogProcTaskFailedCallback,
737 attempt_number,
738 error,
739 os_error);
[email protected]0f292de02012-02-01 22:28:20740 } else {
[email protected]cd565142012-06-12 16:21:45741 net_log_callback = NetLog::IntegerCallback("attempt_number",
742 attempt_number);
[email protected]0f292de02012-02-01 22:28:20743 }
[email protected]cd565142012-06-12 16:21:45744 net_log_.AddEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_ATTEMPT_FINISHED,
745 net_log_callback);
[email protected]0f292de02012-02-01 22:28:20746
747 if (was_completed())
748 return;
749
750 // Copy the results from the first worker thread that resolves the host.
751 results_ = results;
752 completed_attempt_number_ = attempt_number;
753 completed_attempt_error_ = error;
754
[email protected]e87b8b512011-06-14 22:12:52755 if (was_retry_attempt) {
756 // If retry attempt finishes before 1st attempt, then get stats on how
757 // much time is saved by having spawned an extra attempt.
758 retry_attempt_finished_time_ = base::TimeTicks::Now();
759 }
760
[email protected]189163e2011-05-11 01:48:54761 if (error != OK) {
[email protected]cd565142012-06-12 16:21:45762 net_log_callback = base::Bind(&NetLogProcTaskFailedCallback,
763 0, error, os_error);
[email protected]ee094b82010-08-24 15:55:51764 } else {
[email protected]cd565142012-06-12 16:21:45765 net_log_callback = results_.CreateNetLogCallback();
[email protected]ee094b82010-08-24 15:55:51766 }
[email protected]cd565142012-06-12 16:21:45767 net_log_.EndEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_PROC_TASK,
768 net_log_callback);
[email protected]ee094b82010-08-24 15:55:51769
[email protected]b3601bc22012-02-21 21:23:20770 callback_.Run(error, results_);
[email protected]b59ff372009-07-15 22:04:32771 }
772
[email protected]189163e2011-05-11 01:48:54773 void RecordPerformanceHistograms(const base::TimeTicks& start_time,
774 const int error,
775 const int os_error) const {
[email protected]3e9d9cc2011-05-03 21:08:15776 DCHECK(origin_loop_->BelongsToCurrentThread());
[email protected]1e9bbd22010-10-15 16:42:45777 enum Category { // Used in HISTOGRAM_ENUMERATION.
778 RESOLVE_SUCCESS,
779 RESOLVE_FAIL,
780 RESOLVE_SPECULATIVE_SUCCESS,
781 RESOLVE_SPECULATIVE_FAIL,
782 RESOLVE_MAX, // Bounding value.
783 };
784 int category = RESOLVE_MAX; // Illegal value for later DCHECK only.
785
[email protected]189163e2011-05-11 01:48:54786 base::TimeDelta duration = base::TimeTicks::Now() - start_time;
787 if (error == OK) {
[email protected]1e9bbd22010-10-15 16:42:45788 if (had_non_speculative_request_) {
789 category = RESOLVE_SUCCESS;
790 DNS_HISTOGRAM("DNS.ResolveSuccess", duration);
791 } else {
792 category = RESOLVE_SPECULATIVE_SUCCESS;
793 DNS_HISTOGRAM("DNS.ResolveSpeculativeSuccess", duration);
794 }
[email protected]7e96d792011-06-10 17:08:23795
[email protected]78eac2a2012-03-14 19:09:27796 // Log DNS lookups based on |address_family|. This will help us determine
[email protected]7e96d792011-06-10 17:08:23797 // if IPv4 or IPv4/6 lookups are faster or slower.
798 switch(key_.address_family) {
799 case ADDRESS_FAMILY_IPV4:
800 DNS_HISTOGRAM("DNS.ResolveSuccess_FAMILY_IPV4", duration);
801 break;
802 case ADDRESS_FAMILY_IPV6:
803 DNS_HISTOGRAM("DNS.ResolveSuccess_FAMILY_IPV6", duration);
804 break;
805 case ADDRESS_FAMILY_UNSPECIFIED:
806 DNS_HISTOGRAM("DNS.ResolveSuccess_FAMILY_UNSPEC", duration);
807 break;
808 }
[email protected]1e9bbd22010-10-15 16:42:45809 } else {
810 if (had_non_speculative_request_) {
811 category = RESOLVE_FAIL;
812 DNS_HISTOGRAM("DNS.ResolveFail", duration);
813 } else {
814 category = RESOLVE_SPECULATIVE_FAIL;
815 DNS_HISTOGRAM("DNS.ResolveSpeculativeFail", duration);
816 }
[email protected]78eac2a2012-03-14 19:09:27817 // Log DNS lookups based on |address_family|. This will help us determine
[email protected]7e96d792011-06-10 17:08:23818 // if IPv4 or IPv4/6 lookups are faster or slower.
819 switch(key_.address_family) {
820 case ADDRESS_FAMILY_IPV4:
821 DNS_HISTOGRAM("DNS.ResolveFail_FAMILY_IPV4", duration);
822 break;
823 case ADDRESS_FAMILY_IPV6:
824 DNS_HISTOGRAM("DNS.ResolveFail_FAMILY_IPV6", duration);
825 break;
826 case ADDRESS_FAMILY_UNSPECIFIED:
827 DNS_HISTOGRAM("DNS.ResolveFail_FAMILY_UNSPEC", duration);
828 break;
829 }
[email protected]c833e322010-10-16 23:51:36830 UMA_HISTOGRAM_CUSTOM_ENUMERATION(kOSErrorsForGetAddrinfoHistogramName,
[email protected]189163e2011-05-11 01:48:54831 std::abs(os_error),
[email protected]1e9bbd22010-10-15 16:42:45832 GetAllGetAddrinfoOSErrors());
833 }
[email protected]051b6ab2010-10-18 16:50:46834 DCHECK_LT(category, static_cast<int>(RESOLVE_MAX)); // Be sure it was set.
[email protected]1e9bbd22010-10-15 16:42:45835
836 UMA_HISTOGRAM_ENUMERATION("DNS.ResolveCategory", category, RESOLVE_MAX);
837
[email protected]edafd4c2011-05-10 17:18:53838 static const bool show_speculative_experiment_histograms =
839 base::FieldTrialList::TrialExists("DnsImpact");
[email protected]ecd95ae2010-10-20 23:58:17840 if (show_speculative_experiment_histograms) {
[email protected]1e9bbd22010-10-15 16:42:45841 UMA_HISTOGRAM_ENUMERATION(
842 base::FieldTrial::MakeName("DNS.ResolveCategory", "DnsImpact"),
843 category, RESOLVE_MAX);
844 if (RESOLVE_SUCCESS == category) {
845 DNS_HISTOGRAM(base::FieldTrial::MakeName("DNS.ResolveSuccess",
846 "DnsImpact"), duration);
847 }
848 }
[email protected]edafd4c2011-05-10 17:18:53849 static const bool show_parallelism_experiment_histograms =
850 base::FieldTrialList::TrialExists("DnsParallelism");
[email protected]ecd95ae2010-10-20 23:58:17851 if (show_parallelism_experiment_histograms) {
852 UMA_HISTOGRAM_ENUMERATION(
853 base::FieldTrial::MakeName("DNS.ResolveCategory", "DnsParallelism"),
854 category, RESOLVE_MAX);
855 if (RESOLVE_SUCCESS == category) {
856 DNS_HISTOGRAM(base::FieldTrial::MakeName("DNS.ResolveSuccess",
857 "DnsParallelism"), duration);
858 }
859 }
[email protected]1e9bbd22010-10-15 16:42:45860 }
861
[email protected]189163e2011-05-11 01:48:54862 void RecordAttemptHistograms(const base::TimeTicks& start_time,
863 const uint32 attempt_number,
864 const int error,
865 const int os_error) const {
[email protected]0f292de02012-02-01 22:28:20866 DCHECK(origin_loop_->BelongsToCurrentThread());
[email protected]189163e2011-05-11 01:48:54867 bool first_attempt_to_complete =
868 completed_attempt_number_ == attempt_number;
[email protected]e87b8b512011-06-14 22:12:52869 bool is_first_attempt = (attempt_number == 1);
[email protected]1e9bbd22010-10-15 16:42:45870
[email protected]189163e2011-05-11 01:48:54871 if (first_attempt_to_complete) {
872 // If this was first attempt to complete, then record the resolution
873 // status of the attempt.
874 if (completed_attempt_error_ == OK) {
875 UMA_HISTOGRAM_ENUMERATION(
876 "DNS.AttemptFirstSuccess", attempt_number, 100);
877 } else {
878 UMA_HISTOGRAM_ENUMERATION(
879 "DNS.AttemptFirstFailure", attempt_number, 100);
880 }
881 }
882
883 if (error == OK)
884 UMA_HISTOGRAM_ENUMERATION("DNS.AttemptSuccess", attempt_number, 100);
885 else
886 UMA_HISTOGRAM_ENUMERATION("DNS.AttemptFailure", attempt_number, 100);
887
[email protected]e87b8b512011-06-14 22:12:52888 // If first attempt didn't finish before retry attempt, then calculate stats
889 // on how much time is saved by having spawned an extra attempt.
[email protected]0f292de02012-02-01 22:28:20890 if (!first_attempt_to_complete && is_first_attempt && !was_canceled()) {
[email protected]e87b8b512011-06-14 22:12:52891 DNS_HISTOGRAM("DNS.AttemptTimeSavedByRetry",
892 base::TimeTicks::Now() - retry_attempt_finished_time_);
893 }
894
[email protected]0f292de02012-02-01 22:28:20895 if (was_canceled() || !first_attempt_to_complete) {
[email protected]189163e2011-05-11 01:48:54896 // Count those attempts which completed after the job was already canceled
897 // OR after the job was already completed by an earlier attempt (so in
898 // effect).
899 UMA_HISTOGRAM_ENUMERATION("DNS.AttemptDiscarded", attempt_number, 100);
900
[email protected]0f292de02012-02-01 22:28:20901 // Record if job is canceled.
902 if (was_canceled())
[email protected]189163e2011-05-11 01:48:54903 UMA_HISTOGRAM_ENUMERATION("DNS.AttemptCancelled", attempt_number, 100);
904 }
905
906 base::TimeDelta duration = base::TimeTicks::Now() - start_time;
907 if (error == OK)
908 DNS_HISTOGRAM("DNS.AttemptSuccessDuration", duration);
909 else
910 DNS_HISTOGRAM("DNS.AttemptFailDuration", duration);
911 }
[email protected]1e9bbd22010-10-15 16:42:45912
[email protected]b59ff372009-07-15 22:04:32913 // Set on the origin thread, read on the worker thread.
[email protected]123ab1e32009-10-21 19:12:57914 Key key_;
[email protected]b59ff372009-07-15 22:04:32915
[email protected]0f292de02012-02-01 22:28:20916 // Holds an owning reference to the HostResolverProc that we are going to use.
[email protected]b59ff372009-07-15 22:04:32917 // This may not be the current resolver procedure by the time we call
918 // ResolveAddrInfo, but that's OK... we'll use it anyways, and the owning
919 // reference ensures that it remains valid until we are done.
[email protected]0f292de02012-02-01 22:28:20920 ProcTaskParams params_;
[email protected]b59ff372009-07-15 22:04:32921
[email protected]0f292de02012-02-01 22:28:20922 // The listener to the results of this ProcTask.
923 Callback callback_;
924
925 // Used to post ourselves onto the origin thread.
926 scoped_refptr<base::MessageLoopProxy> origin_loop_;
[email protected]189163e2011-05-11 01:48:54927
928 // Keeps track of the number of attempts we have made so far to resolve the
929 // host. Whenever we start an attempt to resolve the host, we increase this
930 // number.
931 uint32 attempt_number_;
932
933 // The index of the attempt which finished first (or 0 if the job is still in
934 // progress).
935 uint32 completed_attempt_number_;
936
937 // The result (a net error code) from the first attempt to complete.
938 int completed_attempt_error_;
[email protected]252b699b2010-02-05 21:38:06939
[email protected]e87b8b512011-06-14 22:12:52940 // The time when retry attempt was finished.
941 base::TimeTicks retry_attempt_finished_time_;
942
[email protected]252b699b2010-02-05 21:38:06943 // True if a non-speculative request was ever attached to this job
[email protected]0f292de02012-02-01 22:28:20944 // (regardless of whether or not it was later canceled.
[email protected]252b699b2010-02-05 21:38:06945 // This boolean is used for histogramming the duration of jobs used to
946 // service non-speculative requests.
947 bool had_non_speculative_request_;
948
[email protected]b59ff372009-07-15 22:04:32949 AddressList results_;
950
[email protected]ee094b82010-08-24 15:55:51951 BoundNetLog net_log_;
952
[email protected]0f292de02012-02-01 22:28:20953 DISALLOW_COPY_AND_ASSIGN(ProcTask);
[email protected]b59ff372009-07-15 22:04:32954};
955
956//-----------------------------------------------------------------------------
957
[email protected]0f292de02012-02-01 22:28:20958// Represents a request to the worker pool for a "probe for IPv6 support" call.
[email protected]b3601bc22012-02-21 21:23:20959//
960// TODO(szym): This could also be replaced with PostTaskAndReply and Callbacks.
[email protected]0f8f1b432010-03-16 19:06:03961class HostResolverImpl::IPv6ProbeJob
962 : public base::RefCountedThreadSafe<HostResolverImpl::IPv6ProbeJob> {
963 public:
[email protected]ae8e80f2012-07-19 21:08:33964 IPv6ProbeJob(HostResolverImpl* resolver, NetLog* net_log)
[email protected]0f8f1b432010-03-16 19:06:03965 : resolver_(resolver),
[email protected]ae8e80f2012-07-19 21:08:33966 origin_loop_(base::MessageLoopProxy::current()),
967 net_log_(BoundNetLog::Make(net_log, NetLog::SOURCE_IPV6_PROBE_JOB)) {
[email protected]3e9d9cc2011-05-03 21:08:15968 DCHECK(resolver);
[email protected]0f8f1b432010-03-16 19:06:03969 }
970
971 void Start() {
[email protected]3e9d9cc2011-05-03 21:08:15972 DCHECK(origin_loop_->BelongsToCurrentThread());
[email protected]0f292de02012-02-01 22:28:20973 if (was_canceled())
[email protected]a9af7112010-05-08 00:56:01974 return;
[email protected]ae8e80f2012-07-19 21:08:33975 net_log_.BeginEvent(NetLog::TYPE_IPV6_PROBE_RUNNING);
[email protected]f092e64b2010-03-17 00:39:18976 const bool kIsSlow = true;
[email protected]ac9ba8fe2010-12-30 18:08:36977 base::WorkerPool::PostTask(
[email protected]33152acc2011-10-20 23:37:12978 FROM_HERE, base::Bind(&IPv6ProbeJob::DoProbe, this), kIsSlow);
[email protected]0f8f1b432010-03-16 19:06:03979 }
980
981 // Cancels the current job.
982 void Cancel() {
[email protected]3e9d9cc2011-05-03 21:08:15983 DCHECK(origin_loop_->BelongsToCurrentThread());
[email protected]0f292de02012-02-01 22:28:20984 if (was_canceled())
[email protected]a9af7112010-05-08 00:56:01985 return;
[email protected]ae8e80f2012-07-19 21:08:33986 net_log_.AddEvent(NetLog::TYPE_CANCELLED);
[email protected]0f8f1b432010-03-16 19:06:03987 resolver_ = NULL; // Read/write ONLY on origin thread.
[email protected]0f8f1b432010-03-16 19:06:03988 }
989
[email protected]0f8f1b432010-03-16 19:06:03990 private:
991 friend class base::RefCountedThreadSafe<HostResolverImpl::IPv6ProbeJob>;
992
993 ~IPv6ProbeJob() {
994 }
995
[email protected]ae8e80f2012-07-19 21:08:33996 // Returns true if cancelled or if probe results have already been received
997 // on the origin thread.
[email protected]0f292de02012-02-01 22:28:20998 bool was_canceled() const {
[email protected]3e9d9cc2011-05-03 21:08:15999 DCHECK(origin_loop_->BelongsToCurrentThread());
1000 return !resolver_;
[email protected]a9af7112010-05-08 00:56:011001 }
1002
[email protected]0f8f1b432010-03-16 19:06:031003 // Run on worker thread.
1004 void DoProbe() {
1005 // Do actual testing on this thread, as it takes 40-100ms.
[email protected]3e9d9cc2011-05-03 21:08:151006 origin_loop_->PostTask(
1007 FROM_HERE,
[email protected]ae8e80f2012-07-19 21:08:331008 base::Bind(&IPv6ProbeJob::OnProbeComplete, this, TestIPv6Support()));
[email protected]0f8f1b432010-03-16 19:06:031009 }
1010
[email protected]3e9d9cc2011-05-03 21:08:151011 // Callback for when DoProbe() completes.
[email protected]ae8e80f2012-07-19 21:08:331012 void OnProbeComplete(const IPv6SupportResult& support_result) {
[email protected]3e9d9cc2011-05-03 21:08:151013 DCHECK(origin_loop_->BelongsToCurrentThread());
[email protected]ae8e80f2012-07-19 21:08:331014 net_log_.EndEvent(
1015 NetLog::TYPE_IPV6_PROBE_RUNNING,
1016 base::Bind(&IPv6SupportResult::ToNetLogValue,
1017 base::Unretained(&support_result)));
[email protected]0f292de02012-02-01 22:28:201018 if (was_canceled())
[email protected]a9af7112010-05-08 00:56:011019 return;
[email protected]ae8e80f2012-07-19 21:08:331020
1021 // Clear |resolver_| so that no cancel event is logged.
1022 HostResolverImpl* resolver = resolver_;
1023 resolver_ = NULL;
1024
1025 resolver->IPv6ProbeSetDefaultAddressFamily(
1026 support_result.ipv6_supported ? ADDRESS_FAMILY_UNSPECIFIED
1027 : ADDRESS_FAMILY_IPV4);
[email protected]0f8f1b432010-03-16 19:06:031028 }
1029
[email protected]0f8f1b432010-03-16 19:06:031030 // Used/set only on origin thread.
1031 HostResolverImpl* resolver_;
1032
1033 // Used to post ourselves onto the origin thread.
[email protected]3e9d9cc2011-05-03 21:08:151034 scoped_refptr<base::MessageLoopProxy> origin_loop_;
[email protected]0f8f1b432010-03-16 19:06:031035
[email protected]ae8e80f2012-07-19 21:08:331036 BoundNetLog net_log_;
1037
[email protected]0f8f1b432010-03-16 19:06:031038 DISALLOW_COPY_AND_ASSIGN(IPv6ProbeJob);
1039};
1040
1041//-----------------------------------------------------------------------------
1042
[email protected]b3601bc22012-02-21 21:23:201043// Resolves the hostname using DnsTransaction.
1044// TODO(szym): This could be moved to separate source file as well.
1045class HostResolverImpl::DnsTask {
1046 public:
1047 typedef base::Callback<void(int net_error,
1048 const AddressList& addr_list,
1049 base::TimeDelta ttl)> Callback;
1050
1051 DnsTask(DnsTransactionFactory* factory,
1052 const Key& key,
1053 const Callback& callback,
1054 const BoundNetLog& job_net_log)
1055 : callback_(callback), net_log_(job_net_log) {
1056 DCHECK(factory);
1057 DCHECK(!callback.is_null());
1058
1059 // For now we treat ADDRESS_FAMILY_UNSPEC as if it was IPV4.
1060 uint16 qtype = (key.address_family == ADDRESS_FAMILY_IPV6)
1061 ? dns_protocol::kTypeAAAA
1062 : dns_protocol::kTypeA;
1063 // TODO(szym): Implement "happy eyeballs".
1064 transaction_ = factory->CreateTransaction(
1065 key.hostname,
1066 qtype,
[email protected]1def74c2012-03-22 20:07:001067 base::Bind(&DnsTask::OnTransactionComplete, base::Unretained(this),
1068 base::TimeTicks::Now()),
[email protected]b3601bc22012-02-21 21:23:201069 net_log_);
1070 DCHECK(transaction_.get());
1071 }
1072
1073 int Start() {
[email protected]4da911f2012-06-14 19:45:201074 net_log_.BeginEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_DNS_TASK);
[email protected]b3601bc22012-02-21 21:23:201075 return transaction_->Start();
1076 }
1077
[email protected]1def74c2012-03-22 20:07:001078 void OnTransactionComplete(const base::TimeTicks& start_time,
1079 DnsTransaction* transaction,
[email protected]b3601bc22012-02-21 21:23:201080 int net_error,
1081 const DnsResponse* response) {
[email protected]add76532012-03-30 14:47:471082 DCHECK(transaction);
[email protected]b3601bc22012-02-21 21:23:201083 // Run |callback_| last since the owning Job will then delete this DnsTask.
1084 DnsResponse::Result result = DnsResponse::DNS_SUCCESS;
1085 if (net_error == OK) {
[email protected]add76532012-03-30 14:47:471086 CHECK(response);
[email protected]1def74c2012-03-22 20:07:001087 DNS_HISTOGRAM("AsyncDNS.TransactionSuccess",
1088 base::TimeTicks::Now() - start_time);
[email protected]b3601bc22012-02-21 21:23:201089 AddressList addr_list;
1090 base::TimeDelta ttl;
1091 result = response->ParseToAddressList(&addr_list, &ttl);
[email protected]1def74c2012-03-22 20:07:001092 UMA_HISTOGRAM_ENUMERATION("AsyncDNS.ParseToAddressList",
1093 result,
1094 DnsResponse::DNS_PARSE_RESULT_MAX);
[email protected]b3601bc22012-02-21 21:23:201095 if (result == DnsResponse::DNS_SUCCESS) {
1096 net_log_.EndEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_DNS_TASK,
[email protected]cd565142012-06-12 16:21:451097 addr_list.CreateNetLogCallback());
[email protected]b3601bc22012-02-21 21:23:201098 callback_.Run(net_error, addr_list, ttl);
1099 return;
1100 }
1101 net_error = ERR_DNS_MALFORMED_RESPONSE;
[email protected]1def74c2012-03-22 20:07:001102 } else {
1103 DNS_HISTOGRAM("AsyncDNS.TransactionFailure",
1104 base::TimeTicks::Now() - start_time);
[email protected]b3601bc22012-02-21 21:23:201105 }
[email protected]cd565142012-06-12 16:21:451106 net_log_.EndEvent(
1107 NetLog::TYPE_HOST_RESOLVER_IMPL_DNS_TASK,
1108 base::Bind(&NetLogDnsTaskFailedCallback, net_error, result));
[email protected]b3601bc22012-02-21 21:23:201109 callback_.Run(net_error, AddressList(), base::TimeDelta());
1110 }
1111
1112 private:
1113 // The listener to the results of this DnsTask.
1114 Callback callback_;
1115
1116 const BoundNetLog net_log_;
1117
1118 scoped_ptr<DnsTransaction> transaction_;
1119};
1120
1121//-----------------------------------------------------------------------------
1122
[email protected]0f292de02012-02-01 22:28:201123// Aggregates all Requests for the same Key. Dispatched via PriorityDispatch.
[email protected]0f292de02012-02-01 22:28:201124class HostResolverImpl::Job : public PrioritizedDispatcher::Job {
[email protected]68ad3ee2010-01-30 03:45:391125 public:
[email protected]0f292de02012-02-01 22:28:201126 // Creates new job for |key| where |request_net_log| is bound to the
[email protected]16ee26d2012-03-08 03:34:351127 // request that spawned it.
[email protected]0f292de02012-02-01 22:28:201128 Job(HostResolverImpl* resolver,
1129 const Key& key,
[email protected]8c98d002012-07-18 19:02:271130 RequestPriority priority,
[email protected]16ee26d2012-03-08 03:34:351131 const BoundNetLog& request_net_log)
[email protected]0f292de02012-02-01 22:28:201132 : resolver_(resolver->AsWeakPtr()),
1133 key_(key),
[email protected]8c98d002012-07-18 19:02:271134 priority_tracker_(priority),
[email protected]0f292de02012-02-01 22:28:201135 had_non_speculative_request_(false),
[email protected]51b9a6b2012-06-25 21:50:291136 had_dns_config_(false),
[email protected]1d932852012-06-19 19:40:331137 dns_task_error_(OK),
[email protected]51b9a6b2012-06-25 21:50:291138 creation_time_(base::TimeTicks::Now()),
1139 priority_change_time_(creation_time_),
[email protected]0f292de02012-02-01 22:28:201140 net_log_(BoundNetLog::Make(request_net_log.net_log(),
[email protected]b3601bc22012-02-21 21:23:201141 NetLog::SOURCE_HOST_RESOLVER_IMPL_JOB)) {
[email protected]4da911f2012-06-14 19:45:201142 request_net_log.AddEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_CREATE_JOB);
[email protected]0f292de02012-02-01 22:28:201143
1144 net_log_.BeginEvent(
1145 NetLog::TYPE_HOST_RESOLVER_IMPL_JOB,
[email protected]cd565142012-06-12 16:21:451146 base::Bind(&NetLogJobCreationCallback,
1147 request_net_log.source(),
1148 &key_.hostname));
[email protected]68ad3ee2010-01-30 03:45:391149 }
1150
[email protected]0f292de02012-02-01 22:28:201151 virtual ~Job() {
[email protected]b3601bc22012-02-21 21:23:201152 if (is_running()) {
1153 // |resolver_| was destroyed with this Job still in flight.
1154 // Clean-up, record in the log, but don't run any callbacks.
1155 if (is_proc_running()) {
[email protected]0f292de02012-02-01 22:28:201156 proc_task_->Cancel();
1157 proc_task_ = NULL;
[email protected]0f292de02012-02-01 22:28:201158 }
[email protected]16ee26d2012-03-08 03:34:351159 // Clean up now for nice NetLog.
1160 dns_task_.reset(NULL);
[email protected]b3601bc22012-02-21 21:23:201161 net_log_.EndEventWithNetErrorCode(NetLog::TYPE_HOST_RESOLVER_IMPL_JOB,
1162 ERR_ABORTED);
1163 } else if (is_queued()) {
[email protected]57a48d32012-03-03 00:04:551164 // |resolver_| was destroyed without running this Job.
[email protected]16ee26d2012-03-08 03:34:351165 // TODO(szym): is there any benefit in having this distinction?
[email protected]4da911f2012-06-14 19:45:201166 net_log_.AddEvent(NetLog::TYPE_CANCELLED);
1167 net_log_.EndEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_JOB);
[email protected]68ad3ee2010-01-30 03:45:391168 }
[email protected]b3601bc22012-02-21 21:23:201169 // else CompleteRequests logged EndEvent.
[email protected]68ad3ee2010-01-30 03:45:391170
[email protected]b3601bc22012-02-21 21:23:201171 // Log any remaining Requests as cancelled.
1172 for (RequestsList::const_iterator it = requests_.begin();
1173 it != requests_.end(); ++it) {
1174 Request* req = *it;
1175 if (req->was_canceled())
1176 continue;
1177 DCHECK_EQ(this, req->job());
1178 LogCancelRequest(req->source_net_log(), req->request_net_log(),
1179 req->info());
1180 }
[email protected]68ad3ee2010-01-30 03:45:391181 }
1182
[email protected]16ee26d2012-03-08 03:34:351183 // Add this job to the dispatcher.
[email protected]8c98d002012-07-18 19:02:271184 void Schedule() {
1185 handle_ = resolver_->dispatcher_.Add(this, priority());
[email protected]16ee26d2012-03-08 03:34:351186 }
1187
[email protected]b3601bc22012-02-21 21:23:201188 void AddRequest(scoped_ptr<Request> req) {
[email protected]0f292de02012-02-01 22:28:201189 DCHECK_EQ(key_.hostname, req->info().hostname());
1190
1191 req->set_job(this);
[email protected]0f292de02012-02-01 22:28:201192 priority_tracker_.Add(req->info().priority());
1193
1194 req->request_net_log().AddEvent(
1195 NetLog::TYPE_HOST_RESOLVER_IMPL_JOB_ATTACH,
[email protected]cd565142012-06-12 16:21:451196 net_log_.source().ToEventParametersCallback());
[email protected]0f292de02012-02-01 22:28:201197
1198 net_log_.AddEvent(
1199 NetLog::TYPE_HOST_RESOLVER_IMPL_JOB_REQUEST_ATTACH,
[email protected]cd565142012-06-12 16:21:451200 base::Bind(&NetLogJobAttachCallback,
1201 req->request_net_log().source(),
1202 priority()));
[email protected]0f292de02012-02-01 22:28:201203
1204 // TODO(szym): Check if this is still needed.
1205 if (!req->info().is_speculative()) {
1206 had_non_speculative_request_ = true;
1207 if (proc_task_)
1208 proc_task_->set_had_non_speculative_request();
[email protected]68ad3ee2010-01-30 03:45:391209 }
[email protected]b3601bc22012-02-21 21:23:201210
1211 requests_.push_back(req.release());
1212
[email protected]51b9a6b2012-06-25 21:50:291213 UpdatePriority();
[email protected]68ad3ee2010-01-30 03:45:391214 }
1215
[email protected]16ee26d2012-03-08 03:34:351216 // Marks |req| as cancelled. If it was the last active Request, also finishes
1217 // this Job marking it either as aborted or cancelled, and deletes it.
[email protected]0f292de02012-02-01 22:28:201218 void CancelRequest(Request* req) {
1219 DCHECK_EQ(key_.hostname, req->info().hostname());
1220 DCHECK(!req->was_canceled());
[email protected]16ee26d2012-03-08 03:34:351221
[email protected]0f292de02012-02-01 22:28:201222 // Don't remove it from |requests_| just mark it canceled.
1223 req->MarkAsCanceled();
1224 LogCancelRequest(req->source_net_log(), req->request_net_log(),
1225 req->info());
[email protected]16ee26d2012-03-08 03:34:351226
[email protected]0f292de02012-02-01 22:28:201227 priority_tracker_.Remove(req->info().priority());
1228 net_log_.AddEvent(
1229 NetLog::TYPE_HOST_RESOLVER_IMPL_JOB_REQUEST_DETACH,
[email protected]cd565142012-06-12 16:21:451230 base::Bind(&NetLogJobAttachCallback,
1231 req->request_net_log().source(),
1232 priority()));
[email protected]b3601bc22012-02-21 21:23:201233
[email protected]16ee26d2012-03-08 03:34:351234 if (num_active_requests() > 0) {
[email protected]51b9a6b2012-06-25 21:50:291235 UpdatePriority();
[email protected]16ee26d2012-03-08 03:34:351236 } else {
1237 // If we were called from a Request's callback within CompleteRequests,
1238 // that Request could not have been cancelled, so num_active_requests()
1239 // could not be 0. Therefore, we are not in CompleteRequests().
1240 CompleteRequests(OK, AddressList(), base::TimeDelta());
[email protected]b3601bc22012-02-21 21:23:201241 }
[email protected]68ad3ee2010-01-30 03:45:391242 }
1243
[email protected]16ee26d2012-03-08 03:34:351244 // Called from AbortAllInProgressJobs. Completes all requests as aborted
1245 // and destroys the job.
[email protected]0f292de02012-02-01 22:28:201246 void Abort() {
[email protected]0f292de02012-02-01 22:28:201247 DCHECK(is_running());
[email protected]b3601bc22012-02-21 21:23:201248 CompleteRequests(ERR_ABORTED, AddressList(), base::TimeDelta());
1249 }
1250
[email protected]16ee26d2012-03-08 03:34:351251 // Called by HostResolverImpl when this job is evicted due to queue overflow.
1252 // Completes all requests and destroys the job.
1253 void OnEvicted() {
1254 DCHECK(!is_running());
1255 DCHECK(is_queued());
1256 handle_.Reset();
1257
[email protected]4da911f2012-06-14 19:45:201258 net_log_.AddEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_JOB_EVICTED);
[email protected]16ee26d2012-03-08 03:34:351259
1260 // This signals to CompleteRequests that this job never ran.
1261 CompleteRequests(ERR_HOST_RESOLVER_QUEUE_TOO_LARGE,
1262 AddressList(),
1263 base::TimeDelta());
1264 }
1265
[email protected]78eac2a2012-03-14 19:09:271266 // Attempts to serve the job from HOSTS. Returns true if succeeded and
1267 // this Job was destroyed.
1268 bool ServeFromHosts() {
1269 DCHECK_GT(num_active_requests(), 0u);
1270 AddressList addr_list;
1271 if (resolver_->ServeFromHosts(key(),
[email protected]3cb676a12012-06-30 15:46:031272 requests_.front()->info(),
[email protected]78eac2a2012-03-14 19:09:271273 &addr_list)) {
1274 // This will destroy the Job.
1275 CompleteRequests(OK, addr_list, base::TimeDelta());
1276 return true;
1277 }
1278 return false;
1279 }
1280
[email protected]b4481b222012-03-16 17:13:111281 const Key key() const {
1282 return key_;
1283 }
1284
1285 bool is_queued() const {
1286 return !handle_.is_null();
1287 }
1288
1289 bool is_running() const {
1290 return is_dns_running() || is_proc_running();
1291 }
1292
[email protected]16ee26d2012-03-08 03:34:351293 private:
[email protected]51b9a6b2012-06-25 21:50:291294 void UpdatePriority() {
1295 if (is_queued()) {
1296 if (priority() != static_cast<RequestPriority>(handle_.priority()))
1297 priority_change_time_ = base::TimeTicks::Now();
1298 handle_ = resolver_->dispatcher_.ChangePriority(handle_, priority());
1299 }
1300 }
1301
[email protected]16ee26d2012-03-08 03:34:351302 // PriorityDispatch::Job:
[email protected]0f292de02012-02-01 22:28:201303 virtual void Start() OVERRIDE {
1304 DCHECK(!is_running());
[email protected]b3601bc22012-02-21 21:23:201305 handle_.Reset();
[email protected]0f292de02012-02-01 22:28:201306
[email protected]4da911f2012-06-14 19:45:201307 net_log_.AddEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_JOB_STARTED);
[email protected]0f292de02012-02-01 22:28:201308
[email protected]51b9a6b2012-06-25 21:50:291309 had_dns_config_ = resolver_->HaveDnsConfig();
1310
1311 base::TimeTicks now = base::TimeTicks::Now();
1312 base::TimeDelta queue_time = now - creation_time_;
1313 base::TimeDelta queue_time_after_change = now - priority_change_time_;
1314
1315 if (had_dns_config_) {
1316 DNS_HISTOGRAM_BY_PRIORITY("AsyncDNS.JobQueueTime", priority(),
1317 queue_time);
1318 DNS_HISTOGRAM_BY_PRIORITY("AsyncDNS.JobQueueTimeAfterChange", priority(),
1319 queue_time_after_change);
1320 } else {
1321 DNS_HISTOGRAM_BY_PRIORITY("DNS.JobQueueTime", priority(), queue_time);
1322 DNS_HISTOGRAM_BY_PRIORITY("DNS.JobQueueTimeAfterChange", priority(),
1323 queue_time_after_change);
1324 }
1325
[email protected]1d932852012-06-19 19:40:331326 // Caution: Job::Start must not complete synchronously.
[email protected]51b9a6b2012-06-25 21:50:291327 if (had_dns_config_ && !ResemblesMulticastDNSName(key_.hostname)) {
[email protected]b3601bc22012-02-21 21:23:201328 StartDnsTask();
1329 } else {
1330 StartProcTask();
1331 }
1332 }
1333
[email protected]b3601bc22012-02-21 21:23:201334 // TODO(szym): Since DnsTransaction does not consume threads, we can increase
1335 // the limits on |dispatcher_|. But in order to keep the number of WorkerPool
1336 // threads low, we will need to use an "inner" PrioritizedDispatcher with
1337 // tighter limits.
1338 void StartProcTask() {
[email protected]16ee26d2012-03-08 03:34:351339 DCHECK(!is_dns_running());
[email protected]0f292de02012-02-01 22:28:201340 proc_task_ = new ProcTask(
1341 key_,
1342 resolver_->proc_params_,
1343 base::Bind(&Job::OnProcTaskComplete, base::Unretained(this)),
1344 net_log_);
1345
1346 if (had_non_speculative_request_)
1347 proc_task_->set_had_non_speculative_request();
1348 // Start() could be called from within Resolve(), hence it must NOT directly
1349 // call OnProcTaskComplete, for example, on synchronous failure.
1350 proc_task_->Start();
[email protected]68ad3ee2010-01-30 03:45:391351 }
1352
[email protected]0f292de02012-02-01 22:28:201353 // Called by ProcTask when it completes.
[email protected]b3601bc22012-02-21 21:23:201354 void OnProcTaskComplete(int net_error, const AddressList& addr_list) {
1355 DCHECK(is_proc_running());
[email protected]68ad3ee2010-01-30 03:45:391356
[email protected]1d932852012-06-19 19:40:331357 if (dns_task_error_ != OK) {
[email protected]1def74c2012-03-22 20:07:001358 if (net_error == OK) {
[email protected]1d932852012-06-19 19:40:331359 if ((dns_task_error_ == ERR_NAME_NOT_RESOLVED) &&
1360 ResemblesNetBIOSName(key_.hostname)) {
1361 UmaAsyncDnsResolveStatus(RESOLVE_STATUS_SUSPECT_NETBIOS);
1362 } else {
1363 UmaAsyncDnsResolveStatus(RESOLVE_STATUS_PROC_SUCCESS);
1364 }
1365 UMA_HISTOGRAM_CUSTOM_ENUMERATION("AsyncDNS.ResolveError",
1366 std::abs(dns_task_error_),
1367 GetAllErrorCodesForUma());
[email protected]1def74c2012-03-22 20:07:001368 } else {
1369 UmaAsyncDnsResolveStatus(RESOLVE_STATUS_FAIL);
1370 }
1371 }
1372
[email protected]b3601bc22012-02-21 21:23:201373 base::TimeDelta ttl = base::TimeDelta::FromSeconds(
1374 kNegativeCacheEntryTTLSeconds);
1375 if (net_error == OK)
1376 ttl = base::TimeDelta::FromSeconds(kCacheEntryTTLSeconds);
[email protected]68ad3ee2010-01-30 03:45:391377
[email protected]16ee26d2012-03-08 03:34:351378 CompleteRequests(net_error, addr_list, ttl);
[email protected]b3601bc22012-02-21 21:23:201379 }
1380
1381 void StartDnsTask() {
[email protected]78eac2a2012-03-14 19:09:271382 DCHECK(resolver_->HaveDnsConfig());
[email protected]b3601bc22012-02-21 21:23:201383 dns_task_.reset(new DnsTask(
[email protected]78eac2a2012-03-14 19:09:271384 resolver_->dns_client_->GetTransactionFactory(),
[email protected]b3601bc22012-02-21 21:23:201385 key_,
1386 base::Bind(&Job::OnDnsTaskComplete, base::Unretained(this)),
1387 net_log_));
1388
1389 int rv = dns_task_->Start();
1390 if (rv != ERR_IO_PENDING) {
1391 DCHECK_NE(OK, rv);
[email protected]51b9a6b2012-06-25 21:50:291392 dns_task_error_ = rv;
[email protected]b3601bc22012-02-21 21:23:201393 dns_task_.reset();
1394 StartProcTask();
1395 }
1396 }
1397
1398 // Called by DnsTask when it completes.
1399 void OnDnsTaskComplete(int net_error,
1400 const AddressList& addr_list,
1401 base::TimeDelta ttl) {
1402 DCHECK(is_dns_running());
[email protected]b3601bc22012-02-21 21:23:201403
1404 if (net_error != OK) {
[email protected]1d932852012-06-19 19:40:331405 dns_task_error_ = net_error;
[email protected]16ee26d2012-03-08 03:34:351406 dns_task_.reset();
[email protected]78eac2a2012-03-14 19:09:271407
1408 // TODO(szym): Run ServeFromHosts now if nsswitch.conf says so.
1409 // http://crbug.com/117655
1410
[email protected]b3601bc22012-02-21 21:23:201411 // TODO(szym): Some net errors indicate lack of connectivity. Starting
1412 // ProcTask in that case is a waste of time.
1413 StartProcTask();
1414 return;
1415 }
1416
[email protected]1def74c2012-03-22 20:07:001417 UmaAsyncDnsResolveStatus(RESOLVE_STATUS_DNS_SUCCESS);
[email protected]16ee26d2012-03-08 03:34:351418 CompleteRequests(net_error, addr_list, ttl);
[email protected]b3601bc22012-02-21 21:23:201419 }
1420
[email protected]16ee26d2012-03-08 03:34:351421 // Performs Job's last rites. Completes all Requests. Deletes this.
[email protected]b3601bc22012-02-21 21:23:201422 void CompleteRequests(int net_error,
1423 const AddressList& addr_list,
1424 base::TimeDelta ttl) {
1425 CHECK(resolver_);
[email protected]b3601bc22012-02-21 21:23:201426
[email protected]16ee26d2012-03-08 03:34:351427 // This job must be removed from resolver's |jobs_| now to make room for a
1428 // new job with the same key in case one of the OnComplete callbacks decides
1429 // to spawn one. Consequently, the job deletes itself when CompleteRequests
1430 // is done.
1431 scoped_ptr<Job> self_deleter(this);
1432
1433 resolver_->RemoveJob(this);
1434
1435 // |addr_list| will be destroyed once we destroy |proc_task_| and
1436 // |dns_task_|.
[email protected]b3601bc22012-02-21 21:23:201437 AddressList list = addr_list;
[email protected]16ee26d2012-03-08 03:34:351438
1439 if (is_running()) {
1440 DCHECK(!is_queued());
1441 if (is_proc_running()) {
1442 proc_task_->Cancel();
1443 proc_task_ = NULL;
1444 }
1445 dns_task_.reset();
1446
1447 // Signal dispatcher that a slot has opened.
1448 resolver_->dispatcher_.OnJobFinished();
1449 } else if (is_queued()) {
1450 resolver_->dispatcher_.Cancel(handle_);
1451 handle_.Reset();
1452 }
1453
1454 if (num_active_requests() == 0) {
[email protected]4da911f2012-06-14 19:45:201455 net_log_.AddEvent(NetLog::TYPE_CANCELLED);
[email protected]16ee26d2012-03-08 03:34:351456 net_log_.EndEventWithNetErrorCode(NetLog::TYPE_HOST_RESOLVER_IMPL_JOB,
1457 OK);
1458 return;
1459 }
[email protected]b3601bc22012-02-21 21:23:201460
1461 net_log_.EndEventWithNetErrorCode(NetLog::TYPE_HOST_RESOLVER_IMPL_JOB,
1462 net_error);
[email protected]68ad3ee2010-01-30 03:45:391463
[email protected]78eac2a2012-03-14 19:09:271464 DCHECK(!requests_.empty());
1465
[email protected]d7b9a2b2012-05-31 22:31:191466 if (net_error == OK) {
[email protected]3cb676a12012-06-30 15:46:031467 SetPortOnAddressList(requests_.front()->info().port(), &list);
[email protected]d7b9a2b2012-05-31 22:31:191468 // Record this histogram here, when we know the system has a valid DNS
1469 // configuration.
[email protected]539df6c2012-06-19 21:21:291470 UMA_HISTOGRAM_BOOLEAN("AsyncDNS.HaveDnsConfig",
1471 resolver_->received_dns_config_);
[email protected]d7b9a2b2012-05-31 22:31:191472 }
[email protected]16ee26d2012-03-08 03:34:351473
[email protected]51b9a6b2012-06-25 21:50:291474 bool did_complete = (net_error != ERR_ABORTED) &&
1475 (net_error != ERR_HOST_RESOLVER_QUEUE_TOO_LARGE);
1476 if (did_complete)
[email protected]16ee26d2012-03-08 03:34:351477 resolver_->CacheResult(key_, net_error, list, ttl);
[email protected]16ee26d2012-03-08 03:34:351478
[email protected]0f292de02012-02-01 22:28:201479 // Complete all of the requests that were attached to the job.
1480 for (RequestsList::const_iterator it = requests_.begin();
1481 it != requests_.end(); ++it) {
1482 Request* req = *it;
1483
1484 if (req->was_canceled())
1485 continue;
1486
1487 DCHECK_EQ(this, req->job());
1488 // Update the net log and notify registered observers.
1489 LogFinishRequest(req->source_net_log(), req->request_net_log(),
[email protected]b3601bc22012-02-21 21:23:201490 req->info(), net_error);
[email protected]51b9a6b2012-06-25 21:50:291491 if (did_complete) {
1492 // Record effective total time from creation to completion.
1493 RecordTotalTime(had_dns_config_, req->info().is_speculative(),
1494 base::TimeTicks::Now() - req->request_time());
1495 }
[email protected]b3601bc22012-02-21 21:23:201496 req->OnComplete(net_error, list);
[email protected]0f292de02012-02-01 22:28:201497
1498 // Check if the resolver was destroyed as a result of running the
1499 // callback. If it was, we could continue, but we choose to bail.
1500 if (!resolver_)
1501 return;
1502 }
1503 }
1504
[email protected]b4481b222012-03-16 17:13:111505 RequestPriority priority() const {
1506 return priority_tracker_.highest_priority();
1507 }
1508
1509 // Number of non-canceled requests in |requests_|.
1510 size_t num_active_requests() const {
1511 return priority_tracker_.total_count();
1512 }
1513
1514 bool is_dns_running() const {
1515 return dns_task_.get() != NULL;
1516 }
1517
1518 bool is_proc_running() const {
1519 return proc_task_.get() != NULL;
1520 }
1521
[email protected]0f292de02012-02-01 22:28:201522 base::WeakPtr<HostResolverImpl> resolver_;
1523
1524 Key key_;
1525
1526 // Tracks the highest priority across |requests_|.
1527 PriorityTracker priority_tracker_;
1528
1529 bool had_non_speculative_request_;
1530
[email protected]51b9a6b2012-06-25 21:50:291531 // Distinguishes measurements taken while DnsClient was fully configured.
1532 bool had_dns_config_;
1533
[email protected]1d932852012-06-19 19:40:331534 // Result of DnsTask.
1535 int dns_task_error_;
[email protected]1def74c2012-03-22 20:07:001536
[email protected]51b9a6b2012-06-25 21:50:291537 const base::TimeTicks creation_time_;
1538 base::TimeTicks priority_change_time_;
1539
[email protected]0f292de02012-02-01 22:28:201540 BoundNetLog net_log_;
1541
[email protected]b3601bc22012-02-21 21:23:201542 // Resolves the host using a HostResolverProc.
[email protected]0f292de02012-02-01 22:28:201543 scoped_refptr<ProcTask> proc_task_;
1544
[email protected]b3601bc22012-02-21 21:23:201545 // Resolves the host using a DnsTransaction.
1546 scoped_ptr<DnsTask> dns_task_;
1547
[email protected]0f292de02012-02-01 22:28:201548 // All Requests waiting for the result of this Job. Some can be canceled.
1549 RequestsList requests_;
1550
[email protected]16ee26d2012-03-08 03:34:351551 // A handle used in |HostResolverImpl::dispatcher_|.
[email protected]0f292de02012-02-01 22:28:201552 PrioritizedDispatcher::Handle handle_;
[email protected]68ad3ee2010-01-30 03:45:391553};
1554
1555//-----------------------------------------------------------------------------
1556
[email protected]0f292de02012-02-01 22:28:201557HostResolverImpl::ProcTaskParams::ProcTaskParams(
[email protected]e95d3aca2010-01-11 22:47:431558 HostResolverProc* resolver_proc,
[email protected]0f292de02012-02-01 22:28:201559 size_t max_retry_attempts)
1560 : resolver_proc(resolver_proc),
1561 max_retry_attempts(max_retry_attempts),
1562 unresponsive_delay(base::TimeDelta::FromMilliseconds(6000)),
1563 retry_factor(2) {
1564}
1565
1566HostResolverImpl::ProcTaskParams::~ProcTaskParams() {}
1567
1568HostResolverImpl::HostResolverImpl(
[email protected]e95d3aca2010-01-11 22:47:431569 HostCache* cache,
[email protected]0f292de02012-02-01 22:28:201570 const PrioritizedDispatcher::Limits& job_limits,
1571 const ProcTaskParams& proc_params,
[email protected]b3601bc22012-02-21 21:23:201572 scoped_ptr<DnsConfigService> dns_config_service,
[email protected]d7b9a2b2012-05-31 22:31:191573 scoped_ptr<DnsClient> dns_client,
[email protected]ee094b82010-08-24 15:55:511574 NetLog* net_log)
[email protected]112bd462009-12-10 07:23:401575 : cache_(cache),
[email protected]0f292de02012-02-01 22:28:201576 dispatcher_(job_limits),
1577 max_queued_jobs_(job_limits.total_jobs * 100u),
1578 proc_params_(proc_params),
[email protected]0c7798452009-10-26 17:59:511579 default_address_family_(ADDRESS_FAMILY_UNSPECIFIED),
[email protected]b3601bc22012-02-21 21:23:201580 dns_config_service_(dns_config_service.Pass()),
[email protected]d7b9a2b2012-05-31 22:31:191581 dns_client_(dns_client.Pass()),
1582 received_dns_config_(false),
[email protected]2f3bc65c2010-07-23 17:47:101583 ipv6_probe_monitoring_(false),
[email protected]ee094b82010-08-24 15:55:511584 additional_resolver_flags_(0),
1585 net_log_(net_log) {
[email protected]0f292de02012-02-01 22:28:201586
1587 DCHECK_GE(dispatcher_.num_priorities(), static_cast<size_t>(NUM_PRIORITIES));
[email protected]68ad3ee2010-01-30 03:45:391588
[email protected]06ef6d92011-05-19 04:24:581589 // Maximum of 4 retry attempts for host resolution.
1590 static const size_t kDefaultMaxRetryAttempts = 4u;
1591
[email protected]0f292de02012-02-01 22:28:201592 if (proc_params_.max_retry_attempts == HostResolver::kDefaultRetryAttempts)
1593 proc_params_.max_retry_attempts = kDefaultMaxRetryAttempts;
[email protected]68ad3ee2010-01-30 03:45:391594
[email protected]b59ff372009-07-15 22:04:321595#if defined(OS_WIN)
1596 EnsureWinsockInit();
1597#endif
[email protected]23f771162011-06-02 18:37:511598#if defined(OS_POSIX) && !defined(OS_MACOSX)
[email protected]2f3bc65c2010-07-23 17:47:101599 if (HaveOnlyLoopbackAddresses())
1600 additional_resolver_flags_ |= HOST_RESOLVER_LOOPBACK_ONLY;
1601#endif
[email protected]232a5812011-03-04 22:42:081602 NetworkChangeNotifier::AddIPAddressObserver(this);
[email protected]d7b9a2b2012-05-31 22:31:191603#if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_OPENBSD) && \
1604 !defined(OS_ANDROID)
[email protected]d7b9a2b2012-05-31 22:31:191605 EnsureDnsReloaderInit();
[email protected]46018c9d2011-09-06 03:42:341606#endif
[email protected]b3601bc22012-02-21 21:23:201607
[email protected]78eac2a2012-03-14 19:09:271608 if (dns_config_service_.get()) {
[email protected]b4481b222012-03-16 17:13:111609 dns_config_service_->Watch(
1610 base::Bind(&HostResolverImpl::OnDnsConfigChanged,
1611 base::Unretained(this)));
[email protected]78eac2a2012-03-14 19:09:271612 }
[email protected]b59ff372009-07-15 22:04:321613}
1614
1615HostResolverImpl::~HostResolverImpl() {
[email protected]0f8f1b432010-03-16 19:06:031616 DiscardIPv6ProbeJob();
1617
[email protected]0f292de02012-02-01 22:28:201618 // This will also cancel all outstanding requests.
1619 STLDeleteValues(&jobs_);
[email protected]e95d3aca2010-01-11 22:47:431620
[email protected]232a5812011-03-04 22:42:081621 NetworkChangeNotifier::RemoveIPAddressObserver(this);
[email protected]b59ff372009-07-15 22:04:321622}
1623
[email protected]0f292de02012-02-01 22:28:201624void HostResolverImpl::SetMaxQueuedJobs(size_t value) {
1625 DCHECK_EQ(0u, dispatcher_.num_queued_jobs());
1626 DCHECK_GT(value, 0u);
1627 max_queued_jobs_ = value;
[email protected]be1a48b2011-01-20 00:12:131628}
1629
[email protected]684970b2009-08-14 04:54:461630int HostResolverImpl::Resolve(const RequestInfo& info,
[email protected]b59ff372009-07-15 22:04:321631 AddressList* addresses,
[email protected]aa22b242011-11-16 18:58:291632 const CompletionCallback& callback,
[email protected]684970b2009-08-14 04:54:461633 RequestHandle* out_req,
[email protected]ee094b82010-08-24 15:55:511634 const BoundNetLog& source_net_log) {
[email protected]95a214c2011-08-04 21:50:401635 DCHECK(addresses);
[email protected]1ac6af92010-06-03 21:00:141636 DCHECK(CalledOnValidThread());
[email protected]aa22b242011-11-16 18:58:291637 DCHECK_EQ(false, callback.is_null());
[email protected]1ac6af92010-06-03 21:00:141638
[email protected]ee094b82010-08-24 15:55:511639 // Make a log item for the request.
1640 BoundNetLog request_net_log = BoundNetLog::Make(net_log_,
1641 NetLog::SOURCE_HOST_RESOLVER_IMPL_REQUEST);
1642
[email protected]0f292de02012-02-01 22:28:201643 LogStartRequest(source_net_log, request_net_log, info);
[email protected]b59ff372009-07-15 22:04:321644
[email protected]123ab1e32009-10-21 19:12:571645 // Build a key that identifies the request in the cache and in the
1646 // outstanding jobs map.
[email protected]137af622010-02-05 02:14:351647 Key key = GetEffectiveKeyForRequest(info);
[email protected]123ab1e32009-10-21 19:12:571648
[email protected]287d7c22011-11-15 17:34:251649 int rv = ResolveHelper(key, info, addresses, request_net_log);
[email protected]95a214c2011-08-04 21:50:401650 if (rv != ERR_DNS_CACHE_MISS) {
[email protected]b3601bc22012-02-21 21:23:201651 LogFinishRequest(source_net_log, request_net_log, info, rv);
[email protected]51b9a6b2012-06-25 21:50:291652 RecordTotalTime(HaveDnsConfig(), info.is_speculative(), base::TimeDelta());
[email protected]95a214c2011-08-04 21:50:401653 return rv;
[email protected]38368712011-03-02 08:09:401654 }
1655
[email protected]0f292de02012-02-01 22:28:201656 // Next we need to attach our request to a "job". This job is responsible for
1657 // calling "getaddrinfo(hostname)" on a worker thread.
1658
1659 JobMap::iterator jobit = jobs_.find(key);
1660 Job* job;
1661 if (jobit == jobs_.end()) {
1662 // Create new Job.
[email protected]8c98d002012-07-18 19:02:271663 job = new Job(this, key, info.priority(), request_net_log);
1664 job->Schedule();
[email protected]0f292de02012-02-01 22:28:201665
1666 // Check for queue overflow.
1667 if (dispatcher_.num_queued_jobs() > max_queued_jobs_) {
1668 Job* evicted = static_cast<Job*>(dispatcher_.EvictOldestLowest());
1669 DCHECK(evicted);
[email protected]16ee26d2012-03-08 03:34:351670 evicted->OnEvicted(); // Deletes |evicted|.
[email protected]0f292de02012-02-01 22:28:201671 if (evicted == job) {
[email protected]0f292de02012-02-01 22:28:201672 rv = ERR_HOST_RESOLVER_QUEUE_TOO_LARGE;
[email protected]b3601bc22012-02-21 21:23:201673 LogFinishRequest(source_net_log, request_net_log, info, rv);
[email protected]0f292de02012-02-01 22:28:201674 return rv;
1675 }
[email protected]0f292de02012-02-01 22:28:201676 }
[email protected]0f292de02012-02-01 22:28:201677 jobs_.insert(jobit, std::make_pair(key, job));
1678 } else {
1679 job = jobit->second;
1680 }
1681
1682 // Can't complete synchronously. Create and attach request.
[email protected]b3601bc22012-02-21 21:23:201683 scoped_ptr<Request> req(new Request(source_net_log,
1684 request_net_log,
1685 info,
1686 callback,
1687 addresses));
[email protected]b59ff372009-07-15 22:04:321688 if (out_req)
[email protected]b3601bc22012-02-21 21:23:201689 *out_req = reinterpret_cast<RequestHandle>(req.get());
[email protected]b59ff372009-07-15 22:04:321690
[email protected]b3601bc22012-02-21 21:23:201691 job->AddRequest(req.Pass());
[email protected]0f292de02012-02-01 22:28:201692 // Completion happens during Job::CompleteRequests().
[email protected]b59ff372009-07-15 22:04:321693 return ERR_IO_PENDING;
1694}
1695
[email protected]287d7c22011-11-15 17:34:251696int HostResolverImpl::ResolveHelper(const Key& key,
[email protected]95a214c2011-08-04 21:50:401697 const RequestInfo& info,
1698 AddressList* addresses,
[email protected]20cd5332011-10-12 22:38:001699 const BoundNetLog& request_net_log) {
[email protected]95a214c2011-08-04 21:50:401700 // The result of |getaddrinfo| for empty hosts is inconsistent across systems.
1701 // On Windows it gives the default interface's address, whereas on Linux it
1702 // gives an error. We will make it fail on all platforms for consistency.
1703 if (info.hostname().empty() || info.hostname().size() > kMaxHostLength)
1704 return ERR_NAME_NOT_RESOLVED;
1705
1706 int net_error = ERR_UNEXPECTED;
1707 if (ResolveAsIP(key, info, &net_error, addresses))
1708 return net_error;
[email protected]78eac2a2012-03-14 19:09:271709 if (ServeFromCache(key, info, &net_error, addresses)) {
[email protected]4da911f2012-06-14 19:45:201710 request_net_log.AddEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_CACHE_HIT);
[email protected]78eac2a2012-03-14 19:09:271711 return net_error;
1712 }
1713 // TODO(szym): Do not do this if nsswitch.conf instructs not to.
1714 // http://crbug.com/117655
1715 if (ServeFromHosts(key, info, addresses)) {
[email protected]4da911f2012-06-14 19:45:201716 request_net_log.AddEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_HOSTS_HIT);
[email protected]78eac2a2012-03-14 19:09:271717 return OK;
1718 }
1719 return ERR_DNS_CACHE_MISS;
[email protected]95a214c2011-08-04 21:50:401720}
1721
1722int HostResolverImpl::ResolveFromCache(const RequestInfo& info,
1723 AddressList* addresses,
1724 const BoundNetLog& source_net_log) {
1725 DCHECK(CalledOnValidThread());
1726 DCHECK(addresses);
1727
[email protected]95a214c2011-08-04 21:50:401728 // Make a log item for the request.
1729 BoundNetLog request_net_log = BoundNetLog::Make(net_log_,
1730 NetLog::SOURCE_HOST_RESOLVER_IMPL_REQUEST);
1731
1732 // Update the net log and notify registered observers.
[email protected]0f292de02012-02-01 22:28:201733 LogStartRequest(source_net_log, request_net_log, info);
[email protected]95a214c2011-08-04 21:50:401734
[email protected]95a214c2011-08-04 21:50:401735 Key key = GetEffectiveKeyForRequest(info);
1736
[email protected]287d7c22011-11-15 17:34:251737 int rv = ResolveHelper(key, info, addresses, request_net_log);
[email protected]b3601bc22012-02-21 21:23:201738 LogFinishRequest(source_net_log, request_net_log, info, rv);
[email protected]95a214c2011-08-04 21:50:401739 return rv;
1740}
1741
[email protected]b59ff372009-07-15 22:04:321742void HostResolverImpl::CancelRequest(RequestHandle req_handle) {
[email protected]1ac6af92010-06-03 21:00:141743 DCHECK(CalledOnValidThread());
[email protected]b59ff372009-07-15 22:04:321744 Request* req = reinterpret_cast<Request*>(req_handle);
1745 DCHECK(req);
[email protected]0f292de02012-02-01 22:28:201746 Job* job = req->job();
1747 DCHECK(job);
[email protected]0f292de02012-02-01 22:28:201748 job->CancelRequest(req);
[email protected]b59ff372009-07-15 22:04:321749}
1750
[email protected]0f8f1b432010-03-16 19:06:031751void HostResolverImpl::SetDefaultAddressFamily(AddressFamily address_family) {
[email protected]1ac6af92010-06-03 21:00:141752 DCHECK(CalledOnValidThread());
[email protected]0f8f1b432010-03-16 19:06:031753 ipv6_probe_monitoring_ = false;
1754 DiscardIPv6ProbeJob();
1755 default_address_family_ = address_family;
1756}
1757
[email protected]f7d310e2010-10-07 16:25:111758AddressFamily HostResolverImpl::GetDefaultAddressFamily() const {
1759 return default_address_family_;
1760}
1761
[email protected]a78f4272011-10-21 19:16:331762void HostResolverImpl::ProbeIPv6Support() {
1763 DCHECK(CalledOnValidThread());
1764 DCHECK(!ipv6_probe_monitoring_);
1765 ipv6_probe_monitoring_ = true;
1766 OnIPAddressChanged(); // Give initial setup call.
[email protected]ddb1e5a2010-12-13 20:10:451767}
1768
[email protected]489d1a82011-10-12 03:09:111769HostCache* HostResolverImpl::GetHostCache() {
1770 return cache_.get();
1771}
[email protected]95a214c2011-08-04 21:50:401772
[email protected]17e92032012-03-29 00:56:241773base::Value* HostResolverImpl::GetDnsConfigAsValue() const {
1774 // Check if async DNS is disabled.
1775 if (!dns_client_.get())
1776 return NULL;
1777
1778 // Check if async DNS is enabled, but we currently have no configuration
1779 // for it.
1780 const DnsConfig* dns_config = dns_client_->GetConfig();
1781 if (dns_config == NULL)
1782 return new DictionaryValue();
1783
1784 return dns_config->ToValue();
1785}
1786
[email protected]95a214c2011-08-04 21:50:401787bool HostResolverImpl::ResolveAsIP(const Key& key,
1788 const RequestInfo& info,
1789 int* net_error,
1790 AddressList* addresses) {
1791 DCHECK(addresses);
1792 DCHECK(net_error);
1793 IPAddressNumber ip_number;
1794 if (!ParseIPLiteralToNumber(key.hostname, &ip_number))
1795 return false;
1796
1797 DCHECK_EQ(key.host_resolver_flags &
1798 ~(HOST_RESOLVER_CANONNAME | HOST_RESOLVER_LOOPBACK_ONLY |
1799 HOST_RESOLVER_DEFAULT_FAMILY_SET_DUE_TO_NO_IPV6),
1800 0) << " Unhandled flag";
[email protected]0f292de02012-02-01 22:28:201801 bool ipv6_disabled = (default_address_family_ == ADDRESS_FAMILY_IPV4) &&
1802 !ipv6_probe_monitoring_;
[email protected]95a214c2011-08-04 21:50:401803 *net_error = OK;
[email protected]0f292de02012-02-01 22:28:201804 if ((ip_number.size() == kIPv6AddressSize) && ipv6_disabled) {
[email protected]95a214c2011-08-04 21:50:401805 *net_error = ERR_NAME_NOT_RESOLVED;
1806 } else {
[email protected]7054e78f2012-05-07 21:44:561807 *addresses = AddressList::CreateFromIPAddress(ip_number, info.port());
1808 if (key.host_resolver_flags & HOST_RESOLVER_CANONNAME)
1809 addresses->SetDefaultCanonicalName();
[email protected]95a214c2011-08-04 21:50:401810 }
1811 return true;
1812}
1813
1814bool HostResolverImpl::ServeFromCache(const Key& key,
1815 const RequestInfo& info,
[email protected]95a214c2011-08-04 21:50:401816 int* net_error,
1817 AddressList* addresses) {
1818 DCHECK(addresses);
1819 DCHECK(net_error);
1820 if (!info.allow_cached_response() || !cache_.get())
1821 return false;
1822
1823 const HostCache::Entry* cache_entry = cache_->Lookup(
1824 key, base::TimeTicks::Now());
1825 if (!cache_entry)
1826 return false;
1827
[email protected]95a214c2011-08-04 21:50:401828 *net_error = cache_entry->error;
[email protected]7054e78f2012-05-07 21:44:561829 if (*net_error == OK) {
1830 *addresses = cache_entry->addrlist;
1831 EnsurePortOnAddressList(info.port(), addresses);
1832 }
[email protected]95a214c2011-08-04 21:50:401833 return true;
1834}
1835
[email protected]78eac2a2012-03-14 19:09:271836bool HostResolverImpl::ServeFromHosts(const Key& key,
1837 const RequestInfo& info,
1838 AddressList* addresses) {
1839 DCHECK(addresses);
1840 if (!HaveDnsConfig())
1841 return false;
1842
[email protected]cb507622012-03-23 16:17:061843 // HOSTS lookups are case-insensitive.
1844 std::string hostname = StringToLowerASCII(key.hostname);
1845
[email protected]78eac2a2012-03-14 19:09:271846 // If |address_family| is ADDRESS_FAMILY_UNSPECIFIED other implementations
1847 // (glibc and c-ares) return the first matching line. We have more
1848 // flexibility, but lose implicit ordering.
1849 // TODO(szym) http://crbug.com/117850
1850 const DnsHosts& hosts = dns_client_->GetConfig()->hosts;
1851 DnsHosts::const_iterator it = hosts.find(
[email protected]cb507622012-03-23 16:17:061852 DnsHostsKey(hostname,
[email protected]78eac2a2012-03-14 19:09:271853 key.address_family == ADDRESS_FAMILY_UNSPECIFIED ?
1854 ADDRESS_FAMILY_IPV4 : key.address_family));
1855
1856 if (it == hosts.end()) {
1857 if (key.address_family != ADDRESS_FAMILY_UNSPECIFIED)
1858 return false;
1859
[email protected]cb507622012-03-23 16:17:061860 it = hosts.find(DnsHostsKey(hostname, ADDRESS_FAMILY_IPV6));
[email protected]78eac2a2012-03-14 19:09:271861 if (it == hosts.end())
1862 return false;
1863 }
1864
1865 *addresses = AddressList::CreateFromIPAddress(it->second, info.port());
1866 return true;
1867}
1868
[email protected]16ee26d2012-03-08 03:34:351869void HostResolverImpl::CacheResult(const Key& key,
1870 int net_error,
1871 const AddressList& addr_list,
1872 base::TimeDelta ttl) {
1873 if (cache_.get())
1874 cache_->Set(key, net_error, addr_list, base::TimeTicks::Now(), ttl);
[email protected]ef4c40c2010-09-01 14:42:031875}
1876
[email protected]0f292de02012-02-01 22:28:201877void HostResolverImpl::RemoveJob(Job* job) {
1878 DCHECK(job);
[email protected]16ee26d2012-03-08 03:34:351879 JobMap::iterator it = jobs_.find(job->key());
1880 if (it != jobs_.end() && it->second == job)
1881 jobs_.erase(it);
[email protected]b59ff372009-07-15 22:04:321882}
1883
[email protected]0f8f1b432010-03-16 19:06:031884void HostResolverImpl::DiscardIPv6ProbeJob() {
1885 if (ipv6_probe_job_.get()) {
1886 ipv6_probe_job_->Cancel();
1887 ipv6_probe_job_ = NULL;
1888 }
1889}
1890
1891void HostResolverImpl::IPv6ProbeSetDefaultAddressFamily(
1892 AddressFamily address_family) {
1893 DCHECK(address_family == ADDRESS_FAMILY_UNSPECIFIED ||
1894 address_family == ADDRESS_FAMILY_IPV4);
[email protected]f092e64b2010-03-17 00:39:181895 if (default_address_family_ != address_family) {
[email protected]b30a3f52010-10-16 01:05:461896 VLOG(1) << "IPv6Probe forced AddressFamily setting to "
1897 << ((address_family == ADDRESS_FAMILY_UNSPECIFIED) ?
1898 "ADDRESS_FAMILY_UNSPECIFIED" : "ADDRESS_FAMILY_IPV4");
[email protected]f092e64b2010-03-17 00:39:181899 }
[email protected]0f8f1b432010-03-16 19:06:031900 default_address_family_ = address_family;
1901 // Drop reference since the job has called us back.
1902 DiscardIPv6ProbeJob();
[email protected]e95d3aca2010-01-11 22:47:431903}
1904
[email protected]137af622010-02-05 02:14:351905HostResolverImpl::Key HostResolverImpl::GetEffectiveKeyForRequest(
1906 const RequestInfo& info) const {
[email protected]eaf3a3b2010-09-03 20:34:271907 HostResolverFlags effective_flags =
1908 info.host_resolver_flags() | additional_resolver_flags_;
[email protected]137af622010-02-05 02:14:351909 AddressFamily effective_address_family = info.address_family();
[email protected]eaf3a3b2010-09-03 20:34:271910 if (effective_address_family == ADDRESS_FAMILY_UNSPECIFIED &&
1911 default_address_family_ != ADDRESS_FAMILY_UNSPECIFIED) {
[email protected]137af622010-02-05 02:14:351912 effective_address_family = default_address_family_;
[email protected]eaf3a3b2010-09-03 20:34:271913 if (ipv6_probe_monitoring_)
1914 effective_flags |= HOST_RESOLVER_DEFAULT_FAMILY_SET_DUE_TO_NO_IPV6;
1915 }
1916 return Key(info.hostname(), effective_address_family, effective_flags);
[email protected]137af622010-02-05 02:14:351917}
1918
[email protected]35ddc282010-09-21 23:42:061919void HostResolverImpl::AbortAllInProgressJobs() {
[email protected]b3601bc22012-02-21 21:23:201920 // In Abort, a Request callback could spawn new Jobs with matching keys, so
1921 // first collect and remove all running jobs from |jobs_|.
[email protected]c143d892012-04-06 07:56:541922 ScopedVector<Job> jobs_to_abort;
[email protected]0f292de02012-02-01 22:28:201923 for (JobMap::iterator it = jobs_.begin(); it != jobs_.end(); ) {
1924 Job* job = it->second;
[email protected]0f292de02012-02-01 22:28:201925 if (job->is_running()) {
[email protected]b3601bc22012-02-21 21:23:201926 jobs_to_abort.push_back(job);
1927 jobs_.erase(it++);
[email protected]0f292de02012-02-01 22:28:201928 } else {
[email protected]b3601bc22012-02-21 21:23:201929 DCHECK(job->is_queued());
1930 ++it;
[email protected]0f292de02012-02-01 22:28:201931 }
[email protected]ef4c40c2010-09-01 14:42:031932 }
[email protected]b3601bc22012-02-21 21:23:201933
[email protected]57a48d32012-03-03 00:04:551934 // Check if no dispatcher slots leaked out.
1935 DCHECK_EQ(dispatcher_.num_running_jobs(), jobs_to_abort.size());
1936
1937 // Life check to bail once |this| is deleted.
1938 base::WeakPtr<HostResolverImpl> self = AsWeakPtr();
1939
[email protected]16ee26d2012-03-08 03:34:351940 // Then Abort them.
[email protected]57a48d32012-03-03 00:04:551941 for (size_t i = 0; self && i < jobs_to_abort.size(); ++i) {
[email protected]57a48d32012-03-03 00:04:551942 jobs_to_abort[i]->Abort();
[email protected]c143d892012-04-06 07:56:541943 jobs_to_abort[i] = NULL;
[email protected]b3601bc22012-02-21 21:23:201944 }
[email protected]ef4c40c2010-09-01 14:42:031945}
1946
[email protected]78eac2a2012-03-14 19:09:271947void HostResolverImpl::TryServingAllJobsFromHosts() {
1948 if (!HaveDnsConfig())
1949 return;
1950
1951 // TODO(szym): Do not do this if nsswitch.conf instructs not to.
1952 // http://crbug.com/117655
1953
1954 // Life check to bail once |this| is deleted.
1955 base::WeakPtr<HostResolverImpl> self = AsWeakPtr();
1956
1957 for (JobMap::iterator it = jobs_.begin(); self && it != jobs_.end(); ) {
1958 Job* job = it->second;
1959 ++it;
1960 // This could remove |job| from |jobs_|, but iterator will remain valid.
1961 job->ServeFromHosts();
1962 }
1963}
1964
[email protected]be1a48b2011-01-20 00:12:131965void HostResolverImpl::OnIPAddressChanged() {
1966 if (cache_.get())
1967 cache_->clear();
1968 if (ipv6_probe_monitoring_) {
[email protected]be1a48b2011-01-20 00:12:131969 DiscardIPv6ProbeJob();
[email protected]ae8e80f2012-07-19 21:08:331970 ipv6_probe_job_ = new IPv6ProbeJob(this, net_log_);
[email protected]be1a48b2011-01-20 00:12:131971 ipv6_probe_job_->Start();
1972 }
[email protected]23f771162011-06-02 18:37:511973#if defined(OS_POSIX) && !defined(OS_MACOSX)
[email protected]be1a48b2011-01-20 00:12:131974 if (HaveOnlyLoopbackAddresses()) {
1975 additional_resolver_flags_ |= HOST_RESOLVER_LOOPBACK_ONLY;
1976 } else {
1977 additional_resolver_flags_ &= ~HOST_RESOLVER_LOOPBACK_ONLY;
1978 }
1979#endif
1980 AbortAllInProgressJobs();
1981 // |this| may be deleted inside AbortAllInProgressJobs().
1982}
1983
[email protected]b4481b222012-03-16 17:13:111984void HostResolverImpl::OnDnsConfigChanged(const DnsConfig& dns_config) {
1985 if (net_log_) {
1986 net_log_->AddGlobalEntry(
1987 NetLog::TYPE_DNS_CONFIG_CHANGED,
[email protected]cd565142012-06-12 16:21:451988 base::Bind(&NetLogDnsConfigCallback, &dns_config));
[email protected]b4481b222012-03-16 17:13:111989 }
1990
[email protected]01b3b9d2012-08-13 16:18:141991 // TODO(szym): Remove once http://crbug.com/137914 is resolved.
[email protected]d7b9a2b2012-05-31 22:31:191992 received_dns_config_ = dns_config.IsValid();
[email protected]78eac2a2012-03-14 19:09:271993
1994 // Life check to bail once |this| is deleted.
1995 base::WeakPtr<HostResolverImpl> self = AsWeakPtr();
1996
[email protected]01b3b9d2012-08-13 16:18:141997 // We want a new DnsSession in place, before we Abort running Jobs, so that
1998 // the newly started jobs use the new config.
1999 if (dns_client_.get())
[email protected]d7b9a2b2012-05-31 22:31:192000 dns_client_->SetConfig(dns_config);
[email protected]01b3b9d2012-08-13 16:18:142001
2002 // If the DNS server has changed, existing cached info could be wrong so we
2003 // have to drop our internal cache :( Note that OS level DNS caches, such
2004 // as NSCD's cache should be dropped automatically by the OS when
2005 // resolv.conf changes so we don't need to do anything to clear that cache.
2006 if (cache_.get())
2007 cache_->clear();
2008
2009 // Existing jobs will have been sent to the original server so they need to
2010 // be aborted.
2011 AbortAllInProgressJobs();
2012
2013 // |this| may be deleted inside AbortAllInProgressJobs().
2014 if (self)
2015 TryServingAllJobsFromHosts();
[email protected]78eac2a2012-03-14 19:09:272016}
2017
2018bool HostResolverImpl::HaveDnsConfig() const {
2019 return (dns_client_.get() != NULL) && (dns_client_->GetConfig() != NULL);
[email protected]b3601bc22012-02-21 21:23:202020}
2021
[email protected]b59ff372009-07-15 22:04:322022} // namespace net