blob: 5591d06701b16311b949ffaceeecf69f780d1478 [file] [log] [blame]
[email protected]a2730882012-01-21 00:56:271// Copyright (c) 2012 The Chromium Authors. All rights reserved.
[email protected]b59ff372009-07-15 22:04:322// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "net/base/host_resolver_impl.h"
6
[email protected]21526002010-05-16 19:42:467#if defined(OS_WIN)
8#include <Winsock2.h>
9#elif defined(OS_POSIX)
10#include <netdb.h>
11#endif
12
[email protected]68ad3ee2010-01-30 03:45:3913#include <cmath>
[email protected]0f292de02012-02-01 22:28:2014#include <utility>
[email protected]21526002010-05-16 19:42:4615#include <vector>
[email protected]68ad3ee2010-01-30 03:45:3916
17#include "base/basictypes.h"
[email protected]33152acc2011-10-20 23:37:1218#include "base/bind.h"
[email protected]aa22b242011-11-16 18:58:2919#include "base/bind_helpers.h"
[email protected]0f292de02012-02-01 22:28:2020#include "base/callback.h"
[email protected]b59ff372009-07-15 22:04:3221#include "base/compiler_specific.h"
[email protected]58580352010-10-26 04:07:5022#include "base/debug/debugger.h"
23#include "base/debug/stack_trace.h"
[email protected]3e9d9cc2011-05-03 21:08:1524#include "base/message_loop_proxy.h"
[email protected]1e9bbd22010-10-15 16:42:4525#include "base/metrics/field_trial.h"
[email protected]835d7c82010-10-14 04:38:3826#include "base/metrics/histogram.h"
[email protected]7286e3fc2011-07-19 22:13:2427#include "base/stl_util.h"
[email protected]b59ff372009-07-15 22:04:3228#include "base/string_util.h"
[email protected]ac9ba8fe2010-12-30 18:08:3629#include "base/threading/worker_pool.h"
[email protected]b59ff372009-07-15 22:04:3230#include "base/time.h"
[email protected]ccaff652010-07-31 06:28:2031#include "base/utf_string_conversions.h"
[email protected]21526002010-05-16 19:42:4632#include "base/values.h"
[email protected]b3601bc22012-02-21 21:23:2033#include "net/base/address_family.h"
[email protected]b59ff372009-07-15 22:04:3234#include "net/base/address_list.h"
[email protected]46018c9d2011-09-06 03:42:3435#include "net/base/dns_reloader.h"
[email protected]ee094b82010-08-24 15:55:5136#include "net/base/host_port_pair.h"
[email protected]b59ff372009-07-15 22:04:3237#include "net/base/host_resolver_proc.h"
[email protected]2bb04442010-08-18 18:01:1538#include "net/base/net_errors.h"
[email protected]ee094b82010-08-24 15:55:5139#include "net/base/net_log.h"
[email protected]0f8f1b432010-03-16 19:06:0340#include "net/base/net_util.h"
[email protected]78eac2a2012-03-14 19:09:2741#include "net/dns/dns_client.h"
[email protected]b3601bc22012-02-21 21:23:2042#include "net/dns/dns_config_service.h"
43#include "net/dns/dns_protocol.h"
44#include "net/dns/dns_response.h"
[email protected]b3601bc22012-02-21 21:23:2045#include "net/dns/dns_transaction.h"
[email protected]b59ff372009-07-15 22:04:3246
47#if defined(OS_WIN)
48#include "net/base/winsock_init.h"
49#endif
50
51namespace net {
52
[email protected]e95d3aca2010-01-11 22:47:4353namespace {
54
[email protected]6e78dfb2011-07-28 21:34:4755// Limit the size of hostnames that will be resolved to combat issues in
56// some platform's resolvers.
57const size_t kMaxHostLength = 4096;
58
[email protected]a2730882012-01-21 00:56:2759// Default TTL for successful resolutions with ProcTask.
60const unsigned kCacheEntryTTLSeconds = 60;
61
[email protected]b3601bc22012-02-21 21:23:2062// Default TTL for unsuccessful resolutions with ProcTask.
63const unsigned kNegativeCacheEntryTTLSeconds = 0;
64
[email protected]4f8a16a2012-04-07 23:59:2065// Maximum of 6 concurrent resolver threads (excluding retries).
[email protected]0f292de02012-02-01 22:28:2066// Some routers (or resolvers) appear to start to provide host-not-found if
67// too many simultaneous resolutions are pending. This number needs to be
[email protected]4f8a16a2012-04-07 23:59:2068// further optimized, but 8 is what FF currently does. We found some routers
69// that limit this to 6, so we're temporarily holding it at that level.
70static const size_t kDefaultMaxProcTasks = 6u;
[email protected]0f292de02012-02-01 22:28:2071
[email protected]24f4bab2010-10-15 01:27:1172// We use a separate histogram name for each platform to facilitate the
73// display of error codes by their symbolic name (since each platform has
74// different mappings).
75const char kOSErrorsForGetAddrinfoHistogramName[] =
76#if defined(OS_WIN)
77 "Net.OSErrorsForGetAddrinfo_Win";
78#elif defined(OS_MACOSX)
79 "Net.OSErrorsForGetAddrinfo_Mac";
80#elif defined(OS_LINUX)
81 "Net.OSErrorsForGetAddrinfo_Linux";
82#else
83 "Net.OSErrorsForGetAddrinfo";
84#endif
85
[email protected]c89b2442011-05-26 14:28:2786// Gets a list of the likely error codes that getaddrinfo() can return
87// (non-exhaustive). These are the error codes that we will track via
88// a histogram.
89std::vector<int> GetAllGetAddrinfoOSErrors() {
90 int os_errors[] = {
91#if defined(OS_POSIX)
[email protected]23f771162011-06-02 18:37:5192#if !defined(OS_FREEBSD)
[email protected]39588992011-07-11 19:54:3793#if !defined(OS_ANDROID)
[email protected]c48aef92011-11-22 23:41:4594 // EAI_ADDRFAMILY has been declared obsolete in Android's and
95 // FreeBSD's netdb.h.
[email protected]c89b2442011-05-26 14:28:2796 EAI_ADDRFAMILY,
[email protected]39588992011-07-11 19:54:3797#endif
[email protected]c48aef92011-11-22 23:41:4598 // EAI_NODATA has been declared obsolete in FreeBSD's netdb.h.
[email protected]23f771162011-06-02 18:37:5199 EAI_NODATA,
100#endif
[email protected]c89b2442011-05-26 14:28:27101 EAI_AGAIN,
102 EAI_BADFLAGS,
103 EAI_FAIL,
104 EAI_FAMILY,
105 EAI_MEMORY,
[email protected]c89b2442011-05-26 14:28:27106 EAI_NONAME,
107 EAI_SERVICE,
108 EAI_SOCKTYPE,
109 EAI_SYSTEM,
110#elif defined(OS_WIN)
111 // See: http://msdn.microsoft.com/en-us/library/ms738520(VS.85).aspx
112 WSA_NOT_ENOUGH_MEMORY,
113 WSAEAFNOSUPPORT,
114 WSAEINVAL,
115 WSAESOCKTNOSUPPORT,
116 WSAHOST_NOT_FOUND,
117 WSANO_DATA,
118 WSANO_RECOVERY,
119 WSANOTINITIALISED,
120 WSATRY_AGAIN,
121 WSATYPE_NOT_FOUND,
122 // The following are not in doc, but might be to appearing in results :-(.
123 WSA_INVALID_HANDLE,
124#endif
125 };
126
127 // Ensure all errors are positive, as histogram only tracks positive values.
128 for (size_t i = 0; i < arraysize(os_errors); ++i) {
129 os_errors[i] = std::abs(os_errors[i]);
130 }
131
132 return base::CustomHistogram::ArrayToCustomRanges(os_errors,
133 arraysize(os_errors));
134}
135
[email protected]1def74c2012-03-22 20:07:00136enum DnsResolveStatus {
137 RESOLVE_STATUS_DNS_SUCCESS = 0,
138 RESOLVE_STATUS_PROC_SUCCESS,
139 RESOLVE_STATUS_FAIL,
140 RESOLVE_STATUS_MAX
141};
142
143void UmaAsyncDnsResolveStatus(DnsResolveStatus result) {
144 UMA_HISTOGRAM_ENUMERATION("AsyncDNS.ResolveStatus",
145 result,
146 RESOLVE_STATUS_MAX);
147}
148
[email protected]d7b9a2b2012-05-31 22:31:19149//-----------------------------------------------------------------------------
150
[email protected]0f292de02012-02-01 22:28:20151// Wraps call to SystemHostResolverProc as an instance of HostResolverProc.
152// TODO(szym): This should probably be declared in host_resolver_proc.h.
153class CallSystemHostResolverProc : public HostResolverProc {
154 public:
155 CallSystemHostResolverProc() : HostResolverProc(NULL) {}
156 virtual int Resolve(const std::string& hostname,
157 AddressFamily address_family,
158 HostResolverFlags host_resolver_flags,
[email protected]b3601bc22012-02-21 21:23:20159 AddressList* addr_list,
[email protected]0f292de02012-02-01 22:28:20160 int* os_error) OVERRIDE {
161 return SystemHostResolverProc(hostname,
162 address_family,
163 host_resolver_flags,
[email protected]b3601bc22012-02-21 21:23:20164 addr_list,
[email protected]0f292de02012-02-01 22:28:20165 os_error);
[email protected]b59ff372009-07-15 22:04:32166 }
[email protected]a9813302012-04-28 09:29:28167
168 protected:
169 virtual ~CallSystemHostResolverProc() {}
[email protected]0f292de02012-02-01 22:28:20170};
[email protected]b59ff372009-07-15 22:04:32171
[email protected]7054e78f2012-05-07 21:44:56172void EnsurePortOnAddressList(uint16 port, AddressList* list) {
173 DCHECK(list);
174 if (list->empty() || list->front().port() == port)
175 return;
176 SetPortOnAddressList(port, list);
177}
178
[email protected]cd565142012-06-12 16:21:45179// Creates NetLog parameters when the resolve failed.
180base::Value* NetLogProcTaskFailedCallback(uint32 attempt_number,
181 int net_error,
182 int os_error,
183 NetLog::LogLevel /* log_level */) {
184 DictionaryValue* dict = new DictionaryValue();
185 if (attempt_number)
186 dict->SetInteger("attempt_number", attempt_number);
[email protected]21526002010-05-16 19:42:46187
[email protected]cd565142012-06-12 16:21:45188 dict->SetInteger("net_error", net_error);
[email protected]13024882011-05-18 23:19:16189
[email protected]cd565142012-06-12 16:21:45190 if (os_error) {
191 dict->SetInteger("os_error", os_error);
[email protected]21526002010-05-16 19:42:46192#if defined(OS_POSIX)
[email protected]cd565142012-06-12 16:21:45193 dict->SetString("os_error_string", gai_strerror(os_error));
[email protected]21526002010-05-16 19:42:46194#elif defined(OS_WIN)
[email protected]cd565142012-06-12 16:21:45195 // Map the error code to a human-readable string.
196 LPWSTR error_string = NULL;
197 int size = FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
198 FORMAT_MESSAGE_FROM_SYSTEM,
199 0, // Use the internal message table.
200 os_error,
201 0, // Use default language.
202 (LPWSTR)&error_string,
203 0, // Buffer size.
204 0); // Arguments (unused).
205 dict->SetString("os_error_string", WideToUTF8(error_string));
206 LocalFree(error_string);
[email protected]21526002010-05-16 19:42:46207#endif
[email protected]21526002010-05-16 19:42:46208 }
209
[email protected]cd565142012-06-12 16:21:45210 return dict;
211}
[email protected]a9813302012-04-28 09:29:28212
[email protected]cd565142012-06-12 16:21:45213// Creates NetLog parameters when the DnsTask failed.
214base::Value* NetLogDnsTaskFailedCallback(int net_error,
215 int dns_error,
216 NetLog::LogLevel /* log_level */) {
217 DictionaryValue* dict = new DictionaryValue();
218 dict->SetInteger("net_error", net_error);
219 if (dns_error)
220 dict->SetInteger("dns_error", dns_error);
221 return dict;
[email protected]ee094b82010-08-24 15:55:51222};
223
[email protected]cd565142012-06-12 16:21:45224// Creates NetLog parameters containing the information in a RequestInfo object,
225// along with the associated NetLog::Source.
226base::Value* NetLogRequestInfoCallback(const NetLog::Source& source,
227 const HostResolver::RequestInfo* info,
228 NetLog::LogLevel /* log_level */) {
229 DictionaryValue* dict = new DictionaryValue();
230 source.AddToEventParameters(dict);
[email protected]b3601bc22012-02-21 21:23:20231
[email protected]cd565142012-06-12 16:21:45232 dict->SetString("host", info->host_port_pair().ToString());
233 dict->SetInteger("address_family",
234 static_cast<int>(info->address_family()));
235 dict->SetBoolean("allow_cached_response", info->allow_cached_response());
236 dict->SetBoolean("is_speculative", info->is_speculative());
237 dict->SetInteger("priority", info->priority());
238 return dict;
239}
[email protected]b3601bc22012-02-21 21:23:20240
[email protected]cd565142012-06-12 16:21:45241// Creates NetLog parameters for the creation of a HostResolverImpl::Job.
242base::Value* NetLogJobCreationCallback(const NetLog::Source& source,
243 const std::string* host,
244 NetLog::LogLevel /* log_level */) {
245 DictionaryValue* dict = new DictionaryValue();
246 source.AddToEventParameters(dict);
247 dict->SetString("host", *host);
248 return dict;
249}
[email protected]a9813302012-04-28 09:29:28250
[email protected]cd565142012-06-12 16:21:45251// Creates NetLog parameters for HOST_RESOLVER_IMPL_JOB_ATTACH/DETACH events.
252base::Value* NetLogJobAttachCallback(const NetLog::Source& source,
253 RequestPriority priority,
254 NetLog::LogLevel /* log_level */) {
255 DictionaryValue* dict = new DictionaryValue();
256 source.AddToEventParameters(dict);
257 dict->SetInteger("priority", priority);
258 return dict;
259}
[email protected]b3601bc22012-02-21 21:23:20260
[email protected]cd565142012-06-12 16:21:45261// Creates NetLog parameters for the DNS_CONFIG_CHANGED event.
262base::Value* NetLogDnsConfigCallback(const DnsConfig* config,
263 NetLog::LogLevel /* log_level */) {
264 return config->ToValue();
265}
[email protected]b4481b222012-03-16 17:13:11266
[email protected]0f292de02012-02-01 22:28:20267// The logging routines are defined here because some requests are resolved
268// without a Request object.
269
270// Logs when a request has just been started.
271void LogStartRequest(const BoundNetLog& source_net_log,
272 const BoundNetLog& request_net_log,
273 const HostResolver::RequestInfo& info) {
274 source_net_log.BeginEvent(
275 NetLog::TYPE_HOST_RESOLVER_IMPL,
[email protected]cd565142012-06-12 16:21:45276 request_net_log.source().ToEventParametersCallback());
[email protected]0f292de02012-02-01 22:28:20277
278 request_net_log.BeginEvent(
279 NetLog::TYPE_HOST_RESOLVER_IMPL_REQUEST,
[email protected]cd565142012-06-12 16:21:45280 base::Bind(&NetLogRequestInfoCallback, source_net_log.source(), &info));
[email protected]0f292de02012-02-01 22:28:20281}
282
283// Logs when a request has just completed (before its callback is run).
284void LogFinishRequest(const BoundNetLog& source_net_log,
285 const BoundNetLog& request_net_log,
286 const HostResolver::RequestInfo& info,
[email protected]b3601bc22012-02-21 21:23:20287 int net_error) {
288 request_net_log.EndEventWithNetErrorCode(
289 NetLog::TYPE_HOST_RESOLVER_IMPL_REQUEST, net_error);
[email protected]0f292de02012-02-01 22:28:20290 source_net_log.EndEvent(NetLog::TYPE_HOST_RESOLVER_IMPL, NULL);
291}
292
293// Logs when a request has been cancelled.
294void LogCancelRequest(const BoundNetLog& source_net_log,
295 const BoundNetLog& request_net_log,
296 const HostResolverImpl::RequestInfo& info) {
297 request_net_log.AddEvent(NetLog::TYPE_CANCELLED, NULL);
298 request_net_log.EndEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_REQUEST, NULL);
299 source_net_log.EndEvent(NetLog::TYPE_HOST_RESOLVER_IMPL, NULL);
300}
301
[email protected]b59ff372009-07-15 22:04:32302//-----------------------------------------------------------------------------
303
[email protected]0f292de02012-02-01 22:28:20304// Keeps track of the highest priority.
305class PriorityTracker {
306 public:
[email protected]16ee26d2012-03-08 03:34:35307 PriorityTracker()
308 : highest_priority_(IDLE), total_count_(0) {
[email protected]0f292de02012-02-01 22:28:20309 memset(counts_, 0, sizeof(counts_));
310 }
311
312 RequestPriority highest_priority() const {
313 return highest_priority_;
314 }
315
316 size_t total_count() const {
317 return total_count_;
318 }
319
320 void Add(RequestPriority req_priority) {
321 ++total_count_;
322 ++counts_[req_priority];
[email protected]31ae7ab2012-04-24 21:09:05323 if (highest_priority_ < req_priority)
[email protected]0f292de02012-02-01 22:28:20324 highest_priority_ = req_priority;
325 }
326
327 void Remove(RequestPriority req_priority) {
328 DCHECK_GT(total_count_, 0u);
329 DCHECK_GT(counts_[req_priority], 0u);
330 --total_count_;
331 --counts_[req_priority];
332 size_t i;
[email protected]31ae7ab2012-04-24 21:09:05333 for (i = highest_priority_; i > MINIMUM_PRIORITY && !counts_[i]; --i);
[email protected]0f292de02012-02-01 22:28:20334 highest_priority_ = static_cast<RequestPriority>(i);
335
[email protected]31ae7ab2012-04-24 21:09:05336 // In absence of requests, default to MINIMUM_PRIORITY.
337 if (total_count_ == 0)
338 DCHECK_EQ(MINIMUM_PRIORITY, highest_priority_);
[email protected]0f292de02012-02-01 22:28:20339 }
340
341 private:
342 RequestPriority highest_priority_;
343 size_t total_count_;
344 size_t counts_[NUM_PRIORITIES];
345};
346
347//-----------------------------------------------------------------------------
348
349HostResolver* CreateHostResolver(size_t max_concurrent_resolves,
350 size_t max_retry_attempts,
[email protected]b3601bc22012-02-21 21:23:20351 HostCache* cache,
352 scoped_ptr<DnsConfigService> config_service,
[email protected]d7b9a2b2012-05-31 22:31:19353 scoped_ptr<DnsClient> dns_client,
[email protected]0f292de02012-02-01 22:28:20354 NetLog* net_log) {
355 if (max_concurrent_resolves == HostResolver::kDefaultParallelism)
356 max_concurrent_resolves = kDefaultMaxProcTasks;
357
358 // TODO(szym): Add experiments with reserved slots for higher priority
359 // requests.
360
361 PrioritizedDispatcher::Limits limits(NUM_PRIORITIES, max_concurrent_resolves);
362
363 HostResolverImpl* resolver = new HostResolverImpl(
[email protected]b3601bc22012-02-21 21:23:20364 cache,
[email protected]0f292de02012-02-01 22:28:20365 limits,
366 HostResolverImpl::ProcTaskParams(NULL, max_retry_attempts),
[email protected]b3601bc22012-02-21 21:23:20367 config_service.Pass(),
[email protected]d7b9a2b2012-05-31 22:31:19368 dns_client.Pass(),
[email protected]0f292de02012-02-01 22:28:20369 net_log);
370
371 return resolver;
372}
373
374} // anonymous namespace
375
376//-----------------------------------------------------------------------------
377
378HostResolver* CreateSystemHostResolver(size_t max_concurrent_resolves,
379 size_t max_retry_attempts,
380 NetLog* net_log) {
381 return CreateHostResolver(max_concurrent_resolves,
382 max_retry_attempts,
[email protected]b3601bc22012-02-21 21:23:20383 HostCache::CreateDefaultCache(),
[email protected]d7b9a2b2012-05-31 22:31:19384 DnsConfigService::CreateSystemService(),
385 scoped_ptr<DnsClient>(NULL),
[email protected]0f292de02012-02-01 22:28:20386 net_log);
387}
388
389HostResolver* CreateNonCachingSystemHostResolver(size_t max_concurrent_resolves,
390 size_t max_retry_attempts,
391 NetLog* net_log) {
392 return CreateHostResolver(max_concurrent_resolves,
393 max_retry_attempts,
[email protected]b3601bc22012-02-21 21:23:20394 NULL,
395 scoped_ptr<DnsConfigService>(NULL),
[email protected]d7b9a2b2012-05-31 22:31:19396 scoped_ptr<DnsClient>(NULL),
[email protected]b3601bc22012-02-21 21:23:20397 net_log);
398}
399
400HostResolver* CreateAsyncHostResolver(size_t max_concurrent_resolves,
401 size_t max_retry_attempts,
402 NetLog* net_log) {
[email protected]b3601bc22012-02-21 21:23:20403 return CreateHostResolver(max_concurrent_resolves,
404 max_retry_attempts,
405 HostCache::CreateDefaultCache(),
[email protected]d7b9a2b2012-05-31 22:31:19406 DnsConfigService::CreateSystemService(),
407 DnsClient::CreateClient(net_log),
[email protected]0f292de02012-02-01 22:28:20408 net_log);
409}
410
411//-----------------------------------------------------------------------------
412
413// Holds the data for a request that could not be completed synchronously.
414// It is owned by a Job. Canceled Requests are only marked as canceled rather
415// than removed from the Job's |requests_| list.
[email protected]b59ff372009-07-15 22:04:32416class HostResolverImpl::Request {
417 public:
[email protected]ee094b82010-08-24 15:55:51418 Request(const BoundNetLog& source_net_log,
419 const BoundNetLog& request_net_log,
[email protected]54e13772009-08-14 03:01:09420 const RequestInfo& info,
[email protected]aa22b242011-11-16 18:58:29421 const CompletionCallback& callback,
[email protected]b59ff372009-07-15 22:04:32422 AddressList* addresses)
[email protected]ee094b82010-08-24 15:55:51423 : source_net_log_(source_net_log),
424 request_net_log_(request_net_log),
[email protected]54e13772009-08-14 03:01:09425 info_(info),
426 job_(NULL),
427 callback_(callback),
428 addresses_(addresses) {
429 }
[email protected]b59ff372009-07-15 22:04:32430
[email protected]0f292de02012-02-01 22:28:20431 // Mark the request as canceled.
432 void MarkAsCanceled() {
[email protected]b59ff372009-07-15 22:04:32433 job_ = NULL;
[email protected]b59ff372009-07-15 22:04:32434 addresses_ = NULL;
[email protected]aa22b242011-11-16 18:58:29435 callback_.Reset();
[email protected]b59ff372009-07-15 22:04:32436 }
437
[email protected]0f292de02012-02-01 22:28:20438 bool was_canceled() const {
[email protected]aa22b242011-11-16 18:58:29439 return callback_.is_null();
[email protected]b59ff372009-07-15 22:04:32440 }
441
442 void set_job(Job* job) {
[email protected]0f292de02012-02-01 22:28:20443 DCHECK(job);
[email protected]b59ff372009-07-15 22:04:32444 // Identify which job the request is waiting on.
445 job_ = job;
446 }
447
[email protected]0f292de02012-02-01 22:28:20448 // Prepare final AddressList and call completion callback.
[email protected]b3601bc22012-02-21 21:23:20449 void OnComplete(int error, const AddressList& addr_list) {
[email protected]7054e78f2012-05-07 21:44:56450 if (error == OK) {
451 *addresses_ = addr_list;
452 EnsurePortOnAddressList(info_.port(), addresses_);
453 }
[email protected]aa22b242011-11-16 18:58:29454 CompletionCallback callback = callback_;
[email protected]0f292de02012-02-01 22:28:20455 MarkAsCanceled();
[email protected]aa22b242011-11-16 18:58:29456 callback.Run(error);
[email protected]b59ff372009-07-15 22:04:32457 }
458
[email protected]b59ff372009-07-15 22:04:32459 Job* job() const {
460 return job_;
461 }
462
[email protected]0f292de02012-02-01 22:28:20463 // NetLog for the source, passed in HostResolver::Resolve.
[email protected]ee094b82010-08-24 15:55:51464 const BoundNetLog& source_net_log() {
465 return source_net_log_;
466 }
467
[email protected]0f292de02012-02-01 22:28:20468 // NetLog for this request.
[email protected]ee094b82010-08-24 15:55:51469 const BoundNetLog& request_net_log() {
470 return request_net_log_;
[email protected]54e13772009-08-14 03:01:09471 }
472
[email protected]b59ff372009-07-15 22:04:32473 const RequestInfo& info() const {
474 return info_;
475 }
476
477 private:
[email protected]ee094b82010-08-24 15:55:51478 BoundNetLog source_net_log_;
479 BoundNetLog request_net_log_;
[email protected]54e13772009-08-14 03:01:09480
[email protected]b59ff372009-07-15 22:04:32481 // The request info that started the request.
482 RequestInfo info_;
483
[email protected]0f292de02012-02-01 22:28:20484 // The resolve job that this request is dependent on.
[email protected]b59ff372009-07-15 22:04:32485 Job* job_;
486
487 // The user's callback to invoke when the request completes.
[email protected]aa22b242011-11-16 18:58:29488 CompletionCallback callback_;
[email protected]b59ff372009-07-15 22:04:32489
490 // The address list to save result into.
491 AddressList* addresses_;
492
493 DISALLOW_COPY_AND_ASSIGN(Request);
494};
495
[email protected]1e9bbd22010-10-15 16:42:45496//------------------------------------------------------------------------------
497
498// Provide a common macro to simplify code and readability. We must use a
499// macros as the underlying HISTOGRAM macro creates static varibles.
500#define DNS_HISTOGRAM(name, time) UMA_HISTOGRAM_CUSTOM_TIMES(name, time, \
501 base::TimeDelta::FromMicroseconds(1), base::TimeDelta::FromHours(1), 100)
[email protected]b59ff372009-07-15 22:04:32502
[email protected]0f292de02012-02-01 22:28:20503// Calls HostResolverProc on the WorkerPool. Performs retries if necessary.
504//
505// Whenever we try to resolve the host, we post a delayed task to check if host
506// resolution (OnLookupComplete) is completed or not. If the original attempt
507// hasn't completed, then we start another attempt for host resolution. We take
508// the results from the first attempt that finishes and ignore the results from
509// all other attempts.
510//
511// TODO(szym): Move to separate source file for testing and mocking.
512//
513class HostResolverImpl::ProcTask
514 : public base::RefCountedThreadSafe<HostResolverImpl::ProcTask> {
[email protected]b59ff372009-07-15 22:04:32515 public:
[email protected]b3601bc22012-02-21 21:23:20516 typedef base::Callback<void(int net_error,
517 const AddressList& addr_list)> Callback;
[email protected]b59ff372009-07-15 22:04:32518
[email protected]0f292de02012-02-01 22:28:20519 ProcTask(const Key& key,
520 const ProcTaskParams& params,
521 const Callback& callback,
522 const BoundNetLog& job_net_log)
523 : key_(key),
524 params_(params),
525 callback_(callback),
526 origin_loop_(base::MessageLoopProxy::current()),
527 attempt_number_(0),
528 completed_attempt_number_(0),
529 completed_attempt_error_(ERR_UNEXPECTED),
530 had_non_speculative_request_(false),
[email protected]b3601bc22012-02-21 21:23:20531 net_log_(job_net_log) {
[email protected]0f292de02012-02-01 22:28:20532 if (!params_.resolver_proc)
533 params_.resolver_proc = HostResolverProc::GetDefault();
534 // If default is unset, use the system proc.
535 if (!params_.resolver_proc)
536 params_.resolver_proc = new CallSystemHostResolverProc();
[email protected]b59ff372009-07-15 22:04:32537 }
538
[email protected]b59ff372009-07-15 22:04:32539 void Start() {
[email protected]3e9d9cc2011-05-03 21:08:15540 DCHECK(origin_loop_->BelongsToCurrentThread());
[email protected]9c571762012-02-27 19:12:40541 net_log_.BeginEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_PROC_TASK, NULL);
[email protected]189163e2011-05-11 01:48:54542 StartLookupAttempt();
543 }
[email protected]252b699b2010-02-05 21:38:06544
[email protected]0f292de02012-02-01 22:28:20545 // Cancels this ProcTask. It will be orphaned. Any outstanding resolve
546 // attempts running on worker threads will continue running. Only once all the
547 // attempts complete will the final reference to this ProcTask be released.
548 void Cancel() {
549 DCHECK(origin_loop_->BelongsToCurrentThread());
550
551 if (was_canceled())
552 return;
553
[email protected]0f292de02012-02-01 22:28:20554 callback_.Reset();
[email protected]0f292de02012-02-01 22:28:20555 net_log_.EndEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_PROC_TASK, NULL);
556 }
557
558 void set_had_non_speculative_request() {
559 DCHECK(origin_loop_->BelongsToCurrentThread());
560 had_non_speculative_request_ = true;
561 }
562
563 bool was_canceled() const {
564 DCHECK(origin_loop_->BelongsToCurrentThread());
565 return callback_.is_null();
566 }
567
568 bool was_completed() const {
569 DCHECK(origin_loop_->BelongsToCurrentThread());
570 return completed_attempt_number_ > 0;
571 }
572
573 private:
[email protected]a9813302012-04-28 09:29:28574 friend class base::RefCountedThreadSafe<ProcTask>;
575 ~ProcTask() {}
576
[email protected]189163e2011-05-11 01:48:54577 void StartLookupAttempt() {
578 DCHECK(origin_loop_->BelongsToCurrentThread());
579 base::TimeTicks start_time = base::TimeTicks::Now();
580 ++attempt_number_;
581 // Dispatch the lookup attempt to a worker thread.
582 if (!base::WorkerPool::PostTask(
583 FROM_HERE,
[email protected]0f292de02012-02-01 22:28:20584 base::Bind(&ProcTask::DoLookup, this, start_time, attempt_number_),
[email protected]189163e2011-05-11 01:48:54585 true)) {
[email protected]b59ff372009-07-15 22:04:32586 NOTREACHED();
587
588 // Since we could be running within Resolve() right now, we can't just
589 // call OnLookupComplete(). Instead we must wait until Resolve() has
590 // returned (IO_PENDING).
[email protected]3e9d9cc2011-05-03 21:08:15591 origin_loop_->PostTask(
[email protected]189163e2011-05-11 01:48:54592 FROM_HERE,
[email protected]0f292de02012-02-01 22:28:20593 base::Bind(&ProcTask::OnLookupComplete, this, AddressList(),
[email protected]33152acc2011-10-20 23:37:12594 start_time, attempt_number_, ERR_UNEXPECTED, 0));
[email protected]189163e2011-05-11 01:48:54595 return;
[email protected]b59ff372009-07-15 22:04:32596 }
[email protected]13024882011-05-18 23:19:16597
598 net_log_.AddEvent(
599 NetLog::TYPE_HOST_RESOLVER_IMPL_ATTEMPT_STARTED,
[email protected]cd565142012-06-12 16:21:45600 NetLog::IntegerCallback("attempt_number", attempt_number_));
[email protected]13024882011-05-18 23:19:16601
[email protected]0f292de02012-02-01 22:28:20602 // If we don't get the results within a given time, RetryIfNotComplete
603 // will start a new attempt on a different worker thread if none of our
604 // outstanding attempts have completed yet.
605 if (attempt_number_ <= params_.max_retry_attempts) {
[email protected]06ef6d92011-05-19 04:24:58606 origin_loop_->PostDelayedTask(
607 FROM_HERE,
[email protected]0f292de02012-02-01 22:28:20608 base::Bind(&ProcTask::RetryIfNotComplete, this),
[email protected]7e560102012-03-08 20:58:42609 params_.unresponsive_delay);
[email protected]06ef6d92011-05-19 04:24:58610 }
[email protected]b59ff372009-07-15 22:04:32611 }
612
[email protected]6c710ee2010-05-07 07:51:16613 // WARNING: This code runs inside a worker pool. The shutdown code cannot
614 // wait for it to finish, so we must be very careful here about using other
615 // objects (like MessageLoops, Singletons, etc). During shutdown these objects
[email protected]189163e2011-05-11 01:48:54616 // may no longer exist. Multiple DoLookups() could be running in parallel, so
617 // any state inside of |this| must not mutate .
618 void DoLookup(const base::TimeTicks& start_time,
619 const uint32 attempt_number) {
620 AddressList results;
621 int os_error = 0;
[email protected]b59ff372009-07-15 22:04:32622 // Running on the worker thread
[email protected]0f292de02012-02-01 22:28:20623 int error = params_.resolver_proc->Resolve(key_.hostname,
624 key_.address_family,
625 key_.host_resolver_flags,
626 &results,
627 &os_error);
[email protected]b59ff372009-07-15 22:04:32628
[email protected]189163e2011-05-11 01:48:54629 origin_loop_->PostTask(
630 FROM_HERE,
[email protected]0f292de02012-02-01 22:28:20631 base::Bind(&ProcTask::OnLookupComplete, this, results, start_time,
[email protected]33152acc2011-10-20 23:37:12632 attempt_number, error, os_error));
[email protected]189163e2011-05-11 01:48:54633 }
634
[email protected]0f292de02012-02-01 22:28:20635 // Makes next attempt if DoLookup() has not finished (runs on origin thread).
636 void RetryIfNotComplete() {
[email protected]189163e2011-05-11 01:48:54637 DCHECK(origin_loop_->BelongsToCurrentThread());
638
[email protected]0f292de02012-02-01 22:28:20639 if (was_completed() || was_canceled())
[email protected]189163e2011-05-11 01:48:54640 return;
641
[email protected]0f292de02012-02-01 22:28:20642 params_.unresponsive_delay *= params_.retry_factor;
[email protected]189163e2011-05-11 01:48:54643 StartLookupAttempt();
[email protected]b59ff372009-07-15 22:04:32644 }
645
646 // Callback for when DoLookup() completes (runs on origin thread).
[email protected]189163e2011-05-11 01:48:54647 void OnLookupComplete(const AddressList& results,
648 const base::TimeTicks& start_time,
649 const uint32 attempt_number,
650 int error,
651 const int os_error) {
[email protected]3e9d9cc2011-05-03 21:08:15652 DCHECK(origin_loop_->BelongsToCurrentThread());
[email protected]7054e78f2012-05-07 21:44:56653 DCHECK(error || !results.empty());
[email protected]189163e2011-05-11 01:48:54654
655 bool was_retry_attempt = attempt_number > 1;
656
[email protected]2d3b7762010-10-09 00:35:47657 // Ideally the following code would be part of host_resolver_proc.cc,
[email protected]b3601bc22012-02-21 21:23:20658 // however it isn't safe to call NetworkChangeNotifier from worker threads.
659 // So we do it here on the IO thread instead.
[email protected]189163e2011-05-11 01:48:54660 if (error != OK && NetworkChangeNotifier::IsOffline())
661 error = ERR_INTERNET_DISCONNECTED;
[email protected]2d3b7762010-10-09 00:35:47662
[email protected]b3601bc22012-02-21 21:23:20663 // If this is the first attempt that is finishing later, then record data
664 // for the first attempt. Won't contaminate with retry attempt's data.
[email protected]189163e2011-05-11 01:48:54665 if (!was_retry_attempt)
666 RecordPerformanceHistograms(start_time, error, os_error);
667
668 RecordAttemptHistograms(start_time, attempt_number, error, os_error);
[email protected]f2d8c4212010-02-02 00:56:35669
[email protected]0f292de02012-02-01 22:28:20670 if (was_canceled())
[email protected]b59ff372009-07-15 22:04:32671 return;
672
[email protected]cd565142012-06-12 16:21:45673 NetLog::ParametersCallback net_log_callback;
[email protected]0f292de02012-02-01 22:28:20674 if (error != OK) {
[email protected]cd565142012-06-12 16:21:45675 net_log_callback = base::Bind(&NetLogProcTaskFailedCallback,
676 attempt_number,
677 error,
678 os_error);
[email protected]0f292de02012-02-01 22:28:20679 } else {
[email protected]cd565142012-06-12 16:21:45680 net_log_callback = NetLog::IntegerCallback("attempt_number",
681 attempt_number);
[email protected]0f292de02012-02-01 22:28:20682 }
[email protected]cd565142012-06-12 16:21:45683 net_log_.AddEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_ATTEMPT_FINISHED,
684 net_log_callback);
[email protected]0f292de02012-02-01 22:28:20685
686 if (was_completed())
687 return;
688
689 // Copy the results from the first worker thread that resolves the host.
690 results_ = results;
691 completed_attempt_number_ = attempt_number;
692 completed_attempt_error_ = error;
693
[email protected]e87b8b512011-06-14 22:12:52694 if (was_retry_attempt) {
695 // If retry attempt finishes before 1st attempt, then get stats on how
696 // much time is saved by having spawned an extra attempt.
697 retry_attempt_finished_time_ = base::TimeTicks::Now();
698 }
699
[email protected]189163e2011-05-11 01:48:54700 if (error != OK) {
[email protected]cd565142012-06-12 16:21:45701 net_log_callback = base::Bind(&NetLogProcTaskFailedCallback,
702 0, error, os_error);
[email protected]ee094b82010-08-24 15:55:51703 } else {
[email protected]cd565142012-06-12 16:21:45704 net_log_callback = results_.CreateNetLogCallback();
[email protected]ee094b82010-08-24 15:55:51705 }
[email protected]cd565142012-06-12 16:21:45706 net_log_.EndEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_PROC_TASK,
707 net_log_callback);
[email protected]ee094b82010-08-24 15:55:51708
[email protected]b3601bc22012-02-21 21:23:20709 callback_.Run(error, results_);
[email protected]b59ff372009-07-15 22:04:32710 }
711
[email protected]189163e2011-05-11 01:48:54712 void RecordPerformanceHistograms(const base::TimeTicks& start_time,
713 const int error,
714 const int os_error) const {
[email protected]3e9d9cc2011-05-03 21:08:15715 DCHECK(origin_loop_->BelongsToCurrentThread());
[email protected]1e9bbd22010-10-15 16:42:45716 enum Category { // Used in HISTOGRAM_ENUMERATION.
717 RESOLVE_SUCCESS,
718 RESOLVE_FAIL,
719 RESOLVE_SPECULATIVE_SUCCESS,
720 RESOLVE_SPECULATIVE_FAIL,
721 RESOLVE_MAX, // Bounding value.
722 };
723 int category = RESOLVE_MAX; // Illegal value for later DCHECK only.
724
[email protected]189163e2011-05-11 01:48:54725 base::TimeDelta duration = base::TimeTicks::Now() - start_time;
726 if (error == OK) {
[email protected]1e9bbd22010-10-15 16:42:45727 if (had_non_speculative_request_) {
728 category = RESOLVE_SUCCESS;
729 DNS_HISTOGRAM("DNS.ResolveSuccess", duration);
730 } else {
731 category = RESOLVE_SPECULATIVE_SUCCESS;
732 DNS_HISTOGRAM("DNS.ResolveSpeculativeSuccess", duration);
733 }
[email protected]7e96d792011-06-10 17:08:23734
[email protected]78eac2a2012-03-14 19:09:27735 // Log DNS lookups based on |address_family|. This will help us determine
[email protected]7e96d792011-06-10 17:08:23736 // if IPv4 or IPv4/6 lookups are faster or slower.
737 switch(key_.address_family) {
738 case ADDRESS_FAMILY_IPV4:
739 DNS_HISTOGRAM("DNS.ResolveSuccess_FAMILY_IPV4", duration);
740 break;
741 case ADDRESS_FAMILY_IPV6:
742 DNS_HISTOGRAM("DNS.ResolveSuccess_FAMILY_IPV6", duration);
743 break;
744 case ADDRESS_FAMILY_UNSPECIFIED:
745 DNS_HISTOGRAM("DNS.ResolveSuccess_FAMILY_UNSPEC", duration);
746 break;
747 }
[email protected]1e9bbd22010-10-15 16:42:45748 } else {
749 if (had_non_speculative_request_) {
750 category = RESOLVE_FAIL;
751 DNS_HISTOGRAM("DNS.ResolveFail", duration);
752 } else {
753 category = RESOLVE_SPECULATIVE_FAIL;
754 DNS_HISTOGRAM("DNS.ResolveSpeculativeFail", duration);
755 }
[email protected]78eac2a2012-03-14 19:09:27756 // Log DNS lookups based on |address_family|. This will help us determine
[email protected]7e96d792011-06-10 17:08:23757 // if IPv4 or IPv4/6 lookups are faster or slower.
758 switch(key_.address_family) {
759 case ADDRESS_FAMILY_IPV4:
760 DNS_HISTOGRAM("DNS.ResolveFail_FAMILY_IPV4", duration);
761 break;
762 case ADDRESS_FAMILY_IPV6:
763 DNS_HISTOGRAM("DNS.ResolveFail_FAMILY_IPV6", duration);
764 break;
765 case ADDRESS_FAMILY_UNSPECIFIED:
766 DNS_HISTOGRAM("DNS.ResolveFail_FAMILY_UNSPEC", duration);
767 break;
768 }
[email protected]c833e322010-10-16 23:51:36769 UMA_HISTOGRAM_CUSTOM_ENUMERATION(kOSErrorsForGetAddrinfoHistogramName,
[email protected]189163e2011-05-11 01:48:54770 std::abs(os_error),
[email protected]1e9bbd22010-10-15 16:42:45771 GetAllGetAddrinfoOSErrors());
772 }
[email protected]051b6ab2010-10-18 16:50:46773 DCHECK_LT(category, static_cast<int>(RESOLVE_MAX)); // Be sure it was set.
[email protected]1e9bbd22010-10-15 16:42:45774
775 UMA_HISTOGRAM_ENUMERATION("DNS.ResolveCategory", category, RESOLVE_MAX);
776
[email protected]edafd4c2011-05-10 17:18:53777 static const bool show_speculative_experiment_histograms =
778 base::FieldTrialList::TrialExists("DnsImpact");
[email protected]ecd95ae2010-10-20 23:58:17779 if (show_speculative_experiment_histograms) {
[email protected]1e9bbd22010-10-15 16:42:45780 UMA_HISTOGRAM_ENUMERATION(
781 base::FieldTrial::MakeName("DNS.ResolveCategory", "DnsImpact"),
782 category, RESOLVE_MAX);
783 if (RESOLVE_SUCCESS == category) {
784 DNS_HISTOGRAM(base::FieldTrial::MakeName("DNS.ResolveSuccess",
785 "DnsImpact"), duration);
786 }
787 }
[email protected]edafd4c2011-05-10 17:18:53788 static const bool show_parallelism_experiment_histograms =
789 base::FieldTrialList::TrialExists("DnsParallelism");
[email protected]ecd95ae2010-10-20 23:58:17790 if (show_parallelism_experiment_histograms) {
791 UMA_HISTOGRAM_ENUMERATION(
792 base::FieldTrial::MakeName("DNS.ResolveCategory", "DnsParallelism"),
793 category, RESOLVE_MAX);
794 if (RESOLVE_SUCCESS == category) {
795 DNS_HISTOGRAM(base::FieldTrial::MakeName("DNS.ResolveSuccess",
796 "DnsParallelism"), duration);
797 }
798 }
[email protected]1e9bbd22010-10-15 16:42:45799 }
800
[email protected]189163e2011-05-11 01:48:54801 void RecordAttemptHistograms(const base::TimeTicks& start_time,
802 const uint32 attempt_number,
803 const int error,
804 const int os_error) const {
[email protected]0f292de02012-02-01 22:28:20805 DCHECK(origin_loop_->BelongsToCurrentThread());
[email protected]189163e2011-05-11 01:48:54806 bool first_attempt_to_complete =
807 completed_attempt_number_ == attempt_number;
[email protected]e87b8b512011-06-14 22:12:52808 bool is_first_attempt = (attempt_number == 1);
[email protected]1e9bbd22010-10-15 16:42:45809
[email protected]189163e2011-05-11 01:48:54810 if (first_attempt_to_complete) {
811 // If this was first attempt to complete, then record the resolution
812 // status of the attempt.
813 if (completed_attempt_error_ == OK) {
814 UMA_HISTOGRAM_ENUMERATION(
815 "DNS.AttemptFirstSuccess", attempt_number, 100);
816 } else {
817 UMA_HISTOGRAM_ENUMERATION(
818 "DNS.AttemptFirstFailure", attempt_number, 100);
819 }
820 }
821
822 if (error == OK)
823 UMA_HISTOGRAM_ENUMERATION("DNS.AttemptSuccess", attempt_number, 100);
824 else
825 UMA_HISTOGRAM_ENUMERATION("DNS.AttemptFailure", attempt_number, 100);
826
[email protected]e87b8b512011-06-14 22:12:52827 // If first attempt didn't finish before retry attempt, then calculate stats
828 // on how much time is saved by having spawned an extra attempt.
[email protected]0f292de02012-02-01 22:28:20829 if (!first_attempt_to_complete && is_first_attempt && !was_canceled()) {
[email protected]e87b8b512011-06-14 22:12:52830 DNS_HISTOGRAM("DNS.AttemptTimeSavedByRetry",
831 base::TimeTicks::Now() - retry_attempt_finished_time_);
832 }
833
[email protected]0f292de02012-02-01 22:28:20834 if (was_canceled() || !first_attempt_to_complete) {
[email protected]189163e2011-05-11 01:48:54835 // Count those attempts which completed after the job was already canceled
836 // OR after the job was already completed by an earlier attempt (so in
837 // effect).
838 UMA_HISTOGRAM_ENUMERATION("DNS.AttemptDiscarded", attempt_number, 100);
839
[email protected]0f292de02012-02-01 22:28:20840 // Record if job is canceled.
841 if (was_canceled())
[email protected]189163e2011-05-11 01:48:54842 UMA_HISTOGRAM_ENUMERATION("DNS.AttemptCancelled", attempt_number, 100);
843 }
844
845 base::TimeDelta duration = base::TimeTicks::Now() - start_time;
846 if (error == OK)
847 DNS_HISTOGRAM("DNS.AttemptSuccessDuration", duration);
848 else
849 DNS_HISTOGRAM("DNS.AttemptFailDuration", duration);
850 }
[email protected]1e9bbd22010-10-15 16:42:45851
[email protected]b59ff372009-07-15 22:04:32852 // Set on the origin thread, read on the worker thread.
[email protected]123ab1e32009-10-21 19:12:57853 Key key_;
[email protected]b59ff372009-07-15 22:04:32854
[email protected]0f292de02012-02-01 22:28:20855 // Holds an owning reference to the HostResolverProc that we are going to use.
[email protected]b59ff372009-07-15 22:04:32856 // This may not be the current resolver procedure by the time we call
857 // ResolveAddrInfo, but that's OK... we'll use it anyways, and the owning
858 // reference ensures that it remains valid until we are done.
[email protected]0f292de02012-02-01 22:28:20859 ProcTaskParams params_;
[email protected]b59ff372009-07-15 22:04:32860
[email protected]0f292de02012-02-01 22:28:20861 // The listener to the results of this ProcTask.
862 Callback callback_;
863
864 // Used to post ourselves onto the origin thread.
865 scoped_refptr<base::MessageLoopProxy> origin_loop_;
[email protected]189163e2011-05-11 01:48:54866
867 // Keeps track of the number of attempts we have made so far to resolve the
868 // host. Whenever we start an attempt to resolve the host, we increase this
869 // number.
870 uint32 attempt_number_;
871
872 // The index of the attempt which finished first (or 0 if the job is still in
873 // progress).
874 uint32 completed_attempt_number_;
875
876 // The result (a net error code) from the first attempt to complete.
877 int completed_attempt_error_;
[email protected]252b699b2010-02-05 21:38:06878
[email protected]e87b8b512011-06-14 22:12:52879 // The time when retry attempt was finished.
880 base::TimeTicks retry_attempt_finished_time_;
881
[email protected]252b699b2010-02-05 21:38:06882 // True if a non-speculative request was ever attached to this job
[email protected]0f292de02012-02-01 22:28:20883 // (regardless of whether or not it was later canceled.
[email protected]252b699b2010-02-05 21:38:06884 // This boolean is used for histogramming the duration of jobs used to
885 // service non-speculative requests.
886 bool had_non_speculative_request_;
887
[email protected]b59ff372009-07-15 22:04:32888 AddressList results_;
889
[email protected]ee094b82010-08-24 15:55:51890 BoundNetLog net_log_;
891
[email protected]0f292de02012-02-01 22:28:20892 DISALLOW_COPY_AND_ASSIGN(ProcTask);
[email protected]b59ff372009-07-15 22:04:32893};
894
895//-----------------------------------------------------------------------------
896
[email protected]0f292de02012-02-01 22:28:20897// Represents a request to the worker pool for a "probe for IPv6 support" call.
[email protected]b3601bc22012-02-21 21:23:20898//
899// TODO(szym): This could also be replaced with PostTaskAndReply and Callbacks.
[email protected]0f8f1b432010-03-16 19:06:03900class HostResolverImpl::IPv6ProbeJob
901 : public base::RefCountedThreadSafe<HostResolverImpl::IPv6ProbeJob> {
902 public:
903 explicit IPv6ProbeJob(HostResolverImpl* resolver)
904 : resolver_(resolver),
[email protected]edd685f2011-08-15 20:33:46905 origin_loop_(base::MessageLoopProxy::current()) {
[email protected]3e9d9cc2011-05-03 21:08:15906 DCHECK(resolver);
[email protected]0f8f1b432010-03-16 19:06:03907 }
908
909 void Start() {
[email protected]3e9d9cc2011-05-03 21:08:15910 DCHECK(origin_loop_->BelongsToCurrentThread());
[email protected]0f292de02012-02-01 22:28:20911 if (was_canceled())
[email protected]a9af7112010-05-08 00:56:01912 return;
[email protected]f092e64b2010-03-17 00:39:18913 const bool kIsSlow = true;
[email protected]ac9ba8fe2010-12-30 18:08:36914 base::WorkerPool::PostTask(
[email protected]33152acc2011-10-20 23:37:12915 FROM_HERE, base::Bind(&IPv6ProbeJob::DoProbe, this), kIsSlow);
[email protected]0f8f1b432010-03-16 19:06:03916 }
917
918 // Cancels the current job.
919 void Cancel() {
[email protected]3e9d9cc2011-05-03 21:08:15920 DCHECK(origin_loop_->BelongsToCurrentThread());
[email protected]0f292de02012-02-01 22:28:20921 if (was_canceled())
[email protected]a9af7112010-05-08 00:56:01922 return;
[email protected]0f8f1b432010-03-16 19:06:03923 resolver_ = NULL; // Read/write ONLY on origin thread.
[email protected]0f8f1b432010-03-16 19:06:03924 }
925
[email protected]0f8f1b432010-03-16 19:06:03926 private:
927 friend class base::RefCountedThreadSafe<HostResolverImpl::IPv6ProbeJob>;
928
929 ~IPv6ProbeJob() {
930 }
931
[email protected]0f292de02012-02-01 22:28:20932 bool was_canceled() const {
[email protected]3e9d9cc2011-05-03 21:08:15933 DCHECK(origin_loop_->BelongsToCurrentThread());
934 return !resolver_;
[email protected]a9af7112010-05-08 00:56:01935 }
936
[email protected]0f8f1b432010-03-16 19:06:03937 // Run on worker thread.
938 void DoProbe() {
939 // Do actual testing on this thread, as it takes 40-100ms.
940 AddressFamily family = IPv6Supported() ? ADDRESS_FAMILY_UNSPECIFIED
941 : ADDRESS_FAMILY_IPV4;
942
[email protected]3e9d9cc2011-05-03 21:08:15943 origin_loop_->PostTask(
944 FROM_HERE,
[email protected]33152acc2011-10-20 23:37:12945 base::Bind(&IPv6ProbeJob::OnProbeComplete, this, family));
[email protected]0f8f1b432010-03-16 19:06:03946 }
947
[email protected]3e9d9cc2011-05-03 21:08:15948 // Callback for when DoProbe() completes.
[email protected]0f8f1b432010-03-16 19:06:03949 void OnProbeComplete(AddressFamily address_family) {
[email protected]3e9d9cc2011-05-03 21:08:15950 DCHECK(origin_loop_->BelongsToCurrentThread());
[email protected]0f292de02012-02-01 22:28:20951 if (was_canceled())
[email protected]a9af7112010-05-08 00:56:01952 return;
[email protected]a9af7112010-05-08 00:56:01953 resolver_->IPv6ProbeSetDefaultAddressFamily(address_family);
[email protected]0f8f1b432010-03-16 19:06:03954 }
955
[email protected]0f8f1b432010-03-16 19:06:03956 // Used/set only on origin thread.
957 HostResolverImpl* resolver_;
958
959 // Used to post ourselves onto the origin thread.
[email protected]3e9d9cc2011-05-03 21:08:15960 scoped_refptr<base::MessageLoopProxy> origin_loop_;
[email protected]0f8f1b432010-03-16 19:06:03961
962 DISALLOW_COPY_AND_ASSIGN(IPv6ProbeJob);
963};
964
965//-----------------------------------------------------------------------------
966
[email protected]b3601bc22012-02-21 21:23:20967// Resolves the hostname using DnsTransaction.
968// TODO(szym): This could be moved to separate source file as well.
969class HostResolverImpl::DnsTask {
970 public:
971 typedef base::Callback<void(int net_error,
972 const AddressList& addr_list,
973 base::TimeDelta ttl)> Callback;
974
975 DnsTask(DnsTransactionFactory* factory,
976 const Key& key,
977 const Callback& callback,
978 const BoundNetLog& job_net_log)
979 : callback_(callback), net_log_(job_net_log) {
980 DCHECK(factory);
981 DCHECK(!callback.is_null());
982
983 // For now we treat ADDRESS_FAMILY_UNSPEC as if it was IPV4.
984 uint16 qtype = (key.address_family == ADDRESS_FAMILY_IPV6)
985 ? dns_protocol::kTypeAAAA
986 : dns_protocol::kTypeA;
987 // TODO(szym): Implement "happy eyeballs".
988 transaction_ = factory->CreateTransaction(
989 key.hostname,
990 qtype,
[email protected]1def74c2012-03-22 20:07:00991 base::Bind(&DnsTask::OnTransactionComplete, base::Unretained(this),
992 base::TimeTicks::Now()),
[email protected]b3601bc22012-02-21 21:23:20993 net_log_);
994 DCHECK(transaction_.get());
995 }
996
997 int Start() {
998 net_log_.BeginEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_DNS_TASK, NULL);
999 return transaction_->Start();
1000 }
1001
[email protected]1def74c2012-03-22 20:07:001002 void OnTransactionComplete(const base::TimeTicks& start_time,
1003 DnsTransaction* transaction,
[email protected]b3601bc22012-02-21 21:23:201004 int net_error,
1005 const DnsResponse* response) {
[email protected]add76532012-03-30 14:47:471006 DCHECK(transaction);
[email protected]b3601bc22012-02-21 21:23:201007 // Run |callback_| last since the owning Job will then delete this DnsTask.
1008 DnsResponse::Result result = DnsResponse::DNS_SUCCESS;
1009 if (net_error == OK) {
[email protected]add76532012-03-30 14:47:471010 CHECK(response);
[email protected]1def74c2012-03-22 20:07:001011 DNS_HISTOGRAM("AsyncDNS.TransactionSuccess",
1012 base::TimeTicks::Now() - start_time);
[email protected]b3601bc22012-02-21 21:23:201013 AddressList addr_list;
1014 base::TimeDelta ttl;
1015 result = response->ParseToAddressList(&addr_list, &ttl);
[email protected]1def74c2012-03-22 20:07:001016 UMA_HISTOGRAM_ENUMERATION("AsyncDNS.ParseToAddressList",
1017 result,
1018 DnsResponse::DNS_PARSE_RESULT_MAX);
[email protected]b3601bc22012-02-21 21:23:201019 if (result == DnsResponse::DNS_SUCCESS) {
1020 net_log_.EndEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_DNS_TASK,
[email protected]cd565142012-06-12 16:21:451021 addr_list.CreateNetLogCallback());
[email protected]b3601bc22012-02-21 21:23:201022 callback_.Run(net_error, addr_list, ttl);
1023 return;
1024 }
1025 net_error = ERR_DNS_MALFORMED_RESPONSE;
[email protected]1def74c2012-03-22 20:07:001026 } else {
1027 DNS_HISTOGRAM("AsyncDNS.TransactionFailure",
1028 base::TimeTicks::Now() - start_time);
[email protected]b3601bc22012-02-21 21:23:201029 }
[email protected]cd565142012-06-12 16:21:451030 net_log_.EndEvent(
1031 NetLog::TYPE_HOST_RESOLVER_IMPL_DNS_TASK,
1032 base::Bind(&NetLogDnsTaskFailedCallback, net_error, result));
[email protected]b3601bc22012-02-21 21:23:201033 callback_.Run(net_error, AddressList(), base::TimeDelta());
1034 }
1035
1036 private:
1037 // The listener to the results of this DnsTask.
1038 Callback callback_;
1039
1040 const BoundNetLog net_log_;
1041
1042 scoped_ptr<DnsTransaction> transaction_;
1043};
1044
1045//-----------------------------------------------------------------------------
1046
[email protected]0f292de02012-02-01 22:28:201047// Aggregates all Requests for the same Key. Dispatched via PriorityDispatch.
[email protected]0f292de02012-02-01 22:28:201048class HostResolverImpl::Job : public PrioritizedDispatcher::Job {
[email protected]68ad3ee2010-01-30 03:45:391049 public:
[email protected]0f292de02012-02-01 22:28:201050 // Creates new job for |key| where |request_net_log| is bound to the
[email protected]16ee26d2012-03-08 03:34:351051 // request that spawned it.
[email protected]0f292de02012-02-01 22:28:201052 Job(HostResolverImpl* resolver,
1053 const Key& key,
[email protected]16ee26d2012-03-08 03:34:351054 const BoundNetLog& request_net_log)
[email protected]0f292de02012-02-01 22:28:201055 : resolver_(resolver->AsWeakPtr()),
1056 key_(key),
1057 had_non_speculative_request_(false),
[email protected]1def74c2012-03-22 20:07:001058 had_dns_config_(false),
[email protected]0f292de02012-02-01 22:28:201059 net_log_(BoundNetLog::Make(request_net_log.net_log(),
[email protected]b3601bc22012-02-21 21:23:201060 NetLog::SOURCE_HOST_RESOLVER_IMPL_JOB)) {
[email protected]0f292de02012-02-01 22:28:201061 request_net_log.AddEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_CREATE_JOB, NULL);
1062
1063 net_log_.BeginEvent(
1064 NetLog::TYPE_HOST_RESOLVER_IMPL_JOB,
[email protected]cd565142012-06-12 16:21:451065 base::Bind(&NetLogJobCreationCallback,
1066 request_net_log.source(),
1067 &key_.hostname));
[email protected]68ad3ee2010-01-30 03:45:391068 }
1069
[email protected]0f292de02012-02-01 22:28:201070 virtual ~Job() {
[email protected]b3601bc22012-02-21 21:23:201071 if (is_running()) {
1072 // |resolver_| was destroyed with this Job still in flight.
1073 // Clean-up, record in the log, but don't run any callbacks.
1074 if (is_proc_running()) {
[email protected]0f292de02012-02-01 22:28:201075 proc_task_->Cancel();
1076 proc_task_ = NULL;
[email protected]0f292de02012-02-01 22:28:201077 }
[email protected]16ee26d2012-03-08 03:34:351078 // Clean up now for nice NetLog.
1079 dns_task_.reset(NULL);
[email protected]b3601bc22012-02-21 21:23:201080 net_log_.EndEventWithNetErrorCode(NetLog::TYPE_HOST_RESOLVER_IMPL_JOB,
1081 ERR_ABORTED);
1082 } else if (is_queued()) {
[email protected]57a48d32012-03-03 00:04:551083 // |resolver_| was destroyed without running this Job.
[email protected]16ee26d2012-03-08 03:34:351084 // TODO(szym): is there any benefit in having this distinction?
[email protected]b3601bc22012-02-21 21:23:201085 net_log_.AddEvent(NetLog::TYPE_CANCELLED, NULL);
1086 net_log_.EndEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_JOB, NULL);
[email protected]68ad3ee2010-01-30 03:45:391087 }
[email protected]b3601bc22012-02-21 21:23:201088 // else CompleteRequests logged EndEvent.
[email protected]68ad3ee2010-01-30 03:45:391089
[email protected]b3601bc22012-02-21 21:23:201090 // Log any remaining Requests as cancelled.
1091 for (RequestsList::const_iterator it = requests_.begin();
1092 it != requests_.end(); ++it) {
1093 Request* req = *it;
1094 if (req->was_canceled())
1095 continue;
1096 DCHECK_EQ(this, req->job());
1097 LogCancelRequest(req->source_net_log(), req->request_net_log(),
1098 req->info());
1099 }
[email protected]68ad3ee2010-01-30 03:45:391100 }
1101
[email protected]16ee26d2012-03-08 03:34:351102 // Add this job to the dispatcher.
1103 void Schedule(RequestPriority priority) {
1104 handle_ = resolver_->dispatcher_.Add(this, priority);
1105 }
1106
[email protected]b3601bc22012-02-21 21:23:201107 void AddRequest(scoped_ptr<Request> req) {
[email protected]0f292de02012-02-01 22:28:201108 DCHECK_EQ(key_.hostname, req->info().hostname());
1109
1110 req->set_job(this);
[email protected]0f292de02012-02-01 22:28:201111 priority_tracker_.Add(req->info().priority());
1112
1113 req->request_net_log().AddEvent(
1114 NetLog::TYPE_HOST_RESOLVER_IMPL_JOB_ATTACH,
[email protected]cd565142012-06-12 16:21:451115 net_log_.source().ToEventParametersCallback());
[email protected]0f292de02012-02-01 22:28:201116
1117 net_log_.AddEvent(
1118 NetLog::TYPE_HOST_RESOLVER_IMPL_JOB_REQUEST_ATTACH,
[email protected]cd565142012-06-12 16:21:451119 base::Bind(&NetLogJobAttachCallback,
1120 req->request_net_log().source(),
1121 priority()));
[email protected]0f292de02012-02-01 22:28:201122
1123 // TODO(szym): Check if this is still needed.
1124 if (!req->info().is_speculative()) {
1125 had_non_speculative_request_ = true;
1126 if (proc_task_)
1127 proc_task_->set_had_non_speculative_request();
[email protected]68ad3ee2010-01-30 03:45:391128 }
[email protected]b3601bc22012-02-21 21:23:201129
1130 requests_.push_back(req.release());
1131
[email protected]16ee26d2012-03-08 03:34:351132 if (is_queued())
[email protected]b3601bc22012-02-21 21:23:201133 handle_ = resolver_->dispatcher_.ChangePriority(handle_, priority());
[email protected]68ad3ee2010-01-30 03:45:391134 }
1135
[email protected]16ee26d2012-03-08 03:34:351136 // Marks |req| as cancelled. If it was the last active Request, also finishes
1137 // this Job marking it either as aborted or cancelled, and deletes it.
[email protected]0f292de02012-02-01 22:28:201138 void CancelRequest(Request* req) {
1139 DCHECK_EQ(key_.hostname, req->info().hostname());
1140 DCHECK(!req->was_canceled());
[email protected]16ee26d2012-03-08 03:34:351141
[email protected]0f292de02012-02-01 22:28:201142 // Don't remove it from |requests_| just mark it canceled.
1143 req->MarkAsCanceled();
1144 LogCancelRequest(req->source_net_log(), req->request_net_log(),
1145 req->info());
[email protected]16ee26d2012-03-08 03:34:351146
[email protected]0f292de02012-02-01 22:28:201147 priority_tracker_.Remove(req->info().priority());
1148 net_log_.AddEvent(
1149 NetLog::TYPE_HOST_RESOLVER_IMPL_JOB_REQUEST_DETACH,
[email protected]cd565142012-06-12 16:21:451150 base::Bind(&NetLogJobAttachCallback,
1151 req->request_net_log().source(),
1152 priority()));
[email protected]b3601bc22012-02-21 21:23:201153
[email protected]16ee26d2012-03-08 03:34:351154 if (num_active_requests() > 0) {
1155 if (is_queued())
[email protected]b3601bc22012-02-21 21:23:201156 handle_ = resolver_->dispatcher_.ChangePriority(handle_, priority());
[email protected]16ee26d2012-03-08 03:34:351157 } else {
1158 // If we were called from a Request's callback within CompleteRequests,
1159 // that Request could not have been cancelled, so num_active_requests()
1160 // could not be 0. Therefore, we are not in CompleteRequests().
1161 CompleteRequests(OK, AddressList(), base::TimeDelta());
[email protected]b3601bc22012-02-21 21:23:201162 }
[email protected]68ad3ee2010-01-30 03:45:391163 }
1164
[email protected]16ee26d2012-03-08 03:34:351165 // Called from AbortAllInProgressJobs. Completes all requests as aborted
1166 // and destroys the job.
[email protected]0f292de02012-02-01 22:28:201167 void Abort() {
[email protected]0f292de02012-02-01 22:28:201168 DCHECK(is_running());
[email protected]b3601bc22012-02-21 21:23:201169 CompleteRequests(ERR_ABORTED, AddressList(), base::TimeDelta());
1170 }
1171
[email protected]16ee26d2012-03-08 03:34:351172 // Called by HostResolverImpl when this job is evicted due to queue overflow.
1173 // Completes all requests and destroys the job.
1174 void OnEvicted() {
1175 DCHECK(!is_running());
1176 DCHECK(is_queued());
1177 handle_.Reset();
1178
1179 net_log_.AddEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_JOB_EVICTED, NULL);
1180
1181 // This signals to CompleteRequests that this job never ran.
1182 CompleteRequests(ERR_HOST_RESOLVER_QUEUE_TOO_LARGE,
1183 AddressList(),
1184 base::TimeDelta());
1185 }
1186
[email protected]78eac2a2012-03-14 19:09:271187 // Attempts to serve the job from HOSTS. Returns true if succeeded and
1188 // this Job was destroyed.
1189 bool ServeFromHosts() {
1190 DCHECK_GT(num_active_requests(), 0u);
1191 AddressList addr_list;
1192 if (resolver_->ServeFromHosts(key(),
[email protected]c143d892012-04-06 07:56:541193 requests_->front()->info(),
[email protected]78eac2a2012-03-14 19:09:271194 &addr_list)) {
1195 // This will destroy the Job.
1196 CompleteRequests(OK, addr_list, base::TimeDelta());
1197 return true;
1198 }
1199 return false;
1200 }
1201
[email protected]b4481b222012-03-16 17:13:111202 const Key key() const {
1203 return key_;
1204 }
1205
1206 bool is_queued() const {
1207 return !handle_.is_null();
1208 }
1209
1210 bool is_running() const {
1211 return is_dns_running() || is_proc_running();
1212 }
1213
[email protected]16ee26d2012-03-08 03:34:351214 private:
[email protected]16ee26d2012-03-08 03:34:351215 // PriorityDispatch::Job:
[email protected]0f292de02012-02-01 22:28:201216 virtual void Start() OVERRIDE {
1217 DCHECK(!is_running());
[email protected]b3601bc22012-02-21 21:23:201218 handle_.Reset();
[email protected]0f292de02012-02-01 22:28:201219
1220 net_log_.AddEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_JOB_STARTED, NULL);
1221
[email protected]1def74c2012-03-22 20:07:001222 had_dns_config_ = resolver_->HaveDnsConfig();
[email protected]16ee26d2012-03-08 03:34:351223 // Job::Start must not complete synchronously.
[email protected]1def74c2012-03-22 20:07:001224 if (had_dns_config_) {
[email protected]b3601bc22012-02-21 21:23:201225 StartDnsTask();
1226 } else {
1227 StartProcTask();
1228 }
1229 }
1230
[email protected]b3601bc22012-02-21 21:23:201231 // TODO(szym): Since DnsTransaction does not consume threads, we can increase
1232 // the limits on |dispatcher_|. But in order to keep the number of WorkerPool
1233 // threads low, we will need to use an "inner" PrioritizedDispatcher with
1234 // tighter limits.
1235 void StartProcTask() {
[email protected]16ee26d2012-03-08 03:34:351236 DCHECK(!is_dns_running());
[email protected]0f292de02012-02-01 22:28:201237 proc_task_ = new ProcTask(
1238 key_,
1239 resolver_->proc_params_,
1240 base::Bind(&Job::OnProcTaskComplete, base::Unretained(this)),
1241 net_log_);
1242
1243 if (had_non_speculative_request_)
1244 proc_task_->set_had_non_speculative_request();
1245 // Start() could be called from within Resolve(), hence it must NOT directly
1246 // call OnProcTaskComplete, for example, on synchronous failure.
1247 proc_task_->Start();
[email protected]68ad3ee2010-01-30 03:45:391248 }
1249
[email protected]0f292de02012-02-01 22:28:201250 // Called by ProcTask when it completes.
[email protected]b3601bc22012-02-21 21:23:201251 void OnProcTaskComplete(int net_error, const AddressList& addr_list) {
1252 DCHECK(is_proc_running());
[email protected]68ad3ee2010-01-30 03:45:391253
[email protected]1def74c2012-03-22 20:07:001254 if (had_dns_config_) {
1255 // TODO(szym): guess if the hostname is a NetBIOS name and discount it.
1256 if (net_error == OK) {
1257 UmaAsyncDnsResolveStatus(RESOLVE_STATUS_PROC_SUCCESS);
1258 } else {
1259 UmaAsyncDnsResolveStatus(RESOLVE_STATUS_FAIL);
1260 }
1261 }
1262
[email protected]b3601bc22012-02-21 21:23:201263 base::TimeDelta ttl = base::TimeDelta::FromSeconds(
1264 kNegativeCacheEntryTTLSeconds);
1265 if (net_error == OK)
1266 ttl = base::TimeDelta::FromSeconds(kCacheEntryTTLSeconds);
[email protected]68ad3ee2010-01-30 03:45:391267
[email protected]16ee26d2012-03-08 03:34:351268 CompleteRequests(net_error, addr_list, ttl);
[email protected]b3601bc22012-02-21 21:23:201269 }
1270
1271 void StartDnsTask() {
[email protected]78eac2a2012-03-14 19:09:271272 DCHECK(resolver_->HaveDnsConfig());
[email protected]b3601bc22012-02-21 21:23:201273 dns_task_.reset(new DnsTask(
[email protected]78eac2a2012-03-14 19:09:271274 resolver_->dns_client_->GetTransactionFactory(),
[email protected]b3601bc22012-02-21 21:23:201275 key_,
1276 base::Bind(&Job::OnDnsTaskComplete, base::Unretained(this)),
1277 net_log_));
1278
1279 int rv = dns_task_->Start();
1280 if (rv != ERR_IO_PENDING) {
1281 DCHECK_NE(OK, rv);
1282 dns_task_.reset();
1283 StartProcTask();
1284 }
1285 }
1286
1287 // Called by DnsTask when it completes.
1288 void OnDnsTaskComplete(int net_error,
1289 const AddressList& addr_list,
1290 base::TimeDelta ttl) {
1291 DCHECK(is_dns_running());
[email protected]b3601bc22012-02-21 21:23:201292
1293 if (net_error != OK) {
[email protected]16ee26d2012-03-08 03:34:351294 dns_task_.reset();
[email protected]78eac2a2012-03-14 19:09:271295
1296 // TODO(szym): Run ServeFromHosts now if nsswitch.conf says so.
1297 // http://crbug.com/117655
1298
[email protected]b3601bc22012-02-21 21:23:201299 // TODO(szym): Some net errors indicate lack of connectivity. Starting
1300 // ProcTask in that case is a waste of time.
1301 StartProcTask();
1302 return;
1303 }
1304
[email protected]1def74c2012-03-22 20:07:001305 UmaAsyncDnsResolveStatus(RESOLVE_STATUS_DNS_SUCCESS);
[email protected]16ee26d2012-03-08 03:34:351306 CompleteRequests(net_error, addr_list, ttl);
[email protected]b3601bc22012-02-21 21:23:201307 }
1308
[email protected]16ee26d2012-03-08 03:34:351309 // Performs Job's last rites. Completes all Requests. Deletes this.
[email protected]b3601bc22012-02-21 21:23:201310 void CompleteRequests(int net_error,
1311 const AddressList& addr_list,
1312 base::TimeDelta ttl) {
1313 CHECK(resolver_);
[email protected]b3601bc22012-02-21 21:23:201314
[email protected]16ee26d2012-03-08 03:34:351315 // This job must be removed from resolver's |jobs_| now to make room for a
1316 // new job with the same key in case one of the OnComplete callbacks decides
1317 // to spawn one. Consequently, the job deletes itself when CompleteRequests
1318 // is done.
1319 scoped_ptr<Job> self_deleter(this);
1320
1321 resolver_->RemoveJob(this);
1322
1323 // |addr_list| will be destroyed once we destroy |proc_task_| and
1324 // |dns_task_|.
[email protected]b3601bc22012-02-21 21:23:201325 AddressList list = addr_list;
[email protected]16ee26d2012-03-08 03:34:351326
1327 if (is_running()) {
1328 DCHECK(!is_queued());
1329 if (is_proc_running()) {
1330 proc_task_->Cancel();
1331 proc_task_ = NULL;
1332 }
1333 dns_task_.reset();
1334
1335 // Signal dispatcher that a slot has opened.
1336 resolver_->dispatcher_.OnJobFinished();
1337 } else if (is_queued()) {
1338 resolver_->dispatcher_.Cancel(handle_);
1339 handle_.Reset();
1340 }
1341
1342 if (num_active_requests() == 0) {
1343 net_log_.AddEvent(NetLog::TYPE_CANCELLED, NULL);
1344 net_log_.EndEventWithNetErrorCode(NetLog::TYPE_HOST_RESOLVER_IMPL_JOB,
1345 OK);
1346 return;
1347 }
[email protected]b3601bc22012-02-21 21:23:201348
1349 net_log_.EndEventWithNetErrorCode(NetLog::TYPE_HOST_RESOLVER_IMPL_JOB,
1350 net_error);
[email protected]68ad3ee2010-01-30 03:45:391351
[email protected]78eac2a2012-03-14 19:09:271352 DCHECK(!requests_.empty());
1353
[email protected]d7b9a2b2012-05-31 22:31:191354 if (net_error == OK) {
[email protected]7054e78f2012-05-07 21:44:561355 SetPortOnAddressList(requests_->front()->info().port(), &list);
[email protected]d7b9a2b2012-05-31 22:31:191356 // Record this histogram here, when we know the system has a valid DNS
1357 // configuration.
1358 UMA_HISTOGRAM_ENUMERATION("AsyncDNS.HaveDnsConfig",
1359 resolver_->received_dns_config_ ? 1 : 0,
1360 2);
1361 }
[email protected]16ee26d2012-03-08 03:34:351362
1363 if ((net_error != ERR_ABORTED) &&
1364 (net_error != ERR_HOST_RESOLVER_QUEUE_TOO_LARGE)) {
1365 resolver_->CacheResult(key_, net_error, list, ttl);
1366 }
1367
[email protected]0f292de02012-02-01 22:28:201368 // Complete all of the requests that were attached to the job.
1369 for (RequestsList::const_iterator it = requests_.begin();
1370 it != requests_.end(); ++it) {
1371 Request* req = *it;
1372
1373 if (req->was_canceled())
1374 continue;
1375
1376 DCHECK_EQ(this, req->job());
1377 // Update the net log and notify registered observers.
1378 LogFinishRequest(req->source_net_log(), req->request_net_log(),
[email protected]b3601bc22012-02-21 21:23:201379 req->info(), net_error);
[email protected]0f292de02012-02-01 22:28:201380
[email protected]b3601bc22012-02-21 21:23:201381 req->OnComplete(net_error, list);
[email protected]0f292de02012-02-01 22:28:201382
1383 // Check if the resolver was destroyed as a result of running the
1384 // callback. If it was, we could continue, but we choose to bail.
1385 if (!resolver_)
1386 return;
1387 }
1388 }
1389
[email protected]b4481b222012-03-16 17:13:111390 RequestPriority priority() const {
1391 return priority_tracker_.highest_priority();
1392 }
1393
1394 // Number of non-canceled requests in |requests_|.
1395 size_t num_active_requests() const {
1396 return priority_tracker_.total_count();
1397 }
1398
1399 bool is_dns_running() const {
1400 return dns_task_.get() != NULL;
1401 }
1402
1403 bool is_proc_running() const {
1404 return proc_task_.get() != NULL;
1405 }
1406
[email protected]0f292de02012-02-01 22:28:201407 base::WeakPtr<HostResolverImpl> resolver_;
1408
1409 Key key_;
1410
1411 // Tracks the highest priority across |requests_|.
1412 PriorityTracker priority_tracker_;
1413
1414 bool had_non_speculative_request_;
1415
[email protected]1def74c2012-03-22 20:07:001416 // True if resolver had DnsConfig when the Job was started.
1417 bool had_dns_config_;
1418
[email protected]0f292de02012-02-01 22:28:201419 BoundNetLog net_log_;
1420
[email protected]b3601bc22012-02-21 21:23:201421 // Resolves the host using a HostResolverProc.
[email protected]0f292de02012-02-01 22:28:201422 scoped_refptr<ProcTask> proc_task_;
1423
[email protected]b3601bc22012-02-21 21:23:201424 // Resolves the host using a DnsTransaction.
1425 scoped_ptr<DnsTask> dns_task_;
1426
[email protected]0f292de02012-02-01 22:28:201427 // All Requests waiting for the result of this Job. Some can be canceled.
1428 RequestsList requests_;
1429
[email protected]16ee26d2012-03-08 03:34:351430 // A handle used in |HostResolverImpl::dispatcher_|.
[email protected]0f292de02012-02-01 22:28:201431 PrioritizedDispatcher::Handle handle_;
[email protected]68ad3ee2010-01-30 03:45:391432};
1433
1434//-----------------------------------------------------------------------------
1435
[email protected]0f292de02012-02-01 22:28:201436HostResolverImpl::ProcTaskParams::ProcTaskParams(
[email protected]e95d3aca2010-01-11 22:47:431437 HostResolverProc* resolver_proc,
[email protected]0f292de02012-02-01 22:28:201438 size_t max_retry_attempts)
1439 : resolver_proc(resolver_proc),
1440 max_retry_attempts(max_retry_attempts),
1441 unresponsive_delay(base::TimeDelta::FromMilliseconds(6000)),
1442 retry_factor(2) {
1443}
1444
1445HostResolverImpl::ProcTaskParams::~ProcTaskParams() {}
1446
1447HostResolverImpl::HostResolverImpl(
[email protected]e95d3aca2010-01-11 22:47:431448 HostCache* cache,
[email protected]0f292de02012-02-01 22:28:201449 const PrioritizedDispatcher::Limits& job_limits,
1450 const ProcTaskParams& proc_params,
[email protected]b3601bc22012-02-21 21:23:201451 scoped_ptr<DnsConfigService> dns_config_service,
[email protected]d7b9a2b2012-05-31 22:31:191452 scoped_ptr<DnsClient> dns_client,
[email protected]ee094b82010-08-24 15:55:511453 NetLog* net_log)
[email protected]112bd462009-12-10 07:23:401454 : cache_(cache),
[email protected]0f292de02012-02-01 22:28:201455 dispatcher_(job_limits),
1456 max_queued_jobs_(job_limits.total_jobs * 100u),
1457 proc_params_(proc_params),
[email protected]0c7798452009-10-26 17:59:511458 default_address_family_(ADDRESS_FAMILY_UNSPECIFIED),
[email protected]b3601bc22012-02-21 21:23:201459 dns_config_service_(dns_config_service.Pass()),
[email protected]d7b9a2b2012-05-31 22:31:191460 dns_client_(dns_client.Pass()),
1461 received_dns_config_(false),
[email protected]2f3bc65c2010-07-23 17:47:101462 ipv6_probe_monitoring_(false),
[email protected]ee094b82010-08-24 15:55:511463 additional_resolver_flags_(0),
1464 net_log_(net_log) {
[email protected]0f292de02012-02-01 22:28:201465
1466 DCHECK_GE(dispatcher_.num_priorities(), static_cast<size_t>(NUM_PRIORITIES));
[email protected]68ad3ee2010-01-30 03:45:391467
[email protected]06ef6d92011-05-19 04:24:581468 // Maximum of 4 retry attempts for host resolution.
1469 static const size_t kDefaultMaxRetryAttempts = 4u;
1470
[email protected]0f292de02012-02-01 22:28:201471 if (proc_params_.max_retry_attempts == HostResolver::kDefaultRetryAttempts)
1472 proc_params_.max_retry_attempts = kDefaultMaxRetryAttempts;
[email protected]68ad3ee2010-01-30 03:45:391473
[email protected]b59ff372009-07-15 22:04:321474#if defined(OS_WIN)
1475 EnsureWinsockInit();
1476#endif
[email protected]23f771162011-06-02 18:37:511477#if defined(OS_POSIX) && !defined(OS_MACOSX)
[email protected]2f3bc65c2010-07-23 17:47:101478 if (HaveOnlyLoopbackAddresses())
1479 additional_resolver_flags_ |= HOST_RESOLVER_LOOPBACK_ONLY;
1480#endif
[email protected]232a5812011-03-04 22:42:081481 NetworkChangeNotifier::AddIPAddressObserver(this);
[email protected]d7b9a2b2012-05-31 22:31:191482#if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_OPENBSD) && \
1483 !defined(OS_ANDROID)
[email protected]46018c9d2011-09-06 03:42:341484 NetworkChangeNotifier::AddDNSObserver(this);
[email protected]d7b9a2b2012-05-31 22:31:191485 EnsureDnsReloaderInit();
[email protected]46018c9d2011-09-06 03:42:341486#endif
[email protected]b3601bc22012-02-21 21:23:201487
[email protected]78eac2a2012-03-14 19:09:271488 if (dns_config_service_.get()) {
[email protected]b4481b222012-03-16 17:13:111489 dns_config_service_->Watch(
1490 base::Bind(&HostResolverImpl::OnDnsConfigChanged,
1491 base::Unretained(this)));
[email protected]78eac2a2012-03-14 19:09:271492 }
[email protected]b59ff372009-07-15 22:04:321493}
1494
1495HostResolverImpl::~HostResolverImpl() {
[email protected]0f8f1b432010-03-16 19:06:031496 DiscardIPv6ProbeJob();
1497
[email protected]0f292de02012-02-01 22:28:201498 // This will also cancel all outstanding requests.
1499 STLDeleteValues(&jobs_);
[email protected]e95d3aca2010-01-11 22:47:431500
[email protected]232a5812011-03-04 22:42:081501 NetworkChangeNotifier::RemoveIPAddressObserver(this);
[email protected]46018c9d2011-09-06 03:42:341502 NetworkChangeNotifier::RemoveDNSObserver(this);
[email protected]b59ff372009-07-15 22:04:321503}
1504
[email protected]0f292de02012-02-01 22:28:201505void HostResolverImpl::SetMaxQueuedJobs(size_t value) {
1506 DCHECK_EQ(0u, dispatcher_.num_queued_jobs());
1507 DCHECK_GT(value, 0u);
1508 max_queued_jobs_ = value;
[email protected]be1a48b2011-01-20 00:12:131509}
1510
[email protected]684970b2009-08-14 04:54:461511int HostResolverImpl::Resolve(const RequestInfo& info,
[email protected]b59ff372009-07-15 22:04:321512 AddressList* addresses,
[email protected]aa22b242011-11-16 18:58:291513 const CompletionCallback& callback,
[email protected]684970b2009-08-14 04:54:461514 RequestHandle* out_req,
[email protected]ee094b82010-08-24 15:55:511515 const BoundNetLog& source_net_log) {
[email protected]95a214c2011-08-04 21:50:401516 DCHECK(addresses);
[email protected]1ac6af92010-06-03 21:00:141517 DCHECK(CalledOnValidThread());
[email protected]aa22b242011-11-16 18:58:291518 DCHECK_EQ(false, callback.is_null());
[email protected]1ac6af92010-06-03 21:00:141519
[email protected]ee094b82010-08-24 15:55:511520 // Make a log item for the request.
1521 BoundNetLog request_net_log = BoundNetLog::Make(net_log_,
1522 NetLog::SOURCE_HOST_RESOLVER_IMPL_REQUEST);
1523
[email protected]0f292de02012-02-01 22:28:201524 LogStartRequest(source_net_log, request_net_log, info);
[email protected]b59ff372009-07-15 22:04:321525
[email protected]123ab1e32009-10-21 19:12:571526 // Build a key that identifies the request in the cache and in the
1527 // outstanding jobs map.
[email protected]137af622010-02-05 02:14:351528 Key key = GetEffectiveKeyForRequest(info);
[email protected]123ab1e32009-10-21 19:12:571529
[email protected]287d7c22011-11-15 17:34:251530 int rv = ResolveHelper(key, info, addresses, request_net_log);
[email protected]95a214c2011-08-04 21:50:401531 if (rv != ERR_DNS_CACHE_MISS) {
[email protected]b3601bc22012-02-21 21:23:201532 LogFinishRequest(source_net_log, request_net_log, info, rv);
[email protected]95a214c2011-08-04 21:50:401533 return rv;
[email protected]38368712011-03-02 08:09:401534 }
1535
[email protected]0f292de02012-02-01 22:28:201536 // Next we need to attach our request to a "job". This job is responsible for
1537 // calling "getaddrinfo(hostname)" on a worker thread.
1538
1539 JobMap::iterator jobit = jobs_.find(key);
1540 Job* job;
1541 if (jobit == jobs_.end()) {
1542 // Create new Job.
[email protected]16ee26d2012-03-08 03:34:351543 job = new Job(this, key, request_net_log);
1544 job->Schedule(info.priority());
[email protected]0f292de02012-02-01 22:28:201545
1546 // Check for queue overflow.
1547 if (dispatcher_.num_queued_jobs() > max_queued_jobs_) {
1548 Job* evicted = static_cast<Job*>(dispatcher_.EvictOldestLowest());
1549 DCHECK(evicted);
[email protected]16ee26d2012-03-08 03:34:351550 evicted->OnEvicted(); // Deletes |evicted|.
[email protected]0f292de02012-02-01 22:28:201551 if (evicted == job) {
[email protected]0f292de02012-02-01 22:28:201552 rv = ERR_HOST_RESOLVER_QUEUE_TOO_LARGE;
[email protected]b3601bc22012-02-21 21:23:201553 LogFinishRequest(source_net_log, request_net_log, info, rv);
[email protected]0f292de02012-02-01 22:28:201554 return rv;
1555 }
[email protected]0f292de02012-02-01 22:28:201556 }
[email protected]0f292de02012-02-01 22:28:201557 jobs_.insert(jobit, std::make_pair(key, job));
1558 } else {
1559 job = jobit->second;
1560 }
1561
1562 // Can't complete synchronously. Create and attach request.
[email protected]b3601bc22012-02-21 21:23:201563 scoped_ptr<Request> req(new Request(source_net_log,
1564 request_net_log,
1565 info,
1566 callback,
1567 addresses));
[email protected]b59ff372009-07-15 22:04:321568 if (out_req)
[email protected]b3601bc22012-02-21 21:23:201569 *out_req = reinterpret_cast<RequestHandle>(req.get());
[email protected]b59ff372009-07-15 22:04:321570
[email protected]b3601bc22012-02-21 21:23:201571 job->AddRequest(req.Pass());
[email protected]0f292de02012-02-01 22:28:201572 // Completion happens during Job::CompleteRequests().
[email protected]b59ff372009-07-15 22:04:321573 return ERR_IO_PENDING;
1574}
1575
[email protected]287d7c22011-11-15 17:34:251576int HostResolverImpl::ResolveHelper(const Key& key,
[email protected]95a214c2011-08-04 21:50:401577 const RequestInfo& info,
1578 AddressList* addresses,
[email protected]20cd5332011-10-12 22:38:001579 const BoundNetLog& request_net_log) {
[email protected]95a214c2011-08-04 21:50:401580 // The result of |getaddrinfo| for empty hosts is inconsistent across systems.
1581 // On Windows it gives the default interface's address, whereas on Linux it
1582 // gives an error. We will make it fail on all platforms for consistency.
1583 if (info.hostname().empty() || info.hostname().size() > kMaxHostLength)
1584 return ERR_NAME_NOT_RESOLVED;
1585
1586 int net_error = ERR_UNEXPECTED;
1587 if (ResolveAsIP(key, info, &net_error, addresses))
1588 return net_error;
[email protected]78eac2a2012-03-14 19:09:271589 if (ServeFromCache(key, info, &net_error, addresses)) {
1590 request_net_log.AddEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_CACHE_HIT, NULL);
1591 return net_error;
1592 }
1593 // TODO(szym): Do not do this if nsswitch.conf instructs not to.
1594 // http://crbug.com/117655
1595 if (ServeFromHosts(key, info, addresses)) {
1596 request_net_log.AddEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_HOSTS_HIT, NULL);
1597 return OK;
1598 }
1599 return ERR_DNS_CACHE_MISS;
[email protected]95a214c2011-08-04 21:50:401600}
1601
1602int HostResolverImpl::ResolveFromCache(const RequestInfo& info,
1603 AddressList* addresses,
1604 const BoundNetLog& source_net_log) {
1605 DCHECK(CalledOnValidThread());
1606 DCHECK(addresses);
1607
[email protected]95a214c2011-08-04 21:50:401608 // Make a log item for the request.
1609 BoundNetLog request_net_log = BoundNetLog::Make(net_log_,
1610 NetLog::SOURCE_HOST_RESOLVER_IMPL_REQUEST);
1611
1612 // Update the net log and notify registered observers.
[email protected]0f292de02012-02-01 22:28:201613 LogStartRequest(source_net_log, request_net_log, info);
[email protected]95a214c2011-08-04 21:50:401614
[email protected]95a214c2011-08-04 21:50:401615 Key key = GetEffectiveKeyForRequest(info);
1616
[email protected]287d7c22011-11-15 17:34:251617 int rv = ResolveHelper(key, info, addresses, request_net_log);
[email protected]b3601bc22012-02-21 21:23:201618 LogFinishRequest(source_net_log, request_net_log, info, rv);
[email protected]95a214c2011-08-04 21:50:401619 return rv;
1620}
1621
[email protected]b59ff372009-07-15 22:04:321622void HostResolverImpl::CancelRequest(RequestHandle req_handle) {
[email protected]1ac6af92010-06-03 21:00:141623 DCHECK(CalledOnValidThread());
[email protected]b59ff372009-07-15 22:04:321624 Request* req = reinterpret_cast<Request*>(req_handle);
1625 DCHECK(req);
[email protected]0f292de02012-02-01 22:28:201626 Job* job = req->job();
1627 DCHECK(job);
[email protected]0f292de02012-02-01 22:28:201628 job->CancelRequest(req);
[email protected]b59ff372009-07-15 22:04:321629}
1630
[email protected]0f8f1b432010-03-16 19:06:031631void HostResolverImpl::SetDefaultAddressFamily(AddressFamily address_family) {
[email protected]1ac6af92010-06-03 21:00:141632 DCHECK(CalledOnValidThread());
[email protected]0f8f1b432010-03-16 19:06:031633 ipv6_probe_monitoring_ = false;
1634 DiscardIPv6ProbeJob();
1635 default_address_family_ = address_family;
1636}
1637
[email protected]f7d310e2010-10-07 16:25:111638AddressFamily HostResolverImpl::GetDefaultAddressFamily() const {
1639 return default_address_family_;
1640}
1641
[email protected]a78f4272011-10-21 19:16:331642void HostResolverImpl::ProbeIPv6Support() {
1643 DCHECK(CalledOnValidThread());
1644 DCHECK(!ipv6_probe_monitoring_);
1645 ipv6_probe_monitoring_ = true;
1646 OnIPAddressChanged(); // Give initial setup call.
[email protected]ddb1e5a2010-12-13 20:10:451647}
1648
[email protected]489d1a82011-10-12 03:09:111649HostCache* HostResolverImpl::GetHostCache() {
1650 return cache_.get();
1651}
[email protected]95a214c2011-08-04 21:50:401652
[email protected]17e92032012-03-29 00:56:241653base::Value* HostResolverImpl::GetDnsConfigAsValue() const {
1654 // Check if async DNS is disabled.
1655 if (!dns_client_.get())
1656 return NULL;
1657
1658 // Check if async DNS is enabled, but we currently have no configuration
1659 // for it.
1660 const DnsConfig* dns_config = dns_client_->GetConfig();
1661 if (dns_config == NULL)
1662 return new DictionaryValue();
1663
1664 return dns_config->ToValue();
1665}
1666
[email protected]95a214c2011-08-04 21:50:401667bool HostResolverImpl::ResolveAsIP(const Key& key,
1668 const RequestInfo& info,
1669 int* net_error,
1670 AddressList* addresses) {
1671 DCHECK(addresses);
1672 DCHECK(net_error);
1673 IPAddressNumber ip_number;
1674 if (!ParseIPLiteralToNumber(key.hostname, &ip_number))
1675 return false;
1676
1677 DCHECK_EQ(key.host_resolver_flags &
1678 ~(HOST_RESOLVER_CANONNAME | HOST_RESOLVER_LOOPBACK_ONLY |
1679 HOST_RESOLVER_DEFAULT_FAMILY_SET_DUE_TO_NO_IPV6),
1680 0) << " Unhandled flag";
[email protected]0f292de02012-02-01 22:28:201681 bool ipv6_disabled = (default_address_family_ == ADDRESS_FAMILY_IPV4) &&
1682 !ipv6_probe_monitoring_;
[email protected]95a214c2011-08-04 21:50:401683 *net_error = OK;
[email protected]0f292de02012-02-01 22:28:201684 if ((ip_number.size() == kIPv6AddressSize) && ipv6_disabled) {
[email protected]95a214c2011-08-04 21:50:401685 *net_error = ERR_NAME_NOT_RESOLVED;
1686 } else {
[email protected]7054e78f2012-05-07 21:44:561687 *addresses = AddressList::CreateFromIPAddress(ip_number, info.port());
1688 if (key.host_resolver_flags & HOST_RESOLVER_CANONNAME)
1689 addresses->SetDefaultCanonicalName();
[email protected]95a214c2011-08-04 21:50:401690 }
1691 return true;
1692}
1693
1694bool HostResolverImpl::ServeFromCache(const Key& key,
1695 const RequestInfo& info,
[email protected]95a214c2011-08-04 21:50:401696 int* net_error,
1697 AddressList* addresses) {
1698 DCHECK(addresses);
1699 DCHECK(net_error);
1700 if (!info.allow_cached_response() || !cache_.get())
1701 return false;
1702
1703 const HostCache::Entry* cache_entry = cache_->Lookup(
1704 key, base::TimeTicks::Now());
1705 if (!cache_entry)
1706 return false;
1707
[email protected]95a214c2011-08-04 21:50:401708 *net_error = cache_entry->error;
[email protected]7054e78f2012-05-07 21:44:561709 if (*net_error == OK) {
1710 *addresses = cache_entry->addrlist;
1711 EnsurePortOnAddressList(info.port(), addresses);
1712 }
[email protected]95a214c2011-08-04 21:50:401713 return true;
1714}
1715
[email protected]78eac2a2012-03-14 19:09:271716bool HostResolverImpl::ServeFromHosts(const Key& key,
1717 const RequestInfo& info,
1718 AddressList* addresses) {
1719 DCHECK(addresses);
1720 if (!HaveDnsConfig())
1721 return false;
1722
[email protected]cb507622012-03-23 16:17:061723 // HOSTS lookups are case-insensitive.
1724 std::string hostname = StringToLowerASCII(key.hostname);
1725
[email protected]78eac2a2012-03-14 19:09:271726 // If |address_family| is ADDRESS_FAMILY_UNSPECIFIED other implementations
1727 // (glibc and c-ares) return the first matching line. We have more
1728 // flexibility, but lose implicit ordering.
1729 // TODO(szym) http://crbug.com/117850
1730 const DnsHosts& hosts = dns_client_->GetConfig()->hosts;
1731 DnsHosts::const_iterator it = hosts.find(
[email protected]cb507622012-03-23 16:17:061732 DnsHostsKey(hostname,
[email protected]78eac2a2012-03-14 19:09:271733 key.address_family == ADDRESS_FAMILY_UNSPECIFIED ?
1734 ADDRESS_FAMILY_IPV4 : key.address_family));
1735
1736 if (it == hosts.end()) {
1737 if (key.address_family != ADDRESS_FAMILY_UNSPECIFIED)
1738 return false;
1739
[email protected]cb507622012-03-23 16:17:061740 it = hosts.find(DnsHostsKey(hostname, ADDRESS_FAMILY_IPV6));
[email protected]78eac2a2012-03-14 19:09:271741 if (it == hosts.end())
1742 return false;
1743 }
1744
1745 *addresses = AddressList::CreateFromIPAddress(it->second, info.port());
1746 return true;
1747}
1748
[email protected]16ee26d2012-03-08 03:34:351749void HostResolverImpl::CacheResult(const Key& key,
1750 int net_error,
1751 const AddressList& addr_list,
1752 base::TimeDelta ttl) {
1753 if (cache_.get())
1754 cache_->Set(key, net_error, addr_list, base::TimeTicks::Now(), ttl);
[email protected]ef4c40c2010-09-01 14:42:031755}
1756
[email protected]0f292de02012-02-01 22:28:201757void HostResolverImpl::RemoveJob(Job* job) {
1758 DCHECK(job);
[email protected]16ee26d2012-03-08 03:34:351759 JobMap::iterator it = jobs_.find(job->key());
1760 if (it != jobs_.end() && it->second == job)
1761 jobs_.erase(it);
[email protected]b59ff372009-07-15 22:04:321762}
1763
[email protected]0f8f1b432010-03-16 19:06:031764void HostResolverImpl::DiscardIPv6ProbeJob() {
1765 if (ipv6_probe_job_.get()) {
1766 ipv6_probe_job_->Cancel();
1767 ipv6_probe_job_ = NULL;
1768 }
1769}
1770
1771void HostResolverImpl::IPv6ProbeSetDefaultAddressFamily(
1772 AddressFamily address_family) {
1773 DCHECK(address_family == ADDRESS_FAMILY_UNSPECIFIED ||
1774 address_family == ADDRESS_FAMILY_IPV4);
[email protected]f092e64b2010-03-17 00:39:181775 if (default_address_family_ != address_family) {
[email protected]b30a3f52010-10-16 01:05:461776 VLOG(1) << "IPv6Probe forced AddressFamily setting to "
1777 << ((address_family == ADDRESS_FAMILY_UNSPECIFIED) ?
1778 "ADDRESS_FAMILY_UNSPECIFIED" : "ADDRESS_FAMILY_IPV4");
[email protected]f092e64b2010-03-17 00:39:181779 }
[email protected]0f8f1b432010-03-16 19:06:031780 default_address_family_ = address_family;
1781 // Drop reference since the job has called us back.
1782 DiscardIPv6ProbeJob();
[email protected]e95d3aca2010-01-11 22:47:431783}
1784
[email protected]137af622010-02-05 02:14:351785HostResolverImpl::Key HostResolverImpl::GetEffectiveKeyForRequest(
1786 const RequestInfo& info) const {
[email protected]eaf3a3b2010-09-03 20:34:271787 HostResolverFlags effective_flags =
1788 info.host_resolver_flags() | additional_resolver_flags_;
[email protected]137af622010-02-05 02:14:351789 AddressFamily effective_address_family = info.address_family();
[email protected]eaf3a3b2010-09-03 20:34:271790 if (effective_address_family == ADDRESS_FAMILY_UNSPECIFIED &&
1791 default_address_family_ != ADDRESS_FAMILY_UNSPECIFIED) {
[email protected]137af622010-02-05 02:14:351792 effective_address_family = default_address_family_;
[email protected]eaf3a3b2010-09-03 20:34:271793 if (ipv6_probe_monitoring_)
1794 effective_flags |= HOST_RESOLVER_DEFAULT_FAMILY_SET_DUE_TO_NO_IPV6;
1795 }
1796 return Key(info.hostname(), effective_address_family, effective_flags);
[email protected]137af622010-02-05 02:14:351797}
1798
[email protected]35ddc282010-09-21 23:42:061799void HostResolverImpl::AbortAllInProgressJobs() {
[email protected]b3601bc22012-02-21 21:23:201800 // In Abort, a Request callback could spawn new Jobs with matching keys, so
1801 // first collect and remove all running jobs from |jobs_|.
[email protected]c143d892012-04-06 07:56:541802 ScopedVector<Job> jobs_to_abort;
[email protected]0f292de02012-02-01 22:28:201803 for (JobMap::iterator it = jobs_.begin(); it != jobs_.end(); ) {
1804 Job* job = it->second;
[email protected]0f292de02012-02-01 22:28:201805 if (job->is_running()) {
[email protected]b3601bc22012-02-21 21:23:201806 jobs_to_abort.push_back(job);
1807 jobs_.erase(it++);
[email protected]0f292de02012-02-01 22:28:201808 } else {
[email protected]b3601bc22012-02-21 21:23:201809 DCHECK(job->is_queued());
1810 ++it;
[email protected]0f292de02012-02-01 22:28:201811 }
[email protected]ef4c40c2010-09-01 14:42:031812 }
[email protected]b3601bc22012-02-21 21:23:201813
[email protected]57a48d32012-03-03 00:04:551814 // Check if no dispatcher slots leaked out.
1815 DCHECK_EQ(dispatcher_.num_running_jobs(), jobs_to_abort.size());
1816
1817 // Life check to bail once |this| is deleted.
1818 base::WeakPtr<HostResolverImpl> self = AsWeakPtr();
1819
[email protected]16ee26d2012-03-08 03:34:351820 // Then Abort them.
[email protected]57a48d32012-03-03 00:04:551821 for (size_t i = 0; self && i < jobs_to_abort.size(); ++i) {
[email protected]57a48d32012-03-03 00:04:551822 jobs_to_abort[i]->Abort();
[email protected]c143d892012-04-06 07:56:541823 jobs_to_abort[i] = NULL;
[email protected]b3601bc22012-02-21 21:23:201824 }
[email protected]ef4c40c2010-09-01 14:42:031825}
1826
[email protected]78eac2a2012-03-14 19:09:271827void HostResolverImpl::TryServingAllJobsFromHosts() {
1828 if (!HaveDnsConfig())
1829 return;
1830
1831 // TODO(szym): Do not do this if nsswitch.conf instructs not to.
1832 // http://crbug.com/117655
1833
1834 // Life check to bail once |this| is deleted.
1835 base::WeakPtr<HostResolverImpl> self = AsWeakPtr();
1836
1837 for (JobMap::iterator it = jobs_.begin(); self && it != jobs_.end(); ) {
1838 Job* job = it->second;
1839 ++it;
1840 // This could remove |job| from |jobs_|, but iterator will remain valid.
1841 job->ServeFromHosts();
1842 }
1843}
1844
[email protected]be1a48b2011-01-20 00:12:131845void HostResolverImpl::OnIPAddressChanged() {
1846 if (cache_.get())
1847 cache_->clear();
1848 if (ipv6_probe_monitoring_) {
[email protected]be1a48b2011-01-20 00:12:131849 DiscardIPv6ProbeJob();
1850 ipv6_probe_job_ = new IPv6ProbeJob(this);
1851 ipv6_probe_job_->Start();
1852 }
[email protected]23f771162011-06-02 18:37:511853#if defined(OS_POSIX) && !defined(OS_MACOSX)
[email protected]be1a48b2011-01-20 00:12:131854 if (HaveOnlyLoopbackAddresses()) {
1855 additional_resolver_flags_ |= HOST_RESOLVER_LOOPBACK_ONLY;
1856 } else {
1857 additional_resolver_flags_ &= ~HOST_RESOLVER_LOOPBACK_ONLY;
1858 }
1859#endif
1860 AbortAllInProgressJobs();
1861 // |this| may be deleted inside AbortAllInProgressJobs().
1862}
1863
[email protected]446df2952012-02-28 07:22:511864void HostResolverImpl::OnDNSChanged(unsigned detail) {
[email protected]d7b9a2b2012-05-31 22:31:191865 // Ignore signals about watches.
1866 const unsigned kIgnoredDetail =
1867 NetworkChangeNotifier::CHANGE_DNS_WATCH_STARTED |
1868 NetworkChangeNotifier::CHANGE_DNS_WATCH_FAILED;
1869 if ((detail & ~kIgnoredDetail) == 0)
1870 return;
[email protected]46018c9d2011-09-06 03:42:341871 // If the DNS server has changed, existing cached info could be wrong so we
1872 // have to drop our internal cache :( Note that OS level DNS caches, such
1873 // as NSCD's cache should be dropped automatically by the OS when
1874 // resolv.conf changes so we don't need to do anything to clear that cache.
1875 if (cache_.get())
1876 cache_->clear();
1877 // Existing jobs will have been sent to the original server so they need to
[email protected]d7b9a2b2012-05-31 22:31:191878 // be aborted.
[email protected]46018c9d2011-09-06 03:42:341879 AbortAllInProgressJobs();
1880 // |this| may be deleted inside AbortAllInProgressJobs().
1881}
1882
[email protected]b4481b222012-03-16 17:13:111883void HostResolverImpl::OnDnsConfigChanged(const DnsConfig& dns_config) {
1884 if (net_log_) {
1885 net_log_->AddGlobalEntry(
1886 NetLog::TYPE_DNS_CONFIG_CHANGED,
[email protected]cd565142012-06-12 16:21:451887 base::Bind(&NetLogDnsConfigCallback, &dns_config));
[email protected]b4481b222012-03-16 17:13:111888 }
1889
[email protected]d7b9a2b2012-05-31 22:31:191890 // TODO(szym): Remove once http://crbug.com/125599 is resolved.
1891 received_dns_config_ = dns_config.IsValid();
[email protected]78eac2a2012-03-14 19:09:271892
1893 // Life check to bail once |this| is deleted.
1894 base::WeakPtr<HostResolverImpl> self = AsWeakPtr();
1895
[email protected]d7b9a2b2012-05-31 22:31:191896 if (dns_client_.get()) {
1897 // We want a new factory in place, before we Abort running Jobs, so that the
1898 // newly started jobs use the new factory.
1899 dns_client_->SetConfig(dns_config);
[email protected]446df2952012-02-28 07:22:511900 OnDNSChanged(NetworkChangeNotifier::CHANGE_DNS_SETTINGS);
[email protected]d7b9a2b2012-05-31 22:31:191901 // |this| may be deleted inside OnDNSChanged().
1902 if (self)
1903 TryServingAllJobsFromHosts();
[email protected]7b5db762012-03-24 09:02:011904 }
[email protected]78eac2a2012-03-14 19:09:271905}
1906
1907bool HostResolverImpl::HaveDnsConfig() const {
1908 return (dns_client_.get() != NULL) && (dns_client_->GetConfig() != NULL);
[email protected]b3601bc22012-02-21 21:23:201909}
1910
[email protected]b59ff372009-07-15 22:04:321911} // namespace net