blob: 2f9e4bb00b438b913543a897ec3ce563d1f405a1 [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]b59ff372009-07-15 22:04:3224#include "base/stl_util-inl.h"
25#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"
33#include "net/base/host_port_pair.h"
[email protected]b59ff372009-07-15 22:04:3234#include "net/base/host_resolver_proc.h"
[email protected]2bb04442010-08-18 18:01:1535#include "net/base/net_errors.h"
[email protected]ee094b82010-08-24 15:55:5136#include "net/base/net_log.h"
[email protected]0f8f1b432010-03-16 19:06:0337#include "net/base/net_util.h"
[email protected]b59ff372009-07-15 22:04:3238
39#if defined(OS_WIN)
40#include "net/base/winsock_init.h"
41#endif
42
43namespace net {
44
[email protected]e95d3aca2010-01-11 22:47:4345namespace {
46
[email protected]fe89ea72011-05-12 02:02:4047// Helper to create an AddressList that has a particular port. It has an
48// optimization to avoid allocating a new address linked list when the
49// port is already what we want.
50AddressList CreateAddressListUsingPort(const AddressList& src, int port) {
51 if (src.GetPort() == port)
52 return src;
53
54 AddressList out = src;
55 out.SetPort(port);
56 return out;
57}
58
59// Helper to mutate the linked list contained by AddressList to the given
60// port. Note that in general this is dangerous since the AddressList's
61// data might be shared (and you should use AddressList::SetPort).
62//
63// However since we allocated the AddressList ourselves we can safely
64// do this optimization and avoid reallocating the list.
65void MutableSetPort(int port, AddressList* addrlist) {
66 struct addrinfo* mutable_head =
67 const_cast<struct addrinfo*>(addrlist->head());
68 SetPortForAllAddrinfos(mutable_head, port);
69}
70
[email protected]24f4bab2010-10-15 01:27:1171// We use a separate histogram name for each platform to facilitate the
72// display of error codes by their symbolic name (since each platform has
73// different mappings).
74const char kOSErrorsForGetAddrinfoHistogramName[] =
75#if defined(OS_WIN)
76 "Net.OSErrorsForGetAddrinfo_Win";
77#elif defined(OS_MACOSX)
78 "Net.OSErrorsForGetAddrinfo_Mac";
79#elif defined(OS_LINUX)
80 "Net.OSErrorsForGetAddrinfo_Linux";
81#else
82 "Net.OSErrorsForGetAddrinfo";
83#endif
84
[email protected]e95d3aca2010-01-11 22:47:4385HostCache* CreateDefaultCache() {
[email protected]b59ff372009-07-15 22:04:3286 static const size_t kMaxHostCacheEntries = 100;
[email protected]112bd462009-12-10 07:23:4087
88 HostCache* cache = new HostCache(
89 kMaxHostCacheEntries,
90 base::TimeDelta::FromMinutes(1),
[email protected]72bceac2010-06-17 21:45:0891 base::TimeDelta::FromSeconds(0)); // Disable caching of failed DNS.
[email protected]112bd462009-12-10 07:23:4092
[email protected]e95d3aca2010-01-11 22:47:4393 return cache;
94}
95
96} // anonymous namespace
97
[email protected]189163e2011-05-11 01:48:5498// static
[email protected]ee094b82010-08-24 15:55:5199HostResolver* CreateSystemHostResolver(size_t max_concurrent_resolves,
[email protected]06ef6d92011-05-19 04:24:58100 size_t max_retry_attempts,
[email protected]ee094b82010-08-24 15:55:51101 NetLog* net_log) {
[email protected]755a93352010-10-29 06:33:59102 // Maximum of 8 concurrent resolver threads.
103 // Some routers (or resolvers) appear to start to provide host-not-found if
104 // too many simultaneous resolutions are pending. This number needs to be
105 // further optimized, but 8 is what FF currently does.
106 static const size_t kDefaultMaxJobs = 8u;
[email protected]962b98212010-07-17 03:37:51107
108 if (max_concurrent_resolves == HostResolver::kDefaultParallelism)
109 max_concurrent_resolves = kDefaultMaxJobs;
[email protected]68ad3ee2010-01-30 03:45:39110
[email protected]66761b952010-06-25 21:30:38111 HostResolverImpl* resolver =
[email protected]06ef6d92011-05-19 04:24:58112 new HostResolverImpl(NULL, CreateDefaultCache(), max_concurrent_resolves,
113 max_retry_attempts, net_log);
[email protected]68ad3ee2010-01-30 03:45:39114
115 return resolver;
[email protected]b59ff372009-07-15 22:04:32116}
117
118static int ResolveAddrInfo(HostResolverProc* resolver_proc,
[email protected]123ab1e32009-10-21 19:12:57119 const std::string& host,
120 AddressFamily address_family,
[email protected]5ea28dea2010-04-08 15:35:13121 HostResolverFlags host_resolver_flags,
[email protected]21526002010-05-16 19:42:46122 AddressList* out,
123 int* os_error) {
[email protected]b59ff372009-07-15 22:04:32124 if (resolver_proc) {
125 // Use the custom procedure.
[email protected]5ea28dea2010-04-08 15:35:13126 return resolver_proc->Resolve(host, address_family,
[email protected]21526002010-05-16 19:42:46127 host_resolver_flags, out, os_error);
[email protected]b59ff372009-07-15 22:04:32128 } else {
129 // Use the system procedure (getaddrinfo).
[email protected]5ea28dea2010-04-08 15:35:13130 return SystemHostResolverProc(host, address_family,
[email protected]21526002010-05-16 19:42:46131 host_resolver_flags, out, os_error);
[email protected]b59ff372009-07-15 22:04:32132 }
133}
134
[email protected]21526002010-05-16 19:42:46135// Extra parameters to attach to the NetLog when the resolve failed.
136class HostResolveFailedParams : public NetLog::EventParameters {
137 public:
[email protected]13024882011-05-18 23:19:16138 HostResolveFailedParams(uint32 attempt_number,
139 int net_error,
140 int os_error)
141 : attempt_number_(attempt_number),
142 net_error_(net_error),
[email protected]ee094b82010-08-24 15:55:51143 os_error_(os_error) {
[email protected]21526002010-05-16 19:42:46144 }
145
146 virtual Value* ToValue() const {
147 DictionaryValue* dict = new DictionaryValue();
[email protected]13024882011-05-18 23:19:16148 if (attempt_number_)
149 dict->SetInteger("attempt_number", attempt_number_);
150
[email protected]ccaff652010-07-31 06:28:20151 dict->SetInteger("net_error", net_error_);
[email protected]21526002010-05-16 19:42:46152
153 if (os_error_) {
[email protected]ccaff652010-07-31 06:28:20154 dict->SetInteger("os_error", os_error_);
[email protected]21526002010-05-16 19:42:46155#if defined(OS_POSIX)
[email protected]ccaff652010-07-31 06:28:20156 dict->SetString("os_error_string", gai_strerror(os_error_));
[email protected]21526002010-05-16 19:42:46157#elif defined(OS_WIN)
158 // Map the error code to a human-readable string.
159 LPWSTR error_string = NULL;
160 int size = FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
161 FORMAT_MESSAGE_FROM_SYSTEM,
162 0, // Use the internal message table.
163 os_error_,
164 0, // Use default language.
165 (LPWSTR)&error_string,
166 0, // Buffer size.
167 0); // Arguments (unused).
[email protected]ccaff652010-07-31 06:28:20168 dict->SetString("os_error_string", WideToUTF8(error_string));
[email protected]21526002010-05-16 19:42:46169 LocalFree(error_string);
170#endif
171 }
172
173 return dict;
174 }
175
176 private:
[email protected]13024882011-05-18 23:19:16177 const uint32 attempt_number_;
[email protected]21526002010-05-16 19:42:46178 const int net_error_;
179 const int os_error_;
[email protected]ee094b82010-08-24 15:55:51180};
181
182// Parameters representing the information in a RequestInfo object, along with
183// the associated NetLog::Source.
184class RequestInfoParameters : public NetLog::EventParameters {
185 public:
186 RequestInfoParameters(const HostResolver::RequestInfo& info,
187 const NetLog::Source& source)
188 : info_(info), source_(source) {}
189
190 virtual Value* ToValue() const {
191 DictionaryValue* dict = new DictionaryValue();
[email protected]930cc742010-09-15 22:54:10192 dict->SetString("host", info_.host_port_pair().ToString());
[email protected]ee094b82010-08-24 15:55:51193 dict->SetInteger("address_family",
194 static_cast<int>(info_.address_family()));
195 dict->SetBoolean("allow_cached_response", info_.allow_cached_response());
[email protected]38368712011-03-02 08:09:40196 dict->SetBoolean("only_use_cached_response",
197 info_.only_use_cached_response());
[email protected]ee094b82010-08-24 15:55:51198 dict->SetBoolean("is_speculative", info_.is_speculative());
199 dict->SetInteger("priority", info_.priority());
200
201 if (source_.is_valid())
202 dict->Set("source_dependency", source_.ToValue());
203
204 return dict;
205 }
206
207 private:
208 const HostResolver::RequestInfo info_;
209 const NetLog::Source source_;
210};
211
[email protected]7b496b32011-02-28 22:25:59212// Parameters associated with the creation of a HostResolverImpl::Job.
[email protected]ee094b82010-08-24 15:55:51213class JobCreationParameters : public NetLog::EventParameters {
214 public:
215 JobCreationParameters(const std::string& host, const NetLog::Source& source)
216 : host_(host), source_(source) {}
217
218 virtual Value* ToValue() const {
219 DictionaryValue* dict = new DictionaryValue();
220 dict->SetString("host", host_);
221 dict->Set("source_dependency", source_.ToValue());
222 return dict;
223 }
224
225 private:
226 const std::string host_;
227 const NetLog::Source source_;
[email protected]21526002010-05-16 19:42:46228};
229
230// Gets a list of the likely error codes that getaddrinfo() can return
231// (non-exhaustive). These are the error codes that we will track via
232// a histogram.
233std::vector<int> GetAllGetAddrinfoOSErrors() {
234 int os_errors[] = {
235#if defined(OS_POSIX)
236 EAI_ADDRFAMILY,
237 EAI_AGAIN,
238 EAI_BADFLAGS,
239 EAI_FAIL,
240 EAI_FAMILY,
241 EAI_MEMORY,
242 EAI_NODATA,
243 EAI_NONAME,
244 EAI_SERVICE,
245 EAI_SOCKTYPE,
246 EAI_SYSTEM,
247#elif defined(OS_WIN)
248 // See: http://msdn.microsoft.com/en-us/library/ms738520(VS.85).aspx
249 WSA_NOT_ENOUGH_MEMORY,
250 WSAEAFNOSUPPORT,
251 WSAEINVAL,
252 WSAESOCKTNOSUPPORT,
253 WSAHOST_NOT_FOUND,
254 WSANO_DATA,
255 WSANO_RECOVERY,
256 WSANOTINITIALISED,
257 WSATRY_AGAIN,
258 WSATYPE_NOT_FOUND,
[email protected]1e9bbd22010-10-15 16:42:45259 // The following are not in doc, but might be to appearing in results :-(.
260 WSA_INVALID_HANDLE,
[email protected]21526002010-05-16 19:42:46261#endif
262 };
263
264 // Histogram enumerations require positive numbers.
265 std::vector<int> errors;
266 for (size_t i = 0; i < arraysize(os_errors); ++i) {
267 errors.push_back(std::abs(os_errors[i]));
268 // Also add N+1 for each error, so the bucket that contains our expected
269 // error is of size 1. That way if we get unexpected error codes, they
270 // won't fall into the same buckets as the expected ones.
271 errors.push_back(std::abs(os_errors[i]) + 1);
272 }
273 return errors;
274}
275
[email protected]b59ff372009-07-15 22:04:32276//-----------------------------------------------------------------------------
277
278class HostResolverImpl::Request {
279 public:
[email protected]ee094b82010-08-24 15:55:51280 Request(const BoundNetLog& source_net_log,
281 const BoundNetLog& request_net_log,
[email protected]54e13772009-08-14 03:01:09282 int id,
283 const RequestInfo& info,
284 CompletionCallback* callback,
[email protected]b59ff372009-07-15 22:04:32285 AddressList* addresses)
[email protected]ee094b82010-08-24 15:55:51286 : source_net_log_(source_net_log),
287 request_net_log_(request_net_log),
[email protected]54e13772009-08-14 03:01:09288 id_(id),
289 info_(info),
290 job_(NULL),
291 callback_(callback),
292 addresses_(addresses) {
293 }
[email protected]b59ff372009-07-15 22:04:32294
295 // Mark the request as cancelled.
296 void MarkAsCancelled() {
297 job_ = NULL;
298 callback_ = NULL;
299 addresses_ = NULL;
300 }
301
302 bool was_cancelled() const {
303 return callback_ == NULL;
304 }
305
306 void set_job(Job* job) {
307 DCHECK(job != NULL);
308 // Identify which job the request is waiting on.
309 job_ = job;
310 }
311
312 void OnComplete(int error, const AddressList& addrlist) {
313 if (error == OK)
[email protected]fe89ea72011-05-12 02:02:40314 *addresses_ = CreateAddressListUsingPort(addrlist, port());
[email protected]ef4c40c2010-09-01 14:42:03315 CompletionCallback* callback = callback_;
316 MarkAsCancelled();
317 callback->Run(error);
[email protected]b59ff372009-07-15 22:04:32318 }
319
320 int port() const {
321 return info_.port();
322 }
323
324 Job* job() const {
325 return job_;
326 }
327
[email protected]ee094b82010-08-24 15:55:51328 const BoundNetLog& source_net_log() {
329 return source_net_log_;
330 }
331
332 const BoundNetLog& request_net_log() {
333 return request_net_log_;
[email protected]54e13772009-08-14 03:01:09334 }
335
[email protected]b59ff372009-07-15 22:04:32336 int id() const {
337 return id_;
338 }
339
340 const RequestInfo& info() const {
341 return info_;
342 }
343
344 private:
[email protected]ee094b82010-08-24 15:55:51345 BoundNetLog source_net_log_;
346 BoundNetLog request_net_log_;
[email protected]54e13772009-08-14 03:01:09347
[email protected]b59ff372009-07-15 22:04:32348 // Unique ID for this request. Used by observers to identify requests.
349 int id_;
350
351 // The request info that started the request.
352 RequestInfo info_;
353
354 // The resolve job (running in worker pool) that this request is dependent on.
355 Job* job_;
356
357 // The user's callback to invoke when the request completes.
358 CompletionCallback* callback_;
359
360 // The address list to save result into.
361 AddressList* addresses_;
362
363 DISALLOW_COPY_AND_ASSIGN(Request);
364};
365
[email protected]1e9bbd22010-10-15 16:42:45366//------------------------------------------------------------------------------
367
368// Provide a common macro to simplify code and readability. We must use a
369// macros as the underlying HISTOGRAM macro creates static varibles.
370#define DNS_HISTOGRAM(name, time) UMA_HISTOGRAM_CUSTOM_TIMES(name, time, \
371 base::TimeDelta::FromMicroseconds(1), base::TimeDelta::FromHours(1), 100)
[email protected]b59ff372009-07-15 22:04:32372
373// This class represents a request to the worker pool for a "getaddrinfo()"
374// call.
375class HostResolverImpl::Job
376 : public base::RefCountedThreadSafe<HostResolverImpl::Job> {
377 public:
[email protected]ee094b82010-08-24 15:55:51378 Job(int id,
379 HostResolverImpl* resolver,
380 const Key& key,
381 const BoundNetLog& source_net_log,
382 NetLog* net_log)
383 : id_(id),
384 key_(key),
385 resolver_(resolver),
[email protected]3e9d9cc2011-05-03 21:08:15386 origin_loop_(base::MessageLoopProxy::CreateForCurrentThread()),
[email protected]ee094b82010-08-24 15:55:51387 resolver_proc_(resolver->effective_resolver_proc()),
[email protected]189163e2011-05-11 01:48:54388 unresponsive_delay_(resolver->unresponsive_delay()),
389 attempt_number_(0),
390 completed_attempt_number_(0),
391 completed_attempt_error_(ERR_UNEXPECTED),
[email protected]ee094b82010-08-24 15:55:51392 had_non_speculative_request_(false),
393 net_log_(BoundNetLog::Make(net_log,
394 NetLog::SOURCE_HOST_RESOLVER_IMPL_JOB)) {
[email protected]3e9d9cc2011-05-03 21:08:15395 DCHECK(resolver);
[email protected]00cd9c42010-11-02 20:15:57396 net_log_.BeginEvent(
397 NetLog::TYPE_HOST_RESOLVER_IMPL_JOB,
398 make_scoped_refptr(
399 new JobCreationParameters(key.hostname, source_net_log.source())));
[email protected]b59ff372009-07-15 22:04:32400 }
401
[email protected]b59ff372009-07-15 22:04:32402 // Attaches a request to this job. The job takes ownership of |req| and will
403 // take care to delete it.
404 void AddRequest(Request* req) {
[email protected]3e9d9cc2011-05-03 21:08:15405 DCHECK(origin_loop_->BelongsToCurrentThread());
[email protected]ee094b82010-08-24 15:55:51406 req->request_net_log().BeginEvent(
407 NetLog::TYPE_HOST_RESOLVER_IMPL_JOB_ATTACH,
[email protected]00cd9c42010-11-02 20:15:57408 make_scoped_refptr(new NetLogSourceParameter(
409 "source_dependency", net_log_.source())));
[email protected]ee094b82010-08-24 15:55:51410
[email protected]b59ff372009-07-15 22:04:32411 req->set_job(this);
412 requests_.push_back(req);
[email protected]252b699b2010-02-05 21:38:06413
414 if (!req->info().is_speculative())
415 had_non_speculative_request_ = true;
[email protected]b59ff372009-07-15 22:04:32416 }
417
[email protected]b59ff372009-07-15 22:04:32418 void Start() {
[email protected]3e9d9cc2011-05-03 21:08:15419 DCHECK(origin_loop_->BelongsToCurrentThread());
[email protected]189163e2011-05-11 01:48:54420 StartLookupAttempt();
421 }
[email protected]252b699b2010-02-05 21:38:06422
[email protected]189163e2011-05-11 01:48:54423 void StartLookupAttempt() {
424 DCHECK(origin_loop_->BelongsToCurrentThread());
425 base::TimeTicks start_time = base::TimeTicks::Now();
426 ++attempt_number_;
427 // Dispatch the lookup attempt to a worker thread.
428 if (!base::WorkerPool::PostTask(
429 FROM_HERE,
430 NewRunnableMethod(this, &Job::DoLookup, start_time,
431 attempt_number_),
432 true)) {
[email protected]b59ff372009-07-15 22:04:32433 NOTREACHED();
434
435 // Since we could be running within Resolve() right now, we can't just
436 // call OnLookupComplete(). Instead we must wait until Resolve() has
437 // returned (IO_PENDING).
[email protected]3e9d9cc2011-05-03 21:08:15438 origin_loop_->PostTask(
[email protected]189163e2011-05-11 01:48:54439 FROM_HERE,
440 NewRunnableMethod(this, &Job::OnLookupComplete, AddressList(),
441 start_time, attempt_number_, ERR_UNEXPECTED, 0));
442 return;
[email protected]b59ff372009-07-15 22:04:32443 }
[email protected]13024882011-05-18 23:19:16444
445 net_log_.AddEvent(
446 NetLog::TYPE_HOST_RESOLVER_IMPL_ATTEMPT_STARTED,
447 make_scoped_refptr(new NetLogIntegerParameter(
448 "attempt_number", attempt_number_)));
449
[email protected]189163e2011-05-11 01:48:54450 // Post a task to check if we get the results within a given time.
451 // OnCheckForComplete has the potential for starting a new attempt on a
452 // different worker thread if none of our outstanding attempts have
453 // completed yet.
[email protected]06ef6d92011-05-19 04:24:58454 if (attempt_number_ <= resolver_->max_retry_attempts()) {
455 origin_loop_->PostDelayedTask(
456 FROM_HERE,
457 NewRunnableMethod(this, &Job::OnCheckForComplete),
458 unresponsive_delay_.InMilliseconds());
459 }
[email protected]b59ff372009-07-15 22:04:32460 }
461
[email protected]189163e2011-05-11 01:48:54462 // Cancels the current job. The Job will be orphaned. Any outstanding resolve
463 // attempts running on worker threads will continue running. Only once all the
464 // attempts complete will the final reference to this Job be released.
[email protected]b59ff372009-07-15 22:04:32465 void Cancel() {
[email protected]3e9d9cc2011-05-03 21:08:15466 DCHECK(origin_loop_->BelongsToCurrentThread());
[email protected]ee094b82010-08-24 15:55:51467 net_log_.AddEvent(NetLog::TYPE_CANCELLED, NULL);
468
[email protected]b59ff372009-07-15 22:04:32469 HostResolver* resolver = resolver_;
470 resolver_ = NULL;
471
[email protected]ee094b82010-08-24 15:55:51472 // End here to prevent issues when a Job outlives the HostResolver that
473 // spawned it.
474 net_log_.EndEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_JOB, NULL);
475
[email protected]1877a2212009-09-18 21:09:26476 // We will call HostResolverImpl::CancelRequest(Request*) on each one
[email protected]27f99c82009-10-29 22:21:00477 // in order to notify any observers.
[email protected]b59ff372009-07-15 22:04:32478 for (RequestsList::const_iterator it = requests_.begin();
479 it != requests_.end(); ++it) {
480 HostResolverImpl::Request* req = *it;
481 if (!req->was_cancelled())
482 resolver->CancelRequest(req);
483 }
484 }
485
[email protected]b59ff372009-07-15 22:04:32486 bool was_cancelled() const {
[email protected]3e9d9cc2011-05-03 21:08:15487 DCHECK(origin_loop_->BelongsToCurrentThread());
[email protected]b59ff372009-07-15 22:04:32488 return resolver_ == NULL;
489 }
490
[email protected]189163e2011-05-11 01:48:54491 bool was_completed() const {
492 DCHECK(origin_loop_->BelongsToCurrentThread());
493 return completed_attempt_number_ > 0;
494 }
495
[email protected]123ab1e32009-10-21 19:12:57496 const Key& key() const {
[email protected]3e9d9cc2011-05-03 21:08:15497 DCHECK(origin_loop_->BelongsToCurrentThread());
[email protected]123ab1e32009-10-21 19:12:57498 return key_;
[email protected]b59ff372009-07-15 22:04:32499 }
500
[email protected]a2fbebe2010-02-05 01:40:12501 int id() const {
[email protected]3e9d9cc2011-05-03 21:08:15502 DCHECK(origin_loop_->BelongsToCurrentThread());
[email protected]a2fbebe2010-02-05 01:40:12503 return id_;
504 }
505
[email protected]b59ff372009-07-15 22:04:32506 const RequestsList& requests() const {
[email protected]3e9d9cc2011-05-03 21:08:15507 DCHECK(origin_loop_->BelongsToCurrentThread());
[email protected]b59ff372009-07-15 22:04:32508 return requests_;
509 }
510
[email protected]68ad3ee2010-01-30 03:45:39511 // Returns the first request attached to the job.
512 const Request* initial_request() const {
[email protected]3e9d9cc2011-05-03 21:08:15513 DCHECK(origin_loop_->BelongsToCurrentThread());
[email protected]68ad3ee2010-01-30 03:45:39514 DCHECK(!requests_.empty());
515 return requests_[0];
516 }
517
[email protected]137af622010-02-05 02:14:35518 // Returns true if |req_info| can be fulfilled by this job.
519 bool CanServiceRequest(const RequestInfo& req_info) const {
[email protected]3e9d9cc2011-05-03 21:08:15520 DCHECK(origin_loop_->BelongsToCurrentThread());
[email protected]137af622010-02-05 02:14:35521 return key_ == resolver_->GetEffectiveKeyForRequest(req_info);
522 }
523
[email protected]b59ff372009-07-15 22:04:32524 private:
[email protected]5389bc72009-11-05 23:34:24525 friend class base::RefCountedThreadSafe<HostResolverImpl::Job>;
526
527 ~Job() {
528 // Free the requests attached to this job.
529 STLDeleteElements(&requests_);
530 }
531
[email protected]6c710ee2010-05-07 07:51:16532 // WARNING: This code runs inside a worker pool. The shutdown code cannot
533 // wait for it to finish, so we must be very careful here about using other
534 // objects (like MessageLoops, Singletons, etc). During shutdown these objects
[email protected]189163e2011-05-11 01:48:54535 // may no longer exist. Multiple DoLookups() could be running in parallel, so
536 // any state inside of |this| must not mutate .
537 void DoLookup(const base::TimeTicks& start_time,
538 const uint32 attempt_number) {
539 AddressList results;
540 int os_error = 0;
[email protected]b59ff372009-07-15 22:04:32541 // Running on the worker thread
[email protected]189163e2011-05-11 01:48:54542 int error = ResolveAddrInfo(resolver_proc_,
543 key_.hostname,
544 key_.address_family,
545 key_.host_resolver_flags,
546 &results,
547 &os_error);
[email protected]b59ff372009-07-15 22:04:32548
[email protected]189163e2011-05-11 01:48:54549 origin_loop_->PostTask(
550 FROM_HERE,
551 NewRunnableMethod(this, &Job::OnLookupComplete, results, start_time,
552 attempt_number, error, os_error));
553 }
554
555 // Callback to see if DoLookup() has finished or not (runs on origin thread).
556 void OnCheckForComplete() {
557 DCHECK(origin_loop_->BelongsToCurrentThread());
558
[email protected]06ef6d92011-05-19 04:24:58559 if (was_completed() || was_cancelled())
[email protected]189163e2011-05-11 01:48:54560 return;
561
562 DCHECK(resolver_);
[email protected]06ef6d92011-05-19 04:24:58563 unresponsive_delay_ *= resolver_->retry_factor();
[email protected]189163e2011-05-11 01:48:54564 StartLookupAttempt();
[email protected]b59ff372009-07-15 22:04:32565 }
566
567 // Callback for when DoLookup() completes (runs on origin thread).
[email protected]189163e2011-05-11 01:48:54568 void OnLookupComplete(const AddressList& results,
569 const base::TimeTicks& start_time,
570 const uint32 attempt_number,
571 int error,
572 const int os_error) {
[email protected]3e9d9cc2011-05-03 21:08:15573 DCHECK(origin_loop_->BelongsToCurrentThread());
[email protected]189163e2011-05-11 01:48:54574 DCHECK(error || results.head());
575
576 bool was_retry_attempt = attempt_number > 1;
577
578 if (!was_cancelled()) {
[email protected]13024882011-05-18 23:19:16579 scoped_refptr<NetLog::EventParameters> params;
580 if (error != OK) {
581 params = new HostResolveFailedParams(attempt_number, error, os_error);
582 } else {
583 params = new NetLogIntegerParameter("attempt_number", attempt_number_);
584 }
585 net_log_.AddEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_ATTEMPT_FINISHED,
586 params);
587
[email protected]189163e2011-05-11 01:48:54588 // If host is already resolved, then record data and return.
589 if (was_completed()) {
590 // If this is the first attempt that is finishing later, then record
591 // data for the first attempt. Won't contaminate with retry attempt's
592 // data.
593 if (!was_retry_attempt)
594 RecordPerformanceHistograms(start_time, error, os_error);
595
596 RecordAttemptHistograms(start_time, attempt_number, error, os_error);
597 return;
598 }
599
600 // Copy the results from the first worker thread that resolves the host.
601 results_ = results;
602 completed_attempt_number_ = attempt_number;
603 completed_attempt_error_ = error;
604 }
[email protected]b59ff372009-07-15 22:04:32605
[email protected]2d3b7762010-10-09 00:35:47606 // Ideally the following code would be part of host_resolver_proc.cc,
607 // however it isn't safe to call NetworkChangeNotifier from worker
608 // threads. So we do it here on the IO thread instead.
[email protected]189163e2011-05-11 01:48:54609 if (error != OK && NetworkChangeNotifier::IsOffline())
610 error = ERR_INTERNET_DISCONNECTED;
[email protected]2d3b7762010-10-09 00:35:47611
[email protected]189163e2011-05-11 01:48:54612 // We will record data for the first attempt. Don't contaminate with retry
613 // attempt's data.
614 if (!was_retry_attempt)
615 RecordPerformanceHistograms(start_time, error, os_error);
616
617 RecordAttemptHistograms(start_time, attempt_number, error, os_error);
[email protected]f2d8c4212010-02-02 00:56:35618
[email protected]b59ff372009-07-15 22:04:32619 if (was_cancelled())
620 return;
621
[email protected]ee094b82010-08-24 15:55:51622 scoped_refptr<NetLog::EventParameters> params;
[email protected]189163e2011-05-11 01:48:54623 if (error != OK) {
[email protected]13024882011-05-18 23:19:16624 params = new HostResolveFailedParams(0, error, os_error);
[email protected]ee094b82010-08-24 15:55:51625 } else {
626 params = new AddressListNetLogParam(results_);
627 }
628
629 // End here to prevent issues when a Job outlives the HostResolver that
630 // spawned it.
631 net_log_.EndEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_JOB, params);
632
[email protected]b59ff372009-07-15 22:04:32633 DCHECK(!requests_.empty());
634
635 // Use the port number of the first request.
[email protected]189163e2011-05-11 01:48:54636 if (error == OK)
[email protected]fe89ea72011-05-12 02:02:40637 MutableSetPort(requests_[0]->port(), &results_);
[email protected]b59ff372009-07-15 22:04:32638
[email protected]189163e2011-05-11 01:48:54639 resolver_->OnJobComplete(this, error, os_error, results_);
[email protected]b59ff372009-07-15 22:04:32640 }
641
[email protected]189163e2011-05-11 01:48:54642 void RecordPerformanceHistograms(const base::TimeTicks& start_time,
643 const int error,
644 const int os_error) const {
[email protected]3e9d9cc2011-05-03 21:08:15645 DCHECK(origin_loop_->BelongsToCurrentThread());
[email protected]1e9bbd22010-10-15 16:42:45646 enum Category { // Used in HISTOGRAM_ENUMERATION.
647 RESOLVE_SUCCESS,
648 RESOLVE_FAIL,
649 RESOLVE_SPECULATIVE_SUCCESS,
650 RESOLVE_SPECULATIVE_FAIL,
651 RESOLVE_MAX, // Bounding value.
652 };
653 int category = RESOLVE_MAX; // Illegal value for later DCHECK only.
654
[email protected]189163e2011-05-11 01:48:54655 base::TimeDelta duration = base::TimeTicks::Now() - start_time;
656 if (error == OK) {
[email protected]1e9bbd22010-10-15 16:42:45657 if (had_non_speculative_request_) {
658 category = RESOLVE_SUCCESS;
659 DNS_HISTOGRAM("DNS.ResolveSuccess", duration);
660 } else {
661 category = RESOLVE_SPECULATIVE_SUCCESS;
662 DNS_HISTOGRAM("DNS.ResolveSpeculativeSuccess", duration);
663 }
664 } else {
665 if (had_non_speculative_request_) {
666 category = RESOLVE_FAIL;
667 DNS_HISTOGRAM("DNS.ResolveFail", duration);
668 } else {
669 category = RESOLVE_SPECULATIVE_FAIL;
670 DNS_HISTOGRAM("DNS.ResolveSpeculativeFail", duration);
671 }
[email protected]c833e322010-10-16 23:51:36672 UMA_HISTOGRAM_CUSTOM_ENUMERATION(kOSErrorsForGetAddrinfoHistogramName,
[email protected]189163e2011-05-11 01:48:54673 std::abs(os_error),
[email protected]1e9bbd22010-10-15 16:42:45674 GetAllGetAddrinfoOSErrors());
675 }
[email protected]051b6ab2010-10-18 16:50:46676 DCHECK_LT(category, static_cast<int>(RESOLVE_MAX)); // Be sure it was set.
[email protected]1e9bbd22010-10-15 16:42:45677
678 UMA_HISTOGRAM_ENUMERATION("DNS.ResolveCategory", category, RESOLVE_MAX);
679
[email protected]edafd4c2011-05-10 17:18:53680 static const bool show_speculative_experiment_histograms =
681 base::FieldTrialList::TrialExists("DnsImpact");
[email protected]ecd95ae2010-10-20 23:58:17682 if (show_speculative_experiment_histograms) {
[email protected]1e9bbd22010-10-15 16:42:45683 UMA_HISTOGRAM_ENUMERATION(
684 base::FieldTrial::MakeName("DNS.ResolveCategory", "DnsImpact"),
685 category, RESOLVE_MAX);
686 if (RESOLVE_SUCCESS == category) {
687 DNS_HISTOGRAM(base::FieldTrial::MakeName("DNS.ResolveSuccess",
688 "DnsImpact"), duration);
689 }
690 }
[email protected]edafd4c2011-05-10 17:18:53691 static const bool show_parallelism_experiment_histograms =
692 base::FieldTrialList::TrialExists("DnsParallelism");
[email protected]ecd95ae2010-10-20 23:58:17693 if (show_parallelism_experiment_histograms) {
694 UMA_HISTOGRAM_ENUMERATION(
695 base::FieldTrial::MakeName("DNS.ResolveCategory", "DnsParallelism"),
696 category, RESOLVE_MAX);
697 if (RESOLVE_SUCCESS == category) {
698 DNS_HISTOGRAM(base::FieldTrial::MakeName("DNS.ResolveSuccess",
699 "DnsParallelism"), duration);
700 }
701 }
[email protected]1e9bbd22010-10-15 16:42:45702 }
703
[email protected]189163e2011-05-11 01:48:54704 void RecordAttemptHistograms(const base::TimeTicks& start_time,
705 const uint32 attempt_number,
706 const int error,
707 const int os_error) const {
708 bool first_attempt_to_complete =
709 completed_attempt_number_ == attempt_number;
[email protected]1e9bbd22010-10-15 16:42:45710
[email protected]189163e2011-05-11 01:48:54711 if (first_attempt_to_complete) {
712 // If this was first attempt to complete, then record the resolution
713 // status of the attempt.
714 if (completed_attempt_error_ == OK) {
715 UMA_HISTOGRAM_ENUMERATION(
716 "DNS.AttemptFirstSuccess", attempt_number, 100);
717 } else {
718 UMA_HISTOGRAM_ENUMERATION(
719 "DNS.AttemptFirstFailure", attempt_number, 100);
720 }
721 }
722
723 if (error == OK)
724 UMA_HISTOGRAM_ENUMERATION("DNS.AttemptSuccess", attempt_number, 100);
725 else
726 UMA_HISTOGRAM_ENUMERATION("DNS.AttemptFailure", attempt_number, 100);
727
728 if (was_cancelled() || !first_attempt_to_complete) {
729 // Count those attempts which completed after the job was already canceled
730 // OR after the job was already completed by an earlier attempt (so in
731 // effect).
732 UMA_HISTOGRAM_ENUMERATION("DNS.AttemptDiscarded", attempt_number, 100);
733
734 // Record if job is cancelled.
735 if (was_cancelled())
736 UMA_HISTOGRAM_ENUMERATION("DNS.AttemptCancelled", attempt_number, 100);
737 }
738
739 base::TimeDelta duration = base::TimeTicks::Now() - start_time;
740 if (error == OK)
741 DNS_HISTOGRAM("DNS.AttemptSuccessDuration", duration);
742 else
743 DNS_HISTOGRAM("DNS.AttemptFailDuration", duration);
744 }
[email protected]1e9bbd22010-10-15 16:42:45745
[email protected]f2d8c4212010-02-02 00:56:35746 // Immutable. Can be read from either thread,
747 const int id_;
748
[email protected]b59ff372009-07-15 22:04:32749 // Set on the origin thread, read on the worker thread.
[email protected]123ab1e32009-10-21 19:12:57750 Key key_;
[email protected]b59ff372009-07-15 22:04:32751
752 // Only used on the origin thread (where Resolve was called).
753 HostResolverImpl* resolver_;
754 RequestsList requests_; // The requests waiting on this job.
755
756 // Used to post ourselves onto the origin thread.
[email protected]3e9d9cc2011-05-03 21:08:15757 scoped_refptr<base::MessageLoopProxy> origin_loop_;
[email protected]b59ff372009-07-15 22:04:32758
759 // Hold an owning reference to the HostResolverProc that we are going to use.
760 // This may not be the current resolver procedure by the time we call
761 // ResolveAddrInfo, but that's OK... we'll use it anyways, and the owning
762 // reference ensures that it remains valid until we are done.
763 scoped_refptr<HostResolverProc> resolver_proc_;
764
[email protected]189163e2011-05-11 01:48:54765 // The amount of time after starting a resolution attempt until deciding to
766 // retry.
767 base::TimeDelta unresponsive_delay_;
768
769 // Keeps track of the number of attempts we have made so far to resolve the
770 // host. Whenever we start an attempt to resolve the host, we increase this
771 // number.
772 uint32 attempt_number_;
773
774 // The index of the attempt which finished first (or 0 if the job is still in
775 // progress).
776 uint32 completed_attempt_number_;
777
778 // The result (a net error code) from the first attempt to complete.
779 int completed_attempt_error_;
[email protected]252b699b2010-02-05 21:38:06780
781 // True if a non-speculative request was ever attached to this job
782 // (regardless of whether or not it was later cancelled.
783 // This boolean is used for histogramming the duration of jobs used to
784 // service non-speculative requests.
785 bool had_non_speculative_request_;
786
[email protected]b59ff372009-07-15 22:04:32787 AddressList results_;
788
[email protected]ee094b82010-08-24 15:55:51789 BoundNetLog net_log_;
790
[email protected]b59ff372009-07-15 22:04:32791 DISALLOW_COPY_AND_ASSIGN(Job);
792};
793
794//-----------------------------------------------------------------------------
795
[email protected]0f8f1b432010-03-16 19:06:03796// This class represents a request to the worker pool for a "probe for IPv6
797// support" call.
798class HostResolverImpl::IPv6ProbeJob
799 : public base::RefCountedThreadSafe<HostResolverImpl::IPv6ProbeJob> {
800 public:
801 explicit IPv6ProbeJob(HostResolverImpl* resolver)
802 : resolver_(resolver),
[email protected]3e9d9cc2011-05-03 21:08:15803 origin_loop_(base::MessageLoopProxy::CreateForCurrentThread()) {
804 DCHECK(resolver);
[email protected]0f8f1b432010-03-16 19:06:03805 }
806
807 void Start() {
[email protected]3e9d9cc2011-05-03 21:08:15808 DCHECK(origin_loop_->BelongsToCurrentThread());
[email protected]a9af7112010-05-08 00:56:01809 if (was_cancelled())
810 return;
[email protected]f092e64b2010-03-17 00:39:18811 const bool kIsSlow = true;
[email protected]ac9ba8fe2010-12-30 18:08:36812 base::WorkerPool::PostTask(
[email protected]f092e64b2010-03-17 00:39:18813 FROM_HERE, NewRunnableMethod(this, &IPv6ProbeJob::DoProbe), kIsSlow);
[email protected]0f8f1b432010-03-16 19:06:03814 }
815
816 // Cancels the current job.
817 void Cancel() {
[email protected]3e9d9cc2011-05-03 21:08:15818 DCHECK(origin_loop_->BelongsToCurrentThread());
[email protected]a9af7112010-05-08 00:56:01819 if (was_cancelled())
820 return;
[email protected]0f8f1b432010-03-16 19:06:03821 resolver_ = NULL; // Read/write ONLY on origin thread.
[email protected]0f8f1b432010-03-16 19:06:03822 }
823
[email protected]0f8f1b432010-03-16 19:06:03824 private:
825 friend class base::RefCountedThreadSafe<HostResolverImpl::IPv6ProbeJob>;
826
827 ~IPv6ProbeJob() {
828 }
829
[email protected]a9af7112010-05-08 00:56:01830 bool was_cancelled() const {
[email protected]3e9d9cc2011-05-03 21:08:15831 DCHECK(origin_loop_->BelongsToCurrentThread());
832 return !resolver_;
[email protected]a9af7112010-05-08 00:56:01833 }
834
[email protected]0f8f1b432010-03-16 19:06:03835 // Run on worker thread.
836 void DoProbe() {
837 // Do actual testing on this thread, as it takes 40-100ms.
838 AddressFamily family = IPv6Supported() ? ADDRESS_FAMILY_UNSPECIFIED
839 : ADDRESS_FAMILY_IPV4;
840
[email protected]3e9d9cc2011-05-03 21:08:15841 origin_loop_->PostTask(
842 FROM_HERE,
843 NewRunnableMethod(this, &IPv6ProbeJob::OnProbeComplete, family));
[email protected]0f8f1b432010-03-16 19:06:03844 }
845
[email protected]3e9d9cc2011-05-03 21:08:15846 // Callback for when DoProbe() completes.
[email protected]0f8f1b432010-03-16 19:06:03847 void OnProbeComplete(AddressFamily address_family) {
[email protected]3e9d9cc2011-05-03 21:08:15848 DCHECK(origin_loop_->BelongsToCurrentThread());
[email protected]a9af7112010-05-08 00:56:01849 if (was_cancelled())
850 return;
[email protected]a9af7112010-05-08 00:56:01851 resolver_->IPv6ProbeSetDefaultAddressFamily(address_family);
[email protected]0f8f1b432010-03-16 19:06:03852 }
853
[email protected]0f8f1b432010-03-16 19:06:03854 // Used/set only on origin thread.
855 HostResolverImpl* resolver_;
856
857 // Used to post ourselves onto the origin thread.
[email protected]3e9d9cc2011-05-03 21:08:15858 scoped_refptr<base::MessageLoopProxy> origin_loop_;
[email protected]0f8f1b432010-03-16 19:06:03859
860 DISALLOW_COPY_AND_ASSIGN(IPv6ProbeJob);
861};
862
863//-----------------------------------------------------------------------------
864
[email protected]68ad3ee2010-01-30 03:45:39865// We rely on the priority enum values being sequential having starting at 0,
866// and increasing for lower priorities.
867COMPILE_ASSERT(HIGHEST == 0u &&
868 LOWEST > HIGHEST &&
[email protected]c9c6f5c2010-07-31 01:30:03869 IDLE > LOWEST &&
870 NUM_PRIORITIES > IDLE,
[email protected]68ad3ee2010-01-30 03:45:39871 priority_indexes_incompatible);
872
873// JobPool contains all the information relating to queued requests, including
874// the limits on how many jobs are allowed to be used for this category of
875// requests.
876class HostResolverImpl::JobPool {
877 public:
878 JobPool(size_t max_outstanding_jobs, size_t max_pending_requests)
879 : num_outstanding_jobs_(0u) {
880 SetConstraints(max_outstanding_jobs, max_pending_requests);
881 }
882
883 ~JobPool() {
884 // Free the pending requests.
885 for (size_t i = 0; i < arraysize(pending_requests_); ++i)
886 STLDeleteElements(&pending_requests_[i]);
887 }
888
889 // Sets the constraints for this pool. See SetPoolConstraints() for the
890 // specific meaning of these parameters.
891 void SetConstraints(size_t max_outstanding_jobs,
892 size_t max_pending_requests) {
[email protected]b1f031dd2010-03-02 23:19:33893 CHECK_NE(max_outstanding_jobs, 0u);
[email protected]68ad3ee2010-01-30 03:45:39894 max_outstanding_jobs_ = max_outstanding_jobs;
895 max_pending_requests_ = max_pending_requests;
896 }
897
898 // Returns the number of pending requests enqueued to this pool.
899 // A pending request is one waiting to be attached to a job.
900 size_t GetNumPendingRequests() const {
901 size_t total = 0u;
902 for (size_t i = 0u; i < arraysize(pending_requests_); ++i)
903 total += pending_requests_[i].size();
904 return total;
905 }
906
907 bool HasPendingRequests() const {
908 return GetNumPendingRequests() > 0u;
909 }
910
911 // Enqueues a request to this pool. As a result of enqueing this request,
912 // the queue may have reached its maximum size. In this case, a request is
913 // evicted from the queue, and returned. Otherwise returns NULL. The caller
914 // is responsible for freeing the evicted request.
915 Request* InsertPendingRequest(Request* req) {
[email protected]ee094b82010-08-24 15:55:51916 req->request_net_log().BeginEvent(
917 NetLog::TYPE_HOST_RESOLVER_IMPL_JOB_POOL_QUEUE,
918 NULL);
919
[email protected]68ad3ee2010-01-30 03:45:39920 PendingRequestsQueue& q = pending_requests_[req->info().priority()];
921 q.push_back(req);
922
923 // If the queue is too big, kick out the lowest priority oldest request.
924 if (GetNumPendingRequests() > max_pending_requests_) {
925 // Iterate over the queues from lowest priority to highest priority.
926 for (int i = static_cast<int>(arraysize(pending_requests_)) - 1;
927 i >= 0; --i) {
928 PendingRequestsQueue& q = pending_requests_[i];
929 if (!q.empty()) {
930 Request* req = q.front();
931 q.pop_front();
[email protected]ee094b82010-08-24 15:55:51932 req->request_net_log().AddEvent(
933 NetLog::TYPE_HOST_RESOLVER_IMPL_JOB_POOL_QUEUE_EVICTED, NULL);
934 req->request_net_log().EndEvent(
935 NetLog::TYPE_HOST_RESOLVER_IMPL_JOB_POOL_QUEUE, NULL);
[email protected]68ad3ee2010-01-30 03:45:39936 return req;
937 }
938 }
939 }
940
941 return NULL;
942 }
943
944 // Erases |req| from this container. Caller is responsible for freeing
945 // |req| afterwards.
946 void RemovePendingRequest(Request* req) {
947 PendingRequestsQueue& q = pending_requests_[req->info().priority()];
948 PendingRequestsQueue::iterator it = std::find(q.begin(), q.end(), req);
949 DCHECK(it != q.end());
950 q.erase(it);
[email protected]ee094b82010-08-24 15:55:51951 req->request_net_log().EndEvent(
952 NetLog::TYPE_HOST_RESOLVER_IMPL_JOB_POOL_QUEUE, NULL);
[email protected]68ad3ee2010-01-30 03:45:39953 }
954
955 // Removes and returns the highest priority pending request.
956 Request* RemoveTopPendingRequest() {
957 DCHECK(HasPendingRequests());
958
959 for (size_t i = 0u; i < arraysize(pending_requests_); ++i) {
960 PendingRequestsQueue& q = pending_requests_[i];
961 if (!q.empty()) {
962 Request* req = q.front();
963 q.pop_front();
[email protected]ee094b82010-08-24 15:55:51964 req->request_net_log().EndEvent(
965 NetLog::TYPE_HOST_RESOLVER_IMPL_JOB_POOL_QUEUE, NULL);
[email protected]68ad3ee2010-01-30 03:45:39966 return req;
967 }
968 }
969
970 NOTREACHED();
971 return NULL;
972 }
973
974 // Keeps track of a job that was just added/removed, and belongs to this pool.
975 void AdjustNumOutstandingJobs(int offset) {
976 DCHECK(offset == 1 || (offset == -1 && num_outstanding_jobs_ > 0u));
977 num_outstanding_jobs_ += offset;
978 }
979
[email protected]35ddc282010-09-21 23:42:06980 void ResetNumOutstandingJobs() {
981 num_outstanding_jobs_ = 0;
982 }
983
[email protected]68ad3ee2010-01-30 03:45:39984 // Returns true if a new job can be created for this pool.
985 bool CanCreateJob() const {
986 return num_outstanding_jobs_ + 1u <= max_outstanding_jobs_;
987 }
988
989 // Removes any pending requests from the queue which are for the
[email protected]137af622010-02-05 02:14:35990 // same (hostname / effective address-family) as |job|, and attaches them to
991 // |job|.
[email protected]68ad3ee2010-01-30 03:45:39992 void MoveRequestsToJob(Job* job) {
993 for (size_t i = 0u; i < arraysize(pending_requests_); ++i) {
994 PendingRequestsQueue& q = pending_requests_[i];
995 PendingRequestsQueue::iterator req_it = q.begin();
996 while (req_it != q.end()) {
997 Request* req = *req_it;
[email protected]137af622010-02-05 02:14:35998 if (job->CanServiceRequest(req->info())) {
[email protected]68ad3ee2010-01-30 03:45:39999 // Job takes ownership of |req|.
1000 job->AddRequest(req);
1001 req_it = q.erase(req_it);
1002 } else {
1003 ++req_it;
1004 }
1005 }
1006 }
1007 }
1008
1009 private:
1010 typedef std::deque<Request*> PendingRequestsQueue;
1011
1012 // Maximum number of concurrent jobs allowed to be started for requests
1013 // belonging to this pool.
1014 size_t max_outstanding_jobs_;
1015
1016 // The current number of running jobs that were started for requests
1017 // belonging to this pool.
1018 size_t num_outstanding_jobs_;
1019
1020 // The maximum number of requests we allow to be waiting on a job,
1021 // for this pool.
1022 size_t max_pending_requests_;
1023
1024 // The requests which are waiting to be started for this pool.
1025 PendingRequestsQueue pending_requests_[NUM_PRIORITIES];
1026};
1027
1028//-----------------------------------------------------------------------------
1029
[email protected]e95d3aca2010-01-11 22:47:431030HostResolverImpl::HostResolverImpl(
1031 HostResolverProc* resolver_proc,
1032 HostCache* cache,
[email protected]ee094b82010-08-24 15:55:511033 size_t max_jobs,
[email protected]06ef6d92011-05-19 04:24:581034 size_t max_retry_attempts,
[email protected]ee094b82010-08-24 15:55:511035 NetLog* net_log)
[email protected]112bd462009-12-10 07:23:401036 : cache_(cache),
[email protected]68ad3ee2010-01-30 03:45:391037 max_jobs_(max_jobs),
[email protected]06ef6d92011-05-19 04:24:581038 max_retry_attempts_(max_retry_attempts),
[email protected]189163e2011-05-11 01:48:541039 unresponsive_delay_(base::TimeDelta::FromMilliseconds(6000)),
1040 retry_factor_(2),
[email protected]123ab1e32009-10-21 19:12:571041 next_request_id_(0),
[email protected]f2d8c4212010-02-02 00:56:351042 next_job_id_(0),
[email protected]123ab1e32009-10-21 19:12:571043 resolver_proc_(resolver_proc),
[email protected]0c7798452009-10-26 17:59:511044 default_address_family_(ADDRESS_FAMILY_UNSPECIFIED),
[email protected]e95d3aca2010-01-11 22:47:431045 shutdown_(false),
[email protected]2f3bc65c2010-07-23 17:47:101046 ipv6_probe_monitoring_(false),
[email protected]ee094b82010-08-24 15:55:511047 additional_resolver_flags_(0),
1048 net_log_(net_log) {
[email protected]68ad3ee2010-01-30 03:45:391049 DCHECK_GT(max_jobs, 0u);
1050
[email protected]06ef6d92011-05-19 04:24:581051 // Maximum of 4 retry attempts for host resolution.
1052 static const size_t kDefaultMaxRetryAttempts = 4u;
1053
1054 if (max_retry_attempts_ == HostResolver::kDefaultRetryAttempts)
1055 max_retry_attempts_ = kDefaultMaxRetryAttempts;
1056
[email protected]68ad3ee2010-01-30 03:45:391057 // It is cumbersome to expose all of the constraints in the constructor,
1058 // so we choose some defaults, which users can override later.
1059 job_pools_[POOL_NORMAL] = new JobPool(max_jobs, 100u * max_jobs);
1060
[email protected]b59ff372009-07-15 22:04:321061#if defined(OS_WIN)
1062 EnsureWinsockInit();
1063#endif
[email protected]2f3bc65c2010-07-23 17:47:101064#if defined(OS_LINUX)
1065 if (HaveOnlyLoopbackAddresses())
1066 additional_resolver_flags_ |= HOST_RESOLVER_LOOPBACK_ONLY;
1067#endif
[email protected]232a5812011-03-04 22:42:081068 NetworkChangeNotifier::AddIPAddressObserver(this);
[email protected]b59ff372009-07-15 22:04:321069}
1070
1071HostResolverImpl::~HostResolverImpl() {
1072 // Cancel the outstanding jobs. Those jobs may contain several attached
1073 // requests, which will also be cancelled.
[email protected]0f8f1b432010-03-16 19:06:031074 DiscardIPv6ProbeJob();
1075
[email protected]ef4c40c2010-09-01 14:42:031076 CancelAllJobs();
[email protected]b59ff372009-07-15 22:04:321077
1078 // In case we are being deleted during the processing of a callback.
1079 if (cur_completing_job_)
1080 cur_completing_job_->Cancel();
[email protected]e95d3aca2010-01-11 22:47:431081
[email protected]232a5812011-03-04 22:42:081082 NetworkChangeNotifier::RemoveIPAddressObserver(this);
[email protected]61a86c42010-04-19 22:45:531083
[email protected]68ad3ee2010-01-30 03:45:391084 // Delete the job pools.
1085 for (size_t i = 0u; i < arraysize(job_pools_); ++i)
1086 delete job_pools_[i];
[email protected]b59ff372009-07-15 22:04:321087}
1088
[email protected]be1a48b2011-01-20 00:12:131089void HostResolverImpl::ProbeIPv6Support() {
1090 DCHECK(CalledOnValidThread());
1091 DCHECK(!ipv6_probe_monitoring_);
1092 ipv6_probe_monitoring_ = true;
1093 OnIPAddressChanged(); // Give initial setup call.
1094}
1095
1096void HostResolverImpl::SetPoolConstraints(JobPoolIndex pool_index,
1097 size_t max_outstanding_jobs,
1098 size_t max_pending_requests) {
1099 DCHECK(CalledOnValidThread());
1100 CHECK_GE(pool_index, 0);
1101 CHECK_LT(pool_index, POOL_COUNT);
1102 CHECK(jobs_.empty()) << "Can only set constraints during setup";
1103 JobPool* pool = job_pools_[pool_index];
1104 pool->SetConstraints(max_outstanding_jobs, max_pending_requests);
1105}
1106
[email protected]684970b2009-08-14 04:54:461107int HostResolverImpl::Resolve(const RequestInfo& info,
[email protected]b59ff372009-07-15 22:04:321108 AddressList* addresses,
1109 CompletionCallback* callback,
[email protected]684970b2009-08-14 04:54:461110 RequestHandle* out_req,
[email protected]ee094b82010-08-24 15:55:511111 const BoundNetLog& source_net_log) {
[email protected]1ac6af92010-06-03 21:00:141112 DCHECK(CalledOnValidThread());
1113
[email protected]b59ff372009-07-15 22:04:321114 if (shutdown_)
1115 return ERR_UNEXPECTED;
1116
1117 // Choose a unique ID number for observers to see.
1118 int request_id = next_request_id_++;
1119
[email protected]ee094b82010-08-24 15:55:511120 // Make a log item for the request.
1121 BoundNetLog request_net_log = BoundNetLog::Make(net_log_,
1122 NetLog::SOURCE_HOST_RESOLVER_IMPL_REQUEST);
1123
[email protected]9e743cd2010-03-16 07:03:531124 // Update the net log and notify registered observers.
[email protected]ee094b82010-08-24 15:55:511125 OnStartRequest(source_net_log, request_net_log, request_id, info);
[email protected]b59ff372009-07-15 22:04:321126
[email protected]123ab1e32009-10-21 19:12:571127 // Build a key that identifies the request in the cache and in the
1128 // outstanding jobs map.
[email protected]137af622010-02-05 02:14:351129 Key key = GetEffectiveKeyForRequest(info);
[email protected]123ab1e32009-10-21 19:12:571130
[email protected]eaf3a3b2010-09-03 20:34:271131 // Check for IP literal.
1132 IPAddressNumber ip_number;
1133 if (ParseIPLiteralToNumber(info.hostname(), &ip_number)) {
1134 DCHECK_EQ(key.host_resolver_flags &
1135 ~(HOST_RESOLVER_CANONNAME | HOST_RESOLVER_LOOPBACK_ONLY |
1136 HOST_RESOLVER_DEFAULT_FAMILY_SET_DUE_TO_NO_IPV6),
1137 0) << " Unhandled flag";
1138 bool ipv6_disabled = default_address_family_ == ADDRESS_FAMILY_IPV4 &&
1139 !ipv6_probe_monitoring_;
1140 int net_error = OK;
1141 if (ip_number.size() == 16 && ipv6_disabled) {
1142 net_error = ERR_NAME_NOT_RESOLVED;
1143 } else {
[email protected]fe89ea72011-05-12 02:02:401144 *addresses = AddressList::CreateFromIPAddressWithCname(
1145 ip_number, info.port(),
1146 (key.host_resolver_flags & HOST_RESOLVER_CANONNAME));
[email protected]eaf3a3b2010-09-03 20:34:271147 }
1148 // Update the net log and notify registered observers.
1149 OnFinishRequest(source_net_log, request_net_log, request_id, info,
1150 net_error, 0 /* os_error (unknown since from cache) */);
1151 return net_error;
1152 }
1153
[email protected]b59ff372009-07-15 22:04:321154 // If we have an unexpired cache entry, use it.
[email protected]112bd462009-12-10 07:23:401155 if (info.allow_cached_response() && cache_.get()) {
1156 const HostCache::Entry* cache_entry = cache_->Lookup(
[email protected]123ab1e32009-10-21 19:12:571157 key, base::TimeTicks::Now());
[email protected]b59ff372009-07-15 22:04:321158 if (cache_entry) {
[email protected]ee094b82010-08-24 15:55:511159 request_net_log.AddEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_CACHE_HIT, NULL);
[email protected]21526002010-05-16 19:42:461160 int net_error = cache_entry->error;
[email protected]fe89ea72011-05-12 02:02:401161 if (net_error == OK) {
1162 *addresses = CreateAddressListUsingPort(
1163 cache_entry->addrlist, info.port());
1164 }
[email protected]b59ff372009-07-15 22:04:321165
[email protected]9e743cd2010-03-16 07:03:531166 // Update the net log and notify registered observers.
[email protected]ee094b82010-08-24 15:55:511167 OnFinishRequest(source_net_log, request_net_log, request_id, info,
1168 net_error,
1169 0 /* os_error (unknown since from cache) */);
[email protected]b59ff372009-07-15 22:04:321170
[email protected]21526002010-05-16 19:42:461171 return net_error;
[email protected]b59ff372009-07-15 22:04:321172 }
1173 }
1174
[email protected]38368712011-03-02 08:09:401175 if (info.only_use_cached_response()) { // Not allowed to do a real lookup.
1176 OnFinishRequest(source_net_log,
1177 request_net_log,
1178 request_id,
1179 info,
1180 ERR_NAME_NOT_RESOLVED,
1181 0);
1182 return ERR_NAME_NOT_RESOLVED;
1183 }
1184
[email protected]b59ff372009-07-15 22:04:321185 // If no callback was specified, do a synchronous resolution.
1186 if (!callback) {
1187 AddressList addrlist;
[email protected]21526002010-05-16 19:42:461188 int os_error = 0;
[email protected]b59ff372009-07-15 22:04:321189 int error = ResolveAddrInfo(
[email protected]5ea28dea2010-04-08 15:35:131190 effective_resolver_proc(), key.hostname, key.address_family,
[email protected]21526002010-05-16 19:42:461191 key.host_resolver_flags, &addrlist, &os_error);
[email protected]b59ff372009-07-15 22:04:321192 if (error == OK) {
[email protected]fe89ea72011-05-12 02:02:401193 MutableSetPort(info.port(), &addrlist);
[email protected]b59ff372009-07-15 22:04:321194 *addresses = addrlist;
1195 }
1196
1197 // Write to cache.
[email protected]112bd462009-12-10 07:23:401198 if (cache_.get())
1199 cache_->Set(key, error, addrlist, base::TimeTicks::Now());
[email protected]b59ff372009-07-15 22:04:321200
[email protected]9e743cd2010-03-16 07:03:531201 // Update the net log and notify registered observers.
[email protected]ee094b82010-08-24 15:55:511202 OnFinishRequest(source_net_log, request_net_log, request_id, info, error,
1203 os_error);
[email protected]b59ff372009-07-15 22:04:321204
1205 return error;
1206 }
1207
1208 // Create a handle for this request, and pass it back to the user if they
1209 // asked for it (out_req != NULL).
[email protected]ee094b82010-08-24 15:55:511210 Request* req = new Request(source_net_log, request_net_log, request_id, info,
1211 callback, addresses);
[email protected]b59ff372009-07-15 22:04:321212 if (out_req)
1213 *out_req = reinterpret_cast<RequestHandle>(req);
1214
1215 // Next we need to attach our request to a "job". This job is responsible for
1216 // calling "getaddrinfo(hostname)" on a worker thread.
1217 scoped_refptr<Job> job;
1218
[email protected]123ab1e32009-10-21 19:12:571219 // If there is already an outstanding job to resolve |key|, use
[email protected]b59ff372009-07-15 22:04:321220 // it. This prevents starting concurrent resolves for the same hostname.
[email protected]123ab1e32009-10-21 19:12:571221 job = FindOutstandingJob(key);
[email protected]b59ff372009-07-15 22:04:321222 if (job) {
1223 job->AddRequest(req);
1224 } else {
[email protected]68ad3ee2010-01-30 03:45:391225 JobPool* pool = GetPoolForRequest(req);
1226 if (CanCreateJobForPool(*pool)) {
1227 CreateAndStartJob(req);
1228 } else {
1229 return EnqueueRequest(pool, req);
1230 }
[email protected]b59ff372009-07-15 22:04:321231 }
1232
1233 // Completion happens during OnJobComplete(Job*).
1234 return ERR_IO_PENDING;
1235}
1236
1237// See OnJobComplete(Job*) for why it is important not to clean out
1238// cancelled requests from Job::requests_.
1239void HostResolverImpl::CancelRequest(RequestHandle req_handle) {
[email protected]1ac6af92010-06-03 21:00:141240 DCHECK(CalledOnValidThread());
[email protected]bf0b51c2009-08-01 23:46:401241 if (shutdown_) {
[email protected]ff1f61b92009-08-03 23:20:231242 // TODO(eroman): temp hack for: http://crbug.com/18373
1243 // Because we destroy outstanding requests during Shutdown(),
1244 // |req_handle| is already cancelled.
[email protected]bf0b51c2009-08-01 23:46:401245 LOG(ERROR) << "Called HostResolverImpl::CancelRequest() after Shutdown().";
[email protected]58580352010-10-26 04:07:501246 base::debug::StackTrace().PrintBacktrace();
[email protected]bf0b51c2009-08-01 23:46:401247 return;
1248 }
[email protected]b59ff372009-07-15 22:04:321249 Request* req = reinterpret_cast<Request*>(req_handle);
1250 DCHECK(req);
[email protected]68ad3ee2010-01-30 03:45:391251
1252 scoped_ptr<Request> request_deleter; // Frees at end of function.
1253
1254 if (!req->job()) {
1255 // If the request was not attached to a job yet, it must have been
1256 // enqueued into a pool. Remove it from that pool's queue.
1257 // Otherwise if it was attached to a job, the job is responsible for
1258 // deleting it.
1259 JobPool* pool = GetPoolForRequest(req);
1260 pool->RemovePendingRequest(req);
1261 request_deleter.reset(req);
[email protected]ee094b82010-08-24 15:55:511262 } else {
1263 req->request_net_log().EndEvent(
1264 NetLog::TYPE_HOST_RESOLVER_IMPL_JOB_ATTACH, NULL);
[email protected]68ad3ee2010-01-30 03:45:391265 }
1266
[email protected]b59ff372009-07-15 22:04:321267 // NULL out the fields of req, to mark it as cancelled.
1268 req->MarkAsCancelled();
[email protected]ee094b82010-08-24 15:55:511269 OnCancelRequest(req->source_net_log(), req->request_net_log(), req->id(),
1270 req->info());
[email protected]b59ff372009-07-15 22:04:321271}
1272
[email protected]e95d3aca2010-01-11 22:47:431273void HostResolverImpl::AddObserver(HostResolver::Observer* observer) {
[email protected]1ac6af92010-06-03 21:00:141274 DCHECK(CalledOnValidThread());
[email protected]b59ff372009-07-15 22:04:321275 observers_.push_back(observer);
1276}
1277
[email protected]e95d3aca2010-01-11 22:47:431278void HostResolverImpl::RemoveObserver(HostResolver::Observer* observer) {
[email protected]1ac6af92010-06-03 21:00:141279 DCHECK(CalledOnValidThread());
[email protected]b59ff372009-07-15 22:04:321280 ObserversList::iterator it =
1281 std::find(observers_.begin(), observers_.end(), observer);
1282
1283 // Observer must exist.
1284 DCHECK(it != observers_.end());
1285
1286 observers_.erase(it);
1287}
1288
[email protected]0f8f1b432010-03-16 19:06:031289void HostResolverImpl::SetDefaultAddressFamily(AddressFamily address_family) {
[email protected]1ac6af92010-06-03 21:00:141290 DCHECK(CalledOnValidThread());
[email protected]0f8f1b432010-03-16 19:06:031291 ipv6_probe_monitoring_ = false;
1292 DiscardIPv6ProbeJob();
1293 default_address_family_ = address_family;
1294}
1295
[email protected]f7d310e2010-10-07 16:25:111296AddressFamily HostResolverImpl::GetDefaultAddressFamily() const {
1297 return default_address_family_;
1298}
1299
[email protected]ddb1e5a2010-12-13 20:10:451300HostResolverImpl* HostResolverImpl::GetAsHostResolverImpl() {
1301 return this;
1302}
1303
[email protected]b59ff372009-07-15 22:04:321304void HostResolverImpl::Shutdown() {
[email protected]1ac6af92010-06-03 21:00:141305 DCHECK(CalledOnValidThread());
[email protected]b59ff372009-07-15 22:04:321306
1307 // Cancel the outstanding jobs.
[email protected]ef4c40c2010-09-01 14:42:031308 CancelAllJobs();
[email protected]0a175512010-04-20 03:09:251309 DiscardIPv6ProbeJob();
[email protected]be5c6162010-07-27 21:12:511310
1311 shutdown_ = true;
[email protected]b59ff372009-07-15 22:04:321312}
1313
1314void HostResolverImpl::AddOutstandingJob(Job* job) {
[email protected]123ab1e32009-10-21 19:12:571315 scoped_refptr<Job>& found_job = jobs_[job->key()];
[email protected]b59ff372009-07-15 22:04:321316 DCHECK(!found_job);
1317 found_job = job;
[email protected]68ad3ee2010-01-30 03:45:391318
1319 JobPool* pool = GetPoolForRequest(job->initial_request());
1320 pool->AdjustNumOutstandingJobs(1);
[email protected]b59ff372009-07-15 22:04:321321}
1322
[email protected]123ab1e32009-10-21 19:12:571323HostResolverImpl::Job* HostResolverImpl::FindOutstandingJob(const Key& key) {
1324 JobMap::iterator it = jobs_.find(key);
[email protected]b59ff372009-07-15 22:04:321325 if (it != jobs_.end())
1326 return it->second;
1327 return NULL;
1328}
1329
1330void HostResolverImpl::RemoveOutstandingJob(Job* job) {
[email protected]123ab1e32009-10-21 19:12:571331 JobMap::iterator it = jobs_.find(job->key());
[email protected]b59ff372009-07-15 22:04:321332 DCHECK(it != jobs_.end());
1333 DCHECK_EQ(it->second.get(), job);
1334 jobs_.erase(it);
[email protected]68ad3ee2010-01-30 03:45:391335
1336 JobPool* pool = GetPoolForRequest(job->initial_request());
1337 pool->AdjustNumOutstandingJobs(-1);
[email protected]b59ff372009-07-15 22:04:321338}
1339
1340void HostResolverImpl::OnJobComplete(Job* job,
[email protected]21526002010-05-16 19:42:461341 int net_error,
1342 int os_error,
[email protected]27f99c82009-10-29 22:21:001343 const AddressList& addrlist) {
[email protected]b59ff372009-07-15 22:04:321344 RemoveOutstandingJob(job);
1345
1346 // Write result to the cache.
[email protected]112bd462009-12-10 07:23:401347 if (cache_.get())
[email protected]21526002010-05-16 19:42:461348 cache_->Set(job->key(), net_error, addrlist, base::TimeTicks::Now());
[email protected]b59ff372009-07-15 22:04:321349
[email protected]ef4c40c2010-09-01 14:42:031350 OnJobCompleteInternal(job, net_error, os_error, addrlist);
1351}
1352
1353void HostResolverImpl::AbortJob(Job* job) {
1354 OnJobCompleteInternal(job, ERR_ABORTED, 0 /* no os_error */, AddressList());
1355}
1356
1357void HostResolverImpl::OnJobCompleteInternal(
1358 Job* job,
1359 int net_error,
1360 int os_error,
1361 const AddressList& addrlist) {
[email protected]b59ff372009-07-15 22:04:321362 // Make a note that we are executing within OnJobComplete() in case the
1363 // HostResolver is deleted by a callback invocation.
1364 DCHECK(!cur_completing_job_);
1365 cur_completing_job_ = job;
1366
[email protected]68ad3ee2010-01-30 03:45:391367 // Try to start any queued requests now that a job-slot has freed up.
1368 ProcessQueuedRequests();
1369
[email protected]b59ff372009-07-15 22:04:321370 // Complete all of the requests that were attached to the job.
1371 for (RequestsList::const_iterator it = job->requests().begin();
1372 it != job->requests().end(); ++it) {
1373 Request* req = *it;
1374 if (!req->was_cancelled()) {
1375 DCHECK_EQ(job, req->job());
[email protected]ee094b82010-08-24 15:55:511376 req->request_net_log().EndEvent(
1377 NetLog::TYPE_HOST_RESOLVER_IMPL_JOB_ATTACH, NULL);
[email protected]b59ff372009-07-15 22:04:321378
[email protected]9e743cd2010-03-16 07:03:531379 // Update the net log and notify registered observers.
[email protected]ee094b82010-08-24 15:55:511380 OnFinishRequest(req->source_net_log(), req->request_net_log(), req->id(),
1381 req->info(), net_error, os_error);
[email protected]b59ff372009-07-15 22:04:321382
[email protected]21526002010-05-16 19:42:461383 req->OnComplete(net_error, addrlist);
[email protected]b59ff372009-07-15 22:04:321384
1385 // Check if the job was cancelled as a result of running the callback.
1386 // (Meaning that |this| was deleted).
1387 if (job->was_cancelled())
1388 return;
1389 }
1390 }
1391
1392 cur_completing_job_ = NULL;
1393}
1394
[email protected]ee094b82010-08-24 15:55:511395void HostResolverImpl::OnStartRequest(const BoundNetLog& source_net_log,
1396 const BoundNetLog& request_net_log,
[email protected]54e13772009-08-14 03:01:091397 int request_id,
1398 const RequestInfo& info) {
[email protected]ee094b82010-08-24 15:55:511399 source_net_log.BeginEvent(
1400 NetLog::TYPE_HOST_RESOLVER_IMPL,
[email protected]00cd9c42010-11-02 20:15:571401 make_scoped_refptr(new NetLogSourceParameter(
1402 "source_dependency", request_net_log.source())));
[email protected]ee094b82010-08-24 15:55:511403
1404 request_net_log.BeginEvent(
1405 NetLog::TYPE_HOST_RESOLVER_IMPL_REQUEST,
[email protected]00cd9c42010-11-02 20:15:571406 make_scoped_refptr(new RequestInfoParameters(
1407 info, source_net_log.source())));
[email protected]54e13772009-08-14 03:01:091408
1409 // Notify the observers of the start.
1410 if (!observers_.empty()) {
[email protected]54e13772009-08-14 03:01:091411 for (ObserversList::iterator it = observers_.begin();
1412 it != observers_.end(); ++it) {
1413 (*it)->OnStartResolution(request_id, info);
1414 }
[email protected]b59ff372009-07-15 22:04:321415 }
1416}
1417
[email protected]ee094b82010-08-24 15:55:511418void HostResolverImpl::OnFinishRequest(const BoundNetLog& source_net_log,
1419 const BoundNetLog& request_net_log,
[email protected]54e13772009-08-14 03:01:091420 int request_id,
1421 const RequestInfo& info,
[email protected]21526002010-05-16 19:42:461422 int net_error,
[email protected]ee094b82010-08-24 15:55:511423 int os_error) {
[email protected]21526002010-05-16 19:42:461424 bool was_resolved = net_error == OK;
1425
[email protected]54e13772009-08-14 03:01:091426 // Notify the observers of the completion.
1427 if (!observers_.empty()) {
[email protected]54e13772009-08-14 03:01:091428 for (ObserversList::iterator it = observers_.begin();
1429 it != observers_.end(); ++it) {
1430 (*it)->OnFinishResolutionWithStatus(request_id, was_resolved, info);
1431 }
[email protected]b59ff372009-07-15 22:04:321432 }
[email protected]54e13772009-08-14 03:01:091433
[email protected]ee094b82010-08-24 15:55:511434 // Log some extra parameters on failure for synchronous requests.
[email protected]21526002010-05-16 19:42:461435 scoped_refptr<NetLog::EventParameters> params;
[email protected]ee094b82010-08-24 15:55:511436 if (!was_resolved) {
[email protected]13024882011-05-18 23:19:161437 params = new HostResolveFailedParams(0, net_error, os_error);
[email protected]ee094b82010-08-24 15:55:511438 }
[email protected]21526002010-05-16 19:42:461439
[email protected]ee094b82010-08-24 15:55:511440 request_net_log.EndEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_REQUEST, params);
1441 source_net_log.EndEvent(NetLog::TYPE_HOST_RESOLVER_IMPL, NULL);
[email protected]b59ff372009-07-15 22:04:321442}
1443
[email protected]ee094b82010-08-24 15:55:511444void HostResolverImpl::OnCancelRequest(const BoundNetLog& source_net_log,
1445 const BoundNetLog& request_net_log,
[email protected]54e13772009-08-14 03:01:091446 int request_id,
1447 const RequestInfo& info) {
[email protected]ee094b82010-08-24 15:55:511448 request_net_log.AddEvent(NetLog::TYPE_CANCELLED, NULL);
[email protected]54e13772009-08-14 03:01:091449
1450 // Notify the observers of the cancellation.
1451 if (!observers_.empty()) {
[email protected]54e13772009-08-14 03:01:091452 for (ObserversList::iterator it = observers_.begin();
1453 it != observers_.end(); ++it) {
1454 (*it)->OnCancelResolution(request_id, info);
1455 }
[email protected]b59ff372009-07-15 22:04:321456 }
[email protected]54e13772009-08-14 03:01:091457
[email protected]ee094b82010-08-24 15:55:511458 request_net_log.EndEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_REQUEST, NULL);
1459 source_net_log.EndEvent(NetLog::TYPE_HOST_RESOLVER_IMPL, NULL);
[email protected]b59ff372009-07-15 22:04:321460}
1461
[email protected]0f8f1b432010-03-16 19:06:031462void HostResolverImpl::DiscardIPv6ProbeJob() {
1463 if (ipv6_probe_job_.get()) {
1464 ipv6_probe_job_->Cancel();
1465 ipv6_probe_job_ = NULL;
1466 }
1467}
1468
1469void HostResolverImpl::IPv6ProbeSetDefaultAddressFamily(
1470 AddressFamily address_family) {
1471 DCHECK(address_family == ADDRESS_FAMILY_UNSPECIFIED ||
1472 address_family == ADDRESS_FAMILY_IPV4);
[email protected]f092e64b2010-03-17 00:39:181473 if (default_address_family_ != address_family) {
[email protected]b30a3f52010-10-16 01:05:461474 VLOG(1) << "IPv6Probe forced AddressFamily setting to "
1475 << ((address_family == ADDRESS_FAMILY_UNSPECIFIED) ?
1476 "ADDRESS_FAMILY_UNSPECIFIED" : "ADDRESS_FAMILY_IPV4");
[email protected]f092e64b2010-03-17 00:39:181477 }
[email protected]0f8f1b432010-03-16 19:06:031478 default_address_family_ = address_family;
1479 // Drop reference since the job has called us back.
1480 DiscardIPv6ProbeJob();
[email protected]e95d3aca2010-01-11 22:47:431481}
1482
[email protected]68ad3ee2010-01-30 03:45:391483bool HostResolverImpl::CanCreateJobForPool(const JobPool& pool) const {
1484 DCHECK_LE(jobs_.size(), max_jobs_);
1485
1486 // We can't create another job if it would exceed the global total.
1487 if (jobs_.size() + 1 > max_jobs_)
1488 return false;
1489
1490 // Check whether the pool's constraints are met.
1491 return pool.CanCreateJob();
1492}
1493
[email protected]be1a48b2011-01-20 00:12:131494// static
1495HostResolverImpl::JobPoolIndex HostResolverImpl::GetJobPoolIndexForRequest(
1496 const Request* req) {
1497 return POOL_NORMAL;
1498}
1499
[email protected]68ad3ee2010-01-30 03:45:391500void HostResolverImpl::ProcessQueuedRequests() {
1501 // Find the highest priority request that can be scheduled.
1502 Request* top_req = NULL;
1503 for (size_t i = 0; i < arraysize(job_pools_); ++i) {
1504 JobPool* pool = job_pools_[i];
1505 if (pool->HasPendingRequests() && CanCreateJobForPool(*pool)) {
1506 top_req = pool->RemoveTopPendingRequest();
1507 break;
1508 }
1509 }
1510
1511 if (!top_req)
1512 return;
1513
[email protected]ad8e04a2010-11-01 04:16:271514 scoped_refptr<Job> job(CreateAndStartJob(top_req));
[email protected]68ad3ee2010-01-30 03:45:391515
1516 // Search for any other pending request which can piggy-back off this job.
1517 for (size_t pool_i = 0; pool_i < POOL_COUNT; ++pool_i) {
1518 JobPool* pool = job_pools_[pool_i];
1519 pool->MoveRequestsToJob(job);
1520 }
1521}
1522
[email protected]137af622010-02-05 02:14:351523HostResolverImpl::Key HostResolverImpl::GetEffectiveKeyForRequest(
1524 const RequestInfo& info) const {
[email protected]eaf3a3b2010-09-03 20:34:271525 HostResolverFlags effective_flags =
1526 info.host_resolver_flags() | additional_resolver_flags_;
[email protected]137af622010-02-05 02:14:351527 AddressFamily effective_address_family = info.address_family();
[email protected]eaf3a3b2010-09-03 20:34:271528 if (effective_address_family == ADDRESS_FAMILY_UNSPECIFIED &&
1529 default_address_family_ != ADDRESS_FAMILY_UNSPECIFIED) {
[email protected]137af622010-02-05 02:14:351530 effective_address_family = default_address_family_;
[email protected]eaf3a3b2010-09-03 20:34:271531 if (ipv6_probe_monitoring_)
1532 effective_flags |= HOST_RESOLVER_DEFAULT_FAMILY_SET_DUE_TO_NO_IPV6;
1533 }
1534 return Key(info.hostname(), effective_address_family, effective_flags);
[email protected]137af622010-02-05 02:14:351535}
1536
[email protected]68ad3ee2010-01-30 03:45:391537HostResolverImpl::Job* HostResolverImpl::CreateAndStartJob(Request* req) {
1538 DCHECK(CanCreateJobForPool(*GetPoolForRequest(req)));
[email protected]137af622010-02-05 02:14:351539 Key key = GetEffectiveKeyForRequest(req->info());
[email protected]ee094b82010-08-24 15:55:511540
1541 req->request_net_log().AddEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_CREATE_JOB,
1542 NULL);
1543
[email protected]ad8e04a2010-11-01 04:16:271544 scoped_refptr<Job> job(new Job(next_job_id_++, this, key,
[email protected]06ef6d92011-05-19 04:24:581545 req->request_net_log(), net_log_));
[email protected]68ad3ee2010-01-30 03:45:391546 job->AddRequest(req);
1547 AddOutstandingJob(job);
1548 job->Start();
[email protected]ee094b82010-08-24 15:55:511549
[email protected]68ad3ee2010-01-30 03:45:391550 return job.get();
1551}
1552
1553int HostResolverImpl::EnqueueRequest(JobPool* pool, Request* req) {
1554 scoped_ptr<Request> req_evicted_from_queue(
1555 pool->InsertPendingRequest(req));
1556
1557 // If the queue has become too large, we need to kick something out.
1558 if (req_evicted_from_queue.get()) {
1559 Request* r = req_evicted_from_queue.get();
1560 int error = ERR_HOST_RESOLVER_QUEUE_TOO_LARGE;
1561
[email protected]ee094b82010-08-24 15:55:511562 OnFinishRequest(r->source_net_log(), r->request_net_log(), r->id(),
1563 r->info(), error,
1564 0 /* os_error (not applicable) */);
[email protected]68ad3ee2010-01-30 03:45:391565
1566 if (r == req)
1567 return error;
1568
1569 r->OnComplete(error, AddressList());
1570 }
1571
1572 return ERR_IO_PENDING;
1573}
1574
[email protected]ef4c40c2010-09-01 14:42:031575void HostResolverImpl::CancelAllJobs() {
1576 JobMap jobs;
1577 jobs.swap(jobs_);
1578 for (JobMap::iterator it = jobs.begin(); it != jobs.end(); ++it)
1579 it->second->Cancel();
1580}
1581
[email protected]35ddc282010-09-21 23:42:061582void HostResolverImpl::AbortAllInProgressJobs() {
1583 for (size_t i = 0; i < arraysize(job_pools_); ++i)
1584 job_pools_[i]->ResetNumOutstandingJobs();
[email protected]ef4c40c2010-09-01 14:42:031585 JobMap jobs;
1586 jobs.swap(jobs_);
1587 for (JobMap::iterator it = jobs.begin(); it != jobs.end(); ++it) {
1588 AbortJob(it->second);
1589 it->second->Cancel();
1590 }
1591}
1592
[email protected]be1a48b2011-01-20 00:12:131593void HostResolverImpl::OnIPAddressChanged() {
1594 if (cache_.get())
1595 cache_->clear();
1596 if (ipv6_probe_monitoring_) {
1597 DCHECK(!shutdown_);
1598 if (shutdown_)
1599 return;
1600 DiscardIPv6ProbeJob();
1601 ipv6_probe_job_ = new IPv6ProbeJob(this);
1602 ipv6_probe_job_->Start();
1603 }
1604#if defined(OS_LINUX)
1605 if (HaveOnlyLoopbackAddresses()) {
1606 additional_resolver_flags_ |= HOST_RESOLVER_LOOPBACK_ONLY;
1607 } else {
1608 additional_resolver_flags_ &= ~HOST_RESOLVER_LOOPBACK_ONLY;
1609 }
1610#endif
1611 AbortAllInProgressJobs();
1612 // |this| may be deleted inside AbortAllInProgressJobs().
1613}
1614
[email protected]b59ff372009-07-15 22:04:321615} // namespace net