blob: 5ee66fff5878213f9a4adc3fdc6a735fe7296e7d [file] [log] [blame]
[email protected]5ea28dea2010-04-08 15:35:131// Copyright (c) 2010 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]bf0b51c2009-08-01 23:46:4019#include "base/debug_util.h"
[email protected]f2d8c4212010-02-02 00:56:3520#include "base/lock.h"
[email protected]b59ff372009-07-15 22:04:3221#include "base/message_loop.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"
26#include "base/time.h"
[email protected]ccaff652010-07-31 06:28:2027#include "base/utf_string_conversions.h"
[email protected]21526002010-05-16 19:42:4628#include "base/values.h"
[email protected]b59ff372009-07-15 22:04:3229#include "base/worker_pool.h"
30#include "net/base/address_list.h"
[email protected]ee094b82010-08-24 15:55:5131#include "net/base/address_list_net_log_param.h"
32#include "net/base/host_port_pair.h"
[email protected]b59ff372009-07-15 22:04:3233#include "net/base/host_resolver_proc.h"
[email protected]2bb04442010-08-18 18:01:1534#include "net/base/net_errors.h"
[email protected]ee094b82010-08-24 15:55:5135#include "net/base/net_log.h"
[email protected]0f8f1b432010-03-16 19:06:0336#include "net/base/net_util.h"
[email protected]b59ff372009-07-15 22:04:3237
38#if defined(OS_WIN)
39#include "net/base/winsock_init.h"
40#endif
41
42namespace net {
43
[email protected]e95d3aca2010-01-11 22:47:4344namespace {
45
[email protected]24f4bab2010-10-15 01:27:1146// We use a separate histogram name for each platform to facilitate the
47// display of error codes by their symbolic name (since each platform has
48// different mappings).
49const char kOSErrorsForGetAddrinfoHistogramName[] =
50#if defined(OS_WIN)
51 "Net.OSErrorsForGetAddrinfo_Win";
52#elif defined(OS_MACOSX)
53 "Net.OSErrorsForGetAddrinfo_Mac";
54#elif defined(OS_LINUX)
55 "Net.OSErrorsForGetAddrinfo_Linux";
56#else
57 "Net.OSErrorsForGetAddrinfo";
58#endif
59
[email protected]e95d3aca2010-01-11 22:47:4360HostCache* CreateDefaultCache() {
[email protected]b59ff372009-07-15 22:04:3261 static const size_t kMaxHostCacheEntries = 100;
[email protected]112bd462009-12-10 07:23:4062
63 HostCache* cache = new HostCache(
64 kMaxHostCacheEntries,
65 base::TimeDelta::FromMinutes(1),
[email protected]72bceac2010-06-17 21:45:0866 base::TimeDelta::FromSeconds(0)); // Disable caching of failed DNS.
[email protected]112bd462009-12-10 07:23:4067
[email protected]e95d3aca2010-01-11 22:47:4368 return cache;
69}
70
71} // anonymous namespace
72
[email protected]ee094b82010-08-24 15:55:5173HostResolver* CreateSystemHostResolver(size_t max_concurrent_resolves,
74 NetLog* net_log) {
[email protected]68ad3ee2010-01-30 03:45:3975 // Maximum of 50 concurrent threads.
76 // TODO(eroman): Adjust this, do some A/B experiments.
[email protected]962b98212010-07-17 03:37:5177 static const size_t kDefaultMaxJobs = 50u;
78
79 if (max_concurrent_resolves == HostResolver::kDefaultParallelism)
80 max_concurrent_resolves = kDefaultMaxJobs;
[email protected]68ad3ee2010-01-30 03:45:3981
[email protected]66761b952010-06-25 21:30:3882 HostResolverImpl* resolver =
[email protected]962b98212010-07-17 03:37:5183 new HostResolverImpl(NULL, CreateDefaultCache(),
[email protected]ee094b82010-08-24 15:55:5184 max_concurrent_resolves, net_log);
[email protected]68ad3ee2010-01-30 03:45:3985
86 return resolver;
[email protected]b59ff372009-07-15 22:04:3287}
88
89static int ResolveAddrInfo(HostResolverProc* resolver_proc,
[email protected]123ab1e32009-10-21 19:12:5790 const std::string& host,
91 AddressFamily address_family,
[email protected]5ea28dea2010-04-08 15:35:1392 HostResolverFlags host_resolver_flags,
[email protected]21526002010-05-16 19:42:4693 AddressList* out,
94 int* os_error) {
[email protected]b59ff372009-07-15 22:04:3295 if (resolver_proc) {
96 // Use the custom procedure.
[email protected]5ea28dea2010-04-08 15:35:1397 return resolver_proc->Resolve(host, address_family,
[email protected]21526002010-05-16 19:42:4698 host_resolver_flags, out, os_error);
[email protected]b59ff372009-07-15 22:04:3299 } else {
100 // Use the system procedure (getaddrinfo).
[email protected]5ea28dea2010-04-08 15:35:13101 return SystemHostResolverProc(host, address_family,
[email protected]21526002010-05-16 19:42:46102 host_resolver_flags, out, os_error);
[email protected]b59ff372009-07-15 22:04:32103 }
104}
105
[email protected]21526002010-05-16 19:42:46106// Extra parameters to attach to the NetLog when the resolve failed.
107class HostResolveFailedParams : public NetLog::EventParameters {
108 public:
[email protected]ee094b82010-08-24 15:55:51109 HostResolveFailedParams(int net_error, int os_error)
[email protected]21526002010-05-16 19:42:46110 : net_error_(net_error),
[email protected]ee094b82010-08-24 15:55:51111 os_error_(os_error) {
[email protected]21526002010-05-16 19:42:46112 }
113
114 virtual Value* ToValue() const {
115 DictionaryValue* dict = new DictionaryValue();
[email protected]ccaff652010-07-31 06:28:20116 dict->SetInteger("net_error", net_error_);
[email protected]21526002010-05-16 19:42:46117
118 if (os_error_) {
[email protected]ccaff652010-07-31 06:28:20119 dict->SetInteger("os_error", os_error_);
[email protected]21526002010-05-16 19:42:46120#if defined(OS_POSIX)
[email protected]ccaff652010-07-31 06:28:20121 dict->SetString("os_error_string", gai_strerror(os_error_));
[email protected]21526002010-05-16 19:42:46122#elif defined(OS_WIN)
123 // Map the error code to a human-readable string.
124 LPWSTR error_string = NULL;
125 int size = FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
126 FORMAT_MESSAGE_FROM_SYSTEM,
127 0, // Use the internal message table.
128 os_error_,
129 0, // Use default language.
130 (LPWSTR)&error_string,
131 0, // Buffer size.
132 0); // Arguments (unused).
[email protected]ccaff652010-07-31 06:28:20133 dict->SetString("os_error_string", WideToUTF8(error_string));
[email protected]21526002010-05-16 19:42:46134 LocalFree(error_string);
135#endif
136 }
137
138 return dict;
139 }
140
141 private:
142 const int net_error_;
143 const int os_error_;
[email protected]ee094b82010-08-24 15:55:51144};
145
146// Parameters representing the information in a RequestInfo object, along with
147// the associated NetLog::Source.
148class RequestInfoParameters : public NetLog::EventParameters {
149 public:
150 RequestInfoParameters(const HostResolver::RequestInfo& info,
151 const NetLog::Source& source)
152 : info_(info), source_(source) {}
153
154 virtual Value* ToValue() const {
155 DictionaryValue* dict = new DictionaryValue();
[email protected]930cc742010-09-15 22:54:10156 dict->SetString("host", info_.host_port_pair().ToString());
[email protected]ee094b82010-08-24 15:55:51157 dict->SetInteger("address_family",
158 static_cast<int>(info_.address_family()));
159 dict->SetBoolean("allow_cached_response", info_.allow_cached_response());
160 dict->SetBoolean("is_speculative", info_.is_speculative());
161 dict->SetInteger("priority", info_.priority());
162
163 if (source_.is_valid())
164 dict->Set("source_dependency", source_.ToValue());
165
166 return dict;
167 }
168
169 private:
170 const HostResolver::RequestInfo info_;
171 const NetLog::Source source_;
172};
173
174// Parameters associated with the creation of a HostResolveImpl::Job.
175class JobCreationParameters : public NetLog::EventParameters {
176 public:
177 JobCreationParameters(const std::string& host, const NetLog::Source& source)
178 : host_(host), source_(source) {}
179
180 virtual Value* ToValue() const {
181 DictionaryValue* dict = new DictionaryValue();
182 dict->SetString("host", host_);
183 dict->Set("source_dependency", source_.ToValue());
184 return dict;
185 }
186
187 private:
188 const std::string host_;
189 const NetLog::Source source_;
[email protected]21526002010-05-16 19:42:46190};
191
192// Gets a list of the likely error codes that getaddrinfo() can return
193// (non-exhaustive). These are the error codes that we will track via
194// a histogram.
195std::vector<int> GetAllGetAddrinfoOSErrors() {
196 int os_errors[] = {
197#if defined(OS_POSIX)
198 EAI_ADDRFAMILY,
199 EAI_AGAIN,
200 EAI_BADFLAGS,
201 EAI_FAIL,
202 EAI_FAMILY,
203 EAI_MEMORY,
204 EAI_NODATA,
205 EAI_NONAME,
206 EAI_SERVICE,
207 EAI_SOCKTYPE,
208 EAI_SYSTEM,
209#elif defined(OS_WIN)
210 // See: http://msdn.microsoft.com/en-us/library/ms738520(VS.85).aspx
211 WSA_NOT_ENOUGH_MEMORY,
212 WSAEAFNOSUPPORT,
213 WSAEINVAL,
214 WSAESOCKTNOSUPPORT,
215 WSAHOST_NOT_FOUND,
216 WSANO_DATA,
217 WSANO_RECOVERY,
218 WSANOTINITIALISED,
219 WSATRY_AGAIN,
220 WSATYPE_NOT_FOUND,
[email protected]1e9bbd22010-10-15 16:42:45221 // The following are not in doc, but might be to appearing in results :-(.
222 WSA_INVALID_HANDLE,
[email protected]21526002010-05-16 19:42:46223#endif
224 };
225
226 // Histogram enumerations require positive numbers.
227 std::vector<int> errors;
228 for (size_t i = 0; i < arraysize(os_errors); ++i) {
229 errors.push_back(std::abs(os_errors[i]));
230 // Also add N+1 for each error, so the bucket that contains our expected
231 // error is of size 1. That way if we get unexpected error codes, they
232 // won't fall into the same buckets as the expected ones.
233 errors.push_back(std::abs(os_errors[i]) + 1);
234 }
235 return errors;
236}
237
[email protected]b59ff372009-07-15 22:04:32238//-----------------------------------------------------------------------------
239
240class HostResolverImpl::Request {
241 public:
[email protected]ee094b82010-08-24 15:55:51242 Request(const BoundNetLog& source_net_log,
243 const BoundNetLog& request_net_log,
[email protected]54e13772009-08-14 03:01:09244 int id,
245 const RequestInfo& info,
246 CompletionCallback* callback,
[email protected]b59ff372009-07-15 22:04:32247 AddressList* addresses)
[email protected]ee094b82010-08-24 15:55:51248 : source_net_log_(source_net_log),
249 request_net_log_(request_net_log),
[email protected]54e13772009-08-14 03:01:09250 id_(id),
251 info_(info),
252 job_(NULL),
253 callback_(callback),
254 addresses_(addresses) {
255 }
[email protected]b59ff372009-07-15 22:04:32256
257 // Mark the request as cancelled.
258 void MarkAsCancelled() {
259 job_ = NULL;
260 callback_ = NULL;
261 addresses_ = NULL;
262 }
263
264 bool was_cancelled() const {
265 return callback_ == NULL;
266 }
267
268 void set_job(Job* job) {
269 DCHECK(job != NULL);
270 // Identify which job the request is waiting on.
271 job_ = job;
272 }
273
274 void OnComplete(int error, const AddressList& addrlist) {
275 if (error == OK)
276 addresses_->SetFrom(addrlist, port());
[email protected]ef4c40c2010-09-01 14:42:03277 CompletionCallback* callback = callback_;
278 MarkAsCancelled();
279 callback->Run(error);
[email protected]b59ff372009-07-15 22:04:32280 }
281
282 int port() const {
283 return info_.port();
284 }
285
286 Job* job() const {
287 return job_;
288 }
289
[email protected]ee094b82010-08-24 15:55:51290 const BoundNetLog& source_net_log() {
291 return source_net_log_;
292 }
293
294 const BoundNetLog& request_net_log() {
295 return request_net_log_;
[email protected]54e13772009-08-14 03:01:09296 }
297
[email protected]b59ff372009-07-15 22:04:32298 int id() const {
299 return id_;
300 }
301
302 const RequestInfo& info() const {
303 return info_;
304 }
305
306 private:
[email protected]ee094b82010-08-24 15:55:51307 BoundNetLog source_net_log_;
308 BoundNetLog request_net_log_;
[email protected]54e13772009-08-14 03:01:09309
[email protected]b59ff372009-07-15 22:04:32310 // Unique ID for this request. Used by observers to identify requests.
311 int id_;
312
313 // The request info that started the request.
314 RequestInfo info_;
315
316 // The resolve job (running in worker pool) that this request is dependent on.
317 Job* job_;
318
319 // The user's callback to invoke when the request completes.
320 CompletionCallback* callback_;
321
322 // The address list to save result into.
323 AddressList* addresses_;
324
325 DISALLOW_COPY_AND_ASSIGN(Request);
326};
327
[email protected]1e9bbd22010-10-15 16:42:45328//------------------------------------------------------------------------------
329
330// Provide a common macro to simplify code and readability. We must use a
331// macros as the underlying HISTOGRAM macro creates static varibles.
332#define DNS_HISTOGRAM(name, time) UMA_HISTOGRAM_CUSTOM_TIMES(name, time, \
333 base::TimeDelta::FromMicroseconds(1), base::TimeDelta::FromHours(1), 100)
[email protected]b59ff372009-07-15 22:04:32334
335// This class represents a request to the worker pool for a "getaddrinfo()"
336// call.
337class HostResolverImpl::Job
338 : public base::RefCountedThreadSafe<HostResolverImpl::Job> {
339 public:
[email protected]ee094b82010-08-24 15:55:51340 Job(int id,
341 HostResolverImpl* resolver,
342 const Key& key,
343 const BoundNetLog& source_net_log,
344 NetLog* net_log)
345 : id_(id),
346 key_(key),
347 resolver_(resolver),
348 origin_loop_(MessageLoop::current()),
349 resolver_proc_(resolver->effective_resolver_proc()),
350 error_(OK),
351 os_error_(0),
352 had_non_speculative_request_(false),
353 net_log_(BoundNetLog::Make(net_log,
354 NetLog::SOURCE_HOST_RESOLVER_IMPL_JOB)) {
355 net_log_.BeginEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_JOB,
356 new JobCreationParameters(key.hostname,
357 source_net_log.source()));
[email protected]b59ff372009-07-15 22:04:32358 }
359
[email protected]b59ff372009-07-15 22:04:32360 // Attaches a request to this job. The job takes ownership of |req| and will
361 // take care to delete it.
362 void AddRequest(Request* req) {
[email protected]ee094b82010-08-24 15:55:51363 req->request_net_log().BeginEvent(
364 NetLog::TYPE_HOST_RESOLVER_IMPL_JOB_ATTACH,
365 new NetLogSourceParameter("source_dependency", net_log_.source()));
366
[email protected]b59ff372009-07-15 22:04:32367 req->set_job(this);
368 requests_.push_back(req);
[email protected]252b699b2010-02-05 21:38:06369
370 if (!req->info().is_speculative())
371 had_non_speculative_request_ = true;
[email protected]b59ff372009-07-15 22:04:32372 }
373
374 // Called from origin loop.
375 void Start() {
[email protected]252b699b2010-02-05 21:38:06376 start_time_ = base::TimeTicks::Now();
377
[email protected]b59ff372009-07-15 22:04:32378 // Dispatch the job to a worker thread.
379 if (!WorkerPool::PostTask(FROM_HERE,
380 NewRunnableMethod(this, &Job::DoLookup), true)) {
381 NOTREACHED();
382
383 // Since we could be running within Resolve() right now, we can't just
384 // call OnLookupComplete(). Instead we must wait until Resolve() has
385 // returned (IO_PENDING).
386 error_ = ERR_UNEXPECTED;
387 MessageLoop::current()->PostTask(
388 FROM_HERE, NewRunnableMethod(this, &Job::OnLookupComplete));
389 }
390 }
391
392 // Cancels the current job. Callable from origin thread.
393 void Cancel() {
[email protected]ee094b82010-08-24 15:55:51394 net_log_.AddEvent(NetLog::TYPE_CANCELLED, NULL);
395
[email protected]b59ff372009-07-15 22:04:32396 HostResolver* resolver = resolver_;
397 resolver_ = NULL;
398
399 // Mark the job as cancelled, so when worker thread completes it will
400 // not try to post completion to origin loop.
401 {
402 AutoLock locked(origin_loop_lock_);
403 origin_loop_ = NULL;
404 }
405
[email protected]ee094b82010-08-24 15:55:51406 // End here to prevent issues when a Job outlives the HostResolver that
407 // spawned it.
408 net_log_.EndEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_JOB, NULL);
409
[email protected]1877a2212009-09-18 21:09:26410 // We will call HostResolverImpl::CancelRequest(Request*) on each one
[email protected]27f99c82009-10-29 22:21:00411 // in order to notify any observers.
[email protected]b59ff372009-07-15 22:04:32412 for (RequestsList::const_iterator it = requests_.begin();
413 it != requests_.end(); ++it) {
414 HostResolverImpl::Request* req = *it;
415 if (!req->was_cancelled())
416 resolver->CancelRequest(req);
417 }
418 }
419
420 // Called from origin thread.
421 bool was_cancelled() const {
422 return resolver_ == NULL;
423 }
424
425 // Called from origin thread.
[email protected]123ab1e32009-10-21 19:12:57426 const Key& key() const {
427 return key_;
[email protected]b59ff372009-07-15 22:04:32428 }
429
[email protected]a2fbebe2010-02-05 01:40:12430 int id() const {
431 return id_;
432 }
433
[email protected]252b699b2010-02-05 21:38:06434 base::TimeTicks start_time() const {
435 return start_time_;
436 }
437
[email protected]b59ff372009-07-15 22:04:32438 // Called from origin thread.
439 const RequestsList& requests() const {
440 return requests_;
441 }
442
[email protected]68ad3ee2010-01-30 03:45:39443 // Returns the first request attached to the job.
444 const Request* initial_request() const {
445 DCHECK_EQ(origin_loop_, MessageLoop::current());
446 DCHECK(!requests_.empty());
447 return requests_[0];
448 }
449
[email protected]137af622010-02-05 02:14:35450 // Returns true if |req_info| can be fulfilled by this job.
451 bool CanServiceRequest(const RequestInfo& req_info) const {
452 return key_ == resolver_->GetEffectiveKeyForRequest(req_info);
453 }
454
[email protected]b59ff372009-07-15 22:04:32455 private:
[email protected]5389bc72009-11-05 23:34:24456 friend class base::RefCountedThreadSafe<HostResolverImpl::Job>;
457
458 ~Job() {
459 // Free the requests attached to this job.
460 STLDeleteElements(&requests_);
461 }
462
[email protected]6c710ee2010-05-07 07:51:16463 // WARNING: This code runs inside a worker pool. The shutdown code cannot
464 // wait for it to finish, so we must be very careful here about using other
465 // objects (like MessageLoops, Singletons, etc). During shutdown these objects
466 // may no longer exist.
[email protected]b59ff372009-07-15 22:04:32467 void DoLookup() {
468 // Running on the worker thread
[email protected]123ab1e32009-10-21 19:12:57469 error_ = ResolveAddrInfo(resolver_proc_,
470 key_.hostname,
471 key_.address_family,
[email protected]5ea28dea2010-04-08 15:35:13472 key_.host_resolver_flags,
[email protected]21526002010-05-16 19:42:46473 &results_,
474 &os_error_);
[email protected]b59ff372009-07-15 22:04:32475
[email protected]b59ff372009-07-15 22:04:32476 // The origin loop could go away while we are trying to post to it, so we
477 // need to call its PostTask method inside a lock. See ~HostResolver.
478 {
479 AutoLock locked(origin_loop_lock_);
480 if (origin_loop_) {
[email protected]6c710ee2010-05-07 07:51:16481 origin_loop_->PostTask(FROM_HERE,
482 NewRunnableMethod(this, &Job::OnLookupComplete));
[email protected]b59ff372009-07-15 22:04:32483 }
484 }
[email protected]b59ff372009-07-15 22:04:32485 }
486
487 // Callback for when DoLookup() completes (runs on origin thread).
488 void OnLookupComplete() {
489 // Should be running on origin loop.
490 // TODO(eroman): this is being hit by URLRequestTest.CancelTest*,
491 // because MessageLoop::current() == NULL.
492 //DCHECK_EQ(origin_loop_, MessageLoop::current());
493 DCHECK(error_ || results_.head());
494
[email protected]2d3b7762010-10-09 00:35:47495 // Ideally the following code would be part of host_resolver_proc.cc,
496 // however it isn't safe to call NetworkChangeNotifier from worker
497 // threads. So we do it here on the IO thread instead.
[email protected]8ed0cab62010-10-15 04:12:45498 if (error_ != OK && NetworkChangeNotifier::IsOffline())
[email protected]2d3b7762010-10-09 00:35:47499 error_ = ERR_INTERNET_DISCONNECTED;
500
[email protected]1e9bbd22010-10-15 16:42:45501 RecordPerformanceHistograms();
[email protected]f2d8c4212010-02-02 00:56:35502
[email protected]b59ff372009-07-15 22:04:32503 if (was_cancelled())
504 return;
505
[email protected]ee094b82010-08-24 15:55:51506 scoped_refptr<NetLog::EventParameters> params;
507 if (error_ != OK) {
508 params = new HostResolveFailedParams(error_, os_error_);
509 } else {
510 params = new AddressListNetLogParam(results_);
511 }
512
513 // End here to prevent issues when a Job outlives the HostResolver that
514 // spawned it.
515 net_log_.EndEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_JOB, params);
516
[email protected]b59ff372009-07-15 22:04:32517 DCHECK(!requests_.empty());
518
519 // Use the port number of the first request.
520 if (error_ == OK)
521 results_.SetPort(requests_[0]->port());
522
[email protected]21526002010-05-16 19:42:46523 resolver_->OnJobComplete(this, error_, os_error_, results_);
[email protected]b59ff372009-07-15 22:04:32524 }
525
[email protected]1e9bbd22010-10-15 16:42:45526 void RecordPerformanceHistograms() const {
527 enum Category { // Used in HISTOGRAM_ENUMERATION.
528 RESOLVE_SUCCESS,
529 RESOLVE_FAIL,
530 RESOLVE_SPECULATIVE_SUCCESS,
531 RESOLVE_SPECULATIVE_FAIL,
532 RESOLVE_MAX, // Bounding value.
533 };
534 int category = RESOLVE_MAX; // Illegal value for later DCHECK only.
535
536 base::TimeDelta duration = base::TimeTicks::Now() - start_time_;
537 if (error_ == OK) {
538 if (had_non_speculative_request_) {
539 category = RESOLVE_SUCCESS;
540 DNS_HISTOGRAM("DNS.ResolveSuccess", duration);
541 } else {
542 category = RESOLVE_SPECULATIVE_SUCCESS;
543 DNS_HISTOGRAM("DNS.ResolveSpeculativeSuccess", duration);
544 }
545 } else {
546 if (had_non_speculative_request_) {
547 category = RESOLVE_FAIL;
548 DNS_HISTOGRAM("DNS.ResolveFail", duration);
549 } else {
550 category = RESOLVE_SPECULATIVE_FAIL;
551 DNS_HISTOGRAM("DNS.ResolveSpeculativeFail", duration);
552 }
553 UMA_HISTOGRAM_CUSTOM_ENUMERATION("Net.OSErrorsForGetAddrinfo",
554 std::abs(os_error_),
555 GetAllGetAddrinfoOSErrors());
556 }
557 DCHECK_LT(category, RESOLVE_MAX); // Be sure it was set.
558
559 UMA_HISTOGRAM_ENUMERATION("DNS.ResolveCategory", category, RESOLVE_MAX);
560
561 static bool show_experiment_histograms =
562 base::FieldTrialList::Find("DnsImpact") &&
563 !base::FieldTrialList::Find("DnsImpact")->group_name().empty();
564 if (show_experiment_histograms) {
565 UMA_HISTOGRAM_ENUMERATION(
566 base::FieldTrial::MakeName("DNS.ResolveCategory", "DnsImpact"),
567 category, RESOLVE_MAX);
568 if (RESOLVE_SUCCESS == category) {
569 DNS_HISTOGRAM(base::FieldTrial::MakeName("DNS.ResolveSuccess",
570 "DnsImpact"), duration);
571 }
572 }
573 }
574
575
576
[email protected]f2d8c4212010-02-02 00:56:35577 // Immutable. Can be read from either thread,
578 const int id_;
579
[email protected]b59ff372009-07-15 22:04:32580 // Set on the origin thread, read on the worker thread.
[email protected]123ab1e32009-10-21 19:12:57581 Key key_;
[email protected]b59ff372009-07-15 22:04:32582
583 // Only used on the origin thread (where Resolve was called).
584 HostResolverImpl* resolver_;
585 RequestsList requests_; // The requests waiting on this job.
586
587 // Used to post ourselves onto the origin thread.
588 Lock origin_loop_lock_;
589 MessageLoop* origin_loop_;
590
591 // Hold an owning reference to the HostResolverProc that we are going to use.
592 // This may not be the current resolver procedure by the time we call
593 // ResolveAddrInfo, but that's OK... we'll use it anyways, and the owning
594 // reference ensures that it remains valid until we are done.
595 scoped_refptr<HostResolverProc> resolver_proc_;
596
597 // Assigned on the worker thread, read on the origin thread.
598 int error_;
[email protected]21526002010-05-16 19:42:46599 int os_error_;
[email protected]252b699b2010-02-05 21:38:06600
601 // True if a non-speculative request was ever attached to this job
602 // (regardless of whether or not it was later cancelled.
603 // This boolean is used for histogramming the duration of jobs used to
604 // service non-speculative requests.
605 bool had_non_speculative_request_;
606
[email protected]b59ff372009-07-15 22:04:32607 AddressList results_;
608
[email protected]252b699b2010-02-05 21:38:06609 // The time when the job was started.
610 base::TimeTicks start_time_;
611
[email protected]ee094b82010-08-24 15:55:51612 BoundNetLog net_log_;
613
[email protected]b59ff372009-07-15 22:04:32614 DISALLOW_COPY_AND_ASSIGN(Job);
615};
616
617//-----------------------------------------------------------------------------
618
[email protected]0f8f1b432010-03-16 19:06:03619// This class represents a request to the worker pool for a "probe for IPv6
620// support" call.
621class HostResolverImpl::IPv6ProbeJob
622 : public base::RefCountedThreadSafe<HostResolverImpl::IPv6ProbeJob> {
623 public:
624 explicit IPv6ProbeJob(HostResolverImpl* resolver)
625 : resolver_(resolver),
626 origin_loop_(MessageLoop::current()) {
[email protected]a9af7112010-05-08 00:56:01627 DCHECK(!was_cancelled());
[email protected]0f8f1b432010-03-16 19:06:03628 }
629
630 void Start() {
[email protected]a9af7112010-05-08 00:56:01631 if (was_cancelled())
632 return;
[email protected]0f8f1b432010-03-16 19:06:03633 DCHECK(IsOnOriginThread());
[email protected]f092e64b2010-03-17 00:39:18634 const bool kIsSlow = true;
[email protected]0f8f1b432010-03-16 19:06:03635 WorkerPool::PostTask(
[email protected]f092e64b2010-03-17 00:39:18636 FROM_HERE, NewRunnableMethod(this, &IPv6ProbeJob::DoProbe), kIsSlow);
[email protected]0f8f1b432010-03-16 19:06:03637 }
638
639 // Cancels the current job.
640 void Cancel() {
[email protected]a9af7112010-05-08 00:56:01641 if (was_cancelled())
642 return;
[email protected]0f8f1b432010-03-16 19:06:03643 DCHECK(IsOnOriginThread());
644 resolver_ = NULL; // Read/write ONLY on origin thread.
645 {
646 AutoLock locked(origin_loop_lock_);
647 // Origin loop may be destroyed before we can use it!
[email protected]a9af7112010-05-08 00:56:01648 origin_loop_ = NULL; // Write ONLY on origin thread.
[email protected]0f8f1b432010-03-16 19:06:03649 }
650 }
651
[email protected]0f8f1b432010-03-16 19:06:03652 private:
653 friend class base::RefCountedThreadSafe<HostResolverImpl::IPv6ProbeJob>;
654
655 ~IPv6ProbeJob() {
656 }
657
[email protected]a9af7112010-05-08 00:56:01658 // Should be run on |orgin_thread_|, but that may not be well defined now.
659 bool was_cancelled() const {
660 if (!resolver_ || !origin_loop_) {
661 DCHECK(!resolver_);
662 DCHECK(!origin_loop_);
663 return true;
664 }
665 return false;
666 }
667
[email protected]0f8f1b432010-03-16 19:06:03668 // Run on worker thread.
669 void DoProbe() {
670 // Do actual testing on this thread, as it takes 40-100ms.
671 AddressFamily family = IPv6Supported() ? ADDRESS_FAMILY_UNSPECIFIED
672 : ADDRESS_FAMILY_IPV4;
673
674 Task* reply = NewRunnableMethod(this, &IPv6ProbeJob::OnProbeComplete,
675 family);
676
677 // The origin loop could go away while we are trying to post to it, so we
678 // need to call its PostTask method inside a lock. See ~HostResolver.
679 {
680 AutoLock locked(origin_loop_lock_);
681 if (origin_loop_) {
682 origin_loop_->PostTask(FROM_HERE, reply);
683 return;
684 }
685 }
686
687 // We didn't post, so delete the reply.
688 delete reply;
689 }
690
691 // Callback for when DoProbe() completes (runs on origin thread).
692 void OnProbeComplete(AddressFamily address_family) {
[email protected]a9af7112010-05-08 00:56:01693 if (was_cancelled())
694 return;
[email protected]0f8f1b432010-03-16 19:06:03695 DCHECK(IsOnOriginThread());
[email protected]a9af7112010-05-08 00:56:01696 resolver_->IPv6ProbeSetDefaultAddressFamily(address_family);
[email protected]0f8f1b432010-03-16 19:06:03697 }
698
699 bool IsOnOriginThread() const {
700 return !MessageLoop::current() || origin_loop_ == MessageLoop::current();
701 }
702
703 // Used/set only on origin thread.
704 HostResolverImpl* resolver_;
705
706 // Used to post ourselves onto the origin thread.
707 Lock origin_loop_lock_;
708 MessageLoop* origin_loop_;
709
710 DISALLOW_COPY_AND_ASSIGN(IPv6ProbeJob);
711};
712
713//-----------------------------------------------------------------------------
714
[email protected]68ad3ee2010-01-30 03:45:39715// We rely on the priority enum values being sequential having starting at 0,
716// and increasing for lower priorities.
717COMPILE_ASSERT(HIGHEST == 0u &&
718 LOWEST > HIGHEST &&
[email protected]c9c6f5c2010-07-31 01:30:03719 IDLE > LOWEST &&
720 NUM_PRIORITIES > IDLE,
[email protected]68ad3ee2010-01-30 03:45:39721 priority_indexes_incompatible);
722
723// JobPool contains all the information relating to queued requests, including
724// the limits on how many jobs are allowed to be used for this category of
725// requests.
726class HostResolverImpl::JobPool {
727 public:
728 JobPool(size_t max_outstanding_jobs, size_t max_pending_requests)
729 : num_outstanding_jobs_(0u) {
730 SetConstraints(max_outstanding_jobs, max_pending_requests);
731 }
732
733 ~JobPool() {
734 // Free the pending requests.
735 for (size_t i = 0; i < arraysize(pending_requests_); ++i)
736 STLDeleteElements(&pending_requests_[i]);
737 }
738
739 // Sets the constraints for this pool. See SetPoolConstraints() for the
740 // specific meaning of these parameters.
741 void SetConstraints(size_t max_outstanding_jobs,
742 size_t max_pending_requests) {
[email protected]b1f031dd2010-03-02 23:19:33743 CHECK_NE(max_outstanding_jobs, 0u);
[email protected]68ad3ee2010-01-30 03:45:39744 max_outstanding_jobs_ = max_outstanding_jobs;
745 max_pending_requests_ = max_pending_requests;
746 }
747
748 // Returns the number of pending requests enqueued to this pool.
749 // A pending request is one waiting to be attached to a job.
750 size_t GetNumPendingRequests() const {
751 size_t total = 0u;
752 for (size_t i = 0u; i < arraysize(pending_requests_); ++i)
753 total += pending_requests_[i].size();
754 return total;
755 }
756
757 bool HasPendingRequests() const {
758 return GetNumPendingRequests() > 0u;
759 }
760
761 // Enqueues a request to this pool. As a result of enqueing this request,
762 // the queue may have reached its maximum size. In this case, a request is
763 // evicted from the queue, and returned. Otherwise returns NULL. The caller
764 // is responsible for freeing the evicted request.
765 Request* InsertPendingRequest(Request* req) {
[email protected]ee094b82010-08-24 15:55:51766 req->request_net_log().BeginEvent(
767 NetLog::TYPE_HOST_RESOLVER_IMPL_JOB_POOL_QUEUE,
768 NULL);
769
[email protected]68ad3ee2010-01-30 03:45:39770 PendingRequestsQueue& q = pending_requests_[req->info().priority()];
771 q.push_back(req);
772
773 // If the queue is too big, kick out the lowest priority oldest request.
774 if (GetNumPendingRequests() > max_pending_requests_) {
775 // Iterate over the queues from lowest priority to highest priority.
776 for (int i = static_cast<int>(arraysize(pending_requests_)) - 1;
777 i >= 0; --i) {
778 PendingRequestsQueue& q = pending_requests_[i];
779 if (!q.empty()) {
780 Request* req = q.front();
781 q.pop_front();
[email protected]ee094b82010-08-24 15:55:51782 req->request_net_log().AddEvent(
783 NetLog::TYPE_HOST_RESOLVER_IMPL_JOB_POOL_QUEUE_EVICTED, NULL);
784 req->request_net_log().EndEvent(
785 NetLog::TYPE_HOST_RESOLVER_IMPL_JOB_POOL_QUEUE, NULL);
[email protected]68ad3ee2010-01-30 03:45:39786 return req;
787 }
788 }
789 }
790
791 return NULL;
792 }
793
794 // Erases |req| from this container. Caller is responsible for freeing
795 // |req| afterwards.
796 void RemovePendingRequest(Request* req) {
797 PendingRequestsQueue& q = pending_requests_[req->info().priority()];
798 PendingRequestsQueue::iterator it = std::find(q.begin(), q.end(), req);
799 DCHECK(it != q.end());
800 q.erase(it);
[email protected]ee094b82010-08-24 15:55:51801 req->request_net_log().EndEvent(
802 NetLog::TYPE_HOST_RESOLVER_IMPL_JOB_POOL_QUEUE, NULL);
[email protected]68ad3ee2010-01-30 03:45:39803 }
804
805 // Removes and returns the highest priority pending request.
806 Request* RemoveTopPendingRequest() {
807 DCHECK(HasPendingRequests());
808
809 for (size_t i = 0u; i < arraysize(pending_requests_); ++i) {
810 PendingRequestsQueue& q = pending_requests_[i];
811 if (!q.empty()) {
812 Request* req = q.front();
813 q.pop_front();
[email protected]ee094b82010-08-24 15:55:51814 req->request_net_log().EndEvent(
815 NetLog::TYPE_HOST_RESOLVER_IMPL_JOB_POOL_QUEUE, NULL);
[email protected]68ad3ee2010-01-30 03:45:39816 return req;
817 }
818 }
819
820 NOTREACHED();
821 return NULL;
822 }
823
824 // Keeps track of a job that was just added/removed, and belongs to this pool.
825 void AdjustNumOutstandingJobs(int offset) {
826 DCHECK(offset == 1 || (offset == -1 && num_outstanding_jobs_ > 0u));
827 num_outstanding_jobs_ += offset;
828 }
829
[email protected]35ddc282010-09-21 23:42:06830 void ResetNumOutstandingJobs() {
831 num_outstanding_jobs_ = 0;
832 }
833
[email protected]68ad3ee2010-01-30 03:45:39834 // Returns true if a new job can be created for this pool.
835 bool CanCreateJob() const {
836 return num_outstanding_jobs_ + 1u <= max_outstanding_jobs_;
837 }
838
839 // Removes any pending requests from the queue which are for the
[email protected]137af622010-02-05 02:14:35840 // same (hostname / effective address-family) as |job|, and attaches them to
841 // |job|.
[email protected]68ad3ee2010-01-30 03:45:39842 void MoveRequestsToJob(Job* job) {
843 for (size_t i = 0u; i < arraysize(pending_requests_); ++i) {
844 PendingRequestsQueue& q = pending_requests_[i];
845 PendingRequestsQueue::iterator req_it = q.begin();
846 while (req_it != q.end()) {
847 Request* req = *req_it;
[email protected]137af622010-02-05 02:14:35848 if (job->CanServiceRequest(req->info())) {
[email protected]68ad3ee2010-01-30 03:45:39849 // Job takes ownership of |req|.
850 job->AddRequest(req);
851 req_it = q.erase(req_it);
852 } else {
853 ++req_it;
854 }
855 }
856 }
857 }
858
859 private:
860 typedef std::deque<Request*> PendingRequestsQueue;
861
862 // Maximum number of concurrent jobs allowed to be started for requests
863 // belonging to this pool.
864 size_t max_outstanding_jobs_;
865
866 // The current number of running jobs that were started for requests
867 // belonging to this pool.
868 size_t num_outstanding_jobs_;
869
870 // The maximum number of requests we allow to be waiting on a job,
871 // for this pool.
872 size_t max_pending_requests_;
873
874 // The requests which are waiting to be started for this pool.
875 PendingRequestsQueue pending_requests_[NUM_PRIORITIES];
876};
877
878//-----------------------------------------------------------------------------
879
[email protected]e95d3aca2010-01-11 22:47:43880HostResolverImpl::HostResolverImpl(
881 HostResolverProc* resolver_proc,
882 HostCache* cache,
[email protected]ee094b82010-08-24 15:55:51883 size_t max_jobs,
884 NetLog* net_log)
[email protected]112bd462009-12-10 07:23:40885 : cache_(cache),
[email protected]68ad3ee2010-01-30 03:45:39886 max_jobs_(max_jobs),
[email protected]123ab1e32009-10-21 19:12:57887 next_request_id_(0),
[email protected]f2d8c4212010-02-02 00:56:35888 next_job_id_(0),
[email protected]123ab1e32009-10-21 19:12:57889 resolver_proc_(resolver_proc),
[email protected]0c7798452009-10-26 17:59:51890 default_address_family_(ADDRESS_FAMILY_UNSPECIFIED),
[email protected]e95d3aca2010-01-11 22:47:43891 shutdown_(false),
[email protected]2f3bc65c2010-07-23 17:47:10892 ipv6_probe_monitoring_(false),
[email protected]ee094b82010-08-24 15:55:51893 additional_resolver_flags_(0),
894 net_log_(net_log) {
[email protected]68ad3ee2010-01-30 03:45:39895 DCHECK_GT(max_jobs, 0u);
896
897 // It is cumbersome to expose all of the constraints in the constructor,
898 // so we choose some defaults, which users can override later.
899 job_pools_[POOL_NORMAL] = new JobPool(max_jobs, 100u * max_jobs);
900
[email protected]b59ff372009-07-15 22:04:32901#if defined(OS_WIN)
902 EnsureWinsockInit();
903#endif
[email protected]2f3bc65c2010-07-23 17:47:10904#if defined(OS_LINUX)
905 if (HaveOnlyLoopbackAddresses())
906 additional_resolver_flags_ |= HOST_RESOLVER_LOOPBACK_ONLY;
907#endif
[email protected]66761b952010-06-25 21:30:38908 NetworkChangeNotifier::AddObserver(this);
[email protected]b59ff372009-07-15 22:04:32909}
910
911HostResolverImpl::~HostResolverImpl() {
912 // Cancel the outstanding jobs. Those jobs may contain several attached
913 // requests, which will also be cancelled.
[email protected]0f8f1b432010-03-16 19:06:03914 DiscardIPv6ProbeJob();
915
[email protected]ef4c40c2010-09-01 14:42:03916 CancelAllJobs();
[email protected]b59ff372009-07-15 22:04:32917
918 // In case we are being deleted during the processing of a callback.
919 if (cur_completing_job_)
920 cur_completing_job_->Cancel();
[email protected]e95d3aca2010-01-11 22:47:43921
[email protected]66761b952010-06-25 21:30:38922 NetworkChangeNotifier::RemoveObserver(this);
[email protected]61a86c42010-04-19 22:45:53923
[email protected]68ad3ee2010-01-30 03:45:39924 // Delete the job pools.
925 for (size_t i = 0u; i < arraysize(job_pools_); ++i)
926 delete job_pools_[i];
[email protected]b59ff372009-07-15 22:04:32927}
928
[email protected]684970b2009-08-14 04:54:46929int HostResolverImpl::Resolve(const RequestInfo& info,
[email protected]b59ff372009-07-15 22:04:32930 AddressList* addresses,
931 CompletionCallback* callback,
[email protected]684970b2009-08-14 04:54:46932 RequestHandle* out_req,
[email protected]ee094b82010-08-24 15:55:51933 const BoundNetLog& source_net_log) {
[email protected]1ac6af92010-06-03 21:00:14934 DCHECK(CalledOnValidThread());
935
[email protected]b59ff372009-07-15 22:04:32936 if (shutdown_)
937 return ERR_UNEXPECTED;
938
939 // Choose a unique ID number for observers to see.
940 int request_id = next_request_id_++;
941
[email protected]ee094b82010-08-24 15:55:51942 // Make a log item for the request.
943 BoundNetLog request_net_log = BoundNetLog::Make(net_log_,
944 NetLog::SOURCE_HOST_RESOLVER_IMPL_REQUEST);
945
[email protected]9e743cd2010-03-16 07:03:53946 // Update the net log and notify registered observers.
[email protected]ee094b82010-08-24 15:55:51947 OnStartRequest(source_net_log, request_net_log, request_id, info);
[email protected]b59ff372009-07-15 22:04:32948
[email protected]123ab1e32009-10-21 19:12:57949 // Build a key that identifies the request in the cache and in the
950 // outstanding jobs map.
[email protected]137af622010-02-05 02:14:35951 Key key = GetEffectiveKeyForRequest(info);
[email protected]123ab1e32009-10-21 19:12:57952
[email protected]eaf3a3b2010-09-03 20:34:27953 // Check for IP literal.
954 IPAddressNumber ip_number;
955 if (ParseIPLiteralToNumber(info.hostname(), &ip_number)) {
956 DCHECK_EQ(key.host_resolver_flags &
957 ~(HOST_RESOLVER_CANONNAME | HOST_RESOLVER_LOOPBACK_ONLY |
958 HOST_RESOLVER_DEFAULT_FAMILY_SET_DUE_TO_NO_IPV6),
959 0) << " Unhandled flag";
960 bool ipv6_disabled = default_address_family_ == ADDRESS_FAMILY_IPV4 &&
961 !ipv6_probe_monitoring_;
962 int net_error = OK;
963 if (ip_number.size() == 16 && ipv6_disabled) {
964 net_error = ERR_NAME_NOT_RESOLVED;
965 } else {
966 AddressList result(ip_number, info.port(),
967 (key.host_resolver_flags & HOST_RESOLVER_CANONNAME));
968 *addresses = result;
969 }
970 // Update the net log and notify registered observers.
971 OnFinishRequest(source_net_log, request_net_log, request_id, info,
972 net_error, 0 /* os_error (unknown since from cache) */);
973 return net_error;
974 }
975
[email protected]b59ff372009-07-15 22:04:32976 // If we have an unexpired cache entry, use it.
[email protected]112bd462009-12-10 07:23:40977 if (info.allow_cached_response() && cache_.get()) {
978 const HostCache::Entry* cache_entry = cache_->Lookup(
[email protected]123ab1e32009-10-21 19:12:57979 key, base::TimeTicks::Now());
[email protected]b59ff372009-07-15 22:04:32980 if (cache_entry) {
[email protected]ee094b82010-08-24 15:55:51981 request_net_log.AddEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_CACHE_HIT, NULL);
[email protected]21526002010-05-16 19:42:46982 int net_error = cache_entry->error;
983 if (net_error == OK)
[email protected]112bd462009-12-10 07:23:40984 addresses->SetFrom(cache_entry->addrlist, info.port());
[email protected]b59ff372009-07-15 22:04:32985
[email protected]9e743cd2010-03-16 07:03:53986 // Update the net log and notify registered observers.
[email protected]ee094b82010-08-24 15:55:51987 OnFinishRequest(source_net_log, request_net_log, request_id, info,
988 net_error,
989 0 /* os_error (unknown since from cache) */);
[email protected]b59ff372009-07-15 22:04:32990
[email protected]21526002010-05-16 19:42:46991 return net_error;
[email protected]b59ff372009-07-15 22:04:32992 }
993 }
994
995 // If no callback was specified, do a synchronous resolution.
996 if (!callback) {
997 AddressList addrlist;
[email protected]21526002010-05-16 19:42:46998 int os_error = 0;
[email protected]b59ff372009-07-15 22:04:32999 int error = ResolveAddrInfo(
[email protected]5ea28dea2010-04-08 15:35:131000 effective_resolver_proc(), key.hostname, key.address_family,
[email protected]21526002010-05-16 19:42:461001 key.host_resolver_flags, &addrlist, &os_error);
[email protected]b59ff372009-07-15 22:04:321002 if (error == OK) {
1003 addrlist.SetPort(info.port());
1004 *addresses = addrlist;
1005 }
1006
1007 // Write to cache.
[email protected]112bd462009-12-10 07:23:401008 if (cache_.get())
1009 cache_->Set(key, error, addrlist, base::TimeTicks::Now());
[email protected]b59ff372009-07-15 22:04:321010
[email protected]9e743cd2010-03-16 07:03:531011 // Update the net log and notify registered observers.
[email protected]ee094b82010-08-24 15:55:511012 OnFinishRequest(source_net_log, request_net_log, request_id, info, error,
1013 os_error);
[email protected]b59ff372009-07-15 22:04:321014
1015 return error;
1016 }
1017
1018 // Create a handle for this request, and pass it back to the user if they
1019 // asked for it (out_req != NULL).
[email protected]ee094b82010-08-24 15:55:511020 Request* req = new Request(source_net_log, request_net_log, request_id, info,
1021 callback, addresses);
[email protected]b59ff372009-07-15 22:04:321022 if (out_req)
1023 *out_req = reinterpret_cast<RequestHandle>(req);
1024
1025 // Next we need to attach our request to a "job". This job is responsible for
1026 // calling "getaddrinfo(hostname)" on a worker thread.
1027 scoped_refptr<Job> job;
1028
[email protected]123ab1e32009-10-21 19:12:571029 // If there is already an outstanding job to resolve |key|, use
[email protected]b59ff372009-07-15 22:04:321030 // it. This prevents starting concurrent resolves for the same hostname.
[email protected]123ab1e32009-10-21 19:12:571031 job = FindOutstandingJob(key);
[email protected]b59ff372009-07-15 22:04:321032 if (job) {
1033 job->AddRequest(req);
1034 } else {
[email protected]68ad3ee2010-01-30 03:45:391035 JobPool* pool = GetPoolForRequest(req);
1036 if (CanCreateJobForPool(*pool)) {
1037 CreateAndStartJob(req);
1038 } else {
1039 return EnqueueRequest(pool, req);
1040 }
[email protected]b59ff372009-07-15 22:04:321041 }
1042
1043 // Completion happens during OnJobComplete(Job*).
1044 return ERR_IO_PENDING;
1045}
1046
1047// See OnJobComplete(Job*) for why it is important not to clean out
1048// cancelled requests from Job::requests_.
1049void HostResolverImpl::CancelRequest(RequestHandle req_handle) {
[email protected]1ac6af92010-06-03 21:00:141050 DCHECK(CalledOnValidThread());
[email protected]bf0b51c2009-08-01 23:46:401051 if (shutdown_) {
[email protected]ff1f61b92009-08-03 23:20:231052 // TODO(eroman): temp hack for: http://crbug.com/18373
1053 // Because we destroy outstanding requests during Shutdown(),
1054 // |req_handle| is already cancelled.
[email protected]bf0b51c2009-08-01 23:46:401055 LOG(ERROR) << "Called HostResolverImpl::CancelRequest() after Shutdown().";
1056 StackTrace().PrintBacktrace();
1057 return;
1058 }
[email protected]b59ff372009-07-15 22:04:321059 Request* req = reinterpret_cast<Request*>(req_handle);
1060 DCHECK(req);
[email protected]68ad3ee2010-01-30 03:45:391061
1062 scoped_ptr<Request> request_deleter; // Frees at end of function.
1063
1064 if (!req->job()) {
1065 // If the request was not attached to a job yet, it must have been
1066 // enqueued into a pool. Remove it from that pool's queue.
1067 // Otherwise if it was attached to a job, the job is responsible for
1068 // deleting it.
1069 JobPool* pool = GetPoolForRequest(req);
1070 pool->RemovePendingRequest(req);
1071 request_deleter.reset(req);
[email protected]ee094b82010-08-24 15:55:511072 } else {
1073 req->request_net_log().EndEvent(
1074 NetLog::TYPE_HOST_RESOLVER_IMPL_JOB_ATTACH, NULL);
[email protected]68ad3ee2010-01-30 03:45:391075 }
1076
[email protected]b59ff372009-07-15 22:04:321077 // NULL out the fields of req, to mark it as cancelled.
1078 req->MarkAsCancelled();
[email protected]ee094b82010-08-24 15:55:511079 OnCancelRequest(req->source_net_log(), req->request_net_log(), req->id(),
1080 req->info());
[email protected]b59ff372009-07-15 22:04:321081}
1082
[email protected]e95d3aca2010-01-11 22:47:431083void HostResolverImpl::AddObserver(HostResolver::Observer* observer) {
[email protected]1ac6af92010-06-03 21:00:141084 DCHECK(CalledOnValidThread());
[email protected]b59ff372009-07-15 22:04:321085 observers_.push_back(observer);
1086}
1087
[email protected]e95d3aca2010-01-11 22:47:431088void HostResolverImpl::RemoveObserver(HostResolver::Observer* observer) {
[email protected]1ac6af92010-06-03 21:00:141089 DCHECK(CalledOnValidThread());
[email protected]b59ff372009-07-15 22:04:321090 ObserversList::iterator it =
1091 std::find(observers_.begin(), observers_.end(), observer);
1092
1093 // Observer must exist.
1094 DCHECK(it != observers_.end());
1095
1096 observers_.erase(it);
1097}
1098
[email protected]0f8f1b432010-03-16 19:06:031099void HostResolverImpl::SetDefaultAddressFamily(AddressFamily address_family) {
[email protected]1ac6af92010-06-03 21:00:141100 DCHECK(CalledOnValidThread());
[email protected]0f8f1b432010-03-16 19:06:031101 ipv6_probe_monitoring_ = false;
1102 DiscardIPv6ProbeJob();
1103 default_address_family_ = address_family;
1104}
1105
[email protected]f7d310e2010-10-07 16:25:111106AddressFamily HostResolverImpl::GetDefaultAddressFamily() const {
1107 return default_address_family_;
1108}
1109
[email protected]0f8f1b432010-03-16 19:06:031110void HostResolverImpl::ProbeIPv6Support() {
[email protected]1ac6af92010-06-03 21:00:141111 DCHECK(CalledOnValidThread());
[email protected]0f8f1b432010-03-16 19:06:031112 DCHECK(!ipv6_probe_monitoring_);
1113 ipv6_probe_monitoring_ = true;
[email protected]61a86c42010-04-19 22:45:531114 OnIPAddressChanged(); // Give initial setup call.
[email protected]0f8f1b432010-03-16 19:06:031115}
1116
[email protected]b59ff372009-07-15 22:04:321117void HostResolverImpl::Shutdown() {
[email protected]1ac6af92010-06-03 21:00:141118 DCHECK(CalledOnValidThread());
[email protected]b59ff372009-07-15 22:04:321119
1120 // Cancel the outstanding jobs.
[email protected]ef4c40c2010-09-01 14:42:031121 CancelAllJobs();
[email protected]0a175512010-04-20 03:09:251122 DiscardIPv6ProbeJob();
[email protected]be5c6162010-07-27 21:12:511123
1124 shutdown_ = true;
[email protected]b59ff372009-07-15 22:04:321125}
1126
[email protected]68ad3ee2010-01-30 03:45:391127void HostResolverImpl::SetPoolConstraints(JobPoolIndex pool_index,
1128 size_t max_outstanding_jobs,
1129 size_t max_pending_requests) {
[email protected]1ac6af92010-06-03 21:00:141130 DCHECK(CalledOnValidThread());
[email protected]b1f031dd2010-03-02 23:19:331131 CHECK_GE(pool_index, 0);
1132 CHECK_LT(pool_index, POOL_COUNT);
[email protected]68ad3ee2010-01-30 03:45:391133 CHECK(jobs_.empty()) << "Can only set constraints during setup";
1134 JobPool* pool = job_pools_[pool_index];
1135 pool->SetConstraints(max_outstanding_jobs, max_pending_requests);
1136}
1137
[email protected]b59ff372009-07-15 22:04:321138void HostResolverImpl::AddOutstandingJob(Job* job) {
[email protected]123ab1e32009-10-21 19:12:571139 scoped_refptr<Job>& found_job = jobs_[job->key()];
[email protected]b59ff372009-07-15 22:04:321140 DCHECK(!found_job);
1141 found_job = job;
[email protected]68ad3ee2010-01-30 03:45:391142
1143 JobPool* pool = GetPoolForRequest(job->initial_request());
1144 pool->AdjustNumOutstandingJobs(1);
[email protected]b59ff372009-07-15 22:04:321145}
1146
[email protected]123ab1e32009-10-21 19:12:571147HostResolverImpl::Job* HostResolverImpl::FindOutstandingJob(const Key& key) {
1148 JobMap::iterator it = jobs_.find(key);
[email protected]b59ff372009-07-15 22:04:321149 if (it != jobs_.end())
1150 return it->second;
1151 return NULL;
1152}
1153
1154void HostResolverImpl::RemoveOutstandingJob(Job* job) {
[email protected]123ab1e32009-10-21 19:12:571155 JobMap::iterator it = jobs_.find(job->key());
[email protected]b59ff372009-07-15 22:04:321156 DCHECK(it != jobs_.end());
1157 DCHECK_EQ(it->second.get(), job);
1158 jobs_.erase(it);
[email protected]68ad3ee2010-01-30 03:45:391159
1160 JobPool* pool = GetPoolForRequest(job->initial_request());
1161 pool->AdjustNumOutstandingJobs(-1);
[email protected]b59ff372009-07-15 22:04:321162}
1163
1164void HostResolverImpl::OnJobComplete(Job* job,
[email protected]21526002010-05-16 19:42:461165 int net_error,
1166 int os_error,
[email protected]27f99c82009-10-29 22:21:001167 const AddressList& addrlist) {
[email protected]b59ff372009-07-15 22:04:321168 RemoveOutstandingJob(job);
1169
1170 // Write result to the cache.
[email protected]112bd462009-12-10 07:23:401171 if (cache_.get())
[email protected]21526002010-05-16 19:42:461172 cache_->Set(job->key(), net_error, addrlist, base::TimeTicks::Now());
[email protected]b59ff372009-07-15 22:04:321173
[email protected]ef4c40c2010-09-01 14:42:031174 OnJobCompleteInternal(job, net_error, os_error, addrlist);
1175}
1176
1177void HostResolverImpl::AbortJob(Job* job) {
1178 OnJobCompleteInternal(job, ERR_ABORTED, 0 /* no os_error */, AddressList());
1179}
1180
1181void HostResolverImpl::OnJobCompleteInternal(
1182 Job* job,
1183 int net_error,
1184 int os_error,
1185 const AddressList& addrlist) {
[email protected]b59ff372009-07-15 22:04:321186 // Make a note that we are executing within OnJobComplete() in case the
1187 // HostResolver is deleted by a callback invocation.
1188 DCHECK(!cur_completing_job_);
1189 cur_completing_job_ = job;
1190
[email protected]68ad3ee2010-01-30 03:45:391191 // Try to start any queued requests now that a job-slot has freed up.
1192 ProcessQueuedRequests();
1193
[email protected]b59ff372009-07-15 22:04:321194 // Complete all of the requests that were attached to the job.
1195 for (RequestsList::const_iterator it = job->requests().begin();
1196 it != job->requests().end(); ++it) {
1197 Request* req = *it;
1198 if (!req->was_cancelled()) {
1199 DCHECK_EQ(job, req->job());
[email protected]ee094b82010-08-24 15:55:511200 req->request_net_log().EndEvent(
1201 NetLog::TYPE_HOST_RESOLVER_IMPL_JOB_ATTACH, NULL);
[email protected]b59ff372009-07-15 22:04:321202
[email protected]9e743cd2010-03-16 07:03:531203 // Update the net log and notify registered observers.
[email protected]ee094b82010-08-24 15:55:511204 OnFinishRequest(req->source_net_log(), req->request_net_log(), req->id(),
1205 req->info(), net_error, os_error);
[email protected]b59ff372009-07-15 22:04:321206
[email protected]21526002010-05-16 19:42:461207 req->OnComplete(net_error, addrlist);
[email protected]b59ff372009-07-15 22:04:321208
1209 // Check if the job was cancelled as a result of running the callback.
1210 // (Meaning that |this| was deleted).
1211 if (job->was_cancelled())
1212 return;
1213 }
1214 }
1215
1216 cur_completing_job_ = NULL;
1217}
1218
[email protected]ee094b82010-08-24 15:55:511219void HostResolverImpl::OnStartRequest(const BoundNetLog& source_net_log,
1220 const BoundNetLog& request_net_log,
[email protected]54e13772009-08-14 03:01:091221 int request_id,
1222 const RequestInfo& info) {
[email protected]ee094b82010-08-24 15:55:511223 source_net_log.BeginEvent(
1224 NetLog::TYPE_HOST_RESOLVER_IMPL,
1225 new NetLogSourceParameter("source_dependency", request_net_log.source()));
1226
1227 request_net_log.BeginEvent(
1228 NetLog::TYPE_HOST_RESOLVER_IMPL_REQUEST,
1229 new RequestInfoParameters(info, source_net_log.source()));
[email protected]54e13772009-08-14 03:01:091230
1231 // Notify the observers of the start.
1232 if (!observers_.empty()) {
[email protected]54e13772009-08-14 03:01:091233 for (ObserversList::iterator it = observers_.begin();
1234 it != observers_.end(); ++it) {
1235 (*it)->OnStartResolution(request_id, info);
1236 }
[email protected]b59ff372009-07-15 22:04:321237 }
1238}
1239
[email protected]ee094b82010-08-24 15:55:511240void HostResolverImpl::OnFinishRequest(const BoundNetLog& source_net_log,
1241 const BoundNetLog& request_net_log,
[email protected]54e13772009-08-14 03:01:091242 int request_id,
1243 const RequestInfo& info,
[email protected]21526002010-05-16 19:42:461244 int net_error,
[email protected]ee094b82010-08-24 15:55:511245 int os_error) {
[email protected]21526002010-05-16 19:42:461246 bool was_resolved = net_error == OK;
1247
[email protected]54e13772009-08-14 03:01:091248 // Notify the observers of the completion.
1249 if (!observers_.empty()) {
[email protected]54e13772009-08-14 03:01:091250 for (ObserversList::iterator it = observers_.begin();
1251 it != observers_.end(); ++it) {
1252 (*it)->OnFinishResolutionWithStatus(request_id, was_resolved, info);
1253 }
[email protected]b59ff372009-07-15 22:04:321254 }
[email protected]54e13772009-08-14 03:01:091255
[email protected]ee094b82010-08-24 15:55:511256 // Log some extra parameters on failure for synchronous requests.
[email protected]21526002010-05-16 19:42:461257 scoped_refptr<NetLog::EventParameters> params;
[email protected]ee094b82010-08-24 15:55:511258 if (!was_resolved) {
1259 params = new HostResolveFailedParams(net_error, os_error);
1260 }
[email protected]21526002010-05-16 19:42:461261
[email protected]ee094b82010-08-24 15:55:511262 request_net_log.EndEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_REQUEST, params);
1263 source_net_log.EndEvent(NetLog::TYPE_HOST_RESOLVER_IMPL, NULL);
[email protected]b59ff372009-07-15 22:04:321264}
1265
[email protected]ee094b82010-08-24 15:55:511266void HostResolverImpl::OnCancelRequest(const BoundNetLog& source_net_log,
1267 const BoundNetLog& request_net_log,
[email protected]54e13772009-08-14 03:01:091268 int request_id,
1269 const RequestInfo& info) {
[email protected]ee094b82010-08-24 15:55:511270 request_net_log.AddEvent(NetLog::TYPE_CANCELLED, NULL);
[email protected]54e13772009-08-14 03:01:091271
1272 // Notify the observers of the cancellation.
1273 if (!observers_.empty()) {
[email protected]54e13772009-08-14 03:01:091274 for (ObserversList::iterator it = observers_.begin();
1275 it != observers_.end(); ++it) {
1276 (*it)->OnCancelResolution(request_id, info);
1277 }
[email protected]b59ff372009-07-15 22:04:321278 }
[email protected]54e13772009-08-14 03:01:091279
[email protected]ee094b82010-08-24 15:55:511280 request_net_log.EndEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_REQUEST, NULL);
1281 source_net_log.EndEvent(NetLog::TYPE_HOST_RESOLVER_IMPL, NULL);
[email protected]b59ff372009-07-15 22:04:321282}
1283
[email protected]61a86c42010-04-19 22:45:531284void HostResolverImpl::OnIPAddressChanged() {
[email protected]e95d3aca2010-01-11 22:47:431285 if (cache_.get())
1286 cache_->clear();
[email protected]0f8f1b432010-03-16 19:06:031287 if (ipv6_probe_monitoring_) {
[email protected]0a175512010-04-20 03:09:251288 DCHECK(!shutdown_);
1289 if (shutdown_)
1290 return;
[email protected]0f8f1b432010-03-16 19:06:031291 DiscardIPv6ProbeJob();
1292 ipv6_probe_job_ = new IPv6ProbeJob(this);
1293 ipv6_probe_job_->Start();
1294 }
[email protected]2f3bc65c2010-07-23 17:47:101295#if defined(OS_LINUX)
1296 if (HaveOnlyLoopbackAddresses()) {
1297 additional_resolver_flags_ |= HOST_RESOLVER_LOOPBACK_ONLY;
1298 } else {
1299 additional_resolver_flags_ &= ~HOST_RESOLVER_LOOPBACK_ONLY;
1300 }
1301#endif
[email protected]35ddc282010-09-21 23:42:061302 AbortAllInProgressJobs();
1303 // |this| may be deleted inside AbortAllInProgressJobs().
[email protected]0f8f1b432010-03-16 19:06:031304}
1305
1306void HostResolverImpl::DiscardIPv6ProbeJob() {
1307 if (ipv6_probe_job_.get()) {
1308 ipv6_probe_job_->Cancel();
1309 ipv6_probe_job_ = NULL;
1310 }
1311}
1312
1313void HostResolverImpl::IPv6ProbeSetDefaultAddressFamily(
1314 AddressFamily address_family) {
1315 DCHECK(address_family == ADDRESS_FAMILY_UNSPECIFIED ||
1316 address_family == ADDRESS_FAMILY_IPV4);
[email protected]f092e64b2010-03-17 00:39:181317 if (default_address_family_ != address_family) {
1318 LOG(INFO) << "IPv6Probe forced AddressFamily setting to "
1319 << ((address_family == ADDRESS_FAMILY_UNSPECIFIED)
1320 ? "ADDRESS_FAMILY_UNSPECIFIED"
1321 : "ADDRESS_FAMILY_IPV4");
1322 }
[email protected]0f8f1b432010-03-16 19:06:031323 default_address_family_ = address_family;
1324 // Drop reference since the job has called us back.
1325 DiscardIPv6ProbeJob();
[email protected]e95d3aca2010-01-11 22:47:431326}
1327
[email protected]68ad3ee2010-01-30 03:45:391328// static
1329HostResolverImpl::JobPoolIndex HostResolverImpl::GetJobPoolIndexForRequest(
1330 const Request* req) {
1331 return POOL_NORMAL;
1332}
1333
1334bool HostResolverImpl::CanCreateJobForPool(const JobPool& pool) const {
1335 DCHECK_LE(jobs_.size(), max_jobs_);
1336
1337 // We can't create another job if it would exceed the global total.
1338 if (jobs_.size() + 1 > max_jobs_)
1339 return false;
1340
1341 // Check whether the pool's constraints are met.
1342 return pool.CanCreateJob();
1343}
1344
1345void HostResolverImpl::ProcessQueuedRequests() {
1346 // Find the highest priority request that can be scheduled.
1347 Request* top_req = NULL;
1348 for (size_t i = 0; i < arraysize(job_pools_); ++i) {
1349 JobPool* pool = job_pools_[i];
1350 if (pool->HasPendingRequests() && CanCreateJobForPool(*pool)) {
1351 top_req = pool->RemoveTopPendingRequest();
1352 break;
1353 }
1354 }
1355
1356 if (!top_req)
1357 return;
1358
1359 scoped_refptr<Job> job = CreateAndStartJob(top_req);
1360
1361 // Search for any other pending request which can piggy-back off this job.
1362 for (size_t pool_i = 0; pool_i < POOL_COUNT; ++pool_i) {
1363 JobPool* pool = job_pools_[pool_i];
1364 pool->MoveRequestsToJob(job);
1365 }
1366}
1367
[email protected]137af622010-02-05 02:14:351368HostResolverImpl::Key HostResolverImpl::GetEffectiveKeyForRequest(
1369 const RequestInfo& info) const {
[email protected]eaf3a3b2010-09-03 20:34:271370 HostResolverFlags effective_flags =
1371 info.host_resolver_flags() | additional_resolver_flags_;
[email protected]137af622010-02-05 02:14:351372 AddressFamily effective_address_family = info.address_family();
[email protected]eaf3a3b2010-09-03 20:34:271373 if (effective_address_family == ADDRESS_FAMILY_UNSPECIFIED &&
1374 default_address_family_ != ADDRESS_FAMILY_UNSPECIFIED) {
[email protected]137af622010-02-05 02:14:351375 effective_address_family = default_address_family_;
[email protected]eaf3a3b2010-09-03 20:34:271376 if (ipv6_probe_monitoring_)
1377 effective_flags |= HOST_RESOLVER_DEFAULT_FAMILY_SET_DUE_TO_NO_IPV6;
1378 }
1379 return Key(info.hostname(), effective_address_family, effective_flags);
[email protected]137af622010-02-05 02:14:351380}
1381
[email protected]68ad3ee2010-01-30 03:45:391382HostResolverImpl::Job* HostResolverImpl::CreateAndStartJob(Request* req) {
1383 DCHECK(CanCreateJobForPool(*GetPoolForRequest(req)));
[email protected]137af622010-02-05 02:14:351384 Key key = GetEffectiveKeyForRequest(req->info());
[email protected]ee094b82010-08-24 15:55:511385
1386 req->request_net_log().AddEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_CREATE_JOB,
1387 NULL);
1388
1389 scoped_refptr<Job> job = new Job(next_job_id_++, this, key,
1390 req->request_net_log(), net_log_);
[email protected]68ad3ee2010-01-30 03:45:391391 job->AddRequest(req);
1392 AddOutstandingJob(job);
1393 job->Start();
[email protected]ee094b82010-08-24 15:55:511394
[email protected]68ad3ee2010-01-30 03:45:391395 return job.get();
1396}
1397
1398int HostResolverImpl::EnqueueRequest(JobPool* pool, Request* req) {
1399 scoped_ptr<Request> req_evicted_from_queue(
1400 pool->InsertPendingRequest(req));
1401
1402 // If the queue has become too large, we need to kick something out.
1403 if (req_evicted_from_queue.get()) {
1404 Request* r = req_evicted_from_queue.get();
1405 int error = ERR_HOST_RESOLVER_QUEUE_TOO_LARGE;
1406
[email protected]ee094b82010-08-24 15:55:511407 OnFinishRequest(r->source_net_log(), r->request_net_log(), r->id(),
1408 r->info(), error,
1409 0 /* os_error (not applicable) */);
[email protected]68ad3ee2010-01-30 03:45:391410
1411 if (r == req)
1412 return error;
1413
1414 r->OnComplete(error, AddressList());
1415 }
1416
1417 return ERR_IO_PENDING;
1418}
1419
[email protected]ef4c40c2010-09-01 14:42:031420void HostResolverImpl::CancelAllJobs() {
1421 JobMap jobs;
1422 jobs.swap(jobs_);
1423 for (JobMap::iterator it = jobs.begin(); it != jobs.end(); ++it)
1424 it->second->Cancel();
1425}
1426
[email protected]35ddc282010-09-21 23:42:061427void HostResolverImpl::AbortAllInProgressJobs() {
1428 for (size_t i = 0; i < arraysize(job_pools_); ++i)
1429 job_pools_[i]->ResetNumOutstandingJobs();
[email protected]ef4c40c2010-09-01 14:42:031430 JobMap jobs;
1431 jobs.swap(jobs_);
1432 for (JobMap::iterator it = jobs.begin(); it != jobs.end(); ++it) {
1433 AbortJob(it->second);
1434 it->second->Cancel();
1435 }
1436}
1437
[email protected]b59ff372009-07-15 22:04:321438} // namespace net