blob: 246f50a4a199dc51c0ae2d2a3532ba9dd144f8e4 [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]58580352010-10-26 04:07:5019#include "base/debug/debugger.h"
20#include "base/debug/stack_trace.h"
[email protected]f2d8c4212010-02-02 00:56:3521#include "base/lock.h"
[email protected]b59ff372009-07-15 22:04:3222#include "base/message_loop.h"
[email protected]1e9bbd22010-10-15 16:42:4523#include "base/metrics/field_trial.h"
[email protected]835d7c82010-10-14 04:38:3824#include "base/metrics/histogram.h"
[email protected]b59ff372009-07-15 22:04:3225#include "base/stl_util-inl.h"
26#include "base/string_util.h"
27#include "base/time.h"
[email protected]ccaff652010-07-31 06:28:2028#include "base/utf_string_conversions.h"
[email protected]21526002010-05-16 19:42:4629#include "base/values.h"
[email protected]b59ff372009-07-15 22:04:3230#include "base/worker_pool.h"
31#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]24f4bab2010-10-15 01:27:1147// We use a separate histogram name for each platform to facilitate the
48// display of error codes by their symbolic name (since each platform has
49// different mappings).
50const char kOSErrorsForGetAddrinfoHistogramName[] =
51#if defined(OS_WIN)
52 "Net.OSErrorsForGetAddrinfo_Win";
53#elif defined(OS_MACOSX)
54 "Net.OSErrorsForGetAddrinfo_Mac";
55#elif defined(OS_LINUX)
56 "Net.OSErrorsForGetAddrinfo_Linux";
57#else
58 "Net.OSErrorsForGetAddrinfo";
59#endif
60
[email protected]e95d3aca2010-01-11 22:47:4361HostCache* CreateDefaultCache() {
[email protected]b59ff372009-07-15 22:04:3262 static const size_t kMaxHostCacheEntries = 100;
[email protected]112bd462009-12-10 07:23:4063
64 HostCache* cache = new HostCache(
65 kMaxHostCacheEntries,
66 base::TimeDelta::FromMinutes(1),
[email protected]72bceac2010-06-17 21:45:0867 base::TimeDelta::FromSeconds(0)); // Disable caching of failed DNS.
[email protected]112bd462009-12-10 07:23:4068
[email protected]e95d3aca2010-01-11 22:47:4369 return cache;
70}
71
72} // anonymous namespace
73
[email protected]ee094b82010-08-24 15:55:5174HostResolver* CreateSystemHostResolver(size_t max_concurrent_resolves,
75 NetLog* net_log) {
[email protected]68ad3ee2010-01-30 03:45:3976 // Maximum of 50 concurrent threads.
77 // TODO(eroman): Adjust this, do some A/B experiments.
[email protected]962b98212010-07-17 03:37:5178 static const size_t kDefaultMaxJobs = 50u;
79
80 if (max_concurrent_resolves == HostResolver::kDefaultParallelism)
81 max_concurrent_resolves = kDefaultMaxJobs;
[email protected]68ad3ee2010-01-30 03:45:3982
[email protected]66761b952010-06-25 21:30:3883 HostResolverImpl* resolver =
[email protected]962b98212010-07-17 03:37:5184 new HostResolverImpl(NULL, CreateDefaultCache(),
[email protected]ee094b82010-08-24 15:55:5185 max_concurrent_resolves, net_log);
[email protected]68ad3ee2010-01-30 03:45:3986
87 return resolver;
[email protected]b59ff372009-07-15 22:04:3288}
89
90static int ResolveAddrInfo(HostResolverProc* resolver_proc,
[email protected]123ab1e32009-10-21 19:12:5791 const std::string& host,
92 AddressFamily address_family,
[email protected]5ea28dea2010-04-08 15:35:1393 HostResolverFlags host_resolver_flags,
[email protected]21526002010-05-16 19:42:4694 AddressList* out,
95 int* os_error) {
[email protected]b59ff372009-07-15 22:04:3296 if (resolver_proc) {
97 // Use the custom procedure.
[email protected]5ea28dea2010-04-08 15:35:1398 return resolver_proc->Resolve(host, address_family,
[email protected]21526002010-05-16 19:42:4699 host_resolver_flags, out, os_error);
[email protected]b59ff372009-07-15 22:04:32100 } else {
101 // Use the system procedure (getaddrinfo).
[email protected]5ea28dea2010-04-08 15:35:13102 return SystemHostResolverProc(host, address_family,
[email protected]21526002010-05-16 19:42:46103 host_resolver_flags, out, os_error);
[email protected]b59ff372009-07-15 22:04:32104 }
105}
106
[email protected]21526002010-05-16 19:42:46107// Extra parameters to attach to the NetLog when the resolve failed.
108class HostResolveFailedParams : public NetLog::EventParameters {
109 public:
[email protected]ee094b82010-08-24 15:55:51110 HostResolveFailedParams(int net_error, int os_error)
[email protected]21526002010-05-16 19:42:46111 : net_error_(net_error),
[email protected]ee094b82010-08-24 15:55:51112 os_error_(os_error) {
[email protected]21526002010-05-16 19:42:46113 }
114
115 virtual Value* ToValue() const {
116 DictionaryValue* dict = new DictionaryValue();
[email protected]ccaff652010-07-31 06:28:20117 dict->SetInteger("net_error", net_error_);
[email protected]21526002010-05-16 19:42:46118
119 if (os_error_) {
[email protected]ccaff652010-07-31 06:28:20120 dict->SetInteger("os_error", os_error_);
[email protected]21526002010-05-16 19:42:46121#if defined(OS_POSIX)
[email protected]ccaff652010-07-31 06:28:20122 dict->SetString("os_error_string", gai_strerror(os_error_));
[email protected]21526002010-05-16 19:42:46123#elif defined(OS_WIN)
124 // Map the error code to a human-readable string.
125 LPWSTR error_string = NULL;
126 int size = FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
127 FORMAT_MESSAGE_FROM_SYSTEM,
128 0, // Use the internal message table.
129 os_error_,
130 0, // Use default language.
131 (LPWSTR)&error_string,
132 0, // Buffer size.
133 0); // Arguments (unused).
[email protected]ccaff652010-07-31 06:28:20134 dict->SetString("os_error_string", WideToUTF8(error_string));
[email protected]21526002010-05-16 19:42:46135 LocalFree(error_string);
136#endif
137 }
138
139 return dict;
140 }
141
142 private:
143 const int net_error_;
144 const int os_error_;
[email protected]ee094b82010-08-24 15:55:51145};
146
147// Parameters representing the information in a RequestInfo object, along with
148// the associated NetLog::Source.
149class RequestInfoParameters : public NetLog::EventParameters {
150 public:
151 RequestInfoParameters(const HostResolver::RequestInfo& info,
152 const NetLog::Source& source)
153 : info_(info), source_(source) {}
154
155 virtual Value* ToValue() const {
156 DictionaryValue* dict = new DictionaryValue();
[email protected]930cc742010-09-15 22:54:10157 dict->SetString("host", info_.host_port_pair().ToString());
[email protected]ee094b82010-08-24 15:55:51158 dict->SetInteger("address_family",
159 static_cast<int>(info_.address_family()));
160 dict->SetBoolean("allow_cached_response", info_.allow_cached_response());
161 dict->SetBoolean("is_speculative", info_.is_speculative());
162 dict->SetInteger("priority", info_.priority());
163
164 if (source_.is_valid())
165 dict->Set("source_dependency", source_.ToValue());
166
167 return dict;
168 }
169
170 private:
171 const HostResolver::RequestInfo info_;
172 const NetLog::Source source_;
173};
174
175// Parameters associated with the creation of a HostResolveImpl::Job.
176class JobCreationParameters : public NetLog::EventParameters {
177 public:
178 JobCreationParameters(const std::string& host, const NetLog::Source& source)
179 : host_(host), source_(source) {}
180
181 virtual Value* ToValue() const {
182 DictionaryValue* dict = new DictionaryValue();
183 dict->SetString("host", host_);
184 dict->Set("source_dependency", source_.ToValue());
185 return dict;
186 }
187
188 private:
189 const std::string host_;
190 const NetLog::Source source_;
[email protected]21526002010-05-16 19:42:46191};
192
193// Gets a list of the likely error codes that getaddrinfo() can return
194// (non-exhaustive). These are the error codes that we will track via
195// a histogram.
196std::vector<int> GetAllGetAddrinfoOSErrors() {
197 int os_errors[] = {
198#if defined(OS_POSIX)
199 EAI_ADDRFAMILY,
200 EAI_AGAIN,
201 EAI_BADFLAGS,
202 EAI_FAIL,
203 EAI_FAMILY,
204 EAI_MEMORY,
205 EAI_NODATA,
206 EAI_NONAME,
207 EAI_SERVICE,
208 EAI_SOCKTYPE,
209 EAI_SYSTEM,
210#elif defined(OS_WIN)
211 // See: http://msdn.microsoft.com/en-us/library/ms738520(VS.85).aspx
212 WSA_NOT_ENOUGH_MEMORY,
213 WSAEAFNOSUPPORT,
214 WSAEINVAL,
215 WSAESOCKTNOSUPPORT,
216 WSAHOST_NOT_FOUND,
217 WSANO_DATA,
218 WSANO_RECOVERY,
219 WSANOTINITIALISED,
220 WSATRY_AGAIN,
221 WSATYPE_NOT_FOUND,
[email protected]1e9bbd22010-10-15 16:42:45222 // The following are not in doc, but might be to appearing in results :-(.
223 WSA_INVALID_HANDLE,
[email protected]21526002010-05-16 19:42:46224#endif
225 };
226
227 // Histogram enumerations require positive numbers.
228 std::vector<int> errors;
229 for (size_t i = 0; i < arraysize(os_errors); ++i) {
230 errors.push_back(std::abs(os_errors[i]));
231 // Also add N+1 for each error, so the bucket that contains our expected
232 // error is of size 1. That way if we get unexpected error codes, they
233 // won't fall into the same buckets as the expected ones.
234 errors.push_back(std::abs(os_errors[i]) + 1);
235 }
236 return errors;
237}
238
[email protected]b59ff372009-07-15 22:04:32239//-----------------------------------------------------------------------------
240
241class HostResolverImpl::Request {
242 public:
[email protected]ee094b82010-08-24 15:55:51243 Request(const BoundNetLog& source_net_log,
244 const BoundNetLog& request_net_log,
[email protected]54e13772009-08-14 03:01:09245 int id,
246 const RequestInfo& info,
247 CompletionCallback* callback,
[email protected]b59ff372009-07-15 22:04:32248 AddressList* addresses)
[email protected]ee094b82010-08-24 15:55:51249 : source_net_log_(source_net_log),
250 request_net_log_(request_net_log),
[email protected]54e13772009-08-14 03:01:09251 id_(id),
252 info_(info),
253 job_(NULL),
254 callback_(callback),
255 addresses_(addresses) {
256 }
[email protected]b59ff372009-07-15 22:04:32257
258 // Mark the request as cancelled.
259 void MarkAsCancelled() {
260 job_ = NULL;
261 callback_ = NULL;
262 addresses_ = NULL;
263 }
264
265 bool was_cancelled() const {
266 return callback_ == NULL;
267 }
268
269 void set_job(Job* job) {
270 DCHECK(job != NULL);
271 // Identify which job the request is waiting on.
272 job_ = job;
273 }
274
275 void OnComplete(int error, const AddressList& addrlist) {
276 if (error == OK)
277 addresses_->SetFrom(addrlist, port());
[email protected]ef4c40c2010-09-01 14:42:03278 CompletionCallback* callback = callback_;
279 MarkAsCancelled();
280 callback->Run(error);
[email protected]b59ff372009-07-15 22:04:32281 }
282
283 int port() const {
284 return info_.port();
285 }
286
287 Job* job() const {
288 return job_;
289 }
290
[email protected]ee094b82010-08-24 15:55:51291 const BoundNetLog& source_net_log() {
292 return source_net_log_;
293 }
294
295 const BoundNetLog& request_net_log() {
296 return request_net_log_;
[email protected]54e13772009-08-14 03:01:09297 }
298
[email protected]b59ff372009-07-15 22:04:32299 int id() const {
300 return id_;
301 }
302
303 const RequestInfo& info() const {
304 return info_;
305 }
306
307 private:
[email protected]ee094b82010-08-24 15:55:51308 BoundNetLog source_net_log_;
309 BoundNetLog request_net_log_;
[email protected]54e13772009-08-14 03:01:09310
[email protected]b59ff372009-07-15 22:04:32311 // Unique ID for this request. Used by observers to identify requests.
312 int id_;
313
314 // The request info that started the request.
315 RequestInfo info_;
316
317 // The resolve job (running in worker pool) that this request is dependent on.
318 Job* job_;
319
320 // The user's callback to invoke when the request completes.
321 CompletionCallback* callback_;
322
323 // The address list to save result into.
324 AddressList* addresses_;
325
326 DISALLOW_COPY_AND_ASSIGN(Request);
327};
328
[email protected]1e9bbd22010-10-15 16:42:45329//------------------------------------------------------------------------------
330
331// Provide a common macro to simplify code and readability. We must use a
332// macros as the underlying HISTOGRAM macro creates static varibles.
333#define DNS_HISTOGRAM(name, time) UMA_HISTOGRAM_CUSTOM_TIMES(name, time, \
334 base::TimeDelta::FromMicroseconds(1), base::TimeDelta::FromHours(1), 100)
[email protected]b59ff372009-07-15 22:04:32335
336// This class represents a request to the worker pool for a "getaddrinfo()"
337// call.
338class HostResolverImpl::Job
339 : public base::RefCountedThreadSafe<HostResolverImpl::Job> {
340 public:
[email protected]ee094b82010-08-24 15:55:51341 Job(int id,
342 HostResolverImpl* resolver,
343 const Key& key,
344 const BoundNetLog& source_net_log,
345 NetLog* net_log)
346 : id_(id),
347 key_(key),
348 resolver_(resolver),
349 origin_loop_(MessageLoop::current()),
350 resolver_proc_(resolver->effective_resolver_proc()),
351 error_(OK),
352 os_error_(0),
353 had_non_speculative_request_(false),
354 net_log_(BoundNetLog::Make(net_log,
355 NetLog::SOURCE_HOST_RESOLVER_IMPL_JOB)) {
356 net_log_.BeginEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_JOB,
357 new JobCreationParameters(key.hostname,
358 source_net_log.source()));
[email protected]b59ff372009-07-15 22:04:32359 }
360
[email protected]b59ff372009-07-15 22:04:32361 // Attaches a request to this job. The job takes ownership of |req| and will
362 // take care to delete it.
363 void AddRequest(Request* req) {
[email protected]ee094b82010-08-24 15:55:51364 req->request_net_log().BeginEvent(
365 NetLog::TYPE_HOST_RESOLVER_IMPL_JOB_ATTACH,
366 new NetLogSourceParameter("source_dependency", net_log_.source()));
367
[email protected]b59ff372009-07-15 22:04:32368 req->set_job(this);
369 requests_.push_back(req);
[email protected]252b699b2010-02-05 21:38:06370
371 if (!req->info().is_speculative())
372 had_non_speculative_request_ = true;
[email protected]b59ff372009-07-15 22:04:32373 }
374
375 // Called from origin loop.
376 void Start() {
[email protected]252b699b2010-02-05 21:38:06377 start_time_ = base::TimeTicks::Now();
378
[email protected]b59ff372009-07-15 22:04:32379 // Dispatch the job to a worker thread.
380 if (!WorkerPool::PostTask(FROM_HERE,
381 NewRunnableMethod(this, &Job::DoLookup), true)) {
382 NOTREACHED();
383
384 // Since we could be running within Resolve() right now, we can't just
385 // call OnLookupComplete(). Instead we must wait until Resolve() has
386 // returned (IO_PENDING).
387 error_ = ERR_UNEXPECTED;
388 MessageLoop::current()->PostTask(
389 FROM_HERE, NewRunnableMethod(this, &Job::OnLookupComplete));
390 }
391 }
392
393 // Cancels the current job. Callable from origin thread.
394 void Cancel() {
[email protected]ee094b82010-08-24 15:55:51395 net_log_.AddEvent(NetLog::TYPE_CANCELLED, NULL);
396
[email protected]b59ff372009-07-15 22:04:32397 HostResolver* resolver = resolver_;
398 resolver_ = NULL;
399
400 // Mark the job as cancelled, so when worker thread completes it will
401 // not try to post completion to origin loop.
402 {
403 AutoLock locked(origin_loop_lock_);
404 origin_loop_ = NULL;
405 }
406
[email protected]ee094b82010-08-24 15:55:51407 // End here to prevent issues when a Job outlives the HostResolver that
408 // spawned it.
409 net_log_.EndEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_JOB, NULL);
410
[email protected]1877a2212009-09-18 21:09:26411 // We will call HostResolverImpl::CancelRequest(Request*) on each one
[email protected]27f99c82009-10-29 22:21:00412 // in order to notify any observers.
[email protected]b59ff372009-07-15 22:04:32413 for (RequestsList::const_iterator it = requests_.begin();
414 it != requests_.end(); ++it) {
415 HostResolverImpl::Request* req = *it;
416 if (!req->was_cancelled())
417 resolver->CancelRequest(req);
418 }
419 }
420
421 // Called from origin thread.
422 bool was_cancelled() const {
423 return resolver_ == NULL;
424 }
425
426 // Called from origin thread.
[email protected]123ab1e32009-10-21 19:12:57427 const Key& key() const {
428 return key_;
[email protected]b59ff372009-07-15 22:04:32429 }
430
[email protected]a2fbebe2010-02-05 01:40:12431 int id() const {
432 return id_;
433 }
434
[email protected]252b699b2010-02-05 21:38:06435 base::TimeTicks start_time() const {
436 return start_time_;
437 }
438
[email protected]b59ff372009-07-15 22:04:32439 // Called from origin thread.
440 const RequestsList& requests() const {
441 return requests_;
442 }
443
[email protected]68ad3ee2010-01-30 03:45:39444 // Returns the first request attached to the job.
445 const Request* initial_request() const {
446 DCHECK_EQ(origin_loop_, MessageLoop::current());
447 DCHECK(!requests_.empty());
448 return requests_[0];
449 }
450
[email protected]137af622010-02-05 02:14:35451 // Returns true if |req_info| can be fulfilled by this job.
452 bool CanServiceRequest(const RequestInfo& req_info) const {
453 return key_ == resolver_->GetEffectiveKeyForRequest(req_info);
454 }
455
[email protected]b59ff372009-07-15 22:04:32456 private:
[email protected]5389bc72009-11-05 23:34:24457 friend class base::RefCountedThreadSafe<HostResolverImpl::Job>;
458
459 ~Job() {
460 // Free the requests attached to this job.
461 STLDeleteElements(&requests_);
462 }
463
[email protected]6c710ee2010-05-07 07:51:16464 // WARNING: This code runs inside a worker pool. The shutdown code cannot
465 // wait for it to finish, so we must be very careful here about using other
466 // objects (like MessageLoops, Singletons, etc). During shutdown these objects
467 // may no longer exist.
[email protected]b59ff372009-07-15 22:04:32468 void DoLookup() {
469 // Running on the worker thread
[email protected]123ab1e32009-10-21 19:12:57470 error_ = ResolveAddrInfo(resolver_proc_,
471 key_.hostname,
472 key_.address_family,
[email protected]5ea28dea2010-04-08 15:35:13473 key_.host_resolver_flags,
[email protected]21526002010-05-16 19:42:46474 &results_,
475 &os_error_);
[email protected]b59ff372009-07-15 22:04:32476
[email protected]b59ff372009-07-15 22:04:32477 // The origin loop could go away while we are trying to post to it, so we
478 // need to call its PostTask method inside a lock. See ~HostResolver.
479 {
480 AutoLock locked(origin_loop_lock_);
481 if (origin_loop_) {
[email protected]6c710ee2010-05-07 07:51:16482 origin_loop_->PostTask(FROM_HERE,
483 NewRunnableMethod(this, &Job::OnLookupComplete));
[email protected]b59ff372009-07-15 22:04:32484 }
485 }
[email protected]b59ff372009-07-15 22:04:32486 }
487
488 // Callback for when DoLookup() completes (runs on origin thread).
489 void OnLookupComplete() {
490 // Should be running on origin loop.
491 // TODO(eroman): this is being hit by URLRequestTest.CancelTest*,
492 // because MessageLoop::current() == NULL.
493 //DCHECK_EQ(origin_loop_, MessageLoop::current());
494 DCHECK(error_ || results_.head());
495
[email protected]2d3b7762010-10-09 00:35:47496 // Ideally the following code would be part of host_resolver_proc.cc,
497 // however it isn't safe to call NetworkChangeNotifier from worker
498 // threads. So we do it here on the IO thread instead.
[email protected]8ed0cab62010-10-15 04:12:45499 if (error_ != OK && NetworkChangeNotifier::IsOffline())
[email protected]2d3b7762010-10-09 00:35:47500 error_ = ERR_INTERNET_DISCONNECTED;
501
[email protected]1e9bbd22010-10-15 16:42:45502 RecordPerformanceHistograms();
[email protected]f2d8c4212010-02-02 00:56:35503
[email protected]b59ff372009-07-15 22:04:32504 if (was_cancelled())
505 return;
506
[email protected]ee094b82010-08-24 15:55:51507 scoped_refptr<NetLog::EventParameters> params;
508 if (error_ != OK) {
509 params = new HostResolveFailedParams(error_, os_error_);
510 } else {
511 params = new AddressListNetLogParam(results_);
512 }
513
514 // End here to prevent issues when a Job outlives the HostResolver that
515 // spawned it.
516 net_log_.EndEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_JOB, params);
517
[email protected]b59ff372009-07-15 22:04:32518 DCHECK(!requests_.empty());
519
520 // Use the port number of the first request.
521 if (error_ == OK)
522 results_.SetPort(requests_[0]->port());
523
[email protected]21526002010-05-16 19:42:46524 resolver_->OnJobComplete(this, error_, os_error_, results_);
[email protected]b59ff372009-07-15 22:04:32525 }
526
[email protected]1e9bbd22010-10-15 16:42:45527 void RecordPerformanceHistograms() const {
528 enum Category { // Used in HISTOGRAM_ENUMERATION.
529 RESOLVE_SUCCESS,
530 RESOLVE_FAIL,
531 RESOLVE_SPECULATIVE_SUCCESS,
532 RESOLVE_SPECULATIVE_FAIL,
533 RESOLVE_MAX, // Bounding value.
534 };
535 int category = RESOLVE_MAX; // Illegal value for later DCHECK only.
536
537 base::TimeDelta duration = base::TimeTicks::Now() - start_time_;
538 if (error_ == OK) {
539 if (had_non_speculative_request_) {
540 category = RESOLVE_SUCCESS;
541 DNS_HISTOGRAM("DNS.ResolveSuccess", duration);
542 } else {
543 category = RESOLVE_SPECULATIVE_SUCCESS;
544 DNS_HISTOGRAM("DNS.ResolveSpeculativeSuccess", duration);
545 }
546 } else {
547 if (had_non_speculative_request_) {
548 category = RESOLVE_FAIL;
549 DNS_HISTOGRAM("DNS.ResolveFail", duration);
550 } else {
551 category = RESOLVE_SPECULATIVE_FAIL;
552 DNS_HISTOGRAM("DNS.ResolveSpeculativeFail", duration);
553 }
[email protected]c833e322010-10-16 23:51:36554 UMA_HISTOGRAM_CUSTOM_ENUMERATION(kOSErrorsForGetAddrinfoHistogramName,
[email protected]1e9bbd22010-10-15 16:42:45555 std::abs(os_error_),
556 GetAllGetAddrinfoOSErrors());
557 }
[email protected]051b6ab2010-10-18 16:50:46558 DCHECK_LT(category, static_cast<int>(RESOLVE_MAX)); // Be sure it was set.
[email protected]1e9bbd22010-10-15 16:42:45559
560 UMA_HISTOGRAM_ENUMERATION("DNS.ResolveCategory", category, RESOLVE_MAX);
561
[email protected]ecd95ae2010-10-20 23:58:17562 static bool show_speculative_experiment_histograms =
[email protected]1e9bbd22010-10-15 16:42:45563 base::FieldTrialList::Find("DnsImpact") &&
564 !base::FieldTrialList::Find("DnsImpact")->group_name().empty();
[email protected]ecd95ae2010-10-20 23:58:17565 if (show_speculative_experiment_histograms) {
[email protected]1e9bbd22010-10-15 16:42:45566 UMA_HISTOGRAM_ENUMERATION(
567 base::FieldTrial::MakeName("DNS.ResolveCategory", "DnsImpact"),
568 category, RESOLVE_MAX);
569 if (RESOLVE_SUCCESS == category) {
570 DNS_HISTOGRAM(base::FieldTrial::MakeName("DNS.ResolveSuccess",
571 "DnsImpact"), duration);
572 }
573 }
[email protected]ecd95ae2010-10-20 23:58:17574 static bool show_parallelism_experiment_histograms =
575 base::FieldTrialList::Find("DnsParallelism") &&
576 !base::FieldTrialList::Find("DnsParallelism")->group_name().empty();
577 if (show_parallelism_experiment_histograms) {
578 UMA_HISTOGRAM_ENUMERATION(
579 base::FieldTrial::MakeName("DNS.ResolveCategory", "DnsParallelism"),
580 category, RESOLVE_MAX);
581 if (RESOLVE_SUCCESS == category) {
582 DNS_HISTOGRAM(base::FieldTrial::MakeName("DNS.ResolveSuccess",
583 "DnsParallelism"), duration);
584 }
585 }
[email protected]1e9bbd22010-10-15 16:42:45586 }
587
588
589
[email protected]f2d8c4212010-02-02 00:56:35590 // Immutable. Can be read from either thread,
591 const int id_;
592
[email protected]b59ff372009-07-15 22:04:32593 // Set on the origin thread, read on the worker thread.
[email protected]123ab1e32009-10-21 19:12:57594 Key key_;
[email protected]b59ff372009-07-15 22:04:32595
596 // Only used on the origin thread (where Resolve was called).
597 HostResolverImpl* resolver_;
598 RequestsList requests_; // The requests waiting on this job.
599
600 // Used to post ourselves onto the origin thread.
601 Lock origin_loop_lock_;
602 MessageLoop* origin_loop_;
603
604 // Hold an owning reference to the HostResolverProc that we are going to use.
605 // This may not be the current resolver procedure by the time we call
606 // ResolveAddrInfo, but that's OK... we'll use it anyways, and the owning
607 // reference ensures that it remains valid until we are done.
608 scoped_refptr<HostResolverProc> resolver_proc_;
609
610 // Assigned on the worker thread, read on the origin thread.
611 int error_;
[email protected]21526002010-05-16 19:42:46612 int os_error_;
[email protected]252b699b2010-02-05 21:38:06613
614 // True if a non-speculative request was ever attached to this job
615 // (regardless of whether or not it was later cancelled.
616 // This boolean is used for histogramming the duration of jobs used to
617 // service non-speculative requests.
618 bool had_non_speculative_request_;
619
[email protected]b59ff372009-07-15 22:04:32620 AddressList results_;
621
[email protected]252b699b2010-02-05 21:38:06622 // The time when the job was started.
623 base::TimeTicks start_time_;
624
[email protected]ee094b82010-08-24 15:55:51625 BoundNetLog net_log_;
626
[email protected]b59ff372009-07-15 22:04:32627 DISALLOW_COPY_AND_ASSIGN(Job);
628};
629
630//-----------------------------------------------------------------------------
631
[email protected]0f8f1b432010-03-16 19:06:03632// This class represents a request to the worker pool for a "probe for IPv6
633// support" call.
634class HostResolverImpl::IPv6ProbeJob
635 : public base::RefCountedThreadSafe<HostResolverImpl::IPv6ProbeJob> {
636 public:
637 explicit IPv6ProbeJob(HostResolverImpl* resolver)
638 : resolver_(resolver),
639 origin_loop_(MessageLoop::current()) {
[email protected]a9af7112010-05-08 00:56:01640 DCHECK(!was_cancelled());
[email protected]0f8f1b432010-03-16 19:06:03641 }
642
643 void Start() {
[email protected]a9af7112010-05-08 00:56:01644 if (was_cancelled())
645 return;
[email protected]0f8f1b432010-03-16 19:06:03646 DCHECK(IsOnOriginThread());
[email protected]f092e64b2010-03-17 00:39:18647 const bool kIsSlow = true;
[email protected]0f8f1b432010-03-16 19:06:03648 WorkerPool::PostTask(
[email protected]f092e64b2010-03-17 00:39:18649 FROM_HERE, NewRunnableMethod(this, &IPv6ProbeJob::DoProbe), kIsSlow);
[email protected]0f8f1b432010-03-16 19:06:03650 }
651
652 // Cancels the current job.
653 void Cancel() {
[email protected]a9af7112010-05-08 00:56:01654 if (was_cancelled())
655 return;
[email protected]0f8f1b432010-03-16 19:06:03656 DCHECK(IsOnOriginThread());
657 resolver_ = NULL; // Read/write ONLY on origin thread.
658 {
659 AutoLock locked(origin_loop_lock_);
660 // Origin loop may be destroyed before we can use it!
[email protected]a9af7112010-05-08 00:56:01661 origin_loop_ = NULL; // Write ONLY on origin thread.
[email protected]0f8f1b432010-03-16 19:06:03662 }
663 }
664
[email protected]0f8f1b432010-03-16 19:06:03665 private:
666 friend class base::RefCountedThreadSafe<HostResolverImpl::IPv6ProbeJob>;
667
668 ~IPv6ProbeJob() {
669 }
670
[email protected]a9af7112010-05-08 00:56:01671 // Should be run on |orgin_thread_|, but that may not be well defined now.
672 bool was_cancelled() const {
673 if (!resolver_ || !origin_loop_) {
674 DCHECK(!resolver_);
675 DCHECK(!origin_loop_);
676 return true;
677 }
678 return false;
679 }
680
[email protected]0f8f1b432010-03-16 19:06:03681 // Run on worker thread.
682 void DoProbe() {
683 // Do actual testing on this thread, as it takes 40-100ms.
684 AddressFamily family = IPv6Supported() ? ADDRESS_FAMILY_UNSPECIFIED
685 : ADDRESS_FAMILY_IPV4;
686
687 Task* reply = NewRunnableMethod(this, &IPv6ProbeJob::OnProbeComplete,
688 family);
689
690 // The origin loop could go away while we are trying to post to it, so we
691 // need to call its PostTask method inside a lock. See ~HostResolver.
692 {
693 AutoLock locked(origin_loop_lock_);
694 if (origin_loop_) {
695 origin_loop_->PostTask(FROM_HERE, reply);
696 return;
697 }
698 }
699
700 // We didn't post, so delete the reply.
701 delete reply;
702 }
703
704 // Callback for when DoProbe() completes (runs on origin thread).
705 void OnProbeComplete(AddressFamily address_family) {
[email protected]a9af7112010-05-08 00:56:01706 if (was_cancelled())
707 return;
[email protected]0f8f1b432010-03-16 19:06:03708 DCHECK(IsOnOriginThread());
[email protected]a9af7112010-05-08 00:56:01709 resolver_->IPv6ProbeSetDefaultAddressFamily(address_family);
[email protected]0f8f1b432010-03-16 19:06:03710 }
711
712 bool IsOnOriginThread() const {
713 return !MessageLoop::current() || origin_loop_ == MessageLoop::current();
714 }
715
716 // Used/set only on origin thread.
717 HostResolverImpl* resolver_;
718
719 // Used to post ourselves onto the origin thread.
720 Lock origin_loop_lock_;
721 MessageLoop* origin_loop_;
722
723 DISALLOW_COPY_AND_ASSIGN(IPv6ProbeJob);
724};
725
726//-----------------------------------------------------------------------------
727
[email protected]68ad3ee2010-01-30 03:45:39728// We rely on the priority enum values being sequential having starting at 0,
729// and increasing for lower priorities.
730COMPILE_ASSERT(HIGHEST == 0u &&
731 LOWEST > HIGHEST &&
[email protected]c9c6f5c2010-07-31 01:30:03732 IDLE > LOWEST &&
733 NUM_PRIORITIES > IDLE,
[email protected]68ad3ee2010-01-30 03:45:39734 priority_indexes_incompatible);
735
736// JobPool contains all the information relating to queued requests, including
737// the limits on how many jobs are allowed to be used for this category of
738// requests.
739class HostResolverImpl::JobPool {
740 public:
741 JobPool(size_t max_outstanding_jobs, size_t max_pending_requests)
742 : num_outstanding_jobs_(0u) {
743 SetConstraints(max_outstanding_jobs, max_pending_requests);
744 }
745
746 ~JobPool() {
747 // Free the pending requests.
748 for (size_t i = 0; i < arraysize(pending_requests_); ++i)
749 STLDeleteElements(&pending_requests_[i]);
750 }
751
752 // Sets the constraints for this pool. See SetPoolConstraints() for the
753 // specific meaning of these parameters.
754 void SetConstraints(size_t max_outstanding_jobs,
755 size_t max_pending_requests) {
[email protected]b1f031dd2010-03-02 23:19:33756 CHECK_NE(max_outstanding_jobs, 0u);
[email protected]68ad3ee2010-01-30 03:45:39757 max_outstanding_jobs_ = max_outstanding_jobs;
758 max_pending_requests_ = max_pending_requests;
759 }
760
761 // Returns the number of pending requests enqueued to this pool.
762 // A pending request is one waiting to be attached to a job.
763 size_t GetNumPendingRequests() const {
764 size_t total = 0u;
765 for (size_t i = 0u; i < arraysize(pending_requests_); ++i)
766 total += pending_requests_[i].size();
767 return total;
768 }
769
770 bool HasPendingRequests() const {
771 return GetNumPendingRequests() > 0u;
772 }
773
774 // Enqueues a request to this pool. As a result of enqueing this request,
775 // the queue may have reached its maximum size. In this case, a request is
776 // evicted from the queue, and returned. Otherwise returns NULL. The caller
777 // is responsible for freeing the evicted request.
778 Request* InsertPendingRequest(Request* req) {
[email protected]ee094b82010-08-24 15:55:51779 req->request_net_log().BeginEvent(
780 NetLog::TYPE_HOST_RESOLVER_IMPL_JOB_POOL_QUEUE,
781 NULL);
782
[email protected]68ad3ee2010-01-30 03:45:39783 PendingRequestsQueue& q = pending_requests_[req->info().priority()];
784 q.push_back(req);
785
786 // If the queue is too big, kick out the lowest priority oldest request.
787 if (GetNumPendingRequests() > max_pending_requests_) {
788 // Iterate over the queues from lowest priority to highest priority.
789 for (int i = static_cast<int>(arraysize(pending_requests_)) - 1;
790 i >= 0; --i) {
791 PendingRequestsQueue& q = pending_requests_[i];
792 if (!q.empty()) {
793 Request* req = q.front();
794 q.pop_front();
[email protected]ee094b82010-08-24 15:55:51795 req->request_net_log().AddEvent(
796 NetLog::TYPE_HOST_RESOLVER_IMPL_JOB_POOL_QUEUE_EVICTED, NULL);
797 req->request_net_log().EndEvent(
798 NetLog::TYPE_HOST_RESOLVER_IMPL_JOB_POOL_QUEUE, NULL);
[email protected]68ad3ee2010-01-30 03:45:39799 return req;
800 }
801 }
802 }
803
804 return NULL;
805 }
806
807 // Erases |req| from this container. Caller is responsible for freeing
808 // |req| afterwards.
809 void RemovePendingRequest(Request* req) {
810 PendingRequestsQueue& q = pending_requests_[req->info().priority()];
811 PendingRequestsQueue::iterator it = std::find(q.begin(), q.end(), req);
812 DCHECK(it != q.end());
813 q.erase(it);
[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 }
817
818 // Removes and returns the highest priority pending request.
819 Request* RemoveTopPendingRequest() {
820 DCHECK(HasPendingRequests());
821
822 for (size_t i = 0u; i < arraysize(pending_requests_); ++i) {
823 PendingRequestsQueue& q = pending_requests_[i];
824 if (!q.empty()) {
825 Request* req = q.front();
826 q.pop_front();
[email protected]ee094b82010-08-24 15:55:51827 req->request_net_log().EndEvent(
828 NetLog::TYPE_HOST_RESOLVER_IMPL_JOB_POOL_QUEUE, NULL);
[email protected]68ad3ee2010-01-30 03:45:39829 return req;
830 }
831 }
832
833 NOTREACHED();
834 return NULL;
835 }
836
837 // Keeps track of a job that was just added/removed, and belongs to this pool.
838 void AdjustNumOutstandingJobs(int offset) {
839 DCHECK(offset == 1 || (offset == -1 && num_outstanding_jobs_ > 0u));
840 num_outstanding_jobs_ += offset;
841 }
842
[email protected]35ddc282010-09-21 23:42:06843 void ResetNumOutstandingJobs() {
844 num_outstanding_jobs_ = 0;
845 }
846
[email protected]68ad3ee2010-01-30 03:45:39847 // Returns true if a new job can be created for this pool.
848 bool CanCreateJob() const {
849 return num_outstanding_jobs_ + 1u <= max_outstanding_jobs_;
850 }
851
852 // Removes any pending requests from the queue which are for the
[email protected]137af622010-02-05 02:14:35853 // same (hostname / effective address-family) as |job|, and attaches them to
854 // |job|.
[email protected]68ad3ee2010-01-30 03:45:39855 void MoveRequestsToJob(Job* job) {
856 for (size_t i = 0u; i < arraysize(pending_requests_); ++i) {
857 PendingRequestsQueue& q = pending_requests_[i];
858 PendingRequestsQueue::iterator req_it = q.begin();
859 while (req_it != q.end()) {
860 Request* req = *req_it;
[email protected]137af622010-02-05 02:14:35861 if (job->CanServiceRequest(req->info())) {
[email protected]68ad3ee2010-01-30 03:45:39862 // Job takes ownership of |req|.
863 job->AddRequest(req);
864 req_it = q.erase(req_it);
865 } else {
866 ++req_it;
867 }
868 }
869 }
870 }
871
872 private:
873 typedef std::deque<Request*> PendingRequestsQueue;
874
875 // Maximum number of concurrent jobs allowed to be started for requests
876 // belonging to this pool.
877 size_t max_outstanding_jobs_;
878
879 // The current number of running jobs that were started for requests
880 // belonging to this pool.
881 size_t num_outstanding_jobs_;
882
883 // The maximum number of requests we allow to be waiting on a job,
884 // for this pool.
885 size_t max_pending_requests_;
886
887 // The requests which are waiting to be started for this pool.
888 PendingRequestsQueue pending_requests_[NUM_PRIORITIES];
889};
890
891//-----------------------------------------------------------------------------
892
[email protected]e95d3aca2010-01-11 22:47:43893HostResolverImpl::HostResolverImpl(
894 HostResolverProc* resolver_proc,
895 HostCache* cache,
[email protected]ee094b82010-08-24 15:55:51896 size_t max_jobs,
897 NetLog* net_log)
[email protected]112bd462009-12-10 07:23:40898 : cache_(cache),
[email protected]68ad3ee2010-01-30 03:45:39899 max_jobs_(max_jobs),
[email protected]123ab1e32009-10-21 19:12:57900 next_request_id_(0),
[email protected]f2d8c4212010-02-02 00:56:35901 next_job_id_(0),
[email protected]123ab1e32009-10-21 19:12:57902 resolver_proc_(resolver_proc),
[email protected]0c7798452009-10-26 17:59:51903 default_address_family_(ADDRESS_FAMILY_UNSPECIFIED),
[email protected]e95d3aca2010-01-11 22:47:43904 shutdown_(false),
[email protected]2f3bc65c2010-07-23 17:47:10905 ipv6_probe_monitoring_(false),
[email protected]ee094b82010-08-24 15:55:51906 additional_resolver_flags_(0),
907 net_log_(net_log) {
[email protected]68ad3ee2010-01-30 03:45:39908 DCHECK_GT(max_jobs, 0u);
909
910 // It is cumbersome to expose all of the constraints in the constructor,
911 // so we choose some defaults, which users can override later.
912 job_pools_[POOL_NORMAL] = new JobPool(max_jobs, 100u * max_jobs);
913
[email protected]b59ff372009-07-15 22:04:32914#if defined(OS_WIN)
915 EnsureWinsockInit();
916#endif
[email protected]2f3bc65c2010-07-23 17:47:10917#if defined(OS_LINUX)
918 if (HaveOnlyLoopbackAddresses())
919 additional_resolver_flags_ |= HOST_RESOLVER_LOOPBACK_ONLY;
920#endif
[email protected]66761b952010-06-25 21:30:38921 NetworkChangeNotifier::AddObserver(this);
[email protected]b59ff372009-07-15 22:04:32922}
923
924HostResolverImpl::~HostResolverImpl() {
925 // Cancel the outstanding jobs. Those jobs may contain several attached
926 // requests, which will also be cancelled.
[email protected]0f8f1b432010-03-16 19:06:03927 DiscardIPv6ProbeJob();
928
[email protected]ef4c40c2010-09-01 14:42:03929 CancelAllJobs();
[email protected]b59ff372009-07-15 22:04:32930
931 // In case we are being deleted during the processing of a callback.
932 if (cur_completing_job_)
933 cur_completing_job_->Cancel();
[email protected]e95d3aca2010-01-11 22:47:43934
[email protected]66761b952010-06-25 21:30:38935 NetworkChangeNotifier::RemoveObserver(this);
[email protected]61a86c42010-04-19 22:45:53936
[email protected]68ad3ee2010-01-30 03:45:39937 // Delete the job pools.
938 for (size_t i = 0u; i < arraysize(job_pools_); ++i)
939 delete job_pools_[i];
[email protected]b59ff372009-07-15 22:04:32940}
941
[email protected]684970b2009-08-14 04:54:46942int HostResolverImpl::Resolve(const RequestInfo& info,
[email protected]b59ff372009-07-15 22:04:32943 AddressList* addresses,
944 CompletionCallback* callback,
[email protected]684970b2009-08-14 04:54:46945 RequestHandle* out_req,
[email protected]ee094b82010-08-24 15:55:51946 const BoundNetLog& source_net_log) {
[email protected]1ac6af92010-06-03 21:00:14947 DCHECK(CalledOnValidThread());
948
[email protected]b59ff372009-07-15 22:04:32949 if (shutdown_)
950 return ERR_UNEXPECTED;
951
952 // Choose a unique ID number for observers to see.
953 int request_id = next_request_id_++;
954
[email protected]ee094b82010-08-24 15:55:51955 // Make a log item for the request.
956 BoundNetLog request_net_log = BoundNetLog::Make(net_log_,
957 NetLog::SOURCE_HOST_RESOLVER_IMPL_REQUEST);
958
[email protected]9e743cd2010-03-16 07:03:53959 // Update the net log and notify registered observers.
[email protected]ee094b82010-08-24 15:55:51960 OnStartRequest(source_net_log, request_net_log, request_id, info);
[email protected]b59ff372009-07-15 22:04:32961
[email protected]123ab1e32009-10-21 19:12:57962 // Build a key that identifies the request in the cache and in the
963 // outstanding jobs map.
[email protected]137af622010-02-05 02:14:35964 Key key = GetEffectiveKeyForRequest(info);
[email protected]123ab1e32009-10-21 19:12:57965
[email protected]eaf3a3b2010-09-03 20:34:27966 // Check for IP literal.
967 IPAddressNumber ip_number;
968 if (ParseIPLiteralToNumber(info.hostname(), &ip_number)) {
969 DCHECK_EQ(key.host_resolver_flags &
970 ~(HOST_RESOLVER_CANONNAME | HOST_RESOLVER_LOOPBACK_ONLY |
971 HOST_RESOLVER_DEFAULT_FAMILY_SET_DUE_TO_NO_IPV6),
972 0) << " Unhandled flag";
973 bool ipv6_disabled = default_address_family_ == ADDRESS_FAMILY_IPV4 &&
974 !ipv6_probe_monitoring_;
975 int net_error = OK;
976 if (ip_number.size() == 16 && ipv6_disabled) {
977 net_error = ERR_NAME_NOT_RESOLVED;
978 } else {
979 AddressList result(ip_number, info.port(),
980 (key.host_resolver_flags & HOST_RESOLVER_CANONNAME));
981 *addresses = result;
982 }
983 // Update the net log and notify registered observers.
984 OnFinishRequest(source_net_log, request_net_log, request_id, info,
985 net_error, 0 /* os_error (unknown since from cache) */);
986 return net_error;
987 }
988
[email protected]b59ff372009-07-15 22:04:32989 // If we have an unexpired cache entry, use it.
[email protected]112bd462009-12-10 07:23:40990 if (info.allow_cached_response() && cache_.get()) {
991 const HostCache::Entry* cache_entry = cache_->Lookup(
[email protected]123ab1e32009-10-21 19:12:57992 key, base::TimeTicks::Now());
[email protected]b59ff372009-07-15 22:04:32993 if (cache_entry) {
[email protected]ee094b82010-08-24 15:55:51994 request_net_log.AddEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_CACHE_HIT, NULL);
[email protected]21526002010-05-16 19:42:46995 int net_error = cache_entry->error;
996 if (net_error == OK)
[email protected]112bd462009-12-10 07:23:40997 addresses->SetFrom(cache_entry->addrlist, info.port());
[email protected]b59ff372009-07-15 22:04:32998
[email protected]9e743cd2010-03-16 07:03:53999 // Update the net log and notify registered observers.
[email protected]ee094b82010-08-24 15:55:511000 OnFinishRequest(source_net_log, request_net_log, request_id, info,
1001 net_error,
1002 0 /* os_error (unknown since from cache) */);
[email protected]b59ff372009-07-15 22:04:321003
[email protected]21526002010-05-16 19:42:461004 return net_error;
[email protected]b59ff372009-07-15 22:04:321005 }
1006 }
1007
1008 // If no callback was specified, do a synchronous resolution.
1009 if (!callback) {
1010 AddressList addrlist;
[email protected]21526002010-05-16 19:42:461011 int os_error = 0;
[email protected]b59ff372009-07-15 22:04:321012 int error = ResolveAddrInfo(
[email protected]5ea28dea2010-04-08 15:35:131013 effective_resolver_proc(), key.hostname, key.address_family,
[email protected]21526002010-05-16 19:42:461014 key.host_resolver_flags, &addrlist, &os_error);
[email protected]b59ff372009-07-15 22:04:321015 if (error == OK) {
1016 addrlist.SetPort(info.port());
1017 *addresses = addrlist;
1018 }
1019
1020 // Write to cache.
[email protected]112bd462009-12-10 07:23:401021 if (cache_.get())
1022 cache_->Set(key, error, addrlist, base::TimeTicks::Now());
[email protected]b59ff372009-07-15 22:04:321023
[email protected]9e743cd2010-03-16 07:03:531024 // Update the net log and notify registered observers.
[email protected]ee094b82010-08-24 15:55:511025 OnFinishRequest(source_net_log, request_net_log, request_id, info, error,
1026 os_error);
[email protected]b59ff372009-07-15 22:04:321027
1028 return error;
1029 }
1030
1031 // Create a handle for this request, and pass it back to the user if they
1032 // asked for it (out_req != NULL).
[email protected]ee094b82010-08-24 15:55:511033 Request* req = new Request(source_net_log, request_net_log, request_id, info,
1034 callback, addresses);
[email protected]b59ff372009-07-15 22:04:321035 if (out_req)
1036 *out_req = reinterpret_cast<RequestHandle>(req);
1037
1038 // Next we need to attach our request to a "job". This job is responsible for
1039 // calling "getaddrinfo(hostname)" on a worker thread.
1040 scoped_refptr<Job> job;
1041
[email protected]123ab1e32009-10-21 19:12:571042 // If there is already an outstanding job to resolve |key|, use
[email protected]b59ff372009-07-15 22:04:321043 // it. This prevents starting concurrent resolves for the same hostname.
[email protected]123ab1e32009-10-21 19:12:571044 job = FindOutstandingJob(key);
[email protected]b59ff372009-07-15 22:04:321045 if (job) {
1046 job->AddRequest(req);
1047 } else {
[email protected]68ad3ee2010-01-30 03:45:391048 JobPool* pool = GetPoolForRequest(req);
1049 if (CanCreateJobForPool(*pool)) {
1050 CreateAndStartJob(req);
1051 } else {
1052 return EnqueueRequest(pool, req);
1053 }
[email protected]b59ff372009-07-15 22:04:321054 }
1055
1056 // Completion happens during OnJobComplete(Job*).
1057 return ERR_IO_PENDING;
1058}
1059
1060// See OnJobComplete(Job*) for why it is important not to clean out
1061// cancelled requests from Job::requests_.
1062void HostResolverImpl::CancelRequest(RequestHandle req_handle) {
[email protected]1ac6af92010-06-03 21:00:141063 DCHECK(CalledOnValidThread());
[email protected]bf0b51c2009-08-01 23:46:401064 if (shutdown_) {
[email protected]ff1f61b92009-08-03 23:20:231065 // TODO(eroman): temp hack for: http://crbug.com/18373
1066 // Because we destroy outstanding requests during Shutdown(),
1067 // |req_handle| is already cancelled.
[email protected]bf0b51c2009-08-01 23:46:401068 LOG(ERROR) << "Called HostResolverImpl::CancelRequest() after Shutdown().";
[email protected]58580352010-10-26 04:07:501069 base::debug::StackTrace().PrintBacktrace();
[email protected]bf0b51c2009-08-01 23:46:401070 return;
1071 }
[email protected]b59ff372009-07-15 22:04:321072 Request* req = reinterpret_cast<Request*>(req_handle);
1073 DCHECK(req);
[email protected]68ad3ee2010-01-30 03:45:391074
1075 scoped_ptr<Request> request_deleter; // Frees at end of function.
1076
1077 if (!req->job()) {
1078 // If the request was not attached to a job yet, it must have been
1079 // enqueued into a pool. Remove it from that pool's queue.
1080 // Otherwise if it was attached to a job, the job is responsible for
1081 // deleting it.
1082 JobPool* pool = GetPoolForRequest(req);
1083 pool->RemovePendingRequest(req);
1084 request_deleter.reset(req);
[email protected]ee094b82010-08-24 15:55:511085 } else {
1086 req->request_net_log().EndEvent(
1087 NetLog::TYPE_HOST_RESOLVER_IMPL_JOB_ATTACH, NULL);
[email protected]68ad3ee2010-01-30 03:45:391088 }
1089
[email protected]b59ff372009-07-15 22:04:321090 // NULL out the fields of req, to mark it as cancelled.
1091 req->MarkAsCancelled();
[email protected]ee094b82010-08-24 15:55:511092 OnCancelRequest(req->source_net_log(), req->request_net_log(), req->id(),
1093 req->info());
[email protected]b59ff372009-07-15 22:04:321094}
1095
[email protected]e95d3aca2010-01-11 22:47:431096void HostResolverImpl::AddObserver(HostResolver::Observer* observer) {
[email protected]1ac6af92010-06-03 21:00:141097 DCHECK(CalledOnValidThread());
[email protected]b59ff372009-07-15 22:04:321098 observers_.push_back(observer);
1099}
1100
[email protected]e95d3aca2010-01-11 22:47:431101void HostResolverImpl::RemoveObserver(HostResolver::Observer* observer) {
[email protected]1ac6af92010-06-03 21:00:141102 DCHECK(CalledOnValidThread());
[email protected]b59ff372009-07-15 22:04:321103 ObserversList::iterator it =
1104 std::find(observers_.begin(), observers_.end(), observer);
1105
1106 // Observer must exist.
1107 DCHECK(it != observers_.end());
1108
1109 observers_.erase(it);
1110}
1111
[email protected]0f8f1b432010-03-16 19:06:031112void HostResolverImpl::SetDefaultAddressFamily(AddressFamily address_family) {
[email protected]1ac6af92010-06-03 21:00:141113 DCHECK(CalledOnValidThread());
[email protected]0f8f1b432010-03-16 19:06:031114 ipv6_probe_monitoring_ = false;
1115 DiscardIPv6ProbeJob();
1116 default_address_family_ = address_family;
1117}
1118
[email protected]f7d310e2010-10-07 16:25:111119AddressFamily HostResolverImpl::GetDefaultAddressFamily() const {
1120 return default_address_family_;
1121}
1122
[email protected]0f8f1b432010-03-16 19:06:031123void HostResolverImpl::ProbeIPv6Support() {
[email protected]1ac6af92010-06-03 21:00:141124 DCHECK(CalledOnValidThread());
[email protected]0f8f1b432010-03-16 19:06:031125 DCHECK(!ipv6_probe_monitoring_);
1126 ipv6_probe_monitoring_ = true;
[email protected]61a86c42010-04-19 22:45:531127 OnIPAddressChanged(); // Give initial setup call.
[email protected]0f8f1b432010-03-16 19:06:031128}
1129
[email protected]b59ff372009-07-15 22:04:321130void HostResolverImpl::Shutdown() {
[email protected]1ac6af92010-06-03 21:00:141131 DCHECK(CalledOnValidThread());
[email protected]b59ff372009-07-15 22:04:321132
1133 // Cancel the outstanding jobs.
[email protected]ef4c40c2010-09-01 14:42:031134 CancelAllJobs();
[email protected]0a175512010-04-20 03:09:251135 DiscardIPv6ProbeJob();
[email protected]be5c6162010-07-27 21:12:511136
1137 shutdown_ = true;
[email protected]b59ff372009-07-15 22:04:321138}
1139
[email protected]68ad3ee2010-01-30 03:45:391140void HostResolverImpl::SetPoolConstraints(JobPoolIndex pool_index,
1141 size_t max_outstanding_jobs,
1142 size_t max_pending_requests) {
[email protected]1ac6af92010-06-03 21:00:141143 DCHECK(CalledOnValidThread());
[email protected]b1f031dd2010-03-02 23:19:331144 CHECK_GE(pool_index, 0);
1145 CHECK_LT(pool_index, POOL_COUNT);
[email protected]68ad3ee2010-01-30 03:45:391146 CHECK(jobs_.empty()) << "Can only set constraints during setup";
1147 JobPool* pool = job_pools_[pool_index];
1148 pool->SetConstraints(max_outstanding_jobs, max_pending_requests);
1149}
1150
[email protected]b59ff372009-07-15 22:04:321151void HostResolverImpl::AddOutstandingJob(Job* job) {
[email protected]123ab1e32009-10-21 19:12:571152 scoped_refptr<Job>& found_job = jobs_[job->key()];
[email protected]b59ff372009-07-15 22:04:321153 DCHECK(!found_job);
1154 found_job = job;
[email protected]68ad3ee2010-01-30 03:45:391155
1156 JobPool* pool = GetPoolForRequest(job->initial_request());
1157 pool->AdjustNumOutstandingJobs(1);
[email protected]b59ff372009-07-15 22:04:321158}
1159
[email protected]123ab1e32009-10-21 19:12:571160HostResolverImpl::Job* HostResolverImpl::FindOutstandingJob(const Key& key) {
1161 JobMap::iterator it = jobs_.find(key);
[email protected]b59ff372009-07-15 22:04:321162 if (it != jobs_.end())
1163 return it->second;
1164 return NULL;
1165}
1166
1167void HostResolverImpl::RemoveOutstandingJob(Job* job) {
[email protected]123ab1e32009-10-21 19:12:571168 JobMap::iterator it = jobs_.find(job->key());
[email protected]b59ff372009-07-15 22:04:321169 DCHECK(it != jobs_.end());
1170 DCHECK_EQ(it->second.get(), job);
1171 jobs_.erase(it);
[email protected]68ad3ee2010-01-30 03:45:391172
1173 JobPool* pool = GetPoolForRequest(job->initial_request());
1174 pool->AdjustNumOutstandingJobs(-1);
[email protected]b59ff372009-07-15 22:04:321175}
1176
1177void HostResolverImpl::OnJobComplete(Job* job,
[email protected]21526002010-05-16 19:42:461178 int net_error,
1179 int os_error,
[email protected]27f99c82009-10-29 22:21:001180 const AddressList& addrlist) {
[email protected]b59ff372009-07-15 22:04:321181 RemoveOutstandingJob(job);
1182
1183 // Write result to the cache.
[email protected]112bd462009-12-10 07:23:401184 if (cache_.get())
[email protected]21526002010-05-16 19:42:461185 cache_->Set(job->key(), net_error, addrlist, base::TimeTicks::Now());
[email protected]b59ff372009-07-15 22:04:321186
[email protected]ef4c40c2010-09-01 14:42:031187 OnJobCompleteInternal(job, net_error, os_error, addrlist);
1188}
1189
1190void HostResolverImpl::AbortJob(Job* job) {
1191 OnJobCompleteInternal(job, ERR_ABORTED, 0 /* no os_error */, AddressList());
1192}
1193
1194void HostResolverImpl::OnJobCompleteInternal(
1195 Job* job,
1196 int net_error,
1197 int os_error,
1198 const AddressList& addrlist) {
[email protected]b59ff372009-07-15 22:04:321199 // Make a note that we are executing within OnJobComplete() in case the
1200 // HostResolver is deleted by a callback invocation.
1201 DCHECK(!cur_completing_job_);
1202 cur_completing_job_ = job;
1203
[email protected]68ad3ee2010-01-30 03:45:391204 // Try to start any queued requests now that a job-slot has freed up.
1205 ProcessQueuedRequests();
1206
[email protected]b59ff372009-07-15 22:04:321207 // Complete all of the requests that were attached to the job.
1208 for (RequestsList::const_iterator it = job->requests().begin();
1209 it != job->requests().end(); ++it) {
1210 Request* req = *it;
1211 if (!req->was_cancelled()) {
1212 DCHECK_EQ(job, req->job());
[email protected]ee094b82010-08-24 15:55:511213 req->request_net_log().EndEvent(
1214 NetLog::TYPE_HOST_RESOLVER_IMPL_JOB_ATTACH, NULL);
[email protected]b59ff372009-07-15 22:04:321215
[email protected]9e743cd2010-03-16 07:03:531216 // Update the net log and notify registered observers.
[email protected]ee094b82010-08-24 15:55:511217 OnFinishRequest(req->source_net_log(), req->request_net_log(), req->id(),
1218 req->info(), net_error, os_error);
[email protected]b59ff372009-07-15 22:04:321219
[email protected]21526002010-05-16 19:42:461220 req->OnComplete(net_error, addrlist);
[email protected]b59ff372009-07-15 22:04:321221
1222 // Check if the job was cancelled as a result of running the callback.
1223 // (Meaning that |this| was deleted).
1224 if (job->was_cancelled())
1225 return;
1226 }
1227 }
1228
1229 cur_completing_job_ = NULL;
1230}
1231
[email protected]ee094b82010-08-24 15:55:511232void HostResolverImpl::OnStartRequest(const BoundNetLog& source_net_log,
1233 const BoundNetLog& request_net_log,
[email protected]54e13772009-08-14 03:01:091234 int request_id,
1235 const RequestInfo& info) {
[email protected]ee094b82010-08-24 15:55:511236 source_net_log.BeginEvent(
1237 NetLog::TYPE_HOST_RESOLVER_IMPL,
1238 new NetLogSourceParameter("source_dependency", request_net_log.source()));
1239
1240 request_net_log.BeginEvent(
1241 NetLog::TYPE_HOST_RESOLVER_IMPL_REQUEST,
1242 new RequestInfoParameters(info, source_net_log.source()));
[email protected]54e13772009-08-14 03:01:091243
1244 // Notify the observers of the start.
1245 if (!observers_.empty()) {
[email protected]54e13772009-08-14 03:01:091246 for (ObserversList::iterator it = observers_.begin();
1247 it != observers_.end(); ++it) {
1248 (*it)->OnStartResolution(request_id, info);
1249 }
[email protected]b59ff372009-07-15 22:04:321250 }
1251}
1252
[email protected]ee094b82010-08-24 15:55:511253void HostResolverImpl::OnFinishRequest(const BoundNetLog& source_net_log,
1254 const BoundNetLog& request_net_log,
[email protected]54e13772009-08-14 03:01:091255 int request_id,
1256 const RequestInfo& info,
[email protected]21526002010-05-16 19:42:461257 int net_error,
[email protected]ee094b82010-08-24 15:55:511258 int os_error) {
[email protected]21526002010-05-16 19:42:461259 bool was_resolved = net_error == OK;
1260
[email protected]54e13772009-08-14 03:01:091261 // Notify the observers of the completion.
1262 if (!observers_.empty()) {
[email protected]54e13772009-08-14 03:01:091263 for (ObserversList::iterator it = observers_.begin();
1264 it != observers_.end(); ++it) {
1265 (*it)->OnFinishResolutionWithStatus(request_id, was_resolved, info);
1266 }
[email protected]b59ff372009-07-15 22:04:321267 }
[email protected]54e13772009-08-14 03:01:091268
[email protected]ee094b82010-08-24 15:55:511269 // Log some extra parameters on failure for synchronous requests.
[email protected]21526002010-05-16 19:42:461270 scoped_refptr<NetLog::EventParameters> params;
[email protected]ee094b82010-08-24 15:55:511271 if (!was_resolved) {
1272 params = new HostResolveFailedParams(net_error, os_error);
1273 }
[email protected]21526002010-05-16 19:42:461274
[email protected]ee094b82010-08-24 15:55:511275 request_net_log.EndEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_REQUEST, params);
1276 source_net_log.EndEvent(NetLog::TYPE_HOST_RESOLVER_IMPL, NULL);
[email protected]b59ff372009-07-15 22:04:321277}
1278
[email protected]ee094b82010-08-24 15:55:511279void HostResolverImpl::OnCancelRequest(const BoundNetLog& source_net_log,
1280 const BoundNetLog& request_net_log,
[email protected]54e13772009-08-14 03:01:091281 int request_id,
1282 const RequestInfo& info) {
[email protected]ee094b82010-08-24 15:55:511283 request_net_log.AddEvent(NetLog::TYPE_CANCELLED, NULL);
[email protected]54e13772009-08-14 03:01:091284
1285 // Notify the observers of the cancellation.
1286 if (!observers_.empty()) {
[email protected]54e13772009-08-14 03:01:091287 for (ObserversList::iterator it = observers_.begin();
1288 it != observers_.end(); ++it) {
1289 (*it)->OnCancelResolution(request_id, info);
1290 }
[email protected]b59ff372009-07-15 22:04:321291 }
[email protected]54e13772009-08-14 03:01:091292
[email protected]ee094b82010-08-24 15:55:511293 request_net_log.EndEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_REQUEST, NULL);
1294 source_net_log.EndEvent(NetLog::TYPE_HOST_RESOLVER_IMPL, NULL);
[email protected]b59ff372009-07-15 22:04:321295}
1296
[email protected]61a86c42010-04-19 22:45:531297void HostResolverImpl::OnIPAddressChanged() {
[email protected]e95d3aca2010-01-11 22:47:431298 if (cache_.get())
1299 cache_->clear();
[email protected]0f8f1b432010-03-16 19:06:031300 if (ipv6_probe_monitoring_) {
[email protected]0a175512010-04-20 03:09:251301 DCHECK(!shutdown_);
1302 if (shutdown_)
1303 return;
[email protected]0f8f1b432010-03-16 19:06:031304 DiscardIPv6ProbeJob();
1305 ipv6_probe_job_ = new IPv6ProbeJob(this);
1306 ipv6_probe_job_->Start();
1307 }
[email protected]2f3bc65c2010-07-23 17:47:101308#if defined(OS_LINUX)
1309 if (HaveOnlyLoopbackAddresses()) {
1310 additional_resolver_flags_ |= HOST_RESOLVER_LOOPBACK_ONLY;
1311 } else {
1312 additional_resolver_flags_ &= ~HOST_RESOLVER_LOOPBACK_ONLY;
1313 }
1314#endif
[email protected]35ddc282010-09-21 23:42:061315 AbortAllInProgressJobs();
1316 // |this| may be deleted inside AbortAllInProgressJobs().
[email protected]0f8f1b432010-03-16 19:06:031317}
1318
1319void HostResolverImpl::DiscardIPv6ProbeJob() {
1320 if (ipv6_probe_job_.get()) {
1321 ipv6_probe_job_->Cancel();
1322 ipv6_probe_job_ = NULL;
1323 }
1324}
1325
1326void HostResolverImpl::IPv6ProbeSetDefaultAddressFamily(
1327 AddressFamily address_family) {
1328 DCHECK(address_family == ADDRESS_FAMILY_UNSPECIFIED ||
1329 address_family == ADDRESS_FAMILY_IPV4);
[email protected]f092e64b2010-03-17 00:39:181330 if (default_address_family_ != address_family) {
[email protected]b30a3f52010-10-16 01:05:461331 VLOG(1) << "IPv6Probe forced AddressFamily setting to "
1332 << ((address_family == ADDRESS_FAMILY_UNSPECIFIED) ?
1333 "ADDRESS_FAMILY_UNSPECIFIED" : "ADDRESS_FAMILY_IPV4");
[email protected]f092e64b2010-03-17 00:39:181334 }
[email protected]0f8f1b432010-03-16 19:06:031335 default_address_family_ = address_family;
1336 // Drop reference since the job has called us back.
1337 DiscardIPv6ProbeJob();
[email protected]e95d3aca2010-01-11 22:47:431338}
1339
[email protected]68ad3ee2010-01-30 03:45:391340// static
1341HostResolverImpl::JobPoolIndex HostResolverImpl::GetJobPoolIndexForRequest(
1342 const Request* req) {
1343 return POOL_NORMAL;
1344}
1345
1346bool HostResolverImpl::CanCreateJobForPool(const JobPool& pool) const {
1347 DCHECK_LE(jobs_.size(), max_jobs_);
1348
1349 // We can't create another job if it would exceed the global total.
1350 if (jobs_.size() + 1 > max_jobs_)
1351 return false;
1352
1353 // Check whether the pool's constraints are met.
1354 return pool.CanCreateJob();
1355}
1356
1357void HostResolverImpl::ProcessQueuedRequests() {
1358 // Find the highest priority request that can be scheduled.
1359 Request* top_req = NULL;
1360 for (size_t i = 0; i < arraysize(job_pools_); ++i) {
1361 JobPool* pool = job_pools_[i];
1362 if (pool->HasPendingRequests() && CanCreateJobForPool(*pool)) {
1363 top_req = pool->RemoveTopPendingRequest();
1364 break;
1365 }
1366 }
1367
1368 if (!top_req)
1369 return;
1370
1371 scoped_refptr<Job> job = CreateAndStartJob(top_req);
1372
1373 // Search for any other pending request which can piggy-back off this job.
1374 for (size_t pool_i = 0; pool_i < POOL_COUNT; ++pool_i) {
1375 JobPool* pool = job_pools_[pool_i];
1376 pool->MoveRequestsToJob(job);
1377 }
1378}
1379
[email protected]137af622010-02-05 02:14:351380HostResolverImpl::Key HostResolverImpl::GetEffectiveKeyForRequest(
1381 const RequestInfo& info) const {
[email protected]eaf3a3b2010-09-03 20:34:271382 HostResolverFlags effective_flags =
1383 info.host_resolver_flags() | additional_resolver_flags_;
[email protected]137af622010-02-05 02:14:351384 AddressFamily effective_address_family = info.address_family();
[email protected]eaf3a3b2010-09-03 20:34:271385 if (effective_address_family == ADDRESS_FAMILY_UNSPECIFIED &&
1386 default_address_family_ != ADDRESS_FAMILY_UNSPECIFIED) {
[email protected]137af622010-02-05 02:14:351387 effective_address_family = default_address_family_;
[email protected]eaf3a3b2010-09-03 20:34:271388 if (ipv6_probe_monitoring_)
1389 effective_flags |= HOST_RESOLVER_DEFAULT_FAMILY_SET_DUE_TO_NO_IPV6;
1390 }
1391 return Key(info.hostname(), effective_address_family, effective_flags);
[email protected]137af622010-02-05 02:14:351392}
1393
[email protected]68ad3ee2010-01-30 03:45:391394HostResolverImpl::Job* HostResolverImpl::CreateAndStartJob(Request* req) {
1395 DCHECK(CanCreateJobForPool(*GetPoolForRequest(req)));
[email protected]137af622010-02-05 02:14:351396 Key key = GetEffectiveKeyForRequest(req->info());
[email protected]ee094b82010-08-24 15:55:511397
1398 req->request_net_log().AddEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_CREATE_JOB,
1399 NULL);
1400
1401 scoped_refptr<Job> job = new Job(next_job_id_++, this, key,
1402 req->request_net_log(), net_log_);
[email protected]68ad3ee2010-01-30 03:45:391403 job->AddRequest(req);
1404 AddOutstandingJob(job);
1405 job->Start();
[email protected]ee094b82010-08-24 15:55:511406
[email protected]68ad3ee2010-01-30 03:45:391407 return job.get();
1408}
1409
1410int HostResolverImpl::EnqueueRequest(JobPool* pool, Request* req) {
1411 scoped_ptr<Request> req_evicted_from_queue(
1412 pool->InsertPendingRequest(req));
1413
1414 // If the queue has become too large, we need to kick something out.
1415 if (req_evicted_from_queue.get()) {
1416 Request* r = req_evicted_from_queue.get();
1417 int error = ERR_HOST_RESOLVER_QUEUE_TOO_LARGE;
1418
[email protected]ee094b82010-08-24 15:55:511419 OnFinishRequest(r->source_net_log(), r->request_net_log(), r->id(),
1420 r->info(), error,
1421 0 /* os_error (not applicable) */);
[email protected]68ad3ee2010-01-30 03:45:391422
1423 if (r == req)
1424 return error;
1425
1426 r->OnComplete(error, AddressList());
1427 }
1428
1429 return ERR_IO_PENDING;
1430}
1431
[email protected]ef4c40c2010-09-01 14:42:031432void HostResolverImpl::CancelAllJobs() {
1433 JobMap jobs;
1434 jobs.swap(jobs_);
1435 for (JobMap::iterator it = jobs.begin(); it != jobs.end(); ++it)
1436 it->second->Cancel();
1437}
1438
[email protected]35ddc282010-09-21 23:42:061439void HostResolverImpl::AbortAllInProgressJobs() {
1440 for (size_t i = 0; i < arraysize(job_pools_); ++i)
1441 job_pools_[i]->ResetNumOutstandingJobs();
[email protected]ef4c40c2010-09-01 14:42:031442 JobMap jobs;
1443 jobs.swap(jobs_);
1444 for (JobMap::iterator it = jobs.begin(); it != jobs.end(); ++it) {
1445 AbortJob(it->second);
1446 it->second->Cancel();
1447 }
1448}
1449
[email protected]b59ff372009-07-15 22:04:321450} // namespace net