blob: 7f785b2733f975c007c4d31ed3c59be775ccf26e [file] [log] [blame]
[email protected]a2730882012-01-21 00:56:271// Copyright (c) 2012 The Chromium Authors. All rights reserved.
[email protected]b59ff372009-07-15 22:04:322// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "net/base/host_resolver_impl.h"
6
[email protected]21526002010-05-16 19:42:467#if defined(OS_WIN)
8#include <Winsock2.h>
9#elif defined(OS_POSIX)
10#include <netdb.h>
11#endif
12
[email protected]68ad3ee2010-01-30 03:45:3913#include <cmath>
[email protected]0f292de02012-02-01 22:28:2014#include <utility>
[email protected]21526002010-05-16 19:42:4615#include <vector>
[email protected]68ad3ee2010-01-30 03:45:3916
17#include "base/basictypes.h"
[email protected]33152acc2011-10-20 23:37:1218#include "base/bind.h"
[email protected]aa22b242011-11-16 18:58:2919#include "base/bind_helpers.h"
[email protected]0f292de02012-02-01 22:28:2020#include "base/callback.h"
[email protected]b59ff372009-07-15 22:04:3221#include "base/compiler_specific.h"
[email protected]58580352010-10-26 04:07:5022#include "base/debug/debugger.h"
23#include "base/debug/stack_trace.h"
[email protected]3e9d9cc2011-05-03 21:08:1524#include "base/message_loop_proxy.h"
[email protected]1e9bbd22010-10-15 16:42:4525#include "base/metrics/field_trial.h"
[email protected]835d7c82010-10-14 04:38:3826#include "base/metrics/histogram.h"
[email protected]7286e3fc2011-07-19 22:13:2427#include "base/stl_util.h"
[email protected]b59ff372009-07-15 22:04:3228#include "base/string_util.h"
[email protected]ac9ba8fe2010-12-30 18:08:3629#include "base/threading/worker_pool.h"
[email protected]b59ff372009-07-15 22:04:3230#include "base/time.h"
[email protected]ccaff652010-07-31 06:28:2031#include "base/utf_string_conversions.h"
[email protected]21526002010-05-16 19:42:4632#include "base/values.h"
[email protected]b3601bc22012-02-21 21:23:2033#include "net/base/address_family.h"
[email protected]b59ff372009-07-15 22:04:3234#include "net/base/address_list.h"
[email protected]46018c9d2011-09-06 03:42:3435#include "net/base/dns_reloader.h"
[email protected]ee094b82010-08-24 15:55:5136#include "net/base/host_port_pair.h"
[email protected]b59ff372009-07-15 22:04:3237#include "net/base/host_resolver_proc.h"
[email protected]2bb04442010-08-18 18:01:1538#include "net/base/net_errors.h"
[email protected]ee094b82010-08-24 15:55:5139#include "net/base/net_log.h"
[email protected]0f8f1b432010-03-16 19:06:0340#include "net/base/net_util.h"
[email protected]0adcb2b2012-08-15 21:30:4641#include "net/dns/address_sorter.h"
[email protected]78eac2a2012-03-14 19:09:2742#include "net/dns/dns_client.h"
[email protected]b3601bc22012-02-21 21:23:2043#include "net/dns/dns_config_service.h"
44#include "net/dns/dns_protocol.h"
45#include "net/dns/dns_response.h"
[email protected]b3601bc22012-02-21 21:23:2046#include "net/dns/dns_transaction.h"
[email protected]b59ff372009-07-15 22:04:3247
48#if defined(OS_WIN)
49#include "net/base/winsock_init.h"
50#endif
51
52namespace net {
53
[email protected]e95d3aca2010-01-11 22:47:4354namespace {
55
[email protected]6e78dfb2011-07-28 21:34:4756// Limit the size of hostnames that will be resolved to combat issues in
57// some platform's resolvers.
58const size_t kMaxHostLength = 4096;
59
[email protected]a2730882012-01-21 00:56:2760// Default TTL for successful resolutions with ProcTask.
61const unsigned kCacheEntryTTLSeconds = 60;
62
[email protected]b3601bc22012-02-21 21:23:2063// Default TTL for unsuccessful resolutions with ProcTask.
64const unsigned kNegativeCacheEntryTTLSeconds = 0;
65
[email protected]4f8a16a2012-04-07 23:59:2066// Maximum of 6 concurrent resolver threads (excluding retries).
[email protected]0f292de02012-02-01 22:28:2067// Some routers (or resolvers) appear to start to provide host-not-found if
68// too many simultaneous resolutions are pending. This number needs to be
[email protected]4f8a16a2012-04-07 23:59:2069// further optimized, but 8 is what FF currently does. We found some routers
70// that limit this to 6, so we're temporarily holding it at that level.
71static const size_t kDefaultMaxProcTasks = 6u;
[email protected]0f292de02012-02-01 22:28:2072
[email protected]24f4bab2010-10-15 01:27:1173// We use a separate histogram name for each platform to facilitate the
74// display of error codes by their symbolic name (since each platform has
75// different mappings).
76const char kOSErrorsForGetAddrinfoHistogramName[] =
77#if defined(OS_WIN)
78 "Net.OSErrorsForGetAddrinfo_Win";
79#elif defined(OS_MACOSX)
80 "Net.OSErrorsForGetAddrinfo_Mac";
81#elif defined(OS_LINUX)
82 "Net.OSErrorsForGetAddrinfo_Linux";
83#else
84 "Net.OSErrorsForGetAddrinfo";
85#endif
86
[email protected]c89b2442011-05-26 14:28:2787// Gets a list of the likely error codes that getaddrinfo() can return
88// (non-exhaustive). These are the error codes that we will track via
89// a histogram.
90std::vector<int> GetAllGetAddrinfoOSErrors() {
91 int os_errors[] = {
92#if defined(OS_POSIX)
[email protected]23f771162011-06-02 18:37:5193#if !defined(OS_FREEBSD)
[email protected]39588992011-07-11 19:54:3794#if !defined(OS_ANDROID)
[email protected]c48aef92011-11-22 23:41:4595 // EAI_ADDRFAMILY has been declared obsolete in Android's and
96 // FreeBSD's netdb.h.
[email protected]c89b2442011-05-26 14:28:2797 EAI_ADDRFAMILY,
[email protected]39588992011-07-11 19:54:3798#endif
[email protected]c48aef92011-11-22 23:41:4599 // EAI_NODATA has been declared obsolete in FreeBSD's netdb.h.
[email protected]23f771162011-06-02 18:37:51100 EAI_NODATA,
101#endif
[email protected]c89b2442011-05-26 14:28:27102 EAI_AGAIN,
103 EAI_BADFLAGS,
104 EAI_FAIL,
105 EAI_FAMILY,
106 EAI_MEMORY,
[email protected]c89b2442011-05-26 14:28:27107 EAI_NONAME,
108 EAI_SERVICE,
109 EAI_SOCKTYPE,
110 EAI_SYSTEM,
111#elif defined(OS_WIN)
112 // See: http://msdn.microsoft.com/en-us/library/ms738520(VS.85).aspx
113 WSA_NOT_ENOUGH_MEMORY,
114 WSAEAFNOSUPPORT,
115 WSAEINVAL,
116 WSAESOCKTNOSUPPORT,
117 WSAHOST_NOT_FOUND,
118 WSANO_DATA,
119 WSANO_RECOVERY,
120 WSANOTINITIALISED,
121 WSATRY_AGAIN,
122 WSATYPE_NOT_FOUND,
123 // The following are not in doc, but might be to appearing in results :-(.
124 WSA_INVALID_HANDLE,
125#endif
126 };
127
128 // Ensure all errors are positive, as histogram only tracks positive values.
129 for (size_t i = 0; i < arraysize(os_errors); ++i) {
130 os_errors[i] = std::abs(os_errors[i]);
131 }
132
133 return base::CustomHistogram::ArrayToCustomRanges(os_errors,
134 arraysize(os_errors));
135}
136
[email protected]1def74c2012-03-22 20:07:00137enum DnsResolveStatus {
138 RESOLVE_STATUS_DNS_SUCCESS = 0,
139 RESOLVE_STATUS_PROC_SUCCESS,
140 RESOLVE_STATUS_FAIL,
[email protected]1d932852012-06-19 19:40:33141 RESOLVE_STATUS_SUSPECT_NETBIOS,
[email protected]1def74c2012-03-22 20:07:00142 RESOLVE_STATUS_MAX
143};
144
145void UmaAsyncDnsResolveStatus(DnsResolveStatus result) {
146 UMA_HISTOGRAM_ENUMERATION("AsyncDNS.ResolveStatus",
147 result,
148 RESOLVE_STATUS_MAX);
149}
150
[email protected]1d932852012-06-19 19:40:33151bool ResemblesNetBIOSName(const std::string& hostname) {
152 return (hostname.size() < 16) && (hostname.find('.') == std::string::npos);
153}
154
155// True if |hostname| ends with either ".local" or ".local.".
156bool ResemblesMulticastDNSName(const std::string& hostname) {
157 DCHECK(!hostname.empty());
158 const char kSuffix[] = ".local.";
159 const size_t kSuffixLen = sizeof(kSuffix) - 1;
160 const size_t kSuffixLenTrimmed = kSuffixLen - 1;
161 if (hostname[hostname.size() - 1] == '.') {
162 return hostname.size() > kSuffixLen &&
163 !hostname.compare(hostname.size() - kSuffixLen, kSuffixLen, kSuffix);
164 }
165 return hostname.size() > kSuffixLenTrimmed &&
166 !hostname.compare(hostname.size() - kSuffixLenTrimmed, kSuffixLenTrimmed,
167 kSuffix, kSuffixLenTrimmed);
168}
169
[email protected]51b9a6b2012-06-25 21:50:29170// Provide a common macro to simplify code and readability. We must use a
171// macro as the underlying HISTOGRAM macro creates static variables.
172#define DNS_HISTOGRAM(name, time) UMA_HISTOGRAM_CUSTOM_TIMES(name, time, \
173 base::TimeDelta::FromMilliseconds(1), base::TimeDelta::FromHours(1), 100)
174
175// A macro to simplify code and readability.
176#define DNS_HISTOGRAM_BY_PRIORITY(basename, priority, time) \
177 do { \
178 switch (priority) { \
179 case HIGHEST: DNS_HISTOGRAM(basename "_HIGHEST", time); break; \
180 case MEDIUM: DNS_HISTOGRAM(basename "_MEDIUM", time); break; \
181 case LOW: DNS_HISTOGRAM(basename "_LOW", time); break; \
182 case LOWEST: DNS_HISTOGRAM(basename "_LOWEST", time); break; \
183 case IDLE: DNS_HISTOGRAM(basename "_IDLE", time); break; \
184 default: NOTREACHED(); break; \
185 } \
186 DNS_HISTOGRAM(basename, time); \
187 } while (0)
188
189// Record time from Request creation until a valid DNS response.
190void RecordTotalTime(bool had_dns_config,
191 bool speculative,
192 base::TimeDelta duration) {
193 if (had_dns_config) {
194 if (speculative) {
195 DNS_HISTOGRAM("AsyncDNS.TotalTime_speculative", duration);
196 } else {
197 DNS_HISTOGRAM("AsyncDNS.TotalTime", duration);
198 }
199 } else {
200 if (speculative) {
201 DNS_HISTOGRAM("DNS.TotalTime_speculative", duration);
202 } else {
203 DNS_HISTOGRAM("DNS.TotalTime", duration);
204 }
205 }
206}
207
[email protected]1339a2a22012-10-17 08:39:43208void RecordTTL(base::TimeDelta ttl) {
209 UMA_HISTOGRAM_CUSTOM_TIMES("AsyncDNS.TTL", ttl,
210 base::TimeDelta::FromSeconds(1),
211 base::TimeDelta::FromDays(1), 100);
212}
213
[email protected]d7b9a2b2012-05-31 22:31:19214//-----------------------------------------------------------------------------
215
[email protected]0f292de02012-02-01 22:28:20216// Wraps call to SystemHostResolverProc as an instance of HostResolverProc.
217// TODO(szym): This should probably be declared in host_resolver_proc.h.
218class CallSystemHostResolverProc : public HostResolverProc {
219 public:
220 CallSystemHostResolverProc() : HostResolverProc(NULL) {}
221 virtual int Resolve(const std::string& hostname,
222 AddressFamily address_family,
223 HostResolverFlags host_resolver_flags,
[email protected]b3601bc22012-02-21 21:23:20224 AddressList* addr_list,
[email protected]0f292de02012-02-01 22:28:20225 int* os_error) OVERRIDE {
226 return SystemHostResolverProc(hostname,
227 address_family,
228 host_resolver_flags,
[email protected]b3601bc22012-02-21 21:23:20229 addr_list,
[email protected]0f292de02012-02-01 22:28:20230 os_error);
[email protected]b59ff372009-07-15 22:04:32231 }
[email protected]a9813302012-04-28 09:29:28232
233 protected:
234 virtual ~CallSystemHostResolverProc() {}
[email protected]0f292de02012-02-01 22:28:20235};
[email protected]b59ff372009-07-15 22:04:32236
[email protected]7054e78f2012-05-07 21:44:56237void EnsurePortOnAddressList(uint16 port, AddressList* list) {
238 DCHECK(list);
239 if (list->empty() || list->front().port() == port)
240 return;
241 SetPortOnAddressList(port, list);
242}
243
[email protected]cd565142012-06-12 16:21:45244// Creates NetLog parameters when the resolve failed.
245base::Value* NetLogProcTaskFailedCallback(uint32 attempt_number,
246 int net_error,
247 int os_error,
248 NetLog::LogLevel /* log_level */) {
249 DictionaryValue* dict = new DictionaryValue();
250 if (attempt_number)
251 dict->SetInteger("attempt_number", attempt_number);
[email protected]21526002010-05-16 19:42:46252
[email protected]cd565142012-06-12 16:21:45253 dict->SetInteger("net_error", net_error);
[email protected]13024882011-05-18 23:19:16254
[email protected]cd565142012-06-12 16:21:45255 if (os_error) {
256 dict->SetInteger("os_error", os_error);
[email protected]21526002010-05-16 19:42:46257#if defined(OS_POSIX)
[email protected]cd565142012-06-12 16:21:45258 dict->SetString("os_error_string", gai_strerror(os_error));
[email protected]21526002010-05-16 19:42:46259#elif defined(OS_WIN)
[email protected]cd565142012-06-12 16:21:45260 // Map the error code to a human-readable string.
261 LPWSTR error_string = NULL;
262 int size = FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
263 FORMAT_MESSAGE_FROM_SYSTEM,
264 0, // Use the internal message table.
265 os_error,
266 0, // Use default language.
267 (LPWSTR)&error_string,
268 0, // Buffer size.
269 0); // Arguments (unused).
270 dict->SetString("os_error_string", WideToUTF8(error_string));
271 LocalFree(error_string);
[email protected]21526002010-05-16 19:42:46272#endif
[email protected]21526002010-05-16 19:42:46273 }
274
[email protected]cd565142012-06-12 16:21:45275 return dict;
276}
[email protected]a9813302012-04-28 09:29:28277
[email protected]cd565142012-06-12 16:21:45278// Creates NetLog parameters when the DnsTask failed.
279base::Value* NetLogDnsTaskFailedCallback(int net_error,
280 int dns_error,
281 NetLog::LogLevel /* log_level */) {
282 DictionaryValue* dict = new DictionaryValue();
283 dict->SetInteger("net_error", net_error);
284 if (dns_error)
285 dict->SetInteger("dns_error", dns_error);
286 return dict;
[email protected]ee094b82010-08-24 15:55:51287};
288
[email protected]cd565142012-06-12 16:21:45289// Creates NetLog parameters containing the information in a RequestInfo object,
290// along with the associated NetLog::Source.
291base::Value* NetLogRequestInfoCallback(const NetLog::Source& source,
292 const HostResolver::RequestInfo* info,
293 NetLog::LogLevel /* log_level */) {
294 DictionaryValue* dict = new DictionaryValue();
295 source.AddToEventParameters(dict);
[email protected]b3601bc22012-02-21 21:23:20296
[email protected]cd565142012-06-12 16:21:45297 dict->SetString("host", info->host_port_pair().ToString());
298 dict->SetInteger("address_family",
299 static_cast<int>(info->address_family()));
300 dict->SetBoolean("allow_cached_response", info->allow_cached_response());
301 dict->SetBoolean("is_speculative", info->is_speculative());
302 dict->SetInteger("priority", info->priority());
303 return dict;
304}
[email protected]b3601bc22012-02-21 21:23:20305
[email protected]cd565142012-06-12 16:21:45306// Creates NetLog parameters for the creation of a HostResolverImpl::Job.
307base::Value* NetLogJobCreationCallback(const NetLog::Source& source,
308 const std::string* host,
309 NetLog::LogLevel /* log_level */) {
310 DictionaryValue* dict = new DictionaryValue();
311 source.AddToEventParameters(dict);
312 dict->SetString("host", *host);
313 return dict;
314}
[email protected]a9813302012-04-28 09:29:28315
[email protected]cd565142012-06-12 16:21:45316// Creates NetLog parameters for HOST_RESOLVER_IMPL_JOB_ATTACH/DETACH events.
317base::Value* NetLogJobAttachCallback(const NetLog::Source& source,
318 RequestPriority priority,
319 NetLog::LogLevel /* log_level */) {
320 DictionaryValue* dict = new DictionaryValue();
321 source.AddToEventParameters(dict);
322 dict->SetInteger("priority", priority);
323 return dict;
324}
[email protected]b3601bc22012-02-21 21:23:20325
[email protected]cd565142012-06-12 16:21:45326// Creates NetLog parameters for the DNS_CONFIG_CHANGED event.
327base::Value* NetLogDnsConfigCallback(const DnsConfig* config,
328 NetLog::LogLevel /* log_level */) {
329 return config->ToValue();
330}
[email protected]b4481b222012-03-16 17:13:11331
[email protected]0f292de02012-02-01 22:28:20332// The logging routines are defined here because some requests are resolved
333// without a Request object.
334
335// Logs when a request has just been started.
336void LogStartRequest(const BoundNetLog& source_net_log,
337 const BoundNetLog& request_net_log,
338 const HostResolver::RequestInfo& info) {
339 source_net_log.BeginEvent(
340 NetLog::TYPE_HOST_RESOLVER_IMPL,
[email protected]cd565142012-06-12 16:21:45341 request_net_log.source().ToEventParametersCallback());
[email protected]0f292de02012-02-01 22:28:20342
343 request_net_log.BeginEvent(
344 NetLog::TYPE_HOST_RESOLVER_IMPL_REQUEST,
[email protected]cd565142012-06-12 16:21:45345 base::Bind(&NetLogRequestInfoCallback, source_net_log.source(), &info));
[email protected]0f292de02012-02-01 22:28:20346}
347
348// Logs when a request has just completed (before its callback is run).
349void LogFinishRequest(const BoundNetLog& source_net_log,
350 const BoundNetLog& request_net_log,
351 const HostResolver::RequestInfo& info,
[email protected]b3601bc22012-02-21 21:23:20352 int net_error) {
353 request_net_log.EndEventWithNetErrorCode(
354 NetLog::TYPE_HOST_RESOLVER_IMPL_REQUEST, net_error);
[email protected]4da911f2012-06-14 19:45:20355 source_net_log.EndEvent(NetLog::TYPE_HOST_RESOLVER_IMPL);
[email protected]0f292de02012-02-01 22:28:20356}
357
358// Logs when a request has been cancelled.
359void LogCancelRequest(const BoundNetLog& source_net_log,
360 const BoundNetLog& request_net_log,
361 const HostResolverImpl::RequestInfo& info) {
[email protected]4da911f2012-06-14 19:45:20362 request_net_log.AddEvent(NetLog::TYPE_CANCELLED);
363 request_net_log.EndEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_REQUEST);
364 source_net_log.EndEvent(NetLog::TYPE_HOST_RESOLVER_IMPL);
[email protected]0f292de02012-02-01 22:28:20365}
366
[email protected]b59ff372009-07-15 22:04:32367//-----------------------------------------------------------------------------
368
[email protected]0f292de02012-02-01 22:28:20369// Keeps track of the highest priority.
370class PriorityTracker {
371 public:
[email protected]8c98d002012-07-18 19:02:27372 explicit PriorityTracker(RequestPriority initial_priority)
373 : highest_priority_(initial_priority), total_count_(0) {
[email protected]0f292de02012-02-01 22:28:20374 memset(counts_, 0, sizeof(counts_));
375 }
376
377 RequestPriority highest_priority() const {
378 return highest_priority_;
379 }
380
381 size_t total_count() const {
382 return total_count_;
383 }
384
385 void Add(RequestPriority req_priority) {
386 ++total_count_;
387 ++counts_[req_priority];
[email protected]31ae7ab2012-04-24 21:09:05388 if (highest_priority_ < req_priority)
[email protected]0f292de02012-02-01 22:28:20389 highest_priority_ = req_priority;
390 }
391
392 void Remove(RequestPriority req_priority) {
393 DCHECK_GT(total_count_, 0u);
394 DCHECK_GT(counts_[req_priority], 0u);
395 --total_count_;
396 --counts_[req_priority];
397 size_t i;
[email protected]31ae7ab2012-04-24 21:09:05398 for (i = highest_priority_; i > MINIMUM_PRIORITY && !counts_[i]; --i);
[email protected]0f292de02012-02-01 22:28:20399 highest_priority_ = static_cast<RequestPriority>(i);
400
[email protected]31ae7ab2012-04-24 21:09:05401 // In absence of requests, default to MINIMUM_PRIORITY.
402 if (total_count_ == 0)
403 DCHECK_EQ(MINIMUM_PRIORITY, highest_priority_);
[email protected]0f292de02012-02-01 22:28:20404 }
405
406 private:
407 RequestPriority highest_priority_;
408 size_t total_count_;
409 size_t counts_[NUM_PRIORITIES];
410};
411
412//-----------------------------------------------------------------------------
413
414HostResolver* CreateHostResolver(size_t max_concurrent_resolves,
415 size_t max_retry_attempts,
[email protected]b3601bc22012-02-21 21:23:20416 HostCache* cache,
[email protected]d7b9a2b2012-05-31 22:31:19417 scoped_ptr<DnsClient> dns_client,
[email protected]0f292de02012-02-01 22:28:20418 NetLog* net_log) {
419 if (max_concurrent_resolves == HostResolver::kDefaultParallelism)
420 max_concurrent_resolves = kDefaultMaxProcTasks;
421
422 // TODO(szym): Add experiments with reserved slots for higher priority
423 // requests.
424
425 PrioritizedDispatcher::Limits limits(NUM_PRIORITIES, max_concurrent_resolves);
426
427 HostResolverImpl* resolver = new HostResolverImpl(
[email protected]b3601bc22012-02-21 21:23:20428 cache,
[email protected]0f292de02012-02-01 22:28:20429 limits,
430 HostResolverImpl::ProcTaskParams(NULL, max_retry_attempts),
[email protected]d7b9a2b2012-05-31 22:31:19431 dns_client.Pass(),
[email protected]0f292de02012-02-01 22:28:20432 net_log);
433
434 return resolver;
435}
436
437} // anonymous namespace
438
439//-----------------------------------------------------------------------------
440
441HostResolver* CreateSystemHostResolver(size_t max_concurrent_resolves,
442 size_t max_retry_attempts,
443 NetLog* net_log) {
444 return CreateHostResolver(max_concurrent_resolves,
445 max_retry_attempts,
[email protected]b3601bc22012-02-21 21:23:20446 HostCache::CreateDefaultCache(),
[email protected]d7b9a2b2012-05-31 22:31:19447 scoped_ptr<DnsClient>(NULL),
[email protected]0f292de02012-02-01 22:28:20448 net_log);
449}
450
451HostResolver* CreateNonCachingSystemHostResolver(size_t max_concurrent_resolves,
452 size_t max_retry_attempts,
453 NetLog* net_log) {
454 return CreateHostResolver(max_concurrent_resolves,
455 max_retry_attempts,
[email protected]b3601bc22012-02-21 21:23:20456 NULL,
[email protected]d7b9a2b2012-05-31 22:31:19457 scoped_ptr<DnsClient>(NULL),
[email protected]b3601bc22012-02-21 21:23:20458 net_log);
459}
460
461HostResolver* CreateAsyncHostResolver(size_t max_concurrent_resolves,
462 size_t max_retry_attempts,
463 NetLog* net_log) {
[email protected]33c814862012-09-18 15:16:03464#if !defined(ENABLE_BUILT_IN_DNS)
465 NOTREACHED();
466 return NULL;
467#else
[email protected]b3601bc22012-02-21 21:23:20468 return CreateHostResolver(max_concurrent_resolves,
469 max_retry_attempts,
470 HostCache::CreateDefaultCache(),
[email protected]d7b9a2b2012-05-31 22:31:19471 DnsClient::CreateClient(net_log),
[email protected]0f292de02012-02-01 22:28:20472 net_log);
[email protected]33c814862012-09-18 15:16:03473#endif // !defined(ENABLE_BUILT_IN_DNS)
[email protected]0f292de02012-02-01 22:28:20474}
475
476//-----------------------------------------------------------------------------
477
478// Holds the data for a request that could not be completed synchronously.
479// It is owned by a Job. Canceled Requests are only marked as canceled rather
480// than removed from the Job's |requests_| list.
[email protected]b59ff372009-07-15 22:04:32481class HostResolverImpl::Request {
482 public:
[email protected]ee094b82010-08-24 15:55:51483 Request(const BoundNetLog& source_net_log,
484 const BoundNetLog& request_net_log,
[email protected]54e13772009-08-14 03:01:09485 const RequestInfo& info,
[email protected]aa22b242011-11-16 18:58:29486 const CompletionCallback& callback,
[email protected]b59ff372009-07-15 22:04:32487 AddressList* addresses)
[email protected]ee094b82010-08-24 15:55:51488 : source_net_log_(source_net_log),
489 request_net_log_(request_net_log),
[email protected]54e13772009-08-14 03:01:09490 info_(info),
491 job_(NULL),
492 callback_(callback),
[email protected]51b9a6b2012-06-25 21:50:29493 addresses_(addresses),
494 request_time_(base::TimeTicks::Now()) {
[email protected]54e13772009-08-14 03:01:09495 }
[email protected]b59ff372009-07-15 22:04:32496
[email protected]0f292de02012-02-01 22:28:20497 // Mark the request as canceled.
498 void MarkAsCanceled() {
[email protected]b59ff372009-07-15 22:04:32499 job_ = NULL;
[email protected]b59ff372009-07-15 22:04:32500 addresses_ = NULL;
[email protected]aa22b242011-11-16 18:58:29501 callback_.Reset();
[email protected]b59ff372009-07-15 22:04:32502 }
503
[email protected]0f292de02012-02-01 22:28:20504 bool was_canceled() const {
[email protected]aa22b242011-11-16 18:58:29505 return callback_.is_null();
[email protected]b59ff372009-07-15 22:04:32506 }
507
508 void set_job(Job* job) {
[email protected]0f292de02012-02-01 22:28:20509 DCHECK(job);
[email protected]b59ff372009-07-15 22:04:32510 // Identify which job the request is waiting on.
511 job_ = job;
512 }
513
[email protected]0f292de02012-02-01 22:28:20514 // Prepare final AddressList and call completion callback.
[email protected]b3601bc22012-02-21 21:23:20515 void OnComplete(int error, const AddressList& addr_list) {
[email protected]51b9a6b2012-06-25 21:50:29516 DCHECK(!was_canceled());
[email protected]7054e78f2012-05-07 21:44:56517 if (error == OK) {
518 *addresses_ = addr_list;
519 EnsurePortOnAddressList(info_.port(), addresses_);
520 }
[email protected]aa22b242011-11-16 18:58:29521 CompletionCallback callback = callback_;
[email protected]0f292de02012-02-01 22:28:20522 MarkAsCanceled();
[email protected]aa22b242011-11-16 18:58:29523 callback.Run(error);
[email protected]b59ff372009-07-15 22:04:32524 }
525
[email protected]b59ff372009-07-15 22:04:32526 Job* job() const {
527 return job_;
528 }
529
[email protected]0f292de02012-02-01 22:28:20530 // NetLog for the source, passed in HostResolver::Resolve.
[email protected]ee094b82010-08-24 15:55:51531 const BoundNetLog& source_net_log() {
532 return source_net_log_;
533 }
534
[email protected]0f292de02012-02-01 22:28:20535 // NetLog for this request.
[email protected]ee094b82010-08-24 15:55:51536 const BoundNetLog& request_net_log() {
537 return request_net_log_;
[email protected]54e13772009-08-14 03:01:09538 }
539
[email protected]b59ff372009-07-15 22:04:32540 const RequestInfo& info() const {
541 return info_;
542 }
543
[email protected]51b9a6b2012-06-25 21:50:29544 base::TimeTicks request_time() const {
545 return request_time_;
546 }
547
[email protected]b59ff372009-07-15 22:04:32548 private:
[email protected]ee094b82010-08-24 15:55:51549 BoundNetLog source_net_log_;
550 BoundNetLog request_net_log_;
[email protected]54e13772009-08-14 03:01:09551
[email protected]b59ff372009-07-15 22:04:32552 // The request info that started the request.
553 RequestInfo info_;
554
[email protected]0f292de02012-02-01 22:28:20555 // The resolve job that this request is dependent on.
[email protected]b59ff372009-07-15 22:04:32556 Job* job_;
557
558 // The user's callback to invoke when the request completes.
[email protected]aa22b242011-11-16 18:58:29559 CompletionCallback callback_;
[email protected]b59ff372009-07-15 22:04:32560
561 // The address list to save result into.
562 AddressList* addresses_;
563
[email protected]51b9a6b2012-06-25 21:50:29564 const base::TimeTicks request_time_;
565
[email protected]b59ff372009-07-15 22:04:32566 DISALLOW_COPY_AND_ASSIGN(Request);
567};
568
[email protected]1e9bbd22010-10-15 16:42:45569//------------------------------------------------------------------------------
570
[email protected]0f292de02012-02-01 22:28:20571// Calls HostResolverProc on the WorkerPool. Performs retries if necessary.
572//
573// Whenever we try to resolve the host, we post a delayed task to check if host
574// resolution (OnLookupComplete) is completed or not. If the original attempt
575// hasn't completed, then we start another attempt for host resolution. We take
576// the results from the first attempt that finishes and ignore the results from
577// all other attempts.
578//
579// TODO(szym): Move to separate source file for testing and mocking.
580//
581class HostResolverImpl::ProcTask
582 : public base::RefCountedThreadSafe<HostResolverImpl::ProcTask> {
[email protected]b59ff372009-07-15 22:04:32583 public:
[email protected]b3601bc22012-02-21 21:23:20584 typedef base::Callback<void(int net_error,
585 const AddressList& addr_list)> Callback;
[email protected]b59ff372009-07-15 22:04:32586
[email protected]0f292de02012-02-01 22:28:20587 ProcTask(const Key& key,
588 const ProcTaskParams& params,
589 const Callback& callback,
590 const BoundNetLog& job_net_log)
591 : key_(key),
592 params_(params),
593 callback_(callback),
594 origin_loop_(base::MessageLoopProxy::current()),
595 attempt_number_(0),
596 completed_attempt_number_(0),
597 completed_attempt_error_(ERR_UNEXPECTED),
598 had_non_speculative_request_(false),
[email protected]b3601bc22012-02-21 21:23:20599 net_log_(job_net_log) {
[email protected]0f292de02012-02-01 22:28:20600 if (!params_.resolver_proc)
601 params_.resolver_proc = HostResolverProc::GetDefault();
602 // If default is unset, use the system proc.
603 if (!params_.resolver_proc)
604 params_.resolver_proc = new CallSystemHostResolverProc();
[email protected]b59ff372009-07-15 22:04:32605 }
606
[email protected]b59ff372009-07-15 22:04:32607 void Start() {
[email protected]3e9d9cc2011-05-03 21:08:15608 DCHECK(origin_loop_->BelongsToCurrentThread());
[email protected]4da911f2012-06-14 19:45:20609 net_log_.BeginEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_PROC_TASK);
[email protected]189163e2011-05-11 01:48:54610 StartLookupAttempt();
611 }
[email protected]252b699b2010-02-05 21:38:06612
[email protected]0f292de02012-02-01 22:28:20613 // Cancels this ProcTask. It will be orphaned. Any outstanding resolve
614 // attempts running on worker threads will continue running. Only once all the
615 // attempts complete will the final reference to this ProcTask be released.
616 void Cancel() {
617 DCHECK(origin_loop_->BelongsToCurrentThread());
618
[email protected]0adcb2b2012-08-15 21:30:46619 if (was_canceled() || was_completed())
[email protected]0f292de02012-02-01 22:28:20620 return;
621
[email protected]0f292de02012-02-01 22:28:20622 callback_.Reset();
[email protected]4da911f2012-06-14 19:45:20623 net_log_.EndEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_PROC_TASK);
[email protected]0f292de02012-02-01 22:28:20624 }
625
626 void set_had_non_speculative_request() {
627 DCHECK(origin_loop_->BelongsToCurrentThread());
628 had_non_speculative_request_ = true;
629 }
630
631 bool was_canceled() const {
632 DCHECK(origin_loop_->BelongsToCurrentThread());
633 return callback_.is_null();
634 }
635
636 bool was_completed() const {
637 DCHECK(origin_loop_->BelongsToCurrentThread());
638 return completed_attempt_number_ > 0;
639 }
640
641 private:
[email protected]a9813302012-04-28 09:29:28642 friend class base::RefCountedThreadSafe<ProcTask>;
643 ~ProcTask() {}
644
[email protected]189163e2011-05-11 01:48:54645 void StartLookupAttempt() {
646 DCHECK(origin_loop_->BelongsToCurrentThread());
647 base::TimeTicks start_time = base::TimeTicks::Now();
648 ++attempt_number_;
649 // Dispatch the lookup attempt to a worker thread.
650 if (!base::WorkerPool::PostTask(
651 FROM_HERE,
[email protected]0f292de02012-02-01 22:28:20652 base::Bind(&ProcTask::DoLookup, this, start_time, attempt_number_),
[email protected]189163e2011-05-11 01:48:54653 true)) {
[email protected]b59ff372009-07-15 22:04:32654 NOTREACHED();
655
656 // Since we could be running within Resolve() right now, we can't just
657 // call OnLookupComplete(). Instead we must wait until Resolve() has
658 // returned (IO_PENDING).
[email protected]3e9d9cc2011-05-03 21:08:15659 origin_loop_->PostTask(
[email protected]189163e2011-05-11 01:48:54660 FROM_HERE,
[email protected]0f292de02012-02-01 22:28:20661 base::Bind(&ProcTask::OnLookupComplete, this, AddressList(),
[email protected]33152acc2011-10-20 23:37:12662 start_time, attempt_number_, ERR_UNEXPECTED, 0));
[email protected]189163e2011-05-11 01:48:54663 return;
[email protected]b59ff372009-07-15 22:04:32664 }
[email protected]13024882011-05-18 23:19:16665
666 net_log_.AddEvent(
667 NetLog::TYPE_HOST_RESOLVER_IMPL_ATTEMPT_STARTED,
[email protected]cd565142012-06-12 16:21:45668 NetLog::IntegerCallback("attempt_number", attempt_number_));
[email protected]13024882011-05-18 23:19:16669
[email protected]0f292de02012-02-01 22:28:20670 // If we don't get the results within a given time, RetryIfNotComplete
671 // will start a new attempt on a different worker thread if none of our
672 // outstanding attempts have completed yet.
673 if (attempt_number_ <= params_.max_retry_attempts) {
[email protected]06ef6d92011-05-19 04:24:58674 origin_loop_->PostDelayedTask(
675 FROM_HERE,
[email protected]0f292de02012-02-01 22:28:20676 base::Bind(&ProcTask::RetryIfNotComplete, this),
[email protected]7e560102012-03-08 20:58:42677 params_.unresponsive_delay);
[email protected]06ef6d92011-05-19 04:24:58678 }
[email protected]b59ff372009-07-15 22:04:32679 }
680
[email protected]6c710ee2010-05-07 07:51:16681 // WARNING: This code runs inside a worker pool. The shutdown code cannot
682 // wait for it to finish, so we must be very careful here about using other
683 // objects (like MessageLoops, Singletons, etc). During shutdown these objects
[email protected]189163e2011-05-11 01:48:54684 // may no longer exist. Multiple DoLookups() could be running in parallel, so
685 // any state inside of |this| must not mutate .
686 void DoLookup(const base::TimeTicks& start_time,
687 const uint32 attempt_number) {
688 AddressList results;
689 int os_error = 0;
[email protected]b59ff372009-07-15 22:04:32690 // Running on the worker thread
[email protected]0f292de02012-02-01 22:28:20691 int error = params_.resolver_proc->Resolve(key_.hostname,
692 key_.address_family,
693 key_.host_resolver_flags,
694 &results,
695 &os_error);
[email protected]b59ff372009-07-15 22:04:32696
[email protected]189163e2011-05-11 01:48:54697 origin_loop_->PostTask(
698 FROM_HERE,
[email protected]0f292de02012-02-01 22:28:20699 base::Bind(&ProcTask::OnLookupComplete, this, results, start_time,
[email protected]33152acc2011-10-20 23:37:12700 attempt_number, error, os_error));
[email protected]189163e2011-05-11 01:48:54701 }
702
[email protected]0f292de02012-02-01 22:28:20703 // Makes next attempt if DoLookup() has not finished (runs on origin thread).
704 void RetryIfNotComplete() {
[email protected]189163e2011-05-11 01:48:54705 DCHECK(origin_loop_->BelongsToCurrentThread());
706
[email protected]0f292de02012-02-01 22:28:20707 if (was_completed() || was_canceled())
[email protected]189163e2011-05-11 01:48:54708 return;
709
[email protected]0f292de02012-02-01 22:28:20710 params_.unresponsive_delay *= params_.retry_factor;
[email protected]189163e2011-05-11 01:48:54711 StartLookupAttempt();
[email protected]b59ff372009-07-15 22:04:32712 }
713
714 // Callback for when DoLookup() completes (runs on origin thread).
[email protected]189163e2011-05-11 01:48:54715 void OnLookupComplete(const AddressList& results,
716 const base::TimeTicks& start_time,
717 const uint32 attempt_number,
718 int error,
719 const int os_error) {
[email protected]3e9d9cc2011-05-03 21:08:15720 DCHECK(origin_loop_->BelongsToCurrentThread());
[email protected]7054e78f2012-05-07 21:44:56721 DCHECK(error || !results.empty());
[email protected]189163e2011-05-11 01:48:54722
723 bool was_retry_attempt = attempt_number > 1;
724
[email protected]2d3b7762010-10-09 00:35:47725 // Ideally the following code would be part of host_resolver_proc.cc,
[email protected]b3601bc22012-02-21 21:23:20726 // however it isn't safe to call NetworkChangeNotifier from worker threads.
727 // So we do it here on the IO thread instead.
[email protected]189163e2011-05-11 01:48:54728 if (error != OK && NetworkChangeNotifier::IsOffline())
729 error = ERR_INTERNET_DISCONNECTED;
[email protected]2d3b7762010-10-09 00:35:47730
[email protected]b3601bc22012-02-21 21:23:20731 // If this is the first attempt that is finishing later, then record data
732 // for the first attempt. Won't contaminate with retry attempt's data.
[email protected]189163e2011-05-11 01:48:54733 if (!was_retry_attempt)
734 RecordPerformanceHistograms(start_time, error, os_error);
735
736 RecordAttemptHistograms(start_time, attempt_number, error, os_error);
[email protected]f2d8c4212010-02-02 00:56:35737
[email protected]0f292de02012-02-01 22:28:20738 if (was_canceled())
[email protected]b59ff372009-07-15 22:04:32739 return;
740
[email protected]cd565142012-06-12 16:21:45741 NetLog::ParametersCallback net_log_callback;
[email protected]0f292de02012-02-01 22:28:20742 if (error != OK) {
[email protected]cd565142012-06-12 16:21:45743 net_log_callback = base::Bind(&NetLogProcTaskFailedCallback,
744 attempt_number,
745 error,
746 os_error);
[email protected]0f292de02012-02-01 22:28:20747 } else {
[email protected]cd565142012-06-12 16:21:45748 net_log_callback = NetLog::IntegerCallback("attempt_number",
749 attempt_number);
[email protected]0f292de02012-02-01 22:28:20750 }
[email protected]cd565142012-06-12 16:21:45751 net_log_.AddEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_ATTEMPT_FINISHED,
752 net_log_callback);
[email protected]0f292de02012-02-01 22:28:20753
754 if (was_completed())
755 return;
756
757 // Copy the results from the first worker thread that resolves the host.
758 results_ = results;
759 completed_attempt_number_ = attempt_number;
760 completed_attempt_error_ = error;
761
[email protected]e87b8b512011-06-14 22:12:52762 if (was_retry_attempt) {
763 // If retry attempt finishes before 1st attempt, then get stats on how
764 // much time is saved by having spawned an extra attempt.
765 retry_attempt_finished_time_ = base::TimeTicks::Now();
766 }
767
[email protected]189163e2011-05-11 01:48:54768 if (error != OK) {
[email protected]cd565142012-06-12 16:21:45769 net_log_callback = base::Bind(&NetLogProcTaskFailedCallback,
770 0, error, os_error);
[email protected]ee094b82010-08-24 15:55:51771 } else {
[email protected]cd565142012-06-12 16:21:45772 net_log_callback = results_.CreateNetLogCallback();
[email protected]ee094b82010-08-24 15:55:51773 }
[email protected]cd565142012-06-12 16:21:45774 net_log_.EndEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_PROC_TASK,
775 net_log_callback);
[email protected]ee094b82010-08-24 15:55:51776
[email protected]b3601bc22012-02-21 21:23:20777 callback_.Run(error, results_);
[email protected]b59ff372009-07-15 22:04:32778 }
779
[email protected]189163e2011-05-11 01:48:54780 void RecordPerformanceHistograms(const base::TimeTicks& start_time,
781 const int error,
782 const int os_error) const {
[email protected]3e9d9cc2011-05-03 21:08:15783 DCHECK(origin_loop_->BelongsToCurrentThread());
[email protected]1e9bbd22010-10-15 16:42:45784 enum Category { // Used in HISTOGRAM_ENUMERATION.
785 RESOLVE_SUCCESS,
786 RESOLVE_FAIL,
787 RESOLVE_SPECULATIVE_SUCCESS,
788 RESOLVE_SPECULATIVE_FAIL,
789 RESOLVE_MAX, // Bounding value.
790 };
791 int category = RESOLVE_MAX; // Illegal value for later DCHECK only.
792
[email protected]189163e2011-05-11 01:48:54793 base::TimeDelta duration = base::TimeTicks::Now() - start_time;
794 if (error == OK) {
[email protected]1e9bbd22010-10-15 16:42:45795 if (had_non_speculative_request_) {
796 category = RESOLVE_SUCCESS;
797 DNS_HISTOGRAM("DNS.ResolveSuccess", duration);
798 } else {
799 category = RESOLVE_SPECULATIVE_SUCCESS;
800 DNS_HISTOGRAM("DNS.ResolveSpeculativeSuccess", duration);
801 }
[email protected]7e96d792011-06-10 17:08:23802
[email protected]78eac2a2012-03-14 19:09:27803 // Log DNS lookups based on |address_family|. This will help us determine
[email protected]7e96d792011-06-10 17:08:23804 // if IPv4 or IPv4/6 lookups are faster or slower.
805 switch(key_.address_family) {
806 case ADDRESS_FAMILY_IPV4:
807 DNS_HISTOGRAM("DNS.ResolveSuccess_FAMILY_IPV4", duration);
808 break;
809 case ADDRESS_FAMILY_IPV6:
810 DNS_HISTOGRAM("DNS.ResolveSuccess_FAMILY_IPV6", duration);
811 break;
812 case ADDRESS_FAMILY_UNSPECIFIED:
813 DNS_HISTOGRAM("DNS.ResolveSuccess_FAMILY_UNSPEC", duration);
814 break;
815 }
[email protected]1e9bbd22010-10-15 16:42:45816 } else {
817 if (had_non_speculative_request_) {
818 category = RESOLVE_FAIL;
819 DNS_HISTOGRAM("DNS.ResolveFail", duration);
820 } else {
821 category = RESOLVE_SPECULATIVE_FAIL;
822 DNS_HISTOGRAM("DNS.ResolveSpeculativeFail", duration);
823 }
[email protected]78eac2a2012-03-14 19:09:27824 // Log DNS lookups based on |address_family|. This will help us determine
[email protected]7e96d792011-06-10 17:08:23825 // if IPv4 or IPv4/6 lookups are faster or slower.
826 switch(key_.address_family) {
827 case ADDRESS_FAMILY_IPV4:
828 DNS_HISTOGRAM("DNS.ResolveFail_FAMILY_IPV4", duration);
829 break;
830 case ADDRESS_FAMILY_IPV6:
831 DNS_HISTOGRAM("DNS.ResolveFail_FAMILY_IPV6", duration);
832 break;
833 case ADDRESS_FAMILY_UNSPECIFIED:
834 DNS_HISTOGRAM("DNS.ResolveFail_FAMILY_UNSPEC", duration);
835 break;
836 }
[email protected]c833e322010-10-16 23:51:36837 UMA_HISTOGRAM_CUSTOM_ENUMERATION(kOSErrorsForGetAddrinfoHistogramName,
[email protected]189163e2011-05-11 01:48:54838 std::abs(os_error),
[email protected]1e9bbd22010-10-15 16:42:45839 GetAllGetAddrinfoOSErrors());
840 }
[email protected]051b6ab2010-10-18 16:50:46841 DCHECK_LT(category, static_cast<int>(RESOLVE_MAX)); // Be sure it was set.
[email protected]1e9bbd22010-10-15 16:42:45842
843 UMA_HISTOGRAM_ENUMERATION("DNS.ResolveCategory", category, RESOLVE_MAX);
844
[email protected]edafd4c2011-05-10 17:18:53845 static const bool show_speculative_experiment_histograms =
846 base::FieldTrialList::TrialExists("DnsImpact");
[email protected]ecd95ae2010-10-20 23:58:17847 if (show_speculative_experiment_histograms) {
[email protected]1e9bbd22010-10-15 16:42:45848 UMA_HISTOGRAM_ENUMERATION(
849 base::FieldTrial::MakeName("DNS.ResolveCategory", "DnsImpact"),
850 category, RESOLVE_MAX);
851 if (RESOLVE_SUCCESS == category) {
852 DNS_HISTOGRAM(base::FieldTrial::MakeName("DNS.ResolveSuccess",
853 "DnsImpact"), duration);
854 }
855 }
[email protected]edafd4c2011-05-10 17:18:53856 static const bool show_parallelism_experiment_histograms =
857 base::FieldTrialList::TrialExists("DnsParallelism");
[email protected]ecd95ae2010-10-20 23:58:17858 if (show_parallelism_experiment_histograms) {
859 UMA_HISTOGRAM_ENUMERATION(
860 base::FieldTrial::MakeName("DNS.ResolveCategory", "DnsParallelism"),
861 category, RESOLVE_MAX);
862 if (RESOLVE_SUCCESS == category) {
863 DNS_HISTOGRAM(base::FieldTrial::MakeName("DNS.ResolveSuccess",
864 "DnsParallelism"), duration);
865 }
866 }
[email protected]1e9bbd22010-10-15 16:42:45867 }
868
[email protected]189163e2011-05-11 01:48:54869 void RecordAttemptHistograms(const base::TimeTicks& start_time,
870 const uint32 attempt_number,
871 const int error,
872 const int os_error) const {
[email protected]0f292de02012-02-01 22:28:20873 DCHECK(origin_loop_->BelongsToCurrentThread());
[email protected]189163e2011-05-11 01:48:54874 bool first_attempt_to_complete =
875 completed_attempt_number_ == attempt_number;
[email protected]e87b8b512011-06-14 22:12:52876 bool is_first_attempt = (attempt_number == 1);
[email protected]1e9bbd22010-10-15 16:42:45877
[email protected]189163e2011-05-11 01:48:54878 if (first_attempt_to_complete) {
879 // If this was first attempt to complete, then record the resolution
880 // status of the attempt.
881 if (completed_attempt_error_ == OK) {
882 UMA_HISTOGRAM_ENUMERATION(
883 "DNS.AttemptFirstSuccess", attempt_number, 100);
884 } else {
885 UMA_HISTOGRAM_ENUMERATION(
886 "DNS.AttemptFirstFailure", attempt_number, 100);
887 }
888 }
889
890 if (error == OK)
891 UMA_HISTOGRAM_ENUMERATION("DNS.AttemptSuccess", attempt_number, 100);
892 else
893 UMA_HISTOGRAM_ENUMERATION("DNS.AttemptFailure", attempt_number, 100);
894
[email protected]e87b8b512011-06-14 22:12:52895 // If first attempt didn't finish before retry attempt, then calculate stats
896 // on how much time is saved by having spawned an extra attempt.
[email protected]0f292de02012-02-01 22:28:20897 if (!first_attempt_to_complete && is_first_attempt && !was_canceled()) {
[email protected]e87b8b512011-06-14 22:12:52898 DNS_HISTOGRAM("DNS.AttemptTimeSavedByRetry",
899 base::TimeTicks::Now() - retry_attempt_finished_time_);
900 }
901
[email protected]0f292de02012-02-01 22:28:20902 if (was_canceled() || !first_attempt_to_complete) {
[email protected]189163e2011-05-11 01:48:54903 // Count those attempts which completed after the job was already canceled
904 // OR after the job was already completed by an earlier attempt (so in
905 // effect).
906 UMA_HISTOGRAM_ENUMERATION("DNS.AttemptDiscarded", attempt_number, 100);
907
[email protected]0f292de02012-02-01 22:28:20908 // Record if job is canceled.
909 if (was_canceled())
[email protected]189163e2011-05-11 01:48:54910 UMA_HISTOGRAM_ENUMERATION("DNS.AttemptCancelled", attempt_number, 100);
911 }
912
913 base::TimeDelta duration = base::TimeTicks::Now() - start_time;
914 if (error == OK)
915 DNS_HISTOGRAM("DNS.AttemptSuccessDuration", duration);
916 else
917 DNS_HISTOGRAM("DNS.AttemptFailDuration", duration);
918 }
[email protected]1e9bbd22010-10-15 16:42:45919
[email protected]b59ff372009-07-15 22:04:32920 // Set on the origin thread, read on the worker thread.
[email protected]123ab1e32009-10-21 19:12:57921 Key key_;
[email protected]b59ff372009-07-15 22:04:32922
[email protected]0f292de02012-02-01 22:28:20923 // Holds an owning reference to the HostResolverProc that we are going to use.
[email protected]b59ff372009-07-15 22:04:32924 // This may not be the current resolver procedure by the time we call
925 // ResolveAddrInfo, but that's OK... we'll use it anyways, and the owning
926 // reference ensures that it remains valid until we are done.
[email protected]0f292de02012-02-01 22:28:20927 ProcTaskParams params_;
[email protected]b59ff372009-07-15 22:04:32928
[email protected]0f292de02012-02-01 22:28:20929 // The listener to the results of this ProcTask.
930 Callback callback_;
931
932 // Used to post ourselves onto the origin thread.
933 scoped_refptr<base::MessageLoopProxy> origin_loop_;
[email protected]189163e2011-05-11 01:48:54934
935 // Keeps track of the number of attempts we have made so far to resolve the
936 // host. Whenever we start an attempt to resolve the host, we increase this
937 // number.
938 uint32 attempt_number_;
939
940 // The index of the attempt which finished first (or 0 if the job is still in
941 // progress).
942 uint32 completed_attempt_number_;
943
944 // The result (a net error code) from the first attempt to complete.
945 int completed_attempt_error_;
[email protected]252b699b2010-02-05 21:38:06946
[email protected]e87b8b512011-06-14 22:12:52947 // The time when retry attempt was finished.
948 base::TimeTicks retry_attempt_finished_time_;
949
[email protected]252b699b2010-02-05 21:38:06950 // True if a non-speculative request was ever attached to this job
[email protected]0f292de02012-02-01 22:28:20951 // (regardless of whether or not it was later canceled.
[email protected]252b699b2010-02-05 21:38:06952 // This boolean is used for histogramming the duration of jobs used to
953 // service non-speculative requests.
954 bool had_non_speculative_request_;
955
[email protected]b59ff372009-07-15 22:04:32956 AddressList results_;
957
[email protected]ee094b82010-08-24 15:55:51958 BoundNetLog net_log_;
959
[email protected]0f292de02012-02-01 22:28:20960 DISALLOW_COPY_AND_ASSIGN(ProcTask);
[email protected]b59ff372009-07-15 22:04:32961};
962
963//-----------------------------------------------------------------------------
964
[email protected]0f292de02012-02-01 22:28:20965// Represents a request to the worker pool for a "probe for IPv6 support" call.
[email protected]b3601bc22012-02-21 21:23:20966//
967// TODO(szym): This could also be replaced with PostTaskAndReply and Callbacks.
[email protected]0f8f1b432010-03-16 19:06:03968class HostResolverImpl::IPv6ProbeJob
969 : public base::RefCountedThreadSafe<HostResolverImpl::IPv6ProbeJob> {
970 public:
[email protected]ae8e80f2012-07-19 21:08:33971 IPv6ProbeJob(HostResolverImpl* resolver, NetLog* net_log)
[email protected]0f8f1b432010-03-16 19:06:03972 : resolver_(resolver),
[email protected]ae8e80f2012-07-19 21:08:33973 origin_loop_(base::MessageLoopProxy::current()),
974 net_log_(BoundNetLog::Make(net_log, NetLog::SOURCE_IPV6_PROBE_JOB)) {
[email protected]3e9d9cc2011-05-03 21:08:15975 DCHECK(resolver);
[email protected]0f8f1b432010-03-16 19:06:03976 }
977
978 void Start() {
[email protected]3e9d9cc2011-05-03 21:08:15979 DCHECK(origin_loop_->BelongsToCurrentThread());
[email protected]0f292de02012-02-01 22:28:20980 if (was_canceled())
[email protected]a9af7112010-05-08 00:56:01981 return;
[email protected]ae8e80f2012-07-19 21:08:33982 net_log_.BeginEvent(NetLog::TYPE_IPV6_PROBE_RUNNING);
[email protected]f092e64b2010-03-17 00:39:18983 const bool kIsSlow = true;
[email protected]ac9ba8fe2010-12-30 18:08:36984 base::WorkerPool::PostTask(
[email protected]33152acc2011-10-20 23:37:12985 FROM_HERE, base::Bind(&IPv6ProbeJob::DoProbe, this), kIsSlow);
[email protected]0f8f1b432010-03-16 19:06:03986 }
987
988 // Cancels the current job.
989 void Cancel() {
[email protected]3e9d9cc2011-05-03 21:08:15990 DCHECK(origin_loop_->BelongsToCurrentThread());
[email protected]0f292de02012-02-01 22:28:20991 if (was_canceled())
[email protected]a9af7112010-05-08 00:56:01992 return;
[email protected]ae8e80f2012-07-19 21:08:33993 net_log_.AddEvent(NetLog::TYPE_CANCELLED);
[email protected]0f8f1b432010-03-16 19:06:03994 resolver_ = NULL; // Read/write ONLY on origin thread.
[email protected]0f8f1b432010-03-16 19:06:03995 }
996
[email protected]0f8f1b432010-03-16 19:06:03997 private:
998 friend class base::RefCountedThreadSafe<HostResolverImpl::IPv6ProbeJob>;
999
1000 ~IPv6ProbeJob() {
1001 }
1002
[email protected]ae8e80f2012-07-19 21:08:331003 // Returns true if cancelled or if probe results have already been received
1004 // on the origin thread.
[email protected]0f292de02012-02-01 22:28:201005 bool was_canceled() const {
[email protected]3e9d9cc2011-05-03 21:08:151006 DCHECK(origin_loop_->BelongsToCurrentThread());
1007 return !resolver_;
[email protected]a9af7112010-05-08 00:56:011008 }
1009
[email protected]0f8f1b432010-03-16 19:06:031010 // Run on worker thread.
1011 void DoProbe() {
1012 // Do actual testing on this thread, as it takes 40-100ms.
[email protected]3e9d9cc2011-05-03 21:08:151013 origin_loop_->PostTask(
1014 FROM_HERE,
[email protected]ae8e80f2012-07-19 21:08:331015 base::Bind(&IPv6ProbeJob::OnProbeComplete, this, TestIPv6Support()));
[email protected]0f8f1b432010-03-16 19:06:031016 }
1017
[email protected]3e9d9cc2011-05-03 21:08:151018 // Callback for when DoProbe() completes.
[email protected]ae8e80f2012-07-19 21:08:331019 void OnProbeComplete(const IPv6SupportResult& support_result) {
[email protected]3e9d9cc2011-05-03 21:08:151020 DCHECK(origin_loop_->BelongsToCurrentThread());
[email protected]ae8e80f2012-07-19 21:08:331021 net_log_.EndEvent(
1022 NetLog::TYPE_IPV6_PROBE_RUNNING,
1023 base::Bind(&IPv6SupportResult::ToNetLogValue,
1024 base::Unretained(&support_result)));
[email protected]0f292de02012-02-01 22:28:201025 if (was_canceled())
[email protected]a9af7112010-05-08 00:56:011026 return;
[email protected]ae8e80f2012-07-19 21:08:331027
1028 // Clear |resolver_| so that no cancel event is logged.
1029 HostResolverImpl* resolver = resolver_;
1030 resolver_ = NULL;
1031
1032 resolver->IPv6ProbeSetDefaultAddressFamily(
1033 support_result.ipv6_supported ? ADDRESS_FAMILY_UNSPECIFIED
1034 : ADDRESS_FAMILY_IPV4);
[email protected]0f8f1b432010-03-16 19:06:031035 }
1036
[email protected]0f8f1b432010-03-16 19:06:031037 // Used/set only on origin thread.
1038 HostResolverImpl* resolver_;
1039
1040 // Used to post ourselves onto the origin thread.
[email protected]3e9d9cc2011-05-03 21:08:151041 scoped_refptr<base::MessageLoopProxy> origin_loop_;
[email protected]0f8f1b432010-03-16 19:06:031042
[email protected]ae8e80f2012-07-19 21:08:331043 BoundNetLog net_log_;
1044
[email protected]0f8f1b432010-03-16 19:06:031045 DISALLOW_COPY_AND_ASSIGN(IPv6ProbeJob);
1046};
1047
1048//-----------------------------------------------------------------------------
1049
[email protected]b3601bc22012-02-21 21:23:201050// Resolves the hostname using DnsTransaction.
1051// TODO(szym): This could be moved to separate source file as well.
[email protected]0adcb2b2012-08-15 21:30:461052class HostResolverImpl::DnsTask : public base::SupportsWeakPtr<DnsTask> {
[email protected]b3601bc22012-02-21 21:23:201053 public:
1054 typedef base::Callback<void(int net_error,
1055 const AddressList& addr_list,
1056 base::TimeDelta ttl)> Callback;
1057
[email protected]0adcb2b2012-08-15 21:30:461058 DnsTask(DnsClient* client,
[email protected]b3601bc22012-02-21 21:23:201059 const Key& key,
1060 const Callback& callback,
1061 const BoundNetLog& job_net_log)
[email protected]0adcb2b2012-08-15 21:30:461062 : client_(client),
1063 family_(key.address_family),
1064 callback_(callback),
1065 net_log_(job_net_log) {
1066 DCHECK(client);
[email protected]b3601bc22012-02-21 21:23:201067 DCHECK(!callback.is_null());
1068
[email protected]0adcb2b2012-08-15 21:30:461069 // If unspecified, do IPv4 first, because suffix search will be faster.
1070 uint16 qtype = (family_ == ADDRESS_FAMILY_IPV6) ?
1071 dns_protocol::kTypeAAAA :
1072 dns_protocol::kTypeA;
1073 transaction_ = client_->GetTransactionFactory()->CreateTransaction(
[email protected]b3601bc22012-02-21 21:23:201074 key.hostname,
1075 qtype,
[email protected]1def74c2012-03-22 20:07:001076 base::Bind(&DnsTask::OnTransactionComplete, base::Unretained(this),
[email protected]0adcb2b2012-08-15 21:30:461077 true /* first_query */, base::TimeTicks::Now()),
[email protected]b3601bc22012-02-21 21:23:201078 net_log_);
[email protected]b3601bc22012-02-21 21:23:201079 }
1080
1081 int Start() {
[email protected]4da911f2012-06-14 19:45:201082 net_log_.BeginEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_DNS_TASK);
[email protected]b3601bc22012-02-21 21:23:201083 return transaction_->Start();
1084 }
1085
[email protected]0adcb2b2012-08-15 21:30:461086 private:
1087 void OnTransactionComplete(bool first_query,
1088 const base::TimeTicks& start_time,
[email protected]1def74c2012-03-22 20:07:001089 DnsTransaction* transaction,
[email protected]b3601bc22012-02-21 21:23:201090 int net_error,
1091 const DnsResponse* response) {
[email protected]add76532012-03-30 14:47:471092 DCHECK(transaction);
[email protected]b3601bc22012-02-21 21:23:201093 // Run |callback_| last since the owning Job will then delete this DnsTask.
[email protected]0adcb2b2012-08-15 21:30:461094 if (net_error != OK) {
[email protected]708d0cc2012-08-14 23:32:291095 DNS_HISTOGRAM("AsyncDNS.TransactionFailure",
[email protected]6c411902012-08-14 22:36:361096 base::TimeTicks::Now() - start_time);
[email protected]0adcb2b2012-08-15 21:30:461097 OnFailure(net_error, DnsResponse::DNS_PARSE_OK);
1098 return;
[email protected]6c411902012-08-14 22:36:361099 }
[email protected]0adcb2b2012-08-15 21:30:461100
1101 CHECK(response);
1102 DNS_HISTOGRAM("AsyncDNS.TransactionSuccess",
1103 base::TimeTicks::Now() - start_time);
1104 AddressList addr_list;
1105 base::TimeDelta ttl;
1106 DnsResponse::Result result = response->ParseToAddressList(&addr_list, &ttl);
1107 UMA_HISTOGRAM_ENUMERATION("AsyncDNS.ParseToAddressList",
1108 result,
1109 DnsResponse::DNS_PARSE_RESULT_MAX);
1110 if (result != DnsResponse::DNS_PARSE_OK) {
1111 // Fail even if the other query succeeds.
1112 OnFailure(ERR_DNS_MALFORMED_RESPONSE, result);
1113 return;
1114 }
1115
1116 bool needs_sort = false;
1117 if (first_query) {
1118 DCHECK(client_->GetConfig()) <<
1119 "Transaction should have been aborted when config changed!";
1120 if (family_ == ADDRESS_FAMILY_IPV6) {
1121 needs_sort = (addr_list.size() > 1);
1122 } else if (family_ == ADDRESS_FAMILY_UNSPECIFIED) {
1123 first_addr_list_ = addr_list;
1124 first_ttl_ = ttl;
1125 // Use fully-qualified domain name to avoid search.
1126 transaction_ = client_->GetTransactionFactory()->CreateTransaction(
1127 response->GetDottedName() + ".",
1128 dns_protocol::kTypeAAAA,
1129 base::Bind(&DnsTask::OnTransactionComplete, base::Unretained(this),
1130 false /* first_query */, base::TimeTicks::Now()),
1131 net_log_);
1132 net_error = transaction_->Start();
1133 if (net_error != ERR_IO_PENDING)
1134 OnFailure(net_error, DnsResponse::DNS_PARSE_OK);
1135 return;
1136 }
1137 } else {
1138 DCHECK_EQ(ADDRESS_FAMILY_UNSPECIFIED, family_);
1139 bool has_ipv6_addresses = !addr_list.empty();
1140 if (!first_addr_list_.empty()) {
1141 ttl = std::min(ttl, first_ttl_);
1142 // Place IPv4 addresses after IPv6.
1143 addr_list.insert(addr_list.end(), first_addr_list_.begin(),
1144 first_addr_list_.end());
1145 }
1146 needs_sort = (has_ipv6_addresses && addr_list.size() > 1);
1147 }
1148
1149 if (addr_list.empty()) {
1150 // TODO(szym): Don't fallback to ProcTask in this case.
1151 OnFailure(ERR_NAME_NOT_RESOLVED, DnsResponse::DNS_PARSE_OK);
1152 return;
1153 }
1154
1155 if (needs_sort) {
1156 // Sort could complete synchronously.
1157 client_->GetAddressSorter()->Sort(
1158 addr_list,
[email protected]4589a3a2012-09-20 20:57:071159 base::Bind(&DnsTask::OnSortComplete,
1160 AsWeakPtr(),
[email protected]0adcb2b2012-08-15 21:30:461161 base::TimeTicks::Now(),
1162 ttl));
1163 } else {
1164 OnSuccess(addr_list, ttl);
1165 }
1166 }
1167
1168 void OnSortComplete(base::TimeTicks start_time,
1169 base::TimeDelta ttl,
1170 bool success,
1171 const AddressList& addr_list) {
1172 if (!success) {
1173 DNS_HISTOGRAM("AsyncDNS.SortFailure",
1174 base::TimeTicks::Now() - start_time);
1175 OnFailure(ERR_DNS_SORT_ERROR, DnsResponse::DNS_PARSE_OK);
1176 return;
1177 }
1178
1179 DNS_HISTOGRAM("AsyncDNS.SortSuccess",
1180 base::TimeTicks::Now() - start_time);
1181
1182 // AddressSorter prunes unusable destinations.
1183 if (addr_list.empty()) {
1184 LOG(WARNING) << "Address list empty after RFC3484 sort";
1185 OnFailure(ERR_NAME_NOT_RESOLVED, DnsResponse::DNS_PARSE_OK);
1186 return;
1187 }
1188
1189 OnSuccess(addr_list, ttl);
1190 }
1191
1192 void OnFailure(int net_error, DnsResponse::Result result) {
1193 DCHECK_NE(OK, net_error);
[email protected]cd565142012-06-12 16:21:451194 net_log_.EndEvent(
1195 NetLog::TYPE_HOST_RESOLVER_IMPL_DNS_TASK,
1196 base::Bind(&NetLogDnsTaskFailedCallback, net_error, result));
[email protected]b3601bc22012-02-21 21:23:201197 callback_.Run(net_error, AddressList(), base::TimeDelta());
1198 }
1199
[email protected]0adcb2b2012-08-15 21:30:461200 void OnSuccess(const AddressList& addr_list, base::TimeDelta ttl) {
1201 net_log_.EndEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_DNS_TASK,
1202 addr_list.CreateNetLogCallback());
1203 callback_.Run(OK, addr_list, ttl);
1204 }
1205
1206 DnsClient* client_;
1207 AddressFamily family_;
[email protected]b3601bc22012-02-21 21:23:201208 // The listener to the results of this DnsTask.
1209 Callback callback_;
[email protected]b3601bc22012-02-21 21:23:201210 const BoundNetLog net_log_;
1211
1212 scoped_ptr<DnsTransaction> transaction_;
[email protected]0adcb2b2012-08-15 21:30:461213
1214 // Results from the first transaction. Used only if |family_| is unspecified.
1215 AddressList first_addr_list_;
1216 base::TimeDelta first_ttl_;
1217
1218 DISALLOW_COPY_AND_ASSIGN(DnsTask);
[email protected]b3601bc22012-02-21 21:23:201219};
1220
1221//-----------------------------------------------------------------------------
1222
[email protected]0f292de02012-02-01 22:28:201223// Aggregates all Requests for the same Key. Dispatched via PriorityDispatch.
[email protected]0f292de02012-02-01 22:28:201224class HostResolverImpl::Job : public PrioritizedDispatcher::Job {
[email protected]68ad3ee2010-01-30 03:45:391225 public:
[email protected]0f292de02012-02-01 22:28:201226 // Creates new job for |key| where |request_net_log| is bound to the
[email protected]16ee26d2012-03-08 03:34:351227 // request that spawned it.
[email protected]0f292de02012-02-01 22:28:201228 Job(HostResolverImpl* resolver,
1229 const Key& key,
[email protected]8c98d002012-07-18 19:02:271230 RequestPriority priority,
[email protected]16ee26d2012-03-08 03:34:351231 const BoundNetLog& request_net_log)
[email protected]4589a3a2012-09-20 20:57:071232 : resolver_(resolver->weak_ptr_factory_.GetWeakPtr()),
[email protected]0f292de02012-02-01 22:28:201233 key_(key),
[email protected]8c98d002012-07-18 19:02:271234 priority_tracker_(priority),
[email protected]0f292de02012-02-01 22:28:201235 had_non_speculative_request_(false),
[email protected]51b9a6b2012-06-25 21:50:291236 had_dns_config_(false),
[email protected]1d932852012-06-19 19:40:331237 dns_task_error_(OK),
[email protected]51b9a6b2012-06-25 21:50:291238 creation_time_(base::TimeTicks::Now()),
1239 priority_change_time_(creation_time_),
[email protected]0f292de02012-02-01 22:28:201240 net_log_(BoundNetLog::Make(request_net_log.net_log(),
[email protected]b3601bc22012-02-21 21:23:201241 NetLog::SOURCE_HOST_RESOLVER_IMPL_JOB)) {
[email protected]4da911f2012-06-14 19:45:201242 request_net_log.AddEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_CREATE_JOB);
[email protected]0f292de02012-02-01 22:28:201243
1244 net_log_.BeginEvent(
1245 NetLog::TYPE_HOST_RESOLVER_IMPL_JOB,
[email protected]cd565142012-06-12 16:21:451246 base::Bind(&NetLogJobCreationCallback,
1247 request_net_log.source(),
1248 &key_.hostname));
[email protected]68ad3ee2010-01-30 03:45:391249 }
1250
[email protected]0f292de02012-02-01 22:28:201251 virtual ~Job() {
[email protected]b3601bc22012-02-21 21:23:201252 if (is_running()) {
1253 // |resolver_| was destroyed with this Job still in flight.
1254 // Clean-up, record in the log, but don't run any callbacks.
1255 if (is_proc_running()) {
[email protected]0f292de02012-02-01 22:28:201256 proc_task_->Cancel();
1257 proc_task_ = NULL;
[email protected]0f292de02012-02-01 22:28:201258 }
[email protected]16ee26d2012-03-08 03:34:351259 // Clean up now for nice NetLog.
1260 dns_task_.reset(NULL);
[email protected]b3601bc22012-02-21 21:23:201261 net_log_.EndEventWithNetErrorCode(NetLog::TYPE_HOST_RESOLVER_IMPL_JOB,
1262 ERR_ABORTED);
1263 } else if (is_queued()) {
[email protected]57a48d32012-03-03 00:04:551264 // |resolver_| was destroyed without running this Job.
[email protected]16ee26d2012-03-08 03:34:351265 // TODO(szym): is there any benefit in having this distinction?
[email protected]4da911f2012-06-14 19:45:201266 net_log_.AddEvent(NetLog::TYPE_CANCELLED);
1267 net_log_.EndEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_JOB);
[email protected]68ad3ee2010-01-30 03:45:391268 }
[email protected]b3601bc22012-02-21 21:23:201269 // else CompleteRequests logged EndEvent.
[email protected]68ad3ee2010-01-30 03:45:391270
[email protected]b3601bc22012-02-21 21:23:201271 // Log any remaining Requests as cancelled.
1272 for (RequestsList::const_iterator it = requests_.begin();
1273 it != requests_.end(); ++it) {
1274 Request* req = *it;
1275 if (req->was_canceled())
1276 continue;
1277 DCHECK_EQ(this, req->job());
1278 LogCancelRequest(req->source_net_log(), req->request_net_log(),
1279 req->info());
1280 }
[email protected]68ad3ee2010-01-30 03:45:391281 }
1282
[email protected]16ee26d2012-03-08 03:34:351283 // Add this job to the dispatcher.
[email protected]8c98d002012-07-18 19:02:271284 void Schedule() {
1285 handle_ = resolver_->dispatcher_.Add(this, priority());
[email protected]16ee26d2012-03-08 03:34:351286 }
1287
[email protected]b3601bc22012-02-21 21:23:201288 void AddRequest(scoped_ptr<Request> req) {
[email protected]0f292de02012-02-01 22:28:201289 DCHECK_EQ(key_.hostname, req->info().hostname());
1290
1291 req->set_job(this);
[email protected]0f292de02012-02-01 22:28:201292 priority_tracker_.Add(req->info().priority());
1293
1294 req->request_net_log().AddEvent(
1295 NetLog::TYPE_HOST_RESOLVER_IMPL_JOB_ATTACH,
[email protected]cd565142012-06-12 16:21:451296 net_log_.source().ToEventParametersCallback());
[email protected]0f292de02012-02-01 22:28:201297
1298 net_log_.AddEvent(
1299 NetLog::TYPE_HOST_RESOLVER_IMPL_JOB_REQUEST_ATTACH,
[email protected]cd565142012-06-12 16:21:451300 base::Bind(&NetLogJobAttachCallback,
1301 req->request_net_log().source(),
1302 priority()));
[email protected]0f292de02012-02-01 22:28:201303
1304 // TODO(szym): Check if this is still needed.
1305 if (!req->info().is_speculative()) {
1306 had_non_speculative_request_ = true;
1307 if (proc_task_)
1308 proc_task_->set_had_non_speculative_request();
[email protected]68ad3ee2010-01-30 03:45:391309 }
[email protected]b3601bc22012-02-21 21:23:201310
1311 requests_.push_back(req.release());
1312
[email protected]51b9a6b2012-06-25 21:50:291313 UpdatePriority();
[email protected]68ad3ee2010-01-30 03:45:391314 }
1315
[email protected]16ee26d2012-03-08 03:34:351316 // Marks |req| as cancelled. If it was the last active Request, also finishes
[email protected]0adcb2b2012-08-15 21:30:461317 // this Job, marking it as cancelled, and deletes it.
[email protected]0f292de02012-02-01 22:28:201318 void CancelRequest(Request* req) {
1319 DCHECK_EQ(key_.hostname, req->info().hostname());
1320 DCHECK(!req->was_canceled());
[email protected]16ee26d2012-03-08 03:34:351321
[email protected]0f292de02012-02-01 22:28:201322 // Don't remove it from |requests_| just mark it canceled.
1323 req->MarkAsCanceled();
1324 LogCancelRequest(req->source_net_log(), req->request_net_log(),
1325 req->info());
[email protected]16ee26d2012-03-08 03:34:351326
[email protected]0f292de02012-02-01 22:28:201327 priority_tracker_.Remove(req->info().priority());
1328 net_log_.AddEvent(
1329 NetLog::TYPE_HOST_RESOLVER_IMPL_JOB_REQUEST_DETACH,
[email protected]cd565142012-06-12 16:21:451330 base::Bind(&NetLogJobAttachCallback,
1331 req->request_net_log().source(),
1332 priority()));
[email protected]b3601bc22012-02-21 21:23:201333
[email protected]16ee26d2012-03-08 03:34:351334 if (num_active_requests() > 0) {
[email protected]51b9a6b2012-06-25 21:50:291335 UpdatePriority();
[email protected]16ee26d2012-03-08 03:34:351336 } else {
1337 // If we were called from a Request's callback within CompleteRequests,
1338 // that Request could not have been cancelled, so num_active_requests()
1339 // could not be 0. Therefore, we are not in CompleteRequests().
[email protected]1339a2a22012-10-17 08:39:431340 CompleteRequestsWithError(OK /* cancelled */);
[email protected]b3601bc22012-02-21 21:23:201341 }
[email protected]68ad3ee2010-01-30 03:45:391342 }
1343
[email protected]16ee26d2012-03-08 03:34:351344 // Called from AbortAllInProgressJobs. Completes all requests as aborted
1345 // and destroys the job.
[email protected]0f292de02012-02-01 22:28:201346 void Abort() {
[email protected]0f292de02012-02-01 22:28:201347 DCHECK(is_running());
[email protected]1339a2a22012-10-17 08:39:431348 CompleteRequestsWithError(ERR_ABORTED);
[email protected]b3601bc22012-02-21 21:23:201349 }
1350
[email protected]16ee26d2012-03-08 03:34:351351 // Called by HostResolverImpl when this job is evicted due to queue overflow.
1352 // Completes all requests and destroys the job.
1353 void OnEvicted() {
1354 DCHECK(!is_running());
1355 DCHECK(is_queued());
1356 handle_.Reset();
1357
[email protected]4da911f2012-06-14 19:45:201358 net_log_.AddEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_JOB_EVICTED);
[email protected]16ee26d2012-03-08 03:34:351359
1360 // This signals to CompleteRequests that this job never ran.
[email protected]1339a2a22012-10-17 08:39:431361 CompleteRequestsWithError(ERR_HOST_RESOLVER_QUEUE_TOO_LARGE);
[email protected]16ee26d2012-03-08 03:34:351362 }
1363
[email protected]78eac2a2012-03-14 19:09:271364 // Attempts to serve the job from HOSTS. Returns true if succeeded and
1365 // this Job was destroyed.
1366 bool ServeFromHosts() {
1367 DCHECK_GT(num_active_requests(), 0u);
1368 AddressList addr_list;
1369 if (resolver_->ServeFromHosts(key(),
[email protected]3cb676a12012-06-30 15:46:031370 requests_.front()->info(),
[email protected]78eac2a2012-03-14 19:09:271371 &addr_list)) {
1372 // This will destroy the Job.
[email protected]1339a2a22012-10-17 08:39:431373 CompleteRequests(OK, addr_list, base::TimeDelta(), false /* true_ttl */);
[email protected]78eac2a2012-03-14 19:09:271374 return true;
1375 }
1376 return false;
1377 }
1378
[email protected]b4481b222012-03-16 17:13:111379 const Key key() const {
1380 return key_;
1381 }
1382
1383 bool is_queued() const {
1384 return !handle_.is_null();
1385 }
1386
1387 bool is_running() const {
1388 return is_dns_running() || is_proc_running();
1389 }
1390
[email protected]16ee26d2012-03-08 03:34:351391 private:
[email protected]51b9a6b2012-06-25 21:50:291392 void UpdatePriority() {
1393 if (is_queued()) {
1394 if (priority() != static_cast<RequestPriority>(handle_.priority()))
1395 priority_change_time_ = base::TimeTicks::Now();
1396 handle_ = resolver_->dispatcher_.ChangePriority(handle_, priority());
1397 }
1398 }
1399
[email protected]16ee26d2012-03-08 03:34:351400 // PriorityDispatch::Job:
[email protected]0f292de02012-02-01 22:28:201401 virtual void Start() OVERRIDE {
1402 DCHECK(!is_running());
[email protected]b3601bc22012-02-21 21:23:201403 handle_.Reset();
[email protected]0f292de02012-02-01 22:28:201404
[email protected]4da911f2012-06-14 19:45:201405 net_log_.AddEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_JOB_STARTED);
[email protected]0f292de02012-02-01 22:28:201406
[email protected]51b9a6b2012-06-25 21:50:291407 had_dns_config_ = resolver_->HaveDnsConfig();
1408
1409 base::TimeTicks now = base::TimeTicks::Now();
1410 base::TimeDelta queue_time = now - creation_time_;
1411 base::TimeDelta queue_time_after_change = now - priority_change_time_;
1412
1413 if (had_dns_config_) {
1414 DNS_HISTOGRAM_BY_PRIORITY("AsyncDNS.JobQueueTime", priority(),
1415 queue_time);
1416 DNS_HISTOGRAM_BY_PRIORITY("AsyncDNS.JobQueueTimeAfterChange", priority(),
1417 queue_time_after_change);
1418 } else {
1419 DNS_HISTOGRAM_BY_PRIORITY("DNS.JobQueueTime", priority(), queue_time);
1420 DNS_HISTOGRAM_BY_PRIORITY("DNS.JobQueueTimeAfterChange", priority(),
1421 queue_time_after_change);
1422 }
1423
[email protected]1d932852012-06-19 19:40:331424 // Caution: Job::Start must not complete synchronously.
[email protected]51b9a6b2012-06-25 21:50:291425 if (had_dns_config_ && !ResemblesMulticastDNSName(key_.hostname)) {
[email protected]b3601bc22012-02-21 21:23:201426 StartDnsTask();
1427 } else {
1428 StartProcTask();
1429 }
1430 }
1431
[email protected]b3601bc22012-02-21 21:23:201432 // TODO(szym): Since DnsTransaction does not consume threads, we can increase
1433 // the limits on |dispatcher_|. But in order to keep the number of WorkerPool
1434 // threads low, we will need to use an "inner" PrioritizedDispatcher with
1435 // tighter limits.
1436 void StartProcTask() {
[email protected]16ee26d2012-03-08 03:34:351437 DCHECK(!is_dns_running());
[email protected]0f292de02012-02-01 22:28:201438 proc_task_ = new ProcTask(
1439 key_,
1440 resolver_->proc_params_,
1441 base::Bind(&Job::OnProcTaskComplete, base::Unretained(this)),
1442 net_log_);
1443
1444 if (had_non_speculative_request_)
1445 proc_task_->set_had_non_speculative_request();
1446 // Start() could be called from within Resolve(), hence it must NOT directly
1447 // call OnProcTaskComplete, for example, on synchronous failure.
1448 proc_task_->Start();
[email protected]68ad3ee2010-01-30 03:45:391449 }
1450
[email protected]0f292de02012-02-01 22:28:201451 // Called by ProcTask when it completes.
[email protected]b3601bc22012-02-21 21:23:201452 void OnProcTaskComplete(int net_error, const AddressList& addr_list) {
1453 DCHECK(is_proc_running());
[email protected]68ad3ee2010-01-30 03:45:391454
[email protected]1d932852012-06-19 19:40:331455 if (dns_task_error_ != OK) {
[email protected]1def74c2012-03-22 20:07:001456 if (net_error == OK) {
[email protected]1d932852012-06-19 19:40:331457 if ((dns_task_error_ == ERR_NAME_NOT_RESOLVED) &&
1458 ResemblesNetBIOSName(key_.hostname)) {
1459 UmaAsyncDnsResolveStatus(RESOLVE_STATUS_SUSPECT_NETBIOS);
1460 } else {
1461 UmaAsyncDnsResolveStatus(RESOLVE_STATUS_PROC_SUCCESS);
1462 }
1463 UMA_HISTOGRAM_CUSTOM_ENUMERATION("AsyncDNS.ResolveError",
1464 std::abs(dns_task_error_),
1465 GetAllErrorCodesForUma());
[email protected]1def74c2012-03-22 20:07:001466 } else {
1467 UmaAsyncDnsResolveStatus(RESOLVE_STATUS_FAIL);
1468 }
1469 }
1470
[email protected]1339a2a22012-10-17 08:39:431471 base::TimeDelta ttl =
1472 base::TimeDelta::FromSeconds(kNegativeCacheEntryTTLSeconds);
[email protected]b3601bc22012-02-21 21:23:201473 if (net_error == OK)
1474 ttl = base::TimeDelta::FromSeconds(kCacheEntryTTLSeconds);
[email protected]68ad3ee2010-01-30 03:45:391475
[email protected]1339a2a22012-10-17 08:39:431476 CompleteRequests(net_error, addr_list, ttl, false /* true_ttl */);
[email protected]b3601bc22012-02-21 21:23:201477 }
1478
1479 void StartDnsTask() {
[email protected]78eac2a2012-03-14 19:09:271480 DCHECK(resolver_->HaveDnsConfig());
[email protected]b3601bc22012-02-21 21:23:201481 dns_task_.reset(new DnsTask(
[email protected]0adcb2b2012-08-15 21:30:461482 resolver_->dns_client_.get(),
[email protected]b3601bc22012-02-21 21:23:201483 key_,
1484 base::Bind(&Job::OnDnsTaskComplete, base::Unretained(this)),
1485 net_log_));
1486
1487 int rv = dns_task_->Start();
1488 if (rv != ERR_IO_PENDING) {
1489 DCHECK_NE(OK, rv);
[email protected]51b9a6b2012-06-25 21:50:291490 dns_task_error_ = rv;
[email protected]b3601bc22012-02-21 21:23:201491 dns_task_.reset();
1492 StartProcTask();
1493 }
1494 }
1495
1496 // Called by DnsTask when it completes.
1497 void OnDnsTaskComplete(int net_error,
1498 const AddressList& addr_list,
1499 base::TimeDelta ttl) {
1500 DCHECK(is_dns_running());
[email protected]b3601bc22012-02-21 21:23:201501
1502 if (net_error != OK) {
[email protected]1d932852012-06-19 19:40:331503 dns_task_error_ = net_error;
[email protected]16ee26d2012-03-08 03:34:351504 dns_task_.reset();
[email protected]78eac2a2012-03-14 19:09:271505
1506 // TODO(szym): Run ServeFromHosts now if nsswitch.conf says so.
1507 // http://crbug.com/117655
1508
[email protected]b3601bc22012-02-21 21:23:201509 // TODO(szym): Some net errors indicate lack of connectivity. Starting
1510 // ProcTask in that case is a waste of time.
1511 StartProcTask();
1512 return;
1513 }
1514
[email protected]1def74c2012-03-22 20:07:001515 UmaAsyncDnsResolveStatus(RESOLVE_STATUS_DNS_SUCCESS);
[email protected]1339a2a22012-10-17 08:39:431516 RecordTTL(ttl);
[email protected]0adcb2b2012-08-15 21:30:461517
[email protected]1339a2a22012-10-17 08:39:431518 CompleteRequests(net_error, addr_list, ttl, true /* true_ttl */);
[email protected]b3601bc22012-02-21 21:23:201519 }
1520
[email protected]16ee26d2012-03-08 03:34:351521 // Performs Job's last rites. Completes all Requests. Deletes this.
[email protected]b3601bc22012-02-21 21:23:201522 void CompleteRequests(int net_error,
1523 const AddressList& addr_list,
[email protected]1339a2a22012-10-17 08:39:431524 base::TimeDelta ttl,
1525 bool true_ttl) {
[email protected]b3601bc22012-02-21 21:23:201526 CHECK(resolver_);
[email protected]b3601bc22012-02-21 21:23:201527
[email protected]16ee26d2012-03-08 03:34:351528 // This job must be removed from resolver's |jobs_| now to make room for a
1529 // new job with the same key in case one of the OnComplete callbacks decides
1530 // to spawn one. Consequently, the job deletes itself when CompleteRequests
1531 // is done.
1532 scoped_ptr<Job> self_deleter(this);
1533
1534 resolver_->RemoveJob(this);
1535
[email protected]1339a2a22012-10-17 08:39:431536 // |addr_list| will be destroyed with |proc_task_| and |dns_task_|.
[email protected]b3601bc22012-02-21 21:23:201537 AddressList list = addr_list;
[email protected]16ee26d2012-03-08 03:34:351538
1539 if (is_running()) {
1540 DCHECK(!is_queued());
1541 if (is_proc_running()) {
1542 proc_task_->Cancel();
1543 proc_task_ = NULL;
1544 }
1545 dns_task_.reset();
1546
1547 // Signal dispatcher that a slot has opened.
1548 resolver_->dispatcher_.OnJobFinished();
1549 } else if (is_queued()) {
1550 resolver_->dispatcher_.Cancel(handle_);
1551 handle_.Reset();
1552 }
1553
1554 if (num_active_requests() == 0) {
[email protected]4da911f2012-06-14 19:45:201555 net_log_.AddEvent(NetLog::TYPE_CANCELLED);
[email protected]16ee26d2012-03-08 03:34:351556 net_log_.EndEventWithNetErrorCode(NetLog::TYPE_HOST_RESOLVER_IMPL_JOB,
1557 OK);
1558 return;
1559 }
[email protected]b3601bc22012-02-21 21:23:201560
1561 net_log_.EndEventWithNetErrorCode(NetLog::TYPE_HOST_RESOLVER_IMPL_JOB,
1562 net_error);
[email protected]68ad3ee2010-01-30 03:45:391563
[email protected]78eac2a2012-03-14 19:09:271564 DCHECK(!requests_.empty());
1565
[email protected]d7b9a2b2012-05-31 22:31:191566 if (net_error == OK) {
[email protected]3cb676a12012-06-30 15:46:031567 SetPortOnAddressList(requests_.front()->info().port(), &list);
[email protected]d7b9a2b2012-05-31 22:31:191568 // Record this histogram here, when we know the system has a valid DNS
1569 // configuration.
[email protected]539df6c2012-06-19 21:21:291570 UMA_HISTOGRAM_BOOLEAN("AsyncDNS.HaveDnsConfig",
1571 resolver_->received_dns_config_);
[email protected]d7b9a2b2012-05-31 22:31:191572 }
[email protected]16ee26d2012-03-08 03:34:351573
[email protected]51b9a6b2012-06-25 21:50:291574 bool did_complete = (net_error != ERR_ABORTED) &&
1575 (net_error != ERR_HOST_RESOLVER_QUEUE_TOO_LARGE);
[email protected]1339a2a22012-10-17 08:39:431576 if (did_complete) {
1577 HostCache::Entry entry = true_ttl ?
1578 HostCache::Entry(net_error, list, ttl) :
1579 HostCache::Entry(net_error, list);
1580 resolver_->CacheResult(key_, entry, ttl);
1581 }
[email protected]16ee26d2012-03-08 03:34:351582
[email protected]0f292de02012-02-01 22:28:201583 // Complete all of the requests that were attached to the job.
1584 for (RequestsList::const_iterator it = requests_.begin();
1585 it != requests_.end(); ++it) {
1586 Request* req = *it;
1587
1588 if (req->was_canceled())
1589 continue;
1590
1591 DCHECK_EQ(this, req->job());
1592 // Update the net log and notify registered observers.
1593 LogFinishRequest(req->source_net_log(), req->request_net_log(),
[email protected]b3601bc22012-02-21 21:23:201594 req->info(), net_error);
[email protected]51b9a6b2012-06-25 21:50:291595 if (did_complete) {
1596 // Record effective total time from creation to completion.
1597 RecordTotalTime(had_dns_config_, req->info().is_speculative(),
1598 base::TimeTicks::Now() - req->request_time());
1599 }
[email protected]b3601bc22012-02-21 21:23:201600 req->OnComplete(net_error, list);
[email protected]0f292de02012-02-01 22:28:201601
1602 // Check if the resolver was destroyed as a result of running the
1603 // callback. If it was, we could continue, but we choose to bail.
1604 if (!resolver_)
1605 return;
1606 }
1607 }
1608
[email protected]1339a2a22012-10-17 08:39:431609 // Convenience wrapper for CompleteRequests in case of failure.
1610 void CompleteRequestsWithError(int net_error) {
1611 CompleteRequests(net_error, AddressList(), base::TimeDelta(), false);
1612 }
1613
[email protected]b4481b222012-03-16 17:13:111614 RequestPriority priority() const {
1615 return priority_tracker_.highest_priority();
1616 }
1617
1618 // Number of non-canceled requests in |requests_|.
1619 size_t num_active_requests() const {
1620 return priority_tracker_.total_count();
1621 }
1622
1623 bool is_dns_running() const {
1624 return dns_task_.get() != NULL;
1625 }
1626
1627 bool is_proc_running() const {
1628 return proc_task_.get() != NULL;
1629 }
1630
[email protected]0f292de02012-02-01 22:28:201631 base::WeakPtr<HostResolverImpl> resolver_;
1632
1633 Key key_;
1634
1635 // Tracks the highest priority across |requests_|.
1636 PriorityTracker priority_tracker_;
1637
1638 bool had_non_speculative_request_;
1639
[email protected]51b9a6b2012-06-25 21:50:291640 // Distinguishes measurements taken while DnsClient was fully configured.
1641 bool had_dns_config_;
1642
[email protected]1d932852012-06-19 19:40:331643 // Result of DnsTask.
1644 int dns_task_error_;
[email protected]1def74c2012-03-22 20:07:001645
[email protected]51b9a6b2012-06-25 21:50:291646 const base::TimeTicks creation_time_;
1647 base::TimeTicks priority_change_time_;
1648
[email protected]0f292de02012-02-01 22:28:201649 BoundNetLog net_log_;
1650
[email protected]b3601bc22012-02-21 21:23:201651 // Resolves the host using a HostResolverProc.
[email protected]0f292de02012-02-01 22:28:201652 scoped_refptr<ProcTask> proc_task_;
1653
[email protected]b3601bc22012-02-21 21:23:201654 // Resolves the host using a DnsTransaction.
1655 scoped_ptr<DnsTask> dns_task_;
1656
[email protected]0f292de02012-02-01 22:28:201657 // All Requests waiting for the result of this Job. Some can be canceled.
1658 RequestsList requests_;
1659
[email protected]16ee26d2012-03-08 03:34:351660 // A handle used in |HostResolverImpl::dispatcher_|.
[email protected]0f292de02012-02-01 22:28:201661 PrioritizedDispatcher::Handle handle_;
[email protected]68ad3ee2010-01-30 03:45:391662};
1663
1664//-----------------------------------------------------------------------------
1665
[email protected]0f292de02012-02-01 22:28:201666HostResolverImpl::ProcTaskParams::ProcTaskParams(
[email protected]e95d3aca2010-01-11 22:47:431667 HostResolverProc* resolver_proc,
[email protected]0f292de02012-02-01 22:28:201668 size_t max_retry_attempts)
1669 : resolver_proc(resolver_proc),
1670 max_retry_attempts(max_retry_attempts),
1671 unresponsive_delay(base::TimeDelta::FromMilliseconds(6000)),
1672 retry_factor(2) {
1673}
1674
1675HostResolverImpl::ProcTaskParams::~ProcTaskParams() {}
1676
1677HostResolverImpl::HostResolverImpl(
[email protected]e95d3aca2010-01-11 22:47:431678 HostCache* cache,
[email protected]0f292de02012-02-01 22:28:201679 const PrioritizedDispatcher::Limits& job_limits,
1680 const ProcTaskParams& proc_params,
[email protected]d7b9a2b2012-05-31 22:31:191681 scoped_ptr<DnsClient> dns_client,
[email protected]ee094b82010-08-24 15:55:511682 NetLog* net_log)
[email protected]112bd462009-12-10 07:23:401683 : cache_(cache),
[email protected]0f292de02012-02-01 22:28:201684 dispatcher_(job_limits),
1685 max_queued_jobs_(job_limits.total_jobs * 100u),
1686 proc_params_(proc_params),
[email protected]0c7798452009-10-26 17:59:511687 default_address_family_(ADDRESS_FAMILY_UNSPECIFIED),
[email protected]4589a3a2012-09-20 20:57:071688 weak_ptr_factory_(this),
[email protected]d7b9a2b2012-05-31 22:31:191689 dns_client_(dns_client.Pass()),
1690 received_dns_config_(false),
[email protected]2f3bc65c2010-07-23 17:47:101691 ipv6_probe_monitoring_(false),
[email protected]ee094b82010-08-24 15:55:511692 additional_resolver_flags_(0),
1693 net_log_(net_log) {
[email protected]0f292de02012-02-01 22:28:201694
1695 DCHECK_GE(dispatcher_.num_priorities(), static_cast<size_t>(NUM_PRIORITIES));
[email protected]68ad3ee2010-01-30 03:45:391696
[email protected]06ef6d92011-05-19 04:24:581697 // Maximum of 4 retry attempts for host resolution.
1698 static const size_t kDefaultMaxRetryAttempts = 4u;
1699
[email protected]0f292de02012-02-01 22:28:201700 if (proc_params_.max_retry_attempts == HostResolver::kDefaultRetryAttempts)
1701 proc_params_.max_retry_attempts = kDefaultMaxRetryAttempts;
[email protected]68ad3ee2010-01-30 03:45:391702
[email protected]b59ff372009-07-15 22:04:321703#if defined(OS_WIN)
1704 EnsureWinsockInit();
1705#endif
[email protected]23f771162011-06-02 18:37:511706#if defined(OS_POSIX) && !defined(OS_MACOSX)
[email protected]2f3bc65c2010-07-23 17:47:101707 if (HaveOnlyLoopbackAddresses())
1708 additional_resolver_flags_ |= HOST_RESOLVER_LOOPBACK_ONLY;
1709#endif
[email protected]232a5812011-03-04 22:42:081710 NetworkChangeNotifier::AddIPAddressObserver(this);
[email protected]bb0e34542012-08-31 19:52:401711 NetworkChangeNotifier::AddDNSObserver(this);
[email protected]3399b072012-09-11 19:40:261712 if (!HaveDnsConfig())
1713 OnDNSChanged();
[email protected]d7b9a2b2012-05-31 22:31:191714#if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_OPENBSD) && \
1715 !defined(OS_ANDROID)
[email protected]d7b9a2b2012-05-31 22:31:191716 EnsureDnsReloaderInit();
[email protected]46018c9d2011-09-06 03:42:341717#endif
[email protected]b59ff372009-07-15 22:04:321718}
1719
1720HostResolverImpl::~HostResolverImpl() {
[email protected]0f8f1b432010-03-16 19:06:031721 DiscardIPv6ProbeJob();
1722
[email protected]0f292de02012-02-01 22:28:201723 // This will also cancel all outstanding requests.
1724 STLDeleteValues(&jobs_);
[email protected]e95d3aca2010-01-11 22:47:431725
[email protected]232a5812011-03-04 22:42:081726 NetworkChangeNotifier::RemoveIPAddressObserver(this);
[email protected]bb0e34542012-08-31 19:52:401727 NetworkChangeNotifier::RemoveDNSObserver(this);
[email protected]b59ff372009-07-15 22:04:321728}
1729
[email protected]0f292de02012-02-01 22:28:201730void HostResolverImpl::SetMaxQueuedJobs(size_t value) {
1731 DCHECK_EQ(0u, dispatcher_.num_queued_jobs());
1732 DCHECK_GT(value, 0u);
1733 max_queued_jobs_ = value;
[email protected]be1a48b2011-01-20 00:12:131734}
1735
[email protected]684970b2009-08-14 04:54:461736int HostResolverImpl::Resolve(const RequestInfo& info,
[email protected]b59ff372009-07-15 22:04:321737 AddressList* addresses,
[email protected]aa22b242011-11-16 18:58:291738 const CompletionCallback& callback,
[email protected]684970b2009-08-14 04:54:461739 RequestHandle* out_req,
[email protected]ee094b82010-08-24 15:55:511740 const BoundNetLog& source_net_log) {
[email protected]95a214c2011-08-04 21:50:401741 DCHECK(addresses);
[email protected]1ac6af92010-06-03 21:00:141742 DCHECK(CalledOnValidThread());
[email protected]aa22b242011-11-16 18:58:291743 DCHECK_EQ(false, callback.is_null());
[email protected]1ac6af92010-06-03 21:00:141744
[email protected]ee094b82010-08-24 15:55:511745 // Make a log item for the request.
1746 BoundNetLog request_net_log = BoundNetLog::Make(net_log_,
1747 NetLog::SOURCE_HOST_RESOLVER_IMPL_REQUEST);
1748
[email protected]0f292de02012-02-01 22:28:201749 LogStartRequest(source_net_log, request_net_log, info);
[email protected]b59ff372009-07-15 22:04:321750
[email protected]123ab1e32009-10-21 19:12:571751 // Build a key that identifies the request in the cache and in the
1752 // outstanding jobs map.
[email protected]137af622010-02-05 02:14:351753 Key key = GetEffectiveKeyForRequest(info);
[email protected]123ab1e32009-10-21 19:12:571754
[email protected]287d7c22011-11-15 17:34:251755 int rv = ResolveHelper(key, info, addresses, request_net_log);
[email protected]95a214c2011-08-04 21:50:401756 if (rv != ERR_DNS_CACHE_MISS) {
[email protected]b3601bc22012-02-21 21:23:201757 LogFinishRequest(source_net_log, request_net_log, info, rv);
[email protected]51b9a6b2012-06-25 21:50:291758 RecordTotalTime(HaveDnsConfig(), info.is_speculative(), base::TimeDelta());
[email protected]95a214c2011-08-04 21:50:401759 return rv;
[email protected]38368712011-03-02 08:09:401760 }
1761
[email protected]0f292de02012-02-01 22:28:201762 // Next we need to attach our request to a "job". This job is responsible for
1763 // calling "getaddrinfo(hostname)" on a worker thread.
1764
1765 JobMap::iterator jobit = jobs_.find(key);
1766 Job* job;
1767 if (jobit == jobs_.end()) {
[email protected]407a30ab2012-08-15 17:16:101768 // If we couldn't find the desired address family, check to see if the
1769 // other family is in the cache or another job, which indicates waste,
1770 // and we should fix crbug.com/139811.
1771 {
1772 bool ipv4 = key.address_family == ADDRESS_FAMILY_IPV4;
1773 Key other_family_key = key;
1774 other_family_key.address_family = ipv4 ?
1775 ADDRESS_FAMILY_UNSPECIFIED : ADDRESS_FAMILY_IPV4;
1776 bool found_other_family_cache = false;
1777 bool found_other_family_job = false;
1778 if (default_address_family_ == ADDRESS_FAMILY_UNSPECIFIED) {
1779 found_other_family_cache = cache_.get() &&
1780 cache_->Lookup(other_family_key, base::TimeTicks::Now()) != NULL;
1781 if (!found_other_family_cache)
1782 found_other_family_job = jobs_.count(other_family_key) > 0;
1783 }
1784 enum { // Used in UMA_HISTOGRAM_ENUMERATION.
1785 AF_WASTE_IPV4_ONLY,
1786 AF_WASTE_CACHE_IPV4,
1787 AF_WASTE_CACHE_UNSPEC,
1788 AF_WASTE_JOB_IPV4,
1789 AF_WASTE_JOB_UNSPEC,
1790 AF_WASTE_NONE_IPV4,
1791 AF_WASTE_NONE_UNSPEC,
1792 AF_WASTE_MAX, // Bounding value.
1793 } category = AF_WASTE_MAX;
1794 if (default_address_family_ != ADDRESS_FAMILY_UNSPECIFIED) {
1795 category = AF_WASTE_IPV4_ONLY;
1796 } else if (found_other_family_cache) {
1797 category = ipv4 ? AF_WASTE_CACHE_IPV4 : AF_WASTE_CACHE_UNSPEC;
1798 } else if (found_other_family_job) {
1799 category = ipv4 ? AF_WASTE_JOB_IPV4 : AF_WASTE_JOB_UNSPEC;
1800 } else {
1801 category = ipv4 ? AF_WASTE_NONE_IPV4 : AF_WASTE_NONE_UNSPEC;
1802 }
1803 UMA_HISTOGRAM_ENUMERATION("DNS.ResolveUnspecWaste", category,
1804 AF_WASTE_MAX);
1805 }
1806
[email protected]0f292de02012-02-01 22:28:201807 // Create new Job.
[email protected]8c98d002012-07-18 19:02:271808 job = new Job(this, key, info.priority(), request_net_log);
1809 job->Schedule();
[email protected]0f292de02012-02-01 22:28:201810
1811 // Check for queue overflow.
1812 if (dispatcher_.num_queued_jobs() > max_queued_jobs_) {
1813 Job* evicted = static_cast<Job*>(dispatcher_.EvictOldestLowest());
1814 DCHECK(evicted);
[email protected]16ee26d2012-03-08 03:34:351815 evicted->OnEvicted(); // Deletes |evicted|.
[email protected]0f292de02012-02-01 22:28:201816 if (evicted == job) {
[email protected]0f292de02012-02-01 22:28:201817 rv = ERR_HOST_RESOLVER_QUEUE_TOO_LARGE;
[email protected]b3601bc22012-02-21 21:23:201818 LogFinishRequest(source_net_log, request_net_log, info, rv);
[email protected]0f292de02012-02-01 22:28:201819 return rv;
1820 }
[email protected]0f292de02012-02-01 22:28:201821 }
[email protected]0f292de02012-02-01 22:28:201822 jobs_.insert(jobit, std::make_pair(key, job));
1823 } else {
1824 job = jobit->second;
1825 }
1826
1827 // Can't complete synchronously. Create and attach request.
[email protected]b3601bc22012-02-21 21:23:201828 scoped_ptr<Request> req(new Request(source_net_log,
1829 request_net_log,
1830 info,
1831 callback,
1832 addresses));
[email protected]b59ff372009-07-15 22:04:321833 if (out_req)
[email protected]b3601bc22012-02-21 21:23:201834 *out_req = reinterpret_cast<RequestHandle>(req.get());
[email protected]b59ff372009-07-15 22:04:321835
[email protected]b3601bc22012-02-21 21:23:201836 job->AddRequest(req.Pass());
[email protected]0f292de02012-02-01 22:28:201837 // Completion happens during Job::CompleteRequests().
[email protected]b59ff372009-07-15 22:04:321838 return ERR_IO_PENDING;
1839}
1840
[email protected]287d7c22011-11-15 17:34:251841int HostResolverImpl::ResolveHelper(const Key& key,
[email protected]95a214c2011-08-04 21:50:401842 const RequestInfo& info,
1843 AddressList* addresses,
[email protected]20cd5332011-10-12 22:38:001844 const BoundNetLog& request_net_log) {
[email protected]95a214c2011-08-04 21:50:401845 // The result of |getaddrinfo| for empty hosts is inconsistent across systems.
1846 // On Windows it gives the default interface's address, whereas on Linux it
1847 // gives an error. We will make it fail on all platforms for consistency.
1848 if (info.hostname().empty() || info.hostname().size() > kMaxHostLength)
1849 return ERR_NAME_NOT_RESOLVED;
1850
1851 int net_error = ERR_UNEXPECTED;
1852 if (ResolveAsIP(key, info, &net_error, addresses))
1853 return net_error;
[email protected]78eac2a2012-03-14 19:09:271854 if (ServeFromCache(key, info, &net_error, addresses)) {
[email protected]4da911f2012-06-14 19:45:201855 request_net_log.AddEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_CACHE_HIT);
[email protected]78eac2a2012-03-14 19:09:271856 return net_error;
1857 }
1858 // TODO(szym): Do not do this if nsswitch.conf instructs not to.
1859 // http://crbug.com/117655
1860 if (ServeFromHosts(key, info, addresses)) {
[email protected]4da911f2012-06-14 19:45:201861 request_net_log.AddEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_HOSTS_HIT);
[email protected]78eac2a2012-03-14 19:09:271862 return OK;
1863 }
1864 return ERR_DNS_CACHE_MISS;
[email protected]95a214c2011-08-04 21:50:401865}
1866
1867int HostResolverImpl::ResolveFromCache(const RequestInfo& info,
1868 AddressList* addresses,
1869 const BoundNetLog& source_net_log) {
1870 DCHECK(CalledOnValidThread());
1871 DCHECK(addresses);
1872
[email protected]95a214c2011-08-04 21:50:401873 // Make a log item for the request.
1874 BoundNetLog request_net_log = BoundNetLog::Make(net_log_,
1875 NetLog::SOURCE_HOST_RESOLVER_IMPL_REQUEST);
1876
1877 // Update the net log and notify registered observers.
[email protected]0f292de02012-02-01 22:28:201878 LogStartRequest(source_net_log, request_net_log, info);
[email protected]95a214c2011-08-04 21:50:401879
[email protected]95a214c2011-08-04 21:50:401880 Key key = GetEffectiveKeyForRequest(info);
1881
[email protected]287d7c22011-11-15 17:34:251882 int rv = ResolveHelper(key, info, addresses, request_net_log);
[email protected]b3601bc22012-02-21 21:23:201883 LogFinishRequest(source_net_log, request_net_log, info, rv);
[email protected]95a214c2011-08-04 21:50:401884 return rv;
1885}
1886
[email protected]b59ff372009-07-15 22:04:321887void HostResolverImpl::CancelRequest(RequestHandle req_handle) {
[email protected]1ac6af92010-06-03 21:00:141888 DCHECK(CalledOnValidThread());
[email protected]b59ff372009-07-15 22:04:321889 Request* req = reinterpret_cast<Request*>(req_handle);
1890 DCHECK(req);
[email protected]0f292de02012-02-01 22:28:201891 Job* job = req->job();
1892 DCHECK(job);
[email protected]0f292de02012-02-01 22:28:201893 job->CancelRequest(req);
[email protected]b59ff372009-07-15 22:04:321894}
1895
[email protected]0f8f1b432010-03-16 19:06:031896void HostResolverImpl::SetDefaultAddressFamily(AddressFamily address_family) {
[email protected]1ac6af92010-06-03 21:00:141897 DCHECK(CalledOnValidThread());
[email protected]0f8f1b432010-03-16 19:06:031898 ipv6_probe_monitoring_ = false;
1899 DiscardIPv6ProbeJob();
1900 default_address_family_ = address_family;
1901}
1902
[email protected]f7d310e2010-10-07 16:25:111903AddressFamily HostResolverImpl::GetDefaultAddressFamily() const {
1904 return default_address_family_;
1905}
1906
[email protected]a78f4272011-10-21 19:16:331907void HostResolverImpl::ProbeIPv6Support() {
1908 DCHECK(CalledOnValidThread());
1909 DCHECK(!ipv6_probe_monitoring_);
1910 ipv6_probe_monitoring_ = true;
1911 OnIPAddressChanged(); // Give initial setup call.
[email protected]ddb1e5a2010-12-13 20:10:451912}
1913
[email protected]489d1a82011-10-12 03:09:111914HostCache* HostResolverImpl::GetHostCache() {
1915 return cache_.get();
1916}
[email protected]95a214c2011-08-04 21:50:401917
[email protected]17e92032012-03-29 00:56:241918base::Value* HostResolverImpl::GetDnsConfigAsValue() const {
1919 // Check if async DNS is disabled.
1920 if (!dns_client_.get())
1921 return NULL;
1922
1923 // Check if async DNS is enabled, but we currently have no configuration
1924 // for it.
1925 const DnsConfig* dns_config = dns_client_->GetConfig();
1926 if (dns_config == NULL)
1927 return new DictionaryValue();
1928
1929 return dns_config->ToValue();
1930}
1931
[email protected]95a214c2011-08-04 21:50:401932bool HostResolverImpl::ResolveAsIP(const Key& key,
1933 const RequestInfo& info,
1934 int* net_error,
1935 AddressList* addresses) {
1936 DCHECK(addresses);
1937 DCHECK(net_error);
1938 IPAddressNumber ip_number;
1939 if (!ParseIPLiteralToNumber(key.hostname, &ip_number))
1940 return false;
1941
1942 DCHECK_EQ(key.host_resolver_flags &
1943 ~(HOST_RESOLVER_CANONNAME | HOST_RESOLVER_LOOPBACK_ONLY |
1944 HOST_RESOLVER_DEFAULT_FAMILY_SET_DUE_TO_NO_IPV6),
1945 0) << " Unhandled flag";
[email protected]0f292de02012-02-01 22:28:201946 bool ipv6_disabled = (default_address_family_ == ADDRESS_FAMILY_IPV4) &&
1947 !ipv6_probe_monitoring_;
[email protected]95a214c2011-08-04 21:50:401948 *net_error = OK;
[email protected]0f292de02012-02-01 22:28:201949 if ((ip_number.size() == kIPv6AddressSize) && ipv6_disabled) {
[email protected]95a214c2011-08-04 21:50:401950 *net_error = ERR_NAME_NOT_RESOLVED;
1951 } else {
[email protected]7054e78f2012-05-07 21:44:561952 *addresses = AddressList::CreateFromIPAddress(ip_number, info.port());
1953 if (key.host_resolver_flags & HOST_RESOLVER_CANONNAME)
1954 addresses->SetDefaultCanonicalName();
[email protected]95a214c2011-08-04 21:50:401955 }
1956 return true;
1957}
1958
1959bool HostResolverImpl::ServeFromCache(const Key& key,
1960 const RequestInfo& info,
[email protected]95a214c2011-08-04 21:50:401961 int* net_error,
1962 AddressList* addresses) {
1963 DCHECK(addresses);
1964 DCHECK(net_error);
1965 if (!info.allow_cached_response() || !cache_.get())
1966 return false;
1967
[email protected]407a30ab2012-08-15 17:16:101968 const HostCache::Entry* cache_entry = cache_->Lookup(
1969 key, base::TimeTicks::Now());
[email protected]95a214c2011-08-04 21:50:401970 if (!cache_entry)
1971 return false;
1972
[email protected]95a214c2011-08-04 21:50:401973 *net_error = cache_entry->error;
[email protected]7054e78f2012-05-07 21:44:561974 if (*net_error == OK) {
[email protected]1339a2a22012-10-17 08:39:431975 if (cache_entry->has_ttl())
1976 RecordTTL(cache_entry->ttl);
[email protected]7054e78f2012-05-07 21:44:561977 *addresses = cache_entry->addrlist;
1978 EnsurePortOnAddressList(info.port(), addresses);
1979 }
[email protected]95a214c2011-08-04 21:50:401980 return true;
1981}
1982
[email protected]78eac2a2012-03-14 19:09:271983bool HostResolverImpl::ServeFromHosts(const Key& key,
1984 const RequestInfo& info,
1985 AddressList* addresses) {
1986 DCHECK(addresses);
1987 if (!HaveDnsConfig())
1988 return false;
1989
[email protected]cb507622012-03-23 16:17:061990 // HOSTS lookups are case-insensitive.
1991 std::string hostname = StringToLowerASCII(key.hostname);
1992
[email protected]78eac2a2012-03-14 19:09:271993 // If |address_family| is ADDRESS_FAMILY_UNSPECIFIED other implementations
1994 // (glibc and c-ares) return the first matching line. We have more
1995 // flexibility, but lose implicit ordering.
1996 // TODO(szym) http://crbug.com/117850
1997 const DnsHosts& hosts = dns_client_->GetConfig()->hosts;
1998 DnsHosts::const_iterator it = hosts.find(
[email protected]cb507622012-03-23 16:17:061999 DnsHostsKey(hostname,
[email protected]78eac2a2012-03-14 19:09:272000 key.address_family == ADDRESS_FAMILY_UNSPECIFIED ?
2001 ADDRESS_FAMILY_IPV4 : key.address_family));
2002
2003 if (it == hosts.end()) {
2004 if (key.address_family != ADDRESS_FAMILY_UNSPECIFIED)
2005 return false;
2006
[email protected]cb507622012-03-23 16:17:062007 it = hosts.find(DnsHostsKey(hostname, ADDRESS_FAMILY_IPV6));
[email protected]78eac2a2012-03-14 19:09:272008 if (it == hosts.end())
2009 return false;
2010 }
2011
2012 *addresses = AddressList::CreateFromIPAddress(it->second, info.port());
2013 return true;
2014}
2015
[email protected]16ee26d2012-03-08 03:34:352016void HostResolverImpl::CacheResult(const Key& key,
[email protected]1339a2a22012-10-17 08:39:432017 const HostCache::Entry& entry,
[email protected]16ee26d2012-03-08 03:34:352018 base::TimeDelta ttl) {
2019 if (cache_.get())
[email protected]1339a2a22012-10-17 08:39:432020 cache_->Set(key, entry, base::TimeTicks::Now(), ttl);
[email protected]ef4c40c2010-09-01 14:42:032021}
2022
[email protected]0f292de02012-02-01 22:28:202023void HostResolverImpl::RemoveJob(Job* job) {
2024 DCHECK(job);
[email protected]16ee26d2012-03-08 03:34:352025 JobMap::iterator it = jobs_.find(job->key());
2026 if (it != jobs_.end() && it->second == job)
2027 jobs_.erase(it);
[email protected]b59ff372009-07-15 22:04:322028}
2029
[email protected]0f8f1b432010-03-16 19:06:032030void HostResolverImpl::DiscardIPv6ProbeJob() {
2031 if (ipv6_probe_job_.get()) {
2032 ipv6_probe_job_->Cancel();
2033 ipv6_probe_job_ = NULL;
2034 }
2035}
2036
2037void HostResolverImpl::IPv6ProbeSetDefaultAddressFamily(
2038 AddressFamily address_family) {
2039 DCHECK(address_family == ADDRESS_FAMILY_UNSPECIFIED ||
2040 address_family == ADDRESS_FAMILY_IPV4);
[email protected]f092e64b2010-03-17 00:39:182041 if (default_address_family_ != address_family) {
[email protected]b30a3f52010-10-16 01:05:462042 VLOG(1) << "IPv6Probe forced AddressFamily setting to "
2043 << ((address_family == ADDRESS_FAMILY_UNSPECIFIED) ?
2044 "ADDRESS_FAMILY_UNSPECIFIED" : "ADDRESS_FAMILY_IPV4");
[email protected]f092e64b2010-03-17 00:39:182045 }
[email protected]0f8f1b432010-03-16 19:06:032046 default_address_family_ = address_family;
2047 // Drop reference since the job has called us back.
2048 DiscardIPv6ProbeJob();
[email protected]e95d3aca2010-01-11 22:47:432049}
2050
[email protected]137af622010-02-05 02:14:352051HostResolverImpl::Key HostResolverImpl::GetEffectiveKeyForRequest(
2052 const RequestInfo& info) const {
[email protected]eaf3a3b2010-09-03 20:34:272053 HostResolverFlags effective_flags =
2054 info.host_resolver_flags() | additional_resolver_flags_;
[email protected]137af622010-02-05 02:14:352055 AddressFamily effective_address_family = info.address_family();
[email protected]eaf3a3b2010-09-03 20:34:272056 if (effective_address_family == ADDRESS_FAMILY_UNSPECIFIED &&
2057 default_address_family_ != ADDRESS_FAMILY_UNSPECIFIED) {
[email protected]137af622010-02-05 02:14:352058 effective_address_family = default_address_family_;
[email protected]eaf3a3b2010-09-03 20:34:272059 if (ipv6_probe_monitoring_)
2060 effective_flags |= HOST_RESOLVER_DEFAULT_FAMILY_SET_DUE_TO_NO_IPV6;
2061 }
2062 return Key(info.hostname(), effective_address_family, effective_flags);
[email protected]137af622010-02-05 02:14:352063}
2064
[email protected]35ddc282010-09-21 23:42:062065void HostResolverImpl::AbortAllInProgressJobs() {
[email protected]b3601bc22012-02-21 21:23:202066 // In Abort, a Request callback could spawn new Jobs with matching keys, so
2067 // first collect and remove all running jobs from |jobs_|.
[email protected]c143d892012-04-06 07:56:542068 ScopedVector<Job> jobs_to_abort;
[email protected]0f292de02012-02-01 22:28:202069 for (JobMap::iterator it = jobs_.begin(); it != jobs_.end(); ) {
2070 Job* job = it->second;
[email protected]0f292de02012-02-01 22:28:202071 if (job->is_running()) {
[email protected]b3601bc22012-02-21 21:23:202072 jobs_to_abort.push_back(job);
2073 jobs_.erase(it++);
[email protected]0f292de02012-02-01 22:28:202074 } else {
[email protected]b3601bc22012-02-21 21:23:202075 DCHECK(job->is_queued());
2076 ++it;
[email protected]0f292de02012-02-01 22:28:202077 }
[email protected]ef4c40c2010-09-01 14:42:032078 }
[email protected]b3601bc22012-02-21 21:23:202079
[email protected]57a48d32012-03-03 00:04:552080 // Check if no dispatcher slots leaked out.
2081 DCHECK_EQ(dispatcher_.num_running_jobs(), jobs_to_abort.size());
2082
2083 // Life check to bail once |this| is deleted.
[email protected]4589a3a2012-09-20 20:57:072084 base::WeakPtr<HostResolverImpl> self = weak_ptr_factory_.GetWeakPtr();
[email protected]57a48d32012-03-03 00:04:552085
[email protected]16ee26d2012-03-08 03:34:352086 // Then Abort them.
[email protected]57a48d32012-03-03 00:04:552087 for (size_t i = 0; self && i < jobs_to_abort.size(); ++i) {
[email protected]57a48d32012-03-03 00:04:552088 jobs_to_abort[i]->Abort();
[email protected]c143d892012-04-06 07:56:542089 jobs_to_abort[i] = NULL;
[email protected]b3601bc22012-02-21 21:23:202090 }
[email protected]ef4c40c2010-09-01 14:42:032091}
2092
[email protected]78eac2a2012-03-14 19:09:272093void HostResolverImpl::TryServingAllJobsFromHosts() {
2094 if (!HaveDnsConfig())
2095 return;
2096
2097 // TODO(szym): Do not do this if nsswitch.conf instructs not to.
2098 // http://crbug.com/117655
2099
2100 // Life check to bail once |this| is deleted.
[email protected]4589a3a2012-09-20 20:57:072101 base::WeakPtr<HostResolverImpl> self = weak_ptr_factory_.GetWeakPtr();
[email protected]78eac2a2012-03-14 19:09:272102
2103 for (JobMap::iterator it = jobs_.begin(); self && it != jobs_.end(); ) {
2104 Job* job = it->second;
2105 ++it;
2106 // This could remove |job| from |jobs_|, but iterator will remain valid.
2107 job->ServeFromHosts();
2108 }
2109}
2110
[email protected]be1a48b2011-01-20 00:12:132111void HostResolverImpl::OnIPAddressChanged() {
2112 if (cache_.get())
2113 cache_->clear();
2114 if (ipv6_probe_monitoring_) {
[email protected]be1a48b2011-01-20 00:12:132115 DiscardIPv6ProbeJob();
[email protected]ae8e80f2012-07-19 21:08:332116 ipv6_probe_job_ = new IPv6ProbeJob(this, net_log_);
[email protected]be1a48b2011-01-20 00:12:132117 ipv6_probe_job_->Start();
2118 }
[email protected]23f771162011-06-02 18:37:512119#if defined(OS_POSIX) && !defined(OS_MACOSX)
[email protected]be1a48b2011-01-20 00:12:132120 if (HaveOnlyLoopbackAddresses()) {
2121 additional_resolver_flags_ |= HOST_RESOLVER_LOOPBACK_ONLY;
2122 } else {
2123 additional_resolver_flags_ &= ~HOST_RESOLVER_LOOPBACK_ONLY;
2124 }
2125#endif
2126 AbortAllInProgressJobs();
2127 // |this| may be deleted inside AbortAllInProgressJobs().
2128}
2129
[email protected]bb0e34542012-08-31 19:52:402130void HostResolverImpl::OnDNSChanged() {
2131 DnsConfig dns_config;
2132 NetworkChangeNotifier::GetDnsConfig(&dns_config);
[email protected]b4481b222012-03-16 17:13:112133 if (net_log_) {
2134 net_log_->AddGlobalEntry(
2135 NetLog::TYPE_DNS_CONFIG_CHANGED,
[email protected]cd565142012-06-12 16:21:452136 base::Bind(&NetLogDnsConfigCallback, &dns_config));
[email protected]b4481b222012-03-16 17:13:112137 }
2138
[email protected]01b3b9d2012-08-13 16:18:142139 // TODO(szym): Remove once http://crbug.com/137914 is resolved.
[email protected]d7b9a2b2012-05-31 22:31:192140 received_dns_config_ = dns_config.IsValid();
[email protected]78eac2a2012-03-14 19:09:272141
2142 // Life check to bail once |this| is deleted.
[email protected]4589a3a2012-09-20 20:57:072143 base::WeakPtr<HostResolverImpl> self = weak_ptr_factory_.GetWeakPtr();
[email protected]78eac2a2012-03-14 19:09:272144
[email protected]01b3b9d2012-08-13 16:18:142145 // We want a new DnsSession in place, before we Abort running Jobs, so that
2146 // the newly started jobs use the new config.
2147 if (dns_client_.get())
[email protected]d7b9a2b2012-05-31 22:31:192148 dns_client_->SetConfig(dns_config);
[email protected]01b3b9d2012-08-13 16:18:142149
2150 // If the DNS server has changed, existing cached info could be wrong so we
2151 // have to drop our internal cache :( Note that OS level DNS caches, such
2152 // as NSCD's cache should be dropped automatically by the OS when
2153 // resolv.conf changes so we don't need to do anything to clear that cache.
2154 if (cache_.get())
2155 cache_->clear();
2156
2157 // Existing jobs will have been sent to the original server so they need to
2158 // be aborted.
2159 AbortAllInProgressJobs();
2160
2161 // |this| may be deleted inside AbortAllInProgressJobs().
2162 if (self)
2163 TryServingAllJobsFromHosts();
[email protected]78eac2a2012-03-14 19:09:272164}
2165
2166bool HostResolverImpl::HaveDnsConfig() const {
2167 return (dns_client_.get() != NULL) && (dns_client_->GetConfig() != NULL);
[email protected]b3601bc22012-02-21 21:23:202168}
2169
[email protected]b59ff372009-07-15 22:04:322170} // namespace net