blob: 843242968527f4e987f9dbeb705110eecae9a927 [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]b3601bc22012-02-21 21:23:2027#include "base/rand_util.h"
[email protected]7286e3fc2011-07-19 22:13:2428#include "base/stl_util.h"
[email protected]b59ff372009-07-15 22:04:3229#include "base/string_util.h"
[email protected]ac9ba8fe2010-12-30 18:08:3630#include "base/threading/worker_pool.h"
[email protected]b59ff372009-07-15 22:04:3231#include "base/time.h"
[email protected]ccaff652010-07-31 06:28:2032#include "base/utf_string_conversions.h"
[email protected]21526002010-05-16 19:42:4633#include "base/values.h"
[email protected]b3601bc22012-02-21 21:23:2034#include "net/base/address_family.h"
[email protected]b59ff372009-07-15 22:04:3235#include "net/base/address_list.h"
[email protected]ee094b82010-08-24 15:55:5136#include "net/base/address_list_net_log_param.h"
[email protected]46018c9d2011-09-06 03:42:3437#include "net/base/dns_reloader.h"
[email protected]ee094b82010-08-24 15:55:5138#include "net/base/host_port_pair.h"
[email protected]b59ff372009-07-15 22:04:3239#include "net/base/host_resolver_proc.h"
[email protected]2bb04442010-08-18 18:01:1540#include "net/base/net_errors.h"
[email protected]ee094b82010-08-24 15:55:5141#include "net/base/net_log.h"
[email protected]0f8f1b432010-03-16 19:06:0342#include "net/base/net_util.h"
[email protected]b3601bc22012-02-21 21:23:2043#include "net/dns/dns_config_service.h"
44#include "net/dns/dns_protocol.h"
45#include "net/dns/dns_response.h"
46#include "net/dns/dns_session.h"
47#include "net/dns/dns_transaction.h"
48#include "net/socket/client_socket_factory.h"
[email protected]b59ff372009-07-15 22:04:3249
50#if defined(OS_WIN)
51#include "net/base/winsock_init.h"
52#endif
53
54namespace net {
55
[email protected]e95d3aca2010-01-11 22:47:4356namespace {
57
[email protected]6e78dfb2011-07-28 21:34:4758// Limit the size of hostnames that will be resolved to combat issues in
59// some platform's resolvers.
60const size_t kMaxHostLength = 4096;
61
[email protected]a2730882012-01-21 00:56:2762// Default TTL for successful resolutions with ProcTask.
63const unsigned kCacheEntryTTLSeconds = 60;
64
[email protected]b3601bc22012-02-21 21:23:2065// Default TTL for unsuccessful resolutions with ProcTask.
66const unsigned kNegativeCacheEntryTTLSeconds = 0;
67
[email protected]0f292de02012-02-01 22:28:2068// Maximum of 8 concurrent resolver threads (excluding retries).
69// Some routers (or resolvers) appear to start to provide host-not-found if
70// too many simultaneous resolutions are pending. This number needs to be
71// further optimized, but 8 is what FF currently does.
72static const size_t kDefaultMaxProcTasks = 8u;
73
[email protected]fe89ea72011-05-12 02:02:4074// Helper to mutate the linked list contained by AddressList to the given
75// port. Note that in general this is dangerous since the AddressList's
76// data might be shared (and you should use AddressList::SetPort).
77//
78// However since we allocated the AddressList ourselves we can safely
79// do this optimization and avoid reallocating the list.
[email protected]b3601bc22012-02-21 21:23:2080void MutableSetPort(int port, AddressList* addr_list) {
[email protected]fe89ea72011-05-12 02:02:4081 struct addrinfo* mutable_head =
[email protected]b3601bc22012-02-21 21:23:2082 const_cast<struct addrinfo*>(addr_list->head());
[email protected]fe89ea72011-05-12 02:02:4083 SetPortForAllAddrinfos(mutable_head, port);
84}
85
[email protected]24f4bab2010-10-15 01:27:1186// We use a separate histogram name for each platform to facilitate the
87// display of error codes by their symbolic name (since each platform has
88// different mappings).
89const char kOSErrorsForGetAddrinfoHistogramName[] =
90#if defined(OS_WIN)
91 "Net.OSErrorsForGetAddrinfo_Win";
92#elif defined(OS_MACOSX)
93 "Net.OSErrorsForGetAddrinfo_Mac";
94#elif defined(OS_LINUX)
95 "Net.OSErrorsForGetAddrinfo_Linux";
96#else
97 "Net.OSErrorsForGetAddrinfo";
98#endif
99
[email protected]c89b2442011-05-26 14:28:27100// Gets a list of the likely error codes that getaddrinfo() can return
101// (non-exhaustive). These are the error codes that we will track via
102// a histogram.
103std::vector<int> GetAllGetAddrinfoOSErrors() {
104 int os_errors[] = {
105#if defined(OS_POSIX)
[email protected]23f771162011-06-02 18:37:51106#if !defined(OS_FREEBSD)
[email protected]39588992011-07-11 19:54:37107#if !defined(OS_ANDROID)
[email protected]c48aef92011-11-22 23:41:45108 // EAI_ADDRFAMILY has been declared obsolete in Android's and
109 // FreeBSD's netdb.h.
[email protected]c89b2442011-05-26 14:28:27110 EAI_ADDRFAMILY,
[email protected]39588992011-07-11 19:54:37111#endif
[email protected]c48aef92011-11-22 23:41:45112 // EAI_NODATA has been declared obsolete in FreeBSD's netdb.h.
[email protected]23f771162011-06-02 18:37:51113 EAI_NODATA,
114#endif
[email protected]c89b2442011-05-26 14:28:27115 EAI_AGAIN,
116 EAI_BADFLAGS,
117 EAI_FAIL,
118 EAI_FAMILY,
119 EAI_MEMORY,
[email protected]c89b2442011-05-26 14:28:27120 EAI_NONAME,
121 EAI_SERVICE,
122 EAI_SOCKTYPE,
123 EAI_SYSTEM,
124#elif defined(OS_WIN)
125 // See: http://msdn.microsoft.com/en-us/library/ms738520(VS.85).aspx
126 WSA_NOT_ENOUGH_MEMORY,
127 WSAEAFNOSUPPORT,
128 WSAEINVAL,
129 WSAESOCKTNOSUPPORT,
130 WSAHOST_NOT_FOUND,
131 WSANO_DATA,
132 WSANO_RECOVERY,
133 WSANOTINITIALISED,
134 WSATRY_AGAIN,
135 WSATYPE_NOT_FOUND,
136 // The following are not in doc, but might be to appearing in results :-(.
137 WSA_INVALID_HANDLE,
138#endif
139 };
140
141 // Ensure all errors are positive, as histogram only tracks positive values.
142 for (size_t i = 0; i < arraysize(os_errors); ++i) {
143 os_errors[i] = std::abs(os_errors[i]);
144 }
145
146 return base::CustomHistogram::ArrayToCustomRanges(os_errors,
147 arraysize(os_errors));
148}
149
[email protected]0f292de02012-02-01 22:28:20150// Wraps call to SystemHostResolverProc as an instance of HostResolverProc.
151// TODO(szym): This should probably be declared in host_resolver_proc.h.
152class CallSystemHostResolverProc : public HostResolverProc {
153 public:
154 CallSystemHostResolverProc() : HostResolverProc(NULL) {}
155 virtual int Resolve(const std::string& hostname,
156 AddressFamily address_family,
157 HostResolverFlags host_resolver_flags,
[email protected]b3601bc22012-02-21 21:23:20158 AddressList* addr_list,
[email protected]0f292de02012-02-01 22:28:20159 int* os_error) OVERRIDE {
160 return SystemHostResolverProc(hostname,
161 address_family,
162 host_resolver_flags,
[email protected]b3601bc22012-02-21 21:23:20163 addr_list,
[email protected]0f292de02012-02-01 22:28:20164 os_error);
[email protected]b59ff372009-07-15 22:04:32165 }
[email protected]0f292de02012-02-01 22:28:20166};
[email protected]b59ff372009-07-15 22:04:32167
[email protected]21526002010-05-16 19:42:46168// Extra parameters to attach to the NetLog when the resolve failed.
[email protected]b3601bc22012-02-21 21:23:20169class ProcTaskFailedParams : public NetLog::EventParameters {
[email protected]21526002010-05-16 19:42:46170 public:
[email protected]b3601bc22012-02-21 21:23:20171 ProcTaskFailedParams(uint32 attempt_number, int net_error, int os_error)
[email protected]13024882011-05-18 23:19:16172 : attempt_number_(attempt_number),
173 net_error_(net_error),
[email protected]ee094b82010-08-24 15:55:51174 os_error_(os_error) {
[email protected]21526002010-05-16 19:42:46175 }
176
[email protected]0f292de02012-02-01 22:28:20177 virtual Value* ToValue() const OVERRIDE {
[email protected]21526002010-05-16 19:42:46178 DictionaryValue* dict = new DictionaryValue();
[email protected]13024882011-05-18 23:19:16179 if (attempt_number_)
180 dict->SetInteger("attempt_number", attempt_number_);
181
[email protected]ccaff652010-07-31 06:28:20182 dict->SetInteger("net_error", net_error_);
[email protected]21526002010-05-16 19:42:46183
184 if (os_error_) {
[email protected]ccaff652010-07-31 06:28:20185 dict->SetInteger("os_error", os_error_);
[email protected]21526002010-05-16 19:42:46186#if defined(OS_POSIX)
[email protected]ccaff652010-07-31 06:28:20187 dict->SetString("os_error_string", gai_strerror(os_error_));
[email protected]21526002010-05-16 19:42:46188#elif defined(OS_WIN)
189 // Map the error code to a human-readable string.
190 LPWSTR error_string = NULL;
191 int size = FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
192 FORMAT_MESSAGE_FROM_SYSTEM,
193 0, // Use the internal message table.
194 os_error_,
195 0, // Use default language.
196 (LPWSTR)&error_string,
197 0, // Buffer size.
198 0); // Arguments (unused).
[email protected]ccaff652010-07-31 06:28:20199 dict->SetString("os_error_string", WideToUTF8(error_string));
[email protected]21526002010-05-16 19:42:46200 LocalFree(error_string);
201#endif
202 }
203
204 return dict;
205 }
206
207 private:
[email protected]13024882011-05-18 23:19:16208 const uint32 attempt_number_;
[email protected]21526002010-05-16 19:42:46209 const int net_error_;
210 const int os_error_;
[email protected]ee094b82010-08-24 15:55:51211};
212
[email protected]b3601bc22012-02-21 21:23:20213// Extra parameters to attach to the NetLog when the DnsTask failed.
214class DnsTaskFailedParams : public NetLog::EventParameters {
215 public:
216 DnsTaskFailedParams(int net_error, int dns_error)
217 : net_error_(net_error), dns_error_(dns_error) {
218 }
219
220 virtual Value* ToValue() const OVERRIDE {
221 DictionaryValue* dict = new DictionaryValue();
222 dict->SetInteger("net_error", net_error_);
223 if (dns_error_)
224 dict->SetInteger("dns_error", dns_error_);
225 return dict;
226 }
227
228 private:
229 const int net_error_;
230 const int dns_error_;
231};
232
[email protected]ee094b82010-08-24 15:55:51233// Parameters representing the information in a RequestInfo object, along with
234// the associated NetLog::Source.
235class RequestInfoParameters : public NetLog::EventParameters {
236 public:
237 RequestInfoParameters(const HostResolver::RequestInfo& info,
238 const NetLog::Source& source)
239 : info_(info), source_(source) {}
240
[email protected]0f292de02012-02-01 22:28:20241 virtual Value* ToValue() const OVERRIDE {
[email protected]ee094b82010-08-24 15:55:51242 DictionaryValue* dict = new DictionaryValue();
[email protected]930cc742010-09-15 22:54:10243 dict->SetString("host", info_.host_port_pair().ToString());
[email protected]ee094b82010-08-24 15:55:51244 dict->SetInteger("address_family",
245 static_cast<int>(info_.address_family()));
246 dict->SetBoolean("allow_cached_response", info_.allow_cached_response());
247 dict->SetBoolean("is_speculative", info_.is_speculative());
248 dict->SetInteger("priority", info_.priority());
249
250 if (source_.is_valid())
251 dict->Set("source_dependency", source_.ToValue());
252
253 return dict;
254 }
255
256 private:
257 const HostResolver::RequestInfo info_;
258 const NetLog::Source source_;
259};
260
[email protected]b3601bc22012-02-21 21:23:20261// Parameters associated with the creation of a HostResolverImpl::Job.
[email protected]ee094b82010-08-24 15:55:51262class JobCreationParameters : public NetLog::EventParameters {
263 public:
[email protected]0f292de02012-02-01 22:28:20264 JobCreationParameters(const std::string& host,
265 const NetLog::Source& source)
[email protected]ee094b82010-08-24 15:55:51266 : host_(host), source_(source) {}
267
[email protected]0f292de02012-02-01 22:28:20268 virtual Value* ToValue() const OVERRIDE {
[email protected]ee094b82010-08-24 15:55:51269 DictionaryValue* dict = new DictionaryValue();
270 dict->SetString("host", host_);
271 dict->Set("source_dependency", source_.ToValue());
272 return dict;
273 }
274
275 private:
276 const std::string host_;
277 const NetLog::Source source_;
[email protected]21526002010-05-16 19:42:46278};
279
[email protected]0f292de02012-02-01 22:28:20280// Parameters of the HOST_RESOLVER_IMPL_JOB_ATTACH/DETACH event.
281class JobAttachParameters : public NetLog::EventParameters {
282 public:
283 JobAttachParameters(const NetLog::Source& source,
284 RequestPriority priority)
285 : source_(source), priority_(priority) {}
286
287 virtual Value* ToValue() const OVERRIDE {
288 DictionaryValue* dict = new DictionaryValue();
289 dict->Set("source_dependency", source_.ToValue());
290 dict->SetInteger("priority", priority_);
291 return dict;
292 }
293
294 private:
295 const NetLog::Source source_;
296 const RequestPriority priority_;
297};
298
299// The logging routines are defined here because some requests are resolved
300// without a Request object.
301
302// Logs when a request has just been started.
303void LogStartRequest(const BoundNetLog& source_net_log,
304 const BoundNetLog& request_net_log,
305 const HostResolver::RequestInfo& info) {
306 source_net_log.BeginEvent(
307 NetLog::TYPE_HOST_RESOLVER_IMPL,
308 make_scoped_refptr(new NetLogSourceParameter(
309 "source_dependency", request_net_log.source())));
310
311 request_net_log.BeginEvent(
312 NetLog::TYPE_HOST_RESOLVER_IMPL_REQUEST,
313 make_scoped_refptr(new RequestInfoParameters(
314 info, source_net_log.source())));
315}
316
317// Logs when a request has just completed (before its callback is run).
318void LogFinishRequest(const BoundNetLog& source_net_log,
319 const BoundNetLog& request_net_log,
320 const HostResolver::RequestInfo& info,
[email protected]b3601bc22012-02-21 21:23:20321 int net_error) {
322 request_net_log.EndEventWithNetErrorCode(
323 NetLog::TYPE_HOST_RESOLVER_IMPL_REQUEST, net_error);
[email protected]0f292de02012-02-01 22:28:20324 source_net_log.EndEvent(NetLog::TYPE_HOST_RESOLVER_IMPL, NULL);
325}
326
327// Logs when a request has been cancelled.
328void LogCancelRequest(const BoundNetLog& source_net_log,
329 const BoundNetLog& request_net_log,
330 const HostResolverImpl::RequestInfo& info) {
331 request_net_log.AddEvent(NetLog::TYPE_CANCELLED, NULL);
332 request_net_log.EndEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_REQUEST, NULL);
333 source_net_log.EndEvent(NetLog::TYPE_HOST_RESOLVER_IMPL, NULL);
334}
335
[email protected]b59ff372009-07-15 22:04:32336//-----------------------------------------------------------------------------
337
[email protected]0f292de02012-02-01 22:28:20338// Keeps track of the highest priority.
339class PriorityTracker {
340 public:
[email protected]16ee26d2012-03-08 03:34:35341 PriorityTracker()
342 : highest_priority_(IDLE), total_count_(0) {
[email protected]0f292de02012-02-01 22:28:20343 memset(counts_, 0, sizeof(counts_));
344 }
345
346 RequestPriority highest_priority() const {
347 return highest_priority_;
348 }
349
350 size_t total_count() const {
351 return total_count_;
352 }
353
354 void Add(RequestPriority req_priority) {
355 ++total_count_;
356 ++counts_[req_priority];
357 if (highest_priority_ > req_priority)
358 highest_priority_ = req_priority;
359 }
360
361 void Remove(RequestPriority req_priority) {
362 DCHECK_GT(total_count_, 0u);
363 DCHECK_GT(counts_[req_priority], 0u);
364 --total_count_;
365 --counts_[req_priority];
366 size_t i;
367 for (i = highest_priority_; i < NUM_PRIORITIES && !counts_[i]; ++i);
368 highest_priority_ = static_cast<RequestPriority>(i);
369
370 // In absence of requests set default.
371 if (highest_priority_ == NUM_PRIORITIES) {
372 DCHECK_EQ(0u, total_count_);
373 highest_priority_ = IDLE;
374 }
375 }
376
377 private:
378 RequestPriority highest_priority_;
379 size_t total_count_;
380 size_t counts_[NUM_PRIORITIES];
381};
382
383//-----------------------------------------------------------------------------
384
385HostResolver* CreateHostResolver(size_t max_concurrent_resolves,
386 size_t max_retry_attempts,
[email protected]b3601bc22012-02-21 21:23:20387 HostCache* cache,
388 scoped_ptr<DnsConfigService> config_service,
[email protected]0f292de02012-02-01 22:28:20389 NetLog* net_log) {
390 if (max_concurrent_resolves == HostResolver::kDefaultParallelism)
391 max_concurrent_resolves = kDefaultMaxProcTasks;
392
393 // TODO(szym): Add experiments with reserved slots for higher priority
394 // requests.
395
396 PrioritizedDispatcher::Limits limits(NUM_PRIORITIES, max_concurrent_resolves);
397
398 HostResolverImpl* resolver = new HostResolverImpl(
[email protected]b3601bc22012-02-21 21:23:20399 cache,
[email protected]0f292de02012-02-01 22:28:20400 limits,
401 HostResolverImpl::ProcTaskParams(NULL, max_retry_attempts),
[email protected]b3601bc22012-02-21 21:23:20402 config_service.Pass(),
[email protected]0f292de02012-02-01 22:28:20403 net_log);
404
405 return resolver;
406}
407
408} // anonymous namespace
409
410//-----------------------------------------------------------------------------
411
412HostResolver* CreateSystemHostResolver(size_t max_concurrent_resolves,
413 size_t max_retry_attempts,
414 NetLog* net_log) {
415 return CreateHostResolver(max_concurrent_resolves,
416 max_retry_attempts,
[email protected]b3601bc22012-02-21 21:23:20417 HostCache::CreateDefaultCache(),
418 scoped_ptr<DnsConfigService>(NULL),
[email protected]0f292de02012-02-01 22:28:20419 net_log);
420}
421
422HostResolver* CreateNonCachingSystemHostResolver(size_t max_concurrent_resolves,
423 size_t max_retry_attempts,
424 NetLog* net_log) {
425 return CreateHostResolver(max_concurrent_resolves,
426 max_retry_attempts,
[email protected]b3601bc22012-02-21 21:23:20427 NULL,
428 scoped_ptr<DnsConfigService>(NULL),
429 net_log);
430}
431
432HostResolver* CreateAsyncHostResolver(size_t max_concurrent_resolves,
433 size_t max_retry_attempts,
434 NetLog* net_log) {
435 scoped_ptr<DnsConfigService> config_service =
436 DnsConfigService::CreateSystemService();
437 config_service->Watch();
438 return CreateHostResolver(max_concurrent_resolves,
439 max_retry_attempts,
440 HostCache::CreateDefaultCache(),
441 config_service.Pass(),
[email protected]0f292de02012-02-01 22:28:20442 net_log);
443}
444
445//-----------------------------------------------------------------------------
446
447// Holds the data for a request that could not be completed synchronously.
448// It is owned by a Job. Canceled Requests are only marked as canceled rather
449// than removed from the Job's |requests_| list.
[email protected]b59ff372009-07-15 22:04:32450class HostResolverImpl::Request {
451 public:
[email protected]ee094b82010-08-24 15:55:51452 Request(const BoundNetLog& source_net_log,
453 const BoundNetLog& request_net_log,
[email protected]54e13772009-08-14 03:01:09454 const RequestInfo& info,
[email protected]aa22b242011-11-16 18:58:29455 const CompletionCallback& callback,
[email protected]b59ff372009-07-15 22:04:32456 AddressList* addresses)
[email protected]ee094b82010-08-24 15:55:51457 : source_net_log_(source_net_log),
458 request_net_log_(request_net_log),
[email protected]54e13772009-08-14 03:01:09459 info_(info),
460 job_(NULL),
461 callback_(callback),
462 addresses_(addresses) {
463 }
[email protected]b59ff372009-07-15 22:04:32464
[email protected]0f292de02012-02-01 22:28:20465 // Mark the request as canceled.
466 void MarkAsCanceled() {
[email protected]b59ff372009-07-15 22:04:32467 job_ = NULL;
[email protected]b59ff372009-07-15 22:04:32468 addresses_ = NULL;
[email protected]aa22b242011-11-16 18:58:29469 callback_.Reset();
[email protected]b59ff372009-07-15 22:04:32470 }
471
[email protected]0f292de02012-02-01 22:28:20472 bool was_canceled() const {
[email protected]aa22b242011-11-16 18:58:29473 return callback_.is_null();
[email protected]b59ff372009-07-15 22:04:32474 }
475
476 void set_job(Job* job) {
[email protected]0f292de02012-02-01 22:28:20477 DCHECK(job);
[email protected]b59ff372009-07-15 22:04:32478 // Identify which job the request is waiting on.
479 job_ = job;
480 }
481
[email protected]0f292de02012-02-01 22:28:20482 // Prepare final AddressList and call completion callback.
[email protected]b3601bc22012-02-21 21:23:20483 void OnComplete(int error, const AddressList& addr_list) {
[email protected]b59ff372009-07-15 22:04:32484 if (error == OK)
[email protected]b3601bc22012-02-21 21:23:20485 *addresses_ = CreateAddressListUsingPort(addr_list, info_.port());
[email protected]aa22b242011-11-16 18:58:29486 CompletionCallback callback = callback_;
[email protected]0f292de02012-02-01 22:28:20487 MarkAsCanceled();
[email protected]aa22b242011-11-16 18:58:29488 callback.Run(error);
[email protected]b59ff372009-07-15 22:04:32489 }
490
[email protected]b59ff372009-07-15 22:04:32491 Job* job() const {
492 return job_;
493 }
494
[email protected]0f292de02012-02-01 22:28:20495 // NetLog for the source, passed in HostResolver::Resolve.
[email protected]ee094b82010-08-24 15:55:51496 const BoundNetLog& source_net_log() {
497 return source_net_log_;
498 }
499
[email protected]0f292de02012-02-01 22:28:20500 // NetLog for this request.
[email protected]ee094b82010-08-24 15:55:51501 const BoundNetLog& request_net_log() {
502 return request_net_log_;
[email protected]54e13772009-08-14 03:01:09503 }
504
[email protected]b59ff372009-07-15 22:04:32505 const RequestInfo& info() const {
506 return info_;
507 }
508
509 private:
[email protected]ee094b82010-08-24 15:55:51510 BoundNetLog source_net_log_;
511 BoundNetLog request_net_log_;
[email protected]54e13772009-08-14 03:01:09512
[email protected]b59ff372009-07-15 22:04:32513 // The request info that started the request.
514 RequestInfo info_;
515
[email protected]0f292de02012-02-01 22:28:20516 // The resolve job that this request is dependent on.
[email protected]b59ff372009-07-15 22:04:32517 Job* job_;
518
519 // The user's callback to invoke when the request completes.
[email protected]aa22b242011-11-16 18:58:29520 CompletionCallback callback_;
[email protected]b59ff372009-07-15 22:04:32521
522 // The address list to save result into.
523 AddressList* addresses_;
524
525 DISALLOW_COPY_AND_ASSIGN(Request);
526};
527
[email protected]1e9bbd22010-10-15 16:42:45528//------------------------------------------------------------------------------
529
530// Provide a common macro to simplify code and readability. We must use a
531// macros as the underlying HISTOGRAM macro creates static varibles.
532#define DNS_HISTOGRAM(name, time) UMA_HISTOGRAM_CUSTOM_TIMES(name, time, \
533 base::TimeDelta::FromMicroseconds(1), base::TimeDelta::FromHours(1), 100)
[email protected]b59ff372009-07-15 22:04:32534
[email protected]0f292de02012-02-01 22:28:20535// Calls HostResolverProc on the WorkerPool. Performs retries if necessary.
536//
537// Whenever we try to resolve the host, we post a delayed task to check if host
538// resolution (OnLookupComplete) is completed or not. If the original attempt
539// hasn't completed, then we start another attempt for host resolution. We take
540// the results from the first attempt that finishes and ignore the results from
541// all other attempts.
542//
543// TODO(szym): Move to separate source file for testing and mocking.
544//
545class HostResolverImpl::ProcTask
546 : public base::RefCountedThreadSafe<HostResolverImpl::ProcTask> {
[email protected]b59ff372009-07-15 22:04:32547 public:
[email protected]b3601bc22012-02-21 21:23:20548 typedef base::Callback<void(int net_error,
549 const AddressList& addr_list)> Callback;
[email protected]b59ff372009-07-15 22:04:32550
[email protected]0f292de02012-02-01 22:28:20551 ProcTask(const Key& key,
552 const ProcTaskParams& params,
553 const Callback& callback,
554 const BoundNetLog& job_net_log)
555 : key_(key),
556 params_(params),
557 callback_(callback),
558 origin_loop_(base::MessageLoopProxy::current()),
559 attempt_number_(0),
560 completed_attempt_number_(0),
561 completed_attempt_error_(ERR_UNEXPECTED),
562 had_non_speculative_request_(false),
[email protected]b3601bc22012-02-21 21:23:20563 net_log_(job_net_log) {
[email protected]0f292de02012-02-01 22:28:20564 if (!params_.resolver_proc)
565 params_.resolver_proc = HostResolverProc::GetDefault();
566 // If default is unset, use the system proc.
567 if (!params_.resolver_proc)
568 params_.resolver_proc = new CallSystemHostResolverProc();
[email protected]b59ff372009-07-15 22:04:32569 }
570
[email protected]b59ff372009-07-15 22:04:32571 void Start() {
[email protected]3e9d9cc2011-05-03 21:08:15572 DCHECK(origin_loop_->BelongsToCurrentThread());
[email protected]9c571762012-02-27 19:12:40573 net_log_.BeginEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_PROC_TASK, NULL);
[email protected]189163e2011-05-11 01:48:54574 StartLookupAttempt();
575 }
[email protected]252b699b2010-02-05 21:38:06576
[email protected]0f292de02012-02-01 22:28:20577 // Cancels this ProcTask. It will be orphaned. Any outstanding resolve
578 // attempts running on worker threads will continue running. Only once all the
579 // attempts complete will the final reference to this ProcTask be released.
580 void Cancel() {
581 DCHECK(origin_loop_->BelongsToCurrentThread());
582
583 if (was_canceled())
584 return;
585
[email protected]0f292de02012-02-01 22:28:20586 callback_.Reset();
[email protected]0f292de02012-02-01 22:28:20587 net_log_.EndEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_PROC_TASK, NULL);
588 }
589
590 void set_had_non_speculative_request() {
591 DCHECK(origin_loop_->BelongsToCurrentThread());
592 had_non_speculative_request_ = true;
593 }
594
595 bool was_canceled() const {
596 DCHECK(origin_loop_->BelongsToCurrentThread());
597 return callback_.is_null();
598 }
599
600 bool was_completed() const {
601 DCHECK(origin_loop_->BelongsToCurrentThread());
602 return completed_attempt_number_ > 0;
603 }
604
605 private:
[email protected]189163e2011-05-11 01:48:54606 void StartLookupAttempt() {
607 DCHECK(origin_loop_->BelongsToCurrentThread());
608 base::TimeTicks start_time = base::TimeTicks::Now();
609 ++attempt_number_;
610 // Dispatch the lookup attempt to a worker thread.
611 if (!base::WorkerPool::PostTask(
612 FROM_HERE,
[email protected]0f292de02012-02-01 22:28:20613 base::Bind(&ProcTask::DoLookup, this, start_time, attempt_number_),
[email protected]189163e2011-05-11 01:48:54614 true)) {
[email protected]b59ff372009-07-15 22:04:32615 NOTREACHED();
616
617 // Since we could be running within Resolve() right now, we can't just
618 // call OnLookupComplete(). Instead we must wait until Resolve() has
619 // returned (IO_PENDING).
[email protected]3e9d9cc2011-05-03 21:08:15620 origin_loop_->PostTask(
[email protected]189163e2011-05-11 01:48:54621 FROM_HERE,
[email protected]0f292de02012-02-01 22:28:20622 base::Bind(&ProcTask::OnLookupComplete, this, AddressList(),
[email protected]33152acc2011-10-20 23:37:12623 start_time, attempt_number_, ERR_UNEXPECTED, 0));
[email protected]189163e2011-05-11 01:48:54624 return;
[email protected]b59ff372009-07-15 22:04:32625 }
[email protected]13024882011-05-18 23:19:16626
627 net_log_.AddEvent(
628 NetLog::TYPE_HOST_RESOLVER_IMPL_ATTEMPT_STARTED,
629 make_scoped_refptr(new NetLogIntegerParameter(
630 "attempt_number", attempt_number_)));
631
[email protected]0f292de02012-02-01 22:28:20632 // If we don't get the results within a given time, RetryIfNotComplete
633 // will start a new attempt on a different worker thread if none of our
634 // outstanding attempts have completed yet.
635 if (attempt_number_ <= params_.max_retry_attempts) {
[email protected]06ef6d92011-05-19 04:24:58636 origin_loop_->PostDelayedTask(
637 FROM_HERE,
[email protected]0f292de02012-02-01 22:28:20638 base::Bind(&ProcTask::RetryIfNotComplete, this),
[email protected]bd493ca2012-03-04 07:32:33639 params_.unresponsive_delay.InMilliseconds());
[email protected]06ef6d92011-05-19 04:24:58640 }
[email protected]b59ff372009-07-15 22:04:32641 }
642
[email protected]6c710ee2010-05-07 07:51:16643 // WARNING: This code runs inside a worker pool. The shutdown code cannot
644 // wait for it to finish, so we must be very careful here about using other
645 // objects (like MessageLoops, Singletons, etc). During shutdown these objects
[email protected]189163e2011-05-11 01:48:54646 // may no longer exist. Multiple DoLookups() could be running in parallel, so
647 // any state inside of |this| must not mutate .
648 void DoLookup(const base::TimeTicks& start_time,
649 const uint32 attempt_number) {
650 AddressList results;
651 int os_error = 0;
[email protected]b59ff372009-07-15 22:04:32652 // Running on the worker thread
[email protected]0f292de02012-02-01 22:28:20653 int error = params_.resolver_proc->Resolve(key_.hostname,
654 key_.address_family,
655 key_.host_resolver_flags,
656 &results,
657 &os_error);
[email protected]b59ff372009-07-15 22:04:32658
[email protected]189163e2011-05-11 01:48:54659 origin_loop_->PostTask(
660 FROM_HERE,
[email protected]0f292de02012-02-01 22:28:20661 base::Bind(&ProcTask::OnLookupComplete, this, results, start_time,
[email protected]33152acc2011-10-20 23:37:12662 attempt_number, error, os_error));
[email protected]189163e2011-05-11 01:48:54663 }
664
[email protected]0f292de02012-02-01 22:28:20665 // Makes next attempt if DoLookup() has not finished (runs on origin thread).
666 void RetryIfNotComplete() {
[email protected]189163e2011-05-11 01:48:54667 DCHECK(origin_loop_->BelongsToCurrentThread());
668
[email protected]0f292de02012-02-01 22:28:20669 if (was_completed() || was_canceled())
[email protected]189163e2011-05-11 01:48:54670 return;
671
[email protected]0f292de02012-02-01 22:28:20672 params_.unresponsive_delay *= params_.retry_factor;
[email protected]189163e2011-05-11 01:48:54673 StartLookupAttempt();
[email protected]b59ff372009-07-15 22:04:32674 }
675
676 // Callback for when DoLookup() completes (runs on origin thread).
[email protected]189163e2011-05-11 01:48:54677 void OnLookupComplete(const AddressList& results,
678 const base::TimeTicks& start_time,
679 const uint32 attempt_number,
680 int error,
681 const int os_error) {
[email protected]3e9d9cc2011-05-03 21:08:15682 DCHECK(origin_loop_->BelongsToCurrentThread());
[email protected]189163e2011-05-11 01:48:54683 DCHECK(error || results.head());
684
685 bool was_retry_attempt = attempt_number > 1;
686
[email protected]2d3b7762010-10-09 00:35:47687 // Ideally the following code would be part of host_resolver_proc.cc,
[email protected]b3601bc22012-02-21 21:23:20688 // however it isn't safe to call NetworkChangeNotifier from worker threads.
689 // So we do it here on the IO thread instead.
[email protected]189163e2011-05-11 01:48:54690 if (error != OK && NetworkChangeNotifier::IsOffline())
691 error = ERR_INTERNET_DISCONNECTED;
[email protected]2d3b7762010-10-09 00:35:47692
[email protected]b3601bc22012-02-21 21:23:20693 // If this is the first attempt that is finishing later, then record data
694 // for the first attempt. Won't contaminate with retry attempt's data.
[email protected]189163e2011-05-11 01:48:54695 if (!was_retry_attempt)
696 RecordPerformanceHistograms(start_time, error, os_error);
697
698 RecordAttemptHistograms(start_time, attempt_number, error, os_error);
[email protected]f2d8c4212010-02-02 00:56:35699
[email protected]0f292de02012-02-01 22:28:20700 if (was_canceled())
[email protected]b59ff372009-07-15 22:04:32701 return;
702
[email protected]0f292de02012-02-01 22:28:20703 scoped_refptr<NetLog::EventParameters> params;
704 if (error != OK) {
[email protected]b3601bc22012-02-21 21:23:20705 params = new ProcTaskFailedParams(attempt_number, error, os_error);
[email protected]0f292de02012-02-01 22:28:20706 } else {
[email protected]53b583b2012-02-09 00:10:47707 params = new NetLogIntegerParameter("attempt_number", attempt_number);
[email protected]0f292de02012-02-01 22:28:20708 }
709 net_log_.AddEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_ATTEMPT_FINISHED, params);
710
711 if (was_completed())
712 return;
713
714 // Copy the results from the first worker thread that resolves the host.
715 results_ = results;
716 completed_attempt_number_ = attempt_number;
717 completed_attempt_error_ = error;
718
[email protected]e87b8b512011-06-14 22:12:52719 if (was_retry_attempt) {
720 // If retry attempt finishes before 1st attempt, then get stats on how
721 // much time is saved by having spawned an extra attempt.
722 retry_attempt_finished_time_ = base::TimeTicks::Now();
723 }
724
[email protected]189163e2011-05-11 01:48:54725 if (error != OK) {
[email protected]b3601bc22012-02-21 21:23:20726 params = new ProcTaskFailedParams(0, error, os_error);
[email protected]ee094b82010-08-24 15:55:51727 } else {
728 params = new AddressListNetLogParam(results_);
729 }
[email protected]0f292de02012-02-01 22:28:20730 net_log_.EndEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_PROC_TASK, params);
[email protected]ee094b82010-08-24 15:55:51731
[email protected]b3601bc22012-02-21 21:23:20732 callback_.Run(error, results_);
[email protected]b59ff372009-07-15 22:04:32733 }
734
[email protected]189163e2011-05-11 01:48:54735 void RecordPerformanceHistograms(const base::TimeTicks& start_time,
736 const int error,
737 const int os_error) const {
[email protected]3e9d9cc2011-05-03 21:08:15738 DCHECK(origin_loop_->BelongsToCurrentThread());
[email protected]1e9bbd22010-10-15 16:42:45739 enum Category { // Used in HISTOGRAM_ENUMERATION.
740 RESOLVE_SUCCESS,
741 RESOLVE_FAIL,
742 RESOLVE_SPECULATIVE_SUCCESS,
743 RESOLVE_SPECULATIVE_FAIL,
744 RESOLVE_MAX, // Bounding value.
745 };
746 int category = RESOLVE_MAX; // Illegal value for later DCHECK only.
747
[email protected]189163e2011-05-11 01:48:54748 base::TimeDelta duration = base::TimeTicks::Now() - start_time;
749 if (error == OK) {
[email protected]1e9bbd22010-10-15 16:42:45750 if (had_non_speculative_request_) {
751 category = RESOLVE_SUCCESS;
752 DNS_HISTOGRAM("DNS.ResolveSuccess", duration);
753 } else {
754 category = RESOLVE_SPECULATIVE_SUCCESS;
755 DNS_HISTOGRAM("DNS.ResolveSpeculativeSuccess", duration);
756 }
[email protected]7e96d792011-06-10 17:08:23757
758 // Log DNS lookups based on address_family. This will help us determine
759 // if IPv4 or IPv4/6 lookups are faster or slower.
760 switch(key_.address_family) {
761 case ADDRESS_FAMILY_IPV4:
762 DNS_HISTOGRAM("DNS.ResolveSuccess_FAMILY_IPV4", duration);
763 break;
764 case ADDRESS_FAMILY_IPV6:
765 DNS_HISTOGRAM("DNS.ResolveSuccess_FAMILY_IPV6", duration);
766 break;
767 case ADDRESS_FAMILY_UNSPECIFIED:
768 DNS_HISTOGRAM("DNS.ResolveSuccess_FAMILY_UNSPEC", duration);
769 break;
770 }
[email protected]1e9bbd22010-10-15 16:42:45771 } else {
772 if (had_non_speculative_request_) {
773 category = RESOLVE_FAIL;
774 DNS_HISTOGRAM("DNS.ResolveFail", duration);
775 } else {
776 category = RESOLVE_SPECULATIVE_FAIL;
777 DNS_HISTOGRAM("DNS.ResolveSpeculativeFail", duration);
778 }
[email protected]7e96d792011-06-10 17:08:23779 // Log DNS lookups based on address_family. This will help us determine
780 // if IPv4 or IPv4/6 lookups are faster or slower.
781 switch(key_.address_family) {
782 case ADDRESS_FAMILY_IPV4:
783 DNS_HISTOGRAM("DNS.ResolveFail_FAMILY_IPV4", duration);
784 break;
785 case ADDRESS_FAMILY_IPV6:
786 DNS_HISTOGRAM("DNS.ResolveFail_FAMILY_IPV6", duration);
787 break;
788 case ADDRESS_FAMILY_UNSPECIFIED:
789 DNS_HISTOGRAM("DNS.ResolveFail_FAMILY_UNSPEC", duration);
790 break;
791 }
[email protected]c833e322010-10-16 23:51:36792 UMA_HISTOGRAM_CUSTOM_ENUMERATION(kOSErrorsForGetAddrinfoHistogramName,
[email protected]189163e2011-05-11 01:48:54793 std::abs(os_error),
[email protected]1e9bbd22010-10-15 16:42:45794 GetAllGetAddrinfoOSErrors());
795 }
[email protected]051b6ab2010-10-18 16:50:46796 DCHECK_LT(category, static_cast<int>(RESOLVE_MAX)); // Be sure it was set.
[email protected]1e9bbd22010-10-15 16:42:45797
798 UMA_HISTOGRAM_ENUMERATION("DNS.ResolveCategory", category, RESOLVE_MAX);
799
[email protected]edafd4c2011-05-10 17:18:53800 static const bool show_speculative_experiment_histograms =
801 base::FieldTrialList::TrialExists("DnsImpact");
[email protected]ecd95ae2010-10-20 23:58:17802 if (show_speculative_experiment_histograms) {
[email protected]1e9bbd22010-10-15 16:42:45803 UMA_HISTOGRAM_ENUMERATION(
804 base::FieldTrial::MakeName("DNS.ResolveCategory", "DnsImpact"),
805 category, RESOLVE_MAX);
806 if (RESOLVE_SUCCESS == category) {
807 DNS_HISTOGRAM(base::FieldTrial::MakeName("DNS.ResolveSuccess",
808 "DnsImpact"), duration);
809 }
810 }
[email protected]edafd4c2011-05-10 17:18:53811 static const bool show_parallelism_experiment_histograms =
812 base::FieldTrialList::TrialExists("DnsParallelism");
[email protected]ecd95ae2010-10-20 23:58:17813 if (show_parallelism_experiment_histograms) {
814 UMA_HISTOGRAM_ENUMERATION(
815 base::FieldTrial::MakeName("DNS.ResolveCategory", "DnsParallelism"),
816 category, RESOLVE_MAX);
817 if (RESOLVE_SUCCESS == category) {
818 DNS_HISTOGRAM(base::FieldTrial::MakeName("DNS.ResolveSuccess",
819 "DnsParallelism"), duration);
820 }
821 }
[email protected]1e9bbd22010-10-15 16:42:45822 }
823
[email protected]189163e2011-05-11 01:48:54824 void RecordAttemptHistograms(const base::TimeTicks& start_time,
825 const uint32 attempt_number,
826 const int error,
827 const int os_error) const {
[email protected]0f292de02012-02-01 22:28:20828 DCHECK(origin_loop_->BelongsToCurrentThread());
[email protected]189163e2011-05-11 01:48:54829 bool first_attempt_to_complete =
830 completed_attempt_number_ == attempt_number;
[email protected]e87b8b512011-06-14 22:12:52831 bool is_first_attempt = (attempt_number == 1);
[email protected]1e9bbd22010-10-15 16:42:45832
[email protected]189163e2011-05-11 01:48:54833 if (first_attempt_to_complete) {
834 // If this was first attempt to complete, then record the resolution
835 // status of the attempt.
836 if (completed_attempt_error_ == OK) {
837 UMA_HISTOGRAM_ENUMERATION(
838 "DNS.AttemptFirstSuccess", attempt_number, 100);
839 } else {
840 UMA_HISTOGRAM_ENUMERATION(
841 "DNS.AttemptFirstFailure", attempt_number, 100);
842 }
843 }
844
845 if (error == OK)
846 UMA_HISTOGRAM_ENUMERATION("DNS.AttemptSuccess", attempt_number, 100);
847 else
848 UMA_HISTOGRAM_ENUMERATION("DNS.AttemptFailure", attempt_number, 100);
849
[email protected]e87b8b512011-06-14 22:12:52850 // If first attempt didn't finish before retry attempt, then calculate stats
851 // on how much time is saved by having spawned an extra attempt.
[email protected]0f292de02012-02-01 22:28:20852 if (!first_attempt_to_complete && is_first_attempt && !was_canceled()) {
[email protected]e87b8b512011-06-14 22:12:52853 DNS_HISTOGRAM("DNS.AttemptTimeSavedByRetry",
854 base::TimeTicks::Now() - retry_attempt_finished_time_);
855 }
856
[email protected]0f292de02012-02-01 22:28:20857 if (was_canceled() || !first_attempt_to_complete) {
[email protected]189163e2011-05-11 01:48:54858 // Count those attempts which completed after the job was already canceled
859 // OR after the job was already completed by an earlier attempt (so in
860 // effect).
861 UMA_HISTOGRAM_ENUMERATION("DNS.AttemptDiscarded", attempt_number, 100);
862
[email protected]0f292de02012-02-01 22:28:20863 // Record if job is canceled.
864 if (was_canceled())
[email protected]189163e2011-05-11 01:48:54865 UMA_HISTOGRAM_ENUMERATION("DNS.AttemptCancelled", attempt_number, 100);
866 }
867
868 base::TimeDelta duration = base::TimeTicks::Now() - start_time;
869 if (error == OK)
870 DNS_HISTOGRAM("DNS.AttemptSuccessDuration", duration);
871 else
872 DNS_HISTOGRAM("DNS.AttemptFailDuration", duration);
873 }
[email protected]1e9bbd22010-10-15 16:42:45874
[email protected]b59ff372009-07-15 22:04:32875 // Set on the origin thread, read on the worker thread.
[email protected]123ab1e32009-10-21 19:12:57876 Key key_;
[email protected]b59ff372009-07-15 22:04:32877
[email protected]0f292de02012-02-01 22:28:20878 // Holds an owning reference to the HostResolverProc that we are going to use.
[email protected]b59ff372009-07-15 22:04:32879 // This may not be the current resolver procedure by the time we call
880 // ResolveAddrInfo, but that's OK... we'll use it anyways, and the owning
881 // reference ensures that it remains valid until we are done.
[email protected]0f292de02012-02-01 22:28:20882 ProcTaskParams params_;
[email protected]b59ff372009-07-15 22:04:32883
[email protected]0f292de02012-02-01 22:28:20884 // The listener to the results of this ProcTask.
885 Callback callback_;
886
887 // Used to post ourselves onto the origin thread.
888 scoped_refptr<base::MessageLoopProxy> origin_loop_;
[email protected]189163e2011-05-11 01:48:54889
890 // Keeps track of the number of attempts we have made so far to resolve the
891 // host. Whenever we start an attempt to resolve the host, we increase this
892 // number.
893 uint32 attempt_number_;
894
895 // The index of the attempt which finished first (or 0 if the job is still in
896 // progress).
897 uint32 completed_attempt_number_;
898
899 // The result (a net error code) from the first attempt to complete.
900 int completed_attempt_error_;
[email protected]252b699b2010-02-05 21:38:06901
[email protected]e87b8b512011-06-14 22:12:52902 // The time when retry attempt was finished.
903 base::TimeTicks retry_attempt_finished_time_;
904
[email protected]252b699b2010-02-05 21:38:06905 // True if a non-speculative request was ever attached to this job
[email protected]0f292de02012-02-01 22:28:20906 // (regardless of whether or not it was later canceled.
[email protected]252b699b2010-02-05 21:38:06907 // This boolean is used for histogramming the duration of jobs used to
908 // service non-speculative requests.
909 bool had_non_speculative_request_;
910
[email protected]b59ff372009-07-15 22:04:32911 AddressList results_;
912
[email protected]ee094b82010-08-24 15:55:51913 BoundNetLog net_log_;
914
[email protected]0f292de02012-02-01 22:28:20915 DISALLOW_COPY_AND_ASSIGN(ProcTask);
[email protected]b59ff372009-07-15 22:04:32916};
917
918//-----------------------------------------------------------------------------
919
[email protected]0f292de02012-02-01 22:28:20920// Represents a request to the worker pool for a "probe for IPv6 support" call.
[email protected]b3601bc22012-02-21 21:23:20921//
922// TODO(szym): This could also be replaced with PostTaskAndReply and Callbacks.
[email protected]0f8f1b432010-03-16 19:06:03923class HostResolverImpl::IPv6ProbeJob
924 : public base::RefCountedThreadSafe<HostResolverImpl::IPv6ProbeJob> {
925 public:
926 explicit IPv6ProbeJob(HostResolverImpl* resolver)
927 : resolver_(resolver),
[email protected]edd685f2011-08-15 20:33:46928 origin_loop_(base::MessageLoopProxy::current()) {
[email protected]3e9d9cc2011-05-03 21:08:15929 DCHECK(resolver);
[email protected]0f8f1b432010-03-16 19:06:03930 }
931
932 void Start() {
[email protected]3e9d9cc2011-05-03 21:08:15933 DCHECK(origin_loop_->BelongsToCurrentThread());
[email protected]0f292de02012-02-01 22:28:20934 if (was_canceled())
[email protected]a9af7112010-05-08 00:56:01935 return;
[email protected]f092e64b2010-03-17 00:39:18936 const bool kIsSlow = true;
[email protected]ac9ba8fe2010-12-30 18:08:36937 base::WorkerPool::PostTask(
[email protected]33152acc2011-10-20 23:37:12938 FROM_HERE, base::Bind(&IPv6ProbeJob::DoProbe, this), kIsSlow);
[email protected]0f8f1b432010-03-16 19:06:03939 }
940
941 // Cancels the current job.
942 void Cancel() {
[email protected]3e9d9cc2011-05-03 21:08:15943 DCHECK(origin_loop_->BelongsToCurrentThread());
[email protected]0f292de02012-02-01 22:28:20944 if (was_canceled())
[email protected]a9af7112010-05-08 00:56:01945 return;
[email protected]0f8f1b432010-03-16 19:06:03946 resolver_ = NULL; // Read/write ONLY on origin thread.
[email protected]0f8f1b432010-03-16 19:06:03947 }
948
[email protected]0f8f1b432010-03-16 19:06:03949 private:
950 friend class base::RefCountedThreadSafe<HostResolverImpl::IPv6ProbeJob>;
951
952 ~IPv6ProbeJob() {
953 }
954
[email protected]0f292de02012-02-01 22:28:20955 bool was_canceled() const {
[email protected]3e9d9cc2011-05-03 21:08:15956 DCHECK(origin_loop_->BelongsToCurrentThread());
957 return !resolver_;
[email protected]a9af7112010-05-08 00:56:01958 }
959
[email protected]0f8f1b432010-03-16 19:06:03960 // Run on worker thread.
961 void DoProbe() {
962 // Do actual testing on this thread, as it takes 40-100ms.
963 AddressFamily family = IPv6Supported() ? ADDRESS_FAMILY_UNSPECIFIED
964 : ADDRESS_FAMILY_IPV4;
965
[email protected]3e9d9cc2011-05-03 21:08:15966 origin_loop_->PostTask(
967 FROM_HERE,
[email protected]33152acc2011-10-20 23:37:12968 base::Bind(&IPv6ProbeJob::OnProbeComplete, this, family));
[email protected]0f8f1b432010-03-16 19:06:03969 }
970
[email protected]3e9d9cc2011-05-03 21:08:15971 // Callback for when DoProbe() completes.
[email protected]0f8f1b432010-03-16 19:06:03972 void OnProbeComplete(AddressFamily address_family) {
[email protected]3e9d9cc2011-05-03 21:08:15973 DCHECK(origin_loop_->BelongsToCurrentThread());
[email protected]0f292de02012-02-01 22:28:20974 if (was_canceled())
[email protected]a9af7112010-05-08 00:56:01975 return;
[email protected]a9af7112010-05-08 00:56:01976 resolver_->IPv6ProbeSetDefaultAddressFamily(address_family);
[email protected]0f8f1b432010-03-16 19:06:03977 }
978
[email protected]0f8f1b432010-03-16 19:06:03979 // Used/set only on origin thread.
980 HostResolverImpl* resolver_;
981
982 // Used to post ourselves onto the origin thread.
[email protected]3e9d9cc2011-05-03 21:08:15983 scoped_refptr<base::MessageLoopProxy> origin_loop_;
[email protected]0f8f1b432010-03-16 19:06:03984
985 DISALLOW_COPY_AND_ASSIGN(IPv6ProbeJob);
986};
987
988//-----------------------------------------------------------------------------
989
[email protected]b3601bc22012-02-21 21:23:20990// Resolves the hostname using DnsTransaction.
991// TODO(szym): This could be moved to separate source file as well.
992class HostResolverImpl::DnsTask {
993 public:
994 typedef base::Callback<void(int net_error,
995 const AddressList& addr_list,
996 base::TimeDelta ttl)> Callback;
997
998 DnsTask(DnsTransactionFactory* factory,
999 const Key& key,
1000 const Callback& callback,
1001 const BoundNetLog& job_net_log)
1002 : callback_(callback), net_log_(job_net_log) {
1003 DCHECK(factory);
1004 DCHECK(!callback.is_null());
1005
1006 // For now we treat ADDRESS_FAMILY_UNSPEC as if it was IPV4.
1007 uint16 qtype = (key.address_family == ADDRESS_FAMILY_IPV6)
1008 ? dns_protocol::kTypeAAAA
1009 : dns_protocol::kTypeA;
1010 // TODO(szym): Implement "happy eyeballs".
1011 transaction_ = factory->CreateTransaction(
1012 key.hostname,
1013 qtype,
1014 base::Bind(&DnsTask::OnTransactionComplete, base::Unretained(this)),
1015 net_log_);
1016 DCHECK(transaction_.get());
1017 }
1018
1019 int Start() {
1020 net_log_.BeginEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_DNS_TASK, NULL);
1021 return transaction_->Start();
1022 }
1023
1024 void OnTransactionComplete(DnsTransaction* transaction,
1025 int net_error,
1026 const DnsResponse* response) {
1027 // TODO(szym): Record performance histograms.
1028 // Run |callback_| last since the owning Job will then delete this DnsTask.
1029 DnsResponse::Result result = DnsResponse::DNS_SUCCESS;
1030 if (net_error == OK) {
1031 AddressList addr_list;
1032 base::TimeDelta ttl;
1033 result = response->ParseToAddressList(&addr_list, &ttl);
1034 if (result == DnsResponse::DNS_SUCCESS) {
1035 net_log_.EndEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_DNS_TASK,
1036 new AddressListNetLogParam(addr_list));
1037 callback_.Run(net_error, addr_list, ttl);
1038 return;
1039 }
1040 net_error = ERR_DNS_MALFORMED_RESPONSE;
1041 }
1042 net_log_.EndEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_DNS_TASK,
1043 new DnsTaskFailedParams(net_error, result));
1044 callback_.Run(net_error, AddressList(), base::TimeDelta());
1045 }
1046
1047 private:
1048 // The listener to the results of this DnsTask.
1049 Callback callback_;
1050
1051 const BoundNetLog net_log_;
1052
1053 scoped_ptr<DnsTransaction> transaction_;
1054};
1055
1056//-----------------------------------------------------------------------------
1057
[email protected]0f292de02012-02-01 22:28:201058// Aggregates all Requests for the same Key. Dispatched via PriorityDispatch.
[email protected]0f292de02012-02-01 22:28:201059class HostResolverImpl::Job : public PrioritizedDispatcher::Job {
[email protected]68ad3ee2010-01-30 03:45:391060 public:
[email protected]0f292de02012-02-01 22:28:201061 // Creates new job for |key| where |request_net_log| is bound to the
[email protected]16ee26d2012-03-08 03:34:351062 // request that spawned it.
[email protected]0f292de02012-02-01 22:28:201063 Job(HostResolverImpl* resolver,
1064 const Key& key,
[email protected]16ee26d2012-03-08 03:34:351065 const BoundNetLog& request_net_log)
[email protected]0f292de02012-02-01 22:28:201066 : resolver_(resolver->AsWeakPtr()),
1067 key_(key),
[email protected]0f292de02012-02-01 22:28:201068 had_non_speculative_request_(false),
1069 net_log_(BoundNetLog::Make(request_net_log.net_log(),
[email protected]b3601bc22012-02-21 21:23:201070 NetLog::SOURCE_HOST_RESOLVER_IMPL_JOB)) {
[email protected]0f292de02012-02-01 22:28:201071 request_net_log.AddEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_CREATE_JOB, NULL);
1072
1073 net_log_.BeginEvent(
1074 NetLog::TYPE_HOST_RESOLVER_IMPL_JOB,
1075 make_scoped_refptr(new JobCreationParameters(
1076 key_.hostname, request_net_log.source())));
[email protected]68ad3ee2010-01-30 03:45:391077 }
1078
[email protected]0f292de02012-02-01 22:28:201079 virtual ~Job() {
[email protected]b3601bc22012-02-21 21:23:201080 if (is_running()) {
1081 // |resolver_| was destroyed with this Job still in flight.
1082 // Clean-up, record in the log, but don't run any callbacks.
1083 if (is_proc_running()) {
[email protected]0f292de02012-02-01 22:28:201084 proc_task_->Cancel();
1085 proc_task_ = NULL;
[email protected]0f292de02012-02-01 22:28:201086 }
[email protected]16ee26d2012-03-08 03:34:351087 // Clean up now for nice NetLog.
1088 dns_task_.reset(NULL);
[email protected]b3601bc22012-02-21 21:23:201089 net_log_.EndEventWithNetErrorCode(NetLog::TYPE_HOST_RESOLVER_IMPL_JOB,
1090 ERR_ABORTED);
1091 } else if (is_queued()) {
[email protected]57a48d32012-03-03 00:04:551092 // |resolver_| was destroyed without running this Job.
[email protected]16ee26d2012-03-08 03:34:351093 // TODO(szym): is there any benefit in having this distinction?
[email protected]b3601bc22012-02-21 21:23:201094 net_log_.AddEvent(NetLog::TYPE_CANCELLED, NULL);
1095 net_log_.EndEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_JOB, NULL);
[email protected]68ad3ee2010-01-30 03:45:391096 }
[email protected]b3601bc22012-02-21 21:23:201097 // else CompleteRequests logged EndEvent.
[email protected]68ad3ee2010-01-30 03:45:391098
[email protected]b3601bc22012-02-21 21:23:201099 // Log any remaining Requests as cancelled.
1100 for (RequestsList::const_iterator it = requests_.begin();
1101 it != requests_.end(); ++it) {
1102 Request* req = *it;
1103 if (req->was_canceled())
1104 continue;
1105 DCHECK_EQ(this, req->job());
1106 LogCancelRequest(req->source_net_log(), req->request_net_log(),
1107 req->info());
1108 }
1109 STLDeleteElements(&requests_);
[email protected]68ad3ee2010-01-30 03:45:391110 }
1111
[email protected]16ee26d2012-03-08 03:34:351112 const Key key() const {
[email protected]0f292de02012-02-01 22:28:201113 return key_;
1114 }
1115
[email protected]b3601bc22012-02-21 21:23:201116 bool is_queued() const {
1117 return !handle_.is_null();
[email protected]0f292de02012-02-01 22:28:201118 }
1119
[email protected]16ee26d2012-03-08 03:34:351120 bool is_running() const {
1121 return is_dns_running() || is_proc_running();
1122 }
1123
1124 // Add this job to the dispatcher.
1125 void Schedule(RequestPriority priority) {
1126 handle_ = resolver_->dispatcher_.Add(this, priority);
1127 }
1128
[email protected]b3601bc22012-02-21 21:23:201129 void AddRequest(scoped_ptr<Request> req) {
[email protected]0f292de02012-02-01 22:28:201130 DCHECK_EQ(key_.hostname, req->info().hostname());
1131
1132 req->set_job(this);
[email protected]0f292de02012-02-01 22:28:201133 priority_tracker_.Add(req->info().priority());
1134
1135 req->request_net_log().AddEvent(
1136 NetLog::TYPE_HOST_RESOLVER_IMPL_JOB_ATTACH,
1137 make_scoped_refptr(new NetLogSourceParameter(
1138 "source_dependency", net_log_.source())));
1139
1140 net_log_.AddEvent(
1141 NetLog::TYPE_HOST_RESOLVER_IMPL_JOB_REQUEST_ATTACH,
1142 make_scoped_refptr(new JobAttachParameters(
1143 req->request_net_log().source(), priority())));
1144
1145 // TODO(szym): Check if this is still needed.
1146 if (!req->info().is_speculative()) {
1147 had_non_speculative_request_ = true;
1148 if (proc_task_)
1149 proc_task_->set_had_non_speculative_request();
[email protected]68ad3ee2010-01-30 03:45:391150 }
[email protected]b3601bc22012-02-21 21:23:201151
1152 requests_.push_back(req.release());
1153
[email protected]16ee26d2012-03-08 03:34:351154 if (is_queued())
[email protected]b3601bc22012-02-21 21:23:201155 handle_ = resolver_->dispatcher_.ChangePriority(handle_, priority());
[email protected]68ad3ee2010-01-30 03:45:391156 }
1157
[email protected]16ee26d2012-03-08 03:34:351158 // Marks |req| as cancelled. If it was the last active Request, also finishes
1159 // this Job marking it either as aborted or cancelled, and deletes it.
[email protected]0f292de02012-02-01 22:28:201160 void CancelRequest(Request* req) {
1161 DCHECK_EQ(key_.hostname, req->info().hostname());
1162 DCHECK(!req->was_canceled());
[email protected]16ee26d2012-03-08 03:34:351163
[email protected]0f292de02012-02-01 22:28:201164 // Don't remove it from |requests_| just mark it canceled.
1165 req->MarkAsCanceled();
1166 LogCancelRequest(req->source_net_log(), req->request_net_log(),
1167 req->info());
[email protected]16ee26d2012-03-08 03:34:351168
[email protected]0f292de02012-02-01 22:28:201169 priority_tracker_.Remove(req->info().priority());
1170 net_log_.AddEvent(
1171 NetLog::TYPE_HOST_RESOLVER_IMPL_JOB_REQUEST_DETACH,
1172 make_scoped_refptr(new JobAttachParameters(
1173 req->request_net_log().source(), priority())));
[email protected]b3601bc22012-02-21 21:23:201174
[email protected]16ee26d2012-03-08 03:34:351175 if (num_active_requests() > 0) {
1176 if (is_queued())
[email protected]b3601bc22012-02-21 21:23:201177 handle_ = resolver_->dispatcher_.ChangePriority(handle_, priority());
[email protected]16ee26d2012-03-08 03:34:351178 } else {
1179 // If we were called from a Request's callback within CompleteRequests,
1180 // that Request could not have been cancelled, so num_active_requests()
1181 // could not be 0. Therefore, we are not in CompleteRequests().
1182 CompleteRequests(OK, AddressList(), base::TimeDelta());
[email protected]b3601bc22012-02-21 21:23:201183 }
[email protected]68ad3ee2010-01-30 03:45:391184 }
1185
[email protected]16ee26d2012-03-08 03:34:351186 // Called from AbortAllInProgressJobs. Completes all requests as aborted
1187 // and destroys the job.
[email protected]0f292de02012-02-01 22:28:201188 void Abort() {
[email protected]0f292de02012-02-01 22:28:201189 DCHECK(is_running());
[email protected]b3601bc22012-02-21 21:23:201190 CompleteRequests(ERR_ABORTED, AddressList(), base::TimeDelta());
1191 }
1192
[email protected]16ee26d2012-03-08 03:34:351193 // Called by HostResolverImpl when this job is evicted due to queue overflow.
1194 // Completes all requests and destroys the job.
1195 void OnEvicted() {
1196 DCHECK(!is_running());
1197 DCHECK(is_queued());
1198 handle_.Reset();
1199
1200 net_log_.AddEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_JOB_EVICTED, NULL);
1201
1202 // This signals to CompleteRequests that this job never ran.
1203 CompleteRequests(ERR_HOST_RESOLVER_QUEUE_TOO_LARGE,
1204 AddressList(),
1205 base::TimeDelta());
1206 }
1207
1208 private:
1209 RequestPriority priority() const {
1210 return priority_tracker_.highest_priority();
1211 }
1212
1213 // Number of non-canceled requests in |requests_|.
1214 size_t num_active_requests() const {
1215 return priority_tracker_.total_count();
1216 }
1217
[email protected]b3601bc22012-02-21 21:23:201218 bool is_dns_running() const {
1219 return dns_task_.get() != NULL;
1220 }
1221
1222 bool is_proc_running() const {
1223 return proc_task_.get() != NULL;
[email protected]35ddc282010-09-21 23:42:061224 }
1225
[email protected]16ee26d2012-03-08 03:34:351226 // PriorityDispatch::Job:
[email protected]0f292de02012-02-01 22:28:201227 virtual void Start() OVERRIDE {
1228 DCHECK(!is_running());
[email protected]b3601bc22012-02-21 21:23:201229 handle_.Reset();
[email protected]0f292de02012-02-01 22:28:201230
1231 net_log_.AddEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_JOB_STARTED, NULL);
1232
[email protected]16ee26d2012-03-08 03:34:351233 // Job::Start must not complete synchronously.
[email protected]b3601bc22012-02-21 21:23:201234 if (resolver_->dns_transaction_factory_.get()) {
1235 StartDnsTask();
1236 } else {
1237 StartProcTask();
1238 }
1239 }
1240
[email protected]b3601bc22012-02-21 21:23:201241 // TODO(szym): Since DnsTransaction does not consume threads, we can increase
1242 // the limits on |dispatcher_|. But in order to keep the number of WorkerPool
1243 // threads low, we will need to use an "inner" PrioritizedDispatcher with
1244 // tighter limits.
1245 void StartProcTask() {
[email protected]16ee26d2012-03-08 03:34:351246 DCHECK(!is_dns_running());
[email protected]0f292de02012-02-01 22:28:201247 proc_task_ = new ProcTask(
1248 key_,
1249 resolver_->proc_params_,
1250 base::Bind(&Job::OnProcTaskComplete, base::Unretained(this)),
1251 net_log_);
1252
1253 if (had_non_speculative_request_)
1254 proc_task_->set_had_non_speculative_request();
1255 // Start() could be called from within Resolve(), hence it must NOT directly
1256 // call OnProcTaskComplete, for example, on synchronous failure.
1257 proc_task_->Start();
[email protected]68ad3ee2010-01-30 03:45:391258 }
1259
[email protected]0f292de02012-02-01 22:28:201260 // Called by ProcTask when it completes.
[email protected]b3601bc22012-02-21 21:23:201261 void OnProcTaskComplete(int net_error, const AddressList& addr_list) {
1262 DCHECK(is_proc_running());
[email protected]68ad3ee2010-01-30 03:45:391263
[email protected]b3601bc22012-02-21 21:23:201264 base::TimeDelta ttl = base::TimeDelta::FromSeconds(
1265 kNegativeCacheEntryTTLSeconds);
1266 if (net_error == OK)
1267 ttl = base::TimeDelta::FromSeconds(kCacheEntryTTLSeconds);
[email protected]68ad3ee2010-01-30 03:45:391268
[email protected]16ee26d2012-03-08 03:34:351269 CompleteRequests(net_error, addr_list, ttl);
[email protected]b3601bc22012-02-21 21:23:201270 }
1271
1272 void StartDnsTask() {
1273 dns_task_.reset(new DnsTask(
1274 resolver_->dns_transaction_factory_.get(),
1275 key_,
1276 base::Bind(&Job::OnDnsTaskComplete, base::Unretained(this)),
1277 net_log_));
1278
1279 int rv = dns_task_->Start();
1280 if (rv != ERR_IO_PENDING) {
1281 DCHECK_NE(OK, rv);
1282 dns_task_.reset();
1283 StartProcTask();
1284 }
1285 }
1286
1287 // Called by DnsTask when it completes.
1288 void OnDnsTaskComplete(int net_error,
1289 const AddressList& addr_list,
1290 base::TimeDelta ttl) {
1291 DCHECK(is_dns_running());
[email protected]b3601bc22012-02-21 21:23:201292
1293 if (net_error != OK) {
[email protected]16ee26d2012-03-08 03:34:351294 dns_task_.reset();
[email protected]b3601bc22012-02-21 21:23:201295 // TODO(szym): Some net errors indicate lack of connectivity. Starting
1296 // ProcTask in that case is a waste of time.
1297 StartProcTask();
1298 return;
1299 }
1300
[email protected]16ee26d2012-03-08 03:34:351301 CompleteRequests(net_error, addr_list, ttl);
[email protected]b3601bc22012-02-21 21:23:201302 }
1303
[email protected]16ee26d2012-03-08 03:34:351304 // Performs Job's last rites. Completes all Requests. Deletes this.
[email protected]b3601bc22012-02-21 21:23:201305 void CompleteRequests(int net_error,
1306 const AddressList& addr_list,
1307 base::TimeDelta ttl) {
1308 CHECK(resolver_);
[email protected]b3601bc22012-02-21 21:23:201309
[email protected]16ee26d2012-03-08 03:34:351310 // This job must be removed from resolver's |jobs_| now to make room for a
1311 // new job with the same key in case one of the OnComplete callbacks decides
1312 // to spawn one. Consequently, the job deletes itself when CompleteRequests
1313 // is done.
1314 scoped_ptr<Job> self_deleter(this);
1315
1316 resolver_->RemoveJob(this);
1317
1318 // |addr_list| will be destroyed once we destroy |proc_task_| and
1319 // |dns_task_|.
[email protected]b3601bc22012-02-21 21:23:201320 AddressList list = addr_list;
[email protected]16ee26d2012-03-08 03:34:351321
1322 if (is_running()) {
1323 DCHECK(!is_queued());
1324 if (is_proc_running()) {
1325 proc_task_->Cancel();
1326 proc_task_ = NULL;
1327 }
1328 dns_task_.reset();
1329
1330 // Signal dispatcher that a slot has opened.
1331 resolver_->dispatcher_.OnJobFinished();
1332 } else if (is_queued()) {
1333 resolver_->dispatcher_.Cancel(handle_);
1334 handle_.Reset();
1335 }
1336
1337 if (num_active_requests() == 0) {
1338 net_log_.AddEvent(NetLog::TYPE_CANCELLED, NULL);
1339 net_log_.EndEventWithNetErrorCode(NetLog::TYPE_HOST_RESOLVER_IMPL_JOB,
1340 OK);
1341 return;
1342 }
[email protected]b3601bc22012-02-21 21:23:201343
1344 net_log_.EndEventWithNetErrorCode(NetLog::TYPE_HOST_RESOLVER_IMPL_JOB,
1345 net_error);
[email protected]68ad3ee2010-01-30 03:45:391346
[email protected]16ee26d2012-03-08 03:34:351347 // We are the only consumer of |list|, so we can safely change the port
1348 // without copy-on-write. This pays off, when job has only one request.
1349 if (net_error == OK && !requests_.empty())
1350 MutableSetPort(requests_.front()->info().port(), &list);
1351
1352 if ((net_error != ERR_ABORTED) &&
1353 (net_error != ERR_HOST_RESOLVER_QUEUE_TOO_LARGE)) {
1354 resolver_->CacheResult(key_, net_error, list, ttl);
1355 }
1356
[email protected]0f292de02012-02-01 22:28:201357 // Complete all of the requests that were attached to the job.
1358 for (RequestsList::const_iterator it = requests_.begin();
1359 it != requests_.end(); ++it) {
1360 Request* req = *it;
1361
1362 if (req->was_canceled())
1363 continue;
1364
1365 DCHECK_EQ(this, req->job());
1366 // Update the net log and notify registered observers.
1367 LogFinishRequest(req->source_net_log(), req->request_net_log(),
[email protected]b3601bc22012-02-21 21:23:201368 req->info(), net_error);
[email protected]0f292de02012-02-01 22:28:201369
[email protected]b3601bc22012-02-21 21:23:201370 req->OnComplete(net_error, list);
[email protected]0f292de02012-02-01 22:28:201371
1372 // Check if the resolver was destroyed as a result of running the
1373 // callback. If it was, we could continue, but we choose to bail.
1374 if (!resolver_)
1375 return;
1376 }
1377 }
1378
[email protected]0f292de02012-02-01 22:28:201379 base::WeakPtr<HostResolverImpl> resolver_;
1380
1381 Key key_;
1382
1383 // Tracks the highest priority across |requests_|.
1384 PriorityTracker priority_tracker_;
1385
1386 bool had_non_speculative_request_;
1387
1388 BoundNetLog net_log_;
1389
[email protected]b3601bc22012-02-21 21:23:201390 // Resolves the host using a HostResolverProc.
[email protected]0f292de02012-02-01 22:28:201391 scoped_refptr<ProcTask> proc_task_;
1392
[email protected]b3601bc22012-02-21 21:23:201393 // Resolves the host using a DnsTransaction.
1394 scoped_ptr<DnsTask> dns_task_;
1395
[email protected]0f292de02012-02-01 22:28:201396 // All Requests waiting for the result of this Job. Some can be canceled.
1397 RequestsList requests_;
1398
[email protected]16ee26d2012-03-08 03:34:351399 // A handle used in |HostResolverImpl::dispatcher_|.
[email protected]0f292de02012-02-01 22:28:201400 PrioritizedDispatcher::Handle handle_;
[email protected]68ad3ee2010-01-30 03:45:391401};
1402
1403//-----------------------------------------------------------------------------
1404
[email protected]0f292de02012-02-01 22:28:201405HostResolverImpl::ProcTaskParams::ProcTaskParams(
[email protected]e95d3aca2010-01-11 22:47:431406 HostResolverProc* resolver_proc,
[email protected]0f292de02012-02-01 22:28:201407 size_t max_retry_attempts)
1408 : resolver_proc(resolver_proc),
1409 max_retry_attempts(max_retry_attempts),
1410 unresponsive_delay(base::TimeDelta::FromMilliseconds(6000)),
1411 retry_factor(2) {
1412}
1413
1414HostResolverImpl::ProcTaskParams::~ProcTaskParams() {}
1415
1416HostResolverImpl::HostResolverImpl(
[email protected]e95d3aca2010-01-11 22:47:431417 HostCache* cache,
[email protected]0f292de02012-02-01 22:28:201418 const PrioritizedDispatcher::Limits& job_limits,
1419 const ProcTaskParams& proc_params,
[email protected]b3601bc22012-02-21 21:23:201420 scoped_ptr<DnsConfigService> dns_config_service,
[email protected]ee094b82010-08-24 15:55:511421 NetLog* net_log)
[email protected]112bd462009-12-10 07:23:401422 : cache_(cache),
[email protected]0f292de02012-02-01 22:28:201423 dispatcher_(job_limits),
1424 max_queued_jobs_(job_limits.total_jobs * 100u),
1425 proc_params_(proc_params),
[email protected]0c7798452009-10-26 17:59:511426 default_address_family_(ADDRESS_FAMILY_UNSPECIFIED),
[email protected]b3601bc22012-02-21 21:23:201427 dns_config_service_(dns_config_service.Pass()),
[email protected]2f3bc65c2010-07-23 17:47:101428 ipv6_probe_monitoring_(false),
[email protected]ee094b82010-08-24 15:55:511429 additional_resolver_flags_(0),
1430 net_log_(net_log) {
[email protected]0f292de02012-02-01 22:28:201431
1432 DCHECK_GE(dispatcher_.num_priorities(), static_cast<size_t>(NUM_PRIORITIES));
[email protected]68ad3ee2010-01-30 03:45:391433
[email protected]06ef6d92011-05-19 04:24:581434 // Maximum of 4 retry attempts for host resolution.
1435 static const size_t kDefaultMaxRetryAttempts = 4u;
1436
[email protected]0f292de02012-02-01 22:28:201437 if (proc_params_.max_retry_attempts == HostResolver::kDefaultRetryAttempts)
1438 proc_params_.max_retry_attempts = kDefaultMaxRetryAttempts;
[email protected]68ad3ee2010-01-30 03:45:391439
[email protected]b59ff372009-07-15 22:04:321440#if defined(OS_WIN)
1441 EnsureWinsockInit();
1442#endif
[email protected]23f771162011-06-02 18:37:511443#if defined(OS_POSIX) && !defined(OS_MACOSX)
[email protected]2f3bc65c2010-07-23 17:47:101444 if (HaveOnlyLoopbackAddresses())
1445 additional_resolver_flags_ |= HOST_RESOLVER_LOOPBACK_ONLY;
1446#endif
[email protected]232a5812011-03-04 22:42:081447 NetworkChangeNotifier::AddIPAddressObserver(this);
[email protected]46018c9d2011-09-06 03:42:341448#if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_OPENBSD)
[email protected]ae7c9f42011-11-21 11:41:161449#if !defined(OS_ANDROID)
[email protected]46018c9d2011-09-06 03:42:341450 EnsureDnsReloaderInit();
[email protected]ae7c9f42011-11-21 11:41:161451#endif
[email protected]46018c9d2011-09-06 03:42:341452 NetworkChangeNotifier::AddDNSObserver(this);
1453#endif
[email protected]b3601bc22012-02-21 21:23:201454
1455 if (dns_config_service_.get())
1456 dns_config_service_->AddObserver(this);
[email protected]b59ff372009-07-15 22:04:321457}
1458
1459HostResolverImpl::~HostResolverImpl() {
[email protected]0f8f1b432010-03-16 19:06:031460 DiscardIPv6ProbeJob();
1461
[email protected]0f292de02012-02-01 22:28:201462 // This will also cancel all outstanding requests.
1463 STLDeleteValues(&jobs_);
[email protected]e95d3aca2010-01-11 22:47:431464
[email protected]232a5812011-03-04 22:42:081465 NetworkChangeNotifier::RemoveIPAddressObserver(this);
[email protected]46018c9d2011-09-06 03:42:341466#if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_OPENBSD)
1467 NetworkChangeNotifier::RemoveDNSObserver(this);
1468#endif
[email protected]b59ff372009-07-15 22:04:321469}
1470
[email protected]0f292de02012-02-01 22:28:201471void HostResolverImpl::SetMaxQueuedJobs(size_t value) {
1472 DCHECK_EQ(0u, dispatcher_.num_queued_jobs());
1473 DCHECK_GT(value, 0u);
1474 max_queued_jobs_ = value;
[email protected]be1a48b2011-01-20 00:12:131475}
1476
[email protected]684970b2009-08-14 04:54:461477int HostResolverImpl::Resolve(const RequestInfo& info,
[email protected]b59ff372009-07-15 22:04:321478 AddressList* addresses,
[email protected]aa22b242011-11-16 18:58:291479 const CompletionCallback& callback,
[email protected]684970b2009-08-14 04:54:461480 RequestHandle* out_req,
[email protected]ee094b82010-08-24 15:55:511481 const BoundNetLog& source_net_log) {
[email protected]95a214c2011-08-04 21:50:401482 DCHECK(addresses);
[email protected]1ac6af92010-06-03 21:00:141483 DCHECK(CalledOnValidThread());
[email protected]aa22b242011-11-16 18:58:291484 DCHECK_EQ(false, callback.is_null());
[email protected]1ac6af92010-06-03 21:00:141485
[email protected]ee094b82010-08-24 15:55:511486 // Make a log item for the request.
1487 BoundNetLog request_net_log = BoundNetLog::Make(net_log_,
1488 NetLog::SOURCE_HOST_RESOLVER_IMPL_REQUEST);
1489
[email protected]0f292de02012-02-01 22:28:201490 LogStartRequest(source_net_log, request_net_log, info);
[email protected]b59ff372009-07-15 22:04:321491
[email protected]123ab1e32009-10-21 19:12:571492 // Build a key that identifies the request in the cache and in the
1493 // outstanding jobs map.
[email protected]137af622010-02-05 02:14:351494 Key key = GetEffectiveKeyForRequest(info);
[email protected]123ab1e32009-10-21 19:12:571495
[email protected]287d7c22011-11-15 17:34:251496 int rv = ResolveHelper(key, info, addresses, request_net_log);
[email protected]95a214c2011-08-04 21:50:401497 if (rv != ERR_DNS_CACHE_MISS) {
[email protected]b3601bc22012-02-21 21:23:201498 LogFinishRequest(source_net_log, request_net_log, info, rv);
[email protected]95a214c2011-08-04 21:50:401499 return rv;
[email protected]38368712011-03-02 08:09:401500 }
1501
[email protected]0f292de02012-02-01 22:28:201502 // Next we need to attach our request to a "job". This job is responsible for
1503 // calling "getaddrinfo(hostname)" on a worker thread.
1504
1505 JobMap::iterator jobit = jobs_.find(key);
1506 Job* job;
1507 if (jobit == jobs_.end()) {
1508 // Create new Job.
[email protected]16ee26d2012-03-08 03:34:351509 job = new Job(this, key, request_net_log);
1510 job->Schedule(info.priority());
[email protected]0f292de02012-02-01 22:28:201511
1512 // Check for queue overflow.
1513 if (dispatcher_.num_queued_jobs() > max_queued_jobs_) {
1514 Job* evicted = static_cast<Job*>(dispatcher_.EvictOldestLowest());
1515 DCHECK(evicted);
[email protected]16ee26d2012-03-08 03:34:351516 evicted->OnEvicted(); // Deletes |evicted|.
[email protected]0f292de02012-02-01 22:28:201517 if (evicted == job) {
[email protected]0f292de02012-02-01 22:28:201518 rv = ERR_HOST_RESOLVER_QUEUE_TOO_LARGE;
[email protected]b3601bc22012-02-21 21:23:201519 LogFinishRequest(source_net_log, request_net_log, info, rv);
[email protected]0f292de02012-02-01 22:28:201520 return rv;
1521 }
[email protected]0f292de02012-02-01 22:28:201522 }
[email protected]0f292de02012-02-01 22:28:201523 jobs_.insert(jobit, std::make_pair(key, job));
1524 } else {
1525 job = jobit->second;
1526 }
1527
1528 // Can't complete synchronously. Create and attach request.
[email protected]b3601bc22012-02-21 21:23:201529 scoped_ptr<Request> req(new Request(source_net_log,
1530 request_net_log,
1531 info,
1532 callback,
1533 addresses));
[email protected]b59ff372009-07-15 22:04:321534 if (out_req)
[email protected]b3601bc22012-02-21 21:23:201535 *out_req = reinterpret_cast<RequestHandle>(req.get());
[email protected]b59ff372009-07-15 22:04:321536
[email protected]b3601bc22012-02-21 21:23:201537 job->AddRequest(req.Pass());
[email protected]0f292de02012-02-01 22:28:201538 // Completion happens during Job::CompleteRequests().
[email protected]b59ff372009-07-15 22:04:321539 return ERR_IO_PENDING;
1540}
1541
[email protected]287d7c22011-11-15 17:34:251542int HostResolverImpl::ResolveHelper(const Key& key,
[email protected]95a214c2011-08-04 21:50:401543 const RequestInfo& info,
1544 AddressList* addresses,
[email protected]20cd5332011-10-12 22:38:001545 const BoundNetLog& request_net_log) {
[email protected]95a214c2011-08-04 21:50:401546 // The result of |getaddrinfo| for empty hosts is inconsistent across systems.
1547 // On Windows it gives the default interface's address, whereas on Linux it
1548 // gives an error. We will make it fail on all platforms for consistency.
1549 if (info.hostname().empty() || info.hostname().size() > kMaxHostLength)
1550 return ERR_NAME_NOT_RESOLVED;
1551
1552 int net_error = ERR_UNEXPECTED;
1553 if (ResolveAsIP(key, info, &net_error, addresses))
1554 return net_error;
1555 net_error = ERR_DNS_CACHE_MISS;
1556 ServeFromCache(key, info, request_net_log, &net_error, addresses);
1557 return net_error;
1558}
1559
1560int HostResolverImpl::ResolveFromCache(const RequestInfo& info,
1561 AddressList* addresses,
1562 const BoundNetLog& source_net_log) {
1563 DCHECK(CalledOnValidThread());
1564 DCHECK(addresses);
1565
[email protected]95a214c2011-08-04 21:50:401566 // Make a log item for the request.
1567 BoundNetLog request_net_log = BoundNetLog::Make(net_log_,
1568 NetLog::SOURCE_HOST_RESOLVER_IMPL_REQUEST);
1569
1570 // Update the net log and notify registered observers.
[email protected]0f292de02012-02-01 22:28:201571 LogStartRequest(source_net_log, request_net_log, info);
[email protected]95a214c2011-08-04 21:50:401572
[email protected]95a214c2011-08-04 21:50:401573 Key key = GetEffectiveKeyForRequest(info);
1574
[email protected]287d7c22011-11-15 17:34:251575 int rv = ResolveHelper(key, info, addresses, request_net_log);
[email protected]b3601bc22012-02-21 21:23:201576 LogFinishRequest(source_net_log, request_net_log, info, rv);
[email protected]95a214c2011-08-04 21:50:401577 return rv;
1578}
1579
[email protected]b59ff372009-07-15 22:04:321580void HostResolverImpl::CancelRequest(RequestHandle req_handle) {
[email protected]1ac6af92010-06-03 21:00:141581 DCHECK(CalledOnValidThread());
[email protected]b59ff372009-07-15 22:04:321582 Request* req = reinterpret_cast<Request*>(req_handle);
1583 DCHECK(req);
[email protected]0f292de02012-02-01 22:28:201584 Job* job = req->job();
1585 DCHECK(job);
[email protected]0f292de02012-02-01 22:28:201586 job->CancelRequest(req);
[email protected]b59ff372009-07-15 22:04:321587}
1588
[email protected]0f8f1b432010-03-16 19:06:031589void HostResolverImpl::SetDefaultAddressFamily(AddressFamily address_family) {
[email protected]1ac6af92010-06-03 21:00:141590 DCHECK(CalledOnValidThread());
[email protected]0f8f1b432010-03-16 19:06:031591 ipv6_probe_monitoring_ = false;
1592 DiscardIPv6ProbeJob();
1593 default_address_family_ = address_family;
1594}
1595
[email protected]f7d310e2010-10-07 16:25:111596AddressFamily HostResolverImpl::GetDefaultAddressFamily() const {
1597 return default_address_family_;
1598}
1599
[email protected]a78f4272011-10-21 19:16:331600void HostResolverImpl::ProbeIPv6Support() {
1601 DCHECK(CalledOnValidThread());
1602 DCHECK(!ipv6_probe_monitoring_);
1603 ipv6_probe_monitoring_ = true;
1604 OnIPAddressChanged(); // Give initial setup call.
[email protected]ddb1e5a2010-12-13 20:10:451605}
1606
[email protected]489d1a82011-10-12 03:09:111607HostCache* HostResolverImpl::GetHostCache() {
1608 return cache_.get();
1609}
[email protected]95a214c2011-08-04 21:50:401610
1611bool HostResolverImpl::ResolveAsIP(const Key& key,
1612 const RequestInfo& info,
1613 int* net_error,
1614 AddressList* addresses) {
1615 DCHECK(addresses);
1616 DCHECK(net_error);
1617 IPAddressNumber ip_number;
1618 if (!ParseIPLiteralToNumber(key.hostname, &ip_number))
1619 return false;
1620
1621 DCHECK_EQ(key.host_resolver_flags &
1622 ~(HOST_RESOLVER_CANONNAME | HOST_RESOLVER_LOOPBACK_ONLY |
1623 HOST_RESOLVER_DEFAULT_FAMILY_SET_DUE_TO_NO_IPV6),
1624 0) << " Unhandled flag";
[email protected]0f292de02012-02-01 22:28:201625 bool ipv6_disabled = (default_address_family_ == ADDRESS_FAMILY_IPV4) &&
1626 !ipv6_probe_monitoring_;
[email protected]95a214c2011-08-04 21:50:401627 *net_error = OK;
[email protected]0f292de02012-02-01 22:28:201628 if ((ip_number.size() == kIPv6AddressSize) && ipv6_disabled) {
[email protected]95a214c2011-08-04 21:50:401629 *net_error = ERR_NAME_NOT_RESOLVED;
1630 } else {
1631 *addresses = AddressList::CreateFromIPAddressWithCname(
1632 ip_number, info.port(),
1633 (key.host_resolver_flags & HOST_RESOLVER_CANONNAME));
1634 }
1635 return true;
1636}
1637
1638bool HostResolverImpl::ServeFromCache(const Key& key,
1639 const RequestInfo& info,
1640 const BoundNetLog& request_net_log,
1641 int* net_error,
1642 AddressList* addresses) {
1643 DCHECK(addresses);
1644 DCHECK(net_error);
1645 if (!info.allow_cached_response() || !cache_.get())
1646 return false;
1647
1648 const HostCache::Entry* cache_entry = cache_->Lookup(
1649 key, base::TimeTicks::Now());
1650 if (!cache_entry)
1651 return false;
1652
1653 request_net_log.AddEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_CACHE_HIT, NULL);
1654 *net_error = cache_entry->error;
1655 if (*net_error == OK)
1656 *addresses = CreateAddressListUsingPort(cache_entry->addrlist, info.port());
1657 return true;
1658}
1659
[email protected]16ee26d2012-03-08 03:34:351660void HostResolverImpl::CacheResult(const Key& key,
1661 int net_error,
1662 const AddressList& addr_list,
1663 base::TimeDelta ttl) {
1664 if (cache_.get())
1665 cache_->Set(key, net_error, addr_list, base::TimeTicks::Now(), ttl);
[email protected]ef4c40c2010-09-01 14:42:031666}
1667
[email protected]0f292de02012-02-01 22:28:201668void HostResolverImpl::RemoveJob(Job* job) {
1669 DCHECK(job);
[email protected]16ee26d2012-03-08 03:34:351670 JobMap::iterator it = jobs_.find(job->key());
1671 if (it != jobs_.end() && it->second == job)
1672 jobs_.erase(it);
[email protected]b59ff372009-07-15 22:04:321673}
1674
[email protected]0f8f1b432010-03-16 19:06:031675void HostResolverImpl::DiscardIPv6ProbeJob() {
1676 if (ipv6_probe_job_.get()) {
1677 ipv6_probe_job_->Cancel();
1678 ipv6_probe_job_ = NULL;
1679 }
1680}
1681
1682void HostResolverImpl::IPv6ProbeSetDefaultAddressFamily(
1683 AddressFamily address_family) {
1684 DCHECK(address_family == ADDRESS_FAMILY_UNSPECIFIED ||
1685 address_family == ADDRESS_FAMILY_IPV4);
[email protected]f092e64b2010-03-17 00:39:181686 if (default_address_family_ != address_family) {
[email protected]b30a3f52010-10-16 01:05:461687 VLOG(1) << "IPv6Probe forced AddressFamily setting to "
1688 << ((address_family == ADDRESS_FAMILY_UNSPECIFIED) ?
1689 "ADDRESS_FAMILY_UNSPECIFIED" : "ADDRESS_FAMILY_IPV4");
[email protected]f092e64b2010-03-17 00:39:181690 }
[email protected]0f8f1b432010-03-16 19:06:031691 default_address_family_ = address_family;
1692 // Drop reference since the job has called us back.
1693 DiscardIPv6ProbeJob();
[email protected]e95d3aca2010-01-11 22:47:431694}
1695
[email protected]137af622010-02-05 02:14:351696HostResolverImpl::Key HostResolverImpl::GetEffectiveKeyForRequest(
1697 const RequestInfo& info) const {
[email protected]eaf3a3b2010-09-03 20:34:271698 HostResolverFlags effective_flags =
1699 info.host_resolver_flags() | additional_resolver_flags_;
[email protected]137af622010-02-05 02:14:351700 AddressFamily effective_address_family = info.address_family();
[email protected]eaf3a3b2010-09-03 20:34:271701 if (effective_address_family == ADDRESS_FAMILY_UNSPECIFIED &&
1702 default_address_family_ != ADDRESS_FAMILY_UNSPECIFIED) {
[email protected]137af622010-02-05 02:14:351703 effective_address_family = default_address_family_;
[email protected]eaf3a3b2010-09-03 20:34:271704 if (ipv6_probe_monitoring_)
1705 effective_flags |= HOST_RESOLVER_DEFAULT_FAMILY_SET_DUE_TO_NO_IPV6;
1706 }
1707 return Key(info.hostname(), effective_address_family, effective_flags);
[email protected]137af622010-02-05 02:14:351708}
1709
[email protected]35ddc282010-09-21 23:42:061710void HostResolverImpl::AbortAllInProgressJobs() {
[email protected]b3601bc22012-02-21 21:23:201711 // In Abort, a Request callback could spawn new Jobs with matching keys, so
1712 // first collect and remove all running jobs from |jobs_|.
1713 std::vector<Job*> jobs_to_abort;
[email protected]0f292de02012-02-01 22:28:201714 for (JobMap::iterator it = jobs_.begin(); it != jobs_.end(); ) {
1715 Job* job = it->second;
[email protected]0f292de02012-02-01 22:28:201716 if (job->is_running()) {
[email protected]b3601bc22012-02-21 21:23:201717 jobs_to_abort.push_back(job);
1718 jobs_.erase(it++);
[email protected]0f292de02012-02-01 22:28:201719 } else {
[email protected]b3601bc22012-02-21 21:23:201720 DCHECK(job->is_queued());
1721 ++it;
[email protected]0f292de02012-02-01 22:28:201722 }
[email protected]ef4c40c2010-09-01 14:42:031723 }
[email protected]b3601bc22012-02-21 21:23:201724
[email protected]57a48d32012-03-03 00:04:551725 // Check if no dispatcher slots leaked out.
1726 DCHECK_EQ(dispatcher_.num_running_jobs(), jobs_to_abort.size());
1727
1728 // Life check to bail once |this| is deleted.
1729 base::WeakPtr<HostResolverImpl> self = AsWeakPtr();
1730
[email protected]16ee26d2012-03-08 03:34:351731 // Then Abort them.
[email protected]57a48d32012-03-03 00:04:551732 for (size_t i = 0; self && i < jobs_to_abort.size(); ++i) {
[email protected]57a48d32012-03-03 00:04:551733 jobs_to_abort[i]->Abort();
[email protected]b3601bc22012-02-21 21:23:201734 }
[email protected]ef4c40c2010-09-01 14:42:031735}
1736
[email protected]be1a48b2011-01-20 00:12:131737void HostResolverImpl::OnIPAddressChanged() {
1738 if (cache_.get())
1739 cache_->clear();
1740 if (ipv6_probe_monitoring_) {
[email protected]be1a48b2011-01-20 00:12:131741 DiscardIPv6ProbeJob();
1742 ipv6_probe_job_ = new IPv6ProbeJob(this);
1743 ipv6_probe_job_->Start();
1744 }
[email protected]23f771162011-06-02 18:37:511745#if defined(OS_POSIX) && !defined(OS_MACOSX)
[email protected]be1a48b2011-01-20 00:12:131746 if (HaveOnlyLoopbackAddresses()) {
1747 additional_resolver_flags_ |= HOST_RESOLVER_LOOPBACK_ONLY;
1748 } else {
1749 additional_resolver_flags_ &= ~HOST_RESOLVER_LOOPBACK_ONLY;
1750 }
1751#endif
1752 AbortAllInProgressJobs();
1753 // |this| may be deleted inside AbortAllInProgressJobs().
1754}
1755
[email protected]446df2952012-02-28 07:22:511756void HostResolverImpl::OnDNSChanged(unsigned detail) {
[email protected]46018c9d2011-09-06 03:42:341757 // If the DNS server has changed, existing cached info could be wrong so we
1758 // have to drop our internal cache :( Note that OS level DNS caches, such
1759 // as NSCD's cache should be dropped automatically by the OS when
1760 // resolv.conf changes so we don't need to do anything to clear that cache.
1761 if (cache_.get())
1762 cache_->clear();
1763 // Existing jobs will have been sent to the original server so they need to
1764 // be aborted. TODO(Craig): Should these jobs be restarted?
1765 AbortAllInProgressJobs();
1766 // |this| may be deleted inside AbortAllInProgressJobs().
1767}
1768
[email protected]b3601bc22012-02-21 21:23:201769void HostResolverImpl::OnConfigChanged(const DnsConfig& dns_config) {
1770 // We want a new factory in place, before we Abort running Jobs, so that the
1771 // newly started jobs use the new factory.
1772 bool had_factory = (dns_transaction_factory_.get() != NULL);
1773 if (dns_config.IsValid()) {
1774 dns_transaction_factory_ = DnsTransactionFactory::CreateFactory(
1775 new DnsSession(dns_config,
1776 ClientSocketFactory::GetDefaultFactory(),
1777 base::Bind(&base::RandInt),
1778 net_log_));
1779 } else {
1780 dns_transaction_factory_.reset();
1781 }
1782 // Don't Abort running Jobs unless they were running on DnsTransaction.
1783 // TODO(szym): This will change once http://crbug.com/114827 is fixed.
1784 if (had_factory)
[email protected]446df2952012-02-28 07:22:511785 OnDNSChanged(NetworkChangeNotifier::CHANGE_DNS_SETTINGS);
[email protected]b3601bc22012-02-21 21:23:201786}
1787
[email protected]b59ff372009-07-15 22:04:321788} // namespace net