blob: a6a5a228c6455c2d53c1893780d2e5c5e5cf943c [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]ee094b82010-08-24 15:55:5135#include "net/base/address_list_net_log_param.h"
[email protected]46018c9d2011-09-06 03:42:3436#include "net/base/dns_reloader.h"
[email protected]ee094b82010-08-24 15:55:5137#include "net/base/host_port_pair.h"
[email protected]b59ff372009-07-15 22:04:3238#include "net/base/host_resolver_proc.h"
[email protected]2bb04442010-08-18 18:01:1539#include "net/base/net_errors.h"
[email protected]ee094b82010-08-24 15:55:5140#include "net/base/net_log.h"
[email protected]0f8f1b432010-03-16 19:06:0341#include "net/base/net_util.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]0f292de02012-02-01 22:28:2066// Maximum of 8 concurrent resolver threads (excluding retries).
67// 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
69// further optimized, but 8 is what FF currently does.
70static const size_t kDefaultMaxProcTasks = 8u;
71
[email protected]fe89ea72011-05-12 02:02:4072// Helper to mutate the linked list contained by AddressList to the given
73// port. Note that in general this is dangerous since the AddressList's
74// data might be shared (and you should use AddressList::SetPort).
75//
76// However since we allocated the AddressList ourselves we can safely
77// do this optimization and avoid reallocating the list.
[email protected]b3601bc22012-02-21 21:23:2078void MutableSetPort(int port, AddressList* addr_list) {
[email protected]fe89ea72011-05-12 02:02:4079 struct addrinfo* mutable_head =
[email protected]b3601bc22012-02-21 21:23:2080 const_cast<struct addrinfo*>(addr_list->head());
[email protected]fe89ea72011-05-12 02:02:4081 SetPortForAllAddrinfos(mutable_head, port);
82}
83
[email protected]24f4bab2010-10-15 01:27:1184// We use a separate histogram name for each platform to facilitate the
85// display of error codes by their symbolic name (since each platform has
86// different mappings).
87const char kOSErrorsForGetAddrinfoHistogramName[] =
88#if defined(OS_WIN)
89 "Net.OSErrorsForGetAddrinfo_Win";
90#elif defined(OS_MACOSX)
91 "Net.OSErrorsForGetAddrinfo_Mac";
92#elif defined(OS_LINUX)
93 "Net.OSErrorsForGetAddrinfo_Linux";
94#else
95 "Net.OSErrorsForGetAddrinfo";
96#endif
97
[email protected]c89b2442011-05-26 14:28:2798// Gets a list of the likely error codes that getaddrinfo() can return
99// (non-exhaustive). These are the error codes that we will track via
100// a histogram.
101std::vector<int> GetAllGetAddrinfoOSErrors() {
102 int os_errors[] = {
103#if defined(OS_POSIX)
[email protected]23f771162011-06-02 18:37:51104#if !defined(OS_FREEBSD)
[email protected]39588992011-07-11 19:54:37105#if !defined(OS_ANDROID)
[email protected]c48aef92011-11-22 23:41:45106 // EAI_ADDRFAMILY has been declared obsolete in Android's and
107 // FreeBSD's netdb.h.
[email protected]c89b2442011-05-26 14:28:27108 EAI_ADDRFAMILY,
[email protected]39588992011-07-11 19:54:37109#endif
[email protected]c48aef92011-11-22 23:41:45110 // EAI_NODATA has been declared obsolete in FreeBSD's netdb.h.
[email protected]23f771162011-06-02 18:37:51111 EAI_NODATA,
112#endif
[email protected]c89b2442011-05-26 14:28:27113 EAI_AGAIN,
114 EAI_BADFLAGS,
115 EAI_FAIL,
116 EAI_FAMILY,
117 EAI_MEMORY,
[email protected]c89b2442011-05-26 14:28:27118 EAI_NONAME,
119 EAI_SERVICE,
120 EAI_SOCKTYPE,
121 EAI_SYSTEM,
122#elif defined(OS_WIN)
123 // See: http://msdn.microsoft.com/en-us/library/ms738520(VS.85).aspx
124 WSA_NOT_ENOUGH_MEMORY,
125 WSAEAFNOSUPPORT,
126 WSAEINVAL,
127 WSAESOCKTNOSUPPORT,
128 WSAHOST_NOT_FOUND,
129 WSANO_DATA,
130 WSANO_RECOVERY,
131 WSANOTINITIALISED,
132 WSATRY_AGAIN,
133 WSATYPE_NOT_FOUND,
134 // The following are not in doc, but might be to appearing in results :-(.
135 WSA_INVALID_HANDLE,
136#endif
137 };
138
139 // Ensure all errors are positive, as histogram only tracks positive values.
140 for (size_t i = 0; i < arraysize(os_errors); ++i) {
141 os_errors[i] = std::abs(os_errors[i]);
142 }
143
144 return base::CustomHistogram::ArrayToCustomRanges(os_errors,
145 arraysize(os_errors));
146}
147
[email protected]1def74c2012-03-22 20:07:00148enum DnsResolveStatus {
149 RESOLVE_STATUS_DNS_SUCCESS = 0,
150 RESOLVE_STATUS_PROC_SUCCESS,
151 RESOLVE_STATUS_FAIL,
152 RESOLVE_STATUS_MAX
153};
154
155void UmaAsyncDnsResolveStatus(DnsResolveStatus result) {
156 UMA_HISTOGRAM_ENUMERATION("AsyncDNS.ResolveStatus",
157 result,
158 RESOLVE_STATUS_MAX);
159}
160
[email protected]0f292de02012-02-01 22:28:20161// Wraps call to SystemHostResolverProc as an instance of HostResolverProc.
162// TODO(szym): This should probably be declared in host_resolver_proc.h.
163class CallSystemHostResolverProc : public HostResolverProc {
164 public:
165 CallSystemHostResolverProc() : HostResolverProc(NULL) {}
166 virtual int Resolve(const std::string& hostname,
167 AddressFamily address_family,
168 HostResolverFlags host_resolver_flags,
[email protected]b3601bc22012-02-21 21:23:20169 AddressList* addr_list,
[email protected]0f292de02012-02-01 22:28:20170 int* os_error) OVERRIDE {
171 return SystemHostResolverProc(hostname,
172 address_family,
173 host_resolver_flags,
[email protected]b3601bc22012-02-21 21:23:20174 addr_list,
[email protected]0f292de02012-02-01 22:28:20175 os_error);
[email protected]b59ff372009-07-15 22:04:32176 }
[email protected]0f292de02012-02-01 22:28:20177};
[email protected]b59ff372009-07-15 22:04:32178
[email protected]21526002010-05-16 19:42:46179// Extra parameters to attach to the NetLog when the resolve failed.
[email protected]b3601bc22012-02-21 21:23:20180class ProcTaskFailedParams : public NetLog::EventParameters {
[email protected]21526002010-05-16 19:42:46181 public:
[email protected]b3601bc22012-02-21 21:23:20182 ProcTaskFailedParams(uint32 attempt_number, int net_error, int os_error)
[email protected]13024882011-05-18 23:19:16183 : attempt_number_(attempt_number),
184 net_error_(net_error),
[email protected]ee094b82010-08-24 15:55:51185 os_error_(os_error) {
[email protected]21526002010-05-16 19:42:46186 }
187
[email protected]0f292de02012-02-01 22:28:20188 virtual Value* ToValue() const OVERRIDE {
[email protected]21526002010-05-16 19:42:46189 DictionaryValue* dict = new DictionaryValue();
[email protected]13024882011-05-18 23:19:16190 if (attempt_number_)
191 dict->SetInteger("attempt_number", attempt_number_);
192
[email protected]ccaff652010-07-31 06:28:20193 dict->SetInteger("net_error", net_error_);
[email protected]21526002010-05-16 19:42:46194
195 if (os_error_) {
[email protected]ccaff652010-07-31 06:28:20196 dict->SetInteger("os_error", os_error_);
[email protected]21526002010-05-16 19:42:46197#if defined(OS_POSIX)
[email protected]ccaff652010-07-31 06:28:20198 dict->SetString("os_error_string", gai_strerror(os_error_));
[email protected]21526002010-05-16 19:42:46199#elif defined(OS_WIN)
200 // Map the error code to a human-readable string.
201 LPWSTR error_string = NULL;
202 int size = FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
203 FORMAT_MESSAGE_FROM_SYSTEM,
204 0, // Use the internal message table.
205 os_error_,
206 0, // Use default language.
207 (LPWSTR)&error_string,
208 0, // Buffer size.
209 0); // Arguments (unused).
[email protected]ccaff652010-07-31 06:28:20210 dict->SetString("os_error_string", WideToUTF8(error_string));
[email protected]21526002010-05-16 19:42:46211 LocalFree(error_string);
212#endif
213 }
214
215 return dict;
216 }
217
218 private:
[email protected]13024882011-05-18 23:19:16219 const uint32 attempt_number_;
[email protected]21526002010-05-16 19:42:46220 const int net_error_;
221 const int os_error_;
[email protected]ee094b82010-08-24 15:55:51222};
223
[email protected]b3601bc22012-02-21 21:23:20224// Extra parameters to attach to the NetLog when the DnsTask failed.
225class DnsTaskFailedParams : public NetLog::EventParameters {
226 public:
227 DnsTaskFailedParams(int net_error, int dns_error)
228 : net_error_(net_error), dns_error_(dns_error) {
229 }
230
231 virtual Value* ToValue() const OVERRIDE {
232 DictionaryValue* dict = new DictionaryValue();
233 dict->SetInteger("net_error", net_error_);
234 if (dns_error_)
235 dict->SetInteger("dns_error", dns_error_);
236 return dict;
237 }
238
239 private:
240 const int net_error_;
241 const int dns_error_;
242};
243
[email protected]ee094b82010-08-24 15:55:51244// Parameters representing the information in a RequestInfo object, along with
245// the associated NetLog::Source.
246class RequestInfoParameters : public NetLog::EventParameters {
247 public:
248 RequestInfoParameters(const HostResolver::RequestInfo& info,
249 const NetLog::Source& source)
250 : info_(info), source_(source) {}
251
[email protected]0f292de02012-02-01 22:28:20252 virtual Value* ToValue() const OVERRIDE {
[email protected]ee094b82010-08-24 15:55:51253 DictionaryValue* dict = new DictionaryValue();
[email protected]930cc742010-09-15 22:54:10254 dict->SetString("host", info_.host_port_pair().ToString());
[email protected]ee094b82010-08-24 15:55:51255 dict->SetInteger("address_family",
256 static_cast<int>(info_.address_family()));
257 dict->SetBoolean("allow_cached_response", info_.allow_cached_response());
258 dict->SetBoolean("is_speculative", info_.is_speculative());
259 dict->SetInteger("priority", info_.priority());
260
261 if (source_.is_valid())
262 dict->Set("source_dependency", source_.ToValue());
263
264 return dict;
265 }
266
267 private:
268 const HostResolver::RequestInfo info_;
269 const NetLog::Source source_;
270};
271
[email protected]b3601bc22012-02-21 21:23:20272// Parameters associated with the creation of a HostResolverImpl::Job.
[email protected]ee094b82010-08-24 15:55:51273class JobCreationParameters : public NetLog::EventParameters {
274 public:
[email protected]0f292de02012-02-01 22:28:20275 JobCreationParameters(const std::string& host,
276 const NetLog::Source& source)
[email protected]ee094b82010-08-24 15:55:51277 : host_(host), source_(source) {}
278
[email protected]0f292de02012-02-01 22:28:20279 virtual Value* ToValue() const OVERRIDE {
[email protected]ee094b82010-08-24 15:55:51280 DictionaryValue* dict = new DictionaryValue();
281 dict->SetString("host", host_);
282 dict->Set("source_dependency", source_.ToValue());
283 return dict;
284 }
285
286 private:
287 const std::string host_;
288 const NetLog::Source source_;
[email protected]21526002010-05-16 19:42:46289};
290
[email protected]0f292de02012-02-01 22:28:20291// Parameters of the HOST_RESOLVER_IMPL_JOB_ATTACH/DETACH event.
292class JobAttachParameters : public NetLog::EventParameters {
293 public:
294 JobAttachParameters(const NetLog::Source& source,
295 RequestPriority priority)
296 : source_(source), priority_(priority) {}
297
298 virtual Value* ToValue() const OVERRIDE {
299 DictionaryValue* dict = new DictionaryValue();
300 dict->Set("source_dependency", source_.ToValue());
301 dict->SetInteger("priority", priority_);
302 return dict;
303 }
304
305 private:
306 const NetLog::Source source_;
307 const RequestPriority priority_;
308};
309
[email protected]b4481b222012-03-16 17:13:11310// Parameters of the DNS_CONFIG_CHANGED event.
311class DnsConfigParameters : public NetLog::EventParameters {
312 public:
313 explicit DnsConfigParameters(const DnsConfig& config)
314 : num_hosts_(config.hosts.size()) {
315 config_.CopyIgnoreHosts(config);
316 }
317
318 virtual Value* ToValue() const OVERRIDE {
[email protected]17e92032012-03-29 00:56:24319 Value* value = config_.ToValue();
320 if (!value)
321 return NULL;
322 DictionaryValue* dict;
323 if (value->GetAsDictionary(&dict))
324 dict->SetInteger("num_hosts", num_hosts_);
325 return value;
[email protected]b4481b222012-03-16 17:13:11326 }
327
328 private:
329 DnsConfig config_; // Does not include DnsHosts to save memory and work.
330 const size_t num_hosts_;
331};
332
[email protected]0f292de02012-02-01 22:28:20333// The logging routines are defined here because some requests are resolved
334// without a Request object.
335
336// Logs when a request has just been started.
337void LogStartRequest(const BoundNetLog& source_net_log,
338 const BoundNetLog& request_net_log,
339 const HostResolver::RequestInfo& info) {
340 source_net_log.BeginEvent(
341 NetLog::TYPE_HOST_RESOLVER_IMPL,
342 make_scoped_refptr(new NetLogSourceParameter(
343 "source_dependency", request_net_log.source())));
344
345 request_net_log.BeginEvent(
346 NetLog::TYPE_HOST_RESOLVER_IMPL_REQUEST,
347 make_scoped_refptr(new RequestInfoParameters(
348 info, source_net_log.source())));
349}
350
351// Logs when a request has just completed (before its callback is run).
352void LogFinishRequest(const BoundNetLog& source_net_log,
353 const BoundNetLog& request_net_log,
354 const HostResolver::RequestInfo& info,
[email protected]b3601bc22012-02-21 21:23:20355 int net_error) {
356 request_net_log.EndEventWithNetErrorCode(
357 NetLog::TYPE_HOST_RESOLVER_IMPL_REQUEST, net_error);
[email protected]0f292de02012-02-01 22:28:20358 source_net_log.EndEvent(NetLog::TYPE_HOST_RESOLVER_IMPL, NULL);
359}
360
361// Logs when a request has been cancelled.
362void LogCancelRequest(const BoundNetLog& source_net_log,
363 const BoundNetLog& request_net_log,
364 const HostResolverImpl::RequestInfo& info) {
365 request_net_log.AddEvent(NetLog::TYPE_CANCELLED, NULL);
366 request_net_log.EndEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_REQUEST, NULL);
367 source_net_log.EndEvent(NetLog::TYPE_HOST_RESOLVER_IMPL, NULL);
368}
369
[email protected]b59ff372009-07-15 22:04:32370//-----------------------------------------------------------------------------
371
[email protected]0f292de02012-02-01 22:28:20372// Keeps track of the highest priority.
373class PriorityTracker {
374 public:
[email protected]16ee26d2012-03-08 03:34:35375 PriorityTracker()
376 : highest_priority_(IDLE), total_count_(0) {
[email protected]0f292de02012-02-01 22:28:20377 memset(counts_, 0, sizeof(counts_));
378 }
379
380 RequestPriority highest_priority() const {
381 return highest_priority_;
382 }
383
384 size_t total_count() const {
385 return total_count_;
386 }
387
388 void Add(RequestPriority req_priority) {
389 ++total_count_;
390 ++counts_[req_priority];
391 if (highest_priority_ > req_priority)
392 highest_priority_ = req_priority;
393 }
394
395 void Remove(RequestPriority req_priority) {
396 DCHECK_GT(total_count_, 0u);
397 DCHECK_GT(counts_[req_priority], 0u);
398 --total_count_;
399 --counts_[req_priority];
400 size_t i;
401 for (i = highest_priority_; i < NUM_PRIORITIES && !counts_[i]; ++i);
402 highest_priority_ = static_cast<RequestPriority>(i);
403
404 // In absence of requests set default.
405 if (highest_priority_ == NUM_PRIORITIES) {
406 DCHECK_EQ(0u, total_count_);
407 highest_priority_ = IDLE;
408 }
409 }
410
411 private:
412 RequestPriority highest_priority_;
413 size_t total_count_;
414 size_t counts_[NUM_PRIORITIES];
415};
416
417//-----------------------------------------------------------------------------
418
419HostResolver* CreateHostResolver(size_t max_concurrent_resolves,
420 size_t max_retry_attempts,
[email protected]b3601bc22012-02-21 21:23:20421 HostCache* cache,
422 scoped_ptr<DnsConfigService> config_service,
[email protected]0f292de02012-02-01 22:28:20423 NetLog* net_log) {
424 if (max_concurrent_resolves == HostResolver::kDefaultParallelism)
425 max_concurrent_resolves = kDefaultMaxProcTasks;
426
427 // TODO(szym): Add experiments with reserved slots for higher priority
428 // requests.
429
430 PrioritizedDispatcher::Limits limits(NUM_PRIORITIES, max_concurrent_resolves);
431
432 HostResolverImpl* resolver = new HostResolverImpl(
[email protected]b3601bc22012-02-21 21:23:20433 cache,
[email protected]0f292de02012-02-01 22:28:20434 limits,
435 HostResolverImpl::ProcTaskParams(NULL, max_retry_attempts),
[email protected]b3601bc22012-02-21 21:23:20436 config_service.Pass(),
[email protected]0f292de02012-02-01 22:28:20437 net_log);
438
439 return resolver;
440}
441
442} // anonymous namespace
443
444//-----------------------------------------------------------------------------
445
446HostResolver* CreateSystemHostResolver(size_t max_concurrent_resolves,
447 size_t max_retry_attempts,
448 NetLog* net_log) {
449 return CreateHostResolver(max_concurrent_resolves,
450 max_retry_attempts,
[email protected]b3601bc22012-02-21 21:23:20451 HostCache::CreateDefaultCache(),
452 scoped_ptr<DnsConfigService>(NULL),
[email protected]0f292de02012-02-01 22:28:20453 net_log);
454}
455
456HostResolver* CreateNonCachingSystemHostResolver(size_t max_concurrent_resolves,
457 size_t max_retry_attempts,
458 NetLog* net_log) {
459 return CreateHostResolver(max_concurrent_resolves,
460 max_retry_attempts,
[email protected]b3601bc22012-02-21 21:23:20461 NULL,
462 scoped_ptr<DnsConfigService>(NULL),
463 net_log);
464}
465
466HostResolver* CreateAsyncHostResolver(size_t max_concurrent_resolves,
467 size_t max_retry_attempts,
468 NetLog* net_log) {
469 scoped_ptr<DnsConfigService> config_service =
470 DnsConfigService::CreateSystemService();
[email protected]b3601bc22012-02-21 21:23:20471 return CreateHostResolver(max_concurrent_resolves,
472 max_retry_attempts,
473 HostCache::CreateDefaultCache(),
474 config_service.Pass(),
[email protected]0f292de02012-02-01 22:28:20475 net_log);
476}
477
478//-----------------------------------------------------------------------------
479
480// Holds the data for a request that could not be completed synchronously.
481// It is owned by a Job. Canceled Requests are only marked as canceled rather
482// than removed from the Job's |requests_| list.
[email protected]b59ff372009-07-15 22:04:32483class HostResolverImpl::Request {
484 public:
[email protected]ee094b82010-08-24 15:55:51485 Request(const BoundNetLog& source_net_log,
486 const BoundNetLog& request_net_log,
[email protected]54e13772009-08-14 03:01:09487 const RequestInfo& info,
[email protected]aa22b242011-11-16 18:58:29488 const CompletionCallback& callback,
[email protected]b59ff372009-07-15 22:04:32489 AddressList* addresses)
[email protected]ee094b82010-08-24 15:55:51490 : source_net_log_(source_net_log),
491 request_net_log_(request_net_log),
[email protected]54e13772009-08-14 03:01:09492 info_(info),
493 job_(NULL),
494 callback_(callback),
495 addresses_(addresses) {
496 }
[email protected]b59ff372009-07-15 22:04:32497
[email protected]0f292de02012-02-01 22:28:20498 // Mark the request as canceled.
499 void MarkAsCanceled() {
[email protected]b59ff372009-07-15 22:04:32500 job_ = NULL;
[email protected]b59ff372009-07-15 22:04:32501 addresses_ = NULL;
[email protected]aa22b242011-11-16 18:58:29502 callback_.Reset();
[email protected]b59ff372009-07-15 22:04:32503 }
504
[email protected]0f292de02012-02-01 22:28:20505 bool was_canceled() const {
[email protected]aa22b242011-11-16 18:58:29506 return callback_.is_null();
[email protected]b59ff372009-07-15 22:04:32507 }
508
509 void set_job(Job* job) {
[email protected]0f292de02012-02-01 22:28:20510 DCHECK(job);
[email protected]b59ff372009-07-15 22:04:32511 // Identify which job the request is waiting on.
512 job_ = job;
513 }
514
[email protected]0f292de02012-02-01 22:28:20515 // Prepare final AddressList and call completion callback.
[email protected]b3601bc22012-02-21 21:23:20516 void OnComplete(int error, const AddressList& addr_list) {
[email protected]b59ff372009-07-15 22:04:32517 if (error == OK)
[email protected]b3601bc22012-02-21 21:23:20518 *addresses_ = CreateAddressListUsingPort(addr_list, info_.port());
[email protected]aa22b242011-11-16 18:58:29519 CompletionCallback callback = callback_;
[email protected]0f292de02012-02-01 22:28:20520 MarkAsCanceled();
[email protected]aa22b242011-11-16 18:58:29521 callback.Run(error);
[email protected]b59ff372009-07-15 22:04:32522 }
523
[email protected]b59ff372009-07-15 22:04:32524 Job* job() const {
525 return job_;
526 }
527
[email protected]0f292de02012-02-01 22:28:20528 // NetLog for the source, passed in HostResolver::Resolve.
[email protected]ee094b82010-08-24 15:55:51529 const BoundNetLog& source_net_log() {
530 return source_net_log_;
531 }
532
[email protected]0f292de02012-02-01 22:28:20533 // NetLog for this request.
[email protected]ee094b82010-08-24 15:55:51534 const BoundNetLog& request_net_log() {
535 return request_net_log_;
[email protected]54e13772009-08-14 03:01:09536 }
537
[email protected]b59ff372009-07-15 22:04:32538 const RequestInfo& info() const {
539 return info_;
540 }
541
542 private:
[email protected]ee094b82010-08-24 15:55:51543 BoundNetLog source_net_log_;
544 BoundNetLog request_net_log_;
[email protected]54e13772009-08-14 03:01:09545
[email protected]b59ff372009-07-15 22:04:32546 // The request info that started the request.
547 RequestInfo info_;
548
[email protected]0f292de02012-02-01 22:28:20549 // The resolve job that this request is dependent on.
[email protected]b59ff372009-07-15 22:04:32550 Job* job_;
551
552 // The user's callback to invoke when the request completes.
[email protected]aa22b242011-11-16 18:58:29553 CompletionCallback callback_;
[email protected]b59ff372009-07-15 22:04:32554
555 // The address list to save result into.
556 AddressList* addresses_;
557
558 DISALLOW_COPY_AND_ASSIGN(Request);
559};
560
[email protected]1e9bbd22010-10-15 16:42:45561//------------------------------------------------------------------------------
562
563// Provide a common macro to simplify code and readability. We must use a
564// macros as the underlying HISTOGRAM macro creates static varibles.
565#define DNS_HISTOGRAM(name, time) UMA_HISTOGRAM_CUSTOM_TIMES(name, time, \
566 base::TimeDelta::FromMicroseconds(1), base::TimeDelta::FromHours(1), 100)
[email protected]b59ff372009-07-15 22:04:32567
[email protected]0f292de02012-02-01 22:28:20568// Calls HostResolverProc on the WorkerPool. Performs retries if necessary.
569//
570// Whenever we try to resolve the host, we post a delayed task to check if host
571// resolution (OnLookupComplete) is completed or not. If the original attempt
572// hasn't completed, then we start another attempt for host resolution. We take
573// the results from the first attempt that finishes and ignore the results from
574// all other attempts.
575//
576// TODO(szym): Move to separate source file for testing and mocking.
577//
578class HostResolverImpl::ProcTask
579 : public base::RefCountedThreadSafe<HostResolverImpl::ProcTask> {
[email protected]b59ff372009-07-15 22:04:32580 public:
[email protected]b3601bc22012-02-21 21:23:20581 typedef base::Callback<void(int net_error,
582 const AddressList& addr_list)> Callback;
[email protected]b59ff372009-07-15 22:04:32583
[email protected]0f292de02012-02-01 22:28:20584 ProcTask(const Key& key,
585 const ProcTaskParams& params,
586 const Callback& callback,
587 const BoundNetLog& job_net_log)
588 : key_(key),
589 params_(params),
590 callback_(callback),
591 origin_loop_(base::MessageLoopProxy::current()),
592 attempt_number_(0),
593 completed_attempt_number_(0),
594 completed_attempt_error_(ERR_UNEXPECTED),
595 had_non_speculative_request_(false),
[email protected]b3601bc22012-02-21 21:23:20596 net_log_(job_net_log) {
[email protected]0f292de02012-02-01 22:28:20597 if (!params_.resolver_proc)
598 params_.resolver_proc = HostResolverProc::GetDefault();
599 // If default is unset, use the system proc.
600 if (!params_.resolver_proc)
601 params_.resolver_proc = new CallSystemHostResolverProc();
[email protected]b59ff372009-07-15 22:04:32602 }
603
[email protected]b59ff372009-07-15 22:04:32604 void Start() {
[email protected]3e9d9cc2011-05-03 21:08:15605 DCHECK(origin_loop_->BelongsToCurrentThread());
[email protected]9c571762012-02-27 19:12:40606 net_log_.BeginEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_PROC_TASK, NULL);
[email protected]189163e2011-05-11 01:48:54607 StartLookupAttempt();
608 }
[email protected]252b699b2010-02-05 21:38:06609
[email protected]0f292de02012-02-01 22:28:20610 // Cancels this ProcTask. It will be orphaned. Any outstanding resolve
611 // attempts running on worker threads will continue running. Only once all the
612 // attempts complete will the final reference to this ProcTask be released.
613 void Cancel() {
614 DCHECK(origin_loop_->BelongsToCurrentThread());
615
616 if (was_canceled())
617 return;
618
[email protected]0f292de02012-02-01 22:28:20619 callback_.Reset();
[email protected]0f292de02012-02-01 22:28:20620 net_log_.EndEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_PROC_TASK, NULL);
621 }
622
623 void set_had_non_speculative_request() {
624 DCHECK(origin_loop_->BelongsToCurrentThread());
625 had_non_speculative_request_ = true;
626 }
627
628 bool was_canceled() const {
629 DCHECK(origin_loop_->BelongsToCurrentThread());
630 return callback_.is_null();
631 }
632
633 bool was_completed() const {
634 DCHECK(origin_loop_->BelongsToCurrentThread());
635 return completed_attempt_number_ > 0;
636 }
637
638 private:
[email protected]189163e2011-05-11 01:48:54639 void StartLookupAttempt() {
640 DCHECK(origin_loop_->BelongsToCurrentThread());
641 base::TimeTicks start_time = base::TimeTicks::Now();
642 ++attempt_number_;
643 // Dispatch the lookup attempt to a worker thread.
644 if (!base::WorkerPool::PostTask(
645 FROM_HERE,
[email protected]0f292de02012-02-01 22:28:20646 base::Bind(&ProcTask::DoLookup, this, start_time, attempt_number_),
[email protected]189163e2011-05-11 01:48:54647 true)) {
[email protected]b59ff372009-07-15 22:04:32648 NOTREACHED();
649
650 // Since we could be running within Resolve() right now, we can't just
651 // call OnLookupComplete(). Instead we must wait until Resolve() has
652 // returned (IO_PENDING).
[email protected]3e9d9cc2011-05-03 21:08:15653 origin_loop_->PostTask(
[email protected]189163e2011-05-11 01:48:54654 FROM_HERE,
[email protected]0f292de02012-02-01 22:28:20655 base::Bind(&ProcTask::OnLookupComplete, this, AddressList(),
[email protected]33152acc2011-10-20 23:37:12656 start_time, attempt_number_, ERR_UNEXPECTED, 0));
[email protected]189163e2011-05-11 01:48:54657 return;
[email protected]b59ff372009-07-15 22:04:32658 }
[email protected]13024882011-05-18 23:19:16659
660 net_log_.AddEvent(
661 NetLog::TYPE_HOST_RESOLVER_IMPL_ATTEMPT_STARTED,
662 make_scoped_refptr(new NetLogIntegerParameter(
663 "attempt_number", attempt_number_)));
664
[email protected]0f292de02012-02-01 22:28:20665 // If we don't get the results within a given time, RetryIfNotComplete
666 // will start a new attempt on a different worker thread if none of our
667 // outstanding attempts have completed yet.
668 if (attempt_number_ <= params_.max_retry_attempts) {
[email protected]06ef6d92011-05-19 04:24:58669 origin_loop_->PostDelayedTask(
670 FROM_HERE,
[email protected]0f292de02012-02-01 22:28:20671 base::Bind(&ProcTask::RetryIfNotComplete, this),
[email protected]7e560102012-03-08 20:58:42672 params_.unresponsive_delay);
[email protected]06ef6d92011-05-19 04:24:58673 }
[email protected]b59ff372009-07-15 22:04:32674 }
675
[email protected]6c710ee2010-05-07 07:51:16676 // WARNING: This code runs inside a worker pool. The shutdown code cannot
677 // wait for it to finish, so we must be very careful here about using other
678 // objects (like MessageLoops, Singletons, etc). During shutdown these objects
[email protected]189163e2011-05-11 01:48:54679 // may no longer exist. Multiple DoLookups() could be running in parallel, so
680 // any state inside of |this| must not mutate .
681 void DoLookup(const base::TimeTicks& start_time,
682 const uint32 attempt_number) {
683 AddressList results;
684 int os_error = 0;
[email protected]b59ff372009-07-15 22:04:32685 // Running on the worker thread
[email protected]0f292de02012-02-01 22:28:20686 int error = params_.resolver_proc->Resolve(key_.hostname,
687 key_.address_family,
688 key_.host_resolver_flags,
689 &results,
690 &os_error);
[email protected]b59ff372009-07-15 22:04:32691
[email protected]189163e2011-05-11 01:48:54692 origin_loop_->PostTask(
693 FROM_HERE,
[email protected]0f292de02012-02-01 22:28:20694 base::Bind(&ProcTask::OnLookupComplete, this, results, start_time,
[email protected]33152acc2011-10-20 23:37:12695 attempt_number, error, os_error));
[email protected]189163e2011-05-11 01:48:54696 }
697
[email protected]0f292de02012-02-01 22:28:20698 // Makes next attempt if DoLookup() has not finished (runs on origin thread).
699 void RetryIfNotComplete() {
[email protected]189163e2011-05-11 01:48:54700 DCHECK(origin_loop_->BelongsToCurrentThread());
701
[email protected]0f292de02012-02-01 22:28:20702 if (was_completed() || was_canceled())
[email protected]189163e2011-05-11 01:48:54703 return;
704
[email protected]0f292de02012-02-01 22:28:20705 params_.unresponsive_delay *= params_.retry_factor;
[email protected]189163e2011-05-11 01:48:54706 StartLookupAttempt();
[email protected]b59ff372009-07-15 22:04:32707 }
708
709 // Callback for when DoLookup() completes (runs on origin thread).
[email protected]189163e2011-05-11 01:48:54710 void OnLookupComplete(const AddressList& results,
711 const base::TimeTicks& start_time,
712 const uint32 attempt_number,
713 int error,
714 const int os_error) {
[email protected]3e9d9cc2011-05-03 21:08:15715 DCHECK(origin_loop_->BelongsToCurrentThread());
[email protected]189163e2011-05-11 01:48:54716 DCHECK(error || results.head());
717
718 bool was_retry_attempt = attempt_number > 1;
719
[email protected]2d3b7762010-10-09 00:35:47720 // Ideally the following code would be part of host_resolver_proc.cc,
[email protected]b3601bc22012-02-21 21:23:20721 // however it isn't safe to call NetworkChangeNotifier from worker threads.
722 // So we do it here on the IO thread instead.
[email protected]189163e2011-05-11 01:48:54723 if (error != OK && NetworkChangeNotifier::IsOffline())
724 error = ERR_INTERNET_DISCONNECTED;
[email protected]2d3b7762010-10-09 00:35:47725
[email protected]b3601bc22012-02-21 21:23:20726 // If this is the first attempt that is finishing later, then record data
727 // for the first attempt. Won't contaminate with retry attempt's data.
[email protected]189163e2011-05-11 01:48:54728 if (!was_retry_attempt)
729 RecordPerformanceHistograms(start_time, error, os_error);
730
731 RecordAttemptHistograms(start_time, attempt_number, error, os_error);
[email protected]f2d8c4212010-02-02 00:56:35732
[email protected]0f292de02012-02-01 22:28:20733 if (was_canceled())
[email protected]b59ff372009-07-15 22:04:32734 return;
735
[email protected]0f292de02012-02-01 22:28:20736 scoped_refptr<NetLog::EventParameters> params;
737 if (error != OK) {
[email protected]b3601bc22012-02-21 21:23:20738 params = new ProcTaskFailedParams(attempt_number, error, os_error);
[email protected]0f292de02012-02-01 22:28:20739 } else {
[email protected]53b583b2012-02-09 00:10:47740 params = new NetLogIntegerParameter("attempt_number", attempt_number);
[email protected]0f292de02012-02-01 22:28:20741 }
742 net_log_.AddEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_ATTEMPT_FINISHED, params);
743
744 if (was_completed())
745 return;
746
747 // Copy the results from the first worker thread that resolves the host.
748 results_ = results;
749 completed_attempt_number_ = attempt_number;
750 completed_attempt_error_ = error;
751
[email protected]e87b8b512011-06-14 22:12:52752 if (was_retry_attempt) {
753 // If retry attempt finishes before 1st attempt, then get stats on how
754 // much time is saved by having spawned an extra attempt.
755 retry_attempt_finished_time_ = base::TimeTicks::Now();
756 }
757
[email protected]189163e2011-05-11 01:48:54758 if (error != OK) {
[email protected]b3601bc22012-02-21 21:23:20759 params = new ProcTaskFailedParams(0, error, os_error);
[email protected]ee094b82010-08-24 15:55:51760 } else {
761 params = new AddressListNetLogParam(results_);
762 }
[email protected]0f292de02012-02-01 22:28:20763 net_log_.EndEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_PROC_TASK, params);
[email protected]ee094b82010-08-24 15:55:51764
[email protected]b3601bc22012-02-21 21:23:20765 callback_.Run(error, results_);
[email protected]b59ff372009-07-15 22:04:32766 }
767
[email protected]189163e2011-05-11 01:48:54768 void RecordPerformanceHistograms(const base::TimeTicks& start_time,
769 const int error,
770 const int os_error) const {
[email protected]3e9d9cc2011-05-03 21:08:15771 DCHECK(origin_loop_->BelongsToCurrentThread());
[email protected]1e9bbd22010-10-15 16:42:45772 enum Category { // Used in HISTOGRAM_ENUMERATION.
773 RESOLVE_SUCCESS,
774 RESOLVE_FAIL,
775 RESOLVE_SPECULATIVE_SUCCESS,
776 RESOLVE_SPECULATIVE_FAIL,
777 RESOLVE_MAX, // Bounding value.
778 };
779 int category = RESOLVE_MAX; // Illegal value for later DCHECK only.
780
[email protected]189163e2011-05-11 01:48:54781 base::TimeDelta duration = base::TimeTicks::Now() - start_time;
782 if (error == OK) {
[email protected]1e9bbd22010-10-15 16:42:45783 if (had_non_speculative_request_) {
784 category = RESOLVE_SUCCESS;
785 DNS_HISTOGRAM("DNS.ResolveSuccess", duration);
786 } else {
787 category = RESOLVE_SPECULATIVE_SUCCESS;
788 DNS_HISTOGRAM("DNS.ResolveSpeculativeSuccess", duration);
789 }
[email protected]7e96d792011-06-10 17:08:23790
[email protected]78eac2a2012-03-14 19:09:27791 // Log DNS lookups based on |address_family|. This will help us determine
[email protected]7e96d792011-06-10 17:08:23792 // if IPv4 or IPv4/6 lookups are faster or slower.
793 switch(key_.address_family) {
794 case ADDRESS_FAMILY_IPV4:
795 DNS_HISTOGRAM("DNS.ResolveSuccess_FAMILY_IPV4", duration);
796 break;
797 case ADDRESS_FAMILY_IPV6:
798 DNS_HISTOGRAM("DNS.ResolveSuccess_FAMILY_IPV6", duration);
799 break;
800 case ADDRESS_FAMILY_UNSPECIFIED:
801 DNS_HISTOGRAM("DNS.ResolveSuccess_FAMILY_UNSPEC", duration);
802 break;
803 }
[email protected]1e9bbd22010-10-15 16:42:45804 } else {
805 if (had_non_speculative_request_) {
806 category = RESOLVE_FAIL;
807 DNS_HISTOGRAM("DNS.ResolveFail", duration);
808 } else {
809 category = RESOLVE_SPECULATIVE_FAIL;
810 DNS_HISTOGRAM("DNS.ResolveSpeculativeFail", duration);
811 }
[email protected]78eac2a2012-03-14 19:09:27812 // Log DNS lookups based on |address_family|. This will help us determine
[email protected]7e96d792011-06-10 17:08:23813 // if IPv4 or IPv4/6 lookups are faster or slower.
814 switch(key_.address_family) {
815 case ADDRESS_FAMILY_IPV4:
816 DNS_HISTOGRAM("DNS.ResolveFail_FAMILY_IPV4", duration);
817 break;
818 case ADDRESS_FAMILY_IPV6:
819 DNS_HISTOGRAM("DNS.ResolveFail_FAMILY_IPV6", duration);
820 break;
821 case ADDRESS_FAMILY_UNSPECIFIED:
822 DNS_HISTOGRAM("DNS.ResolveFail_FAMILY_UNSPEC", duration);
823 break;
824 }
[email protected]c833e322010-10-16 23:51:36825 UMA_HISTOGRAM_CUSTOM_ENUMERATION(kOSErrorsForGetAddrinfoHistogramName,
[email protected]189163e2011-05-11 01:48:54826 std::abs(os_error),
[email protected]1e9bbd22010-10-15 16:42:45827 GetAllGetAddrinfoOSErrors());
828 }
[email protected]051b6ab2010-10-18 16:50:46829 DCHECK_LT(category, static_cast<int>(RESOLVE_MAX)); // Be sure it was set.
[email protected]1e9bbd22010-10-15 16:42:45830
831 UMA_HISTOGRAM_ENUMERATION("DNS.ResolveCategory", category, RESOLVE_MAX);
832
[email protected]edafd4c2011-05-10 17:18:53833 static const bool show_speculative_experiment_histograms =
834 base::FieldTrialList::TrialExists("DnsImpact");
[email protected]ecd95ae2010-10-20 23:58:17835 if (show_speculative_experiment_histograms) {
[email protected]1e9bbd22010-10-15 16:42:45836 UMA_HISTOGRAM_ENUMERATION(
837 base::FieldTrial::MakeName("DNS.ResolveCategory", "DnsImpact"),
838 category, RESOLVE_MAX);
839 if (RESOLVE_SUCCESS == category) {
840 DNS_HISTOGRAM(base::FieldTrial::MakeName("DNS.ResolveSuccess",
841 "DnsImpact"), duration);
842 }
843 }
[email protected]edafd4c2011-05-10 17:18:53844 static const bool show_parallelism_experiment_histograms =
845 base::FieldTrialList::TrialExists("DnsParallelism");
[email protected]ecd95ae2010-10-20 23:58:17846 if (show_parallelism_experiment_histograms) {
847 UMA_HISTOGRAM_ENUMERATION(
848 base::FieldTrial::MakeName("DNS.ResolveCategory", "DnsParallelism"),
849 category, RESOLVE_MAX);
850 if (RESOLVE_SUCCESS == category) {
851 DNS_HISTOGRAM(base::FieldTrial::MakeName("DNS.ResolveSuccess",
852 "DnsParallelism"), duration);
853 }
854 }
[email protected]1e9bbd22010-10-15 16:42:45855 }
856
[email protected]189163e2011-05-11 01:48:54857 void RecordAttemptHistograms(const base::TimeTicks& start_time,
858 const uint32 attempt_number,
859 const int error,
860 const int os_error) const {
[email protected]0f292de02012-02-01 22:28:20861 DCHECK(origin_loop_->BelongsToCurrentThread());
[email protected]189163e2011-05-11 01:48:54862 bool first_attempt_to_complete =
863 completed_attempt_number_ == attempt_number;
[email protected]e87b8b512011-06-14 22:12:52864 bool is_first_attempt = (attempt_number == 1);
[email protected]1e9bbd22010-10-15 16:42:45865
[email protected]189163e2011-05-11 01:48:54866 if (first_attempt_to_complete) {
867 // If this was first attempt to complete, then record the resolution
868 // status of the attempt.
869 if (completed_attempt_error_ == OK) {
870 UMA_HISTOGRAM_ENUMERATION(
871 "DNS.AttemptFirstSuccess", attempt_number, 100);
872 } else {
873 UMA_HISTOGRAM_ENUMERATION(
874 "DNS.AttemptFirstFailure", attempt_number, 100);
875 }
876 }
877
878 if (error == OK)
879 UMA_HISTOGRAM_ENUMERATION("DNS.AttemptSuccess", attempt_number, 100);
880 else
881 UMA_HISTOGRAM_ENUMERATION("DNS.AttemptFailure", attempt_number, 100);
882
[email protected]e87b8b512011-06-14 22:12:52883 // If first attempt didn't finish before retry attempt, then calculate stats
884 // on how much time is saved by having spawned an extra attempt.
[email protected]0f292de02012-02-01 22:28:20885 if (!first_attempt_to_complete && is_first_attempt && !was_canceled()) {
[email protected]e87b8b512011-06-14 22:12:52886 DNS_HISTOGRAM("DNS.AttemptTimeSavedByRetry",
887 base::TimeTicks::Now() - retry_attempt_finished_time_);
888 }
889
[email protected]0f292de02012-02-01 22:28:20890 if (was_canceled() || !first_attempt_to_complete) {
[email protected]189163e2011-05-11 01:48:54891 // Count those attempts which completed after the job was already canceled
892 // OR after the job was already completed by an earlier attempt (so in
893 // effect).
894 UMA_HISTOGRAM_ENUMERATION("DNS.AttemptDiscarded", attempt_number, 100);
895
[email protected]0f292de02012-02-01 22:28:20896 // Record if job is canceled.
897 if (was_canceled())
[email protected]189163e2011-05-11 01:48:54898 UMA_HISTOGRAM_ENUMERATION("DNS.AttemptCancelled", attempt_number, 100);
899 }
900
901 base::TimeDelta duration = base::TimeTicks::Now() - start_time;
902 if (error == OK)
903 DNS_HISTOGRAM("DNS.AttemptSuccessDuration", duration);
904 else
905 DNS_HISTOGRAM("DNS.AttemptFailDuration", duration);
906 }
[email protected]1e9bbd22010-10-15 16:42:45907
[email protected]b59ff372009-07-15 22:04:32908 // Set on the origin thread, read on the worker thread.
[email protected]123ab1e32009-10-21 19:12:57909 Key key_;
[email protected]b59ff372009-07-15 22:04:32910
[email protected]0f292de02012-02-01 22:28:20911 // Holds an owning reference to the HostResolverProc that we are going to use.
[email protected]b59ff372009-07-15 22:04:32912 // This may not be the current resolver procedure by the time we call
913 // ResolveAddrInfo, but that's OK... we'll use it anyways, and the owning
914 // reference ensures that it remains valid until we are done.
[email protected]0f292de02012-02-01 22:28:20915 ProcTaskParams params_;
[email protected]b59ff372009-07-15 22:04:32916
[email protected]0f292de02012-02-01 22:28:20917 // The listener to the results of this ProcTask.
918 Callback callback_;
919
920 // Used to post ourselves onto the origin thread.
921 scoped_refptr<base::MessageLoopProxy> origin_loop_;
[email protected]189163e2011-05-11 01:48:54922
923 // Keeps track of the number of attempts we have made so far to resolve the
924 // host. Whenever we start an attempt to resolve the host, we increase this
925 // number.
926 uint32 attempt_number_;
927
928 // The index of the attempt which finished first (or 0 if the job is still in
929 // progress).
930 uint32 completed_attempt_number_;
931
932 // The result (a net error code) from the first attempt to complete.
933 int completed_attempt_error_;
[email protected]252b699b2010-02-05 21:38:06934
[email protected]e87b8b512011-06-14 22:12:52935 // The time when retry attempt was finished.
936 base::TimeTicks retry_attempt_finished_time_;
937
[email protected]252b699b2010-02-05 21:38:06938 // True if a non-speculative request was ever attached to this job
[email protected]0f292de02012-02-01 22:28:20939 // (regardless of whether or not it was later canceled.
[email protected]252b699b2010-02-05 21:38:06940 // This boolean is used for histogramming the duration of jobs used to
941 // service non-speculative requests.
942 bool had_non_speculative_request_;
943
[email protected]b59ff372009-07-15 22:04:32944 AddressList results_;
945
[email protected]ee094b82010-08-24 15:55:51946 BoundNetLog net_log_;
947
[email protected]0f292de02012-02-01 22:28:20948 DISALLOW_COPY_AND_ASSIGN(ProcTask);
[email protected]b59ff372009-07-15 22:04:32949};
950
951//-----------------------------------------------------------------------------
952
[email protected]0f292de02012-02-01 22:28:20953// Represents a request to the worker pool for a "probe for IPv6 support" call.
[email protected]b3601bc22012-02-21 21:23:20954//
955// TODO(szym): This could also be replaced with PostTaskAndReply and Callbacks.
[email protected]0f8f1b432010-03-16 19:06:03956class HostResolverImpl::IPv6ProbeJob
957 : public base::RefCountedThreadSafe<HostResolverImpl::IPv6ProbeJob> {
958 public:
959 explicit IPv6ProbeJob(HostResolverImpl* resolver)
960 : resolver_(resolver),
[email protected]edd685f2011-08-15 20:33:46961 origin_loop_(base::MessageLoopProxy::current()) {
[email protected]3e9d9cc2011-05-03 21:08:15962 DCHECK(resolver);
[email protected]0f8f1b432010-03-16 19:06:03963 }
964
965 void Start() {
[email protected]3e9d9cc2011-05-03 21:08:15966 DCHECK(origin_loop_->BelongsToCurrentThread());
[email protected]0f292de02012-02-01 22:28:20967 if (was_canceled())
[email protected]a9af7112010-05-08 00:56:01968 return;
[email protected]f092e64b2010-03-17 00:39:18969 const bool kIsSlow = true;
[email protected]ac9ba8fe2010-12-30 18:08:36970 base::WorkerPool::PostTask(
[email protected]33152acc2011-10-20 23:37:12971 FROM_HERE, base::Bind(&IPv6ProbeJob::DoProbe, this), kIsSlow);
[email protected]0f8f1b432010-03-16 19:06:03972 }
973
974 // Cancels the current job.
975 void Cancel() {
[email protected]3e9d9cc2011-05-03 21:08:15976 DCHECK(origin_loop_->BelongsToCurrentThread());
[email protected]0f292de02012-02-01 22:28:20977 if (was_canceled())
[email protected]a9af7112010-05-08 00:56:01978 return;
[email protected]0f8f1b432010-03-16 19:06:03979 resolver_ = NULL; // Read/write ONLY on origin thread.
[email protected]0f8f1b432010-03-16 19:06:03980 }
981
[email protected]0f8f1b432010-03-16 19:06:03982 private:
983 friend class base::RefCountedThreadSafe<HostResolverImpl::IPv6ProbeJob>;
984
985 ~IPv6ProbeJob() {
986 }
987
[email protected]0f292de02012-02-01 22:28:20988 bool was_canceled() const {
[email protected]3e9d9cc2011-05-03 21:08:15989 DCHECK(origin_loop_->BelongsToCurrentThread());
990 return !resolver_;
[email protected]a9af7112010-05-08 00:56:01991 }
992
[email protected]0f8f1b432010-03-16 19:06:03993 // Run on worker thread.
994 void DoProbe() {
995 // Do actual testing on this thread, as it takes 40-100ms.
996 AddressFamily family = IPv6Supported() ? ADDRESS_FAMILY_UNSPECIFIED
997 : ADDRESS_FAMILY_IPV4;
998
[email protected]3e9d9cc2011-05-03 21:08:15999 origin_loop_->PostTask(
1000 FROM_HERE,
[email protected]33152acc2011-10-20 23:37:121001 base::Bind(&IPv6ProbeJob::OnProbeComplete, this, family));
[email protected]0f8f1b432010-03-16 19:06:031002 }
1003
[email protected]3e9d9cc2011-05-03 21:08:151004 // Callback for when DoProbe() completes.
[email protected]0f8f1b432010-03-16 19:06:031005 void OnProbeComplete(AddressFamily address_family) {
[email protected]3e9d9cc2011-05-03 21:08:151006 DCHECK(origin_loop_->BelongsToCurrentThread());
[email protected]0f292de02012-02-01 22:28:201007 if (was_canceled())
[email protected]a9af7112010-05-08 00:56:011008 return;
[email protected]a9af7112010-05-08 00:56:011009 resolver_->IPv6ProbeSetDefaultAddressFamily(address_family);
[email protected]0f8f1b432010-03-16 19:06:031010 }
1011
[email protected]0f8f1b432010-03-16 19:06:031012 // Used/set only on origin thread.
1013 HostResolverImpl* resolver_;
1014
1015 // Used to post ourselves onto the origin thread.
[email protected]3e9d9cc2011-05-03 21:08:151016 scoped_refptr<base::MessageLoopProxy> origin_loop_;
[email protected]0f8f1b432010-03-16 19:06:031017
1018 DISALLOW_COPY_AND_ASSIGN(IPv6ProbeJob);
1019};
1020
1021//-----------------------------------------------------------------------------
1022
[email protected]b3601bc22012-02-21 21:23:201023// Resolves the hostname using DnsTransaction.
1024// TODO(szym): This could be moved to separate source file as well.
1025class HostResolverImpl::DnsTask {
1026 public:
1027 typedef base::Callback<void(int net_error,
1028 const AddressList& addr_list,
1029 base::TimeDelta ttl)> Callback;
1030
1031 DnsTask(DnsTransactionFactory* factory,
1032 const Key& key,
1033 const Callback& callback,
1034 const BoundNetLog& job_net_log)
1035 : callback_(callback), net_log_(job_net_log) {
1036 DCHECK(factory);
1037 DCHECK(!callback.is_null());
1038
1039 // For now we treat ADDRESS_FAMILY_UNSPEC as if it was IPV4.
1040 uint16 qtype = (key.address_family == ADDRESS_FAMILY_IPV6)
1041 ? dns_protocol::kTypeAAAA
1042 : dns_protocol::kTypeA;
1043 // TODO(szym): Implement "happy eyeballs".
1044 transaction_ = factory->CreateTransaction(
1045 key.hostname,
1046 qtype,
[email protected]1def74c2012-03-22 20:07:001047 base::Bind(&DnsTask::OnTransactionComplete, base::Unretained(this),
1048 base::TimeTicks::Now()),
[email protected]b3601bc22012-02-21 21:23:201049 net_log_);
1050 DCHECK(transaction_.get());
1051 }
1052
1053 int Start() {
1054 net_log_.BeginEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_DNS_TASK, NULL);
1055 return transaction_->Start();
1056 }
1057
[email protected]1def74c2012-03-22 20:07:001058 void OnTransactionComplete(const base::TimeTicks& start_time,
1059 DnsTransaction* transaction,
[email protected]b3601bc22012-02-21 21:23:201060 int net_error,
1061 const DnsResponse* response) {
[email protected]add76532012-03-30 14:47:471062 DCHECK(transaction);
[email protected]b3601bc22012-02-21 21:23:201063 // Run |callback_| last since the owning Job will then delete this DnsTask.
1064 DnsResponse::Result result = DnsResponse::DNS_SUCCESS;
1065 if (net_error == OK) {
[email protected]add76532012-03-30 14:47:471066 CHECK(response);
[email protected]1def74c2012-03-22 20:07:001067 DNS_HISTOGRAM("AsyncDNS.TransactionSuccess",
1068 base::TimeTicks::Now() - start_time);
[email protected]b3601bc22012-02-21 21:23:201069 AddressList addr_list;
1070 base::TimeDelta ttl;
1071 result = response->ParseToAddressList(&addr_list, &ttl);
[email protected]1def74c2012-03-22 20:07:001072 UMA_HISTOGRAM_ENUMERATION("AsyncDNS.ParseToAddressList",
1073 result,
1074 DnsResponse::DNS_PARSE_RESULT_MAX);
[email protected]b3601bc22012-02-21 21:23:201075 if (result == DnsResponse::DNS_SUCCESS) {
1076 net_log_.EndEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_DNS_TASK,
1077 new AddressListNetLogParam(addr_list));
1078 callback_.Run(net_error, addr_list, ttl);
1079 return;
1080 }
1081 net_error = ERR_DNS_MALFORMED_RESPONSE;
[email protected]1def74c2012-03-22 20:07:001082 } else {
1083 DNS_HISTOGRAM("AsyncDNS.TransactionFailure",
1084 base::TimeTicks::Now() - start_time);
[email protected]b3601bc22012-02-21 21:23:201085 }
1086 net_log_.EndEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_DNS_TASK,
1087 new DnsTaskFailedParams(net_error, result));
1088 callback_.Run(net_error, AddressList(), base::TimeDelta());
1089 }
1090
1091 private:
1092 // The listener to the results of this DnsTask.
1093 Callback callback_;
1094
1095 const BoundNetLog net_log_;
1096
1097 scoped_ptr<DnsTransaction> transaction_;
1098};
1099
1100//-----------------------------------------------------------------------------
1101
[email protected]0f292de02012-02-01 22:28:201102// Aggregates all Requests for the same Key. Dispatched via PriorityDispatch.
[email protected]0f292de02012-02-01 22:28:201103class HostResolverImpl::Job : public PrioritizedDispatcher::Job {
[email protected]68ad3ee2010-01-30 03:45:391104 public:
[email protected]0f292de02012-02-01 22:28:201105 // Creates new job for |key| where |request_net_log| is bound to the
[email protected]16ee26d2012-03-08 03:34:351106 // request that spawned it.
[email protected]0f292de02012-02-01 22:28:201107 Job(HostResolverImpl* resolver,
1108 const Key& key,
[email protected]16ee26d2012-03-08 03:34:351109 const BoundNetLog& request_net_log)
[email protected]0f292de02012-02-01 22:28:201110 : resolver_(resolver->AsWeakPtr()),
1111 key_(key),
1112 had_non_speculative_request_(false),
[email protected]1def74c2012-03-22 20:07:001113 had_dns_config_(false),
[email protected]0f292de02012-02-01 22:28:201114 net_log_(BoundNetLog::Make(request_net_log.net_log(),
[email protected]b3601bc22012-02-21 21:23:201115 NetLog::SOURCE_HOST_RESOLVER_IMPL_JOB)) {
[email protected]0f292de02012-02-01 22:28:201116 request_net_log.AddEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_CREATE_JOB, NULL);
1117
1118 net_log_.BeginEvent(
1119 NetLog::TYPE_HOST_RESOLVER_IMPL_JOB,
1120 make_scoped_refptr(new JobCreationParameters(
1121 key_.hostname, request_net_log.source())));
[email protected]68ad3ee2010-01-30 03:45:391122 }
1123
[email protected]0f292de02012-02-01 22:28:201124 virtual ~Job() {
[email protected]b3601bc22012-02-21 21:23:201125 if (is_running()) {
1126 // |resolver_| was destroyed with this Job still in flight.
1127 // Clean-up, record in the log, but don't run any callbacks.
1128 if (is_proc_running()) {
[email protected]0f292de02012-02-01 22:28:201129 proc_task_->Cancel();
1130 proc_task_ = NULL;
[email protected]0f292de02012-02-01 22:28:201131 }
[email protected]16ee26d2012-03-08 03:34:351132 // Clean up now for nice NetLog.
1133 dns_task_.reset(NULL);
[email protected]b3601bc22012-02-21 21:23:201134 net_log_.EndEventWithNetErrorCode(NetLog::TYPE_HOST_RESOLVER_IMPL_JOB,
1135 ERR_ABORTED);
1136 } else if (is_queued()) {
[email protected]57a48d32012-03-03 00:04:551137 // |resolver_| was destroyed without running this Job.
[email protected]16ee26d2012-03-08 03:34:351138 // TODO(szym): is there any benefit in having this distinction?
[email protected]b3601bc22012-02-21 21:23:201139 net_log_.AddEvent(NetLog::TYPE_CANCELLED, NULL);
1140 net_log_.EndEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_JOB, NULL);
[email protected]68ad3ee2010-01-30 03:45:391141 }
[email protected]b3601bc22012-02-21 21:23:201142 // else CompleteRequests logged EndEvent.
[email protected]68ad3ee2010-01-30 03:45:391143
[email protected]b3601bc22012-02-21 21:23:201144 // Log any remaining Requests as cancelled.
1145 for (RequestsList::const_iterator it = requests_.begin();
1146 it != requests_.end(); ++it) {
1147 Request* req = *it;
1148 if (req->was_canceled())
1149 continue;
1150 DCHECK_EQ(this, req->job());
1151 LogCancelRequest(req->source_net_log(), req->request_net_log(),
1152 req->info());
1153 }
[email protected]68ad3ee2010-01-30 03:45:391154 }
1155
[email protected]16ee26d2012-03-08 03:34:351156 // Add this job to the dispatcher.
1157 void Schedule(RequestPriority priority) {
1158 handle_ = resolver_->dispatcher_.Add(this, priority);
1159 }
1160
[email protected]b3601bc22012-02-21 21:23:201161 void AddRequest(scoped_ptr<Request> req) {
[email protected]0f292de02012-02-01 22:28:201162 DCHECK_EQ(key_.hostname, req->info().hostname());
1163
1164 req->set_job(this);
[email protected]0f292de02012-02-01 22:28:201165 priority_tracker_.Add(req->info().priority());
1166
1167 req->request_net_log().AddEvent(
1168 NetLog::TYPE_HOST_RESOLVER_IMPL_JOB_ATTACH,
1169 make_scoped_refptr(new NetLogSourceParameter(
1170 "source_dependency", net_log_.source())));
1171
1172 net_log_.AddEvent(
1173 NetLog::TYPE_HOST_RESOLVER_IMPL_JOB_REQUEST_ATTACH,
1174 make_scoped_refptr(new JobAttachParameters(
1175 req->request_net_log().source(), priority())));
1176
1177 // TODO(szym): Check if this is still needed.
1178 if (!req->info().is_speculative()) {
1179 had_non_speculative_request_ = true;
1180 if (proc_task_)
1181 proc_task_->set_had_non_speculative_request();
[email protected]68ad3ee2010-01-30 03:45:391182 }
[email protected]b3601bc22012-02-21 21:23:201183
1184 requests_.push_back(req.release());
1185
[email protected]16ee26d2012-03-08 03:34:351186 if (is_queued())
[email protected]b3601bc22012-02-21 21:23:201187 handle_ = resolver_->dispatcher_.ChangePriority(handle_, priority());
[email protected]68ad3ee2010-01-30 03:45:391188 }
1189
[email protected]16ee26d2012-03-08 03:34:351190 // Marks |req| as cancelled. If it was the last active Request, also finishes
1191 // this Job marking it either as aborted or cancelled, and deletes it.
[email protected]0f292de02012-02-01 22:28:201192 void CancelRequest(Request* req) {
1193 DCHECK_EQ(key_.hostname, req->info().hostname());
1194 DCHECK(!req->was_canceled());
[email protected]16ee26d2012-03-08 03:34:351195
[email protected]0f292de02012-02-01 22:28:201196 // Don't remove it from |requests_| just mark it canceled.
1197 req->MarkAsCanceled();
1198 LogCancelRequest(req->source_net_log(), req->request_net_log(),
1199 req->info());
[email protected]16ee26d2012-03-08 03:34:351200
[email protected]0f292de02012-02-01 22:28:201201 priority_tracker_.Remove(req->info().priority());
1202 net_log_.AddEvent(
1203 NetLog::TYPE_HOST_RESOLVER_IMPL_JOB_REQUEST_DETACH,
1204 make_scoped_refptr(new JobAttachParameters(
1205 req->request_net_log().source(), priority())));
[email protected]b3601bc22012-02-21 21:23:201206
[email protected]16ee26d2012-03-08 03:34:351207 if (num_active_requests() > 0) {
1208 if (is_queued())
[email protected]b3601bc22012-02-21 21:23:201209 handle_ = resolver_->dispatcher_.ChangePriority(handle_, priority());
[email protected]16ee26d2012-03-08 03:34:351210 } else {
1211 // If we were called from a Request's callback within CompleteRequests,
1212 // that Request could not have been cancelled, so num_active_requests()
1213 // could not be 0. Therefore, we are not in CompleteRequests().
1214 CompleteRequests(OK, AddressList(), base::TimeDelta());
[email protected]b3601bc22012-02-21 21:23:201215 }
[email protected]68ad3ee2010-01-30 03:45:391216 }
1217
[email protected]16ee26d2012-03-08 03:34:351218 // Called from AbortAllInProgressJobs. Completes all requests as aborted
1219 // and destroys the job.
[email protected]0f292de02012-02-01 22:28:201220 void Abort() {
[email protected]0f292de02012-02-01 22:28:201221 DCHECK(is_running());
[email protected]b3601bc22012-02-21 21:23:201222 CompleteRequests(ERR_ABORTED, AddressList(), base::TimeDelta());
1223 }
1224
[email protected]16ee26d2012-03-08 03:34:351225 // Called by HostResolverImpl when this job is evicted due to queue overflow.
1226 // Completes all requests and destroys the job.
1227 void OnEvicted() {
1228 DCHECK(!is_running());
1229 DCHECK(is_queued());
1230 handle_.Reset();
1231
1232 net_log_.AddEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_JOB_EVICTED, NULL);
1233
1234 // This signals to CompleteRequests that this job never ran.
1235 CompleteRequests(ERR_HOST_RESOLVER_QUEUE_TOO_LARGE,
1236 AddressList(),
1237 base::TimeDelta());
1238 }
1239
[email protected]78eac2a2012-03-14 19:09:271240 // Attempts to serve the job from HOSTS. Returns true if succeeded and
1241 // this Job was destroyed.
1242 bool ServeFromHosts() {
1243 DCHECK_GT(num_active_requests(), 0u);
1244 AddressList addr_list;
1245 if (resolver_->ServeFromHosts(key(),
[email protected]c143d892012-04-06 07:56:541246 requests_->front()->info(),
[email protected]78eac2a2012-03-14 19:09:271247 &addr_list)) {
1248 // This will destroy the Job.
1249 CompleteRequests(OK, addr_list, base::TimeDelta());
1250 return true;
1251 }
1252 return false;
1253 }
1254
[email protected]b4481b222012-03-16 17:13:111255 const Key key() const {
1256 return key_;
1257 }
1258
1259 bool is_queued() const {
1260 return !handle_.is_null();
1261 }
1262
1263 bool is_running() const {
1264 return is_dns_running() || is_proc_running();
1265 }
1266
[email protected]16ee26d2012-03-08 03:34:351267 private:
[email protected]16ee26d2012-03-08 03:34:351268 // PriorityDispatch::Job:
[email protected]0f292de02012-02-01 22:28:201269 virtual void Start() OVERRIDE {
1270 DCHECK(!is_running());
[email protected]b3601bc22012-02-21 21:23:201271 handle_.Reset();
[email protected]0f292de02012-02-01 22:28:201272
1273 net_log_.AddEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_JOB_STARTED, NULL);
1274
[email protected]1def74c2012-03-22 20:07:001275 had_dns_config_ = resolver_->HaveDnsConfig();
[email protected]16ee26d2012-03-08 03:34:351276 // Job::Start must not complete synchronously.
[email protected]1def74c2012-03-22 20:07:001277 if (had_dns_config_) {
[email protected]b3601bc22012-02-21 21:23:201278 StartDnsTask();
1279 } else {
1280 StartProcTask();
1281 }
1282 }
1283
[email protected]b3601bc22012-02-21 21:23:201284 // TODO(szym): Since DnsTransaction does not consume threads, we can increase
1285 // the limits on |dispatcher_|. But in order to keep the number of WorkerPool
1286 // threads low, we will need to use an "inner" PrioritizedDispatcher with
1287 // tighter limits.
1288 void StartProcTask() {
[email protected]16ee26d2012-03-08 03:34:351289 DCHECK(!is_dns_running());
[email protected]0f292de02012-02-01 22:28:201290 proc_task_ = new ProcTask(
1291 key_,
1292 resolver_->proc_params_,
1293 base::Bind(&Job::OnProcTaskComplete, base::Unretained(this)),
1294 net_log_);
1295
1296 if (had_non_speculative_request_)
1297 proc_task_->set_had_non_speculative_request();
1298 // Start() could be called from within Resolve(), hence it must NOT directly
1299 // call OnProcTaskComplete, for example, on synchronous failure.
1300 proc_task_->Start();
[email protected]68ad3ee2010-01-30 03:45:391301 }
1302
[email protected]0f292de02012-02-01 22:28:201303 // Called by ProcTask when it completes.
[email protected]b3601bc22012-02-21 21:23:201304 void OnProcTaskComplete(int net_error, const AddressList& addr_list) {
1305 DCHECK(is_proc_running());
[email protected]68ad3ee2010-01-30 03:45:391306
[email protected]1def74c2012-03-22 20:07:001307 if (had_dns_config_) {
1308 // TODO(szym): guess if the hostname is a NetBIOS name and discount it.
1309 if (net_error == OK) {
1310 UmaAsyncDnsResolveStatus(RESOLVE_STATUS_PROC_SUCCESS);
1311 } else {
1312 UmaAsyncDnsResolveStatus(RESOLVE_STATUS_FAIL);
1313 }
1314 }
1315
[email protected]b3601bc22012-02-21 21:23:201316 base::TimeDelta ttl = base::TimeDelta::FromSeconds(
1317 kNegativeCacheEntryTTLSeconds);
1318 if (net_error == OK)
1319 ttl = base::TimeDelta::FromSeconds(kCacheEntryTTLSeconds);
[email protected]68ad3ee2010-01-30 03:45:391320
[email protected]16ee26d2012-03-08 03:34:351321 CompleteRequests(net_error, addr_list, ttl);
[email protected]b3601bc22012-02-21 21:23:201322 }
1323
1324 void StartDnsTask() {
[email protected]78eac2a2012-03-14 19:09:271325 DCHECK(resolver_->HaveDnsConfig());
[email protected]b3601bc22012-02-21 21:23:201326 dns_task_.reset(new DnsTask(
[email protected]78eac2a2012-03-14 19:09:271327 resolver_->dns_client_->GetTransactionFactory(),
[email protected]b3601bc22012-02-21 21:23:201328 key_,
1329 base::Bind(&Job::OnDnsTaskComplete, base::Unretained(this)),
1330 net_log_));
1331
1332 int rv = dns_task_->Start();
1333 if (rv != ERR_IO_PENDING) {
1334 DCHECK_NE(OK, rv);
1335 dns_task_.reset();
1336 StartProcTask();
1337 }
1338 }
1339
1340 // Called by DnsTask when it completes.
1341 void OnDnsTaskComplete(int net_error,
1342 const AddressList& addr_list,
1343 base::TimeDelta ttl) {
1344 DCHECK(is_dns_running());
[email protected]b3601bc22012-02-21 21:23:201345
1346 if (net_error != OK) {
[email protected]16ee26d2012-03-08 03:34:351347 dns_task_.reset();
[email protected]78eac2a2012-03-14 19:09:271348
1349 // TODO(szym): Run ServeFromHosts now if nsswitch.conf says so.
1350 // http://crbug.com/117655
1351
[email protected]b3601bc22012-02-21 21:23:201352 // TODO(szym): Some net errors indicate lack of connectivity. Starting
1353 // ProcTask in that case is a waste of time.
1354 StartProcTask();
1355 return;
1356 }
1357
[email protected]1def74c2012-03-22 20:07:001358 UmaAsyncDnsResolveStatus(RESOLVE_STATUS_DNS_SUCCESS);
[email protected]16ee26d2012-03-08 03:34:351359 CompleteRequests(net_error, addr_list, ttl);
[email protected]b3601bc22012-02-21 21:23:201360 }
1361
[email protected]16ee26d2012-03-08 03:34:351362 // Performs Job's last rites. Completes all Requests. Deletes this.
[email protected]b3601bc22012-02-21 21:23:201363 void CompleteRequests(int net_error,
1364 const AddressList& addr_list,
1365 base::TimeDelta ttl) {
1366 CHECK(resolver_);
[email protected]b3601bc22012-02-21 21:23:201367
[email protected]16ee26d2012-03-08 03:34:351368 // This job must be removed from resolver's |jobs_| now to make room for a
1369 // new job with the same key in case one of the OnComplete callbacks decides
1370 // to spawn one. Consequently, the job deletes itself when CompleteRequests
1371 // is done.
1372 scoped_ptr<Job> self_deleter(this);
1373
1374 resolver_->RemoveJob(this);
1375
1376 // |addr_list| will be destroyed once we destroy |proc_task_| and
1377 // |dns_task_|.
[email protected]b3601bc22012-02-21 21:23:201378 AddressList list = addr_list;
[email protected]16ee26d2012-03-08 03:34:351379
1380 if (is_running()) {
1381 DCHECK(!is_queued());
1382 if (is_proc_running()) {
1383 proc_task_->Cancel();
1384 proc_task_ = NULL;
1385 }
1386 dns_task_.reset();
1387
1388 // Signal dispatcher that a slot has opened.
1389 resolver_->dispatcher_.OnJobFinished();
1390 } else if (is_queued()) {
1391 resolver_->dispatcher_.Cancel(handle_);
1392 handle_.Reset();
1393 }
1394
1395 if (num_active_requests() == 0) {
1396 net_log_.AddEvent(NetLog::TYPE_CANCELLED, NULL);
1397 net_log_.EndEventWithNetErrorCode(NetLog::TYPE_HOST_RESOLVER_IMPL_JOB,
1398 OK);
1399 return;
1400 }
[email protected]b3601bc22012-02-21 21:23:201401
1402 net_log_.EndEventWithNetErrorCode(NetLog::TYPE_HOST_RESOLVER_IMPL_JOB,
1403 net_error);
[email protected]68ad3ee2010-01-30 03:45:391404
[email protected]78eac2a2012-03-14 19:09:271405 DCHECK(!requests_.empty());
1406
[email protected]16ee26d2012-03-08 03:34:351407 // We are the only consumer of |list|, so we can safely change the port
1408 // without copy-on-write. This pays off, when job has only one request.
[email protected]78eac2a2012-03-14 19:09:271409 if (net_error == OK)
[email protected]c143d892012-04-06 07:56:541410 MutableSetPort(requests_->front()->info().port(), &list);
[email protected]16ee26d2012-03-08 03:34:351411
1412 if ((net_error != ERR_ABORTED) &&
1413 (net_error != ERR_HOST_RESOLVER_QUEUE_TOO_LARGE)) {
1414 resolver_->CacheResult(key_, net_error, list, ttl);
1415 }
1416
[email protected]0f292de02012-02-01 22:28:201417 // Complete all of the requests that were attached to the job.
1418 for (RequestsList::const_iterator it = requests_.begin();
1419 it != requests_.end(); ++it) {
1420 Request* req = *it;
1421
1422 if (req->was_canceled())
1423 continue;
1424
1425 DCHECK_EQ(this, req->job());
1426 // Update the net log and notify registered observers.
1427 LogFinishRequest(req->source_net_log(), req->request_net_log(),
[email protected]b3601bc22012-02-21 21:23:201428 req->info(), net_error);
[email protected]0f292de02012-02-01 22:28:201429
[email protected]b3601bc22012-02-21 21:23:201430 req->OnComplete(net_error, list);
[email protected]0f292de02012-02-01 22:28:201431
1432 // Check if the resolver was destroyed as a result of running the
1433 // callback. If it was, we could continue, but we choose to bail.
1434 if (!resolver_)
1435 return;
1436 }
1437 }
1438
[email protected]b4481b222012-03-16 17:13:111439 RequestPriority priority() const {
1440 return priority_tracker_.highest_priority();
1441 }
1442
1443 // Number of non-canceled requests in |requests_|.
1444 size_t num_active_requests() const {
1445 return priority_tracker_.total_count();
1446 }
1447
1448 bool is_dns_running() const {
1449 return dns_task_.get() != NULL;
1450 }
1451
1452 bool is_proc_running() const {
1453 return proc_task_.get() != NULL;
1454 }
1455
[email protected]0f292de02012-02-01 22:28:201456 base::WeakPtr<HostResolverImpl> resolver_;
1457
1458 Key key_;
1459
1460 // Tracks the highest priority across |requests_|.
1461 PriorityTracker priority_tracker_;
1462
1463 bool had_non_speculative_request_;
1464
[email protected]1def74c2012-03-22 20:07:001465 // True if resolver had DnsConfig when the Job was started.
1466 bool had_dns_config_;
1467
[email protected]0f292de02012-02-01 22:28:201468 BoundNetLog net_log_;
1469
[email protected]b3601bc22012-02-21 21:23:201470 // Resolves the host using a HostResolverProc.
[email protected]0f292de02012-02-01 22:28:201471 scoped_refptr<ProcTask> proc_task_;
1472
[email protected]b3601bc22012-02-21 21:23:201473 // Resolves the host using a DnsTransaction.
1474 scoped_ptr<DnsTask> dns_task_;
1475
[email protected]0f292de02012-02-01 22:28:201476 // All Requests waiting for the result of this Job. Some can be canceled.
1477 RequestsList requests_;
1478
[email protected]16ee26d2012-03-08 03:34:351479 // A handle used in |HostResolverImpl::dispatcher_|.
[email protected]0f292de02012-02-01 22:28:201480 PrioritizedDispatcher::Handle handle_;
[email protected]68ad3ee2010-01-30 03:45:391481};
1482
1483//-----------------------------------------------------------------------------
1484
[email protected]0f292de02012-02-01 22:28:201485HostResolverImpl::ProcTaskParams::ProcTaskParams(
[email protected]e95d3aca2010-01-11 22:47:431486 HostResolverProc* resolver_proc,
[email protected]0f292de02012-02-01 22:28:201487 size_t max_retry_attempts)
1488 : resolver_proc(resolver_proc),
1489 max_retry_attempts(max_retry_attempts),
1490 unresponsive_delay(base::TimeDelta::FromMilliseconds(6000)),
1491 retry_factor(2) {
1492}
1493
1494HostResolverImpl::ProcTaskParams::~ProcTaskParams() {}
1495
1496HostResolverImpl::HostResolverImpl(
[email protected]e95d3aca2010-01-11 22:47:431497 HostCache* cache,
[email protected]0f292de02012-02-01 22:28:201498 const PrioritizedDispatcher::Limits& job_limits,
1499 const ProcTaskParams& proc_params,
[email protected]b3601bc22012-02-21 21:23:201500 scoped_ptr<DnsConfigService> dns_config_service,
[email protected]ee094b82010-08-24 15:55:511501 NetLog* net_log)
[email protected]112bd462009-12-10 07:23:401502 : cache_(cache),
[email protected]0f292de02012-02-01 22:28:201503 dispatcher_(job_limits),
1504 max_queued_jobs_(job_limits.total_jobs * 100u),
1505 proc_params_(proc_params),
[email protected]0c7798452009-10-26 17:59:511506 default_address_family_(ADDRESS_FAMILY_UNSPECIFIED),
[email protected]78eac2a2012-03-14 19:09:271507 dns_client_(NULL),
[email protected]b3601bc22012-02-21 21:23:201508 dns_config_service_(dns_config_service.Pass()),
[email protected]2f3bc65c2010-07-23 17:47:101509 ipv6_probe_monitoring_(false),
[email protected]ee094b82010-08-24 15:55:511510 additional_resolver_flags_(0),
1511 net_log_(net_log) {
[email protected]0f292de02012-02-01 22:28:201512
1513 DCHECK_GE(dispatcher_.num_priorities(), static_cast<size_t>(NUM_PRIORITIES));
[email protected]68ad3ee2010-01-30 03:45:391514
[email protected]06ef6d92011-05-19 04:24:581515 // Maximum of 4 retry attempts for host resolution.
1516 static const size_t kDefaultMaxRetryAttempts = 4u;
1517
[email protected]0f292de02012-02-01 22:28:201518 if (proc_params_.max_retry_attempts == HostResolver::kDefaultRetryAttempts)
1519 proc_params_.max_retry_attempts = kDefaultMaxRetryAttempts;
[email protected]68ad3ee2010-01-30 03:45:391520
[email protected]b59ff372009-07-15 22:04:321521#if defined(OS_WIN)
1522 EnsureWinsockInit();
1523#endif
[email protected]23f771162011-06-02 18:37:511524#if defined(OS_POSIX) && !defined(OS_MACOSX)
[email protected]2f3bc65c2010-07-23 17:47:101525 if (HaveOnlyLoopbackAddresses())
1526 additional_resolver_flags_ |= HOST_RESOLVER_LOOPBACK_ONLY;
1527#endif
[email protected]232a5812011-03-04 22:42:081528 NetworkChangeNotifier::AddIPAddressObserver(this);
[email protected]46018c9d2011-09-06 03:42:341529#if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_OPENBSD)
[email protected]ae7c9f42011-11-21 11:41:161530#if !defined(OS_ANDROID)
[email protected]46018c9d2011-09-06 03:42:341531 EnsureDnsReloaderInit();
[email protected]ae7c9f42011-11-21 11:41:161532#endif
[email protected]46018c9d2011-09-06 03:42:341533 NetworkChangeNotifier::AddDNSObserver(this);
1534#endif
[email protected]b3601bc22012-02-21 21:23:201535
[email protected]78eac2a2012-03-14 19:09:271536 if (dns_config_service_.get()) {
[email protected]b4481b222012-03-16 17:13:111537 dns_config_service_->Watch(
1538 base::Bind(&HostResolverImpl::OnDnsConfigChanged,
1539 base::Unretained(this)));
[email protected]78eac2a2012-03-14 19:09:271540 dns_client_ = DnsClient::CreateClient(net_log_);
1541 }
[email protected]b59ff372009-07-15 22:04:321542}
1543
1544HostResolverImpl::~HostResolverImpl() {
[email protected]0f8f1b432010-03-16 19:06:031545 DiscardIPv6ProbeJob();
1546
[email protected]0f292de02012-02-01 22:28:201547 // This will also cancel all outstanding requests.
1548 STLDeleteValues(&jobs_);
[email protected]e95d3aca2010-01-11 22:47:431549
[email protected]232a5812011-03-04 22:42:081550 NetworkChangeNotifier::RemoveIPAddressObserver(this);
[email protected]46018c9d2011-09-06 03:42:341551#if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_OPENBSD)
1552 NetworkChangeNotifier::RemoveDNSObserver(this);
1553#endif
[email protected]b59ff372009-07-15 22:04:321554}
1555
[email protected]0f292de02012-02-01 22:28:201556void HostResolverImpl::SetMaxQueuedJobs(size_t value) {
1557 DCHECK_EQ(0u, dispatcher_.num_queued_jobs());
1558 DCHECK_GT(value, 0u);
1559 max_queued_jobs_ = value;
[email protected]be1a48b2011-01-20 00:12:131560}
1561
[email protected]684970b2009-08-14 04:54:461562int HostResolverImpl::Resolve(const RequestInfo& info,
[email protected]b59ff372009-07-15 22:04:321563 AddressList* addresses,
[email protected]aa22b242011-11-16 18:58:291564 const CompletionCallback& callback,
[email protected]684970b2009-08-14 04:54:461565 RequestHandle* out_req,
[email protected]ee094b82010-08-24 15:55:511566 const BoundNetLog& source_net_log) {
[email protected]95a214c2011-08-04 21:50:401567 DCHECK(addresses);
[email protected]1ac6af92010-06-03 21:00:141568 DCHECK(CalledOnValidThread());
[email protected]aa22b242011-11-16 18:58:291569 DCHECK_EQ(false, callback.is_null());
[email protected]1ac6af92010-06-03 21:00:141570
[email protected]ee094b82010-08-24 15:55:511571 // Make a log item for the request.
1572 BoundNetLog request_net_log = BoundNetLog::Make(net_log_,
1573 NetLog::SOURCE_HOST_RESOLVER_IMPL_REQUEST);
1574
[email protected]0f292de02012-02-01 22:28:201575 LogStartRequest(source_net_log, request_net_log, info);
[email protected]b59ff372009-07-15 22:04:321576
[email protected]123ab1e32009-10-21 19:12:571577 // Build a key that identifies the request in the cache and in the
1578 // outstanding jobs map.
[email protected]137af622010-02-05 02:14:351579 Key key = GetEffectiveKeyForRequest(info);
[email protected]123ab1e32009-10-21 19:12:571580
[email protected]287d7c22011-11-15 17:34:251581 int rv = ResolveHelper(key, info, addresses, request_net_log);
[email protected]95a214c2011-08-04 21:50:401582 if (rv != ERR_DNS_CACHE_MISS) {
[email protected]b3601bc22012-02-21 21:23:201583 LogFinishRequest(source_net_log, request_net_log, info, rv);
[email protected]95a214c2011-08-04 21:50:401584 return rv;
[email protected]38368712011-03-02 08:09:401585 }
1586
[email protected]0f292de02012-02-01 22:28:201587 // Next we need to attach our request to a "job". This job is responsible for
1588 // calling "getaddrinfo(hostname)" on a worker thread.
1589
1590 JobMap::iterator jobit = jobs_.find(key);
1591 Job* job;
1592 if (jobit == jobs_.end()) {
1593 // Create new Job.
[email protected]16ee26d2012-03-08 03:34:351594 job = new Job(this, key, request_net_log);
1595 job->Schedule(info.priority());
[email protected]0f292de02012-02-01 22:28:201596
1597 // Check for queue overflow.
1598 if (dispatcher_.num_queued_jobs() > max_queued_jobs_) {
1599 Job* evicted = static_cast<Job*>(dispatcher_.EvictOldestLowest());
1600 DCHECK(evicted);
[email protected]16ee26d2012-03-08 03:34:351601 evicted->OnEvicted(); // Deletes |evicted|.
[email protected]0f292de02012-02-01 22:28:201602 if (evicted == job) {
[email protected]0f292de02012-02-01 22:28:201603 rv = ERR_HOST_RESOLVER_QUEUE_TOO_LARGE;
[email protected]b3601bc22012-02-21 21:23:201604 LogFinishRequest(source_net_log, request_net_log, info, rv);
[email protected]0f292de02012-02-01 22:28:201605 return rv;
1606 }
[email protected]0f292de02012-02-01 22:28:201607 }
[email protected]0f292de02012-02-01 22:28:201608 jobs_.insert(jobit, std::make_pair(key, job));
1609 } else {
1610 job = jobit->second;
1611 }
1612
1613 // Can't complete synchronously. Create and attach request.
[email protected]b3601bc22012-02-21 21:23:201614 scoped_ptr<Request> req(new Request(source_net_log,
1615 request_net_log,
1616 info,
1617 callback,
1618 addresses));
[email protected]b59ff372009-07-15 22:04:321619 if (out_req)
[email protected]b3601bc22012-02-21 21:23:201620 *out_req = reinterpret_cast<RequestHandle>(req.get());
[email protected]b59ff372009-07-15 22:04:321621
[email protected]b3601bc22012-02-21 21:23:201622 job->AddRequest(req.Pass());
[email protected]0f292de02012-02-01 22:28:201623 // Completion happens during Job::CompleteRequests().
[email protected]b59ff372009-07-15 22:04:321624 return ERR_IO_PENDING;
1625}
1626
[email protected]287d7c22011-11-15 17:34:251627int HostResolverImpl::ResolveHelper(const Key& key,
[email protected]95a214c2011-08-04 21:50:401628 const RequestInfo& info,
1629 AddressList* addresses,
[email protected]20cd5332011-10-12 22:38:001630 const BoundNetLog& request_net_log) {
[email protected]95a214c2011-08-04 21:50:401631 // The result of |getaddrinfo| for empty hosts is inconsistent across systems.
1632 // On Windows it gives the default interface's address, whereas on Linux it
1633 // gives an error. We will make it fail on all platforms for consistency.
1634 if (info.hostname().empty() || info.hostname().size() > kMaxHostLength)
1635 return ERR_NAME_NOT_RESOLVED;
1636
1637 int net_error = ERR_UNEXPECTED;
1638 if (ResolveAsIP(key, info, &net_error, addresses))
1639 return net_error;
[email protected]78eac2a2012-03-14 19:09:271640 if (ServeFromCache(key, info, &net_error, addresses)) {
1641 request_net_log.AddEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_CACHE_HIT, NULL);
1642 return net_error;
1643 }
1644 // TODO(szym): Do not do this if nsswitch.conf instructs not to.
1645 // http://crbug.com/117655
1646 if (ServeFromHosts(key, info, addresses)) {
1647 request_net_log.AddEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_HOSTS_HIT, NULL);
1648 return OK;
1649 }
1650 return ERR_DNS_CACHE_MISS;
[email protected]95a214c2011-08-04 21:50:401651}
1652
1653int HostResolverImpl::ResolveFromCache(const RequestInfo& info,
1654 AddressList* addresses,
1655 const BoundNetLog& source_net_log) {
1656 DCHECK(CalledOnValidThread());
1657 DCHECK(addresses);
1658
[email protected]95a214c2011-08-04 21:50:401659 // Make a log item for the request.
1660 BoundNetLog request_net_log = BoundNetLog::Make(net_log_,
1661 NetLog::SOURCE_HOST_RESOLVER_IMPL_REQUEST);
1662
1663 // Update the net log and notify registered observers.
[email protected]0f292de02012-02-01 22:28:201664 LogStartRequest(source_net_log, request_net_log, info);
[email protected]95a214c2011-08-04 21:50:401665
[email protected]95a214c2011-08-04 21:50:401666 Key key = GetEffectiveKeyForRequest(info);
1667
[email protected]287d7c22011-11-15 17:34:251668 int rv = ResolveHelper(key, info, addresses, request_net_log);
[email protected]b3601bc22012-02-21 21:23:201669 LogFinishRequest(source_net_log, request_net_log, info, rv);
[email protected]95a214c2011-08-04 21:50:401670 return rv;
1671}
1672
[email protected]b59ff372009-07-15 22:04:321673void HostResolverImpl::CancelRequest(RequestHandle req_handle) {
[email protected]1ac6af92010-06-03 21:00:141674 DCHECK(CalledOnValidThread());
[email protected]b59ff372009-07-15 22:04:321675 Request* req = reinterpret_cast<Request*>(req_handle);
1676 DCHECK(req);
[email protected]0f292de02012-02-01 22:28:201677 Job* job = req->job();
1678 DCHECK(job);
[email protected]0f292de02012-02-01 22:28:201679 job->CancelRequest(req);
[email protected]b59ff372009-07-15 22:04:321680}
1681
[email protected]0f8f1b432010-03-16 19:06:031682void HostResolverImpl::SetDefaultAddressFamily(AddressFamily address_family) {
[email protected]1ac6af92010-06-03 21:00:141683 DCHECK(CalledOnValidThread());
[email protected]0f8f1b432010-03-16 19:06:031684 ipv6_probe_monitoring_ = false;
1685 DiscardIPv6ProbeJob();
1686 default_address_family_ = address_family;
1687}
1688
[email protected]f7d310e2010-10-07 16:25:111689AddressFamily HostResolverImpl::GetDefaultAddressFamily() const {
1690 return default_address_family_;
1691}
1692
[email protected]a78f4272011-10-21 19:16:331693void HostResolverImpl::ProbeIPv6Support() {
1694 DCHECK(CalledOnValidThread());
1695 DCHECK(!ipv6_probe_monitoring_);
1696 ipv6_probe_monitoring_ = true;
1697 OnIPAddressChanged(); // Give initial setup call.
[email protected]ddb1e5a2010-12-13 20:10:451698}
1699
[email protected]489d1a82011-10-12 03:09:111700HostCache* HostResolverImpl::GetHostCache() {
1701 return cache_.get();
1702}
[email protected]95a214c2011-08-04 21:50:401703
[email protected]17e92032012-03-29 00:56:241704base::Value* HostResolverImpl::GetDnsConfigAsValue() const {
1705 // Check if async DNS is disabled.
1706 if (!dns_client_.get())
1707 return NULL;
1708
1709 // Check if async DNS is enabled, but we currently have no configuration
1710 // for it.
1711 const DnsConfig* dns_config = dns_client_->GetConfig();
1712 if (dns_config == NULL)
1713 return new DictionaryValue();
1714
1715 return dns_config->ToValue();
1716}
1717
[email protected]95a214c2011-08-04 21:50:401718bool HostResolverImpl::ResolveAsIP(const Key& key,
1719 const RequestInfo& info,
1720 int* net_error,
1721 AddressList* addresses) {
1722 DCHECK(addresses);
1723 DCHECK(net_error);
1724 IPAddressNumber ip_number;
1725 if (!ParseIPLiteralToNumber(key.hostname, &ip_number))
1726 return false;
1727
1728 DCHECK_EQ(key.host_resolver_flags &
1729 ~(HOST_RESOLVER_CANONNAME | HOST_RESOLVER_LOOPBACK_ONLY |
1730 HOST_RESOLVER_DEFAULT_FAMILY_SET_DUE_TO_NO_IPV6),
1731 0) << " Unhandled flag";
[email protected]0f292de02012-02-01 22:28:201732 bool ipv6_disabled = (default_address_family_ == ADDRESS_FAMILY_IPV4) &&
1733 !ipv6_probe_monitoring_;
[email protected]95a214c2011-08-04 21:50:401734 *net_error = OK;
[email protected]0f292de02012-02-01 22:28:201735 if ((ip_number.size() == kIPv6AddressSize) && ipv6_disabled) {
[email protected]95a214c2011-08-04 21:50:401736 *net_error = ERR_NAME_NOT_RESOLVED;
1737 } else {
1738 *addresses = AddressList::CreateFromIPAddressWithCname(
1739 ip_number, info.port(),
1740 (key.host_resolver_flags & HOST_RESOLVER_CANONNAME));
1741 }
1742 return true;
1743}
1744
1745bool HostResolverImpl::ServeFromCache(const Key& key,
1746 const RequestInfo& info,
[email protected]95a214c2011-08-04 21:50:401747 int* net_error,
1748 AddressList* addresses) {
1749 DCHECK(addresses);
1750 DCHECK(net_error);
1751 if (!info.allow_cached_response() || !cache_.get())
1752 return false;
1753
1754 const HostCache::Entry* cache_entry = cache_->Lookup(
1755 key, base::TimeTicks::Now());
1756 if (!cache_entry)
1757 return false;
1758
[email protected]95a214c2011-08-04 21:50:401759 *net_error = cache_entry->error;
1760 if (*net_error == OK)
1761 *addresses = CreateAddressListUsingPort(cache_entry->addrlist, info.port());
1762 return true;
1763}
1764
[email protected]78eac2a2012-03-14 19:09:271765bool HostResolverImpl::ServeFromHosts(const Key& key,
1766 const RequestInfo& info,
1767 AddressList* addresses) {
1768 DCHECK(addresses);
1769 if (!HaveDnsConfig())
1770 return false;
1771
[email protected]cb507622012-03-23 16:17:061772 // HOSTS lookups are case-insensitive.
1773 std::string hostname = StringToLowerASCII(key.hostname);
1774
[email protected]78eac2a2012-03-14 19:09:271775 // If |address_family| is ADDRESS_FAMILY_UNSPECIFIED other implementations
1776 // (glibc and c-ares) return the first matching line. We have more
1777 // flexibility, but lose implicit ordering.
1778 // TODO(szym) http://crbug.com/117850
1779 const DnsHosts& hosts = dns_client_->GetConfig()->hosts;
1780 DnsHosts::const_iterator it = hosts.find(
[email protected]cb507622012-03-23 16:17:061781 DnsHostsKey(hostname,
[email protected]78eac2a2012-03-14 19:09:271782 key.address_family == ADDRESS_FAMILY_UNSPECIFIED ?
1783 ADDRESS_FAMILY_IPV4 : key.address_family));
1784
1785 if (it == hosts.end()) {
1786 if (key.address_family != ADDRESS_FAMILY_UNSPECIFIED)
1787 return false;
1788
[email protected]cb507622012-03-23 16:17:061789 it = hosts.find(DnsHostsKey(hostname, ADDRESS_FAMILY_IPV6));
[email protected]78eac2a2012-03-14 19:09:271790 if (it == hosts.end())
1791 return false;
1792 }
1793
1794 *addresses = AddressList::CreateFromIPAddress(it->second, info.port());
1795 return true;
1796}
1797
[email protected]16ee26d2012-03-08 03:34:351798void HostResolverImpl::CacheResult(const Key& key,
1799 int net_error,
1800 const AddressList& addr_list,
1801 base::TimeDelta ttl) {
1802 if (cache_.get())
1803 cache_->Set(key, net_error, addr_list, base::TimeTicks::Now(), ttl);
[email protected]ef4c40c2010-09-01 14:42:031804}
1805
[email protected]0f292de02012-02-01 22:28:201806void HostResolverImpl::RemoveJob(Job* job) {
1807 DCHECK(job);
[email protected]16ee26d2012-03-08 03:34:351808 JobMap::iterator it = jobs_.find(job->key());
1809 if (it != jobs_.end() && it->second == job)
1810 jobs_.erase(it);
[email protected]b59ff372009-07-15 22:04:321811}
1812
[email protected]0f8f1b432010-03-16 19:06:031813void HostResolverImpl::DiscardIPv6ProbeJob() {
1814 if (ipv6_probe_job_.get()) {
1815 ipv6_probe_job_->Cancel();
1816 ipv6_probe_job_ = NULL;
1817 }
1818}
1819
1820void HostResolverImpl::IPv6ProbeSetDefaultAddressFamily(
1821 AddressFamily address_family) {
1822 DCHECK(address_family == ADDRESS_FAMILY_UNSPECIFIED ||
1823 address_family == ADDRESS_FAMILY_IPV4);
[email protected]f092e64b2010-03-17 00:39:181824 if (default_address_family_ != address_family) {
[email protected]b30a3f52010-10-16 01:05:461825 VLOG(1) << "IPv6Probe forced AddressFamily setting to "
1826 << ((address_family == ADDRESS_FAMILY_UNSPECIFIED) ?
1827 "ADDRESS_FAMILY_UNSPECIFIED" : "ADDRESS_FAMILY_IPV4");
[email protected]f092e64b2010-03-17 00:39:181828 }
[email protected]0f8f1b432010-03-16 19:06:031829 default_address_family_ = address_family;
1830 // Drop reference since the job has called us back.
1831 DiscardIPv6ProbeJob();
[email protected]e95d3aca2010-01-11 22:47:431832}
1833
[email protected]137af622010-02-05 02:14:351834HostResolverImpl::Key HostResolverImpl::GetEffectiveKeyForRequest(
1835 const RequestInfo& info) const {
[email protected]eaf3a3b2010-09-03 20:34:271836 HostResolverFlags effective_flags =
1837 info.host_resolver_flags() | additional_resolver_flags_;
[email protected]137af622010-02-05 02:14:351838 AddressFamily effective_address_family = info.address_family();
[email protected]eaf3a3b2010-09-03 20:34:271839 if (effective_address_family == ADDRESS_FAMILY_UNSPECIFIED &&
1840 default_address_family_ != ADDRESS_FAMILY_UNSPECIFIED) {
[email protected]137af622010-02-05 02:14:351841 effective_address_family = default_address_family_;
[email protected]eaf3a3b2010-09-03 20:34:271842 if (ipv6_probe_monitoring_)
1843 effective_flags |= HOST_RESOLVER_DEFAULT_FAMILY_SET_DUE_TO_NO_IPV6;
1844 }
1845 return Key(info.hostname(), effective_address_family, effective_flags);
[email protected]137af622010-02-05 02:14:351846}
1847
[email protected]35ddc282010-09-21 23:42:061848void HostResolverImpl::AbortAllInProgressJobs() {
[email protected]b3601bc22012-02-21 21:23:201849 // In Abort, a Request callback could spawn new Jobs with matching keys, so
1850 // first collect and remove all running jobs from |jobs_|.
[email protected]c143d892012-04-06 07:56:541851 ScopedVector<Job> jobs_to_abort;
[email protected]0f292de02012-02-01 22:28:201852 for (JobMap::iterator it = jobs_.begin(); it != jobs_.end(); ) {
1853 Job* job = it->second;
[email protected]0f292de02012-02-01 22:28:201854 if (job->is_running()) {
[email protected]b3601bc22012-02-21 21:23:201855 jobs_to_abort.push_back(job);
1856 jobs_.erase(it++);
[email protected]0f292de02012-02-01 22:28:201857 } else {
[email protected]b3601bc22012-02-21 21:23:201858 DCHECK(job->is_queued());
1859 ++it;
[email protected]0f292de02012-02-01 22:28:201860 }
[email protected]ef4c40c2010-09-01 14:42:031861 }
[email protected]b3601bc22012-02-21 21:23:201862
[email protected]57a48d32012-03-03 00:04:551863 // Check if no dispatcher slots leaked out.
1864 DCHECK_EQ(dispatcher_.num_running_jobs(), jobs_to_abort.size());
1865
1866 // Life check to bail once |this| is deleted.
1867 base::WeakPtr<HostResolverImpl> self = AsWeakPtr();
1868
[email protected]16ee26d2012-03-08 03:34:351869 // Then Abort them.
[email protected]57a48d32012-03-03 00:04:551870 for (size_t i = 0; self && i < jobs_to_abort.size(); ++i) {
[email protected]57a48d32012-03-03 00:04:551871 jobs_to_abort[i]->Abort();
[email protected]c143d892012-04-06 07:56:541872 jobs_to_abort[i] = NULL;
[email protected]b3601bc22012-02-21 21:23:201873 }
[email protected]ef4c40c2010-09-01 14:42:031874}
1875
[email protected]78eac2a2012-03-14 19:09:271876void HostResolverImpl::TryServingAllJobsFromHosts() {
1877 if (!HaveDnsConfig())
1878 return;
1879
1880 // TODO(szym): Do not do this if nsswitch.conf instructs not to.
1881 // http://crbug.com/117655
1882
1883 // Life check to bail once |this| is deleted.
1884 base::WeakPtr<HostResolverImpl> self = AsWeakPtr();
1885
1886 for (JobMap::iterator it = jobs_.begin(); self && it != jobs_.end(); ) {
1887 Job* job = it->second;
1888 ++it;
1889 // This could remove |job| from |jobs_|, but iterator will remain valid.
1890 job->ServeFromHosts();
1891 }
1892}
1893
[email protected]be1a48b2011-01-20 00:12:131894void HostResolverImpl::OnIPAddressChanged() {
1895 if (cache_.get())
1896 cache_->clear();
1897 if (ipv6_probe_monitoring_) {
[email protected]be1a48b2011-01-20 00:12:131898 DiscardIPv6ProbeJob();
1899 ipv6_probe_job_ = new IPv6ProbeJob(this);
1900 ipv6_probe_job_->Start();
1901 }
[email protected]23f771162011-06-02 18:37:511902#if defined(OS_POSIX) && !defined(OS_MACOSX)
[email protected]be1a48b2011-01-20 00:12:131903 if (HaveOnlyLoopbackAddresses()) {
1904 additional_resolver_flags_ |= HOST_RESOLVER_LOOPBACK_ONLY;
1905 } else {
1906 additional_resolver_flags_ &= ~HOST_RESOLVER_LOOPBACK_ONLY;
1907 }
1908#endif
1909 AbortAllInProgressJobs();
1910 // |this| may be deleted inside AbortAllInProgressJobs().
1911}
1912
[email protected]446df2952012-02-28 07:22:511913void HostResolverImpl::OnDNSChanged(unsigned detail) {
[email protected]46018c9d2011-09-06 03:42:341914 // If the DNS server has changed, existing cached info could be wrong so we
1915 // have to drop our internal cache :( Note that OS level DNS caches, such
1916 // as NSCD's cache should be dropped automatically by the OS when
1917 // resolv.conf changes so we don't need to do anything to clear that cache.
1918 if (cache_.get())
1919 cache_->clear();
1920 // Existing jobs will have been sent to the original server so they need to
1921 // be aborted. TODO(Craig): Should these jobs be restarted?
1922 AbortAllInProgressJobs();
1923 // |this| may be deleted inside AbortAllInProgressJobs().
1924}
1925
[email protected]b4481b222012-03-16 17:13:111926void HostResolverImpl::OnDnsConfigChanged(const DnsConfig& dns_config) {
1927 if (net_log_) {
1928 net_log_->AddGlobalEntry(
1929 NetLog::TYPE_DNS_CONFIG_CHANGED,
1930 make_scoped_refptr(new DnsConfigParameters(dns_config)));
1931 }
1932
[email protected]78eac2a2012-03-14 19:09:271933 DCHECK(dns_client_.get());
1934
1935 // Life check to bail once |this| is deleted.
1936 base::WeakPtr<HostResolverImpl> self = AsWeakPtr();
1937
[email protected]7b5db762012-03-24 09:02:011938 bool config_changed = (dns_client_->GetConfig() != NULL) &&
1939 !dns_config.EqualsIgnoreHosts(*dns_client_->GetConfig());
1940
1941 // We want a new factory in place, before we Abort running Jobs, so that the
1942 // newly started jobs use the new factory.
[email protected]78eac2a2012-03-14 19:09:271943 dns_client_->SetConfig(dns_config);
1944
[email protected]7b5db762012-03-24 09:02:011945 // Don't Abort running Jobs unless they were running on DnsTransaction and
1946 // DnsConfig changed beyond DnsHosts. HOSTS-only change will be resolved by
1947 // TryServingAllJobsFromHosts below.
1948 if (config_changed) {
1949 // TODO(szym): This will change once http://crbug.com/114827 is fixed.
[email protected]446df2952012-02-28 07:22:511950 OnDNSChanged(NetworkChangeNotifier::CHANGE_DNS_SETTINGS);
[email protected]7b5db762012-03-24 09:02:011951 }
[email protected]78eac2a2012-03-14 19:09:271952
1953 if (self && dns_config.IsValid())
1954 TryServingAllJobsFromHosts();
1955}
1956
1957bool HostResolverImpl::HaveDnsConfig() const {
1958 return (dns_client_.get() != NULL) && (dns_client_->GetConfig() != NULL);
[email protected]b3601bc22012-02-21 21:23:201959}
1960
[email protected]b59ff372009-07-15 22:04:321961} // namespace net