blob: edab00e1e87c2ad5244ca3244a1a1bd1687b3500 [file] [log] [blame]
[email protected]a2730882012-01-21 00:56:271// Copyright (c) 2012 The Chromium Authors. All rights reserved.
[email protected]b59ff372009-07-15 22:04:322// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "net/base/host_resolver_impl.h"
6
[email protected]21526002010-05-16 19:42:467#if defined(OS_WIN)
8#include <Winsock2.h>
9#elif defined(OS_POSIX)
10#include <netdb.h>
11#endif
12
[email protected]68ad3ee2010-01-30 03:45:3913#include <cmath>
[email protected]0f292de02012-02-01 22:28:2014#include <utility>
[email protected]21526002010-05-16 19:42:4615#include <vector>
[email protected]68ad3ee2010-01-30 03:45:3916
17#include "base/basictypes.h"
[email protected]33152acc2011-10-20 23:37:1218#include "base/bind.h"
[email protected]aa22b242011-11-16 18:58:2919#include "base/bind_helpers.h"
[email protected]0f292de02012-02-01 22:28:2020#include "base/callback.h"
[email protected]b59ff372009-07-15 22:04:3221#include "base/compiler_specific.h"
[email protected]58580352010-10-26 04:07:5022#include "base/debug/debugger.h"
23#include "base/debug/stack_trace.h"
[email protected]3e9d9cc2011-05-03 21:08:1524#include "base/message_loop_proxy.h"
[email protected]1e9bbd22010-10-15 16:42:4525#include "base/metrics/field_trial.h"
[email protected]835d7c82010-10-14 04:38:3826#include "base/metrics/histogram.h"
[email protected]7286e3fc2011-07-19 22:13:2427#include "base/stl_util.h"
[email protected]b59ff372009-07-15 22:04:3228#include "base/string_util.h"
[email protected]ac9ba8fe2010-12-30 18:08:3629#include "base/threading/worker_pool.h"
[email protected]b59ff372009-07-15 22:04:3230#include "base/time.h"
[email protected]ccaff652010-07-31 06:28:2031#include "base/utf_string_conversions.h"
[email protected]21526002010-05-16 19:42:4632#include "base/values.h"
[email protected]b3601bc22012-02-21 21:23:2033#include "net/base/address_family.h"
[email protected]b59ff372009-07-15 22:04:3234#include "net/base/address_list.h"
[email protected]46018c9d2011-09-06 03:42:3435#include "net/base/dns_reloader.h"
[email protected]ee094b82010-08-24 15:55:5136#include "net/base/host_port_pair.h"
[email protected]b59ff372009-07-15 22:04:3237#include "net/base/host_resolver_proc.h"
[email protected]2bb04442010-08-18 18:01:1538#include "net/base/net_errors.h"
[email protected]ee094b82010-08-24 15:55:5139#include "net/base/net_log.h"
[email protected]0f8f1b432010-03-16 19:06:0340#include "net/base/net_util.h"
[email protected]78eac2a2012-03-14 19:09:2741#include "net/dns/dns_client.h"
[email protected]b3601bc22012-02-21 21:23:2042#include "net/dns/dns_config_service.h"
43#include "net/dns/dns_protocol.h"
44#include "net/dns/dns_response.h"
[email protected]b3601bc22012-02-21 21:23:2045#include "net/dns/dns_transaction.h"
[email protected]b59ff372009-07-15 22:04:3246
47#if defined(OS_WIN)
48#include "net/base/winsock_init.h"
49#endif
50
51namespace net {
52
[email protected]e95d3aca2010-01-11 22:47:4353namespace {
54
[email protected]6e78dfb2011-07-28 21:34:4755// Limit the size of hostnames that will be resolved to combat issues in
56// some platform's resolvers.
57const size_t kMaxHostLength = 4096;
58
[email protected]a2730882012-01-21 00:56:2759// Default TTL for successful resolutions with ProcTask.
60const unsigned kCacheEntryTTLSeconds = 60;
61
[email protected]b3601bc22012-02-21 21:23:2062// Default TTL for unsuccessful resolutions with ProcTask.
63const unsigned kNegativeCacheEntryTTLSeconds = 0;
64
[email protected]4f8a16a2012-04-07 23:59:2065// Maximum of 6 concurrent resolver threads (excluding retries).
[email protected]0f292de02012-02-01 22:28:2066// Some routers (or resolvers) appear to start to provide host-not-found if
67// too many simultaneous resolutions are pending. This number needs to be
[email protected]4f8a16a2012-04-07 23:59:2068// further optimized, but 8 is what FF currently does. We found some routers
69// that limit this to 6, so we're temporarily holding it at that level.
70static const size_t kDefaultMaxProcTasks = 6u;
[email protected]0f292de02012-02-01 22:28:2071
[email protected]24f4bab2010-10-15 01:27:1172// We use a separate histogram name for each platform to facilitate the
73// display of error codes by their symbolic name (since each platform has
74// different mappings).
75const char kOSErrorsForGetAddrinfoHistogramName[] =
76#if defined(OS_WIN)
77 "Net.OSErrorsForGetAddrinfo_Win";
78#elif defined(OS_MACOSX)
79 "Net.OSErrorsForGetAddrinfo_Mac";
80#elif defined(OS_LINUX)
81 "Net.OSErrorsForGetAddrinfo_Linux";
82#else
83 "Net.OSErrorsForGetAddrinfo";
84#endif
85
[email protected]c89b2442011-05-26 14:28:2786// Gets a list of the likely error codes that getaddrinfo() can return
87// (non-exhaustive). These are the error codes that we will track via
88// a histogram.
89std::vector<int> GetAllGetAddrinfoOSErrors() {
90 int os_errors[] = {
91#if defined(OS_POSIX)
[email protected]23f771162011-06-02 18:37:5192#if !defined(OS_FREEBSD)
[email protected]39588992011-07-11 19:54:3793#if !defined(OS_ANDROID)
[email protected]c48aef92011-11-22 23:41:4594 // EAI_ADDRFAMILY has been declared obsolete in Android's and
95 // FreeBSD's netdb.h.
[email protected]c89b2442011-05-26 14:28:2796 EAI_ADDRFAMILY,
[email protected]39588992011-07-11 19:54:3797#endif
[email protected]c48aef92011-11-22 23:41:4598 // EAI_NODATA has been declared obsolete in FreeBSD's netdb.h.
[email protected]23f771162011-06-02 18:37:5199 EAI_NODATA,
100#endif
[email protected]c89b2442011-05-26 14:28:27101 EAI_AGAIN,
102 EAI_BADFLAGS,
103 EAI_FAIL,
104 EAI_FAMILY,
105 EAI_MEMORY,
[email protected]c89b2442011-05-26 14:28:27106 EAI_NONAME,
107 EAI_SERVICE,
108 EAI_SOCKTYPE,
109 EAI_SYSTEM,
110#elif defined(OS_WIN)
111 // See: http://msdn.microsoft.com/en-us/library/ms738520(VS.85).aspx
112 WSA_NOT_ENOUGH_MEMORY,
113 WSAEAFNOSUPPORT,
114 WSAEINVAL,
115 WSAESOCKTNOSUPPORT,
116 WSAHOST_NOT_FOUND,
117 WSANO_DATA,
118 WSANO_RECOVERY,
119 WSANOTINITIALISED,
120 WSATRY_AGAIN,
121 WSATYPE_NOT_FOUND,
122 // The following are not in doc, but might be to appearing in results :-(.
123 WSA_INVALID_HANDLE,
124#endif
125 };
126
127 // Ensure all errors are positive, as histogram only tracks positive values.
128 for (size_t i = 0; i < arraysize(os_errors); ++i) {
129 os_errors[i] = std::abs(os_errors[i]);
130 }
131
132 return base::CustomHistogram::ArrayToCustomRanges(os_errors,
133 arraysize(os_errors));
134}
135
[email protected]1def74c2012-03-22 20:07:00136enum DnsResolveStatus {
137 RESOLVE_STATUS_DNS_SUCCESS = 0,
138 RESOLVE_STATUS_PROC_SUCCESS,
139 RESOLVE_STATUS_FAIL,
[email protected]1d932852012-06-19 19:40:33140 RESOLVE_STATUS_SUSPECT_NETBIOS,
[email protected]1def74c2012-03-22 20:07:00141 RESOLVE_STATUS_MAX
142};
143
144void UmaAsyncDnsResolveStatus(DnsResolveStatus result) {
145 UMA_HISTOGRAM_ENUMERATION("AsyncDNS.ResolveStatus",
146 result,
147 RESOLVE_STATUS_MAX);
148}
149
[email protected]1d932852012-06-19 19:40:33150bool ResemblesNetBIOSName(const std::string& hostname) {
151 return (hostname.size() < 16) && (hostname.find('.') == std::string::npos);
152}
153
154// True if |hostname| ends with either ".local" or ".local.".
155bool ResemblesMulticastDNSName(const std::string& hostname) {
156 DCHECK(!hostname.empty());
157 const char kSuffix[] = ".local.";
158 const size_t kSuffixLen = sizeof(kSuffix) - 1;
159 const size_t kSuffixLenTrimmed = kSuffixLen - 1;
160 if (hostname[hostname.size() - 1] == '.') {
161 return hostname.size() > kSuffixLen &&
162 !hostname.compare(hostname.size() - kSuffixLen, kSuffixLen, kSuffix);
163 }
164 return hostname.size() > kSuffixLenTrimmed &&
165 !hostname.compare(hostname.size() - kSuffixLenTrimmed, kSuffixLenTrimmed,
166 kSuffix, kSuffixLenTrimmed);
167}
168
[email protected]d7b9a2b2012-05-31 22:31:19169//-----------------------------------------------------------------------------
170
[email protected]0f292de02012-02-01 22:28:20171// Wraps call to SystemHostResolverProc as an instance of HostResolverProc.
172// TODO(szym): This should probably be declared in host_resolver_proc.h.
173class CallSystemHostResolverProc : public HostResolverProc {
174 public:
175 CallSystemHostResolverProc() : HostResolverProc(NULL) {}
176 virtual int Resolve(const std::string& hostname,
177 AddressFamily address_family,
178 HostResolverFlags host_resolver_flags,
[email protected]b3601bc22012-02-21 21:23:20179 AddressList* addr_list,
[email protected]0f292de02012-02-01 22:28:20180 int* os_error) OVERRIDE {
181 return SystemHostResolverProc(hostname,
182 address_family,
183 host_resolver_flags,
[email protected]b3601bc22012-02-21 21:23:20184 addr_list,
[email protected]0f292de02012-02-01 22:28:20185 os_error);
[email protected]b59ff372009-07-15 22:04:32186 }
[email protected]a9813302012-04-28 09:29:28187
188 protected:
189 virtual ~CallSystemHostResolverProc() {}
[email protected]0f292de02012-02-01 22:28:20190};
[email protected]b59ff372009-07-15 22:04:32191
[email protected]7054e78f2012-05-07 21:44:56192void EnsurePortOnAddressList(uint16 port, AddressList* list) {
193 DCHECK(list);
194 if (list->empty() || list->front().port() == port)
195 return;
196 SetPortOnAddressList(port, list);
197}
198
[email protected]cd565142012-06-12 16:21:45199// Creates NetLog parameters when the resolve failed.
200base::Value* NetLogProcTaskFailedCallback(uint32 attempt_number,
201 int net_error,
202 int os_error,
203 NetLog::LogLevel /* log_level */) {
204 DictionaryValue* dict = new DictionaryValue();
205 if (attempt_number)
206 dict->SetInteger("attempt_number", attempt_number);
[email protected]21526002010-05-16 19:42:46207
[email protected]cd565142012-06-12 16:21:45208 dict->SetInteger("net_error", net_error);
[email protected]13024882011-05-18 23:19:16209
[email protected]cd565142012-06-12 16:21:45210 if (os_error) {
211 dict->SetInteger("os_error", os_error);
[email protected]21526002010-05-16 19:42:46212#if defined(OS_POSIX)
[email protected]cd565142012-06-12 16:21:45213 dict->SetString("os_error_string", gai_strerror(os_error));
[email protected]21526002010-05-16 19:42:46214#elif defined(OS_WIN)
[email protected]cd565142012-06-12 16:21:45215 // Map the error code to a human-readable string.
216 LPWSTR error_string = NULL;
217 int size = FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
218 FORMAT_MESSAGE_FROM_SYSTEM,
219 0, // Use the internal message table.
220 os_error,
221 0, // Use default language.
222 (LPWSTR)&error_string,
223 0, // Buffer size.
224 0); // Arguments (unused).
225 dict->SetString("os_error_string", WideToUTF8(error_string));
226 LocalFree(error_string);
[email protected]21526002010-05-16 19:42:46227#endif
[email protected]21526002010-05-16 19:42:46228 }
229
[email protected]cd565142012-06-12 16:21:45230 return dict;
231}
[email protected]a9813302012-04-28 09:29:28232
[email protected]cd565142012-06-12 16:21:45233// Creates NetLog parameters when the DnsTask failed.
234base::Value* NetLogDnsTaskFailedCallback(int net_error,
235 int dns_error,
236 NetLog::LogLevel /* log_level */) {
237 DictionaryValue* dict = new DictionaryValue();
238 dict->SetInteger("net_error", net_error);
239 if (dns_error)
240 dict->SetInteger("dns_error", dns_error);
241 return dict;
[email protected]ee094b82010-08-24 15:55:51242};
243
[email protected]cd565142012-06-12 16:21:45244// Creates NetLog parameters containing the information in a RequestInfo object,
245// along with the associated NetLog::Source.
246base::Value* NetLogRequestInfoCallback(const NetLog::Source& source,
247 const HostResolver::RequestInfo* info,
248 NetLog::LogLevel /* log_level */) {
249 DictionaryValue* dict = new DictionaryValue();
250 source.AddToEventParameters(dict);
[email protected]b3601bc22012-02-21 21:23:20251
[email protected]cd565142012-06-12 16:21:45252 dict->SetString("host", info->host_port_pair().ToString());
253 dict->SetInteger("address_family",
254 static_cast<int>(info->address_family()));
255 dict->SetBoolean("allow_cached_response", info->allow_cached_response());
256 dict->SetBoolean("is_speculative", info->is_speculative());
257 dict->SetInteger("priority", info->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 creation of a HostResolverImpl::Job.
262base::Value* NetLogJobCreationCallback(const NetLog::Source& source,
263 const std::string* host,
264 NetLog::LogLevel /* log_level */) {
265 DictionaryValue* dict = new DictionaryValue();
266 source.AddToEventParameters(dict);
267 dict->SetString("host", *host);
268 return dict;
269}
[email protected]a9813302012-04-28 09:29:28270
[email protected]cd565142012-06-12 16:21:45271// Creates NetLog parameters for HOST_RESOLVER_IMPL_JOB_ATTACH/DETACH events.
272base::Value* NetLogJobAttachCallback(const NetLog::Source& source,
273 RequestPriority priority,
274 NetLog::LogLevel /* log_level */) {
275 DictionaryValue* dict = new DictionaryValue();
276 source.AddToEventParameters(dict);
277 dict->SetInteger("priority", priority);
278 return dict;
279}
[email protected]b3601bc22012-02-21 21:23:20280
[email protected]cd565142012-06-12 16:21:45281// Creates NetLog parameters for the DNS_CONFIG_CHANGED event.
282base::Value* NetLogDnsConfigCallback(const DnsConfig* config,
283 NetLog::LogLevel /* log_level */) {
284 return config->ToValue();
285}
[email protected]b4481b222012-03-16 17:13:11286
[email protected]0f292de02012-02-01 22:28:20287// The logging routines are defined here because some requests are resolved
288// without a Request object.
289
290// Logs when a request has just been started.
291void LogStartRequest(const BoundNetLog& source_net_log,
292 const BoundNetLog& request_net_log,
293 const HostResolver::RequestInfo& info) {
294 source_net_log.BeginEvent(
295 NetLog::TYPE_HOST_RESOLVER_IMPL,
[email protected]cd565142012-06-12 16:21:45296 request_net_log.source().ToEventParametersCallback());
[email protected]0f292de02012-02-01 22:28:20297
298 request_net_log.BeginEvent(
299 NetLog::TYPE_HOST_RESOLVER_IMPL_REQUEST,
[email protected]cd565142012-06-12 16:21:45300 base::Bind(&NetLogRequestInfoCallback, source_net_log.source(), &info));
[email protected]0f292de02012-02-01 22:28:20301}
302
303// Logs when a request has just completed (before its callback is run).
304void LogFinishRequest(const BoundNetLog& source_net_log,
305 const BoundNetLog& request_net_log,
306 const HostResolver::RequestInfo& info,
[email protected]b3601bc22012-02-21 21:23:20307 int net_error) {
308 request_net_log.EndEventWithNetErrorCode(
309 NetLog::TYPE_HOST_RESOLVER_IMPL_REQUEST, net_error);
[email protected]4da911f2012-06-14 19:45:20310 source_net_log.EndEvent(NetLog::TYPE_HOST_RESOLVER_IMPL);
[email protected]0f292de02012-02-01 22:28:20311}
312
313// Logs when a request has been cancelled.
314void LogCancelRequest(const BoundNetLog& source_net_log,
315 const BoundNetLog& request_net_log,
316 const HostResolverImpl::RequestInfo& info) {
[email protected]4da911f2012-06-14 19:45:20317 request_net_log.AddEvent(NetLog::TYPE_CANCELLED);
318 request_net_log.EndEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_REQUEST);
319 source_net_log.EndEvent(NetLog::TYPE_HOST_RESOLVER_IMPL);
[email protected]0f292de02012-02-01 22:28:20320}
321
[email protected]b59ff372009-07-15 22:04:32322//-----------------------------------------------------------------------------
323
[email protected]0f292de02012-02-01 22:28:20324// Keeps track of the highest priority.
325class PriorityTracker {
326 public:
[email protected]16ee26d2012-03-08 03:34:35327 PriorityTracker()
328 : highest_priority_(IDLE), total_count_(0) {
[email protected]0f292de02012-02-01 22:28:20329 memset(counts_, 0, sizeof(counts_));
330 }
331
332 RequestPriority highest_priority() const {
333 return highest_priority_;
334 }
335
336 size_t total_count() const {
337 return total_count_;
338 }
339
340 void Add(RequestPriority req_priority) {
341 ++total_count_;
342 ++counts_[req_priority];
[email protected]31ae7ab2012-04-24 21:09:05343 if (highest_priority_ < req_priority)
[email protected]0f292de02012-02-01 22:28:20344 highest_priority_ = req_priority;
345 }
346
347 void Remove(RequestPriority req_priority) {
348 DCHECK_GT(total_count_, 0u);
349 DCHECK_GT(counts_[req_priority], 0u);
350 --total_count_;
351 --counts_[req_priority];
352 size_t i;
[email protected]31ae7ab2012-04-24 21:09:05353 for (i = highest_priority_; i > MINIMUM_PRIORITY && !counts_[i]; --i);
[email protected]0f292de02012-02-01 22:28:20354 highest_priority_ = static_cast<RequestPriority>(i);
355
[email protected]31ae7ab2012-04-24 21:09:05356 // In absence of requests, default to MINIMUM_PRIORITY.
357 if (total_count_ == 0)
358 DCHECK_EQ(MINIMUM_PRIORITY, highest_priority_);
[email protected]0f292de02012-02-01 22:28:20359 }
360
361 private:
362 RequestPriority highest_priority_;
363 size_t total_count_;
364 size_t counts_[NUM_PRIORITIES];
365};
366
367//-----------------------------------------------------------------------------
368
369HostResolver* CreateHostResolver(size_t max_concurrent_resolves,
370 size_t max_retry_attempts,
[email protected]b3601bc22012-02-21 21:23:20371 HostCache* cache,
372 scoped_ptr<DnsConfigService> config_service,
[email protected]d7b9a2b2012-05-31 22:31:19373 scoped_ptr<DnsClient> dns_client,
[email protected]0f292de02012-02-01 22:28:20374 NetLog* net_log) {
375 if (max_concurrent_resolves == HostResolver::kDefaultParallelism)
376 max_concurrent_resolves = kDefaultMaxProcTasks;
377
378 // TODO(szym): Add experiments with reserved slots for higher priority
379 // requests.
380
381 PrioritizedDispatcher::Limits limits(NUM_PRIORITIES, max_concurrent_resolves);
382
383 HostResolverImpl* resolver = new HostResolverImpl(
[email protected]b3601bc22012-02-21 21:23:20384 cache,
[email protected]0f292de02012-02-01 22:28:20385 limits,
386 HostResolverImpl::ProcTaskParams(NULL, max_retry_attempts),
[email protected]b3601bc22012-02-21 21:23:20387 config_service.Pass(),
[email protected]d7b9a2b2012-05-31 22:31:19388 dns_client.Pass(),
[email protected]0f292de02012-02-01 22:28:20389 net_log);
390
391 return resolver;
392}
393
394} // anonymous namespace
395
396//-----------------------------------------------------------------------------
397
398HostResolver* CreateSystemHostResolver(size_t max_concurrent_resolves,
399 size_t max_retry_attempts,
400 NetLog* net_log) {
401 return CreateHostResolver(max_concurrent_resolves,
402 max_retry_attempts,
[email protected]b3601bc22012-02-21 21:23:20403 HostCache::CreateDefaultCache(),
[email protected]d7b9a2b2012-05-31 22:31:19404 DnsConfigService::CreateSystemService(),
405 scoped_ptr<DnsClient>(NULL),
[email protected]0f292de02012-02-01 22:28:20406 net_log);
407}
408
409HostResolver* CreateNonCachingSystemHostResolver(size_t max_concurrent_resolves,
410 size_t max_retry_attempts,
411 NetLog* net_log) {
412 return CreateHostResolver(max_concurrent_resolves,
413 max_retry_attempts,
[email protected]b3601bc22012-02-21 21:23:20414 NULL,
415 scoped_ptr<DnsConfigService>(NULL),
[email protected]d7b9a2b2012-05-31 22:31:19416 scoped_ptr<DnsClient>(NULL),
[email protected]b3601bc22012-02-21 21:23:20417 net_log);
418}
419
420HostResolver* CreateAsyncHostResolver(size_t max_concurrent_resolves,
421 size_t max_retry_attempts,
422 NetLog* net_log) {
[email protected]b3601bc22012-02-21 21:23:20423 return CreateHostResolver(max_concurrent_resolves,
424 max_retry_attempts,
425 HostCache::CreateDefaultCache(),
[email protected]d7b9a2b2012-05-31 22:31:19426 DnsConfigService::CreateSystemService(),
427 DnsClient::CreateClient(net_log),
[email protected]0f292de02012-02-01 22:28:20428 net_log);
429}
430
431//-----------------------------------------------------------------------------
432
433// Holds the data for a request that could not be completed synchronously.
434// It is owned by a Job. Canceled Requests are only marked as canceled rather
435// than removed from the Job's |requests_| list.
[email protected]b59ff372009-07-15 22:04:32436class HostResolverImpl::Request {
437 public:
[email protected]ee094b82010-08-24 15:55:51438 Request(const BoundNetLog& source_net_log,
439 const BoundNetLog& request_net_log,
[email protected]54e13772009-08-14 03:01:09440 const RequestInfo& info,
[email protected]aa22b242011-11-16 18:58:29441 const CompletionCallback& callback,
[email protected]b59ff372009-07-15 22:04:32442 AddressList* addresses)
[email protected]ee094b82010-08-24 15:55:51443 : source_net_log_(source_net_log),
444 request_net_log_(request_net_log),
[email protected]54e13772009-08-14 03:01:09445 info_(info),
446 job_(NULL),
447 callback_(callback),
448 addresses_(addresses) {
449 }
[email protected]b59ff372009-07-15 22:04:32450
[email protected]0f292de02012-02-01 22:28:20451 // Mark the request as canceled.
452 void MarkAsCanceled() {
[email protected]b59ff372009-07-15 22:04:32453 job_ = NULL;
[email protected]b59ff372009-07-15 22:04:32454 addresses_ = NULL;
[email protected]aa22b242011-11-16 18:58:29455 callback_.Reset();
[email protected]b59ff372009-07-15 22:04:32456 }
457
[email protected]0f292de02012-02-01 22:28:20458 bool was_canceled() const {
[email protected]aa22b242011-11-16 18:58:29459 return callback_.is_null();
[email protected]b59ff372009-07-15 22:04:32460 }
461
462 void set_job(Job* job) {
[email protected]0f292de02012-02-01 22:28:20463 DCHECK(job);
[email protected]b59ff372009-07-15 22:04:32464 // Identify which job the request is waiting on.
465 job_ = job;
466 }
467
[email protected]0f292de02012-02-01 22:28:20468 // Prepare final AddressList and call completion callback.
[email protected]b3601bc22012-02-21 21:23:20469 void OnComplete(int error, const AddressList& addr_list) {
[email protected]7054e78f2012-05-07 21:44:56470 if (error == OK) {
471 *addresses_ = addr_list;
472 EnsurePortOnAddressList(info_.port(), addresses_);
473 }
[email protected]aa22b242011-11-16 18:58:29474 CompletionCallback callback = callback_;
[email protected]0f292de02012-02-01 22:28:20475 MarkAsCanceled();
[email protected]aa22b242011-11-16 18:58:29476 callback.Run(error);
[email protected]b59ff372009-07-15 22:04:32477 }
478
[email protected]b59ff372009-07-15 22:04:32479 Job* job() const {
480 return job_;
481 }
482
[email protected]0f292de02012-02-01 22:28:20483 // NetLog for the source, passed in HostResolver::Resolve.
[email protected]ee094b82010-08-24 15:55:51484 const BoundNetLog& source_net_log() {
485 return source_net_log_;
486 }
487
[email protected]0f292de02012-02-01 22:28:20488 // NetLog for this request.
[email protected]ee094b82010-08-24 15:55:51489 const BoundNetLog& request_net_log() {
490 return request_net_log_;
[email protected]54e13772009-08-14 03:01:09491 }
492
[email protected]b59ff372009-07-15 22:04:32493 const RequestInfo& info() const {
494 return info_;
495 }
496
497 private:
[email protected]ee094b82010-08-24 15:55:51498 BoundNetLog source_net_log_;
499 BoundNetLog request_net_log_;
[email protected]54e13772009-08-14 03:01:09500
[email protected]b59ff372009-07-15 22:04:32501 // The request info that started the request.
502 RequestInfo info_;
503
[email protected]0f292de02012-02-01 22:28:20504 // The resolve job that this request is dependent on.
[email protected]b59ff372009-07-15 22:04:32505 Job* job_;
506
507 // The user's callback to invoke when the request completes.
[email protected]aa22b242011-11-16 18:58:29508 CompletionCallback callback_;
[email protected]b59ff372009-07-15 22:04:32509
510 // The address list to save result into.
511 AddressList* addresses_;
512
513 DISALLOW_COPY_AND_ASSIGN(Request);
514};
515
[email protected]1e9bbd22010-10-15 16:42:45516//------------------------------------------------------------------------------
517
518// Provide a common macro to simplify code and readability. We must use a
519// macros as the underlying HISTOGRAM macro creates static varibles.
520#define DNS_HISTOGRAM(name, time) UMA_HISTOGRAM_CUSTOM_TIMES(name, time, \
521 base::TimeDelta::FromMicroseconds(1), base::TimeDelta::FromHours(1), 100)
[email protected]b59ff372009-07-15 22:04:32522
[email protected]0f292de02012-02-01 22:28:20523// Calls HostResolverProc on the WorkerPool. Performs retries if necessary.
524//
525// Whenever we try to resolve the host, we post a delayed task to check if host
526// resolution (OnLookupComplete) is completed or not. If the original attempt
527// hasn't completed, then we start another attempt for host resolution. We take
528// the results from the first attempt that finishes and ignore the results from
529// all other attempts.
530//
531// TODO(szym): Move to separate source file for testing and mocking.
532//
533class HostResolverImpl::ProcTask
534 : public base::RefCountedThreadSafe<HostResolverImpl::ProcTask> {
[email protected]b59ff372009-07-15 22:04:32535 public:
[email protected]b3601bc22012-02-21 21:23:20536 typedef base::Callback<void(int net_error,
537 const AddressList& addr_list)> Callback;
[email protected]b59ff372009-07-15 22:04:32538
[email protected]0f292de02012-02-01 22:28:20539 ProcTask(const Key& key,
540 const ProcTaskParams& params,
541 const Callback& callback,
542 const BoundNetLog& job_net_log)
543 : key_(key),
544 params_(params),
545 callback_(callback),
546 origin_loop_(base::MessageLoopProxy::current()),
547 attempt_number_(0),
548 completed_attempt_number_(0),
549 completed_attempt_error_(ERR_UNEXPECTED),
550 had_non_speculative_request_(false),
[email protected]b3601bc22012-02-21 21:23:20551 net_log_(job_net_log) {
[email protected]0f292de02012-02-01 22:28:20552 if (!params_.resolver_proc)
553 params_.resolver_proc = HostResolverProc::GetDefault();
554 // If default is unset, use the system proc.
555 if (!params_.resolver_proc)
556 params_.resolver_proc = new CallSystemHostResolverProc();
[email protected]b59ff372009-07-15 22:04:32557 }
558
[email protected]b59ff372009-07-15 22:04:32559 void Start() {
[email protected]3e9d9cc2011-05-03 21:08:15560 DCHECK(origin_loop_->BelongsToCurrentThread());
[email protected]4da911f2012-06-14 19:45:20561 net_log_.BeginEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_PROC_TASK);
[email protected]189163e2011-05-11 01:48:54562 StartLookupAttempt();
563 }
[email protected]252b699b2010-02-05 21:38:06564
[email protected]0f292de02012-02-01 22:28:20565 // Cancels this ProcTask. It will be orphaned. Any outstanding resolve
566 // attempts running on worker threads will continue running. Only once all the
567 // attempts complete will the final reference to this ProcTask be released.
568 void Cancel() {
569 DCHECK(origin_loop_->BelongsToCurrentThread());
570
571 if (was_canceled())
572 return;
573
[email protected]0f292de02012-02-01 22:28:20574 callback_.Reset();
[email protected]4da911f2012-06-14 19:45:20575 net_log_.EndEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_PROC_TASK);
[email protected]0f292de02012-02-01 22:28:20576 }
577
578 void set_had_non_speculative_request() {
579 DCHECK(origin_loop_->BelongsToCurrentThread());
580 had_non_speculative_request_ = true;
581 }
582
583 bool was_canceled() const {
584 DCHECK(origin_loop_->BelongsToCurrentThread());
585 return callback_.is_null();
586 }
587
588 bool was_completed() const {
589 DCHECK(origin_loop_->BelongsToCurrentThread());
590 return completed_attempt_number_ > 0;
591 }
592
593 private:
[email protected]a9813302012-04-28 09:29:28594 friend class base::RefCountedThreadSafe<ProcTask>;
595 ~ProcTask() {}
596
[email protected]189163e2011-05-11 01:48:54597 void StartLookupAttempt() {
598 DCHECK(origin_loop_->BelongsToCurrentThread());
599 base::TimeTicks start_time = base::TimeTicks::Now();
600 ++attempt_number_;
601 // Dispatch the lookup attempt to a worker thread.
602 if (!base::WorkerPool::PostTask(
603 FROM_HERE,
[email protected]0f292de02012-02-01 22:28:20604 base::Bind(&ProcTask::DoLookup, this, start_time, attempt_number_),
[email protected]189163e2011-05-11 01:48:54605 true)) {
[email protected]b59ff372009-07-15 22:04:32606 NOTREACHED();
607
608 // Since we could be running within Resolve() right now, we can't just
609 // call OnLookupComplete(). Instead we must wait until Resolve() has
610 // returned (IO_PENDING).
[email protected]3e9d9cc2011-05-03 21:08:15611 origin_loop_->PostTask(
[email protected]189163e2011-05-11 01:48:54612 FROM_HERE,
[email protected]0f292de02012-02-01 22:28:20613 base::Bind(&ProcTask::OnLookupComplete, this, AddressList(),
[email protected]33152acc2011-10-20 23:37:12614 start_time, attempt_number_, ERR_UNEXPECTED, 0));
[email protected]189163e2011-05-11 01:48:54615 return;
[email protected]b59ff372009-07-15 22:04:32616 }
[email protected]13024882011-05-18 23:19:16617
618 net_log_.AddEvent(
619 NetLog::TYPE_HOST_RESOLVER_IMPL_ATTEMPT_STARTED,
[email protected]cd565142012-06-12 16:21:45620 NetLog::IntegerCallback("attempt_number", attempt_number_));
[email protected]13024882011-05-18 23:19:16621
[email protected]0f292de02012-02-01 22:28:20622 // If we don't get the results within a given time, RetryIfNotComplete
623 // will start a new attempt on a different worker thread if none of our
624 // outstanding attempts have completed yet.
625 if (attempt_number_ <= params_.max_retry_attempts) {
[email protected]06ef6d92011-05-19 04:24:58626 origin_loop_->PostDelayedTask(
627 FROM_HERE,
[email protected]0f292de02012-02-01 22:28:20628 base::Bind(&ProcTask::RetryIfNotComplete, this),
[email protected]7e560102012-03-08 20:58:42629 params_.unresponsive_delay);
[email protected]06ef6d92011-05-19 04:24:58630 }
[email protected]b59ff372009-07-15 22:04:32631 }
632
[email protected]6c710ee2010-05-07 07:51:16633 // WARNING: This code runs inside a worker pool. The shutdown code cannot
634 // wait for it to finish, so we must be very careful here about using other
635 // objects (like MessageLoops, Singletons, etc). During shutdown these objects
[email protected]189163e2011-05-11 01:48:54636 // may no longer exist. Multiple DoLookups() could be running in parallel, so
637 // any state inside of |this| must not mutate .
638 void DoLookup(const base::TimeTicks& start_time,
639 const uint32 attempt_number) {
640 AddressList results;
641 int os_error = 0;
[email protected]b59ff372009-07-15 22:04:32642 // Running on the worker thread
[email protected]0f292de02012-02-01 22:28:20643 int error = params_.resolver_proc->Resolve(key_.hostname,
644 key_.address_family,
645 key_.host_resolver_flags,
646 &results,
647 &os_error);
[email protected]b59ff372009-07-15 22:04:32648
[email protected]189163e2011-05-11 01:48:54649 origin_loop_->PostTask(
650 FROM_HERE,
[email protected]0f292de02012-02-01 22:28:20651 base::Bind(&ProcTask::OnLookupComplete, this, results, start_time,
[email protected]33152acc2011-10-20 23:37:12652 attempt_number, error, os_error));
[email protected]189163e2011-05-11 01:48:54653 }
654
[email protected]0f292de02012-02-01 22:28:20655 // Makes next attempt if DoLookup() has not finished (runs on origin thread).
656 void RetryIfNotComplete() {
[email protected]189163e2011-05-11 01:48:54657 DCHECK(origin_loop_->BelongsToCurrentThread());
658
[email protected]0f292de02012-02-01 22:28:20659 if (was_completed() || was_canceled())
[email protected]189163e2011-05-11 01:48:54660 return;
661
[email protected]0f292de02012-02-01 22:28:20662 params_.unresponsive_delay *= params_.retry_factor;
[email protected]189163e2011-05-11 01:48:54663 StartLookupAttempt();
[email protected]b59ff372009-07-15 22:04:32664 }
665
666 // Callback for when DoLookup() completes (runs on origin thread).
[email protected]189163e2011-05-11 01:48:54667 void OnLookupComplete(const AddressList& results,
668 const base::TimeTicks& start_time,
669 const uint32 attempt_number,
670 int error,
671 const int os_error) {
[email protected]3e9d9cc2011-05-03 21:08:15672 DCHECK(origin_loop_->BelongsToCurrentThread());
[email protected]7054e78f2012-05-07 21:44:56673 DCHECK(error || !results.empty());
[email protected]189163e2011-05-11 01:48:54674
675 bool was_retry_attempt = attempt_number > 1;
676
[email protected]2d3b7762010-10-09 00:35:47677 // Ideally the following code would be part of host_resolver_proc.cc,
[email protected]b3601bc22012-02-21 21:23:20678 // however it isn't safe to call NetworkChangeNotifier from worker threads.
679 // So we do it here on the IO thread instead.
[email protected]189163e2011-05-11 01:48:54680 if (error != OK && NetworkChangeNotifier::IsOffline())
681 error = ERR_INTERNET_DISCONNECTED;
[email protected]2d3b7762010-10-09 00:35:47682
[email protected]b3601bc22012-02-21 21:23:20683 // If this is the first attempt that is finishing later, then record data
684 // for the first attempt. Won't contaminate with retry attempt's data.
[email protected]189163e2011-05-11 01:48:54685 if (!was_retry_attempt)
686 RecordPerformanceHistograms(start_time, error, os_error);
687
688 RecordAttemptHistograms(start_time, attempt_number, error, os_error);
[email protected]f2d8c4212010-02-02 00:56:35689
[email protected]0f292de02012-02-01 22:28:20690 if (was_canceled())
[email protected]b59ff372009-07-15 22:04:32691 return;
692
[email protected]cd565142012-06-12 16:21:45693 NetLog::ParametersCallback net_log_callback;
[email protected]0f292de02012-02-01 22:28:20694 if (error != OK) {
[email protected]cd565142012-06-12 16:21:45695 net_log_callback = base::Bind(&NetLogProcTaskFailedCallback,
696 attempt_number,
697 error,
698 os_error);
[email protected]0f292de02012-02-01 22:28:20699 } else {
[email protected]cd565142012-06-12 16:21:45700 net_log_callback = NetLog::IntegerCallback("attempt_number",
701 attempt_number);
[email protected]0f292de02012-02-01 22:28:20702 }
[email protected]cd565142012-06-12 16:21:45703 net_log_.AddEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_ATTEMPT_FINISHED,
704 net_log_callback);
[email protected]0f292de02012-02-01 22:28:20705
706 if (was_completed())
707 return;
708
709 // Copy the results from the first worker thread that resolves the host.
710 results_ = results;
711 completed_attempt_number_ = attempt_number;
712 completed_attempt_error_ = error;
713
[email protected]e87b8b512011-06-14 22:12:52714 if (was_retry_attempt) {
715 // If retry attempt finishes before 1st attempt, then get stats on how
716 // much time is saved by having spawned an extra attempt.
717 retry_attempt_finished_time_ = base::TimeTicks::Now();
718 }
719
[email protected]189163e2011-05-11 01:48:54720 if (error != OK) {
[email protected]cd565142012-06-12 16:21:45721 net_log_callback = base::Bind(&NetLogProcTaskFailedCallback,
722 0, error, os_error);
[email protected]ee094b82010-08-24 15:55:51723 } else {
[email protected]cd565142012-06-12 16:21:45724 net_log_callback = results_.CreateNetLogCallback();
[email protected]ee094b82010-08-24 15:55:51725 }
[email protected]cd565142012-06-12 16:21:45726 net_log_.EndEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_PROC_TASK,
727 net_log_callback);
[email protected]ee094b82010-08-24 15:55:51728
[email protected]b3601bc22012-02-21 21:23:20729 callback_.Run(error, results_);
[email protected]b59ff372009-07-15 22:04:32730 }
731
[email protected]189163e2011-05-11 01:48:54732 void RecordPerformanceHistograms(const base::TimeTicks& start_time,
733 const int error,
734 const int os_error) const {
[email protected]3e9d9cc2011-05-03 21:08:15735 DCHECK(origin_loop_->BelongsToCurrentThread());
[email protected]1e9bbd22010-10-15 16:42:45736 enum Category { // Used in HISTOGRAM_ENUMERATION.
737 RESOLVE_SUCCESS,
738 RESOLVE_FAIL,
739 RESOLVE_SPECULATIVE_SUCCESS,
740 RESOLVE_SPECULATIVE_FAIL,
741 RESOLVE_MAX, // Bounding value.
742 };
743 int category = RESOLVE_MAX; // Illegal value for later DCHECK only.
744
[email protected]189163e2011-05-11 01:48:54745 base::TimeDelta duration = base::TimeTicks::Now() - start_time;
746 if (error == OK) {
[email protected]1e9bbd22010-10-15 16:42:45747 if (had_non_speculative_request_) {
748 category = RESOLVE_SUCCESS;
749 DNS_HISTOGRAM("DNS.ResolveSuccess", duration);
750 } else {
751 category = RESOLVE_SPECULATIVE_SUCCESS;
752 DNS_HISTOGRAM("DNS.ResolveSpeculativeSuccess", duration);
753 }
[email protected]7e96d792011-06-10 17:08:23754
[email protected]78eac2a2012-03-14 19:09:27755 // Log DNS lookups based on |address_family|. This will help us determine
[email protected]7e96d792011-06-10 17:08:23756 // if IPv4 or IPv4/6 lookups are faster or slower.
757 switch(key_.address_family) {
758 case ADDRESS_FAMILY_IPV4:
759 DNS_HISTOGRAM("DNS.ResolveSuccess_FAMILY_IPV4", duration);
760 break;
761 case ADDRESS_FAMILY_IPV6:
762 DNS_HISTOGRAM("DNS.ResolveSuccess_FAMILY_IPV6", duration);
763 break;
764 case ADDRESS_FAMILY_UNSPECIFIED:
765 DNS_HISTOGRAM("DNS.ResolveSuccess_FAMILY_UNSPEC", duration);
766 break;
767 }
[email protected]1e9bbd22010-10-15 16:42:45768 } else {
769 if (had_non_speculative_request_) {
770 category = RESOLVE_FAIL;
771 DNS_HISTOGRAM("DNS.ResolveFail", duration);
772 } else {
773 category = RESOLVE_SPECULATIVE_FAIL;
774 DNS_HISTOGRAM("DNS.ResolveSpeculativeFail", duration);
775 }
[email protected]78eac2a2012-03-14 19:09:27776 // Log DNS lookups based on |address_family|. This will help us determine
[email protected]7e96d792011-06-10 17:08:23777 // if IPv4 or IPv4/6 lookups are faster or slower.
778 switch(key_.address_family) {
779 case ADDRESS_FAMILY_IPV4:
780 DNS_HISTOGRAM("DNS.ResolveFail_FAMILY_IPV4", duration);
781 break;
782 case ADDRESS_FAMILY_IPV6:
783 DNS_HISTOGRAM("DNS.ResolveFail_FAMILY_IPV6", duration);
784 break;
785 case ADDRESS_FAMILY_UNSPECIFIED:
786 DNS_HISTOGRAM("DNS.ResolveFail_FAMILY_UNSPEC", duration);
787 break;
788 }
[email protected]c833e322010-10-16 23:51:36789 UMA_HISTOGRAM_CUSTOM_ENUMERATION(kOSErrorsForGetAddrinfoHistogramName,
[email protected]189163e2011-05-11 01:48:54790 std::abs(os_error),
[email protected]1e9bbd22010-10-15 16:42:45791 GetAllGetAddrinfoOSErrors());
792 }
[email protected]051b6ab2010-10-18 16:50:46793 DCHECK_LT(category, static_cast<int>(RESOLVE_MAX)); // Be sure it was set.
[email protected]1e9bbd22010-10-15 16:42:45794
795 UMA_HISTOGRAM_ENUMERATION("DNS.ResolveCategory", category, RESOLVE_MAX);
796
[email protected]edafd4c2011-05-10 17:18:53797 static const bool show_speculative_experiment_histograms =
798 base::FieldTrialList::TrialExists("DnsImpact");
[email protected]ecd95ae2010-10-20 23:58:17799 if (show_speculative_experiment_histograms) {
[email protected]1e9bbd22010-10-15 16:42:45800 UMA_HISTOGRAM_ENUMERATION(
801 base::FieldTrial::MakeName("DNS.ResolveCategory", "DnsImpact"),
802 category, RESOLVE_MAX);
803 if (RESOLVE_SUCCESS == category) {
804 DNS_HISTOGRAM(base::FieldTrial::MakeName("DNS.ResolveSuccess",
805 "DnsImpact"), duration);
806 }
807 }
[email protected]edafd4c2011-05-10 17:18:53808 static const bool show_parallelism_experiment_histograms =
809 base::FieldTrialList::TrialExists("DnsParallelism");
[email protected]ecd95ae2010-10-20 23:58:17810 if (show_parallelism_experiment_histograms) {
811 UMA_HISTOGRAM_ENUMERATION(
812 base::FieldTrial::MakeName("DNS.ResolveCategory", "DnsParallelism"),
813 category, RESOLVE_MAX);
814 if (RESOLVE_SUCCESS == category) {
815 DNS_HISTOGRAM(base::FieldTrial::MakeName("DNS.ResolveSuccess",
816 "DnsParallelism"), duration);
817 }
818 }
[email protected]1e9bbd22010-10-15 16:42:45819 }
820
[email protected]189163e2011-05-11 01:48:54821 void RecordAttemptHistograms(const base::TimeTicks& start_time,
822 const uint32 attempt_number,
823 const int error,
824 const int os_error) const {
[email protected]0f292de02012-02-01 22:28:20825 DCHECK(origin_loop_->BelongsToCurrentThread());
[email protected]189163e2011-05-11 01:48:54826 bool first_attempt_to_complete =
827 completed_attempt_number_ == attempt_number;
[email protected]e87b8b512011-06-14 22:12:52828 bool is_first_attempt = (attempt_number == 1);
[email protected]1e9bbd22010-10-15 16:42:45829
[email protected]189163e2011-05-11 01:48:54830 if (first_attempt_to_complete) {
831 // If this was first attempt to complete, then record the resolution
832 // status of the attempt.
833 if (completed_attempt_error_ == OK) {
834 UMA_HISTOGRAM_ENUMERATION(
835 "DNS.AttemptFirstSuccess", attempt_number, 100);
836 } else {
837 UMA_HISTOGRAM_ENUMERATION(
838 "DNS.AttemptFirstFailure", attempt_number, 100);
839 }
840 }
841
842 if (error == OK)
843 UMA_HISTOGRAM_ENUMERATION("DNS.AttemptSuccess", attempt_number, 100);
844 else
845 UMA_HISTOGRAM_ENUMERATION("DNS.AttemptFailure", attempt_number, 100);
846
[email protected]e87b8b512011-06-14 22:12:52847 // If first attempt didn't finish before retry attempt, then calculate stats
848 // on how much time is saved by having spawned an extra attempt.
[email protected]0f292de02012-02-01 22:28:20849 if (!first_attempt_to_complete && is_first_attempt && !was_canceled()) {
[email protected]e87b8b512011-06-14 22:12:52850 DNS_HISTOGRAM("DNS.AttemptTimeSavedByRetry",
851 base::TimeTicks::Now() - retry_attempt_finished_time_);
852 }
853
[email protected]0f292de02012-02-01 22:28:20854 if (was_canceled() || !first_attempt_to_complete) {
[email protected]189163e2011-05-11 01:48:54855 // Count those attempts which completed after the job was already canceled
856 // OR after the job was already completed by an earlier attempt (so in
857 // effect).
858 UMA_HISTOGRAM_ENUMERATION("DNS.AttemptDiscarded", attempt_number, 100);
859
[email protected]0f292de02012-02-01 22:28:20860 // Record if job is canceled.
861 if (was_canceled())
[email protected]189163e2011-05-11 01:48:54862 UMA_HISTOGRAM_ENUMERATION("DNS.AttemptCancelled", attempt_number, 100);
863 }
864
865 base::TimeDelta duration = base::TimeTicks::Now() - start_time;
866 if (error == OK)
867 DNS_HISTOGRAM("DNS.AttemptSuccessDuration", duration);
868 else
869 DNS_HISTOGRAM("DNS.AttemptFailDuration", duration);
870 }
[email protected]1e9bbd22010-10-15 16:42:45871
[email protected]b59ff372009-07-15 22:04:32872 // Set on the origin thread, read on the worker thread.
[email protected]123ab1e32009-10-21 19:12:57873 Key key_;
[email protected]b59ff372009-07-15 22:04:32874
[email protected]0f292de02012-02-01 22:28:20875 // Holds an owning reference to the HostResolverProc that we are going to use.
[email protected]b59ff372009-07-15 22:04:32876 // This may not be the current resolver procedure by the time we call
877 // ResolveAddrInfo, but that's OK... we'll use it anyways, and the owning
878 // reference ensures that it remains valid until we are done.
[email protected]0f292de02012-02-01 22:28:20879 ProcTaskParams params_;
[email protected]b59ff372009-07-15 22:04:32880
[email protected]0f292de02012-02-01 22:28:20881 // The listener to the results of this ProcTask.
882 Callback callback_;
883
884 // Used to post ourselves onto the origin thread.
885 scoped_refptr<base::MessageLoopProxy> origin_loop_;
[email protected]189163e2011-05-11 01:48:54886
887 // Keeps track of the number of attempts we have made so far to resolve the
888 // host. Whenever we start an attempt to resolve the host, we increase this
889 // number.
890 uint32 attempt_number_;
891
892 // The index of the attempt which finished first (or 0 if the job is still in
893 // progress).
894 uint32 completed_attempt_number_;
895
896 // The result (a net error code) from the first attempt to complete.
897 int completed_attempt_error_;
[email protected]252b699b2010-02-05 21:38:06898
[email protected]e87b8b512011-06-14 22:12:52899 // The time when retry attempt was finished.
900 base::TimeTicks retry_attempt_finished_time_;
901
[email protected]252b699b2010-02-05 21:38:06902 // True if a non-speculative request was ever attached to this job
[email protected]0f292de02012-02-01 22:28:20903 // (regardless of whether or not it was later canceled.
[email protected]252b699b2010-02-05 21:38:06904 // This boolean is used for histogramming the duration of jobs used to
905 // service non-speculative requests.
906 bool had_non_speculative_request_;
907
[email protected]b59ff372009-07-15 22:04:32908 AddressList results_;
909
[email protected]ee094b82010-08-24 15:55:51910 BoundNetLog net_log_;
911
[email protected]0f292de02012-02-01 22:28:20912 DISALLOW_COPY_AND_ASSIGN(ProcTask);
[email protected]b59ff372009-07-15 22:04:32913};
914
915//-----------------------------------------------------------------------------
916
[email protected]0f292de02012-02-01 22:28:20917// Represents a request to the worker pool for a "probe for IPv6 support" call.
[email protected]b3601bc22012-02-21 21:23:20918//
919// TODO(szym): This could also be replaced with PostTaskAndReply and Callbacks.
[email protected]0f8f1b432010-03-16 19:06:03920class HostResolverImpl::IPv6ProbeJob
921 : public base::RefCountedThreadSafe<HostResolverImpl::IPv6ProbeJob> {
922 public:
923 explicit IPv6ProbeJob(HostResolverImpl* resolver)
924 : resolver_(resolver),
[email protected]edd685f2011-08-15 20:33:46925 origin_loop_(base::MessageLoopProxy::current()) {
[email protected]3e9d9cc2011-05-03 21:08:15926 DCHECK(resolver);
[email protected]0f8f1b432010-03-16 19:06:03927 }
928
929 void Start() {
[email protected]3e9d9cc2011-05-03 21:08:15930 DCHECK(origin_loop_->BelongsToCurrentThread());
[email protected]0f292de02012-02-01 22:28:20931 if (was_canceled())
[email protected]a9af7112010-05-08 00:56:01932 return;
[email protected]f092e64b2010-03-17 00:39:18933 const bool kIsSlow = true;
[email protected]ac9ba8fe2010-12-30 18:08:36934 base::WorkerPool::PostTask(
[email protected]33152acc2011-10-20 23:37:12935 FROM_HERE, base::Bind(&IPv6ProbeJob::DoProbe, this), kIsSlow);
[email protected]0f8f1b432010-03-16 19:06:03936 }
937
938 // Cancels the current job.
939 void Cancel() {
[email protected]3e9d9cc2011-05-03 21:08:15940 DCHECK(origin_loop_->BelongsToCurrentThread());
[email protected]0f292de02012-02-01 22:28:20941 if (was_canceled())
[email protected]a9af7112010-05-08 00:56:01942 return;
[email protected]0f8f1b432010-03-16 19:06:03943 resolver_ = NULL; // Read/write ONLY on origin thread.
[email protected]0f8f1b432010-03-16 19:06:03944 }
945
[email protected]0f8f1b432010-03-16 19:06:03946 private:
947 friend class base::RefCountedThreadSafe<HostResolverImpl::IPv6ProbeJob>;
948
949 ~IPv6ProbeJob() {
950 }
951
[email protected]0f292de02012-02-01 22:28:20952 bool was_canceled() const {
[email protected]3e9d9cc2011-05-03 21:08:15953 DCHECK(origin_loop_->BelongsToCurrentThread());
954 return !resolver_;
[email protected]a9af7112010-05-08 00:56:01955 }
956
[email protected]0f8f1b432010-03-16 19:06:03957 // Run on worker thread.
958 void DoProbe() {
959 // Do actual testing on this thread, as it takes 40-100ms.
960 AddressFamily family = IPv6Supported() ? ADDRESS_FAMILY_UNSPECIFIED
961 : ADDRESS_FAMILY_IPV4;
962
[email protected]3e9d9cc2011-05-03 21:08:15963 origin_loop_->PostTask(
964 FROM_HERE,
[email protected]33152acc2011-10-20 23:37:12965 base::Bind(&IPv6ProbeJob::OnProbeComplete, this, family));
[email protected]0f8f1b432010-03-16 19:06:03966 }
967
[email protected]3e9d9cc2011-05-03 21:08:15968 // Callback for when DoProbe() completes.
[email protected]0f8f1b432010-03-16 19:06:03969 void OnProbeComplete(AddressFamily address_family) {
[email protected]3e9d9cc2011-05-03 21:08:15970 DCHECK(origin_loop_->BelongsToCurrentThread());
[email protected]0f292de02012-02-01 22:28:20971 if (was_canceled())
[email protected]a9af7112010-05-08 00:56:01972 return;
[email protected]a9af7112010-05-08 00:56:01973 resolver_->IPv6ProbeSetDefaultAddressFamily(address_family);
[email protected]0f8f1b432010-03-16 19:06:03974 }
975
[email protected]0f8f1b432010-03-16 19:06:03976 // Used/set only on origin thread.
977 HostResolverImpl* resolver_;
978
979 // Used to post ourselves onto the origin thread.
[email protected]3e9d9cc2011-05-03 21:08:15980 scoped_refptr<base::MessageLoopProxy> origin_loop_;
[email protected]0f8f1b432010-03-16 19:06:03981
982 DISALLOW_COPY_AND_ASSIGN(IPv6ProbeJob);
983};
984
985//-----------------------------------------------------------------------------
986
[email protected]b3601bc22012-02-21 21:23:20987// Resolves the hostname using DnsTransaction.
988// TODO(szym): This could be moved to separate source file as well.
989class HostResolverImpl::DnsTask {
990 public:
991 typedef base::Callback<void(int net_error,
992 const AddressList& addr_list,
993 base::TimeDelta ttl)> Callback;
994
995 DnsTask(DnsTransactionFactory* factory,
996 const Key& key,
997 const Callback& callback,
998 const BoundNetLog& job_net_log)
999 : callback_(callback), net_log_(job_net_log) {
1000 DCHECK(factory);
1001 DCHECK(!callback.is_null());
1002
1003 // For now we treat ADDRESS_FAMILY_UNSPEC as if it was IPV4.
1004 uint16 qtype = (key.address_family == ADDRESS_FAMILY_IPV6)
1005 ? dns_protocol::kTypeAAAA
1006 : dns_protocol::kTypeA;
1007 // TODO(szym): Implement "happy eyeballs".
1008 transaction_ = factory->CreateTransaction(
1009 key.hostname,
1010 qtype,
[email protected]1def74c2012-03-22 20:07:001011 base::Bind(&DnsTask::OnTransactionComplete, base::Unretained(this),
1012 base::TimeTicks::Now()),
[email protected]b3601bc22012-02-21 21:23:201013 net_log_);
1014 DCHECK(transaction_.get());
1015 }
1016
1017 int Start() {
[email protected]4da911f2012-06-14 19:45:201018 net_log_.BeginEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_DNS_TASK);
[email protected]b3601bc22012-02-21 21:23:201019 return transaction_->Start();
1020 }
1021
[email protected]1def74c2012-03-22 20:07:001022 void OnTransactionComplete(const base::TimeTicks& start_time,
1023 DnsTransaction* transaction,
[email protected]b3601bc22012-02-21 21:23:201024 int net_error,
1025 const DnsResponse* response) {
[email protected]add76532012-03-30 14:47:471026 DCHECK(transaction);
[email protected]b3601bc22012-02-21 21:23:201027 // Run |callback_| last since the owning Job will then delete this DnsTask.
1028 DnsResponse::Result result = DnsResponse::DNS_SUCCESS;
1029 if (net_error == OK) {
[email protected]add76532012-03-30 14:47:471030 CHECK(response);
[email protected]1def74c2012-03-22 20:07:001031 DNS_HISTOGRAM("AsyncDNS.TransactionSuccess",
1032 base::TimeTicks::Now() - start_time);
[email protected]b3601bc22012-02-21 21:23:201033 AddressList addr_list;
1034 base::TimeDelta ttl;
1035 result = response->ParseToAddressList(&addr_list, &ttl);
[email protected]1def74c2012-03-22 20:07:001036 UMA_HISTOGRAM_ENUMERATION("AsyncDNS.ParseToAddressList",
1037 result,
1038 DnsResponse::DNS_PARSE_RESULT_MAX);
[email protected]b3601bc22012-02-21 21:23:201039 if (result == DnsResponse::DNS_SUCCESS) {
1040 net_log_.EndEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_DNS_TASK,
[email protected]cd565142012-06-12 16:21:451041 addr_list.CreateNetLogCallback());
[email protected]b3601bc22012-02-21 21:23:201042 callback_.Run(net_error, addr_list, ttl);
1043 return;
1044 }
1045 net_error = ERR_DNS_MALFORMED_RESPONSE;
[email protected]1def74c2012-03-22 20:07:001046 } else {
1047 DNS_HISTOGRAM("AsyncDNS.TransactionFailure",
1048 base::TimeTicks::Now() - start_time);
[email protected]b3601bc22012-02-21 21:23:201049 }
[email protected]cd565142012-06-12 16:21:451050 net_log_.EndEvent(
1051 NetLog::TYPE_HOST_RESOLVER_IMPL_DNS_TASK,
1052 base::Bind(&NetLogDnsTaskFailedCallback, net_error, result));
[email protected]b3601bc22012-02-21 21:23:201053 callback_.Run(net_error, AddressList(), base::TimeDelta());
1054 }
1055
1056 private:
1057 // The listener to the results of this DnsTask.
1058 Callback callback_;
1059
1060 const BoundNetLog net_log_;
1061
1062 scoped_ptr<DnsTransaction> transaction_;
1063};
1064
1065//-----------------------------------------------------------------------------
1066
[email protected]0f292de02012-02-01 22:28:201067// Aggregates all Requests for the same Key. Dispatched via PriorityDispatch.
[email protected]0f292de02012-02-01 22:28:201068class HostResolverImpl::Job : public PrioritizedDispatcher::Job {
[email protected]68ad3ee2010-01-30 03:45:391069 public:
[email protected]0f292de02012-02-01 22:28:201070 // Creates new job for |key| where |request_net_log| is bound to the
[email protected]16ee26d2012-03-08 03:34:351071 // request that spawned it.
[email protected]0f292de02012-02-01 22:28:201072 Job(HostResolverImpl* resolver,
1073 const Key& key,
[email protected]16ee26d2012-03-08 03:34:351074 const BoundNetLog& request_net_log)
[email protected]0f292de02012-02-01 22:28:201075 : resolver_(resolver->AsWeakPtr()),
1076 key_(key),
1077 had_non_speculative_request_(false),
[email protected]1d932852012-06-19 19:40:331078 dns_task_error_(OK),
[email protected]0f292de02012-02-01 22:28:201079 net_log_(BoundNetLog::Make(request_net_log.net_log(),
[email protected]b3601bc22012-02-21 21:23:201080 NetLog::SOURCE_HOST_RESOLVER_IMPL_JOB)) {
[email protected]4da911f2012-06-14 19:45:201081 request_net_log.AddEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_CREATE_JOB);
[email protected]0f292de02012-02-01 22:28:201082
1083 net_log_.BeginEvent(
1084 NetLog::TYPE_HOST_RESOLVER_IMPL_JOB,
[email protected]cd565142012-06-12 16:21:451085 base::Bind(&NetLogJobCreationCallback,
1086 request_net_log.source(),
1087 &key_.hostname));
[email protected]68ad3ee2010-01-30 03:45:391088 }
1089
[email protected]0f292de02012-02-01 22:28:201090 virtual ~Job() {
[email protected]b3601bc22012-02-21 21:23:201091 if (is_running()) {
1092 // |resolver_| was destroyed with this Job still in flight.
1093 // Clean-up, record in the log, but don't run any callbacks.
1094 if (is_proc_running()) {
[email protected]0f292de02012-02-01 22:28:201095 proc_task_->Cancel();
1096 proc_task_ = NULL;
[email protected]0f292de02012-02-01 22:28:201097 }
[email protected]16ee26d2012-03-08 03:34:351098 // Clean up now for nice NetLog.
1099 dns_task_.reset(NULL);
[email protected]b3601bc22012-02-21 21:23:201100 net_log_.EndEventWithNetErrorCode(NetLog::TYPE_HOST_RESOLVER_IMPL_JOB,
1101 ERR_ABORTED);
1102 } else if (is_queued()) {
[email protected]57a48d32012-03-03 00:04:551103 // |resolver_| was destroyed without running this Job.
[email protected]16ee26d2012-03-08 03:34:351104 // TODO(szym): is there any benefit in having this distinction?
[email protected]4da911f2012-06-14 19:45:201105 net_log_.AddEvent(NetLog::TYPE_CANCELLED);
1106 net_log_.EndEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_JOB);
[email protected]68ad3ee2010-01-30 03:45:391107 }
[email protected]b3601bc22012-02-21 21:23:201108 // else CompleteRequests logged EndEvent.
[email protected]68ad3ee2010-01-30 03:45:391109
[email protected]b3601bc22012-02-21 21:23:201110 // Log any remaining Requests as cancelled.
1111 for (RequestsList::const_iterator it = requests_.begin();
1112 it != requests_.end(); ++it) {
1113 Request* req = *it;
1114 if (req->was_canceled())
1115 continue;
1116 DCHECK_EQ(this, req->job());
1117 LogCancelRequest(req->source_net_log(), req->request_net_log(),
1118 req->info());
1119 }
[email protected]68ad3ee2010-01-30 03:45:391120 }
1121
[email protected]16ee26d2012-03-08 03:34:351122 // Add this job to the dispatcher.
1123 void Schedule(RequestPriority priority) {
1124 handle_ = resolver_->dispatcher_.Add(this, priority);
1125 }
1126
[email protected]b3601bc22012-02-21 21:23:201127 void AddRequest(scoped_ptr<Request> req) {
[email protected]0f292de02012-02-01 22:28:201128 DCHECK_EQ(key_.hostname, req->info().hostname());
1129
1130 req->set_job(this);
[email protected]0f292de02012-02-01 22:28:201131 priority_tracker_.Add(req->info().priority());
1132
1133 req->request_net_log().AddEvent(
1134 NetLog::TYPE_HOST_RESOLVER_IMPL_JOB_ATTACH,
[email protected]cd565142012-06-12 16:21:451135 net_log_.source().ToEventParametersCallback());
[email protected]0f292de02012-02-01 22:28:201136
1137 net_log_.AddEvent(
1138 NetLog::TYPE_HOST_RESOLVER_IMPL_JOB_REQUEST_ATTACH,
[email protected]cd565142012-06-12 16:21:451139 base::Bind(&NetLogJobAttachCallback,
1140 req->request_net_log().source(),
1141 priority()));
[email protected]0f292de02012-02-01 22:28:201142
1143 // TODO(szym): Check if this is still needed.
1144 if (!req->info().is_speculative()) {
1145 had_non_speculative_request_ = true;
1146 if (proc_task_)
1147 proc_task_->set_had_non_speculative_request();
[email protected]68ad3ee2010-01-30 03:45:391148 }
[email protected]b3601bc22012-02-21 21:23:201149
1150 requests_.push_back(req.release());
1151
[email protected]16ee26d2012-03-08 03:34:351152 if (is_queued())
[email protected]b3601bc22012-02-21 21:23:201153 handle_ = resolver_->dispatcher_.ChangePriority(handle_, priority());
[email protected]68ad3ee2010-01-30 03:45:391154 }
1155
[email protected]16ee26d2012-03-08 03:34:351156 // Marks |req| as cancelled. If it was the last active Request, also finishes
1157 // this Job marking it either as aborted or cancelled, and deletes it.
[email protected]0f292de02012-02-01 22:28:201158 void CancelRequest(Request* req) {
1159 DCHECK_EQ(key_.hostname, req->info().hostname());
1160 DCHECK(!req->was_canceled());
[email protected]16ee26d2012-03-08 03:34:351161
[email protected]0f292de02012-02-01 22:28:201162 // Don't remove it from |requests_| just mark it canceled.
1163 req->MarkAsCanceled();
1164 LogCancelRequest(req->source_net_log(), req->request_net_log(),
1165 req->info());
[email protected]16ee26d2012-03-08 03:34:351166
[email protected]0f292de02012-02-01 22:28:201167 priority_tracker_.Remove(req->info().priority());
1168 net_log_.AddEvent(
1169 NetLog::TYPE_HOST_RESOLVER_IMPL_JOB_REQUEST_DETACH,
[email protected]cd565142012-06-12 16:21:451170 base::Bind(&NetLogJobAttachCallback,
1171 req->request_net_log().source(),
1172 priority()));
[email protected]b3601bc22012-02-21 21:23:201173
[email protected]16ee26d2012-03-08 03:34:351174 if (num_active_requests() > 0) {
1175 if (is_queued())
[email protected]b3601bc22012-02-21 21:23:201176 handle_ = resolver_->dispatcher_.ChangePriority(handle_, priority());
[email protected]16ee26d2012-03-08 03:34:351177 } else {
1178 // If we were called from a Request's callback within CompleteRequests,
1179 // that Request could not have been cancelled, so num_active_requests()
1180 // could not be 0. Therefore, we are not in CompleteRequests().
1181 CompleteRequests(OK, AddressList(), base::TimeDelta());
[email protected]b3601bc22012-02-21 21:23:201182 }
[email protected]68ad3ee2010-01-30 03:45:391183 }
1184
[email protected]16ee26d2012-03-08 03:34:351185 // Called from AbortAllInProgressJobs. Completes all requests as aborted
1186 // and destroys the job.
[email protected]0f292de02012-02-01 22:28:201187 void Abort() {
[email protected]0f292de02012-02-01 22:28:201188 DCHECK(is_running());
[email protected]b3601bc22012-02-21 21:23:201189 CompleteRequests(ERR_ABORTED, AddressList(), base::TimeDelta());
1190 }
1191
[email protected]16ee26d2012-03-08 03:34:351192 // Called by HostResolverImpl when this job is evicted due to queue overflow.
1193 // Completes all requests and destroys the job.
1194 void OnEvicted() {
1195 DCHECK(!is_running());
1196 DCHECK(is_queued());
1197 handle_.Reset();
1198
[email protected]4da911f2012-06-14 19:45:201199 net_log_.AddEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_JOB_EVICTED);
[email protected]16ee26d2012-03-08 03:34:351200
1201 // This signals to CompleteRequests that this job never ran.
1202 CompleteRequests(ERR_HOST_RESOLVER_QUEUE_TOO_LARGE,
1203 AddressList(),
1204 base::TimeDelta());
1205 }
1206
[email protected]78eac2a2012-03-14 19:09:271207 // Attempts to serve the job from HOSTS. Returns true if succeeded and
1208 // this Job was destroyed.
1209 bool ServeFromHosts() {
1210 DCHECK_GT(num_active_requests(), 0u);
1211 AddressList addr_list;
1212 if (resolver_->ServeFromHosts(key(),
[email protected]c143d892012-04-06 07:56:541213 requests_->front()->info(),
[email protected]78eac2a2012-03-14 19:09:271214 &addr_list)) {
1215 // This will destroy the Job.
1216 CompleteRequests(OK, addr_list, base::TimeDelta());
1217 return true;
1218 }
1219 return false;
1220 }
1221
[email protected]b4481b222012-03-16 17:13:111222 const Key key() const {
1223 return key_;
1224 }
1225
1226 bool is_queued() const {
1227 return !handle_.is_null();
1228 }
1229
1230 bool is_running() const {
1231 return is_dns_running() || is_proc_running();
1232 }
1233
[email protected]16ee26d2012-03-08 03:34:351234 private:
[email protected]16ee26d2012-03-08 03:34:351235 // PriorityDispatch::Job:
[email protected]0f292de02012-02-01 22:28:201236 virtual void Start() OVERRIDE {
1237 DCHECK(!is_running());
[email protected]b3601bc22012-02-21 21:23:201238 handle_.Reset();
[email protected]0f292de02012-02-01 22:28:201239
[email protected]4da911f2012-06-14 19:45:201240 net_log_.AddEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_JOB_STARTED);
[email protected]0f292de02012-02-01 22:28:201241
[email protected]1d932852012-06-19 19:40:331242 // Caution: Job::Start must not complete synchronously.
1243 if (resolver_->HaveDnsConfig() &&
1244 !ResemblesMulticastDNSName(key_.hostname)) {
[email protected]b3601bc22012-02-21 21:23:201245 StartDnsTask();
1246 } else {
1247 StartProcTask();
1248 }
1249 }
1250
[email protected]b3601bc22012-02-21 21:23:201251 // TODO(szym): Since DnsTransaction does not consume threads, we can increase
1252 // the limits on |dispatcher_|. But in order to keep the number of WorkerPool
1253 // threads low, we will need to use an "inner" PrioritizedDispatcher with
1254 // tighter limits.
1255 void StartProcTask() {
[email protected]16ee26d2012-03-08 03:34:351256 DCHECK(!is_dns_running());
[email protected]0f292de02012-02-01 22:28:201257 proc_task_ = new ProcTask(
1258 key_,
1259 resolver_->proc_params_,
1260 base::Bind(&Job::OnProcTaskComplete, base::Unretained(this)),
1261 net_log_);
1262
1263 if (had_non_speculative_request_)
1264 proc_task_->set_had_non_speculative_request();
1265 // Start() could be called from within Resolve(), hence it must NOT directly
1266 // call OnProcTaskComplete, for example, on synchronous failure.
1267 proc_task_->Start();
[email protected]68ad3ee2010-01-30 03:45:391268 }
1269
[email protected]0f292de02012-02-01 22:28:201270 // Called by ProcTask when it completes.
[email protected]b3601bc22012-02-21 21:23:201271 void OnProcTaskComplete(int net_error, const AddressList& addr_list) {
1272 DCHECK(is_proc_running());
[email protected]68ad3ee2010-01-30 03:45:391273
[email protected]1d932852012-06-19 19:40:331274 if (dns_task_error_ != OK) {
[email protected]1def74c2012-03-22 20:07:001275 if (net_error == OK) {
[email protected]1d932852012-06-19 19:40:331276 if ((dns_task_error_ == ERR_NAME_NOT_RESOLVED) &&
1277 ResemblesNetBIOSName(key_.hostname)) {
1278 UmaAsyncDnsResolveStatus(RESOLVE_STATUS_SUSPECT_NETBIOS);
1279 } else {
1280 UmaAsyncDnsResolveStatus(RESOLVE_STATUS_PROC_SUCCESS);
1281 }
1282 UMA_HISTOGRAM_CUSTOM_ENUMERATION("AsyncDNS.ResolveError",
1283 std::abs(dns_task_error_),
1284 GetAllErrorCodesForUma());
[email protected]1def74c2012-03-22 20:07:001285 } else {
1286 UmaAsyncDnsResolveStatus(RESOLVE_STATUS_FAIL);
1287 }
1288 }
1289
[email protected]b3601bc22012-02-21 21:23:201290 base::TimeDelta ttl = base::TimeDelta::FromSeconds(
1291 kNegativeCacheEntryTTLSeconds);
1292 if (net_error == OK)
1293 ttl = base::TimeDelta::FromSeconds(kCacheEntryTTLSeconds);
[email protected]68ad3ee2010-01-30 03:45:391294
[email protected]16ee26d2012-03-08 03:34:351295 CompleteRequests(net_error, addr_list, ttl);
[email protected]b3601bc22012-02-21 21:23:201296 }
1297
1298 void StartDnsTask() {
[email protected]78eac2a2012-03-14 19:09:271299 DCHECK(resolver_->HaveDnsConfig());
[email protected]b3601bc22012-02-21 21:23:201300 dns_task_.reset(new DnsTask(
[email protected]78eac2a2012-03-14 19:09:271301 resolver_->dns_client_->GetTransactionFactory(),
[email protected]b3601bc22012-02-21 21:23:201302 key_,
1303 base::Bind(&Job::OnDnsTaskComplete, base::Unretained(this)),
1304 net_log_));
1305
1306 int rv = dns_task_->Start();
1307 if (rv != ERR_IO_PENDING) {
1308 DCHECK_NE(OK, rv);
1309 dns_task_.reset();
1310 StartProcTask();
1311 }
1312 }
1313
1314 // Called by DnsTask when it completes.
1315 void OnDnsTaskComplete(int net_error,
1316 const AddressList& addr_list,
1317 base::TimeDelta ttl) {
1318 DCHECK(is_dns_running());
[email protected]b3601bc22012-02-21 21:23:201319
1320 if (net_error != OK) {
[email protected]1d932852012-06-19 19:40:331321 dns_task_error_ = net_error;
[email protected]16ee26d2012-03-08 03:34:351322 dns_task_.reset();
[email protected]78eac2a2012-03-14 19:09:271323
1324 // TODO(szym): Run ServeFromHosts now if nsswitch.conf says so.
1325 // http://crbug.com/117655
1326
[email protected]b3601bc22012-02-21 21:23:201327 // TODO(szym): Some net errors indicate lack of connectivity. Starting
1328 // ProcTask in that case is a waste of time.
1329 StartProcTask();
1330 return;
1331 }
1332
[email protected]1def74c2012-03-22 20:07:001333 UmaAsyncDnsResolveStatus(RESOLVE_STATUS_DNS_SUCCESS);
[email protected]16ee26d2012-03-08 03:34:351334 CompleteRequests(net_error, addr_list, ttl);
[email protected]b3601bc22012-02-21 21:23:201335 }
1336
[email protected]16ee26d2012-03-08 03:34:351337 // Performs Job's last rites. Completes all Requests. Deletes this.
[email protected]b3601bc22012-02-21 21:23:201338 void CompleteRequests(int net_error,
1339 const AddressList& addr_list,
1340 base::TimeDelta ttl) {
1341 CHECK(resolver_);
[email protected]b3601bc22012-02-21 21:23:201342
[email protected]16ee26d2012-03-08 03:34:351343 // This job must be removed from resolver's |jobs_| now to make room for a
1344 // new job with the same key in case one of the OnComplete callbacks decides
1345 // to spawn one. Consequently, the job deletes itself when CompleteRequests
1346 // is done.
1347 scoped_ptr<Job> self_deleter(this);
1348
1349 resolver_->RemoveJob(this);
1350
1351 // |addr_list| will be destroyed once we destroy |proc_task_| and
1352 // |dns_task_|.
[email protected]b3601bc22012-02-21 21:23:201353 AddressList list = addr_list;
[email protected]16ee26d2012-03-08 03:34:351354
1355 if (is_running()) {
1356 DCHECK(!is_queued());
1357 if (is_proc_running()) {
1358 proc_task_->Cancel();
1359 proc_task_ = NULL;
1360 }
1361 dns_task_.reset();
1362
1363 // Signal dispatcher that a slot has opened.
1364 resolver_->dispatcher_.OnJobFinished();
1365 } else if (is_queued()) {
1366 resolver_->dispatcher_.Cancel(handle_);
1367 handle_.Reset();
1368 }
1369
1370 if (num_active_requests() == 0) {
[email protected]4da911f2012-06-14 19:45:201371 net_log_.AddEvent(NetLog::TYPE_CANCELLED);
[email protected]16ee26d2012-03-08 03:34:351372 net_log_.EndEventWithNetErrorCode(NetLog::TYPE_HOST_RESOLVER_IMPL_JOB,
1373 OK);
1374 return;
1375 }
[email protected]b3601bc22012-02-21 21:23:201376
1377 net_log_.EndEventWithNetErrorCode(NetLog::TYPE_HOST_RESOLVER_IMPL_JOB,
1378 net_error);
[email protected]68ad3ee2010-01-30 03:45:391379
[email protected]78eac2a2012-03-14 19:09:271380 DCHECK(!requests_.empty());
1381
[email protected]d7b9a2b2012-05-31 22:31:191382 if (net_error == OK) {
[email protected]7054e78f2012-05-07 21:44:561383 SetPortOnAddressList(requests_->front()->info().port(), &list);
[email protected]d7b9a2b2012-05-31 22:31:191384 // Record this histogram here, when we know the system has a valid DNS
1385 // configuration.
1386 UMA_HISTOGRAM_ENUMERATION("AsyncDNS.HaveDnsConfig",
1387 resolver_->received_dns_config_ ? 1 : 0,
1388 2);
1389 }
[email protected]16ee26d2012-03-08 03:34:351390
1391 if ((net_error != ERR_ABORTED) &&
1392 (net_error != ERR_HOST_RESOLVER_QUEUE_TOO_LARGE)) {
1393 resolver_->CacheResult(key_, net_error, list, ttl);
1394 }
1395
[email protected]0f292de02012-02-01 22:28:201396 // Complete all of the requests that were attached to the job.
1397 for (RequestsList::const_iterator it = requests_.begin();
1398 it != requests_.end(); ++it) {
1399 Request* req = *it;
1400
1401 if (req->was_canceled())
1402 continue;
1403
1404 DCHECK_EQ(this, req->job());
1405 // Update the net log and notify registered observers.
1406 LogFinishRequest(req->source_net_log(), req->request_net_log(),
[email protected]b3601bc22012-02-21 21:23:201407 req->info(), net_error);
[email protected]0f292de02012-02-01 22:28:201408
[email protected]b3601bc22012-02-21 21:23:201409 req->OnComplete(net_error, list);
[email protected]0f292de02012-02-01 22:28:201410
1411 // Check if the resolver was destroyed as a result of running the
1412 // callback. If it was, we could continue, but we choose to bail.
1413 if (!resolver_)
1414 return;
1415 }
1416 }
1417
[email protected]b4481b222012-03-16 17:13:111418 RequestPriority priority() const {
1419 return priority_tracker_.highest_priority();
1420 }
1421
1422 // Number of non-canceled requests in |requests_|.
1423 size_t num_active_requests() const {
1424 return priority_tracker_.total_count();
1425 }
1426
1427 bool is_dns_running() const {
1428 return dns_task_.get() != NULL;
1429 }
1430
1431 bool is_proc_running() const {
1432 return proc_task_.get() != NULL;
1433 }
1434
[email protected]0f292de02012-02-01 22:28:201435 base::WeakPtr<HostResolverImpl> resolver_;
1436
1437 Key key_;
1438
1439 // Tracks the highest priority across |requests_|.
1440 PriorityTracker priority_tracker_;
1441
1442 bool had_non_speculative_request_;
1443
[email protected]1d932852012-06-19 19:40:331444 // Result of DnsTask.
1445 int dns_task_error_;
[email protected]1def74c2012-03-22 20:07:001446
[email protected]0f292de02012-02-01 22:28:201447 BoundNetLog net_log_;
1448
[email protected]b3601bc22012-02-21 21:23:201449 // Resolves the host using a HostResolverProc.
[email protected]0f292de02012-02-01 22:28:201450 scoped_refptr<ProcTask> proc_task_;
1451
[email protected]b3601bc22012-02-21 21:23:201452 // Resolves the host using a DnsTransaction.
1453 scoped_ptr<DnsTask> dns_task_;
1454
[email protected]0f292de02012-02-01 22:28:201455 // All Requests waiting for the result of this Job. Some can be canceled.
1456 RequestsList requests_;
1457
[email protected]16ee26d2012-03-08 03:34:351458 // A handle used in |HostResolverImpl::dispatcher_|.
[email protected]0f292de02012-02-01 22:28:201459 PrioritizedDispatcher::Handle handle_;
[email protected]68ad3ee2010-01-30 03:45:391460};
1461
1462//-----------------------------------------------------------------------------
1463
[email protected]0f292de02012-02-01 22:28:201464HostResolverImpl::ProcTaskParams::ProcTaskParams(
[email protected]e95d3aca2010-01-11 22:47:431465 HostResolverProc* resolver_proc,
[email protected]0f292de02012-02-01 22:28:201466 size_t max_retry_attempts)
1467 : resolver_proc(resolver_proc),
1468 max_retry_attempts(max_retry_attempts),
1469 unresponsive_delay(base::TimeDelta::FromMilliseconds(6000)),
1470 retry_factor(2) {
1471}
1472
1473HostResolverImpl::ProcTaskParams::~ProcTaskParams() {}
1474
1475HostResolverImpl::HostResolverImpl(
[email protected]e95d3aca2010-01-11 22:47:431476 HostCache* cache,
[email protected]0f292de02012-02-01 22:28:201477 const PrioritizedDispatcher::Limits& job_limits,
1478 const ProcTaskParams& proc_params,
[email protected]b3601bc22012-02-21 21:23:201479 scoped_ptr<DnsConfigService> dns_config_service,
[email protected]d7b9a2b2012-05-31 22:31:191480 scoped_ptr<DnsClient> dns_client,
[email protected]ee094b82010-08-24 15:55:511481 NetLog* net_log)
[email protected]112bd462009-12-10 07:23:401482 : cache_(cache),
[email protected]0f292de02012-02-01 22:28:201483 dispatcher_(job_limits),
1484 max_queued_jobs_(job_limits.total_jobs * 100u),
1485 proc_params_(proc_params),
[email protected]0c7798452009-10-26 17:59:511486 default_address_family_(ADDRESS_FAMILY_UNSPECIFIED),
[email protected]b3601bc22012-02-21 21:23:201487 dns_config_service_(dns_config_service.Pass()),
[email protected]d7b9a2b2012-05-31 22:31:191488 dns_client_(dns_client.Pass()),
1489 received_dns_config_(false),
[email protected]2f3bc65c2010-07-23 17:47:101490 ipv6_probe_monitoring_(false),
[email protected]ee094b82010-08-24 15:55:511491 additional_resolver_flags_(0),
1492 net_log_(net_log) {
[email protected]0f292de02012-02-01 22:28:201493
1494 DCHECK_GE(dispatcher_.num_priorities(), static_cast<size_t>(NUM_PRIORITIES));
[email protected]68ad3ee2010-01-30 03:45:391495
[email protected]06ef6d92011-05-19 04:24:581496 // Maximum of 4 retry attempts for host resolution.
1497 static const size_t kDefaultMaxRetryAttempts = 4u;
1498
[email protected]0f292de02012-02-01 22:28:201499 if (proc_params_.max_retry_attempts == HostResolver::kDefaultRetryAttempts)
1500 proc_params_.max_retry_attempts = kDefaultMaxRetryAttempts;
[email protected]68ad3ee2010-01-30 03:45:391501
[email protected]b59ff372009-07-15 22:04:321502#if defined(OS_WIN)
1503 EnsureWinsockInit();
1504#endif
[email protected]23f771162011-06-02 18:37:511505#if defined(OS_POSIX) && !defined(OS_MACOSX)
[email protected]2f3bc65c2010-07-23 17:47:101506 if (HaveOnlyLoopbackAddresses())
1507 additional_resolver_flags_ |= HOST_RESOLVER_LOOPBACK_ONLY;
1508#endif
[email protected]232a5812011-03-04 22:42:081509 NetworkChangeNotifier::AddIPAddressObserver(this);
[email protected]d7b9a2b2012-05-31 22:31:191510#if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_OPENBSD) && \
1511 !defined(OS_ANDROID)
[email protected]46018c9d2011-09-06 03:42:341512 NetworkChangeNotifier::AddDNSObserver(this);
[email protected]d7b9a2b2012-05-31 22:31:191513 EnsureDnsReloaderInit();
[email protected]46018c9d2011-09-06 03:42:341514#endif
[email protected]b3601bc22012-02-21 21:23:201515
[email protected]78eac2a2012-03-14 19:09:271516 if (dns_config_service_.get()) {
[email protected]b4481b222012-03-16 17:13:111517 dns_config_service_->Watch(
1518 base::Bind(&HostResolverImpl::OnDnsConfigChanged,
1519 base::Unretained(this)));
[email protected]78eac2a2012-03-14 19:09:271520 }
[email protected]b59ff372009-07-15 22:04:321521}
1522
1523HostResolverImpl::~HostResolverImpl() {
[email protected]0f8f1b432010-03-16 19:06:031524 DiscardIPv6ProbeJob();
1525
[email protected]0f292de02012-02-01 22:28:201526 // This will also cancel all outstanding requests.
1527 STLDeleteValues(&jobs_);
[email protected]e95d3aca2010-01-11 22:47:431528
[email protected]232a5812011-03-04 22:42:081529 NetworkChangeNotifier::RemoveIPAddressObserver(this);
[email protected]46018c9d2011-09-06 03:42:341530 NetworkChangeNotifier::RemoveDNSObserver(this);
[email protected]b59ff372009-07-15 22:04:321531}
1532
[email protected]0f292de02012-02-01 22:28:201533void HostResolverImpl::SetMaxQueuedJobs(size_t value) {
1534 DCHECK_EQ(0u, dispatcher_.num_queued_jobs());
1535 DCHECK_GT(value, 0u);
1536 max_queued_jobs_ = value;
[email protected]be1a48b2011-01-20 00:12:131537}
1538
[email protected]684970b2009-08-14 04:54:461539int HostResolverImpl::Resolve(const RequestInfo& info,
[email protected]b59ff372009-07-15 22:04:321540 AddressList* addresses,
[email protected]aa22b242011-11-16 18:58:291541 const CompletionCallback& callback,
[email protected]684970b2009-08-14 04:54:461542 RequestHandle* out_req,
[email protected]ee094b82010-08-24 15:55:511543 const BoundNetLog& source_net_log) {
[email protected]95a214c2011-08-04 21:50:401544 DCHECK(addresses);
[email protected]1ac6af92010-06-03 21:00:141545 DCHECK(CalledOnValidThread());
[email protected]aa22b242011-11-16 18:58:291546 DCHECK_EQ(false, callback.is_null());
[email protected]1ac6af92010-06-03 21:00:141547
[email protected]ee094b82010-08-24 15:55:511548 // Make a log item for the request.
1549 BoundNetLog request_net_log = BoundNetLog::Make(net_log_,
1550 NetLog::SOURCE_HOST_RESOLVER_IMPL_REQUEST);
1551
[email protected]0f292de02012-02-01 22:28:201552 LogStartRequest(source_net_log, request_net_log, info);
[email protected]b59ff372009-07-15 22:04:321553
[email protected]123ab1e32009-10-21 19:12:571554 // Build a key that identifies the request in the cache and in the
1555 // outstanding jobs map.
[email protected]137af622010-02-05 02:14:351556 Key key = GetEffectiveKeyForRequest(info);
[email protected]123ab1e32009-10-21 19:12:571557
[email protected]287d7c22011-11-15 17:34:251558 int rv = ResolveHelper(key, info, addresses, request_net_log);
[email protected]95a214c2011-08-04 21:50:401559 if (rv != ERR_DNS_CACHE_MISS) {
[email protected]b3601bc22012-02-21 21:23:201560 LogFinishRequest(source_net_log, request_net_log, info, rv);
[email protected]95a214c2011-08-04 21:50:401561 return rv;
[email protected]38368712011-03-02 08:09:401562 }
1563
[email protected]0f292de02012-02-01 22:28:201564 // Next we need to attach our request to a "job". This job is responsible for
1565 // calling "getaddrinfo(hostname)" on a worker thread.
1566
1567 JobMap::iterator jobit = jobs_.find(key);
1568 Job* job;
1569 if (jobit == jobs_.end()) {
1570 // Create new Job.
[email protected]16ee26d2012-03-08 03:34:351571 job = new Job(this, key, request_net_log);
1572 job->Schedule(info.priority());
[email protected]0f292de02012-02-01 22:28:201573
1574 // Check for queue overflow.
1575 if (dispatcher_.num_queued_jobs() > max_queued_jobs_) {
1576 Job* evicted = static_cast<Job*>(dispatcher_.EvictOldestLowest());
1577 DCHECK(evicted);
[email protected]16ee26d2012-03-08 03:34:351578 evicted->OnEvicted(); // Deletes |evicted|.
[email protected]0f292de02012-02-01 22:28:201579 if (evicted == job) {
[email protected]0f292de02012-02-01 22:28:201580 rv = ERR_HOST_RESOLVER_QUEUE_TOO_LARGE;
[email protected]b3601bc22012-02-21 21:23:201581 LogFinishRequest(source_net_log, request_net_log, info, rv);
[email protected]0f292de02012-02-01 22:28:201582 return rv;
1583 }
[email protected]0f292de02012-02-01 22:28:201584 }
[email protected]0f292de02012-02-01 22:28:201585 jobs_.insert(jobit, std::make_pair(key, job));
1586 } else {
1587 job = jobit->second;
1588 }
1589
1590 // Can't complete synchronously. Create and attach request.
[email protected]b3601bc22012-02-21 21:23:201591 scoped_ptr<Request> req(new Request(source_net_log,
1592 request_net_log,
1593 info,
1594 callback,
1595 addresses));
[email protected]b59ff372009-07-15 22:04:321596 if (out_req)
[email protected]b3601bc22012-02-21 21:23:201597 *out_req = reinterpret_cast<RequestHandle>(req.get());
[email protected]b59ff372009-07-15 22:04:321598
[email protected]b3601bc22012-02-21 21:23:201599 job->AddRequest(req.Pass());
[email protected]0f292de02012-02-01 22:28:201600 // Completion happens during Job::CompleteRequests().
[email protected]b59ff372009-07-15 22:04:321601 return ERR_IO_PENDING;
1602}
1603
[email protected]287d7c22011-11-15 17:34:251604int HostResolverImpl::ResolveHelper(const Key& key,
[email protected]95a214c2011-08-04 21:50:401605 const RequestInfo& info,
1606 AddressList* addresses,
[email protected]20cd5332011-10-12 22:38:001607 const BoundNetLog& request_net_log) {
[email protected]95a214c2011-08-04 21:50:401608 // The result of |getaddrinfo| for empty hosts is inconsistent across systems.
1609 // On Windows it gives the default interface's address, whereas on Linux it
1610 // gives an error. We will make it fail on all platforms for consistency.
1611 if (info.hostname().empty() || info.hostname().size() > kMaxHostLength)
1612 return ERR_NAME_NOT_RESOLVED;
1613
1614 int net_error = ERR_UNEXPECTED;
1615 if (ResolveAsIP(key, info, &net_error, addresses))
1616 return net_error;
[email protected]78eac2a2012-03-14 19:09:271617 if (ServeFromCache(key, info, &net_error, addresses)) {
[email protected]4da911f2012-06-14 19:45:201618 request_net_log.AddEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_CACHE_HIT);
[email protected]78eac2a2012-03-14 19:09:271619 return net_error;
1620 }
1621 // TODO(szym): Do not do this if nsswitch.conf instructs not to.
1622 // http://crbug.com/117655
1623 if (ServeFromHosts(key, info, addresses)) {
[email protected]4da911f2012-06-14 19:45:201624 request_net_log.AddEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_HOSTS_HIT);
[email protected]78eac2a2012-03-14 19:09:271625 return OK;
1626 }
1627 return ERR_DNS_CACHE_MISS;
[email protected]95a214c2011-08-04 21:50:401628}
1629
1630int HostResolverImpl::ResolveFromCache(const RequestInfo& info,
1631 AddressList* addresses,
1632 const BoundNetLog& source_net_log) {
1633 DCHECK(CalledOnValidThread());
1634 DCHECK(addresses);
1635
[email protected]95a214c2011-08-04 21:50:401636 // Make a log item for the request.
1637 BoundNetLog request_net_log = BoundNetLog::Make(net_log_,
1638 NetLog::SOURCE_HOST_RESOLVER_IMPL_REQUEST);
1639
1640 // Update the net log and notify registered observers.
[email protected]0f292de02012-02-01 22:28:201641 LogStartRequest(source_net_log, request_net_log, info);
[email protected]95a214c2011-08-04 21:50:401642
[email protected]95a214c2011-08-04 21:50:401643 Key key = GetEffectiveKeyForRequest(info);
1644
[email protected]287d7c22011-11-15 17:34:251645 int rv = ResolveHelper(key, info, addresses, request_net_log);
[email protected]b3601bc22012-02-21 21:23:201646 LogFinishRequest(source_net_log, request_net_log, info, rv);
[email protected]95a214c2011-08-04 21:50:401647 return rv;
1648}
1649
[email protected]b59ff372009-07-15 22:04:321650void HostResolverImpl::CancelRequest(RequestHandle req_handle) {
[email protected]1ac6af92010-06-03 21:00:141651 DCHECK(CalledOnValidThread());
[email protected]b59ff372009-07-15 22:04:321652 Request* req = reinterpret_cast<Request*>(req_handle);
1653 DCHECK(req);
[email protected]0f292de02012-02-01 22:28:201654 Job* job = req->job();
1655 DCHECK(job);
[email protected]0f292de02012-02-01 22:28:201656 job->CancelRequest(req);
[email protected]b59ff372009-07-15 22:04:321657}
1658
[email protected]0f8f1b432010-03-16 19:06:031659void HostResolverImpl::SetDefaultAddressFamily(AddressFamily address_family) {
[email protected]1ac6af92010-06-03 21:00:141660 DCHECK(CalledOnValidThread());
[email protected]0f8f1b432010-03-16 19:06:031661 ipv6_probe_monitoring_ = false;
1662 DiscardIPv6ProbeJob();
1663 default_address_family_ = address_family;
1664}
1665
[email protected]f7d310e2010-10-07 16:25:111666AddressFamily HostResolverImpl::GetDefaultAddressFamily() const {
1667 return default_address_family_;
1668}
1669
[email protected]a78f4272011-10-21 19:16:331670void HostResolverImpl::ProbeIPv6Support() {
1671 DCHECK(CalledOnValidThread());
1672 DCHECK(!ipv6_probe_monitoring_);
1673 ipv6_probe_monitoring_ = true;
1674 OnIPAddressChanged(); // Give initial setup call.
[email protected]ddb1e5a2010-12-13 20:10:451675}
1676
[email protected]489d1a82011-10-12 03:09:111677HostCache* HostResolverImpl::GetHostCache() {
1678 return cache_.get();
1679}
[email protected]95a214c2011-08-04 21:50:401680
[email protected]17e92032012-03-29 00:56:241681base::Value* HostResolverImpl::GetDnsConfigAsValue() const {
1682 // Check if async DNS is disabled.
1683 if (!dns_client_.get())
1684 return NULL;
1685
1686 // Check if async DNS is enabled, but we currently have no configuration
1687 // for it.
1688 const DnsConfig* dns_config = dns_client_->GetConfig();
1689 if (dns_config == NULL)
1690 return new DictionaryValue();
1691
1692 return dns_config->ToValue();
1693}
1694
[email protected]95a214c2011-08-04 21:50:401695bool HostResolverImpl::ResolveAsIP(const Key& key,
1696 const RequestInfo& info,
1697 int* net_error,
1698 AddressList* addresses) {
1699 DCHECK(addresses);
1700 DCHECK(net_error);
1701 IPAddressNumber ip_number;
1702 if (!ParseIPLiteralToNumber(key.hostname, &ip_number))
1703 return false;
1704
1705 DCHECK_EQ(key.host_resolver_flags &
1706 ~(HOST_RESOLVER_CANONNAME | HOST_RESOLVER_LOOPBACK_ONLY |
1707 HOST_RESOLVER_DEFAULT_FAMILY_SET_DUE_TO_NO_IPV6),
1708 0) << " Unhandled flag";
[email protected]0f292de02012-02-01 22:28:201709 bool ipv6_disabled = (default_address_family_ == ADDRESS_FAMILY_IPV4) &&
1710 !ipv6_probe_monitoring_;
[email protected]95a214c2011-08-04 21:50:401711 *net_error = OK;
[email protected]0f292de02012-02-01 22:28:201712 if ((ip_number.size() == kIPv6AddressSize) && ipv6_disabled) {
[email protected]95a214c2011-08-04 21:50:401713 *net_error = ERR_NAME_NOT_RESOLVED;
1714 } else {
[email protected]7054e78f2012-05-07 21:44:561715 *addresses = AddressList::CreateFromIPAddress(ip_number, info.port());
1716 if (key.host_resolver_flags & HOST_RESOLVER_CANONNAME)
1717 addresses->SetDefaultCanonicalName();
[email protected]95a214c2011-08-04 21:50:401718 }
1719 return true;
1720}
1721
1722bool HostResolverImpl::ServeFromCache(const Key& key,
1723 const RequestInfo& info,
[email protected]95a214c2011-08-04 21:50:401724 int* net_error,
1725 AddressList* addresses) {
1726 DCHECK(addresses);
1727 DCHECK(net_error);
1728 if (!info.allow_cached_response() || !cache_.get())
1729 return false;
1730
1731 const HostCache::Entry* cache_entry = cache_->Lookup(
1732 key, base::TimeTicks::Now());
1733 if (!cache_entry)
1734 return false;
1735
[email protected]95a214c2011-08-04 21:50:401736 *net_error = cache_entry->error;
[email protected]7054e78f2012-05-07 21:44:561737 if (*net_error == OK) {
1738 *addresses = cache_entry->addrlist;
1739 EnsurePortOnAddressList(info.port(), addresses);
1740 }
[email protected]95a214c2011-08-04 21:50:401741 return true;
1742}
1743
[email protected]78eac2a2012-03-14 19:09:271744bool HostResolverImpl::ServeFromHosts(const Key& key,
1745 const RequestInfo& info,
1746 AddressList* addresses) {
1747 DCHECK(addresses);
1748 if (!HaveDnsConfig())
1749 return false;
1750
[email protected]cb507622012-03-23 16:17:061751 // HOSTS lookups are case-insensitive.
1752 std::string hostname = StringToLowerASCII(key.hostname);
1753
[email protected]78eac2a2012-03-14 19:09:271754 // If |address_family| is ADDRESS_FAMILY_UNSPECIFIED other implementations
1755 // (glibc and c-ares) return the first matching line. We have more
1756 // flexibility, but lose implicit ordering.
1757 // TODO(szym) http://crbug.com/117850
1758 const DnsHosts& hosts = dns_client_->GetConfig()->hosts;
1759 DnsHosts::const_iterator it = hosts.find(
[email protected]cb507622012-03-23 16:17:061760 DnsHostsKey(hostname,
[email protected]78eac2a2012-03-14 19:09:271761 key.address_family == ADDRESS_FAMILY_UNSPECIFIED ?
1762 ADDRESS_FAMILY_IPV4 : key.address_family));
1763
1764 if (it == hosts.end()) {
1765 if (key.address_family != ADDRESS_FAMILY_UNSPECIFIED)
1766 return false;
1767
[email protected]cb507622012-03-23 16:17:061768 it = hosts.find(DnsHostsKey(hostname, ADDRESS_FAMILY_IPV6));
[email protected]78eac2a2012-03-14 19:09:271769 if (it == hosts.end())
1770 return false;
1771 }
1772
1773 *addresses = AddressList::CreateFromIPAddress(it->second, info.port());
1774 return true;
1775}
1776
[email protected]16ee26d2012-03-08 03:34:351777void HostResolverImpl::CacheResult(const Key& key,
1778 int net_error,
1779 const AddressList& addr_list,
1780 base::TimeDelta ttl) {
1781 if (cache_.get())
1782 cache_->Set(key, net_error, addr_list, base::TimeTicks::Now(), ttl);
[email protected]ef4c40c2010-09-01 14:42:031783}
1784
[email protected]0f292de02012-02-01 22:28:201785void HostResolverImpl::RemoveJob(Job* job) {
1786 DCHECK(job);
[email protected]16ee26d2012-03-08 03:34:351787 JobMap::iterator it = jobs_.find(job->key());
1788 if (it != jobs_.end() && it->second == job)
1789 jobs_.erase(it);
[email protected]b59ff372009-07-15 22:04:321790}
1791
[email protected]0f8f1b432010-03-16 19:06:031792void HostResolverImpl::DiscardIPv6ProbeJob() {
1793 if (ipv6_probe_job_.get()) {
1794 ipv6_probe_job_->Cancel();
1795 ipv6_probe_job_ = NULL;
1796 }
1797}
1798
1799void HostResolverImpl::IPv6ProbeSetDefaultAddressFamily(
1800 AddressFamily address_family) {
1801 DCHECK(address_family == ADDRESS_FAMILY_UNSPECIFIED ||
1802 address_family == ADDRESS_FAMILY_IPV4);
[email protected]f092e64b2010-03-17 00:39:181803 if (default_address_family_ != address_family) {
[email protected]b30a3f52010-10-16 01:05:461804 VLOG(1) << "IPv6Probe forced AddressFamily setting to "
1805 << ((address_family == ADDRESS_FAMILY_UNSPECIFIED) ?
1806 "ADDRESS_FAMILY_UNSPECIFIED" : "ADDRESS_FAMILY_IPV4");
[email protected]f092e64b2010-03-17 00:39:181807 }
[email protected]0f8f1b432010-03-16 19:06:031808 default_address_family_ = address_family;
1809 // Drop reference since the job has called us back.
1810 DiscardIPv6ProbeJob();
[email protected]e95d3aca2010-01-11 22:47:431811}
1812
[email protected]137af622010-02-05 02:14:351813HostResolverImpl::Key HostResolverImpl::GetEffectiveKeyForRequest(
1814 const RequestInfo& info) const {
[email protected]eaf3a3b2010-09-03 20:34:271815 HostResolverFlags effective_flags =
1816 info.host_resolver_flags() | additional_resolver_flags_;
[email protected]137af622010-02-05 02:14:351817 AddressFamily effective_address_family = info.address_family();
[email protected]eaf3a3b2010-09-03 20:34:271818 if (effective_address_family == ADDRESS_FAMILY_UNSPECIFIED &&
1819 default_address_family_ != ADDRESS_FAMILY_UNSPECIFIED) {
[email protected]137af622010-02-05 02:14:351820 effective_address_family = default_address_family_;
[email protected]eaf3a3b2010-09-03 20:34:271821 if (ipv6_probe_monitoring_)
1822 effective_flags |= HOST_RESOLVER_DEFAULT_FAMILY_SET_DUE_TO_NO_IPV6;
1823 }
1824 return Key(info.hostname(), effective_address_family, effective_flags);
[email protected]137af622010-02-05 02:14:351825}
1826
[email protected]35ddc282010-09-21 23:42:061827void HostResolverImpl::AbortAllInProgressJobs() {
[email protected]b3601bc22012-02-21 21:23:201828 // In Abort, a Request callback could spawn new Jobs with matching keys, so
1829 // first collect and remove all running jobs from |jobs_|.
[email protected]c143d892012-04-06 07:56:541830 ScopedVector<Job> jobs_to_abort;
[email protected]0f292de02012-02-01 22:28:201831 for (JobMap::iterator it = jobs_.begin(); it != jobs_.end(); ) {
1832 Job* job = it->second;
[email protected]0f292de02012-02-01 22:28:201833 if (job->is_running()) {
[email protected]b3601bc22012-02-21 21:23:201834 jobs_to_abort.push_back(job);
1835 jobs_.erase(it++);
[email protected]0f292de02012-02-01 22:28:201836 } else {
[email protected]b3601bc22012-02-21 21:23:201837 DCHECK(job->is_queued());
1838 ++it;
[email protected]0f292de02012-02-01 22:28:201839 }
[email protected]ef4c40c2010-09-01 14:42:031840 }
[email protected]b3601bc22012-02-21 21:23:201841
[email protected]57a48d32012-03-03 00:04:551842 // Check if no dispatcher slots leaked out.
1843 DCHECK_EQ(dispatcher_.num_running_jobs(), jobs_to_abort.size());
1844
1845 // Life check to bail once |this| is deleted.
1846 base::WeakPtr<HostResolverImpl> self = AsWeakPtr();
1847
[email protected]16ee26d2012-03-08 03:34:351848 // Then Abort them.
[email protected]57a48d32012-03-03 00:04:551849 for (size_t i = 0; self && i < jobs_to_abort.size(); ++i) {
[email protected]57a48d32012-03-03 00:04:551850 jobs_to_abort[i]->Abort();
[email protected]c143d892012-04-06 07:56:541851 jobs_to_abort[i] = NULL;
[email protected]b3601bc22012-02-21 21:23:201852 }
[email protected]ef4c40c2010-09-01 14:42:031853}
1854
[email protected]78eac2a2012-03-14 19:09:271855void HostResolverImpl::TryServingAllJobsFromHosts() {
1856 if (!HaveDnsConfig())
1857 return;
1858
1859 // TODO(szym): Do not do this if nsswitch.conf instructs not to.
1860 // http://crbug.com/117655
1861
1862 // Life check to bail once |this| is deleted.
1863 base::WeakPtr<HostResolverImpl> self = AsWeakPtr();
1864
1865 for (JobMap::iterator it = jobs_.begin(); self && it != jobs_.end(); ) {
1866 Job* job = it->second;
1867 ++it;
1868 // This could remove |job| from |jobs_|, but iterator will remain valid.
1869 job->ServeFromHosts();
1870 }
1871}
1872
[email protected]be1a48b2011-01-20 00:12:131873void HostResolverImpl::OnIPAddressChanged() {
1874 if (cache_.get())
1875 cache_->clear();
1876 if (ipv6_probe_monitoring_) {
[email protected]be1a48b2011-01-20 00:12:131877 DiscardIPv6ProbeJob();
1878 ipv6_probe_job_ = new IPv6ProbeJob(this);
1879 ipv6_probe_job_->Start();
1880 }
[email protected]23f771162011-06-02 18:37:511881#if defined(OS_POSIX) && !defined(OS_MACOSX)
[email protected]be1a48b2011-01-20 00:12:131882 if (HaveOnlyLoopbackAddresses()) {
1883 additional_resolver_flags_ |= HOST_RESOLVER_LOOPBACK_ONLY;
1884 } else {
1885 additional_resolver_flags_ &= ~HOST_RESOLVER_LOOPBACK_ONLY;
1886 }
1887#endif
1888 AbortAllInProgressJobs();
1889 // |this| may be deleted inside AbortAllInProgressJobs().
1890}
1891
[email protected]446df2952012-02-28 07:22:511892void HostResolverImpl::OnDNSChanged(unsigned detail) {
[email protected]d7b9a2b2012-05-31 22:31:191893 // Ignore signals about watches.
1894 const unsigned kIgnoredDetail =
1895 NetworkChangeNotifier::CHANGE_DNS_WATCH_STARTED |
1896 NetworkChangeNotifier::CHANGE_DNS_WATCH_FAILED;
1897 if ((detail & ~kIgnoredDetail) == 0)
1898 return;
[email protected]46018c9d2011-09-06 03:42:341899 // If the DNS server has changed, existing cached info could be wrong so we
1900 // have to drop our internal cache :( Note that OS level DNS caches, such
1901 // as NSCD's cache should be dropped automatically by the OS when
1902 // resolv.conf changes so we don't need to do anything to clear that cache.
1903 if (cache_.get())
1904 cache_->clear();
1905 // Existing jobs will have been sent to the original server so they need to
[email protected]d7b9a2b2012-05-31 22:31:191906 // be aborted.
[email protected]46018c9d2011-09-06 03:42:341907 AbortAllInProgressJobs();
1908 // |this| may be deleted inside AbortAllInProgressJobs().
1909}
1910
[email protected]b4481b222012-03-16 17:13:111911void HostResolverImpl::OnDnsConfigChanged(const DnsConfig& dns_config) {
1912 if (net_log_) {
1913 net_log_->AddGlobalEntry(
1914 NetLog::TYPE_DNS_CONFIG_CHANGED,
[email protected]cd565142012-06-12 16:21:451915 base::Bind(&NetLogDnsConfigCallback, &dns_config));
[email protected]b4481b222012-03-16 17:13:111916 }
1917
[email protected]d7b9a2b2012-05-31 22:31:191918 // TODO(szym): Remove once http://crbug.com/125599 is resolved.
1919 received_dns_config_ = dns_config.IsValid();
[email protected]78eac2a2012-03-14 19:09:271920
1921 // Life check to bail once |this| is deleted.
1922 base::WeakPtr<HostResolverImpl> self = AsWeakPtr();
1923
[email protected]d7b9a2b2012-05-31 22:31:191924 if (dns_client_.get()) {
1925 // We want a new factory in place, before we Abort running Jobs, so that the
1926 // newly started jobs use the new factory.
1927 dns_client_->SetConfig(dns_config);
[email protected]446df2952012-02-28 07:22:511928 OnDNSChanged(NetworkChangeNotifier::CHANGE_DNS_SETTINGS);
[email protected]d7b9a2b2012-05-31 22:31:191929 // |this| may be deleted inside OnDNSChanged().
1930 if (self)
1931 TryServingAllJobsFromHosts();
[email protected]7b5db762012-03-24 09:02:011932 }
[email protected]78eac2a2012-03-14 19:09:271933}
1934
1935bool HostResolverImpl::HaveDnsConfig() const {
1936 return (dns_client_.get() != NULL) && (dns_client_->GetConfig() != NULL);
[email protected]b3601bc22012-02-21 21:23:201937}
1938
[email protected]b59ff372009-07-15 22:04:321939} // namespace net