blob: bc212cf38ea8e5f859f433e71afe6b75188dbf6e [file] [log] [blame]
[email protected]6e7fd162011-04-27 18:08:201// Copyright (c) 2011 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>
14#include <deque>
[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]b59ff372009-07-15 22:04:3218#include "base/compiler_specific.h"
[email protected]58580352010-10-26 04:07:5019#include "base/debug/debugger.h"
20#include "base/debug/stack_trace.h"
[email protected]3e9d9cc2011-05-03 21:08:1521#include "base/message_loop_proxy.h"
[email protected]1e9bbd22010-10-15 16:42:4522#include "base/metrics/field_trial.h"
[email protected]835d7c82010-10-14 04:38:3823#include "base/metrics/histogram.h"
[email protected]7286e3fc2011-07-19 22:13:2424#include "base/stl_util.h"
[email protected]b59ff372009-07-15 22:04:3225#include "base/string_util.h"
[email protected]189163e2011-05-11 01:48:5426#include "base/task.h"
[email protected]ac9ba8fe2010-12-30 18:08:3627#include "base/threading/worker_pool.h"
[email protected]b59ff372009-07-15 22:04:3228#include "base/time.h"
[email protected]ccaff652010-07-31 06:28:2029#include "base/utf_string_conversions.h"
[email protected]21526002010-05-16 19:42:4630#include "base/values.h"
[email protected]b59ff372009-07-15 22:04:3231#include "net/base/address_list.h"
[email protected]ee094b82010-08-24 15:55:5132#include "net/base/address_list_net_log_param.h"
[email protected]46018c9d2011-09-06 03:42:3433#include "net/base/dns_reloader.h"
[email protected]ee094b82010-08-24 15:55:5134#include "net/base/host_port_pair.h"
[email protected]b59ff372009-07-15 22:04:3235#include "net/base/host_resolver_proc.h"
[email protected]2bb04442010-08-18 18:01:1536#include "net/base/net_errors.h"
[email protected]ee094b82010-08-24 15:55:5137#include "net/base/net_log.h"
[email protected]0f8f1b432010-03-16 19:06:0338#include "net/base/net_util.h"
[email protected]b59ff372009-07-15 22:04:3239
40#if defined(OS_WIN)
41#include "net/base/winsock_init.h"
42#endif
43
44namespace net {
45
[email protected]e95d3aca2010-01-11 22:47:4346namespace {
47
[email protected]6e78dfb2011-07-28 21:34:4748// Limit the size of hostnames that will be resolved to combat issues in
49// some platform's resolvers.
50const size_t kMaxHostLength = 4096;
51
[email protected]fe89ea72011-05-12 02:02:4052// Helper to mutate the linked list contained by AddressList to the given
53// port. Note that in general this is dangerous since the AddressList's
54// data might be shared (and you should use AddressList::SetPort).
55//
56// However since we allocated the AddressList ourselves we can safely
57// do this optimization and avoid reallocating the list.
58void MutableSetPort(int port, AddressList* addrlist) {
59 struct addrinfo* mutable_head =
60 const_cast<struct addrinfo*>(addrlist->head());
61 SetPortForAllAddrinfos(mutable_head, port);
62}
63
[email protected]24f4bab2010-10-15 01:27:1164// We use a separate histogram name for each platform to facilitate the
65// display of error codes by their symbolic name (since each platform has
66// different mappings).
67const char kOSErrorsForGetAddrinfoHistogramName[] =
68#if defined(OS_WIN)
69 "Net.OSErrorsForGetAddrinfo_Win";
70#elif defined(OS_MACOSX)
71 "Net.OSErrorsForGetAddrinfo_Mac";
72#elif defined(OS_LINUX)
73 "Net.OSErrorsForGetAddrinfo_Linux";
74#else
75 "Net.OSErrorsForGetAddrinfo";
76#endif
77
[email protected]c89b2442011-05-26 14:28:2778// Gets a list of the likely error codes that getaddrinfo() can return
79// (non-exhaustive). These are the error codes that we will track via
80// a histogram.
81std::vector<int> GetAllGetAddrinfoOSErrors() {
82 int os_errors[] = {
83#if defined(OS_POSIX)
[email protected]23f771162011-06-02 18:37:5184#if !defined(OS_FREEBSD)
[email protected]39588992011-07-11 19:54:3785#if !defined(OS_ANDROID)
86 // EAI_ADDRFAMILY has been declared obsolete in Android's netdb.h.
[email protected]c89b2442011-05-26 14:28:2787 EAI_ADDRFAMILY,
[email protected]39588992011-07-11 19:54:3788#endif
[email protected]23f771162011-06-02 18:37:5189 EAI_NODATA,
90#endif
[email protected]c89b2442011-05-26 14:28:2791 EAI_AGAIN,
92 EAI_BADFLAGS,
93 EAI_FAIL,
94 EAI_FAMILY,
95 EAI_MEMORY,
[email protected]c89b2442011-05-26 14:28:2796 EAI_NONAME,
97 EAI_SERVICE,
98 EAI_SOCKTYPE,
99 EAI_SYSTEM,
100#elif defined(OS_WIN)
101 // See: http://msdn.microsoft.com/en-us/library/ms738520(VS.85).aspx
102 WSA_NOT_ENOUGH_MEMORY,
103 WSAEAFNOSUPPORT,
104 WSAEINVAL,
105 WSAESOCKTNOSUPPORT,
106 WSAHOST_NOT_FOUND,
107 WSANO_DATA,
108 WSANO_RECOVERY,
109 WSANOTINITIALISED,
110 WSATRY_AGAIN,
111 WSATYPE_NOT_FOUND,
112 // The following are not in doc, but might be to appearing in results :-(.
113 WSA_INVALID_HANDLE,
114#endif
115 };
116
117 // Ensure all errors are positive, as histogram only tracks positive values.
118 for (size_t i = 0; i < arraysize(os_errors); ++i) {
119 os_errors[i] = std::abs(os_errors[i]);
120 }
121
122 return base::CustomHistogram::ArrayToCustomRanges(os_errors,
123 arraysize(os_errors));
124}
125
[email protected]e95d3aca2010-01-11 22:47:43126} // anonymous namespace
127
[email protected]189163e2011-05-11 01:48:54128// static
[email protected]ee094b82010-08-24 15:55:51129HostResolver* CreateSystemHostResolver(size_t max_concurrent_resolves,
[email protected]06ef6d92011-05-19 04:24:58130 size_t max_retry_attempts,
[email protected]ee094b82010-08-24 15:55:51131 NetLog* net_log) {
[email protected]755a93352010-10-29 06:33:59132 // Maximum of 8 concurrent resolver threads.
133 // Some routers (or resolvers) appear to start to provide host-not-found if
134 // too many simultaneous resolutions are pending. This number needs to be
135 // further optimized, but 8 is what FF currently does.
136 static const size_t kDefaultMaxJobs = 8u;
[email protected]962b98212010-07-17 03:37:51137
138 if (max_concurrent_resolves == HostResolver::kDefaultParallelism)
139 max_concurrent_resolves = kDefaultMaxJobs;
[email protected]68ad3ee2010-01-30 03:45:39140
[email protected]66761b952010-06-25 21:30:38141 HostResolverImpl* resolver =
[email protected]ba25bb12011-07-21 21:24:24142 new HostResolverImpl(NULL, HostCache::CreateDefaultCache(),
143 max_concurrent_resolves, max_retry_attempts, net_log);
[email protected]68ad3ee2010-01-30 03:45:39144
145 return resolver;
[email protected]b59ff372009-07-15 22:04:32146}
147
148static int ResolveAddrInfo(HostResolverProc* resolver_proc,
[email protected]123ab1e32009-10-21 19:12:57149 const std::string& host,
150 AddressFamily address_family,
[email protected]5ea28dea2010-04-08 15:35:13151 HostResolverFlags host_resolver_flags,
[email protected]21526002010-05-16 19:42:46152 AddressList* out,
153 int* os_error) {
[email protected]b59ff372009-07-15 22:04:32154 if (resolver_proc) {
155 // Use the custom procedure.
[email protected]5ea28dea2010-04-08 15:35:13156 return resolver_proc->Resolve(host, address_family,
[email protected]21526002010-05-16 19:42:46157 host_resolver_flags, out, os_error);
[email protected]b59ff372009-07-15 22:04:32158 } else {
159 // Use the system procedure (getaddrinfo).
[email protected]5ea28dea2010-04-08 15:35:13160 return SystemHostResolverProc(host, address_family,
[email protected]21526002010-05-16 19:42:46161 host_resolver_flags, out, os_error);
[email protected]b59ff372009-07-15 22:04:32162 }
163}
164
[email protected]21526002010-05-16 19:42:46165// Extra parameters to attach to the NetLog when the resolve failed.
166class HostResolveFailedParams : public NetLog::EventParameters {
167 public:
[email protected]13024882011-05-18 23:19:16168 HostResolveFailedParams(uint32 attempt_number,
169 int net_error,
170 int os_error)
171 : attempt_number_(attempt_number),
172 net_error_(net_error),
[email protected]ee094b82010-08-24 15:55:51173 os_error_(os_error) {
[email protected]21526002010-05-16 19:42:46174 }
175
176 virtual Value* ToValue() const {
177 DictionaryValue* dict = new DictionaryValue();
[email protected]13024882011-05-18 23:19:16178 if (attempt_number_)
179 dict->SetInteger("attempt_number", attempt_number_);
180
[email protected]ccaff652010-07-31 06:28:20181 dict->SetInteger("net_error", net_error_);
[email protected]21526002010-05-16 19:42:46182
183 if (os_error_) {
[email protected]ccaff652010-07-31 06:28:20184 dict->SetInteger("os_error", os_error_);
[email protected]21526002010-05-16 19:42:46185#if defined(OS_POSIX)
[email protected]ccaff652010-07-31 06:28:20186 dict->SetString("os_error_string", gai_strerror(os_error_));
[email protected]21526002010-05-16 19:42:46187#elif defined(OS_WIN)
188 // Map the error code to a human-readable string.
189 LPWSTR error_string = NULL;
190 int size = FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
191 FORMAT_MESSAGE_FROM_SYSTEM,
192 0, // Use the internal message table.
193 os_error_,
194 0, // Use default language.
195 (LPWSTR)&error_string,
196 0, // Buffer size.
197 0); // Arguments (unused).
[email protected]ccaff652010-07-31 06:28:20198 dict->SetString("os_error_string", WideToUTF8(error_string));
[email protected]21526002010-05-16 19:42:46199 LocalFree(error_string);
200#endif
201 }
202
203 return dict;
204 }
205
206 private:
[email protected]13024882011-05-18 23:19:16207 const uint32 attempt_number_;
[email protected]21526002010-05-16 19:42:46208 const int net_error_;
209 const int os_error_;
[email protected]ee094b82010-08-24 15:55:51210};
211
212// Parameters representing the information in a RequestInfo object, along with
213// the associated NetLog::Source.
214class RequestInfoParameters : public NetLog::EventParameters {
215 public:
216 RequestInfoParameters(const HostResolver::RequestInfo& info,
217 const NetLog::Source& source)
218 : info_(info), source_(source) {}
219
220 virtual Value* ToValue() const {
221 DictionaryValue* dict = new DictionaryValue();
[email protected]930cc742010-09-15 22:54:10222 dict->SetString("host", info_.host_port_pair().ToString());
[email protected]ee094b82010-08-24 15:55:51223 dict->SetInteger("address_family",
224 static_cast<int>(info_.address_family()));
225 dict->SetBoolean("allow_cached_response", info_.allow_cached_response());
226 dict->SetBoolean("is_speculative", info_.is_speculative());
227 dict->SetInteger("priority", info_.priority());
228
229 if (source_.is_valid())
230 dict->Set("source_dependency", source_.ToValue());
231
232 return dict;
233 }
234
235 private:
236 const HostResolver::RequestInfo info_;
237 const NetLog::Source source_;
238};
239
[email protected]7b496b32011-02-28 22:25:59240// Parameters associated with the creation of a HostResolverImpl::Job.
[email protected]ee094b82010-08-24 15:55:51241class JobCreationParameters : public NetLog::EventParameters {
242 public:
243 JobCreationParameters(const std::string& host, const NetLog::Source& source)
244 : host_(host), source_(source) {}
245
246 virtual Value* ToValue() const {
247 DictionaryValue* dict = new DictionaryValue();
248 dict->SetString("host", host_);
249 dict->Set("source_dependency", source_.ToValue());
250 return dict;
251 }
252
253 private:
254 const std::string host_;
255 const NetLog::Source source_;
[email protected]21526002010-05-16 19:42:46256};
257
[email protected]b59ff372009-07-15 22:04:32258//-----------------------------------------------------------------------------
259
260class HostResolverImpl::Request {
261 public:
[email protected]ee094b82010-08-24 15:55:51262 Request(const BoundNetLog& source_net_log,
263 const BoundNetLog& request_net_log,
[email protected]54e13772009-08-14 03:01:09264 int id,
265 const RequestInfo& info,
[email protected]f1f3f0f82011-10-01 20:38:10266 OldCompletionCallback* callback,
[email protected]b59ff372009-07-15 22:04:32267 AddressList* addresses)
[email protected]ee094b82010-08-24 15:55:51268 : source_net_log_(source_net_log),
269 request_net_log_(request_net_log),
[email protected]54e13772009-08-14 03:01:09270 id_(id),
271 info_(info),
272 job_(NULL),
273 callback_(callback),
274 addresses_(addresses) {
275 }
[email protected]b59ff372009-07-15 22:04:32276
277 // Mark the request as cancelled.
278 void MarkAsCancelled() {
279 job_ = NULL;
280 callback_ = NULL;
281 addresses_ = NULL;
282 }
283
284 bool was_cancelled() const {
285 return callback_ == NULL;
286 }
287
288 void set_job(Job* job) {
289 DCHECK(job != NULL);
290 // Identify which job the request is waiting on.
291 job_ = job;
292 }
293
294 void OnComplete(int error, const AddressList& addrlist) {
295 if (error == OK)
[email protected]fe89ea72011-05-12 02:02:40296 *addresses_ = CreateAddressListUsingPort(addrlist, port());
[email protected]f1f3f0f82011-10-01 20:38:10297 OldCompletionCallback* callback = callback_;
[email protected]ef4c40c2010-09-01 14:42:03298 MarkAsCancelled();
299 callback->Run(error);
[email protected]b59ff372009-07-15 22:04:32300 }
301
302 int port() const {
303 return info_.port();
304 }
305
306 Job* job() const {
307 return job_;
308 }
309
[email protected]ee094b82010-08-24 15:55:51310 const BoundNetLog& source_net_log() {
311 return source_net_log_;
312 }
313
314 const BoundNetLog& request_net_log() {
315 return request_net_log_;
[email protected]54e13772009-08-14 03:01:09316 }
317
[email protected]b59ff372009-07-15 22:04:32318 int id() const {
319 return id_;
320 }
321
322 const RequestInfo& info() const {
323 return info_;
324 }
325
326 private:
[email protected]ee094b82010-08-24 15:55:51327 BoundNetLog source_net_log_;
328 BoundNetLog request_net_log_;
[email protected]54e13772009-08-14 03:01:09329
[email protected]b59ff372009-07-15 22:04:32330 // Unique ID for this request. Used by observers to identify requests.
331 int id_;
332
333 // The request info that started the request.
334 RequestInfo info_;
335
336 // The resolve job (running in worker pool) that this request is dependent on.
337 Job* job_;
338
339 // The user's callback to invoke when the request completes.
[email protected]f1f3f0f82011-10-01 20:38:10340 OldCompletionCallback* callback_;
[email protected]b59ff372009-07-15 22:04:32341
342 // The address list to save result into.
343 AddressList* addresses_;
344
345 DISALLOW_COPY_AND_ASSIGN(Request);
346};
347
[email protected]1e9bbd22010-10-15 16:42:45348//------------------------------------------------------------------------------
349
350// Provide a common macro to simplify code and readability. We must use a
351// macros as the underlying HISTOGRAM macro creates static varibles.
352#define DNS_HISTOGRAM(name, time) UMA_HISTOGRAM_CUSTOM_TIMES(name, time, \
353 base::TimeDelta::FromMicroseconds(1), base::TimeDelta::FromHours(1), 100)
[email protected]b59ff372009-07-15 22:04:32354
355// This class represents a request to the worker pool for a "getaddrinfo()"
356// call.
357class HostResolverImpl::Job
358 : public base::RefCountedThreadSafe<HostResolverImpl::Job> {
359 public:
[email protected]ee094b82010-08-24 15:55:51360 Job(int id,
361 HostResolverImpl* resolver,
362 const Key& key,
363 const BoundNetLog& source_net_log,
364 NetLog* net_log)
365 : id_(id),
366 key_(key),
367 resolver_(resolver),
[email protected]edd685f2011-08-15 20:33:46368 origin_loop_(base::MessageLoopProxy::current()),
[email protected]ee094b82010-08-24 15:55:51369 resolver_proc_(resolver->effective_resolver_proc()),
[email protected]189163e2011-05-11 01:48:54370 unresponsive_delay_(resolver->unresponsive_delay()),
371 attempt_number_(0),
372 completed_attempt_number_(0),
373 completed_attempt_error_(ERR_UNEXPECTED),
[email protected]ee094b82010-08-24 15:55:51374 had_non_speculative_request_(false),
375 net_log_(BoundNetLog::Make(net_log,
376 NetLog::SOURCE_HOST_RESOLVER_IMPL_JOB)) {
[email protected]3e9d9cc2011-05-03 21:08:15377 DCHECK(resolver);
[email protected]00cd9c42010-11-02 20:15:57378 net_log_.BeginEvent(
379 NetLog::TYPE_HOST_RESOLVER_IMPL_JOB,
380 make_scoped_refptr(
381 new JobCreationParameters(key.hostname, source_net_log.source())));
[email protected]b59ff372009-07-15 22:04:32382 }
383
[email protected]b59ff372009-07-15 22:04:32384 // Attaches a request to this job. The job takes ownership of |req| and will
385 // take care to delete it.
386 void AddRequest(Request* req) {
[email protected]3e9d9cc2011-05-03 21:08:15387 DCHECK(origin_loop_->BelongsToCurrentThread());
[email protected]ee094b82010-08-24 15:55:51388 req->request_net_log().BeginEvent(
389 NetLog::TYPE_HOST_RESOLVER_IMPL_JOB_ATTACH,
[email protected]00cd9c42010-11-02 20:15:57390 make_scoped_refptr(new NetLogSourceParameter(
391 "source_dependency", net_log_.source())));
[email protected]ee094b82010-08-24 15:55:51392
[email protected]b59ff372009-07-15 22:04:32393 req->set_job(this);
394 requests_.push_back(req);
[email protected]252b699b2010-02-05 21:38:06395
396 if (!req->info().is_speculative())
397 had_non_speculative_request_ = true;
[email protected]b59ff372009-07-15 22:04:32398 }
399
[email protected]b59ff372009-07-15 22:04:32400 void Start() {
[email protected]3e9d9cc2011-05-03 21:08:15401 DCHECK(origin_loop_->BelongsToCurrentThread());
[email protected]189163e2011-05-11 01:48:54402 StartLookupAttempt();
403 }
[email protected]252b699b2010-02-05 21:38:06404
[email protected]189163e2011-05-11 01:48:54405 void StartLookupAttempt() {
406 DCHECK(origin_loop_->BelongsToCurrentThread());
407 base::TimeTicks start_time = base::TimeTicks::Now();
408 ++attempt_number_;
409 // Dispatch the lookup attempt to a worker thread.
410 if (!base::WorkerPool::PostTask(
411 FROM_HERE,
412 NewRunnableMethod(this, &Job::DoLookup, start_time,
413 attempt_number_),
414 true)) {
[email protected]b59ff372009-07-15 22:04:32415 NOTREACHED();
416
417 // Since we could be running within Resolve() right now, we can't just
418 // call OnLookupComplete(). Instead we must wait until Resolve() has
419 // returned (IO_PENDING).
[email protected]3e9d9cc2011-05-03 21:08:15420 origin_loop_->PostTask(
[email protected]189163e2011-05-11 01:48:54421 FROM_HERE,
422 NewRunnableMethod(this, &Job::OnLookupComplete, AddressList(),
423 start_time, attempt_number_, ERR_UNEXPECTED, 0));
424 return;
[email protected]b59ff372009-07-15 22:04:32425 }
[email protected]13024882011-05-18 23:19:16426
427 net_log_.AddEvent(
428 NetLog::TYPE_HOST_RESOLVER_IMPL_ATTEMPT_STARTED,
429 make_scoped_refptr(new NetLogIntegerParameter(
430 "attempt_number", attempt_number_)));
431
[email protected]189163e2011-05-11 01:48:54432 // Post a task to check if we get the results within a given time.
433 // OnCheckForComplete has the potential for starting a new attempt on a
434 // different worker thread if none of our outstanding attempts have
435 // completed yet.
[email protected]06ef6d92011-05-19 04:24:58436 if (attempt_number_ <= resolver_->max_retry_attempts()) {
437 origin_loop_->PostDelayedTask(
438 FROM_HERE,
439 NewRunnableMethod(this, &Job::OnCheckForComplete),
440 unresponsive_delay_.InMilliseconds());
441 }
[email protected]b59ff372009-07-15 22:04:32442 }
443
[email protected]189163e2011-05-11 01:48:54444 // Cancels the current job. The Job will be orphaned. Any outstanding resolve
445 // attempts running on worker threads will continue running. Only once all the
446 // attempts complete will the final reference to this Job be released.
[email protected]b59ff372009-07-15 22:04:32447 void Cancel() {
[email protected]3e9d9cc2011-05-03 21:08:15448 DCHECK(origin_loop_->BelongsToCurrentThread());
[email protected]ee094b82010-08-24 15:55:51449 net_log_.AddEvent(NetLog::TYPE_CANCELLED, NULL);
450
[email protected]b59ff372009-07-15 22:04:32451 HostResolver* resolver = resolver_;
452 resolver_ = NULL;
453
[email protected]ee094b82010-08-24 15:55:51454 // End here to prevent issues when a Job outlives the HostResolver that
455 // spawned it.
456 net_log_.EndEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_JOB, NULL);
457
[email protected]1877a2212009-09-18 21:09:26458 // We will call HostResolverImpl::CancelRequest(Request*) on each one
[email protected]27f99c82009-10-29 22:21:00459 // in order to notify any observers.
[email protected]b59ff372009-07-15 22:04:32460 for (RequestsList::const_iterator it = requests_.begin();
461 it != requests_.end(); ++it) {
462 HostResolverImpl::Request* req = *it;
463 if (!req->was_cancelled())
464 resolver->CancelRequest(req);
465 }
466 }
467
[email protected]b59ff372009-07-15 22:04:32468 bool was_cancelled() const {
[email protected]3e9d9cc2011-05-03 21:08:15469 DCHECK(origin_loop_->BelongsToCurrentThread());
[email protected]b59ff372009-07-15 22:04:32470 return resolver_ == NULL;
471 }
472
[email protected]189163e2011-05-11 01:48:54473 bool was_completed() const {
474 DCHECK(origin_loop_->BelongsToCurrentThread());
475 return completed_attempt_number_ > 0;
476 }
477
[email protected]123ab1e32009-10-21 19:12:57478 const Key& key() const {
[email protected]3e9d9cc2011-05-03 21:08:15479 DCHECK(origin_loop_->BelongsToCurrentThread());
[email protected]123ab1e32009-10-21 19:12:57480 return key_;
[email protected]b59ff372009-07-15 22:04:32481 }
482
[email protected]a2fbebe2010-02-05 01:40:12483 int id() const {
[email protected]3e9d9cc2011-05-03 21:08:15484 DCHECK(origin_loop_->BelongsToCurrentThread());
[email protected]a2fbebe2010-02-05 01:40:12485 return id_;
486 }
487
[email protected]b59ff372009-07-15 22:04:32488 const RequestsList& requests() const {
[email protected]3e9d9cc2011-05-03 21:08:15489 DCHECK(origin_loop_->BelongsToCurrentThread());
[email protected]b59ff372009-07-15 22:04:32490 return requests_;
491 }
492
[email protected]68ad3ee2010-01-30 03:45:39493 // Returns the first request attached to the job.
494 const Request* initial_request() const {
[email protected]3e9d9cc2011-05-03 21:08:15495 DCHECK(origin_loop_->BelongsToCurrentThread());
[email protected]68ad3ee2010-01-30 03:45:39496 DCHECK(!requests_.empty());
497 return requests_[0];
498 }
499
[email protected]137af622010-02-05 02:14:35500 // Returns true if |req_info| can be fulfilled by this job.
501 bool CanServiceRequest(const RequestInfo& req_info) const {
[email protected]3e9d9cc2011-05-03 21:08:15502 DCHECK(origin_loop_->BelongsToCurrentThread());
[email protected]137af622010-02-05 02:14:35503 return key_ == resolver_->GetEffectiveKeyForRequest(req_info);
504 }
505
[email protected]b59ff372009-07-15 22:04:32506 private:
[email protected]5389bc72009-11-05 23:34:24507 friend class base::RefCountedThreadSafe<HostResolverImpl::Job>;
508
509 ~Job() {
510 // Free the requests attached to this job.
511 STLDeleteElements(&requests_);
512 }
513
[email protected]6c710ee2010-05-07 07:51:16514 // WARNING: This code runs inside a worker pool. The shutdown code cannot
515 // wait for it to finish, so we must be very careful here about using other
516 // objects (like MessageLoops, Singletons, etc). During shutdown these objects
[email protected]189163e2011-05-11 01:48:54517 // may no longer exist. Multiple DoLookups() could be running in parallel, so
518 // any state inside of |this| must not mutate .
519 void DoLookup(const base::TimeTicks& start_time,
520 const uint32 attempt_number) {
521 AddressList results;
522 int os_error = 0;
[email protected]b59ff372009-07-15 22:04:32523 // Running on the worker thread
[email protected]189163e2011-05-11 01:48:54524 int error = ResolveAddrInfo(resolver_proc_,
525 key_.hostname,
526 key_.address_family,
527 key_.host_resolver_flags,
528 &results,
529 &os_error);
[email protected]b59ff372009-07-15 22:04:32530
[email protected]189163e2011-05-11 01:48:54531 origin_loop_->PostTask(
532 FROM_HERE,
533 NewRunnableMethod(this, &Job::OnLookupComplete, results, start_time,
534 attempt_number, error, os_error));
535 }
536
537 // Callback to see if DoLookup() has finished or not (runs on origin thread).
538 void OnCheckForComplete() {
539 DCHECK(origin_loop_->BelongsToCurrentThread());
540
[email protected]06ef6d92011-05-19 04:24:58541 if (was_completed() || was_cancelled())
[email protected]189163e2011-05-11 01:48:54542 return;
543
544 DCHECK(resolver_);
[email protected]06ef6d92011-05-19 04:24:58545 unresponsive_delay_ *= resolver_->retry_factor();
[email protected]189163e2011-05-11 01:48:54546 StartLookupAttempt();
[email protected]b59ff372009-07-15 22:04:32547 }
548
549 // Callback for when DoLookup() completes (runs on origin thread).
[email protected]189163e2011-05-11 01:48:54550 void OnLookupComplete(const AddressList& results,
551 const base::TimeTicks& start_time,
552 const uint32 attempt_number,
553 int error,
554 const int os_error) {
[email protected]3e9d9cc2011-05-03 21:08:15555 DCHECK(origin_loop_->BelongsToCurrentThread());
[email protected]189163e2011-05-11 01:48:54556 DCHECK(error || results.head());
557
558 bool was_retry_attempt = attempt_number > 1;
559
560 if (!was_cancelled()) {
[email protected]13024882011-05-18 23:19:16561 scoped_refptr<NetLog::EventParameters> params;
562 if (error != OK) {
563 params = new HostResolveFailedParams(attempt_number, error, os_error);
564 } else {
565 params = new NetLogIntegerParameter("attempt_number", attempt_number_);
566 }
567 net_log_.AddEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_ATTEMPT_FINISHED,
568 params);
569
[email protected]189163e2011-05-11 01:48:54570 // If host is already resolved, then record data and return.
571 if (was_completed()) {
572 // If this is the first attempt that is finishing later, then record
573 // data for the first attempt. Won't contaminate with retry attempt's
574 // data.
575 if (!was_retry_attempt)
576 RecordPerformanceHistograms(start_time, error, os_error);
577
578 RecordAttemptHistograms(start_time, attempt_number, error, os_error);
579 return;
580 }
581
582 // Copy the results from the first worker thread that resolves the host.
583 results_ = results;
584 completed_attempt_number_ = attempt_number;
585 completed_attempt_error_ = error;
586 }
[email protected]b59ff372009-07-15 22:04:32587
[email protected]2d3b7762010-10-09 00:35:47588 // Ideally the following code would be part of host_resolver_proc.cc,
589 // however it isn't safe to call NetworkChangeNotifier from worker
590 // threads. So we do it here on the IO thread instead.
[email protected]189163e2011-05-11 01:48:54591 if (error != OK && NetworkChangeNotifier::IsOffline())
592 error = ERR_INTERNET_DISCONNECTED;
[email protected]2d3b7762010-10-09 00:35:47593
[email protected]189163e2011-05-11 01:48:54594 // We will record data for the first attempt. Don't contaminate with retry
595 // attempt's data.
596 if (!was_retry_attempt)
597 RecordPerformanceHistograms(start_time, error, os_error);
598
599 RecordAttemptHistograms(start_time, attempt_number, error, os_error);
[email protected]f2d8c4212010-02-02 00:56:35600
[email protected]b59ff372009-07-15 22:04:32601 if (was_cancelled())
602 return;
603
[email protected]e87b8b512011-06-14 22:12:52604 if (was_retry_attempt) {
605 // If retry attempt finishes before 1st attempt, then get stats on how
606 // much time is saved by having spawned an extra attempt.
607 retry_attempt_finished_time_ = base::TimeTicks::Now();
608 }
609
[email protected]ee094b82010-08-24 15:55:51610 scoped_refptr<NetLog::EventParameters> params;
[email protected]189163e2011-05-11 01:48:54611 if (error != OK) {
[email protected]13024882011-05-18 23:19:16612 params = new HostResolveFailedParams(0, error, os_error);
[email protected]ee094b82010-08-24 15:55:51613 } else {
614 params = new AddressListNetLogParam(results_);
615 }
616
617 // End here to prevent issues when a Job outlives the HostResolver that
618 // spawned it.
619 net_log_.EndEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_JOB, params);
620
[email protected]b59ff372009-07-15 22:04:32621 DCHECK(!requests_.empty());
622
623 // Use the port number of the first request.
[email protected]189163e2011-05-11 01:48:54624 if (error == OK)
[email protected]fe89ea72011-05-12 02:02:40625 MutableSetPort(requests_[0]->port(), &results_);
[email protected]b59ff372009-07-15 22:04:32626
[email protected]189163e2011-05-11 01:48:54627 resolver_->OnJobComplete(this, error, os_error, results_);
[email protected]b59ff372009-07-15 22:04:32628 }
629
[email protected]189163e2011-05-11 01:48:54630 void RecordPerformanceHistograms(const base::TimeTicks& start_time,
631 const int error,
632 const int os_error) const {
[email protected]3e9d9cc2011-05-03 21:08:15633 DCHECK(origin_loop_->BelongsToCurrentThread());
[email protected]1e9bbd22010-10-15 16:42:45634 enum Category { // Used in HISTOGRAM_ENUMERATION.
635 RESOLVE_SUCCESS,
636 RESOLVE_FAIL,
637 RESOLVE_SPECULATIVE_SUCCESS,
638 RESOLVE_SPECULATIVE_FAIL,
639 RESOLVE_MAX, // Bounding value.
640 };
641 int category = RESOLVE_MAX; // Illegal value for later DCHECK only.
642
[email protected]189163e2011-05-11 01:48:54643 base::TimeDelta duration = base::TimeTicks::Now() - start_time;
644 if (error == OK) {
[email protected]1e9bbd22010-10-15 16:42:45645 if (had_non_speculative_request_) {
646 category = RESOLVE_SUCCESS;
647 DNS_HISTOGRAM("DNS.ResolveSuccess", duration);
648 } else {
649 category = RESOLVE_SPECULATIVE_SUCCESS;
650 DNS_HISTOGRAM("DNS.ResolveSpeculativeSuccess", duration);
651 }
[email protected]7e96d792011-06-10 17:08:23652
653 // Log DNS lookups based on address_family. This will help us determine
654 // if IPv4 or IPv4/6 lookups are faster or slower.
655 switch(key_.address_family) {
656 case ADDRESS_FAMILY_IPV4:
657 DNS_HISTOGRAM("DNS.ResolveSuccess_FAMILY_IPV4", duration);
658 break;
659 case ADDRESS_FAMILY_IPV6:
660 DNS_HISTOGRAM("DNS.ResolveSuccess_FAMILY_IPV6", duration);
661 break;
662 case ADDRESS_FAMILY_UNSPECIFIED:
663 DNS_HISTOGRAM("DNS.ResolveSuccess_FAMILY_UNSPEC", duration);
664 break;
665 }
[email protected]1e9bbd22010-10-15 16:42:45666 } else {
667 if (had_non_speculative_request_) {
668 category = RESOLVE_FAIL;
669 DNS_HISTOGRAM("DNS.ResolveFail", duration);
670 } else {
671 category = RESOLVE_SPECULATIVE_FAIL;
672 DNS_HISTOGRAM("DNS.ResolveSpeculativeFail", duration);
673 }
[email protected]7e96d792011-06-10 17:08:23674 // Log DNS lookups based on address_family. This will help us determine
675 // if IPv4 or IPv4/6 lookups are faster or slower.
676 switch(key_.address_family) {
677 case ADDRESS_FAMILY_IPV4:
678 DNS_HISTOGRAM("DNS.ResolveFail_FAMILY_IPV4", duration);
679 break;
680 case ADDRESS_FAMILY_IPV6:
681 DNS_HISTOGRAM("DNS.ResolveFail_FAMILY_IPV6", duration);
682 break;
683 case ADDRESS_FAMILY_UNSPECIFIED:
684 DNS_HISTOGRAM("DNS.ResolveFail_FAMILY_UNSPEC", duration);
685 break;
686 }
[email protected]c833e322010-10-16 23:51:36687 UMA_HISTOGRAM_CUSTOM_ENUMERATION(kOSErrorsForGetAddrinfoHistogramName,
[email protected]189163e2011-05-11 01:48:54688 std::abs(os_error),
[email protected]1e9bbd22010-10-15 16:42:45689 GetAllGetAddrinfoOSErrors());
690 }
[email protected]051b6ab2010-10-18 16:50:46691 DCHECK_LT(category, static_cast<int>(RESOLVE_MAX)); // Be sure it was set.
[email protected]1e9bbd22010-10-15 16:42:45692
693 UMA_HISTOGRAM_ENUMERATION("DNS.ResolveCategory", category, RESOLVE_MAX);
694
[email protected]edafd4c2011-05-10 17:18:53695 static const bool show_speculative_experiment_histograms =
696 base::FieldTrialList::TrialExists("DnsImpact");
[email protected]ecd95ae2010-10-20 23:58:17697 if (show_speculative_experiment_histograms) {
[email protected]1e9bbd22010-10-15 16:42:45698 UMA_HISTOGRAM_ENUMERATION(
699 base::FieldTrial::MakeName("DNS.ResolveCategory", "DnsImpact"),
700 category, RESOLVE_MAX);
701 if (RESOLVE_SUCCESS == category) {
702 DNS_HISTOGRAM(base::FieldTrial::MakeName("DNS.ResolveSuccess",
703 "DnsImpact"), duration);
704 }
705 }
[email protected]edafd4c2011-05-10 17:18:53706 static const bool show_parallelism_experiment_histograms =
707 base::FieldTrialList::TrialExists("DnsParallelism");
[email protected]ecd95ae2010-10-20 23:58:17708 if (show_parallelism_experiment_histograms) {
709 UMA_HISTOGRAM_ENUMERATION(
710 base::FieldTrial::MakeName("DNS.ResolveCategory", "DnsParallelism"),
711 category, RESOLVE_MAX);
712 if (RESOLVE_SUCCESS == category) {
713 DNS_HISTOGRAM(base::FieldTrial::MakeName("DNS.ResolveSuccess",
714 "DnsParallelism"), duration);
715 }
716 }
[email protected]1e9bbd22010-10-15 16:42:45717 }
718
[email protected]189163e2011-05-11 01:48:54719 void RecordAttemptHistograms(const base::TimeTicks& start_time,
720 const uint32 attempt_number,
721 const int error,
722 const int os_error) const {
723 bool first_attempt_to_complete =
724 completed_attempt_number_ == attempt_number;
[email protected]e87b8b512011-06-14 22:12:52725 bool is_first_attempt = (attempt_number == 1);
[email protected]1e9bbd22010-10-15 16:42:45726
[email protected]189163e2011-05-11 01:48:54727 if (first_attempt_to_complete) {
728 // If this was first attempt to complete, then record the resolution
729 // status of the attempt.
730 if (completed_attempt_error_ == OK) {
731 UMA_HISTOGRAM_ENUMERATION(
732 "DNS.AttemptFirstSuccess", attempt_number, 100);
733 } else {
734 UMA_HISTOGRAM_ENUMERATION(
735 "DNS.AttemptFirstFailure", attempt_number, 100);
736 }
737 }
738
739 if (error == OK)
740 UMA_HISTOGRAM_ENUMERATION("DNS.AttemptSuccess", attempt_number, 100);
741 else
742 UMA_HISTOGRAM_ENUMERATION("DNS.AttemptFailure", attempt_number, 100);
743
[email protected]e87b8b512011-06-14 22:12:52744 // If first attempt didn't finish before retry attempt, then calculate stats
745 // on how much time is saved by having spawned an extra attempt.
746 if (!first_attempt_to_complete && is_first_attempt && !was_cancelled()) {
747 DNS_HISTOGRAM("DNS.AttemptTimeSavedByRetry",
748 base::TimeTicks::Now() - retry_attempt_finished_time_);
749 }
750
[email protected]189163e2011-05-11 01:48:54751 if (was_cancelled() || !first_attempt_to_complete) {
752 // Count those attempts which completed after the job was already canceled
753 // OR after the job was already completed by an earlier attempt (so in
754 // effect).
755 UMA_HISTOGRAM_ENUMERATION("DNS.AttemptDiscarded", attempt_number, 100);
756
757 // Record if job is cancelled.
758 if (was_cancelled())
759 UMA_HISTOGRAM_ENUMERATION("DNS.AttemptCancelled", attempt_number, 100);
760 }
761
762 base::TimeDelta duration = base::TimeTicks::Now() - start_time;
763 if (error == OK)
764 DNS_HISTOGRAM("DNS.AttemptSuccessDuration", duration);
765 else
766 DNS_HISTOGRAM("DNS.AttemptFailDuration", duration);
767 }
[email protected]1e9bbd22010-10-15 16:42:45768
[email protected]f2d8c4212010-02-02 00:56:35769 // Immutable. Can be read from either thread,
770 const int id_;
771
[email protected]b59ff372009-07-15 22:04:32772 // Set on the origin thread, read on the worker thread.
[email protected]123ab1e32009-10-21 19:12:57773 Key key_;
[email protected]b59ff372009-07-15 22:04:32774
775 // Only used on the origin thread (where Resolve was called).
776 HostResolverImpl* resolver_;
777 RequestsList requests_; // The requests waiting on this job.
778
779 // Used to post ourselves onto the origin thread.
[email protected]3e9d9cc2011-05-03 21:08:15780 scoped_refptr<base::MessageLoopProxy> origin_loop_;
[email protected]b59ff372009-07-15 22:04:32781
782 // Hold an owning reference to the HostResolverProc that we are going to use.
783 // This may not be the current resolver procedure by the time we call
784 // ResolveAddrInfo, but that's OK... we'll use it anyways, and the owning
785 // reference ensures that it remains valid until we are done.
786 scoped_refptr<HostResolverProc> resolver_proc_;
787
[email protected]189163e2011-05-11 01:48:54788 // The amount of time after starting a resolution attempt until deciding to
789 // retry.
790 base::TimeDelta unresponsive_delay_;
791
792 // Keeps track of the number of attempts we have made so far to resolve the
793 // host. Whenever we start an attempt to resolve the host, we increase this
794 // number.
795 uint32 attempt_number_;
796
797 // The index of the attempt which finished first (or 0 if the job is still in
798 // progress).
799 uint32 completed_attempt_number_;
800
801 // The result (a net error code) from the first attempt to complete.
802 int completed_attempt_error_;
[email protected]252b699b2010-02-05 21:38:06803
[email protected]e87b8b512011-06-14 22:12:52804 // The time when retry attempt was finished.
805 base::TimeTicks retry_attempt_finished_time_;
806
[email protected]252b699b2010-02-05 21:38:06807 // True if a non-speculative request was ever attached to this job
808 // (regardless of whether or not it was later cancelled.
809 // This boolean is used for histogramming the duration of jobs used to
810 // service non-speculative requests.
811 bool had_non_speculative_request_;
812
[email protected]b59ff372009-07-15 22:04:32813 AddressList results_;
814
[email protected]ee094b82010-08-24 15:55:51815 BoundNetLog net_log_;
816
[email protected]b59ff372009-07-15 22:04:32817 DISALLOW_COPY_AND_ASSIGN(Job);
818};
819
820//-----------------------------------------------------------------------------
821
[email protected]0f8f1b432010-03-16 19:06:03822// This class represents a request to the worker pool for a "probe for IPv6
823// support" call.
824class HostResolverImpl::IPv6ProbeJob
825 : public base::RefCountedThreadSafe<HostResolverImpl::IPv6ProbeJob> {
826 public:
827 explicit IPv6ProbeJob(HostResolverImpl* resolver)
828 : resolver_(resolver),
[email protected]edd685f2011-08-15 20:33:46829 origin_loop_(base::MessageLoopProxy::current()) {
[email protected]3e9d9cc2011-05-03 21:08:15830 DCHECK(resolver);
[email protected]0f8f1b432010-03-16 19:06:03831 }
832
833 void Start() {
[email protected]3e9d9cc2011-05-03 21:08:15834 DCHECK(origin_loop_->BelongsToCurrentThread());
[email protected]a9af7112010-05-08 00:56:01835 if (was_cancelled())
836 return;
[email protected]f092e64b2010-03-17 00:39:18837 const bool kIsSlow = true;
[email protected]ac9ba8fe2010-12-30 18:08:36838 base::WorkerPool::PostTask(
[email protected]f092e64b2010-03-17 00:39:18839 FROM_HERE, NewRunnableMethod(this, &IPv6ProbeJob::DoProbe), kIsSlow);
[email protected]0f8f1b432010-03-16 19:06:03840 }
841
842 // Cancels the current job.
843 void Cancel() {
[email protected]3e9d9cc2011-05-03 21:08:15844 DCHECK(origin_loop_->BelongsToCurrentThread());
[email protected]a9af7112010-05-08 00:56:01845 if (was_cancelled())
846 return;
[email protected]0f8f1b432010-03-16 19:06:03847 resolver_ = NULL; // Read/write ONLY on origin thread.
[email protected]0f8f1b432010-03-16 19:06:03848 }
849
[email protected]0f8f1b432010-03-16 19:06:03850 private:
851 friend class base::RefCountedThreadSafe<HostResolverImpl::IPv6ProbeJob>;
852
853 ~IPv6ProbeJob() {
854 }
855
[email protected]a9af7112010-05-08 00:56:01856 bool was_cancelled() const {
[email protected]3e9d9cc2011-05-03 21:08:15857 DCHECK(origin_loop_->BelongsToCurrentThread());
858 return !resolver_;
[email protected]a9af7112010-05-08 00:56:01859 }
860
[email protected]0f8f1b432010-03-16 19:06:03861 // Run on worker thread.
862 void DoProbe() {
863 // Do actual testing on this thread, as it takes 40-100ms.
864 AddressFamily family = IPv6Supported() ? ADDRESS_FAMILY_UNSPECIFIED
865 : ADDRESS_FAMILY_IPV4;
866
[email protected]3e9d9cc2011-05-03 21:08:15867 origin_loop_->PostTask(
868 FROM_HERE,
869 NewRunnableMethod(this, &IPv6ProbeJob::OnProbeComplete, family));
[email protected]0f8f1b432010-03-16 19:06:03870 }
871
[email protected]3e9d9cc2011-05-03 21:08:15872 // Callback for when DoProbe() completes.
[email protected]0f8f1b432010-03-16 19:06:03873 void OnProbeComplete(AddressFamily address_family) {
[email protected]3e9d9cc2011-05-03 21:08:15874 DCHECK(origin_loop_->BelongsToCurrentThread());
[email protected]a9af7112010-05-08 00:56:01875 if (was_cancelled())
876 return;
[email protected]a9af7112010-05-08 00:56:01877 resolver_->IPv6ProbeSetDefaultAddressFamily(address_family);
[email protected]0f8f1b432010-03-16 19:06:03878 }
879
[email protected]0f8f1b432010-03-16 19:06:03880 // Used/set only on origin thread.
881 HostResolverImpl* resolver_;
882
883 // Used to post ourselves onto the origin thread.
[email protected]3e9d9cc2011-05-03 21:08:15884 scoped_refptr<base::MessageLoopProxy> origin_loop_;
[email protected]0f8f1b432010-03-16 19:06:03885
886 DISALLOW_COPY_AND_ASSIGN(IPv6ProbeJob);
887};
888
889//-----------------------------------------------------------------------------
890
[email protected]68ad3ee2010-01-30 03:45:39891// We rely on the priority enum values being sequential having starting at 0,
892// and increasing for lower priorities.
893COMPILE_ASSERT(HIGHEST == 0u &&
894 LOWEST > HIGHEST &&
[email protected]c9c6f5c2010-07-31 01:30:03895 IDLE > LOWEST &&
896 NUM_PRIORITIES > IDLE,
[email protected]68ad3ee2010-01-30 03:45:39897 priority_indexes_incompatible);
898
899// JobPool contains all the information relating to queued requests, including
900// the limits on how many jobs are allowed to be used for this category of
901// requests.
902class HostResolverImpl::JobPool {
903 public:
904 JobPool(size_t max_outstanding_jobs, size_t max_pending_requests)
905 : num_outstanding_jobs_(0u) {
906 SetConstraints(max_outstanding_jobs, max_pending_requests);
907 }
908
909 ~JobPool() {
910 // Free the pending requests.
911 for (size_t i = 0; i < arraysize(pending_requests_); ++i)
912 STLDeleteElements(&pending_requests_[i]);
913 }
914
915 // Sets the constraints for this pool. See SetPoolConstraints() for the
916 // specific meaning of these parameters.
917 void SetConstraints(size_t max_outstanding_jobs,
918 size_t max_pending_requests) {
[email protected]b1f031dd2010-03-02 23:19:33919 CHECK_NE(max_outstanding_jobs, 0u);
[email protected]68ad3ee2010-01-30 03:45:39920 max_outstanding_jobs_ = max_outstanding_jobs;
921 max_pending_requests_ = max_pending_requests;
922 }
923
924 // Returns the number of pending requests enqueued to this pool.
925 // A pending request is one waiting to be attached to a job.
926 size_t GetNumPendingRequests() const {
927 size_t total = 0u;
928 for (size_t i = 0u; i < arraysize(pending_requests_); ++i)
929 total += pending_requests_[i].size();
930 return total;
931 }
932
933 bool HasPendingRequests() const {
934 return GetNumPendingRequests() > 0u;
935 }
936
937 // Enqueues a request to this pool. As a result of enqueing this request,
938 // the queue may have reached its maximum size. In this case, a request is
939 // evicted from the queue, and returned. Otherwise returns NULL. The caller
940 // is responsible for freeing the evicted request.
941 Request* InsertPendingRequest(Request* req) {
[email protected]ee094b82010-08-24 15:55:51942 req->request_net_log().BeginEvent(
943 NetLog::TYPE_HOST_RESOLVER_IMPL_JOB_POOL_QUEUE,
944 NULL);
945
[email protected]68ad3ee2010-01-30 03:45:39946 PendingRequestsQueue& q = pending_requests_[req->info().priority()];
947 q.push_back(req);
948
949 // If the queue is too big, kick out the lowest priority oldest request.
950 if (GetNumPendingRequests() > max_pending_requests_) {
951 // Iterate over the queues from lowest priority to highest priority.
952 for (int i = static_cast<int>(arraysize(pending_requests_)) - 1;
953 i >= 0; --i) {
954 PendingRequestsQueue& q = pending_requests_[i];
955 if (!q.empty()) {
956 Request* req = q.front();
957 q.pop_front();
[email protected]ee094b82010-08-24 15:55:51958 req->request_net_log().AddEvent(
959 NetLog::TYPE_HOST_RESOLVER_IMPL_JOB_POOL_QUEUE_EVICTED, NULL);
960 req->request_net_log().EndEvent(
961 NetLog::TYPE_HOST_RESOLVER_IMPL_JOB_POOL_QUEUE, NULL);
[email protected]68ad3ee2010-01-30 03:45:39962 return req;
963 }
964 }
965 }
966
967 return NULL;
968 }
969
970 // Erases |req| from this container. Caller is responsible for freeing
971 // |req| afterwards.
972 void RemovePendingRequest(Request* req) {
973 PendingRequestsQueue& q = pending_requests_[req->info().priority()];
974 PendingRequestsQueue::iterator it = std::find(q.begin(), q.end(), req);
975 DCHECK(it != q.end());
976 q.erase(it);
[email protected]ee094b82010-08-24 15:55:51977 req->request_net_log().EndEvent(
978 NetLog::TYPE_HOST_RESOLVER_IMPL_JOB_POOL_QUEUE, NULL);
[email protected]68ad3ee2010-01-30 03:45:39979 }
980
981 // Removes and returns the highest priority pending request.
982 Request* RemoveTopPendingRequest() {
983 DCHECK(HasPendingRequests());
984
985 for (size_t i = 0u; i < arraysize(pending_requests_); ++i) {
986 PendingRequestsQueue& q = pending_requests_[i];
987 if (!q.empty()) {
988 Request* req = q.front();
989 q.pop_front();
[email protected]ee094b82010-08-24 15:55:51990 req->request_net_log().EndEvent(
991 NetLog::TYPE_HOST_RESOLVER_IMPL_JOB_POOL_QUEUE, NULL);
[email protected]68ad3ee2010-01-30 03:45:39992 return req;
993 }
994 }
995
996 NOTREACHED();
997 return NULL;
998 }
999
1000 // Keeps track of a job that was just added/removed, and belongs to this pool.
1001 void AdjustNumOutstandingJobs(int offset) {
1002 DCHECK(offset == 1 || (offset == -1 && num_outstanding_jobs_ > 0u));
1003 num_outstanding_jobs_ += offset;
1004 }
1005
[email protected]35ddc282010-09-21 23:42:061006 void ResetNumOutstandingJobs() {
1007 num_outstanding_jobs_ = 0;
1008 }
1009
[email protected]68ad3ee2010-01-30 03:45:391010 // Returns true if a new job can be created for this pool.
1011 bool CanCreateJob() const {
1012 return num_outstanding_jobs_ + 1u <= max_outstanding_jobs_;
1013 }
1014
1015 // Removes any pending requests from the queue which are for the
[email protected]137af622010-02-05 02:14:351016 // same (hostname / effective address-family) as |job|, and attaches them to
1017 // |job|.
[email protected]68ad3ee2010-01-30 03:45:391018 void MoveRequestsToJob(Job* job) {
1019 for (size_t i = 0u; i < arraysize(pending_requests_); ++i) {
1020 PendingRequestsQueue& q = pending_requests_[i];
1021 PendingRequestsQueue::iterator req_it = q.begin();
1022 while (req_it != q.end()) {
1023 Request* req = *req_it;
[email protected]137af622010-02-05 02:14:351024 if (job->CanServiceRequest(req->info())) {
[email protected]68ad3ee2010-01-30 03:45:391025 // Job takes ownership of |req|.
1026 job->AddRequest(req);
1027 req_it = q.erase(req_it);
1028 } else {
1029 ++req_it;
1030 }
1031 }
1032 }
1033 }
1034
1035 private:
1036 typedef std::deque<Request*> PendingRequestsQueue;
1037
1038 // Maximum number of concurrent jobs allowed to be started for requests
1039 // belonging to this pool.
1040 size_t max_outstanding_jobs_;
1041
1042 // The current number of running jobs that were started for requests
1043 // belonging to this pool.
1044 size_t num_outstanding_jobs_;
1045
1046 // The maximum number of requests we allow to be waiting on a job,
1047 // for this pool.
1048 size_t max_pending_requests_;
1049
1050 // The requests which are waiting to be started for this pool.
1051 PendingRequestsQueue pending_requests_[NUM_PRIORITIES];
1052};
1053
1054//-----------------------------------------------------------------------------
1055
[email protected]e95d3aca2010-01-11 22:47:431056HostResolverImpl::HostResolverImpl(
1057 HostResolverProc* resolver_proc,
1058 HostCache* cache,
[email protected]ee094b82010-08-24 15:55:511059 size_t max_jobs,
[email protected]06ef6d92011-05-19 04:24:581060 size_t max_retry_attempts,
[email protected]ee094b82010-08-24 15:55:511061 NetLog* net_log)
[email protected]112bd462009-12-10 07:23:401062 : cache_(cache),
[email protected]68ad3ee2010-01-30 03:45:391063 max_jobs_(max_jobs),
[email protected]06ef6d92011-05-19 04:24:581064 max_retry_attempts_(max_retry_attempts),
[email protected]189163e2011-05-11 01:48:541065 unresponsive_delay_(base::TimeDelta::FromMilliseconds(6000)),
1066 retry_factor_(2),
[email protected]123ab1e32009-10-21 19:12:571067 next_request_id_(0),
[email protected]f2d8c4212010-02-02 00:56:351068 next_job_id_(0),
[email protected]123ab1e32009-10-21 19:12:571069 resolver_proc_(resolver_proc),
[email protected]0c7798452009-10-26 17:59:511070 default_address_family_(ADDRESS_FAMILY_UNSPECIFIED),
[email protected]2f3bc65c2010-07-23 17:47:101071 ipv6_probe_monitoring_(false),
[email protected]ee094b82010-08-24 15:55:511072 additional_resolver_flags_(0),
1073 net_log_(net_log) {
[email protected]68ad3ee2010-01-30 03:45:391074 DCHECK_GT(max_jobs, 0u);
1075
[email protected]06ef6d92011-05-19 04:24:581076 // Maximum of 4 retry attempts for host resolution.
1077 static const size_t kDefaultMaxRetryAttempts = 4u;
1078
1079 if (max_retry_attempts_ == HostResolver::kDefaultRetryAttempts)
1080 max_retry_attempts_ = kDefaultMaxRetryAttempts;
1081
[email protected]68ad3ee2010-01-30 03:45:391082 // It is cumbersome to expose all of the constraints in the constructor,
1083 // so we choose some defaults, which users can override later.
1084 job_pools_[POOL_NORMAL] = new JobPool(max_jobs, 100u * max_jobs);
1085
[email protected]b59ff372009-07-15 22:04:321086#if defined(OS_WIN)
1087 EnsureWinsockInit();
1088#endif
[email protected]23f771162011-06-02 18:37:511089#if defined(OS_POSIX) && !defined(OS_MACOSX)
[email protected]2f3bc65c2010-07-23 17:47:101090 if (HaveOnlyLoopbackAddresses())
1091 additional_resolver_flags_ |= HOST_RESOLVER_LOOPBACK_ONLY;
1092#endif
[email protected]232a5812011-03-04 22:42:081093 NetworkChangeNotifier::AddIPAddressObserver(this);
[email protected]46018c9d2011-09-06 03:42:341094#if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_OPENBSD)
1095 EnsureDnsReloaderInit();
1096 NetworkChangeNotifier::AddDNSObserver(this);
1097#endif
[email protected]b59ff372009-07-15 22:04:321098}
1099
1100HostResolverImpl::~HostResolverImpl() {
1101 // Cancel the outstanding jobs. Those jobs may contain several attached
1102 // requests, which will also be cancelled.
[email protected]0f8f1b432010-03-16 19:06:031103 DiscardIPv6ProbeJob();
1104
[email protected]ef4c40c2010-09-01 14:42:031105 CancelAllJobs();
[email protected]b59ff372009-07-15 22:04:321106
1107 // In case we are being deleted during the processing of a callback.
1108 if (cur_completing_job_)
1109 cur_completing_job_->Cancel();
[email protected]e95d3aca2010-01-11 22:47:431110
[email protected]232a5812011-03-04 22:42:081111 NetworkChangeNotifier::RemoveIPAddressObserver(this);
[email protected]46018c9d2011-09-06 03:42:341112#if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_OPENBSD)
1113 NetworkChangeNotifier::RemoveDNSObserver(this);
1114#endif
[email protected]61a86c42010-04-19 22:45:531115
[email protected]68ad3ee2010-01-30 03:45:391116 // Delete the job pools.
1117 for (size_t i = 0u; i < arraysize(job_pools_); ++i)
1118 delete job_pools_[i];
[email protected]b59ff372009-07-15 22:04:321119}
1120
[email protected]be1a48b2011-01-20 00:12:131121void HostResolverImpl::ProbeIPv6Support() {
1122 DCHECK(CalledOnValidThread());
1123 DCHECK(!ipv6_probe_monitoring_);
1124 ipv6_probe_monitoring_ = true;
1125 OnIPAddressChanged(); // Give initial setup call.
1126}
1127
1128void HostResolverImpl::SetPoolConstraints(JobPoolIndex pool_index,
1129 size_t max_outstanding_jobs,
1130 size_t max_pending_requests) {
1131 DCHECK(CalledOnValidThread());
1132 CHECK_GE(pool_index, 0);
1133 CHECK_LT(pool_index, POOL_COUNT);
1134 CHECK(jobs_.empty()) << "Can only set constraints during setup";
1135 JobPool* pool = job_pools_[pool_index];
1136 pool->SetConstraints(max_outstanding_jobs, max_pending_requests);
1137}
1138
[email protected]684970b2009-08-14 04:54:461139int HostResolverImpl::Resolve(const RequestInfo& info,
[email protected]b59ff372009-07-15 22:04:321140 AddressList* addresses,
[email protected]f1f3f0f82011-10-01 20:38:101141 OldCompletionCallback* callback,
[email protected]684970b2009-08-14 04:54:461142 RequestHandle* out_req,
[email protected]ee094b82010-08-24 15:55:511143 const BoundNetLog& source_net_log) {
[email protected]95a214c2011-08-04 21:50:401144 DCHECK(addresses);
1145 DCHECK(callback);
[email protected]1ac6af92010-06-03 21:00:141146 DCHECK(CalledOnValidThread());
1147
[email protected]b59ff372009-07-15 22:04:321148 // Choose a unique ID number for observers to see.
1149 int request_id = next_request_id_++;
1150
[email protected]ee094b82010-08-24 15:55:511151 // Make a log item for the request.
1152 BoundNetLog request_net_log = BoundNetLog::Make(net_log_,
1153 NetLog::SOURCE_HOST_RESOLVER_IMPL_REQUEST);
1154
[email protected]9e743cd2010-03-16 07:03:531155 // Update the net log and notify registered observers.
[email protected]ee094b82010-08-24 15:55:511156 OnStartRequest(source_net_log, request_net_log, request_id, info);
[email protected]b59ff372009-07-15 22:04:321157
[email protected]123ab1e32009-10-21 19:12:571158 // Build a key that identifies the request in the cache and in the
1159 // outstanding jobs map.
[email protected]137af622010-02-05 02:14:351160 Key key = GetEffectiveKeyForRequest(info);
[email protected]123ab1e32009-10-21 19:12:571161
[email protected]95a214c2011-08-04 21:50:401162 int rv = ResolveHelper(request_id, key, info, addresses,
1163 source_net_log, request_net_log);
1164 if (rv != ERR_DNS_CACHE_MISS) {
[email protected]eaf3a3b2010-09-03 20:34:271165 OnFinishRequest(source_net_log, request_net_log, request_id, info,
[email protected]95a214c2011-08-04 21:50:401166 rv,
1167 0 /* os_error (unknown since from cache) */);
1168 return rv;
[email protected]38368712011-03-02 08:09:401169 }
1170
[email protected]6e78dfb2011-07-28 21:34:471171 // Create a handle for this request, and pass it back to the user if they
[email protected]b59ff372009-07-15 22:04:321172 // asked for it (out_req != NULL).
[email protected]ee094b82010-08-24 15:55:511173 Request* req = new Request(source_net_log, request_net_log, request_id, info,
1174 callback, addresses);
[email protected]b59ff372009-07-15 22:04:321175 if (out_req)
1176 *out_req = reinterpret_cast<RequestHandle>(req);
1177
1178 // Next we need to attach our request to a "job". This job is responsible for
1179 // calling "getaddrinfo(hostname)" on a worker thread.
1180 scoped_refptr<Job> job;
1181
[email protected]123ab1e32009-10-21 19:12:571182 // If there is already an outstanding job to resolve |key|, use
[email protected]b59ff372009-07-15 22:04:321183 // it. This prevents starting concurrent resolves for the same hostname.
[email protected]123ab1e32009-10-21 19:12:571184 job = FindOutstandingJob(key);
[email protected]b59ff372009-07-15 22:04:321185 if (job) {
1186 job->AddRequest(req);
1187 } else {
[email protected]68ad3ee2010-01-30 03:45:391188 JobPool* pool = GetPoolForRequest(req);
1189 if (CanCreateJobForPool(*pool)) {
1190 CreateAndStartJob(req);
1191 } else {
1192 return EnqueueRequest(pool, req);
1193 }
[email protected]b59ff372009-07-15 22:04:321194 }
1195
1196 // Completion happens during OnJobComplete(Job*).
1197 return ERR_IO_PENDING;
1198}
1199
[email protected]95a214c2011-08-04 21:50:401200int HostResolverImpl::ResolveHelper(int request_id,
1201 const Key& key,
1202 const RequestInfo& info,
1203 AddressList* addresses,
1204 const BoundNetLog& request_net_log,
1205 const BoundNetLog& source_net_log) {
1206 // The result of |getaddrinfo| for empty hosts is inconsistent across systems.
1207 // On Windows it gives the default interface's address, whereas on Linux it
1208 // gives an error. We will make it fail on all platforms for consistency.
1209 if (info.hostname().empty() || info.hostname().size() > kMaxHostLength)
1210 return ERR_NAME_NOT_RESOLVED;
1211
1212 int net_error = ERR_UNEXPECTED;
1213 if (ResolveAsIP(key, info, &net_error, addresses))
1214 return net_error;
1215 net_error = ERR_DNS_CACHE_MISS;
1216 ServeFromCache(key, info, request_net_log, &net_error, addresses);
1217 return net_error;
1218}
1219
1220int HostResolverImpl::ResolveFromCache(const RequestInfo& info,
1221 AddressList* addresses,
1222 const BoundNetLog& source_net_log) {
1223 DCHECK(CalledOnValidThread());
1224 DCHECK(addresses);
1225
1226 // Choose a unique ID number for observers to see.
1227 int request_id = next_request_id_++;
1228
1229 // Make a log item for the request.
1230 BoundNetLog request_net_log = BoundNetLog::Make(net_log_,
1231 NetLog::SOURCE_HOST_RESOLVER_IMPL_REQUEST);
1232
1233 // Update the net log and notify registered observers.
1234 OnStartRequest(source_net_log, request_net_log, request_id, info);
1235
1236 // Build a key that identifies the request in the cache and in the
1237 // outstanding jobs map.
1238 Key key = GetEffectiveKeyForRequest(info);
1239
1240 int rv = ResolveHelper(request_id, key, info, addresses, request_net_log,
1241 source_net_log);
1242 OnFinishRequest(source_net_log, request_net_log, request_id, info,
1243 rv,
1244 0 /* os_error (unknown since from cache) */);
1245 return rv;
1246}
1247
[email protected]b59ff372009-07-15 22:04:321248// See OnJobComplete(Job*) for why it is important not to clean out
1249// cancelled requests from Job::requests_.
1250void HostResolverImpl::CancelRequest(RequestHandle req_handle) {
[email protected]1ac6af92010-06-03 21:00:141251 DCHECK(CalledOnValidThread());
[email protected]b59ff372009-07-15 22:04:321252 Request* req = reinterpret_cast<Request*>(req_handle);
1253 DCHECK(req);
[email protected]68ad3ee2010-01-30 03:45:391254
1255 scoped_ptr<Request> request_deleter; // Frees at end of function.
1256
1257 if (!req->job()) {
1258 // If the request was not attached to a job yet, it must have been
1259 // enqueued into a pool. Remove it from that pool's queue.
1260 // Otherwise if it was attached to a job, the job is responsible for
1261 // deleting it.
1262 JobPool* pool = GetPoolForRequest(req);
1263 pool->RemovePendingRequest(req);
1264 request_deleter.reset(req);
[email protected]ee094b82010-08-24 15:55:511265 } else {
1266 req->request_net_log().EndEvent(
1267 NetLog::TYPE_HOST_RESOLVER_IMPL_JOB_ATTACH, NULL);
[email protected]68ad3ee2010-01-30 03:45:391268 }
1269
[email protected]b59ff372009-07-15 22:04:321270 // NULL out the fields of req, to mark it as cancelled.
1271 req->MarkAsCancelled();
[email protected]ee094b82010-08-24 15:55:511272 OnCancelRequest(req->source_net_log(), req->request_net_log(), req->id(),
1273 req->info());
[email protected]b59ff372009-07-15 22:04:321274}
1275
[email protected]e95d3aca2010-01-11 22:47:431276void HostResolverImpl::AddObserver(HostResolver::Observer* observer) {
[email protected]1ac6af92010-06-03 21:00:141277 DCHECK(CalledOnValidThread());
[email protected]b59ff372009-07-15 22:04:321278 observers_.push_back(observer);
1279}
1280
[email protected]e95d3aca2010-01-11 22:47:431281void HostResolverImpl::RemoveObserver(HostResolver::Observer* observer) {
[email protected]1ac6af92010-06-03 21:00:141282 DCHECK(CalledOnValidThread());
[email protected]b59ff372009-07-15 22:04:321283 ObserversList::iterator it =
1284 std::find(observers_.begin(), observers_.end(), observer);
1285
1286 // Observer must exist.
1287 DCHECK(it != observers_.end());
1288
1289 observers_.erase(it);
1290}
1291
[email protected]0f8f1b432010-03-16 19:06:031292void HostResolverImpl::SetDefaultAddressFamily(AddressFamily address_family) {
[email protected]1ac6af92010-06-03 21:00:141293 DCHECK(CalledOnValidThread());
[email protected]0f8f1b432010-03-16 19:06:031294 ipv6_probe_monitoring_ = false;
1295 DiscardIPv6ProbeJob();
1296 default_address_family_ = address_family;
1297}
1298
[email protected]f7d310e2010-10-07 16:25:111299AddressFamily HostResolverImpl::GetDefaultAddressFamily() const {
1300 return default_address_family_;
1301}
1302
[email protected]ddb1e5a2010-12-13 20:10:451303HostResolverImpl* HostResolverImpl::GetAsHostResolverImpl() {
1304 return this;
1305}
1306
[email protected]489d1a82011-10-12 03:09:111307HostCache* HostResolverImpl::GetHostCache() {
1308 return cache_.get();
1309}
[email protected]95a214c2011-08-04 21:50:401310
1311bool HostResolverImpl::ResolveAsIP(const Key& key,
1312 const RequestInfo& info,
1313 int* net_error,
1314 AddressList* addresses) {
1315 DCHECK(addresses);
1316 DCHECK(net_error);
1317 IPAddressNumber ip_number;
1318 if (!ParseIPLiteralToNumber(key.hostname, &ip_number))
1319 return false;
1320
1321 DCHECK_EQ(key.host_resolver_flags &
1322 ~(HOST_RESOLVER_CANONNAME | HOST_RESOLVER_LOOPBACK_ONLY |
1323 HOST_RESOLVER_DEFAULT_FAMILY_SET_DUE_TO_NO_IPV6),
1324 0) << " Unhandled flag";
1325 bool ipv6_disabled = default_address_family_ == ADDRESS_FAMILY_IPV4 &&
1326 !ipv6_probe_monitoring_;
1327 *net_error = OK;
1328 if (ip_number.size() == 16 && ipv6_disabled) {
1329 *net_error = ERR_NAME_NOT_RESOLVED;
1330 } else {
1331 *addresses = AddressList::CreateFromIPAddressWithCname(
1332 ip_number, info.port(),
1333 (key.host_resolver_flags & HOST_RESOLVER_CANONNAME));
1334 }
1335 return true;
1336}
1337
1338bool HostResolverImpl::ServeFromCache(const Key& key,
1339 const RequestInfo& info,
1340 const BoundNetLog& request_net_log,
1341 int* net_error,
1342 AddressList* addresses) {
1343 DCHECK(addresses);
1344 DCHECK(net_error);
1345 if (!info.allow_cached_response() || !cache_.get())
1346 return false;
1347
1348 const HostCache::Entry* cache_entry = cache_->Lookup(
1349 key, base::TimeTicks::Now());
1350 if (!cache_entry)
1351 return false;
1352
1353 request_net_log.AddEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_CACHE_HIT, NULL);
1354 *net_error = cache_entry->error;
1355 if (*net_error == OK)
1356 *addresses = CreateAddressListUsingPort(cache_entry->addrlist, info.port());
1357 return true;
1358}
1359
[email protected]b59ff372009-07-15 22:04:321360void HostResolverImpl::AddOutstandingJob(Job* job) {
[email protected]123ab1e32009-10-21 19:12:571361 scoped_refptr<Job>& found_job = jobs_[job->key()];
[email protected]b59ff372009-07-15 22:04:321362 DCHECK(!found_job);
1363 found_job = job;
[email protected]68ad3ee2010-01-30 03:45:391364
1365 JobPool* pool = GetPoolForRequest(job->initial_request());
1366 pool->AdjustNumOutstandingJobs(1);
[email protected]b59ff372009-07-15 22:04:321367}
1368
[email protected]123ab1e32009-10-21 19:12:571369HostResolverImpl::Job* HostResolverImpl::FindOutstandingJob(const Key& key) {
1370 JobMap::iterator it = jobs_.find(key);
[email protected]b59ff372009-07-15 22:04:321371 if (it != jobs_.end())
1372 return it->second;
1373 return NULL;
1374}
1375
1376void HostResolverImpl::RemoveOutstandingJob(Job* job) {
[email protected]123ab1e32009-10-21 19:12:571377 JobMap::iterator it = jobs_.find(job->key());
[email protected]b59ff372009-07-15 22:04:321378 DCHECK(it != jobs_.end());
1379 DCHECK_EQ(it->second.get(), job);
1380 jobs_.erase(it);
[email protected]68ad3ee2010-01-30 03:45:391381
1382 JobPool* pool = GetPoolForRequest(job->initial_request());
1383 pool->AdjustNumOutstandingJobs(-1);
[email protected]b59ff372009-07-15 22:04:321384}
1385
1386void HostResolverImpl::OnJobComplete(Job* job,
[email protected]21526002010-05-16 19:42:461387 int net_error,
1388 int os_error,
[email protected]27f99c82009-10-29 22:21:001389 const AddressList& addrlist) {
[email protected]b59ff372009-07-15 22:04:321390 RemoveOutstandingJob(job);
1391
1392 // Write result to the cache.
[email protected]112bd462009-12-10 07:23:401393 if (cache_.get())
[email protected]21526002010-05-16 19:42:461394 cache_->Set(job->key(), net_error, addrlist, base::TimeTicks::Now());
[email protected]b59ff372009-07-15 22:04:321395
[email protected]ef4c40c2010-09-01 14:42:031396 OnJobCompleteInternal(job, net_error, os_error, addrlist);
1397}
1398
1399void HostResolverImpl::AbortJob(Job* job) {
1400 OnJobCompleteInternal(job, ERR_ABORTED, 0 /* no os_error */, AddressList());
1401}
1402
1403void HostResolverImpl::OnJobCompleteInternal(
1404 Job* job,
1405 int net_error,
1406 int os_error,
1407 const AddressList& addrlist) {
[email protected]b59ff372009-07-15 22:04:321408 // Make a note that we are executing within OnJobComplete() in case the
1409 // HostResolver is deleted by a callback invocation.
1410 DCHECK(!cur_completing_job_);
1411 cur_completing_job_ = job;
1412
[email protected]68ad3ee2010-01-30 03:45:391413 // Try to start any queued requests now that a job-slot has freed up.
1414 ProcessQueuedRequests();
1415
[email protected]b59ff372009-07-15 22:04:321416 // Complete all of the requests that were attached to the job.
1417 for (RequestsList::const_iterator it = job->requests().begin();
1418 it != job->requests().end(); ++it) {
1419 Request* req = *it;
1420 if (!req->was_cancelled()) {
1421 DCHECK_EQ(job, req->job());
[email protected]ee094b82010-08-24 15:55:511422 req->request_net_log().EndEvent(
1423 NetLog::TYPE_HOST_RESOLVER_IMPL_JOB_ATTACH, NULL);
[email protected]b59ff372009-07-15 22:04:321424
[email protected]9e743cd2010-03-16 07:03:531425 // Update the net log and notify registered observers.
[email protected]ee094b82010-08-24 15:55:511426 OnFinishRequest(req->source_net_log(), req->request_net_log(), req->id(),
1427 req->info(), net_error, os_error);
[email protected]b59ff372009-07-15 22:04:321428
[email protected]21526002010-05-16 19:42:461429 req->OnComplete(net_error, addrlist);
[email protected]b59ff372009-07-15 22:04:321430
1431 // Check if the job was cancelled as a result of running the callback.
1432 // (Meaning that |this| was deleted).
1433 if (job->was_cancelled())
1434 return;
1435 }
1436 }
1437
1438 cur_completing_job_ = NULL;
1439}
1440
[email protected]ee094b82010-08-24 15:55:511441void HostResolverImpl::OnStartRequest(const BoundNetLog& source_net_log,
1442 const BoundNetLog& request_net_log,
[email protected]54e13772009-08-14 03:01:091443 int request_id,
1444 const RequestInfo& info) {
[email protected]ee094b82010-08-24 15:55:511445 source_net_log.BeginEvent(
1446 NetLog::TYPE_HOST_RESOLVER_IMPL,
[email protected]00cd9c42010-11-02 20:15:571447 make_scoped_refptr(new NetLogSourceParameter(
1448 "source_dependency", request_net_log.source())));
[email protected]ee094b82010-08-24 15:55:511449
1450 request_net_log.BeginEvent(
1451 NetLog::TYPE_HOST_RESOLVER_IMPL_REQUEST,
[email protected]00cd9c42010-11-02 20:15:571452 make_scoped_refptr(new RequestInfoParameters(
1453 info, source_net_log.source())));
[email protected]54e13772009-08-14 03:01:091454
1455 // Notify the observers of the start.
1456 if (!observers_.empty()) {
[email protected]54e13772009-08-14 03:01:091457 for (ObserversList::iterator it = observers_.begin();
1458 it != observers_.end(); ++it) {
1459 (*it)->OnStartResolution(request_id, info);
1460 }
[email protected]b59ff372009-07-15 22:04:321461 }
1462}
1463
[email protected]ee094b82010-08-24 15:55:511464void HostResolverImpl::OnFinishRequest(const BoundNetLog& source_net_log,
1465 const BoundNetLog& request_net_log,
[email protected]54e13772009-08-14 03:01:091466 int request_id,
1467 const RequestInfo& info,
[email protected]21526002010-05-16 19:42:461468 int net_error,
[email protected]ee094b82010-08-24 15:55:511469 int os_error) {
[email protected]21526002010-05-16 19:42:461470 bool was_resolved = net_error == OK;
1471
[email protected]54e13772009-08-14 03:01:091472 // Notify the observers of the completion.
1473 if (!observers_.empty()) {
[email protected]54e13772009-08-14 03:01:091474 for (ObserversList::iterator it = observers_.begin();
1475 it != observers_.end(); ++it) {
1476 (*it)->OnFinishResolutionWithStatus(request_id, was_resolved, info);
1477 }
[email protected]b59ff372009-07-15 22:04:321478 }
[email protected]54e13772009-08-14 03:01:091479
[email protected]ee094b82010-08-24 15:55:511480 // Log some extra parameters on failure for synchronous requests.
[email protected]21526002010-05-16 19:42:461481 scoped_refptr<NetLog::EventParameters> params;
[email protected]ee094b82010-08-24 15:55:511482 if (!was_resolved) {
[email protected]13024882011-05-18 23:19:161483 params = new HostResolveFailedParams(0, net_error, os_error);
[email protected]ee094b82010-08-24 15:55:511484 }
[email protected]21526002010-05-16 19:42:461485
[email protected]ee094b82010-08-24 15:55:511486 request_net_log.EndEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_REQUEST, params);
1487 source_net_log.EndEvent(NetLog::TYPE_HOST_RESOLVER_IMPL, NULL);
[email protected]b59ff372009-07-15 22:04:321488}
1489
[email protected]ee094b82010-08-24 15:55:511490void HostResolverImpl::OnCancelRequest(const BoundNetLog& source_net_log,
1491 const BoundNetLog& request_net_log,
[email protected]54e13772009-08-14 03:01:091492 int request_id,
1493 const RequestInfo& info) {
[email protected]ee094b82010-08-24 15:55:511494 request_net_log.AddEvent(NetLog::TYPE_CANCELLED, NULL);
[email protected]54e13772009-08-14 03:01:091495
1496 // Notify the observers of the cancellation.
1497 if (!observers_.empty()) {
[email protected]54e13772009-08-14 03:01:091498 for (ObserversList::iterator it = observers_.begin();
1499 it != observers_.end(); ++it) {
1500 (*it)->OnCancelResolution(request_id, info);
1501 }
[email protected]b59ff372009-07-15 22:04:321502 }
[email protected]54e13772009-08-14 03:01:091503
[email protected]ee094b82010-08-24 15:55:511504 request_net_log.EndEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_REQUEST, NULL);
1505 source_net_log.EndEvent(NetLog::TYPE_HOST_RESOLVER_IMPL, NULL);
[email protected]b59ff372009-07-15 22:04:321506}
1507
[email protected]0f8f1b432010-03-16 19:06:031508void HostResolverImpl::DiscardIPv6ProbeJob() {
1509 if (ipv6_probe_job_.get()) {
1510 ipv6_probe_job_->Cancel();
1511 ipv6_probe_job_ = NULL;
1512 }
1513}
1514
1515void HostResolverImpl::IPv6ProbeSetDefaultAddressFamily(
1516 AddressFamily address_family) {
1517 DCHECK(address_family == ADDRESS_FAMILY_UNSPECIFIED ||
1518 address_family == ADDRESS_FAMILY_IPV4);
[email protected]f092e64b2010-03-17 00:39:181519 if (default_address_family_ != address_family) {
[email protected]b30a3f52010-10-16 01:05:461520 VLOG(1) << "IPv6Probe forced AddressFamily setting to "
1521 << ((address_family == ADDRESS_FAMILY_UNSPECIFIED) ?
1522 "ADDRESS_FAMILY_UNSPECIFIED" : "ADDRESS_FAMILY_IPV4");
[email protected]f092e64b2010-03-17 00:39:181523 }
[email protected]0f8f1b432010-03-16 19:06:031524 default_address_family_ = address_family;
1525 // Drop reference since the job has called us back.
1526 DiscardIPv6ProbeJob();
[email protected]e95d3aca2010-01-11 22:47:431527}
1528
[email protected]68ad3ee2010-01-30 03:45:391529bool HostResolverImpl::CanCreateJobForPool(const JobPool& pool) const {
1530 DCHECK_LE(jobs_.size(), max_jobs_);
1531
1532 // We can't create another job if it would exceed the global total.
1533 if (jobs_.size() + 1 > max_jobs_)
1534 return false;
1535
1536 // Check whether the pool's constraints are met.
1537 return pool.CanCreateJob();
1538}
1539
[email protected]be1a48b2011-01-20 00:12:131540// static
1541HostResolverImpl::JobPoolIndex HostResolverImpl::GetJobPoolIndexForRequest(
1542 const Request* req) {
1543 return POOL_NORMAL;
1544}
1545
[email protected]68ad3ee2010-01-30 03:45:391546void HostResolverImpl::ProcessQueuedRequests() {
1547 // Find the highest priority request that can be scheduled.
1548 Request* top_req = NULL;
1549 for (size_t i = 0; i < arraysize(job_pools_); ++i) {
1550 JobPool* pool = job_pools_[i];
1551 if (pool->HasPendingRequests() && CanCreateJobForPool(*pool)) {
1552 top_req = pool->RemoveTopPendingRequest();
1553 break;
1554 }
1555 }
1556
1557 if (!top_req)
1558 return;
1559
[email protected]ad8e04a2010-11-01 04:16:271560 scoped_refptr<Job> job(CreateAndStartJob(top_req));
[email protected]68ad3ee2010-01-30 03:45:391561
1562 // Search for any other pending request which can piggy-back off this job.
1563 for (size_t pool_i = 0; pool_i < POOL_COUNT; ++pool_i) {
1564 JobPool* pool = job_pools_[pool_i];
1565 pool->MoveRequestsToJob(job);
1566 }
1567}
1568
[email protected]137af622010-02-05 02:14:351569HostResolverImpl::Key HostResolverImpl::GetEffectiveKeyForRequest(
1570 const RequestInfo& info) const {
[email protected]eaf3a3b2010-09-03 20:34:271571 HostResolverFlags effective_flags =
1572 info.host_resolver_flags() | additional_resolver_flags_;
[email protected]137af622010-02-05 02:14:351573 AddressFamily effective_address_family = info.address_family();
[email protected]eaf3a3b2010-09-03 20:34:271574 if (effective_address_family == ADDRESS_FAMILY_UNSPECIFIED &&
1575 default_address_family_ != ADDRESS_FAMILY_UNSPECIFIED) {
[email protected]137af622010-02-05 02:14:351576 effective_address_family = default_address_family_;
[email protected]eaf3a3b2010-09-03 20:34:271577 if (ipv6_probe_monitoring_)
1578 effective_flags |= HOST_RESOLVER_DEFAULT_FAMILY_SET_DUE_TO_NO_IPV6;
1579 }
1580 return Key(info.hostname(), effective_address_family, effective_flags);
[email protected]137af622010-02-05 02:14:351581}
1582
[email protected]68ad3ee2010-01-30 03:45:391583HostResolverImpl::Job* HostResolverImpl::CreateAndStartJob(Request* req) {
1584 DCHECK(CanCreateJobForPool(*GetPoolForRequest(req)));
[email protected]137af622010-02-05 02:14:351585 Key key = GetEffectiveKeyForRequest(req->info());
[email protected]ee094b82010-08-24 15:55:511586
1587 req->request_net_log().AddEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_CREATE_JOB,
1588 NULL);
1589
[email protected]ad8e04a2010-11-01 04:16:271590 scoped_refptr<Job> job(new Job(next_job_id_++, this, key,
[email protected]06ef6d92011-05-19 04:24:581591 req->request_net_log(), net_log_));
[email protected]68ad3ee2010-01-30 03:45:391592 job->AddRequest(req);
1593 AddOutstandingJob(job);
1594 job->Start();
[email protected]ee094b82010-08-24 15:55:511595
[email protected]68ad3ee2010-01-30 03:45:391596 return job.get();
1597}
1598
1599int HostResolverImpl::EnqueueRequest(JobPool* pool, Request* req) {
1600 scoped_ptr<Request> req_evicted_from_queue(
1601 pool->InsertPendingRequest(req));
1602
1603 // If the queue has become too large, we need to kick something out.
1604 if (req_evicted_from_queue.get()) {
1605 Request* r = req_evicted_from_queue.get();
1606 int error = ERR_HOST_RESOLVER_QUEUE_TOO_LARGE;
1607
[email protected]ee094b82010-08-24 15:55:511608 OnFinishRequest(r->source_net_log(), r->request_net_log(), r->id(),
1609 r->info(), error,
1610 0 /* os_error (not applicable) */);
[email protected]68ad3ee2010-01-30 03:45:391611
1612 if (r == req)
1613 return error;
1614
1615 r->OnComplete(error, AddressList());
1616 }
1617
1618 return ERR_IO_PENDING;
1619}
1620
[email protected]ef4c40c2010-09-01 14:42:031621void HostResolverImpl::CancelAllJobs() {
1622 JobMap jobs;
1623 jobs.swap(jobs_);
1624 for (JobMap::iterator it = jobs.begin(); it != jobs.end(); ++it)
1625 it->second->Cancel();
1626}
1627
[email protected]35ddc282010-09-21 23:42:061628void HostResolverImpl::AbortAllInProgressJobs() {
1629 for (size_t i = 0; i < arraysize(job_pools_); ++i)
1630 job_pools_[i]->ResetNumOutstandingJobs();
[email protected]ef4c40c2010-09-01 14:42:031631 JobMap jobs;
1632 jobs.swap(jobs_);
1633 for (JobMap::iterator it = jobs.begin(); it != jobs.end(); ++it) {
1634 AbortJob(it->second);
1635 it->second->Cancel();
1636 }
1637}
1638
[email protected]be1a48b2011-01-20 00:12:131639void HostResolverImpl::OnIPAddressChanged() {
1640 if (cache_.get())
1641 cache_->clear();
1642 if (ipv6_probe_monitoring_) {
[email protected]be1a48b2011-01-20 00:12:131643 DiscardIPv6ProbeJob();
1644 ipv6_probe_job_ = new IPv6ProbeJob(this);
1645 ipv6_probe_job_->Start();
1646 }
[email protected]23f771162011-06-02 18:37:511647#if defined(OS_POSIX) && !defined(OS_MACOSX)
[email protected]be1a48b2011-01-20 00:12:131648 if (HaveOnlyLoopbackAddresses()) {
1649 additional_resolver_flags_ |= HOST_RESOLVER_LOOPBACK_ONLY;
1650 } else {
1651 additional_resolver_flags_ &= ~HOST_RESOLVER_LOOPBACK_ONLY;
1652 }
1653#endif
1654 AbortAllInProgressJobs();
1655 // |this| may be deleted inside AbortAllInProgressJobs().
1656}
1657
[email protected]46018c9d2011-09-06 03:42:341658void HostResolverImpl::OnDNSChanged() {
1659 // If the DNS server has changed, existing cached info could be wrong so we
1660 // have to drop our internal cache :( Note that OS level DNS caches, such
1661 // as NSCD's cache should be dropped automatically by the OS when
1662 // resolv.conf changes so we don't need to do anything to clear that cache.
1663 if (cache_.get())
1664 cache_->clear();
1665 // Existing jobs will have been sent to the original server so they need to
1666 // be aborted. TODO(Craig): Should these jobs be restarted?
1667 AbortAllInProgressJobs();
1668 // |this| may be deleted inside AbortAllInProgressJobs().
1669}
1670
[email protected]b59ff372009-07-15 22:04:321671} // namespace net