blob: b77140a60c8941170fd55520f74867f0c75a80ff [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]16ee26d2012-03-08 03:34:35365 PriorityTracker()
366 : highest_priority_(IDLE), 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:
964 explicit IPv6ProbeJob(HostResolverImpl* resolver)
965 : resolver_(resolver),
[email protected]edd685f2011-08-15 20:33:46966 origin_loop_(base::MessageLoopProxy::current()) {
[email protected]3e9d9cc2011-05-03 21:08:15967 DCHECK(resolver);
[email protected]0f8f1b432010-03-16 19:06:03968 }
969
970 void Start() {
[email protected]3e9d9cc2011-05-03 21:08:15971 DCHECK(origin_loop_->BelongsToCurrentThread());
[email protected]0f292de02012-02-01 22:28:20972 if (was_canceled())
[email protected]a9af7112010-05-08 00:56:01973 return;
[email protected]f092e64b2010-03-17 00:39:18974 const bool kIsSlow = true;
[email protected]ac9ba8fe2010-12-30 18:08:36975 base::WorkerPool::PostTask(
[email protected]33152acc2011-10-20 23:37:12976 FROM_HERE, base::Bind(&IPv6ProbeJob::DoProbe, this), kIsSlow);
[email protected]0f8f1b432010-03-16 19:06:03977 }
978
979 // Cancels the current job.
980 void Cancel() {
[email protected]3e9d9cc2011-05-03 21:08:15981 DCHECK(origin_loop_->BelongsToCurrentThread());
[email protected]0f292de02012-02-01 22:28:20982 if (was_canceled())
[email protected]a9af7112010-05-08 00:56:01983 return;
[email protected]0f8f1b432010-03-16 19:06:03984 resolver_ = NULL; // Read/write ONLY on origin thread.
[email protected]0f8f1b432010-03-16 19:06:03985 }
986
[email protected]0f8f1b432010-03-16 19:06:03987 private:
988 friend class base::RefCountedThreadSafe<HostResolverImpl::IPv6ProbeJob>;
989
990 ~IPv6ProbeJob() {
991 }
992
[email protected]0f292de02012-02-01 22:28:20993 bool was_canceled() const {
[email protected]3e9d9cc2011-05-03 21:08:15994 DCHECK(origin_loop_->BelongsToCurrentThread());
995 return !resolver_;
[email protected]a9af7112010-05-08 00:56:01996 }
997
[email protected]0f8f1b432010-03-16 19:06:03998 // Run on worker thread.
999 void DoProbe() {
1000 // Do actual testing on this thread, as it takes 40-100ms.
1001 AddressFamily family = IPv6Supported() ? ADDRESS_FAMILY_UNSPECIFIED
1002 : ADDRESS_FAMILY_IPV4;
1003
[email protected]3e9d9cc2011-05-03 21:08:151004 origin_loop_->PostTask(
1005 FROM_HERE,
[email protected]33152acc2011-10-20 23:37:121006 base::Bind(&IPv6ProbeJob::OnProbeComplete, this, family));
[email protected]0f8f1b432010-03-16 19:06:031007 }
1008
[email protected]3e9d9cc2011-05-03 21:08:151009 // Callback for when DoProbe() completes.
[email protected]0f8f1b432010-03-16 19:06:031010 void OnProbeComplete(AddressFamily address_family) {
[email protected]3e9d9cc2011-05-03 21:08:151011 DCHECK(origin_loop_->BelongsToCurrentThread());
[email protected]0f292de02012-02-01 22:28:201012 if (was_canceled())
[email protected]a9af7112010-05-08 00:56:011013 return;
[email protected]a9af7112010-05-08 00:56:011014 resolver_->IPv6ProbeSetDefaultAddressFamily(address_family);
[email protected]0f8f1b432010-03-16 19:06:031015 }
1016
[email protected]0f8f1b432010-03-16 19:06:031017 // Used/set only on origin thread.
1018 HostResolverImpl* resolver_;
1019
1020 // Used to post ourselves onto the origin thread.
[email protected]3e9d9cc2011-05-03 21:08:151021 scoped_refptr<base::MessageLoopProxy> origin_loop_;
[email protected]0f8f1b432010-03-16 19:06:031022
1023 DISALLOW_COPY_AND_ASSIGN(IPv6ProbeJob);
1024};
1025
1026//-----------------------------------------------------------------------------
1027
[email protected]b3601bc22012-02-21 21:23:201028// Resolves the hostname using DnsTransaction.
1029// TODO(szym): This could be moved to separate source file as well.
1030class HostResolverImpl::DnsTask {
1031 public:
1032 typedef base::Callback<void(int net_error,
1033 const AddressList& addr_list,
1034 base::TimeDelta ttl)> Callback;
1035
1036 DnsTask(DnsTransactionFactory* factory,
1037 const Key& key,
1038 const Callback& callback,
1039 const BoundNetLog& job_net_log)
1040 : callback_(callback), net_log_(job_net_log) {
1041 DCHECK(factory);
1042 DCHECK(!callback.is_null());
1043
1044 // For now we treat ADDRESS_FAMILY_UNSPEC as if it was IPV4.
1045 uint16 qtype = (key.address_family == ADDRESS_FAMILY_IPV6)
1046 ? dns_protocol::kTypeAAAA
1047 : dns_protocol::kTypeA;
1048 // TODO(szym): Implement "happy eyeballs".
1049 transaction_ = factory->CreateTransaction(
1050 key.hostname,
1051 qtype,
[email protected]1def74c2012-03-22 20:07:001052 base::Bind(&DnsTask::OnTransactionComplete, base::Unretained(this),
1053 base::TimeTicks::Now()),
[email protected]b3601bc22012-02-21 21:23:201054 net_log_);
1055 DCHECK(transaction_.get());
1056 }
1057
1058 int Start() {
[email protected]4da911f2012-06-14 19:45:201059 net_log_.BeginEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_DNS_TASK);
[email protected]b3601bc22012-02-21 21:23:201060 return transaction_->Start();
1061 }
1062
[email protected]1def74c2012-03-22 20:07:001063 void OnTransactionComplete(const base::TimeTicks& start_time,
1064 DnsTransaction* transaction,
[email protected]b3601bc22012-02-21 21:23:201065 int net_error,
1066 const DnsResponse* response) {
[email protected]add76532012-03-30 14:47:471067 DCHECK(transaction);
[email protected]b3601bc22012-02-21 21:23:201068 // Run |callback_| last since the owning Job will then delete this DnsTask.
1069 DnsResponse::Result result = DnsResponse::DNS_SUCCESS;
1070 if (net_error == OK) {
[email protected]add76532012-03-30 14:47:471071 CHECK(response);
[email protected]1def74c2012-03-22 20:07:001072 DNS_HISTOGRAM("AsyncDNS.TransactionSuccess",
1073 base::TimeTicks::Now() - start_time);
[email protected]b3601bc22012-02-21 21:23:201074 AddressList addr_list;
1075 base::TimeDelta ttl;
1076 result = response->ParseToAddressList(&addr_list, &ttl);
[email protected]1def74c2012-03-22 20:07:001077 UMA_HISTOGRAM_ENUMERATION("AsyncDNS.ParseToAddressList",
1078 result,
1079 DnsResponse::DNS_PARSE_RESULT_MAX);
[email protected]b3601bc22012-02-21 21:23:201080 if (result == DnsResponse::DNS_SUCCESS) {
1081 net_log_.EndEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_DNS_TASK,
[email protected]cd565142012-06-12 16:21:451082 addr_list.CreateNetLogCallback());
[email protected]b3601bc22012-02-21 21:23:201083 callback_.Run(net_error, addr_list, ttl);
1084 return;
1085 }
1086 net_error = ERR_DNS_MALFORMED_RESPONSE;
[email protected]1def74c2012-03-22 20:07:001087 } else {
1088 DNS_HISTOGRAM("AsyncDNS.TransactionFailure",
1089 base::TimeTicks::Now() - start_time);
[email protected]b3601bc22012-02-21 21:23:201090 }
[email protected]cd565142012-06-12 16:21:451091 net_log_.EndEvent(
1092 NetLog::TYPE_HOST_RESOLVER_IMPL_DNS_TASK,
1093 base::Bind(&NetLogDnsTaskFailedCallback, net_error, result));
[email protected]b3601bc22012-02-21 21:23:201094 callback_.Run(net_error, AddressList(), base::TimeDelta());
1095 }
1096
1097 private:
1098 // The listener to the results of this DnsTask.
1099 Callback callback_;
1100
1101 const BoundNetLog net_log_;
1102
1103 scoped_ptr<DnsTransaction> transaction_;
1104};
1105
1106//-----------------------------------------------------------------------------
1107
[email protected]0f292de02012-02-01 22:28:201108// Aggregates all Requests for the same Key. Dispatched via PriorityDispatch.
[email protected]0f292de02012-02-01 22:28:201109class HostResolverImpl::Job : public PrioritizedDispatcher::Job {
[email protected]68ad3ee2010-01-30 03:45:391110 public:
[email protected]0f292de02012-02-01 22:28:201111 // Creates new job for |key| where |request_net_log| is bound to the
[email protected]16ee26d2012-03-08 03:34:351112 // request that spawned it.
[email protected]0f292de02012-02-01 22:28:201113 Job(HostResolverImpl* resolver,
1114 const Key& key,
[email protected]16ee26d2012-03-08 03:34:351115 const BoundNetLog& request_net_log)
[email protected]0f292de02012-02-01 22:28:201116 : resolver_(resolver->AsWeakPtr()),
1117 key_(key),
1118 had_non_speculative_request_(false),
[email protected]51b9a6b2012-06-25 21:50:291119 had_dns_config_(false),
[email protected]1d932852012-06-19 19:40:331120 dns_task_error_(OK),
[email protected]51b9a6b2012-06-25 21:50:291121 creation_time_(base::TimeTicks::Now()),
1122 priority_change_time_(creation_time_),
[email protected]0f292de02012-02-01 22:28:201123 net_log_(BoundNetLog::Make(request_net_log.net_log(),
[email protected]b3601bc22012-02-21 21:23:201124 NetLog::SOURCE_HOST_RESOLVER_IMPL_JOB)) {
[email protected]4da911f2012-06-14 19:45:201125 request_net_log.AddEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_CREATE_JOB);
[email protected]0f292de02012-02-01 22:28:201126
1127 net_log_.BeginEvent(
1128 NetLog::TYPE_HOST_RESOLVER_IMPL_JOB,
[email protected]cd565142012-06-12 16:21:451129 base::Bind(&NetLogJobCreationCallback,
1130 request_net_log.source(),
1131 &key_.hostname));
[email protected]68ad3ee2010-01-30 03:45:391132 }
1133
[email protected]0f292de02012-02-01 22:28:201134 virtual ~Job() {
[email protected]b3601bc22012-02-21 21:23:201135 if (is_running()) {
1136 // |resolver_| was destroyed with this Job still in flight.
1137 // Clean-up, record in the log, but don't run any callbacks.
1138 if (is_proc_running()) {
[email protected]0f292de02012-02-01 22:28:201139 proc_task_->Cancel();
1140 proc_task_ = NULL;
[email protected]0f292de02012-02-01 22:28:201141 }
[email protected]16ee26d2012-03-08 03:34:351142 // Clean up now for nice NetLog.
1143 dns_task_.reset(NULL);
[email protected]b3601bc22012-02-21 21:23:201144 net_log_.EndEventWithNetErrorCode(NetLog::TYPE_HOST_RESOLVER_IMPL_JOB,
1145 ERR_ABORTED);
1146 } else if (is_queued()) {
[email protected]57a48d32012-03-03 00:04:551147 // |resolver_| was destroyed without running this Job.
[email protected]16ee26d2012-03-08 03:34:351148 // TODO(szym): is there any benefit in having this distinction?
[email protected]4da911f2012-06-14 19:45:201149 net_log_.AddEvent(NetLog::TYPE_CANCELLED);
1150 net_log_.EndEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_JOB);
[email protected]68ad3ee2010-01-30 03:45:391151 }
[email protected]b3601bc22012-02-21 21:23:201152 // else CompleteRequests logged EndEvent.
[email protected]68ad3ee2010-01-30 03:45:391153
[email protected]b3601bc22012-02-21 21:23:201154 // Log any remaining Requests as cancelled.
1155 for (RequestsList::const_iterator it = requests_.begin();
1156 it != requests_.end(); ++it) {
1157 Request* req = *it;
1158 if (req->was_canceled())
1159 continue;
1160 DCHECK_EQ(this, req->job());
1161 LogCancelRequest(req->source_net_log(), req->request_net_log(),
1162 req->info());
1163 }
[email protected]68ad3ee2010-01-30 03:45:391164 }
1165
[email protected]16ee26d2012-03-08 03:34:351166 // Add this job to the dispatcher.
1167 void Schedule(RequestPriority priority) {
1168 handle_ = resolver_->dispatcher_.Add(this, priority);
1169 }
1170
[email protected]b3601bc22012-02-21 21:23:201171 void AddRequest(scoped_ptr<Request> req) {
[email protected]0f292de02012-02-01 22:28:201172 DCHECK_EQ(key_.hostname, req->info().hostname());
1173
1174 req->set_job(this);
[email protected]0f292de02012-02-01 22:28:201175 priority_tracker_.Add(req->info().priority());
1176
1177 req->request_net_log().AddEvent(
1178 NetLog::TYPE_HOST_RESOLVER_IMPL_JOB_ATTACH,
[email protected]cd565142012-06-12 16:21:451179 net_log_.source().ToEventParametersCallback());
[email protected]0f292de02012-02-01 22:28:201180
1181 net_log_.AddEvent(
1182 NetLog::TYPE_HOST_RESOLVER_IMPL_JOB_REQUEST_ATTACH,
[email protected]cd565142012-06-12 16:21:451183 base::Bind(&NetLogJobAttachCallback,
1184 req->request_net_log().source(),
1185 priority()));
[email protected]0f292de02012-02-01 22:28:201186
1187 // TODO(szym): Check if this is still needed.
1188 if (!req->info().is_speculative()) {
1189 had_non_speculative_request_ = true;
1190 if (proc_task_)
1191 proc_task_->set_had_non_speculative_request();
[email protected]68ad3ee2010-01-30 03:45:391192 }
[email protected]b3601bc22012-02-21 21:23:201193
1194 requests_.push_back(req.release());
1195
[email protected]51b9a6b2012-06-25 21:50:291196 UpdatePriority();
[email protected]68ad3ee2010-01-30 03:45:391197 }
1198
[email protected]16ee26d2012-03-08 03:34:351199 // Marks |req| as cancelled. If it was the last active Request, also finishes
1200 // this Job marking it either as aborted or cancelled, and deletes it.
[email protected]0f292de02012-02-01 22:28:201201 void CancelRequest(Request* req) {
1202 DCHECK_EQ(key_.hostname, req->info().hostname());
1203 DCHECK(!req->was_canceled());
[email protected]16ee26d2012-03-08 03:34:351204
[email protected]0f292de02012-02-01 22:28:201205 // Don't remove it from |requests_| just mark it canceled.
1206 req->MarkAsCanceled();
1207 LogCancelRequest(req->source_net_log(), req->request_net_log(),
1208 req->info());
[email protected]16ee26d2012-03-08 03:34:351209
[email protected]0f292de02012-02-01 22:28:201210 priority_tracker_.Remove(req->info().priority());
1211 net_log_.AddEvent(
1212 NetLog::TYPE_HOST_RESOLVER_IMPL_JOB_REQUEST_DETACH,
[email protected]cd565142012-06-12 16:21:451213 base::Bind(&NetLogJobAttachCallback,
1214 req->request_net_log().source(),
1215 priority()));
[email protected]b3601bc22012-02-21 21:23:201216
[email protected]16ee26d2012-03-08 03:34:351217 if (num_active_requests() > 0) {
[email protected]51b9a6b2012-06-25 21:50:291218 UpdatePriority();
[email protected]16ee26d2012-03-08 03:34:351219 } else {
1220 // If we were called from a Request's callback within CompleteRequests,
1221 // that Request could not have been cancelled, so num_active_requests()
1222 // could not be 0. Therefore, we are not in CompleteRequests().
1223 CompleteRequests(OK, AddressList(), base::TimeDelta());
[email protected]b3601bc22012-02-21 21:23:201224 }
[email protected]68ad3ee2010-01-30 03:45:391225 }
1226
[email protected]16ee26d2012-03-08 03:34:351227 // Called from AbortAllInProgressJobs. Completes all requests as aborted
1228 // and destroys the job.
[email protected]0f292de02012-02-01 22:28:201229 void Abort() {
[email protected]0f292de02012-02-01 22:28:201230 DCHECK(is_running());
[email protected]b3601bc22012-02-21 21:23:201231 CompleteRequests(ERR_ABORTED, AddressList(), base::TimeDelta());
1232 }
1233
[email protected]16ee26d2012-03-08 03:34:351234 // Called by HostResolverImpl when this job is evicted due to queue overflow.
1235 // Completes all requests and destroys the job.
1236 void OnEvicted() {
1237 DCHECK(!is_running());
1238 DCHECK(is_queued());
1239 handle_.Reset();
1240
[email protected]4da911f2012-06-14 19:45:201241 net_log_.AddEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_JOB_EVICTED);
[email protected]16ee26d2012-03-08 03:34:351242
1243 // This signals to CompleteRequests that this job never ran.
1244 CompleteRequests(ERR_HOST_RESOLVER_QUEUE_TOO_LARGE,
1245 AddressList(),
1246 base::TimeDelta());
1247 }
1248
[email protected]78eac2a2012-03-14 19:09:271249 // Attempts to serve the job from HOSTS. Returns true if succeeded and
1250 // this Job was destroyed.
1251 bool ServeFromHosts() {
1252 DCHECK_GT(num_active_requests(), 0u);
1253 AddressList addr_list;
1254 if (resolver_->ServeFromHosts(key(),
[email protected]c143d892012-04-06 07:56:541255 requests_->front()->info(),
[email protected]78eac2a2012-03-14 19:09:271256 &addr_list)) {
1257 // This will destroy the Job.
1258 CompleteRequests(OK, addr_list, base::TimeDelta());
1259 return true;
1260 }
1261 return false;
1262 }
1263
[email protected]b4481b222012-03-16 17:13:111264 const Key key() const {
1265 return key_;
1266 }
1267
1268 bool is_queued() const {
1269 return !handle_.is_null();
1270 }
1271
1272 bool is_running() const {
1273 return is_dns_running() || is_proc_running();
1274 }
1275
[email protected]16ee26d2012-03-08 03:34:351276 private:
[email protected]51b9a6b2012-06-25 21:50:291277 void UpdatePriority() {
1278 if (is_queued()) {
1279 if (priority() != static_cast<RequestPriority>(handle_.priority()))
1280 priority_change_time_ = base::TimeTicks::Now();
1281 handle_ = resolver_->dispatcher_.ChangePriority(handle_, priority());
1282 }
1283 }
1284
[email protected]16ee26d2012-03-08 03:34:351285 // PriorityDispatch::Job:
[email protected]0f292de02012-02-01 22:28:201286 virtual void Start() OVERRIDE {
1287 DCHECK(!is_running());
[email protected]b3601bc22012-02-21 21:23:201288 handle_.Reset();
[email protected]0f292de02012-02-01 22:28:201289
[email protected]4da911f2012-06-14 19:45:201290 net_log_.AddEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_JOB_STARTED);
[email protected]0f292de02012-02-01 22:28:201291
[email protected]51b9a6b2012-06-25 21:50:291292 had_dns_config_ = resolver_->HaveDnsConfig();
1293
1294 base::TimeTicks now = base::TimeTicks::Now();
1295 base::TimeDelta queue_time = now - creation_time_;
1296 base::TimeDelta queue_time_after_change = now - priority_change_time_;
1297
1298 if (had_dns_config_) {
1299 DNS_HISTOGRAM_BY_PRIORITY("AsyncDNS.JobQueueTime", priority(),
1300 queue_time);
1301 DNS_HISTOGRAM_BY_PRIORITY("AsyncDNS.JobQueueTimeAfterChange", priority(),
1302 queue_time_after_change);
1303 } else {
1304 DNS_HISTOGRAM_BY_PRIORITY("DNS.JobQueueTime", priority(), queue_time);
1305 DNS_HISTOGRAM_BY_PRIORITY("DNS.JobQueueTimeAfterChange", priority(),
1306 queue_time_after_change);
1307 }
1308
[email protected]1d932852012-06-19 19:40:331309 // Caution: Job::Start must not complete synchronously.
[email protected]51b9a6b2012-06-25 21:50:291310 if (had_dns_config_ && !ResemblesMulticastDNSName(key_.hostname)) {
[email protected]b3601bc22012-02-21 21:23:201311 StartDnsTask();
1312 } else {
1313 StartProcTask();
1314 }
1315 }
1316
[email protected]b3601bc22012-02-21 21:23:201317 // TODO(szym): Since DnsTransaction does not consume threads, we can increase
1318 // the limits on |dispatcher_|. But in order to keep the number of WorkerPool
1319 // threads low, we will need to use an "inner" PrioritizedDispatcher with
1320 // tighter limits.
1321 void StartProcTask() {
[email protected]16ee26d2012-03-08 03:34:351322 DCHECK(!is_dns_running());
[email protected]0f292de02012-02-01 22:28:201323 proc_task_ = new ProcTask(
1324 key_,
1325 resolver_->proc_params_,
1326 base::Bind(&Job::OnProcTaskComplete, base::Unretained(this)),
1327 net_log_);
1328
1329 if (had_non_speculative_request_)
1330 proc_task_->set_had_non_speculative_request();
1331 // Start() could be called from within Resolve(), hence it must NOT directly
1332 // call OnProcTaskComplete, for example, on synchronous failure.
1333 proc_task_->Start();
[email protected]68ad3ee2010-01-30 03:45:391334 }
1335
[email protected]0f292de02012-02-01 22:28:201336 // Called by ProcTask when it completes.
[email protected]b3601bc22012-02-21 21:23:201337 void OnProcTaskComplete(int net_error, const AddressList& addr_list) {
1338 DCHECK(is_proc_running());
[email protected]68ad3ee2010-01-30 03:45:391339
[email protected]1d932852012-06-19 19:40:331340 if (dns_task_error_ != OK) {
[email protected]1def74c2012-03-22 20:07:001341 if (net_error == OK) {
[email protected]1d932852012-06-19 19:40:331342 if ((dns_task_error_ == ERR_NAME_NOT_RESOLVED) &&
1343 ResemblesNetBIOSName(key_.hostname)) {
1344 UmaAsyncDnsResolveStatus(RESOLVE_STATUS_SUSPECT_NETBIOS);
1345 } else {
1346 UmaAsyncDnsResolveStatus(RESOLVE_STATUS_PROC_SUCCESS);
1347 }
1348 UMA_HISTOGRAM_CUSTOM_ENUMERATION("AsyncDNS.ResolveError",
1349 std::abs(dns_task_error_),
1350 GetAllErrorCodesForUma());
[email protected]1def74c2012-03-22 20:07:001351 } else {
1352 UmaAsyncDnsResolveStatus(RESOLVE_STATUS_FAIL);
1353 }
1354 }
1355
[email protected]b3601bc22012-02-21 21:23:201356 base::TimeDelta ttl = base::TimeDelta::FromSeconds(
1357 kNegativeCacheEntryTTLSeconds);
1358 if (net_error == OK)
1359 ttl = base::TimeDelta::FromSeconds(kCacheEntryTTLSeconds);
[email protected]68ad3ee2010-01-30 03:45:391360
[email protected]16ee26d2012-03-08 03:34:351361 CompleteRequests(net_error, addr_list, ttl);
[email protected]b3601bc22012-02-21 21:23:201362 }
1363
1364 void StartDnsTask() {
[email protected]78eac2a2012-03-14 19:09:271365 DCHECK(resolver_->HaveDnsConfig());
[email protected]b3601bc22012-02-21 21:23:201366 dns_task_.reset(new DnsTask(
[email protected]78eac2a2012-03-14 19:09:271367 resolver_->dns_client_->GetTransactionFactory(),
[email protected]b3601bc22012-02-21 21:23:201368 key_,
1369 base::Bind(&Job::OnDnsTaskComplete, base::Unretained(this)),
1370 net_log_));
1371
1372 int rv = dns_task_->Start();
1373 if (rv != ERR_IO_PENDING) {
1374 DCHECK_NE(OK, rv);
[email protected]51b9a6b2012-06-25 21:50:291375 dns_task_error_ = rv;
[email protected]b3601bc22012-02-21 21:23:201376 dns_task_.reset();
1377 StartProcTask();
1378 }
1379 }
1380
1381 // Called by DnsTask when it completes.
1382 void OnDnsTaskComplete(int net_error,
1383 const AddressList& addr_list,
1384 base::TimeDelta ttl) {
1385 DCHECK(is_dns_running());
[email protected]b3601bc22012-02-21 21:23:201386
1387 if (net_error != OK) {
[email protected]1d932852012-06-19 19:40:331388 dns_task_error_ = net_error;
[email protected]16ee26d2012-03-08 03:34:351389 dns_task_.reset();
[email protected]78eac2a2012-03-14 19:09:271390
1391 // TODO(szym): Run ServeFromHosts now if nsswitch.conf says so.
1392 // http://crbug.com/117655
1393
[email protected]b3601bc22012-02-21 21:23:201394 // TODO(szym): Some net errors indicate lack of connectivity. Starting
1395 // ProcTask in that case is a waste of time.
1396 StartProcTask();
1397 return;
1398 }
1399
[email protected]1def74c2012-03-22 20:07:001400 UmaAsyncDnsResolveStatus(RESOLVE_STATUS_DNS_SUCCESS);
[email protected]16ee26d2012-03-08 03:34:351401 CompleteRequests(net_error, addr_list, ttl);
[email protected]b3601bc22012-02-21 21:23:201402 }
1403
[email protected]16ee26d2012-03-08 03:34:351404 // Performs Job's last rites. Completes all Requests. Deletes this.
[email protected]b3601bc22012-02-21 21:23:201405 void CompleteRequests(int net_error,
1406 const AddressList& addr_list,
1407 base::TimeDelta ttl) {
1408 CHECK(resolver_);
[email protected]b3601bc22012-02-21 21:23:201409
[email protected]16ee26d2012-03-08 03:34:351410 // This job must be removed from resolver's |jobs_| now to make room for a
1411 // new job with the same key in case one of the OnComplete callbacks decides
1412 // to spawn one. Consequently, the job deletes itself when CompleteRequests
1413 // is done.
1414 scoped_ptr<Job> self_deleter(this);
1415
1416 resolver_->RemoveJob(this);
1417
1418 // |addr_list| will be destroyed once we destroy |proc_task_| and
1419 // |dns_task_|.
[email protected]b3601bc22012-02-21 21:23:201420 AddressList list = addr_list;
[email protected]16ee26d2012-03-08 03:34:351421
1422 if (is_running()) {
1423 DCHECK(!is_queued());
1424 if (is_proc_running()) {
1425 proc_task_->Cancel();
1426 proc_task_ = NULL;
1427 }
1428 dns_task_.reset();
1429
1430 // Signal dispatcher that a slot has opened.
1431 resolver_->dispatcher_.OnJobFinished();
1432 } else if (is_queued()) {
1433 resolver_->dispatcher_.Cancel(handle_);
1434 handle_.Reset();
1435 }
1436
1437 if (num_active_requests() == 0) {
[email protected]4da911f2012-06-14 19:45:201438 net_log_.AddEvent(NetLog::TYPE_CANCELLED);
[email protected]16ee26d2012-03-08 03:34:351439 net_log_.EndEventWithNetErrorCode(NetLog::TYPE_HOST_RESOLVER_IMPL_JOB,
1440 OK);
1441 return;
1442 }
[email protected]b3601bc22012-02-21 21:23:201443
1444 net_log_.EndEventWithNetErrorCode(NetLog::TYPE_HOST_RESOLVER_IMPL_JOB,
1445 net_error);
[email protected]68ad3ee2010-01-30 03:45:391446
[email protected]78eac2a2012-03-14 19:09:271447 DCHECK(!requests_.empty());
1448
[email protected]d7b9a2b2012-05-31 22:31:191449 if (net_error == OK) {
[email protected]7054e78f2012-05-07 21:44:561450 SetPortOnAddressList(requests_->front()->info().port(), &list);
[email protected]d7b9a2b2012-05-31 22:31:191451 // Record this histogram here, when we know the system has a valid DNS
1452 // configuration.
[email protected]539df6c2012-06-19 21:21:291453 UMA_HISTOGRAM_BOOLEAN("AsyncDNS.HaveDnsConfig",
1454 resolver_->received_dns_config_);
[email protected]d7b9a2b2012-05-31 22:31:191455 }
[email protected]16ee26d2012-03-08 03:34:351456
[email protected]51b9a6b2012-06-25 21:50:291457 bool did_complete = (net_error != ERR_ABORTED) &&
1458 (net_error != ERR_HOST_RESOLVER_QUEUE_TOO_LARGE);
1459 if (did_complete)
[email protected]16ee26d2012-03-08 03:34:351460 resolver_->CacheResult(key_, net_error, list, ttl);
[email protected]16ee26d2012-03-08 03:34:351461
[email protected]0f292de02012-02-01 22:28:201462 // Complete all of the requests that were attached to the job.
1463 for (RequestsList::const_iterator it = requests_.begin();
1464 it != requests_.end(); ++it) {
1465 Request* req = *it;
1466
1467 if (req->was_canceled())
1468 continue;
1469
1470 DCHECK_EQ(this, req->job());
1471 // Update the net log and notify registered observers.
1472 LogFinishRequest(req->source_net_log(), req->request_net_log(),
[email protected]b3601bc22012-02-21 21:23:201473 req->info(), net_error);
[email protected]51b9a6b2012-06-25 21:50:291474 if (did_complete) {
1475 // Record effective total time from creation to completion.
1476 RecordTotalTime(had_dns_config_, req->info().is_speculative(),
1477 base::TimeTicks::Now() - req->request_time());
1478 }
[email protected]b3601bc22012-02-21 21:23:201479 req->OnComplete(net_error, list);
[email protected]0f292de02012-02-01 22:28:201480
1481 // Check if the resolver was destroyed as a result of running the
1482 // callback. If it was, we could continue, but we choose to bail.
1483 if (!resolver_)
1484 return;
1485 }
1486 }
1487
[email protected]b4481b222012-03-16 17:13:111488 RequestPriority priority() const {
1489 return priority_tracker_.highest_priority();
1490 }
1491
1492 // Number of non-canceled requests in |requests_|.
1493 size_t num_active_requests() const {
1494 return priority_tracker_.total_count();
1495 }
1496
1497 bool is_dns_running() const {
1498 return dns_task_.get() != NULL;
1499 }
1500
1501 bool is_proc_running() const {
1502 return proc_task_.get() != NULL;
1503 }
1504
[email protected]0f292de02012-02-01 22:28:201505 base::WeakPtr<HostResolverImpl> resolver_;
1506
1507 Key key_;
1508
1509 // Tracks the highest priority across |requests_|.
1510 PriorityTracker priority_tracker_;
1511
1512 bool had_non_speculative_request_;
1513
[email protected]51b9a6b2012-06-25 21:50:291514 // Distinguishes measurements taken while DnsClient was fully configured.
1515 bool had_dns_config_;
1516
[email protected]1d932852012-06-19 19:40:331517 // Result of DnsTask.
1518 int dns_task_error_;
[email protected]1def74c2012-03-22 20:07:001519
[email protected]51b9a6b2012-06-25 21:50:291520 const base::TimeTicks creation_time_;
1521 base::TimeTicks priority_change_time_;
1522
[email protected]0f292de02012-02-01 22:28:201523 BoundNetLog net_log_;
1524
[email protected]b3601bc22012-02-21 21:23:201525 // Resolves the host using a HostResolverProc.
[email protected]0f292de02012-02-01 22:28:201526 scoped_refptr<ProcTask> proc_task_;
1527
[email protected]b3601bc22012-02-21 21:23:201528 // Resolves the host using a DnsTransaction.
1529 scoped_ptr<DnsTask> dns_task_;
1530
[email protected]0f292de02012-02-01 22:28:201531 // All Requests waiting for the result of this Job. Some can be canceled.
1532 RequestsList requests_;
1533
[email protected]16ee26d2012-03-08 03:34:351534 // A handle used in |HostResolverImpl::dispatcher_|.
[email protected]0f292de02012-02-01 22:28:201535 PrioritizedDispatcher::Handle handle_;
[email protected]68ad3ee2010-01-30 03:45:391536};
1537
1538//-----------------------------------------------------------------------------
1539
[email protected]0f292de02012-02-01 22:28:201540HostResolverImpl::ProcTaskParams::ProcTaskParams(
[email protected]e95d3aca2010-01-11 22:47:431541 HostResolverProc* resolver_proc,
[email protected]0f292de02012-02-01 22:28:201542 size_t max_retry_attempts)
1543 : resolver_proc(resolver_proc),
1544 max_retry_attempts(max_retry_attempts),
1545 unresponsive_delay(base::TimeDelta::FromMilliseconds(6000)),
1546 retry_factor(2) {
1547}
1548
1549HostResolverImpl::ProcTaskParams::~ProcTaskParams() {}
1550
1551HostResolverImpl::HostResolverImpl(
[email protected]e95d3aca2010-01-11 22:47:431552 HostCache* cache,
[email protected]0f292de02012-02-01 22:28:201553 const PrioritizedDispatcher::Limits& job_limits,
1554 const ProcTaskParams& proc_params,
[email protected]b3601bc22012-02-21 21:23:201555 scoped_ptr<DnsConfigService> dns_config_service,
[email protected]d7b9a2b2012-05-31 22:31:191556 scoped_ptr<DnsClient> dns_client,
[email protected]ee094b82010-08-24 15:55:511557 NetLog* net_log)
[email protected]112bd462009-12-10 07:23:401558 : cache_(cache),
[email protected]0f292de02012-02-01 22:28:201559 dispatcher_(job_limits),
1560 max_queued_jobs_(job_limits.total_jobs * 100u),
1561 proc_params_(proc_params),
[email protected]0c7798452009-10-26 17:59:511562 default_address_family_(ADDRESS_FAMILY_UNSPECIFIED),
[email protected]b3601bc22012-02-21 21:23:201563 dns_config_service_(dns_config_service.Pass()),
[email protected]d7b9a2b2012-05-31 22:31:191564 dns_client_(dns_client.Pass()),
1565 received_dns_config_(false),
[email protected]2f3bc65c2010-07-23 17:47:101566 ipv6_probe_monitoring_(false),
[email protected]ee094b82010-08-24 15:55:511567 additional_resolver_flags_(0),
1568 net_log_(net_log) {
[email protected]0f292de02012-02-01 22:28:201569
1570 DCHECK_GE(dispatcher_.num_priorities(), static_cast<size_t>(NUM_PRIORITIES));
[email protected]68ad3ee2010-01-30 03:45:391571
[email protected]06ef6d92011-05-19 04:24:581572 // Maximum of 4 retry attempts for host resolution.
1573 static const size_t kDefaultMaxRetryAttempts = 4u;
1574
[email protected]0f292de02012-02-01 22:28:201575 if (proc_params_.max_retry_attempts == HostResolver::kDefaultRetryAttempts)
1576 proc_params_.max_retry_attempts = kDefaultMaxRetryAttempts;
[email protected]68ad3ee2010-01-30 03:45:391577
[email protected]b59ff372009-07-15 22:04:321578#if defined(OS_WIN)
1579 EnsureWinsockInit();
1580#endif
[email protected]23f771162011-06-02 18:37:511581#if defined(OS_POSIX) && !defined(OS_MACOSX)
[email protected]2f3bc65c2010-07-23 17:47:101582 if (HaveOnlyLoopbackAddresses())
1583 additional_resolver_flags_ |= HOST_RESOLVER_LOOPBACK_ONLY;
1584#endif
[email protected]232a5812011-03-04 22:42:081585 NetworkChangeNotifier::AddIPAddressObserver(this);
[email protected]d7b9a2b2012-05-31 22:31:191586#if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_OPENBSD) && \
1587 !defined(OS_ANDROID)
[email protected]46018c9d2011-09-06 03:42:341588 NetworkChangeNotifier::AddDNSObserver(this);
[email protected]d7b9a2b2012-05-31 22:31:191589 EnsureDnsReloaderInit();
[email protected]46018c9d2011-09-06 03:42:341590#endif
[email protected]b3601bc22012-02-21 21:23:201591
[email protected]78eac2a2012-03-14 19:09:271592 if (dns_config_service_.get()) {
[email protected]b4481b222012-03-16 17:13:111593 dns_config_service_->Watch(
1594 base::Bind(&HostResolverImpl::OnDnsConfigChanged,
1595 base::Unretained(this)));
[email protected]78eac2a2012-03-14 19:09:271596 }
[email protected]b59ff372009-07-15 22:04:321597}
1598
1599HostResolverImpl::~HostResolverImpl() {
[email protected]0f8f1b432010-03-16 19:06:031600 DiscardIPv6ProbeJob();
1601
[email protected]0f292de02012-02-01 22:28:201602 // This will also cancel all outstanding requests.
1603 STLDeleteValues(&jobs_);
[email protected]e95d3aca2010-01-11 22:47:431604
[email protected]232a5812011-03-04 22:42:081605 NetworkChangeNotifier::RemoveIPAddressObserver(this);
[email protected]46018c9d2011-09-06 03:42:341606 NetworkChangeNotifier::RemoveDNSObserver(this);
[email protected]b59ff372009-07-15 22:04:321607}
1608
[email protected]0f292de02012-02-01 22:28:201609void HostResolverImpl::SetMaxQueuedJobs(size_t value) {
1610 DCHECK_EQ(0u, dispatcher_.num_queued_jobs());
1611 DCHECK_GT(value, 0u);
1612 max_queued_jobs_ = value;
[email protected]be1a48b2011-01-20 00:12:131613}
1614
[email protected]684970b2009-08-14 04:54:461615int HostResolverImpl::Resolve(const RequestInfo& info,
[email protected]b59ff372009-07-15 22:04:321616 AddressList* addresses,
[email protected]aa22b242011-11-16 18:58:291617 const CompletionCallback& callback,
[email protected]684970b2009-08-14 04:54:461618 RequestHandle* out_req,
[email protected]ee094b82010-08-24 15:55:511619 const BoundNetLog& source_net_log) {
[email protected]95a214c2011-08-04 21:50:401620 DCHECK(addresses);
[email protected]1ac6af92010-06-03 21:00:141621 DCHECK(CalledOnValidThread());
[email protected]aa22b242011-11-16 18:58:291622 DCHECK_EQ(false, callback.is_null());
[email protected]1ac6af92010-06-03 21:00:141623
[email protected]ee094b82010-08-24 15:55:511624 // Make a log item for the request.
1625 BoundNetLog request_net_log = BoundNetLog::Make(net_log_,
1626 NetLog::SOURCE_HOST_RESOLVER_IMPL_REQUEST);
1627
[email protected]0f292de02012-02-01 22:28:201628 LogStartRequest(source_net_log, request_net_log, info);
[email protected]b59ff372009-07-15 22:04:321629
[email protected]123ab1e32009-10-21 19:12:571630 // Build a key that identifies the request in the cache and in the
1631 // outstanding jobs map.
[email protected]137af622010-02-05 02:14:351632 Key key = GetEffectiveKeyForRequest(info);
[email protected]123ab1e32009-10-21 19:12:571633
[email protected]287d7c22011-11-15 17:34:251634 int rv = ResolveHelper(key, info, addresses, request_net_log);
[email protected]95a214c2011-08-04 21:50:401635 if (rv != ERR_DNS_CACHE_MISS) {
[email protected]b3601bc22012-02-21 21:23:201636 LogFinishRequest(source_net_log, request_net_log, info, rv);
[email protected]51b9a6b2012-06-25 21:50:291637 RecordTotalTime(HaveDnsConfig(), info.is_speculative(), base::TimeDelta());
[email protected]95a214c2011-08-04 21:50:401638 return rv;
[email protected]38368712011-03-02 08:09:401639 }
1640
[email protected]0f292de02012-02-01 22:28:201641 // Next we need to attach our request to a "job". This job is responsible for
1642 // calling "getaddrinfo(hostname)" on a worker thread.
1643
1644 JobMap::iterator jobit = jobs_.find(key);
1645 Job* job;
1646 if (jobit == jobs_.end()) {
1647 // Create new Job.
[email protected]16ee26d2012-03-08 03:34:351648 job = new Job(this, key, request_net_log);
1649 job->Schedule(info.priority());
[email protected]0f292de02012-02-01 22:28:201650
1651 // Check for queue overflow.
1652 if (dispatcher_.num_queued_jobs() > max_queued_jobs_) {
1653 Job* evicted = static_cast<Job*>(dispatcher_.EvictOldestLowest());
1654 DCHECK(evicted);
[email protected]16ee26d2012-03-08 03:34:351655 evicted->OnEvicted(); // Deletes |evicted|.
[email protected]0f292de02012-02-01 22:28:201656 if (evicted == job) {
[email protected]0f292de02012-02-01 22:28:201657 rv = ERR_HOST_RESOLVER_QUEUE_TOO_LARGE;
[email protected]b3601bc22012-02-21 21:23:201658 LogFinishRequest(source_net_log, request_net_log, info, rv);
[email protected]0f292de02012-02-01 22:28:201659 return rv;
1660 }
[email protected]0f292de02012-02-01 22:28:201661 }
[email protected]0f292de02012-02-01 22:28:201662 jobs_.insert(jobit, std::make_pair(key, job));
1663 } else {
1664 job = jobit->second;
1665 }
1666
1667 // Can't complete synchronously. Create and attach request.
[email protected]b3601bc22012-02-21 21:23:201668 scoped_ptr<Request> req(new Request(source_net_log,
1669 request_net_log,
1670 info,
1671 callback,
1672 addresses));
[email protected]b59ff372009-07-15 22:04:321673 if (out_req)
[email protected]b3601bc22012-02-21 21:23:201674 *out_req = reinterpret_cast<RequestHandle>(req.get());
[email protected]b59ff372009-07-15 22:04:321675
[email protected]b3601bc22012-02-21 21:23:201676 job->AddRequest(req.Pass());
[email protected]0f292de02012-02-01 22:28:201677 // Completion happens during Job::CompleteRequests().
[email protected]b59ff372009-07-15 22:04:321678 return ERR_IO_PENDING;
1679}
1680
[email protected]287d7c22011-11-15 17:34:251681int HostResolverImpl::ResolveHelper(const Key& key,
[email protected]95a214c2011-08-04 21:50:401682 const RequestInfo& info,
1683 AddressList* addresses,
[email protected]20cd5332011-10-12 22:38:001684 const BoundNetLog& request_net_log) {
[email protected]95a214c2011-08-04 21:50:401685 // The result of |getaddrinfo| for empty hosts is inconsistent across systems.
1686 // On Windows it gives the default interface's address, whereas on Linux it
1687 // gives an error. We will make it fail on all platforms for consistency.
1688 if (info.hostname().empty() || info.hostname().size() > kMaxHostLength)
1689 return ERR_NAME_NOT_RESOLVED;
1690
1691 int net_error = ERR_UNEXPECTED;
1692 if (ResolveAsIP(key, info, &net_error, addresses))
1693 return net_error;
[email protected]78eac2a2012-03-14 19:09:271694 if (ServeFromCache(key, info, &net_error, addresses)) {
[email protected]4da911f2012-06-14 19:45:201695 request_net_log.AddEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_CACHE_HIT);
[email protected]78eac2a2012-03-14 19:09:271696 return net_error;
1697 }
1698 // TODO(szym): Do not do this if nsswitch.conf instructs not to.
1699 // http://crbug.com/117655
1700 if (ServeFromHosts(key, info, addresses)) {
[email protected]4da911f2012-06-14 19:45:201701 request_net_log.AddEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_HOSTS_HIT);
[email protected]78eac2a2012-03-14 19:09:271702 return OK;
1703 }
1704 return ERR_DNS_CACHE_MISS;
[email protected]95a214c2011-08-04 21:50:401705}
1706
1707int HostResolverImpl::ResolveFromCache(const RequestInfo& info,
1708 AddressList* addresses,
1709 const BoundNetLog& source_net_log) {
1710 DCHECK(CalledOnValidThread());
1711 DCHECK(addresses);
1712
[email protected]95a214c2011-08-04 21:50:401713 // Make a log item for the request.
1714 BoundNetLog request_net_log = BoundNetLog::Make(net_log_,
1715 NetLog::SOURCE_HOST_RESOLVER_IMPL_REQUEST);
1716
1717 // Update the net log and notify registered observers.
[email protected]0f292de02012-02-01 22:28:201718 LogStartRequest(source_net_log, request_net_log, info);
[email protected]95a214c2011-08-04 21:50:401719
[email protected]95a214c2011-08-04 21:50:401720 Key key = GetEffectiveKeyForRequest(info);
1721
[email protected]287d7c22011-11-15 17:34:251722 int rv = ResolveHelper(key, info, addresses, request_net_log);
[email protected]b3601bc22012-02-21 21:23:201723 LogFinishRequest(source_net_log, request_net_log, info, rv);
[email protected]95a214c2011-08-04 21:50:401724 return rv;
1725}
1726
[email protected]b59ff372009-07-15 22:04:321727void HostResolverImpl::CancelRequest(RequestHandle req_handle) {
[email protected]1ac6af92010-06-03 21:00:141728 DCHECK(CalledOnValidThread());
[email protected]b59ff372009-07-15 22:04:321729 Request* req = reinterpret_cast<Request*>(req_handle);
1730 DCHECK(req);
[email protected]0f292de02012-02-01 22:28:201731 Job* job = req->job();
1732 DCHECK(job);
[email protected]0f292de02012-02-01 22:28:201733 job->CancelRequest(req);
[email protected]b59ff372009-07-15 22:04:321734}
1735
[email protected]0f8f1b432010-03-16 19:06:031736void HostResolverImpl::SetDefaultAddressFamily(AddressFamily address_family) {
[email protected]1ac6af92010-06-03 21:00:141737 DCHECK(CalledOnValidThread());
[email protected]0f8f1b432010-03-16 19:06:031738 ipv6_probe_monitoring_ = false;
1739 DiscardIPv6ProbeJob();
1740 default_address_family_ = address_family;
1741}
1742
[email protected]f7d310e2010-10-07 16:25:111743AddressFamily HostResolverImpl::GetDefaultAddressFamily() const {
1744 return default_address_family_;
1745}
1746
[email protected]a78f4272011-10-21 19:16:331747void HostResolverImpl::ProbeIPv6Support() {
1748 DCHECK(CalledOnValidThread());
1749 DCHECK(!ipv6_probe_monitoring_);
1750 ipv6_probe_monitoring_ = true;
1751 OnIPAddressChanged(); // Give initial setup call.
[email protected]ddb1e5a2010-12-13 20:10:451752}
1753
[email protected]489d1a82011-10-12 03:09:111754HostCache* HostResolverImpl::GetHostCache() {
1755 return cache_.get();
1756}
[email protected]95a214c2011-08-04 21:50:401757
[email protected]17e92032012-03-29 00:56:241758base::Value* HostResolverImpl::GetDnsConfigAsValue() const {
1759 // Check if async DNS is disabled.
1760 if (!dns_client_.get())
1761 return NULL;
1762
1763 // Check if async DNS is enabled, but we currently have no configuration
1764 // for it.
1765 const DnsConfig* dns_config = dns_client_->GetConfig();
1766 if (dns_config == NULL)
1767 return new DictionaryValue();
1768
1769 return dns_config->ToValue();
1770}
1771
[email protected]95a214c2011-08-04 21:50:401772bool HostResolverImpl::ResolveAsIP(const Key& key,
1773 const RequestInfo& info,
1774 int* net_error,
1775 AddressList* addresses) {
1776 DCHECK(addresses);
1777 DCHECK(net_error);
1778 IPAddressNumber ip_number;
1779 if (!ParseIPLiteralToNumber(key.hostname, &ip_number))
1780 return false;
1781
1782 DCHECK_EQ(key.host_resolver_flags &
1783 ~(HOST_RESOLVER_CANONNAME | HOST_RESOLVER_LOOPBACK_ONLY |
1784 HOST_RESOLVER_DEFAULT_FAMILY_SET_DUE_TO_NO_IPV6),
1785 0) << " Unhandled flag";
[email protected]0f292de02012-02-01 22:28:201786 bool ipv6_disabled = (default_address_family_ == ADDRESS_FAMILY_IPV4) &&
1787 !ipv6_probe_monitoring_;
[email protected]95a214c2011-08-04 21:50:401788 *net_error = OK;
[email protected]0f292de02012-02-01 22:28:201789 if ((ip_number.size() == kIPv6AddressSize) && ipv6_disabled) {
[email protected]95a214c2011-08-04 21:50:401790 *net_error = ERR_NAME_NOT_RESOLVED;
1791 } else {
[email protected]7054e78f2012-05-07 21:44:561792 *addresses = AddressList::CreateFromIPAddress(ip_number, info.port());
1793 if (key.host_resolver_flags & HOST_RESOLVER_CANONNAME)
1794 addresses->SetDefaultCanonicalName();
[email protected]95a214c2011-08-04 21:50:401795 }
1796 return true;
1797}
1798
1799bool HostResolverImpl::ServeFromCache(const Key& key,
1800 const RequestInfo& info,
[email protected]95a214c2011-08-04 21:50:401801 int* net_error,
1802 AddressList* addresses) {
1803 DCHECK(addresses);
1804 DCHECK(net_error);
1805 if (!info.allow_cached_response() || !cache_.get())
1806 return false;
1807
1808 const HostCache::Entry* cache_entry = cache_->Lookup(
1809 key, base::TimeTicks::Now());
1810 if (!cache_entry)
1811 return false;
1812
[email protected]95a214c2011-08-04 21:50:401813 *net_error = cache_entry->error;
[email protected]7054e78f2012-05-07 21:44:561814 if (*net_error == OK) {
1815 *addresses = cache_entry->addrlist;
1816 EnsurePortOnAddressList(info.port(), addresses);
1817 }
[email protected]95a214c2011-08-04 21:50:401818 return true;
1819}
1820
[email protected]78eac2a2012-03-14 19:09:271821bool HostResolverImpl::ServeFromHosts(const Key& key,
1822 const RequestInfo& info,
1823 AddressList* addresses) {
1824 DCHECK(addresses);
1825 if (!HaveDnsConfig())
1826 return false;
1827
[email protected]cb507622012-03-23 16:17:061828 // HOSTS lookups are case-insensitive.
1829 std::string hostname = StringToLowerASCII(key.hostname);
1830
[email protected]78eac2a2012-03-14 19:09:271831 // If |address_family| is ADDRESS_FAMILY_UNSPECIFIED other implementations
1832 // (glibc and c-ares) return the first matching line. We have more
1833 // flexibility, but lose implicit ordering.
1834 // TODO(szym) http://crbug.com/117850
1835 const DnsHosts& hosts = dns_client_->GetConfig()->hosts;
1836 DnsHosts::const_iterator it = hosts.find(
[email protected]cb507622012-03-23 16:17:061837 DnsHostsKey(hostname,
[email protected]78eac2a2012-03-14 19:09:271838 key.address_family == ADDRESS_FAMILY_UNSPECIFIED ?
1839 ADDRESS_FAMILY_IPV4 : key.address_family));
1840
1841 if (it == hosts.end()) {
1842 if (key.address_family != ADDRESS_FAMILY_UNSPECIFIED)
1843 return false;
1844
[email protected]cb507622012-03-23 16:17:061845 it = hosts.find(DnsHostsKey(hostname, ADDRESS_FAMILY_IPV6));
[email protected]78eac2a2012-03-14 19:09:271846 if (it == hosts.end())
1847 return false;
1848 }
1849
1850 *addresses = AddressList::CreateFromIPAddress(it->second, info.port());
1851 return true;
1852}
1853
[email protected]16ee26d2012-03-08 03:34:351854void HostResolverImpl::CacheResult(const Key& key,
1855 int net_error,
1856 const AddressList& addr_list,
1857 base::TimeDelta ttl) {
1858 if (cache_.get())
1859 cache_->Set(key, net_error, addr_list, base::TimeTicks::Now(), ttl);
[email protected]ef4c40c2010-09-01 14:42:031860}
1861
[email protected]0f292de02012-02-01 22:28:201862void HostResolverImpl::RemoveJob(Job* job) {
1863 DCHECK(job);
[email protected]16ee26d2012-03-08 03:34:351864 JobMap::iterator it = jobs_.find(job->key());
1865 if (it != jobs_.end() && it->second == job)
1866 jobs_.erase(it);
[email protected]b59ff372009-07-15 22:04:321867}
1868
[email protected]0f8f1b432010-03-16 19:06:031869void HostResolverImpl::DiscardIPv6ProbeJob() {
1870 if (ipv6_probe_job_.get()) {
1871 ipv6_probe_job_->Cancel();
1872 ipv6_probe_job_ = NULL;
1873 }
1874}
1875
1876void HostResolverImpl::IPv6ProbeSetDefaultAddressFamily(
1877 AddressFamily address_family) {
1878 DCHECK(address_family == ADDRESS_FAMILY_UNSPECIFIED ||
1879 address_family == ADDRESS_FAMILY_IPV4);
[email protected]f092e64b2010-03-17 00:39:181880 if (default_address_family_ != address_family) {
[email protected]b30a3f52010-10-16 01:05:461881 VLOG(1) << "IPv6Probe forced AddressFamily setting to "
1882 << ((address_family == ADDRESS_FAMILY_UNSPECIFIED) ?
1883 "ADDRESS_FAMILY_UNSPECIFIED" : "ADDRESS_FAMILY_IPV4");
[email protected]f092e64b2010-03-17 00:39:181884 }
[email protected]0f8f1b432010-03-16 19:06:031885 default_address_family_ = address_family;
1886 // Drop reference since the job has called us back.
1887 DiscardIPv6ProbeJob();
[email protected]e95d3aca2010-01-11 22:47:431888}
1889
[email protected]137af622010-02-05 02:14:351890HostResolverImpl::Key HostResolverImpl::GetEffectiveKeyForRequest(
1891 const RequestInfo& info) const {
[email protected]eaf3a3b2010-09-03 20:34:271892 HostResolverFlags effective_flags =
1893 info.host_resolver_flags() | additional_resolver_flags_;
[email protected]137af622010-02-05 02:14:351894 AddressFamily effective_address_family = info.address_family();
[email protected]eaf3a3b2010-09-03 20:34:271895 if (effective_address_family == ADDRESS_FAMILY_UNSPECIFIED &&
1896 default_address_family_ != ADDRESS_FAMILY_UNSPECIFIED) {
[email protected]137af622010-02-05 02:14:351897 effective_address_family = default_address_family_;
[email protected]eaf3a3b2010-09-03 20:34:271898 if (ipv6_probe_monitoring_)
1899 effective_flags |= HOST_RESOLVER_DEFAULT_FAMILY_SET_DUE_TO_NO_IPV6;
1900 }
1901 return Key(info.hostname(), effective_address_family, effective_flags);
[email protected]137af622010-02-05 02:14:351902}
1903
[email protected]35ddc282010-09-21 23:42:061904void HostResolverImpl::AbortAllInProgressJobs() {
[email protected]b3601bc22012-02-21 21:23:201905 // In Abort, a Request callback could spawn new Jobs with matching keys, so
1906 // first collect and remove all running jobs from |jobs_|.
[email protected]c143d892012-04-06 07:56:541907 ScopedVector<Job> jobs_to_abort;
[email protected]0f292de02012-02-01 22:28:201908 for (JobMap::iterator it = jobs_.begin(); it != jobs_.end(); ) {
1909 Job* job = it->second;
[email protected]0f292de02012-02-01 22:28:201910 if (job->is_running()) {
[email protected]b3601bc22012-02-21 21:23:201911 jobs_to_abort.push_back(job);
1912 jobs_.erase(it++);
[email protected]0f292de02012-02-01 22:28:201913 } else {
[email protected]b3601bc22012-02-21 21:23:201914 DCHECK(job->is_queued());
1915 ++it;
[email protected]0f292de02012-02-01 22:28:201916 }
[email protected]ef4c40c2010-09-01 14:42:031917 }
[email protected]b3601bc22012-02-21 21:23:201918
[email protected]57a48d32012-03-03 00:04:551919 // Check if no dispatcher slots leaked out.
1920 DCHECK_EQ(dispatcher_.num_running_jobs(), jobs_to_abort.size());
1921
1922 // Life check to bail once |this| is deleted.
1923 base::WeakPtr<HostResolverImpl> self = AsWeakPtr();
1924
[email protected]16ee26d2012-03-08 03:34:351925 // Then Abort them.
[email protected]57a48d32012-03-03 00:04:551926 for (size_t i = 0; self && i < jobs_to_abort.size(); ++i) {
[email protected]57a48d32012-03-03 00:04:551927 jobs_to_abort[i]->Abort();
[email protected]c143d892012-04-06 07:56:541928 jobs_to_abort[i] = NULL;
[email protected]b3601bc22012-02-21 21:23:201929 }
[email protected]ef4c40c2010-09-01 14:42:031930}
1931
[email protected]78eac2a2012-03-14 19:09:271932void HostResolverImpl::TryServingAllJobsFromHosts() {
1933 if (!HaveDnsConfig())
1934 return;
1935
1936 // TODO(szym): Do not do this if nsswitch.conf instructs not to.
1937 // http://crbug.com/117655
1938
1939 // Life check to bail once |this| is deleted.
1940 base::WeakPtr<HostResolverImpl> self = AsWeakPtr();
1941
1942 for (JobMap::iterator it = jobs_.begin(); self && it != jobs_.end(); ) {
1943 Job* job = it->second;
1944 ++it;
1945 // This could remove |job| from |jobs_|, but iterator will remain valid.
1946 job->ServeFromHosts();
1947 }
1948}
1949
[email protected]be1a48b2011-01-20 00:12:131950void HostResolverImpl::OnIPAddressChanged() {
1951 if (cache_.get())
1952 cache_->clear();
1953 if (ipv6_probe_monitoring_) {
[email protected]be1a48b2011-01-20 00:12:131954 DiscardIPv6ProbeJob();
1955 ipv6_probe_job_ = new IPv6ProbeJob(this);
1956 ipv6_probe_job_->Start();
1957 }
[email protected]23f771162011-06-02 18:37:511958#if defined(OS_POSIX) && !defined(OS_MACOSX)
[email protected]be1a48b2011-01-20 00:12:131959 if (HaveOnlyLoopbackAddresses()) {
1960 additional_resolver_flags_ |= HOST_RESOLVER_LOOPBACK_ONLY;
1961 } else {
1962 additional_resolver_flags_ &= ~HOST_RESOLVER_LOOPBACK_ONLY;
1963 }
1964#endif
1965 AbortAllInProgressJobs();
1966 // |this| may be deleted inside AbortAllInProgressJobs().
1967}
1968
[email protected]446df2952012-02-28 07:22:511969void HostResolverImpl::OnDNSChanged(unsigned detail) {
[email protected]d7b9a2b2012-05-31 22:31:191970 // Ignore signals about watches.
1971 const unsigned kIgnoredDetail =
1972 NetworkChangeNotifier::CHANGE_DNS_WATCH_STARTED |
1973 NetworkChangeNotifier::CHANGE_DNS_WATCH_FAILED;
1974 if ((detail & ~kIgnoredDetail) == 0)
1975 return;
[email protected]46018c9d2011-09-06 03:42:341976 // If the DNS server has changed, existing cached info could be wrong so we
1977 // have to drop our internal cache :( Note that OS level DNS caches, such
1978 // as NSCD's cache should be dropped automatically by the OS when
1979 // resolv.conf changes so we don't need to do anything to clear that cache.
1980 if (cache_.get())
1981 cache_->clear();
1982 // Existing jobs will have been sent to the original server so they need to
[email protected]d7b9a2b2012-05-31 22:31:191983 // be aborted.
[email protected]46018c9d2011-09-06 03:42:341984 AbortAllInProgressJobs();
1985 // |this| may be deleted inside AbortAllInProgressJobs().
1986}
1987
[email protected]b4481b222012-03-16 17:13:111988void HostResolverImpl::OnDnsConfigChanged(const DnsConfig& dns_config) {
1989 if (net_log_) {
1990 net_log_->AddGlobalEntry(
1991 NetLog::TYPE_DNS_CONFIG_CHANGED,
[email protected]cd565142012-06-12 16:21:451992 base::Bind(&NetLogDnsConfigCallback, &dns_config));
[email protected]b4481b222012-03-16 17:13:111993 }
1994
[email protected]d7b9a2b2012-05-31 22:31:191995 // TODO(szym): Remove once http://crbug.com/125599 is resolved.
1996 received_dns_config_ = dns_config.IsValid();
[email protected]78eac2a2012-03-14 19:09:271997
1998 // Life check to bail once |this| is deleted.
1999 base::WeakPtr<HostResolverImpl> self = AsWeakPtr();
2000
[email protected]d7b9a2b2012-05-31 22:31:192001 if (dns_client_.get()) {
2002 // We want a new factory in place, before we Abort running Jobs, so that the
2003 // newly started jobs use the new factory.
2004 dns_client_->SetConfig(dns_config);
[email protected]446df2952012-02-28 07:22:512005 OnDNSChanged(NetworkChangeNotifier::CHANGE_DNS_SETTINGS);
[email protected]d7b9a2b2012-05-31 22:31:192006 // |this| may be deleted inside OnDNSChanged().
2007 if (self)
2008 TryServingAllJobsFromHosts();
[email protected]7b5db762012-03-24 09:02:012009 }
[email protected]78eac2a2012-03-14 19:09:272010}
2011
2012bool HostResolverImpl::HaveDnsConfig() const {
2013 return (dns_client_.get() != NULL) && (dns_client_->GetConfig() != NULL);
[email protected]b3601bc22012-02-21 21:23:202014}
2015
[email protected]b59ff372009-07-15 22:04:322016} // namespace net