blob: e8902228b1a487c6b0faef1de1e3d85504c1d202 [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 {
319 DictionaryValue* dict = new DictionaryValue();
320
321 ListValue* list = new ListValue();
[email protected]bb4354d42012-03-20 03:42:44322 for (size_t i = 0; i < config_.nameservers.size(); ++i) {
[email protected]b4481b222012-03-16 17:13:11323 list->Append(Value::CreateStringValue(
324 config_.nameservers[i].ToString()));
325 }
326 dict->Set("nameservers", list);
327
328 list = new ListValue();
[email protected]bb4354d42012-03-20 03:42:44329 for (size_t i = 0; i < config_.search.size(); ++i) {
[email protected]b4481b222012-03-16 17:13:11330 list->Append(Value::CreateStringValue(config_.search[i]));
331 }
332 dict->Set("search", list);
333
334 dict->SetBoolean("append_to_multi_label_name",
335 config_.append_to_multi_label_name);
336 dict->SetInteger("ndots", config_.ndots);
337 dict->SetDouble("timeout", config_.timeout.InSecondsF());
338 dict->SetInteger("attempts", config_.attempts);
339 dict->SetBoolean("rotate", config_.rotate);
340 dict->SetBoolean("edns0", config_.edns0);
341 dict->SetInteger("num_hosts", num_hosts_);
342
343 return dict;
344 }
345
346 private:
347 DnsConfig config_; // Does not include DnsHosts to save memory and work.
348 const size_t num_hosts_;
349};
350
[email protected]0f292de02012-02-01 22:28:20351// The logging routines are defined here because some requests are resolved
352// without a Request object.
353
354// Logs when a request has just been started.
355void LogStartRequest(const BoundNetLog& source_net_log,
356 const BoundNetLog& request_net_log,
357 const HostResolver::RequestInfo& info) {
358 source_net_log.BeginEvent(
359 NetLog::TYPE_HOST_RESOLVER_IMPL,
360 make_scoped_refptr(new NetLogSourceParameter(
361 "source_dependency", request_net_log.source())));
362
363 request_net_log.BeginEvent(
364 NetLog::TYPE_HOST_RESOLVER_IMPL_REQUEST,
365 make_scoped_refptr(new RequestInfoParameters(
366 info, source_net_log.source())));
367}
368
369// Logs when a request has just completed (before its callback is run).
370void LogFinishRequest(const BoundNetLog& source_net_log,
371 const BoundNetLog& request_net_log,
372 const HostResolver::RequestInfo& info,
[email protected]b3601bc22012-02-21 21:23:20373 int net_error) {
374 request_net_log.EndEventWithNetErrorCode(
375 NetLog::TYPE_HOST_RESOLVER_IMPL_REQUEST, net_error);
[email protected]0f292de02012-02-01 22:28:20376 source_net_log.EndEvent(NetLog::TYPE_HOST_RESOLVER_IMPL, NULL);
377}
378
379// Logs when a request has been cancelled.
380void LogCancelRequest(const BoundNetLog& source_net_log,
381 const BoundNetLog& request_net_log,
382 const HostResolverImpl::RequestInfo& info) {
383 request_net_log.AddEvent(NetLog::TYPE_CANCELLED, NULL);
384 request_net_log.EndEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_REQUEST, NULL);
385 source_net_log.EndEvent(NetLog::TYPE_HOST_RESOLVER_IMPL, NULL);
386}
387
[email protected]b59ff372009-07-15 22:04:32388//-----------------------------------------------------------------------------
389
[email protected]0f292de02012-02-01 22:28:20390// Keeps track of the highest priority.
391class PriorityTracker {
392 public:
[email protected]16ee26d2012-03-08 03:34:35393 PriorityTracker()
394 : highest_priority_(IDLE), total_count_(0) {
[email protected]0f292de02012-02-01 22:28:20395 memset(counts_, 0, sizeof(counts_));
396 }
397
398 RequestPriority highest_priority() const {
399 return highest_priority_;
400 }
401
402 size_t total_count() const {
403 return total_count_;
404 }
405
406 void Add(RequestPriority req_priority) {
407 ++total_count_;
408 ++counts_[req_priority];
409 if (highest_priority_ > req_priority)
410 highest_priority_ = req_priority;
411 }
412
413 void Remove(RequestPriority req_priority) {
414 DCHECK_GT(total_count_, 0u);
415 DCHECK_GT(counts_[req_priority], 0u);
416 --total_count_;
417 --counts_[req_priority];
418 size_t i;
419 for (i = highest_priority_; i < NUM_PRIORITIES && !counts_[i]; ++i);
420 highest_priority_ = static_cast<RequestPriority>(i);
421
422 // In absence of requests set default.
423 if (highest_priority_ == NUM_PRIORITIES) {
424 DCHECK_EQ(0u, total_count_);
425 highest_priority_ = IDLE;
426 }
427 }
428
429 private:
430 RequestPriority highest_priority_;
431 size_t total_count_;
432 size_t counts_[NUM_PRIORITIES];
433};
434
435//-----------------------------------------------------------------------------
436
437HostResolver* CreateHostResolver(size_t max_concurrent_resolves,
438 size_t max_retry_attempts,
[email protected]b3601bc22012-02-21 21:23:20439 HostCache* cache,
440 scoped_ptr<DnsConfigService> config_service,
[email protected]0f292de02012-02-01 22:28:20441 NetLog* net_log) {
442 if (max_concurrent_resolves == HostResolver::kDefaultParallelism)
443 max_concurrent_resolves = kDefaultMaxProcTasks;
444
445 // TODO(szym): Add experiments with reserved slots for higher priority
446 // requests.
447
448 PrioritizedDispatcher::Limits limits(NUM_PRIORITIES, max_concurrent_resolves);
449
450 HostResolverImpl* resolver = new HostResolverImpl(
[email protected]b3601bc22012-02-21 21:23:20451 cache,
[email protected]0f292de02012-02-01 22:28:20452 limits,
453 HostResolverImpl::ProcTaskParams(NULL, max_retry_attempts),
[email protected]b3601bc22012-02-21 21:23:20454 config_service.Pass(),
[email protected]0f292de02012-02-01 22:28:20455 net_log);
456
457 return resolver;
458}
459
460} // anonymous namespace
461
462//-----------------------------------------------------------------------------
463
464HostResolver* CreateSystemHostResolver(size_t max_concurrent_resolves,
465 size_t max_retry_attempts,
466 NetLog* net_log) {
467 return CreateHostResolver(max_concurrent_resolves,
468 max_retry_attempts,
[email protected]b3601bc22012-02-21 21:23:20469 HostCache::CreateDefaultCache(),
470 scoped_ptr<DnsConfigService>(NULL),
[email protected]0f292de02012-02-01 22:28:20471 net_log);
472}
473
474HostResolver* CreateNonCachingSystemHostResolver(size_t max_concurrent_resolves,
475 size_t max_retry_attempts,
476 NetLog* net_log) {
477 return CreateHostResolver(max_concurrent_resolves,
478 max_retry_attempts,
[email protected]b3601bc22012-02-21 21:23:20479 NULL,
480 scoped_ptr<DnsConfigService>(NULL),
481 net_log);
482}
483
484HostResolver* CreateAsyncHostResolver(size_t max_concurrent_resolves,
485 size_t max_retry_attempts,
486 NetLog* net_log) {
487 scoped_ptr<DnsConfigService> config_service =
488 DnsConfigService::CreateSystemService();
[email protected]b3601bc22012-02-21 21:23:20489 return CreateHostResolver(max_concurrent_resolves,
490 max_retry_attempts,
491 HostCache::CreateDefaultCache(),
492 config_service.Pass(),
[email protected]0f292de02012-02-01 22:28:20493 net_log);
494}
495
496//-----------------------------------------------------------------------------
497
498// Holds the data for a request that could not be completed synchronously.
499// It is owned by a Job. Canceled Requests are only marked as canceled rather
500// than removed from the Job's |requests_| list.
[email protected]b59ff372009-07-15 22:04:32501class HostResolverImpl::Request {
502 public:
[email protected]ee094b82010-08-24 15:55:51503 Request(const BoundNetLog& source_net_log,
504 const BoundNetLog& request_net_log,
[email protected]54e13772009-08-14 03:01:09505 const RequestInfo& info,
[email protected]aa22b242011-11-16 18:58:29506 const CompletionCallback& callback,
[email protected]b59ff372009-07-15 22:04:32507 AddressList* addresses)
[email protected]ee094b82010-08-24 15:55:51508 : source_net_log_(source_net_log),
509 request_net_log_(request_net_log),
[email protected]54e13772009-08-14 03:01:09510 info_(info),
511 job_(NULL),
512 callback_(callback),
513 addresses_(addresses) {
514 }
[email protected]b59ff372009-07-15 22:04:32515
[email protected]0f292de02012-02-01 22:28:20516 // Mark the request as canceled.
517 void MarkAsCanceled() {
[email protected]b59ff372009-07-15 22:04:32518 job_ = NULL;
[email protected]b59ff372009-07-15 22:04:32519 addresses_ = NULL;
[email protected]aa22b242011-11-16 18:58:29520 callback_.Reset();
[email protected]b59ff372009-07-15 22:04:32521 }
522
[email protected]0f292de02012-02-01 22:28:20523 bool was_canceled() const {
[email protected]aa22b242011-11-16 18:58:29524 return callback_.is_null();
[email protected]b59ff372009-07-15 22:04:32525 }
526
527 void set_job(Job* job) {
[email protected]0f292de02012-02-01 22:28:20528 DCHECK(job);
[email protected]b59ff372009-07-15 22:04:32529 // Identify which job the request is waiting on.
530 job_ = job;
531 }
532
[email protected]0f292de02012-02-01 22:28:20533 // Prepare final AddressList and call completion callback.
[email protected]b3601bc22012-02-21 21:23:20534 void OnComplete(int error, const AddressList& addr_list) {
[email protected]b59ff372009-07-15 22:04:32535 if (error == OK)
[email protected]b3601bc22012-02-21 21:23:20536 *addresses_ = CreateAddressListUsingPort(addr_list, info_.port());
[email protected]aa22b242011-11-16 18:58:29537 CompletionCallback callback = callback_;
[email protected]0f292de02012-02-01 22:28:20538 MarkAsCanceled();
[email protected]aa22b242011-11-16 18:58:29539 callback.Run(error);
[email protected]b59ff372009-07-15 22:04:32540 }
541
[email protected]b59ff372009-07-15 22:04:32542 Job* job() const {
543 return job_;
544 }
545
[email protected]0f292de02012-02-01 22:28:20546 // NetLog for the source, passed in HostResolver::Resolve.
[email protected]ee094b82010-08-24 15:55:51547 const BoundNetLog& source_net_log() {
548 return source_net_log_;
549 }
550
[email protected]0f292de02012-02-01 22:28:20551 // NetLog for this request.
[email protected]ee094b82010-08-24 15:55:51552 const BoundNetLog& request_net_log() {
553 return request_net_log_;
[email protected]54e13772009-08-14 03:01:09554 }
555
[email protected]b59ff372009-07-15 22:04:32556 const RequestInfo& info() const {
557 return info_;
558 }
559
560 private:
[email protected]ee094b82010-08-24 15:55:51561 BoundNetLog source_net_log_;
562 BoundNetLog request_net_log_;
[email protected]54e13772009-08-14 03:01:09563
[email protected]b59ff372009-07-15 22:04:32564 // The request info that started the request.
565 RequestInfo info_;
566
[email protected]0f292de02012-02-01 22:28:20567 // The resolve job that this request is dependent on.
[email protected]b59ff372009-07-15 22:04:32568 Job* job_;
569
570 // The user's callback to invoke when the request completes.
[email protected]aa22b242011-11-16 18:58:29571 CompletionCallback callback_;
[email protected]b59ff372009-07-15 22:04:32572
573 // The address list to save result into.
574 AddressList* addresses_;
575
576 DISALLOW_COPY_AND_ASSIGN(Request);
577};
578
[email protected]1e9bbd22010-10-15 16:42:45579//------------------------------------------------------------------------------
580
581// Provide a common macro to simplify code and readability. We must use a
582// macros as the underlying HISTOGRAM macro creates static varibles.
583#define DNS_HISTOGRAM(name, time) UMA_HISTOGRAM_CUSTOM_TIMES(name, time, \
584 base::TimeDelta::FromMicroseconds(1), base::TimeDelta::FromHours(1), 100)
[email protected]b59ff372009-07-15 22:04:32585
[email protected]0f292de02012-02-01 22:28:20586// Calls HostResolverProc on the WorkerPool. Performs retries if necessary.
587//
588// Whenever we try to resolve the host, we post a delayed task to check if host
589// resolution (OnLookupComplete) is completed or not. If the original attempt
590// hasn't completed, then we start another attempt for host resolution. We take
591// the results from the first attempt that finishes and ignore the results from
592// all other attempts.
593//
594// TODO(szym): Move to separate source file for testing and mocking.
595//
596class HostResolverImpl::ProcTask
597 : public base::RefCountedThreadSafe<HostResolverImpl::ProcTask> {
[email protected]b59ff372009-07-15 22:04:32598 public:
[email protected]b3601bc22012-02-21 21:23:20599 typedef base::Callback<void(int net_error,
600 const AddressList& addr_list)> Callback;
[email protected]b59ff372009-07-15 22:04:32601
[email protected]0f292de02012-02-01 22:28:20602 ProcTask(const Key& key,
603 const ProcTaskParams& params,
604 const Callback& callback,
605 const BoundNetLog& job_net_log)
606 : key_(key),
607 params_(params),
608 callback_(callback),
609 origin_loop_(base::MessageLoopProxy::current()),
610 attempt_number_(0),
611 completed_attempt_number_(0),
612 completed_attempt_error_(ERR_UNEXPECTED),
613 had_non_speculative_request_(false),
[email protected]b3601bc22012-02-21 21:23:20614 net_log_(job_net_log) {
[email protected]0f292de02012-02-01 22:28:20615 if (!params_.resolver_proc)
616 params_.resolver_proc = HostResolverProc::GetDefault();
617 // If default is unset, use the system proc.
618 if (!params_.resolver_proc)
619 params_.resolver_proc = new CallSystemHostResolverProc();
[email protected]b59ff372009-07-15 22:04:32620 }
621
[email protected]b59ff372009-07-15 22:04:32622 void Start() {
[email protected]3e9d9cc2011-05-03 21:08:15623 DCHECK(origin_loop_->BelongsToCurrentThread());
[email protected]9c571762012-02-27 19:12:40624 net_log_.BeginEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_PROC_TASK, NULL);
[email protected]189163e2011-05-11 01:48:54625 StartLookupAttempt();
626 }
[email protected]252b699b2010-02-05 21:38:06627
[email protected]0f292de02012-02-01 22:28:20628 // Cancels this ProcTask. It will be orphaned. Any outstanding resolve
629 // attempts running on worker threads will continue running. Only once all the
630 // attempts complete will the final reference to this ProcTask be released.
631 void Cancel() {
632 DCHECK(origin_loop_->BelongsToCurrentThread());
633
634 if (was_canceled())
635 return;
636
[email protected]0f292de02012-02-01 22:28:20637 callback_.Reset();
[email protected]0f292de02012-02-01 22:28:20638 net_log_.EndEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_PROC_TASK, NULL);
639 }
640
641 void set_had_non_speculative_request() {
642 DCHECK(origin_loop_->BelongsToCurrentThread());
643 had_non_speculative_request_ = true;
644 }
645
646 bool was_canceled() const {
647 DCHECK(origin_loop_->BelongsToCurrentThread());
648 return callback_.is_null();
649 }
650
651 bool was_completed() const {
652 DCHECK(origin_loop_->BelongsToCurrentThread());
653 return completed_attempt_number_ > 0;
654 }
655
656 private:
[email protected]189163e2011-05-11 01:48:54657 void StartLookupAttempt() {
658 DCHECK(origin_loop_->BelongsToCurrentThread());
659 base::TimeTicks start_time = base::TimeTicks::Now();
660 ++attempt_number_;
661 // Dispatch the lookup attempt to a worker thread.
662 if (!base::WorkerPool::PostTask(
663 FROM_HERE,
[email protected]0f292de02012-02-01 22:28:20664 base::Bind(&ProcTask::DoLookup, this, start_time, attempt_number_),
[email protected]189163e2011-05-11 01:48:54665 true)) {
[email protected]b59ff372009-07-15 22:04:32666 NOTREACHED();
667
668 // Since we could be running within Resolve() right now, we can't just
669 // call OnLookupComplete(). Instead we must wait until Resolve() has
670 // returned (IO_PENDING).
[email protected]3e9d9cc2011-05-03 21:08:15671 origin_loop_->PostTask(
[email protected]189163e2011-05-11 01:48:54672 FROM_HERE,
[email protected]0f292de02012-02-01 22:28:20673 base::Bind(&ProcTask::OnLookupComplete, this, AddressList(),
[email protected]33152acc2011-10-20 23:37:12674 start_time, attempt_number_, ERR_UNEXPECTED, 0));
[email protected]189163e2011-05-11 01:48:54675 return;
[email protected]b59ff372009-07-15 22:04:32676 }
[email protected]13024882011-05-18 23:19:16677
678 net_log_.AddEvent(
679 NetLog::TYPE_HOST_RESOLVER_IMPL_ATTEMPT_STARTED,
680 make_scoped_refptr(new NetLogIntegerParameter(
681 "attempt_number", attempt_number_)));
682
[email protected]0f292de02012-02-01 22:28:20683 // If we don't get the results within a given time, RetryIfNotComplete
684 // will start a new attempt on a different worker thread if none of our
685 // outstanding attempts have completed yet.
686 if (attempt_number_ <= params_.max_retry_attempts) {
[email protected]06ef6d92011-05-19 04:24:58687 origin_loop_->PostDelayedTask(
688 FROM_HERE,
[email protected]0f292de02012-02-01 22:28:20689 base::Bind(&ProcTask::RetryIfNotComplete, this),
[email protected]7e560102012-03-08 20:58:42690 params_.unresponsive_delay);
[email protected]06ef6d92011-05-19 04:24:58691 }
[email protected]b59ff372009-07-15 22:04:32692 }
693
[email protected]6c710ee2010-05-07 07:51:16694 // WARNING: This code runs inside a worker pool. The shutdown code cannot
695 // wait for it to finish, so we must be very careful here about using other
696 // objects (like MessageLoops, Singletons, etc). During shutdown these objects
[email protected]189163e2011-05-11 01:48:54697 // may no longer exist. Multiple DoLookups() could be running in parallel, so
698 // any state inside of |this| must not mutate .
699 void DoLookup(const base::TimeTicks& start_time,
700 const uint32 attempt_number) {
701 AddressList results;
702 int os_error = 0;
[email protected]b59ff372009-07-15 22:04:32703 // Running on the worker thread
[email protected]0f292de02012-02-01 22:28:20704 int error = params_.resolver_proc->Resolve(key_.hostname,
705 key_.address_family,
706 key_.host_resolver_flags,
707 &results,
708 &os_error);
[email protected]b59ff372009-07-15 22:04:32709
[email protected]189163e2011-05-11 01:48:54710 origin_loop_->PostTask(
711 FROM_HERE,
[email protected]0f292de02012-02-01 22:28:20712 base::Bind(&ProcTask::OnLookupComplete, this, results, start_time,
[email protected]33152acc2011-10-20 23:37:12713 attempt_number, error, os_error));
[email protected]189163e2011-05-11 01:48:54714 }
715
[email protected]0f292de02012-02-01 22:28:20716 // Makes next attempt if DoLookup() has not finished (runs on origin thread).
717 void RetryIfNotComplete() {
[email protected]189163e2011-05-11 01:48:54718 DCHECK(origin_loop_->BelongsToCurrentThread());
719
[email protected]0f292de02012-02-01 22:28:20720 if (was_completed() || was_canceled())
[email protected]189163e2011-05-11 01:48:54721 return;
722
[email protected]0f292de02012-02-01 22:28:20723 params_.unresponsive_delay *= params_.retry_factor;
[email protected]189163e2011-05-11 01:48:54724 StartLookupAttempt();
[email protected]b59ff372009-07-15 22:04:32725 }
726
727 // Callback for when DoLookup() completes (runs on origin thread).
[email protected]189163e2011-05-11 01:48:54728 void OnLookupComplete(const AddressList& results,
729 const base::TimeTicks& start_time,
730 const uint32 attempt_number,
731 int error,
732 const int os_error) {
[email protected]3e9d9cc2011-05-03 21:08:15733 DCHECK(origin_loop_->BelongsToCurrentThread());
[email protected]189163e2011-05-11 01:48:54734 DCHECK(error || results.head());
735
736 bool was_retry_attempt = attempt_number > 1;
737
[email protected]2d3b7762010-10-09 00:35:47738 // Ideally the following code would be part of host_resolver_proc.cc,
[email protected]b3601bc22012-02-21 21:23:20739 // however it isn't safe to call NetworkChangeNotifier from worker threads.
740 // So we do it here on the IO thread instead.
[email protected]189163e2011-05-11 01:48:54741 if (error != OK && NetworkChangeNotifier::IsOffline())
742 error = ERR_INTERNET_DISCONNECTED;
[email protected]2d3b7762010-10-09 00:35:47743
[email protected]b3601bc22012-02-21 21:23:20744 // If this is the first attempt that is finishing later, then record data
745 // for the first attempt. Won't contaminate with retry attempt's data.
[email protected]189163e2011-05-11 01:48:54746 if (!was_retry_attempt)
747 RecordPerformanceHistograms(start_time, error, os_error);
748
749 RecordAttemptHistograms(start_time, attempt_number, error, os_error);
[email protected]f2d8c4212010-02-02 00:56:35750
[email protected]0f292de02012-02-01 22:28:20751 if (was_canceled())
[email protected]b59ff372009-07-15 22:04:32752 return;
753
[email protected]0f292de02012-02-01 22:28:20754 scoped_refptr<NetLog::EventParameters> params;
755 if (error != OK) {
[email protected]b3601bc22012-02-21 21:23:20756 params = new ProcTaskFailedParams(attempt_number, error, os_error);
[email protected]0f292de02012-02-01 22:28:20757 } else {
[email protected]53b583b2012-02-09 00:10:47758 params = new NetLogIntegerParameter("attempt_number", attempt_number);
[email protected]0f292de02012-02-01 22:28:20759 }
760 net_log_.AddEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_ATTEMPT_FINISHED, params);
761
762 if (was_completed())
763 return;
764
765 // Copy the results from the first worker thread that resolves the host.
766 results_ = results;
767 completed_attempt_number_ = attempt_number;
768 completed_attempt_error_ = error;
769
[email protected]e87b8b512011-06-14 22:12:52770 if (was_retry_attempt) {
771 // If retry attempt finishes before 1st attempt, then get stats on how
772 // much time is saved by having spawned an extra attempt.
773 retry_attempt_finished_time_ = base::TimeTicks::Now();
774 }
775
[email protected]189163e2011-05-11 01:48:54776 if (error != OK) {
[email protected]b3601bc22012-02-21 21:23:20777 params = new ProcTaskFailedParams(0, error, os_error);
[email protected]ee094b82010-08-24 15:55:51778 } else {
779 params = new AddressListNetLogParam(results_);
780 }
[email protected]0f292de02012-02-01 22:28:20781 net_log_.EndEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_PROC_TASK, params);
[email protected]ee094b82010-08-24 15:55:51782
[email protected]b3601bc22012-02-21 21:23:20783 callback_.Run(error, results_);
[email protected]b59ff372009-07-15 22:04:32784 }
785
[email protected]189163e2011-05-11 01:48:54786 void RecordPerformanceHistograms(const base::TimeTicks& start_time,
787 const int error,
788 const int os_error) const {
[email protected]3e9d9cc2011-05-03 21:08:15789 DCHECK(origin_loop_->BelongsToCurrentThread());
[email protected]1e9bbd22010-10-15 16:42:45790 enum Category { // Used in HISTOGRAM_ENUMERATION.
791 RESOLVE_SUCCESS,
792 RESOLVE_FAIL,
793 RESOLVE_SPECULATIVE_SUCCESS,
794 RESOLVE_SPECULATIVE_FAIL,
795 RESOLVE_MAX, // Bounding value.
796 };
797 int category = RESOLVE_MAX; // Illegal value for later DCHECK only.
798
[email protected]189163e2011-05-11 01:48:54799 base::TimeDelta duration = base::TimeTicks::Now() - start_time;
800 if (error == OK) {
[email protected]1e9bbd22010-10-15 16:42:45801 if (had_non_speculative_request_) {
802 category = RESOLVE_SUCCESS;
803 DNS_HISTOGRAM("DNS.ResolveSuccess", duration);
804 } else {
805 category = RESOLVE_SPECULATIVE_SUCCESS;
806 DNS_HISTOGRAM("DNS.ResolveSpeculativeSuccess", duration);
807 }
[email protected]7e96d792011-06-10 17:08:23808
[email protected]78eac2a2012-03-14 19:09:27809 // Log DNS lookups based on |address_family|. This will help us determine
[email protected]7e96d792011-06-10 17:08:23810 // if IPv4 or IPv4/6 lookups are faster or slower.
811 switch(key_.address_family) {
812 case ADDRESS_FAMILY_IPV4:
813 DNS_HISTOGRAM("DNS.ResolveSuccess_FAMILY_IPV4", duration);
814 break;
815 case ADDRESS_FAMILY_IPV6:
816 DNS_HISTOGRAM("DNS.ResolveSuccess_FAMILY_IPV6", duration);
817 break;
818 case ADDRESS_FAMILY_UNSPECIFIED:
819 DNS_HISTOGRAM("DNS.ResolveSuccess_FAMILY_UNSPEC", duration);
820 break;
821 }
[email protected]1e9bbd22010-10-15 16:42:45822 } else {
823 if (had_non_speculative_request_) {
824 category = RESOLVE_FAIL;
825 DNS_HISTOGRAM("DNS.ResolveFail", duration);
826 } else {
827 category = RESOLVE_SPECULATIVE_FAIL;
828 DNS_HISTOGRAM("DNS.ResolveSpeculativeFail", duration);
829 }
[email protected]78eac2a2012-03-14 19:09:27830 // Log DNS lookups based on |address_family|. This will help us determine
[email protected]7e96d792011-06-10 17:08:23831 // if IPv4 or IPv4/6 lookups are faster or slower.
832 switch(key_.address_family) {
833 case ADDRESS_FAMILY_IPV4:
834 DNS_HISTOGRAM("DNS.ResolveFail_FAMILY_IPV4", duration);
835 break;
836 case ADDRESS_FAMILY_IPV6:
837 DNS_HISTOGRAM("DNS.ResolveFail_FAMILY_IPV6", duration);
838 break;
839 case ADDRESS_FAMILY_UNSPECIFIED:
840 DNS_HISTOGRAM("DNS.ResolveFail_FAMILY_UNSPEC", duration);
841 break;
842 }
[email protected]c833e322010-10-16 23:51:36843 UMA_HISTOGRAM_CUSTOM_ENUMERATION(kOSErrorsForGetAddrinfoHistogramName,
[email protected]189163e2011-05-11 01:48:54844 std::abs(os_error),
[email protected]1e9bbd22010-10-15 16:42:45845 GetAllGetAddrinfoOSErrors());
846 }
[email protected]051b6ab2010-10-18 16:50:46847 DCHECK_LT(category, static_cast<int>(RESOLVE_MAX)); // Be sure it was set.
[email protected]1e9bbd22010-10-15 16:42:45848
849 UMA_HISTOGRAM_ENUMERATION("DNS.ResolveCategory", category, RESOLVE_MAX);
850
[email protected]edafd4c2011-05-10 17:18:53851 static const bool show_speculative_experiment_histograms =
852 base::FieldTrialList::TrialExists("DnsImpact");
[email protected]ecd95ae2010-10-20 23:58:17853 if (show_speculative_experiment_histograms) {
[email protected]1e9bbd22010-10-15 16:42:45854 UMA_HISTOGRAM_ENUMERATION(
855 base::FieldTrial::MakeName("DNS.ResolveCategory", "DnsImpact"),
856 category, RESOLVE_MAX);
857 if (RESOLVE_SUCCESS == category) {
858 DNS_HISTOGRAM(base::FieldTrial::MakeName("DNS.ResolveSuccess",
859 "DnsImpact"), duration);
860 }
861 }
[email protected]edafd4c2011-05-10 17:18:53862 static const bool show_parallelism_experiment_histograms =
863 base::FieldTrialList::TrialExists("DnsParallelism");
[email protected]ecd95ae2010-10-20 23:58:17864 if (show_parallelism_experiment_histograms) {
865 UMA_HISTOGRAM_ENUMERATION(
866 base::FieldTrial::MakeName("DNS.ResolveCategory", "DnsParallelism"),
867 category, RESOLVE_MAX);
868 if (RESOLVE_SUCCESS == category) {
869 DNS_HISTOGRAM(base::FieldTrial::MakeName("DNS.ResolveSuccess",
870 "DnsParallelism"), duration);
871 }
872 }
[email protected]1e9bbd22010-10-15 16:42:45873 }
874
[email protected]189163e2011-05-11 01:48:54875 void RecordAttemptHistograms(const base::TimeTicks& start_time,
876 const uint32 attempt_number,
877 const int error,
878 const int os_error) const {
[email protected]0f292de02012-02-01 22:28:20879 DCHECK(origin_loop_->BelongsToCurrentThread());
[email protected]189163e2011-05-11 01:48:54880 bool first_attempt_to_complete =
881 completed_attempt_number_ == attempt_number;
[email protected]e87b8b512011-06-14 22:12:52882 bool is_first_attempt = (attempt_number == 1);
[email protected]1e9bbd22010-10-15 16:42:45883
[email protected]189163e2011-05-11 01:48:54884 if (first_attempt_to_complete) {
885 // If this was first attempt to complete, then record the resolution
886 // status of the attempt.
887 if (completed_attempt_error_ == OK) {
888 UMA_HISTOGRAM_ENUMERATION(
889 "DNS.AttemptFirstSuccess", attempt_number, 100);
890 } else {
891 UMA_HISTOGRAM_ENUMERATION(
892 "DNS.AttemptFirstFailure", attempt_number, 100);
893 }
894 }
895
896 if (error == OK)
897 UMA_HISTOGRAM_ENUMERATION("DNS.AttemptSuccess", attempt_number, 100);
898 else
899 UMA_HISTOGRAM_ENUMERATION("DNS.AttemptFailure", attempt_number, 100);
900
[email protected]e87b8b512011-06-14 22:12:52901 // If first attempt didn't finish before retry attempt, then calculate stats
902 // on how much time is saved by having spawned an extra attempt.
[email protected]0f292de02012-02-01 22:28:20903 if (!first_attempt_to_complete && is_first_attempt && !was_canceled()) {
[email protected]e87b8b512011-06-14 22:12:52904 DNS_HISTOGRAM("DNS.AttemptTimeSavedByRetry",
905 base::TimeTicks::Now() - retry_attempt_finished_time_);
906 }
907
[email protected]0f292de02012-02-01 22:28:20908 if (was_canceled() || !first_attempt_to_complete) {
[email protected]189163e2011-05-11 01:48:54909 // Count those attempts which completed after the job was already canceled
910 // OR after the job was already completed by an earlier attempt (so in
911 // effect).
912 UMA_HISTOGRAM_ENUMERATION("DNS.AttemptDiscarded", attempt_number, 100);
913
[email protected]0f292de02012-02-01 22:28:20914 // Record if job is canceled.
915 if (was_canceled())
[email protected]189163e2011-05-11 01:48:54916 UMA_HISTOGRAM_ENUMERATION("DNS.AttemptCancelled", attempt_number, 100);
917 }
918
919 base::TimeDelta duration = base::TimeTicks::Now() - start_time;
920 if (error == OK)
921 DNS_HISTOGRAM("DNS.AttemptSuccessDuration", duration);
922 else
923 DNS_HISTOGRAM("DNS.AttemptFailDuration", duration);
924 }
[email protected]1e9bbd22010-10-15 16:42:45925
[email protected]b59ff372009-07-15 22:04:32926 // Set on the origin thread, read on the worker thread.
[email protected]123ab1e32009-10-21 19:12:57927 Key key_;
[email protected]b59ff372009-07-15 22:04:32928
[email protected]0f292de02012-02-01 22:28:20929 // Holds an owning reference to the HostResolverProc that we are going to use.
[email protected]b59ff372009-07-15 22:04:32930 // This may not be the current resolver procedure by the time we call
931 // ResolveAddrInfo, but that's OK... we'll use it anyways, and the owning
932 // reference ensures that it remains valid until we are done.
[email protected]0f292de02012-02-01 22:28:20933 ProcTaskParams params_;
[email protected]b59ff372009-07-15 22:04:32934
[email protected]0f292de02012-02-01 22:28:20935 // The listener to the results of this ProcTask.
936 Callback callback_;
937
938 // Used to post ourselves onto the origin thread.
939 scoped_refptr<base::MessageLoopProxy> origin_loop_;
[email protected]189163e2011-05-11 01:48:54940
941 // Keeps track of the number of attempts we have made so far to resolve the
942 // host. Whenever we start an attempt to resolve the host, we increase this
943 // number.
944 uint32 attempt_number_;
945
946 // The index of the attempt which finished first (or 0 if the job is still in
947 // progress).
948 uint32 completed_attempt_number_;
949
950 // The result (a net error code) from the first attempt to complete.
951 int completed_attempt_error_;
[email protected]252b699b2010-02-05 21:38:06952
[email protected]e87b8b512011-06-14 22:12:52953 // The time when retry attempt was finished.
954 base::TimeTicks retry_attempt_finished_time_;
955
[email protected]252b699b2010-02-05 21:38:06956 // True if a non-speculative request was ever attached to this job
[email protected]0f292de02012-02-01 22:28:20957 // (regardless of whether or not it was later canceled.
[email protected]252b699b2010-02-05 21:38:06958 // This boolean is used for histogramming the duration of jobs used to
959 // service non-speculative requests.
960 bool had_non_speculative_request_;
961
[email protected]b59ff372009-07-15 22:04:32962 AddressList results_;
963
[email protected]ee094b82010-08-24 15:55:51964 BoundNetLog net_log_;
965
[email protected]0f292de02012-02-01 22:28:20966 DISALLOW_COPY_AND_ASSIGN(ProcTask);
[email protected]b59ff372009-07-15 22:04:32967};
968
969//-----------------------------------------------------------------------------
970
[email protected]0f292de02012-02-01 22:28:20971// Represents a request to the worker pool for a "probe for IPv6 support" call.
[email protected]b3601bc22012-02-21 21:23:20972//
973// TODO(szym): This could also be replaced with PostTaskAndReply and Callbacks.
[email protected]0f8f1b432010-03-16 19:06:03974class HostResolverImpl::IPv6ProbeJob
975 : public base::RefCountedThreadSafe<HostResolverImpl::IPv6ProbeJob> {
976 public:
977 explicit IPv6ProbeJob(HostResolverImpl* resolver)
978 : resolver_(resolver),
[email protected]edd685f2011-08-15 20:33:46979 origin_loop_(base::MessageLoopProxy::current()) {
[email protected]3e9d9cc2011-05-03 21:08:15980 DCHECK(resolver);
[email protected]0f8f1b432010-03-16 19:06:03981 }
982
983 void Start() {
[email protected]3e9d9cc2011-05-03 21:08:15984 DCHECK(origin_loop_->BelongsToCurrentThread());
[email protected]0f292de02012-02-01 22:28:20985 if (was_canceled())
[email protected]a9af7112010-05-08 00:56:01986 return;
[email protected]f092e64b2010-03-17 00:39:18987 const bool kIsSlow = true;
[email protected]ac9ba8fe2010-12-30 18:08:36988 base::WorkerPool::PostTask(
[email protected]33152acc2011-10-20 23:37:12989 FROM_HERE, base::Bind(&IPv6ProbeJob::DoProbe, this), kIsSlow);
[email protected]0f8f1b432010-03-16 19:06:03990 }
991
992 // Cancels the current job.
993 void Cancel() {
[email protected]3e9d9cc2011-05-03 21:08:15994 DCHECK(origin_loop_->BelongsToCurrentThread());
[email protected]0f292de02012-02-01 22:28:20995 if (was_canceled())
[email protected]a9af7112010-05-08 00:56:01996 return;
[email protected]0f8f1b432010-03-16 19:06:03997 resolver_ = NULL; // Read/write ONLY on origin thread.
[email protected]0f8f1b432010-03-16 19:06:03998 }
999
[email protected]0f8f1b432010-03-16 19:06:031000 private:
1001 friend class base::RefCountedThreadSafe<HostResolverImpl::IPv6ProbeJob>;
1002
1003 ~IPv6ProbeJob() {
1004 }
1005
[email protected]0f292de02012-02-01 22:28:201006 bool was_canceled() const {
[email protected]3e9d9cc2011-05-03 21:08:151007 DCHECK(origin_loop_->BelongsToCurrentThread());
1008 return !resolver_;
[email protected]a9af7112010-05-08 00:56:011009 }
1010
[email protected]0f8f1b432010-03-16 19:06:031011 // Run on worker thread.
1012 void DoProbe() {
1013 // Do actual testing on this thread, as it takes 40-100ms.
1014 AddressFamily family = IPv6Supported() ? ADDRESS_FAMILY_UNSPECIFIED
1015 : ADDRESS_FAMILY_IPV4;
1016
[email protected]3e9d9cc2011-05-03 21:08:151017 origin_loop_->PostTask(
1018 FROM_HERE,
[email protected]33152acc2011-10-20 23:37:121019 base::Bind(&IPv6ProbeJob::OnProbeComplete, this, family));
[email protected]0f8f1b432010-03-16 19:06:031020 }
1021
[email protected]3e9d9cc2011-05-03 21:08:151022 // Callback for when DoProbe() completes.
[email protected]0f8f1b432010-03-16 19:06:031023 void OnProbeComplete(AddressFamily address_family) {
[email protected]3e9d9cc2011-05-03 21:08:151024 DCHECK(origin_loop_->BelongsToCurrentThread());
[email protected]0f292de02012-02-01 22:28:201025 if (was_canceled())
[email protected]a9af7112010-05-08 00:56:011026 return;
[email protected]a9af7112010-05-08 00:56:011027 resolver_->IPv6ProbeSetDefaultAddressFamily(address_family);
[email protected]0f8f1b432010-03-16 19:06:031028 }
1029
[email protected]0f8f1b432010-03-16 19:06:031030 // Used/set only on origin thread.
1031 HostResolverImpl* resolver_;
1032
1033 // Used to post ourselves onto the origin thread.
[email protected]3e9d9cc2011-05-03 21:08:151034 scoped_refptr<base::MessageLoopProxy> origin_loop_;
[email protected]0f8f1b432010-03-16 19:06:031035
1036 DISALLOW_COPY_AND_ASSIGN(IPv6ProbeJob);
1037};
1038
1039//-----------------------------------------------------------------------------
1040
[email protected]b3601bc22012-02-21 21:23:201041// Resolves the hostname using DnsTransaction.
1042// TODO(szym): This could be moved to separate source file as well.
1043class HostResolverImpl::DnsTask {
1044 public:
1045 typedef base::Callback<void(int net_error,
1046 const AddressList& addr_list,
1047 base::TimeDelta ttl)> Callback;
1048
1049 DnsTask(DnsTransactionFactory* factory,
1050 const Key& key,
1051 const Callback& callback,
1052 const BoundNetLog& job_net_log)
1053 : callback_(callback), net_log_(job_net_log) {
1054 DCHECK(factory);
1055 DCHECK(!callback.is_null());
1056
1057 // For now we treat ADDRESS_FAMILY_UNSPEC as if it was IPV4.
1058 uint16 qtype = (key.address_family == ADDRESS_FAMILY_IPV6)
1059 ? dns_protocol::kTypeAAAA
1060 : dns_protocol::kTypeA;
1061 // TODO(szym): Implement "happy eyeballs".
1062 transaction_ = factory->CreateTransaction(
1063 key.hostname,
1064 qtype,
[email protected]1def74c2012-03-22 20:07:001065 base::Bind(&DnsTask::OnTransactionComplete, base::Unretained(this),
1066 base::TimeTicks::Now()),
[email protected]b3601bc22012-02-21 21:23:201067 net_log_);
1068 DCHECK(transaction_.get());
1069 }
1070
1071 int Start() {
1072 net_log_.BeginEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_DNS_TASK, NULL);
1073 return transaction_->Start();
1074 }
1075
[email protected]1def74c2012-03-22 20:07:001076 void OnTransactionComplete(const base::TimeTicks& start_time,
1077 DnsTransaction* transaction,
[email protected]b3601bc22012-02-21 21:23:201078 int net_error,
1079 const DnsResponse* response) {
[email protected]b3601bc22012-02-21 21:23:201080 // Run |callback_| last since the owning Job will then delete this DnsTask.
1081 DnsResponse::Result result = DnsResponse::DNS_SUCCESS;
1082 if (net_error == OK) {
[email protected]1def74c2012-03-22 20:07:001083 DNS_HISTOGRAM("AsyncDNS.TransactionSuccess",
1084 base::TimeTicks::Now() - start_time);
[email protected]b3601bc22012-02-21 21:23:201085 AddressList addr_list;
1086 base::TimeDelta ttl;
1087 result = response->ParseToAddressList(&addr_list, &ttl);
[email protected]1def74c2012-03-22 20:07:001088 UMA_HISTOGRAM_ENUMERATION("AsyncDNS.ParseToAddressList",
1089 result,
1090 DnsResponse::DNS_PARSE_RESULT_MAX);
[email protected]b3601bc22012-02-21 21:23:201091 if (result == DnsResponse::DNS_SUCCESS) {
1092 net_log_.EndEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_DNS_TASK,
1093 new AddressListNetLogParam(addr_list));
1094 callback_.Run(net_error, addr_list, ttl);
1095 return;
1096 }
1097 net_error = ERR_DNS_MALFORMED_RESPONSE;
[email protected]1def74c2012-03-22 20:07:001098 } else {
1099 DNS_HISTOGRAM("AsyncDNS.TransactionFailure",
1100 base::TimeTicks::Now() - start_time);
[email protected]b3601bc22012-02-21 21:23:201101 }
1102 net_log_.EndEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_DNS_TASK,
1103 new DnsTaskFailedParams(net_error, result));
1104 callback_.Run(net_error, AddressList(), base::TimeDelta());
1105 }
1106
1107 private:
1108 // The listener to the results of this DnsTask.
1109 Callback callback_;
1110
1111 const BoundNetLog net_log_;
1112
1113 scoped_ptr<DnsTransaction> transaction_;
1114};
1115
1116//-----------------------------------------------------------------------------
1117
[email protected]0f292de02012-02-01 22:28:201118// Aggregates all Requests for the same Key. Dispatched via PriorityDispatch.
[email protected]0f292de02012-02-01 22:28:201119class HostResolverImpl::Job : public PrioritizedDispatcher::Job {
[email protected]68ad3ee2010-01-30 03:45:391120 public:
[email protected]0f292de02012-02-01 22:28:201121 // Creates new job for |key| where |request_net_log| is bound to the
[email protected]16ee26d2012-03-08 03:34:351122 // request that spawned it.
[email protected]0f292de02012-02-01 22:28:201123 Job(HostResolverImpl* resolver,
1124 const Key& key,
[email protected]16ee26d2012-03-08 03:34:351125 const BoundNetLog& request_net_log)
[email protected]0f292de02012-02-01 22:28:201126 : resolver_(resolver->AsWeakPtr()),
1127 key_(key),
1128 had_non_speculative_request_(false),
[email protected]1def74c2012-03-22 20:07:001129 had_dns_config_(false),
[email protected]0f292de02012-02-01 22:28:201130 net_log_(BoundNetLog::Make(request_net_log.net_log(),
[email protected]b3601bc22012-02-21 21:23:201131 NetLog::SOURCE_HOST_RESOLVER_IMPL_JOB)) {
[email protected]0f292de02012-02-01 22:28:201132 request_net_log.AddEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_CREATE_JOB, NULL);
1133
1134 net_log_.BeginEvent(
1135 NetLog::TYPE_HOST_RESOLVER_IMPL_JOB,
1136 make_scoped_refptr(new JobCreationParameters(
1137 key_.hostname, request_net_log.source())));
[email protected]68ad3ee2010-01-30 03:45:391138 }
1139
[email protected]0f292de02012-02-01 22:28:201140 virtual ~Job() {
[email protected]b3601bc22012-02-21 21:23:201141 if (is_running()) {
1142 // |resolver_| was destroyed with this Job still in flight.
1143 // Clean-up, record in the log, but don't run any callbacks.
1144 if (is_proc_running()) {
[email protected]0f292de02012-02-01 22:28:201145 proc_task_->Cancel();
1146 proc_task_ = NULL;
[email protected]0f292de02012-02-01 22:28:201147 }
[email protected]16ee26d2012-03-08 03:34:351148 // Clean up now for nice NetLog.
1149 dns_task_.reset(NULL);
[email protected]b3601bc22012-02-21 21:23:201150 net_log_.EndEventWithNetErrorCode(NetLog::TYPE_HOST_RESOLVER_IMPL_JOB,
1151 ERR_ABORTED);
1152 } else if (is_queued()) {
[email protected]57a48d32012-03-03 00:04:551153 // |resolver_| was destroyed without running this Job.
[email protected]16ee26d2012-03-08 03:34:351154 // TODO(szym): is there any benefit in having this distinction?
[email protected]b3601bc22012-02-21 21:23:201155 net_log_.AddEvent(NetLog::TYPE_CANCELLED, NULL);
1156 net_log_.EndEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_JOB, NULL);
[email protected]68ad3ee2010-01-30 03:45:391157 }
[email protected]b3601bc22012-02-21 21:23:201158 // else CompleteRequests logged EndEvent.
[email protected]68ad3ee2010-01-30 03:45:391159
[email protected]b3601bc22012-02-21 21:23:201160 // Log any remaining Requests as cancelled.
1161 for (RequestsList::const_iterator it = requests_.begin();
1162 it != requests_.end(); ++it) {
1163 Request* req = *it;
1164 if (req->was_canceled())
1165 continue;
1166 DCHECK_EQ(this, req->job());
1167 LogCancelRequest(req->source_net_log(), req->request_net_log(),
1168 req->info());
1169 }
1170 STLDeleteElements(&requests_);
[email protected]68ad3ee2010-01-30 03:45:391171 }
1172
[email protected]16ee26d2012-03-08 03:34:351173 // Add this job to the dispatcher.
1174 void Schedule(RequestPriority priority) {
1175 handle_ = resolver_->dispatcher_.Add(this, priority);
1176 }
1177
[email protected]b3601bc22012-02-21 21:23:201178 void AddRequest(scoped_ptr<Request> req) {
[email protected]0f292de02012-02-01 22:28:201179 DCHECK_EQ(key_.hostname, req->info().hostname());
1180
1181 req->set_job(this);
[email protected]0f292de02012-02-01 22:28:201182 priority_tracker_.Add(req->info().priority());
1183
1184 req->request_net_log().AddEvent(
1185 NetLog::TYPE_HOST_RESOLVER_IMPL_JOB_ATTACH,
1186 make_scoped_refptr(new NetLogSourceParameter(
1187 "source_dependency", net_log_.source())));
1188
1189 net_log_.AddEvent(
1190 NetLog::TYPE_HOST_RESOLVER_IMPL_JOB_REQUEST_ATTACH,
1191 make_scoped_refptr(new JobAttachParameters(
1192 req->request_net_log().source(), priority())));
1193
1194 // TODO(szym): Check if this is still needed.
1195 if (!req->info().is_speculative()) {
1196 had_non_speculative_request_ = true;
1197 if (proc_task_)
1198 proc_task_->set_had_non_speculative_request();
[email protected]68ad3ee2010-01-30 03:45:391199 }
[email protected]b3601bc22012-02-21 21:23:201200
1201 requests_.push_back(req.release());
1202
[email protected]16ee26d2012-03-08 03:34:351203 if (is_queued())
[email protected]b3601bc22012-02-21 21:23:201204 handle_ = resolver_->dispatcher_.ChangePriority(handle_, priority());
[email protected]68ad3ee2010-01-30 03:45:391205 }
1206
[email protected]16ee26d2012-03-08 03:34:351207 // Marks |req| as cancelled. If it was the last active Request, also finishes
1208 // this Job marking it either as aborted or cancelled, and deletes it.
[email protected]0f292de02012-02-01 22:28:201209 void CancelRequest(Request* req) {
1210 DCHECK_EQ(key_.hostname, req->info().hostname());
1211 DCHECK(!req->was_canceled());
[email protected]16ee26d2012-03-08 03:34:351212
[email protected]0f292de02012-02-01 22:28:201213 // Don't remove it from |requests_| just mark it canceled.
1214 req->MarkAsCanceled();
1215 LogCancelRequest(req->source_net_log(), req->request_net_log(),
1216 req->info());
[email protected]16ee26d2012-03-08 03:34:351217
[email protected]0f292de02012-02-01 22:28:201218 priority_tracker_.Remove(req->info().priority());
1219 net_log_.AddEvent(
1220 NetLog::TYPE_HOST_RESOLVER_IMPL_JOB_REQUEST_DETACH,
1221 make_scoped_refptr(new JobAttachParameters(
1222 req->request_net_log().source(), priority())));
[email protected]b3601bc22012-02-21 21:23:201223
[email protected]16ee26d2012-03-08 03:34:351224 if (num_active_requests() > 0) {
1225 if (is_queued())
[email protected]b3601bc22012-02-21 21:23:201226 handle_ = resolver_->dispatcher_.ChangePriority(handle_, priority());
[email protected]16ee26d2012-03-08 03:34:351227 } else {
1228 // If we were called from a Request's callback within CompleteRequests,
1229 // that Request could not have been cancelled, so num_active_requests()
1230 // could not be 0. Therefore, we are not in CompleteRequests().
1231 CompleteRequests(OK, AddressList(), base::TimeDelta());
[email protected]b3601bc22012-02-21 21:23:201232 }
[email protected]68ad3ee2010-01-30 03:45:391233 }
1234
[email protected]16ee26d2012-03-08 03:34:351235 // Called from AbortAllInProgressJobs. Completes all requests as aborted
1236 // and destroys the job.
[email protected]0f292de02012-02-01 22:28:201237 void Abort() {
[email protected]0f292de02012-02-01 22:28:201238 DCHECK(is_running());
[email protected]b3601bc22012-02-21 21:23:201239 CompleteRequests(ERR_ABORTED, AddressList(), base::TimeDelta());
1240 }
1241
[email protected]16ee26d2012-03-08 03:34:351242 // Called by HostResolverImpl when this job is evicted due to queue overflow.
1243 // Completes all requests and destroys the job.
1244 void OnEvicted() {
1245 DCHECK(!is_running());
1246 DCHECK(is_queued());
1247 handle_.Reset();
1248
1249 net_log_.AddEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_JOB_EVICTED, NULL);
1250
1251 // This signals to CompleteRequests that this job never ran.
1252 CompleteRequests(ERR_HOST_RESOLVER_QUEUE_TOO_LARGE,
1253 AddressList(),
1254 base::TimeDelta());
1255 }
1256
[email protected]78eac2a2012-03-14 19:09:271257 // Attempts to serve the job from HOSTS. Returns true if succeeded and
1258 // this Job was destroyed.
1259 bool ServeFromHosts() {
1260 DCHECK_GT(num_active_requests(), 0u);
1261 AddressList addr_list;
1262 if (resolver_->ServeFromHosts(key(),
1263 requests_.front()->info(),
1264 &addr_list)) {
1265 // This will destroy the Job.
1266 CompleteRequests(OK, addr_list, base::TimeDelta());
1267 return true;
1268 }
1269 return false;
1270 }
1271
[email protected]b4481b222012-03-16 17:13:111272 const Key key() const {
1273 return key_;
1274 }
1275
1276 bool is_queued() const {
1277 return !handle_.is_null();
1278 }
1279
1280 bool is_running() const {
1281 return is_dns_running() || is_proc_running();
1282 }
1283
[email protected]16ee26d2012-03-08 03:34:351284 private:
[email protected]16ee26d2012-03-08 03:34:351285 // PriorityDispatch::Job:
[email protected]0f292de02012-02-01 22:28:201286 virtual void Start() OVERRIDE {
1287 DCHECK(!is_running());
[email protected]b3601bc22012-02-21 21:23:201288 handle_.Reset();
[email protected]0f292de02012-02-01 22:28:201289
1290 net_log_.AddEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_JOB_STARTED, NULL);
1291
[email protected]1def74c2012-03-22 20:07:001292 had_dns_config_ = resolver_->HaveDnsConfig();
[email protected]16ee26d2012-03-08 03:34:351293 // Job::Start must not complete synchronously.
[email protected]1def74c2012-03-22 20:07:001294 if (had_dns_config_) {
[email protected]b3601bc22012-02-21 21:23:201295 StartDnsTask();
1296 } else {
1297 StartProcTask();
1298 }
1299 }
1300
[email protected]b3601bc22012-02-21 21:23:201301 // TODO(szym): Since DnsTransaction does not consume threads, we can increase
1302 // the limits on |dispatcher_|. But in order to keep the number of WorkerPool
1303 // threads low, we will need to use an "inner" PrioritizedDispatcher with
1304 // tighter limits.
1305 void StartProcTask() {
[email protected]16ee26d2012-03-08 03:34:351306 DCHECK(!is_dns_running());
[email protected]0f292de02012-02-01 22:28:201307 proc_task_ = new ProcTask(
1308 key_,
1309 resolver_->proc_params_,
1310 base::Bind(&Job::OnProcTaskComplete, base::Unretained(this)),
1311 net_log_);
1312
1313 if (had_non_speculative_request_)
1314 proc_task_->set_had_non_speculative_request();
1315 // Start() could be called from within Resolve(), hence it must NOT directly
1316 // call OnProcTaskComplete, for example, on synchronous failure.
1317 proc_task_->Start();
[email protected]68ad3ee2010-01-30 03:45:391318 }
1319
[email protected]0f292de02012-02-01 22:28:201320 // Called by ProcTask when it completes.
[email protected]b3601bc22012-02-21 21:23:201321 void OnProcTaskComplete(int net_error, const AddressList& addr_list) {
1322 DCHECK(is_proc_running());
[email protected]68ad3ee2010-01-30 03:45:391323
[email protected]1def74c2012-03-22 20:07:001324 if (had_dns_config_) {
1325 // TODO(szym): guess if the hostname is a NetBIOS name and discount it.
1326 if (net_error == OK) {
1327 UmaAsyncDnsResolveStatus(RESOLVE_STATUS_PROC_SUCCESS);
1328 } else {
1329 UmaAsyncDnsResolveStatus(RESOLVE_STATUS_FAIL);
1330 }
1331 }
1332
[email protected]b3601bc22012-02-21 21:23:201333 base::TimeDelta ttl = base::TimeDelta::FromSeconds(
1334 kNegativeCacheEntryTTLSeconds);
1335 if (net_error == OK)
1336 ttl = base::TimeDelta::FromSeconds(kCacheEntryTTLSeconds);
[email protected]68ad3ee2010-01-30 03:45:391337
[email protected]16ee26d2012-03-08 03:34:351338 CompleteRequests(net_error, addr_list, ttl);
[email protected]b3601bc22012-02-21 21:23:201339 }
1340
1341 void StartDnsTask() {
[email protected]78eac2a2012-03-14 19:09:271342 DCHECK(resolver_->HaveDnsConfig());
[email protected]b3601bc22012-02-21 21:23:201343 dns_task_.reset(new DnsTask(
[email protected]78eac2a2012-03-14 19:09:271344 resolver_->dns_client_->GetTransactionFactory(),
[email protected]b3601bc22012-02-21 21:23:201345 key_,
1346 base::Bind(&Job::OnDnsTaskComplete, base::Unretained(this)),
1347 net_log_));
1348
1349 int rv = dns_task_->Start();
1350 if (rv != ERR_IO_PENDING) {
1351 DCHECK_NE(OK, rv);
1352 dns_task_.reset();
1353 StartProcTask();
1354 }
1355 }
1356
1357 // Called by DnsTask when it completes.
1358 void OnDnsTaskComplete(int net_error,
1359 const AddressList& addr_list,
1360 base::TimeDelta ttl) {
1361 DCHECK(is_dns_running());
[email protected]b3601bc22012-02-21 21:23:201362
1363 if (net_error != OK) {
[email protected]16ee26d2012-03-08 03:34:351364 dns_task_.reset();
[email protected]78eac2a2012-03-14 19:09:271365
1366 // TODO(szym): Run ServeFromHosts now if nsswitch.conf says so.
1367 // http://crbug.com/117655
1368
[email protected]b3601bc22012-02-21 21:23:201369 // TODO(szym): Some net errors indicate lack of connectivity. Starting
1370 // ProcTask in that case is a waste of time.
1371 StartProcTask();
1372 return;
1373 }
1374
[email protected]1def74c2012-03-22 20:07:001375 UmaAsyncDnsResolveStatus(RESOLVE_STATUS_DNS_SUCCESS);
[email protected]16ee26d2012-03-08 03:34:351376 CompleteRequests(net_error, addr_list, ttl);
[email protected]b3601bc22012-02-21 21:23:201377 }
1378
[email protected]16ee26d2012-03-08 03:34:351379 // Performs Job's last rites. Completes all Requests. Deletes this.
[email protected]b3601bc22012-02-21 21:23:201380 void CompleteRequests(int net_error,
1381 const AddressList& addr_list,
1382 base::TimeDelta ttl) {
1383 CHECK(resolver_);
[email protected]b3601bc22012-02-21 21:23:201384
[email protected]16ee26d2012-03-08 03:34:351385 // This job must be removed from resolver's |jobs_| now to make room for a
1386 // new job with the same key in case one of the OnComplete callbacks decides
1387 // to spawn one. Consequently, the job deletes itself when CompleteRequests
1388 // is done.
1389 scoped_ptr<Job> self_deleter(this);
1390
1391 resolver_->RemoveJob(this);
1392
1393 // |addr_list| will be destroyed once we destroy |proc_task_| and
1394 // |dns_task_|.
[email protected]b3601bc22012-02-21 21:23:201395 AddressList list = addr_list;
[email protected]16ee26d2012-03-08 03:34:351396
1397 if (is_running()) {
1398 DCHECK(!is_queued());
1399 if (is_proc_running()) {
1400 proc_task_->Cancel();
1401 proc_task_ = NULL;
1402 }
1403 dns_task_.reset();
1404
1405 // Signal dispatcher that a slot has opened.
1406 resolver_->dispatcher_.OnJobFinished();
1407 } else if (is_queued()) {
1408 resolver_->dispatcher_.Cancel(handle_);
1409 handle_.Reset();
1410 }
1411
1412 if (num_active_requests() == 0) {
1413 net_log_.AddEvent(NetLog::TYPE_CANCELLED, NULL);
1414 net_log_.EndEventWithNetErrorCode(NetLog::TYPE_HOST_RESOLVER_IMPL_JOB,
1415 OK);
1416 return;
1417 }
[email protected]b3601bc22012-02-21 21:23:201418
1419 net_log_.EndEventWithNetErrorCode(NetLog::TYPE_HOST_RESOLVER_IMPL_JOB,
1420 net_error);
[email protected]68ad3ee2010-01-30 03:45:391421
[email protected]78eac2a2012-03-14 19:09:271422 DCHECK(!requests_.empty());
1423
[email protected]16ee26d2012-03-08 03:34:351424 // We are the only consumer of |list|, so we can safely change the port
1425 // without copy-on-write. This pays off, when job has only one request.
[email protected]78eac2a2012-03-14 19:09:271426 if (net_error == OK)
[email protected]16ee26d2012-03-08 03:34:351427 MutableSetPort(requests_.front()->info().port(), &list);
1428
1429 if ((net_error != ERR_ABORTED) &&
1430 (net_error != ERR_HOST_RESOLVER_QUEUE_TOO_LARGE)) {
1431 resolver_->CacheResult(key_, net_error, list, ttl);
1432 }
1433
[email protected]0f292de02012-02-01 22:28:201434 // Complete all of the requests that were attached to the job.
1435 for (RequestsList::const_iterator it = requests_.begin();
1436 it != requests_.end(); ++it) {
1437 Request* req = *it;
1438
1439 if (req->was_canceled())
1440 continue;
1441
1442 DCHECK_EQ(this, req->job());
1443 // Update the net log and notify registered observers.
1444 LogFinishRequest(req->source_net_log(), req->request_net_log(),
[email protected]b3601bc22012-02-21 21:23:201445 req->info(), net_error);
[email protected]0f292de02012-02-01 22:28:201446
[email protected]b3601bc22012-02-21 21:23:201447 req->OnComplete(net_error, list);
[email protected]0f292de02012-02-01 22:28:201448
1449 // Check if the resolver was destroyed as a result of running the
1450 // callback. If it was, we could continue, but we choose to bail.
1451 if (!resolver_)
1452 return;
1453 }
1454 }
1455
[email protected]b4481b222012-03-16 17:13:111456 RequestPriority priority() const {
1457 return priority_tracker_.highest_priority();
1458 }
1459
1460 // Number of non-canceled requests in |requests_|.
1461 size_t num_active_requests() const {
1462 return priority_tracker_.total_count();
1463 }
1464
1465 bool is_dns_running() const {
1466 return dns_task_.get() != NULL;
1467 }
1468
1469 bool is_proc_running() const {
1470 return proc_task_.get() != NULL;
1471 }
1472
[email protected]0f292de02012-02-01 22:28:201473 base::WeakPtr<HostResolverImpl> resolver_;
1474
1475 Key key_;
1476
1477 // Tracks the highest priority across |requests_|.
1478 PriorityTracker priority_tracker_;
1479
1480 bool had_non_speculative_request_;
1481
[email protected]1def74c2012-03-22 20:07:001482 // True if resolver had DnsConfig when the Job was started.
1483 bool had_dns_config_;
1484
[email protected]0f292de02012-02-01 22:28:201485 BoundNetLog net_log_;
1486
[email protected]b3601bc22012-02-21 21:23:201487 // Resolves the host using a HostResolverProc.
[email protected]0f292de02012-02-01 22:28:201488 scoped_refptr<ProcTask> proc_task_;
1489
[email protected]b3601bc22012-02-21 21:23:201490 // Resolves the host using a DnsTransaction.
1491 scoped_ptr<DnsTask> dns_task_;
1492
[email protected]0f292de02012-02-01 22:28:201493 // All Requests waiting for the result of this Job. Some can be canceled.
1494 RequestsList requests_;
1495
[email protected]16ee26d2012-03-08 03:34:351496 // A handle used in |HostResolverImpl::dispatcher_|.
[email protected]0f292de02012-02-01 22:28:201497 PrioritizedDispatcher::Handle handle_;
[email protected]68ad3ee2010-01-30 03:45:391498};
1499
1500//-----------------------------------------------------------------------------
1501
[email protected]0f292de02012-02-01 22:28:201502HostResolverImpl::ProcTaskParams::ProcTaskParams(
[email protected]e95d3aca2010-01-11 22:47:431503 HostResolverProc* resolver_proc,
[email protected]0f292de02012-02-01 22:28:201504 size_t max_retry_attempts)
1505 : resolver_proc(resolver_proc),
1506 max_retry_attempts(max_retry_attempts),
1507 unresponsive_delay(base::TimeDelta::FromMilliseconds(6000)),
1508 retry_factor(2) {
1509}
1510
1511HostResolverImpl::ProcTaskParams::~ProcTaskParams() {}
1512
1513HostResolverImpl::HostResolverImpl(
[email protected]e95d3aca2010-01-11 22:47:431514 HostCache* cache,
[email protected]0f292de02012-02-01 22:28:201515 const PrioritizedDispatcher::Limits& job_limits,
1516 const ProcTaskParams& proc_params,
[email protected]b3601bc22012-02-21 21:23:201517 scoped_ptr<DnsConfigService> dns_config_service,
[email protected]ee094b82010-08-24 15:55:511518 NetLog* net_log)
[email protected]112bd462009-12-10 07:23:401519 : cache_(cache),
[email protected]0f292de02012-02-01 22:28:201520 dispatcher_(job_limits),
1521 max_queued_jobs_(job_limits.total_jobs * 100u),
1522 proc_params_(proc_params),
[email protected]0c7798452009-10-26 17:59:511523 default_address_family_(ADDRESS_FAMILY_UNSPECIFIED),
[email protected]78eac2a2012-03-14 19:09:271524 dns_client_(NULL),
[email protected]b3601bc22012-02-21 21:23:201525 dns_config_service_(dns_config_service.Pass()),
[email protected]2f3bc65c2010-07-23 17:47:101526 ipv6_probe_monitoring_(false),
[email protected]ee094b82010-08-24 15:55:511527 additional_resolver_flags_(0),
1528 net_log_(net_log) {
[email protected]0f292de02012-02-01 22:28:201529
1530 DCHECK_GE(dispatcher_.num_priorities(), static_cast<size_t>(NUM_PRIORITIES));
[email protected]68ad3ee2010-01-30 03:45:391531
[email protected]06ef6d92011-05-19 04:24:581532 // Maximum of 4 retry attempts for host resolution.
1533 static const size_t kDefaultMaxRetryAttempts = 4u;
1534
[email protected]0f292de02012-02-01 22:28:201535 if (proc_params_.max_retry_attempts == HostResolver::kDefaultRetryAttempts)
1536 proc_params_.max_retry_attempts = kDefaultMaxRetryAttempts;
[email protected]68ad3ee2010-01-30 03:45:391537
[email protected]b59ff372009-07-15 22:04:321538#if defined(OS_WIN)
1539 EnsureWinsockInit();
1540#endif
[email protected]23f771162011-06-02 18:37:511541#if defined(OS_POSIX) && !defined(OS_MACOSX)
[email protected]2f3bc65c2010-07-23 17:47:101542 if (HaveOnlyLoopbackAddresses())
1543 additional_resolver_flags_ |= HOST_RESOLVER_LOOPBACK_ONLY;
1544#endif
[email protected]232a5812011-03-04 22:42:081545 NetworkChangeNotifier::AddIPAddressObserver(this);
[email protected]46018c9d2011-09-06 03:42:341546#if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_OPENBSD)
[email protected]ae7c9f42011-11-21 11:41:161547#if !defined(OS_ANDROID)
[email protected]46018c9d2011-09-06 03:42:341548 EnsureDnsReloaderInit();
[email protected]ae7c9f42011-11-21 11:41:161549#endif
[email protected]46018c9d2011-09-06 03:42:341550 NetworkChangeNotifier::AddDNSObserver(this);
1551#endif
[email protected]b3601bc22012-02-21 21:23:201552
[email protected]78eac2a2012-03-14 19:09:271553 if (dns_config_service_.get()) {
[email protected]b4481b222012-03-16 17:13:111554 dns_config_service_->Watch(
1555 base::Bind(&HostResolverImpl::OnDnsConfigChanged,
1556 base::Unretained(this)));
[email protected]78eac2a2012-03-14 19:09:271557 dns_client_ = DnsClient::CreateClient(net_log_);
1558 }
[email protected]b59ff372009-07-15 22:04:321559}
1560
1561HostResolverImpl::~HostResolverImpl() {
[email protected]0f8f1b432010-03-16 19:06:031562 DiscardIPv6ProbeJob();
1563
[email protected]0f292de02012-02-01 22:28:201564 // This will also cancel all outstanding requests.
1565 STLDeleteValues(&jobs_);
[email protected]e95d3aca2010-01-11 22:47:431566
[email protected]232a5812011-03-04 22:42:081567 NetworkChangeNotifier::RemoveIPAddressObserver(this);
[email protected]46018c9d2011-09-06 03:42:341568#if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_OPENBSD)
1569 NetworkChangeNotifier::RemoveDNSObserver(this);
1570#endif
[email protected]b59ff372009-07-15 22:04:321571}
1572
[email protected]0f292de02012-02-01 22:28:201573void HostResolverImpl::SetMaxQueuedJobs(size_t value) {
1574 DCHECK_EQ(0u, dispatcher_.num_queued_jobs());
1575 DCHECK_GT(value, 0u);
1576 max_queued_jobs_ = value;
[email protected]be1a48b2011-01-20 00:12:131577}
1578
[email protected]684970b2009-08-14 04:54:461579int HostResolverImpl::Resolve(const RequestInfo& info,
[email protected]b59ff372009-07-15 22:04:321580 AddressList* addresses,
[email protected]aa22b242011-11-16 18:58:291581 const CompletionCallback& callback,
[email protected]684970b2009-08-14 04:54:461582 RequestHandle* out_req,
[email protected]ee094b82010-08-24 15:55:511583 const BoundNetLog& source_net_log) {
[email protected]95a214c2011-08-04 21:50:401584 DCHECK(addresses);
[email protected]1ac6af92010-06-03 21:00:141585 DCHECK(CalledOnValidThread());
[email protected]aa22b242011-11-16 18:58:291586 DCHECK_EQ(false, callback.is_null());
[email protected]1ac6af92010-06-03 21:00:141587
[email protected]ee094b82010-08-24 15:55:511588 // Make a log item for the request.
1589 BoundNetLog request_net_log = BoundNetLog::Make(net_log_,
1590 NetLog::SOURCE_HOST_RESOLVER_IMPL_REQUEST);
1591
[email protected]0f292de02012-02-01 22:28:201592 LogStartRequest(source_net_log, request_net_log, info);
[email protected]b59ff372009-07-15 22:04:321593
[email protected]123ab1e32009-10-21 19:12:571594 // Build a key that identifies the request in the cache and in the
1595 // outstanding jobs map.
[email protected]137af622010-02-05 02:14:351596 Key key = GetEffectiveKeyForRequest(info);
[email protected]123ab1e32009-10-21 19:12:571597
[email protected]287d7c22011-11-15 17:34:251598 int rv = ResolveHelper(key, info, addresses, request_net_log);
[email protected]95a214c2011-08-04 21:50:401599 if (rv != ERR_DNS_CACHE_MISS) {
[email protected]b3601bc22012-02-21 21:23:201600 LogFinishRequest(source_net_log, request_net_log, info, rv);
[email protected]95a214c2011-08-04 21:50:401601 return rv;
[email protected]38368712011-03-02 08:09:401602 }
1603
[email protected]0f292de02012-02-01 22:28:201604 // Next we need to attach our request to a "job". This job is responsible for
1605 // calling "getaddrinfo(hostname)" on a worker thread.
1606
1607 JobMap::iterator jobit = jobs_.find(key);
1608 Job* job;
1609 if (jobit == jobs_.end()) {
1610 // Create new Job.
[email protected]16ee26d2012-03-08 03:34:351611 job = new Job(this, key, request_net_log);
1612 job->Schedule(info.priority());
[email protected]0f292de02012-02-01 22:28:201613
1614 // Check for queue overflow.
1615 if (dispatcher_.num_queued_jobs() > max_queued_jobs_) {
1616 Job* evicted = static_cast<Job*>(dispatcher_.EvictOldestLowest());
1617 DCHECK(evicted);
[email protected]16ee26d2012-03-08 03:34:351618 evicted->OnEvicted(); // Deletes |evicted|.
[email protected]0f292de02012-02-01 22:28:201619 if (evicted == job) {
[email protected]0f292de02012-02-01 22:28:201620 rv = ERR_HOST_RESOLVER_QUEUE_TOO_LARGE;
[email protected]b3601bc22012-02-21 21:23:201621 LogFinishRequest(source_net_log, request_net_log, info, rv);
[email protected]0f292de02012-02-01 22:28:201622 return rv;
1623 }
[email protected]0f292de02012-02-01 22:28:201624 }
[email protected]0f292de02012-02-01 22:28:201625 jobs_.insert(jobit, std::make_pair(key, job));
1626 } else {
1627 job = jobit->second;
1628 }
1629
1630 // Can't complete synchronously. Create and attach request.
[email protected]b3601bc22012-02-21 21:23:201631 scoped_ptr<Request> req(new Request(source_net_log,
1632 request_net_log,
1633 info,
1634 callback,
1635 addresses));
[email protected]b59ff372009-07-15 22:04:321636 if (out_req)
[email protected]b3601bc22012-02-21 21:23:201637 *out_req = reinterpret_cast<RequestHandle>(req.get());
[email protected]b59ff372009-07-15 22:04:321638
[email protected]b3601bc22012-02-21 21:23:201639 job->AddRequest(req.Pass());
[email protected]0f292de02012-02-01 22:28:201640 // Completion happens during Job::CompleteRequests().
[email protected]b59ff372009-07-15 22:04:321641 return ERR_IO_PENDING;
1642}
1643
[email protected]287d7c22011-11-15 17:34:251644int HostResolverImpl::ResolveHelper(const Key& key,
[email protected]95a214c2011-08-04 21:50:401645 const RequestInfo& info,
1646 AddressList* addresses,
[email protected]20cd5332011-10-12 22:38:001647 const BoundNetLog& request_net_log) {
[email protected]95a214c2011-08-04 21:50:401648 // The result of |getaddrinfo| for empty hosts is inconsistent across systems.
1649 // On Windows it gives the default interface's address, whereas on Linux it
1650 // gives an error. We will make it fail on all platforms for consistency.
1651 if (info.hostname().empty() || info.hostname().size() > kMaxHostLength)
1652 return ERR_NAME_NOT_RESOLVED;
1653
1654 int net_error = ERR_UNEXPECTED;
1655 if (ResolveAsIP(key, info, &net_error, addresses))
1656 return net_error;
[email protected]78eac2a2012-03-14 19:09:271657 if (ServeFromCache(key, info, &net_error, addresses)) {
1658 request_net_log.AddEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_CACHE_HIT, NULL);
1659 return net_error;
1660 }
1661 // TODO(szym): Do not do this if nsswitch.conf instructs not to.
1662 // http://crbug.com/117655
1663 if (ServeFromHosts(key, info, addresses)) {
1664 request_net_log.AddEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_HOSTS_HIT, NULL);
1665 return OK;
1666 }
1667 return ERR_DNS_CACHE_MISS;
[email protected]95a214c2011-08-04 21:50:401668}
1669
1670int HostResolverImpl::ResolveFromCache(const RequestInfo& info,
1671 AddressList* addresses,
1672 const BoundNetLog& source_net_log) {
1673 DCHECK(CalledOnValidThread());
1674 DCHECK(addresses);
1675
[email protected]95a214c2011-08-04 21:50:401676 // Make a log item for the request.
1677 BoundNetLog request_net_log = BoundNetLog::Make(net_log_,
1678 NetLog::SOURCE_HOST_RESOLVER_IMPL_REQUEST);
1679
1680 // Update the net log and notify registered observers.
[email protected]0f292de02012-02-01 22:28:201681 LogStartRequest(source_net_log, request_net_log, info);
[email protected]95a214c2011-08-04 21:50:401682
[email protected]95a214c2011-08-04 21:50:401683 Key key = GetEffectiveKeyForRequest(info);
1684
[email protected]287d7c22011-11-15 17:34:251685 int rv = ResolveHelper(key, info, addresses, request_net_log);
[email protected]b3601bc22012-02-21 21:23:201686 LogFinishRequest(source_net_log, request_net_log, info, rv);
[email protected]95a214c2011-08-04 21:50:401687 return rv;
1688}
1689
[email protected]b59ff372009-07-15 22:04:321690void HostResolverImpl::CancelRequest(RequestHandle req_handle) {
[email protected]1ac6af92010-06-03 21:00:141691 DCHECK(CalledOnValidThread());
[email protected]b59ff372009-07-15 22:04:321692 Request* req = reinterpret_cast<Request*>(req_handle);
1693 DCHECK(req);
[email protected]0f292de02012-02-01 22:28:201694 Job* job = req->job();
1695 DCHECK(job);
[email protected]0f292de02012-02-01 22:28:201696 job->CancelRequest(req);
[email protected]b59ff372009-07-15 22:04:321697}
1698
[email protected]0f8f1b432010-03-16 19:06:031699void HostResolverImpl::SetDefaultAddressFamily(AddressFamily address_family) {
[email protected]1ac6af92010-06-03 21:00:141700 DCHECK(CalledOnValidThread());
[email protected]0f8f1b432010-03-16 19:06:031701 ipv6_probe_monitoring_ = false;
1702 DiscardIPv6ProbeJob();
1703 default_address_family_ = address_family;
1704}
1705
[email protected]f7d310e2010-10-07 16:25:111706AddressFamily HostResolverImpl::GetDefaultAddressFamily() const {
1707 return default_address_family_;
1708}
1709
[email protected]a78f4272011-10-21 19:16:331710void HostResolverImpl::ProbeIPv6Support() {
1711 DCHECK(CalledOnValidThread());
1712 DCHECK(!ipv6_probe_monitoring_);
1713 ipv6_probe_monitoring_ = true;
1714 OnIPAddressChanged(); // Give initial setup call.
[email protected]ddb1e5a2010-12-13 20:10:451715}
1716
[email protected]489d1a82011-10-12 03:09:111717HostCache* HostResolverImpl::GetHostCache() {
1718 return cache_.get();
1719}
[email protected]95a214c2011-08-04 21:50:401720
1721bool HostResolverImpl::ResolveAsIP(const Key& key,
1722 const RequestInfo& info,
1723 int* net_error,
1724 AddressList* addresses) {
1725 DCHECK(addresses);
1726 DCHECK(net_error);
1727 IPAddressNumber ip_number;
1728 if (!ParseIPLiteralToNumber(key.hostname, &ip_number))
1729 return false;
1730
1731 DCHECK_EQ(key.host_resolver_flags &
1732 ~(HOST_RESOLVER_CANONNAME | HOST_RESOLVER_LOOPBACK_ONLY |
1733 HOST_RESOLVER_DEFAULT_FAMILY_SET_DUE_TO_NO_IPV6),
1734 0) << " Unhandled flag";
[email protected]0f292de02012-02-01 22:28:201735 bool ipv6_disabled = (default_address_family_ == ADDRESS_FAMILY_IPV4) &&
1736 !ipv6_probe_monitoring_;
[email protected]95a214c2011-08-04 21:50:401737 *net_error = OK;
[email protected]0f292de02012-02-01 22:28:201738 if ((ip_number.size() == kIPv6AddressSize) && ipv6_disabled) {
[email protected]95a214c2011-08-04 21:50:401739 *net_error = ERR_NAME_NOT_RESOLVED;
1740 } else {
1741 *addresses = AddressList::CreateFromIPAddressWithCname(
1742 ip_number, info.port(),
1743 (key.host_resolver_flags & HOST_RESOLVER_CANONNAME));
1744 }
1745 return true;
1746}
1747
1748bool HostResolverImpl::ServeFromCache(const Key& key,
1749 const RequestInfo& info,
[email protected]95a214c2011-08-04 21:50:401750 int* net_error,
1751 AddressList* addresses) {
1752 DCHECK(addresses);
1753 DCHECK(net_error);
1754 if (!info.allow_cached_response() || !cache_.get())
1755 return false;
1756
1757 const HostCache::Entry* cache_entry = cache_->Lookup(
1758 key, base::TimeTicks::Now());
1759 if (!cache_entry)
1760 return false;
1761
[email protected]78eac2a2012-03-14 19:09:271762
[email protected]95a214c2011-08-04 21:50:401763 *net_error = cache_entry->error;
1764 if (*net_error == OK)
1765 *addresses = CreateAddressListUsingPort(cache_entry->addrlist, info.port());
1766 return true;
1767}
1768
[email protected]78eac2a2012-03-14 19:09:271769bool HostResolverImpl::ServeFromHosts(const Key& key,
1770 const RequestInfo& info,
1771 AddressList* addresses) {
1772 DCHECK(addresses);
1773 if (!HaveDnsConfig())
1774 return false;
1775
1776 // If |address_family| is ADDRESS_FAMILY_UNSPECIFIED other implementations
1777 // (glibc and c-ares) return the first matching line. We have more
1778 // flexibility, but lose implicit ordering.
1779 // TODO(szym) http://crbug.com/117850
1780 const DnsHosts& hosts = dns_client_->GetConfig()->hosts;
1781 DnsHosts::const_iterator it = hosts.find(
1782 DnsHostsKey(key.hostname,
1783 key.address_family == ADDRESS_FAMILY_UNSPECIFIED ?
1784 ADDRESS_FAMILY_IPV4 : key.address_family));
1785
1786 if (it == hosts.end()) {
1787 if (key.address_family != ADDRESS_FAMILY_UNSPECIFIED)
1788 return false;
1789
1790 it = hosts.find(DnsHostsKey(key.hostname, ADDRESS_FAMILY_IPV6));
1791 if (it == hosts.end())
1792 return false;
1793 }
1794
1795 *addresses = AddressList::CreateFromIPAddress(it->second, info.port());
1796 return true;
1797}
1798
[email protected]16ee26d2012-03-08 03:34:351799void HostResolverImpl::CacheResult(const Key& key,
1800 int net_error,
1801 const AddressList& addr_list,
1802 base::TimeDelta ttl) {
1803 if (cache_.get())
1804 cache_->Set(key, net_error, addr_list, base::TimeTicks::Now(), ttl);
[email protected]ef4c40c2010-09-01 14:42:031805}
1806
[email protected]0f292de02012-02-01 22:28:201807void HostResolverImpl::RemoveJob(Job* job) {
1808 DCHECK(job);
[email protected]16ee26d2012-03-08 03:34:351809 JobMap::iterator it = jobs_.find(job->key());
1810 if (it != jobs_.end() && it->second == job)
1811 jobs_.erase(it);
[email protected]b59ff372009-07-15 22:04:321812}
1813
[email protected]0f8f1b432010-03-16 19:06:031814void HostResolverImpl::DiscardIPv6ProbeJob() {
1815 if (ipv6_probe_job_.get()) {
1816 ipv6_probe_job_->Cancel();
1817 ipv6_probe_job_ = NULL;
1818 }
1819}
1820
1821void HostResolverImpl::IPv6ProbeSetDefaultAddressFamily(
1822 AddressFamily address_family) {
1823 DCHECK(address_family == ADDRESS_FAMILY_UNSPECIFIED ||
1824 address_family == ADDRESS_FAMILY_IPV4);
[email protected]f092e64b2010-03-17 00:39:181825 if (default_address_family_ != address_family) {
[email protected]b30a3f52010-10-16 01:05:461826 VLOG(1) << "IPv6Probe forced AddressFamily setting to "
1827 << ((address_family == ADDRESS_FAMILY_UNSPECIFIED) ?
1828 "ADDRESS_FAMILY_UNSPECIFIED" : "ADDRESS_FAMILY_IPV4");
[email protected]f092e64b2010-03-17 00:39:181829 }
[email protected]0f8f1b432010-03-16 19:06:031830 default_address_family_ = address_family;
1831 // Drop reference since the job has called us back.
1832 DiscardIPv6ProbeJob();
[email protected]e95d3aca2010-01-11 22:47:431833}
1834
[email protected]137af622010-02-05 02:14:351835HostResolverImpl::Key HostResolverImpl::GetEffectiveKeyForRequest(
1836 const RequestInfo& info) const {
[email protected]eaf3a3b2010-09-03 20:34:271837 HostResolverFlags effective_flags =
1838 info.host_resolver_flags() | additional_resolver_flags_;
[email protected]137af622010-02-05 02:14:351839 AddressFamily effective_address_family = info.address_family();
[email protected]eaf3a3b2010-09-03 20:34:271840 if (effective_address_family == ADDRESS_FAMILY_UNSPECIFIED &&
1841 default_address_family_ != ADDRESS_FAMILY_UNSPECIFIED) {
[email protected]137af622010-02-05 02:14:351842 effective_address_family = default_address_family_;
[email protected]eaf3a3b2010-09-03 20:34:271843 if (ipv6_probe_monitoring_)
1844 effective_flags |= HOST_RESOLVER_DEFAULT_FAMILY_SET_DUE_TO_NO_IPV6;
1845 }
1846 return Key(info.hostname(), effective_address_family, effective_flags);
[email protected]137af622010-02-05 02:14:351847}
1848
[email protected]35ddc282010-09-21 23:42:061849void HostResolverImpl::AbortAllInProgressJobs() {
[email protected]b3601bc22012-02-21 21:23:201850 // In Abort, a Request callback could spawn new Jobs with matching keys, so
1851 // first collect and remove all running jobs from |jobs_|.
1852 std::vector<Job*> jobs_to_abort;
[email protected]0f292de02012-02-01 22:28:201853 for (JobMap::iterator it = jobs_.begin(); it != jobs_.end(); ) {
1854 Job* job = it->second;
[email protected]0f292de02012-02-01 22:28:201855 if (job->is_running()) {
[email protected]b3601bc22012-02-21 21:23:201856 jobs_to_abort.push_back(job);
1857 jobs_.erase(it++);
[email protected]0f292de02012-02-01 22:28:201858 } else {
[email protected]b3601bc22012-02-21 21:23:201859 DCHECK(job->is_queued());
1860 ++it;
[email protected]0f292de02012-02-01 22:28:201861 }
[email protected]ef4c40c2010-09-01 14:42:031862 }
[email protected]b3601bc22012-02-21 21:23:201863
[email protected]57a48d32012-03-03 00:04:551864 // Check if no dispatcher slots leaked out.
1865 DCHECK_EQ(dispatcher_.num_running_jobs(), jobs_to_abort.size());
1866
1867 // Life check to bail once |this| is deleted.
1868 base::WeakPtr<HostResolverImpl> self = AsWeakPtr();
1869
[email protected]16ee26d2012-03-08 03:34:351870 // Then Abort them.
[email protected]57a48d32012-03-03 00:04:551871 for (size_t i = 0; self && i < jobs_to_abort.size(); ++i) {
[email protected]57a48d32012-03-03 00:04:551872 jobs_to_abort[i]->Abort();
[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]b3601bc22012-02-21 21:23:201933 // We want a new factory in place, before we Abort running Jobs, so that the
1934 // newly started jobs use the new factory.
[email protected]78eac2a2012-03-14 19:09:271935 DCHECK(dns_client_.get());
1936
1937 // Life check to bail once |this| is deleted.
1938 base::WeakPtr<HostResolverImpl> self = AsWeakPtr();
1939
1940 bool had_factory = (dns_client_->GetConfig() != NULL);
1941 dns_client_->SetConfig(dns_config);
1942
[email protected]b3601bc22012-02-21 21:23:201943 // Don't Abort running Jobs unless they were running on DnsTransaction.
1944 // TODO(szym): This will change once http://crbug.com/114827 is fixed.
1945 if (had_factory)
[email protected]446df2952012-02-28 07:22:511946 OnDNSChanged(NetworkChangeNotifier::CHANGE_DNS_SETTINGS);
[email protected]78eac2a2012-03-14 19:09:271947
1948 if (self && dns_config.IsValid())
1949 TryServingAllJobsFromHosts();
1950}
1951
1952bool HostResolverImpl::HaveDnsConfig() const {
1953 return (dns_client_.get() != NULL) && (dns_client_->GetConfig() != NULL);
[email protected]b3601bc22012-02-21 21:23:201954}
1955
[email protected]b59ff372009-07-15 22:04:321956} // namespace net