blob: 8854d07c03b2c8845a4b23ade7b2a67418d29b71 [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]5097dc82010-07-15 17:23:2320#include "base/histogram.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"
23#include "base/stl_util-inl.h"
24#include "base/string_util.h"
25#include "base/time.h"
[email protected]ccaff652010-07-31 06:28:2026#include "base/utf_string_conversions.h"
[email protected]21526002010-05-16 19:42:4627#include "base/values.h"
[email protected]b59ff372009-07-15 22:04:3228#include "base/worker_pool.h"
29#include "net/base/address_list.h"
[email protected]ee094b82010-08-24 15:55:5130#include "net/base/address_list_net_log_param.h"
31#include "net/base/host_port_pair.h"
[email protected]b59ff372009-07-15 22:04:3232#include "net/base/host_resolver_proc.h"
[email protected]2bb04442010-08-18 18:01:1533#include "net/base/net_errors.h"
[email protected]ee094b82010-08-24 15:55:5134#include "net/base/net_log.h"
[email protected]0f8f1b432010-03-16 19:06:0335#include "net/base/net_util.h"
[email protected]b59ff372009-07-15 22:04:3236
37#if defined(OS_WIN)
38#include "net/base/winsock_init.h"
39#endif
40
41namespace net {
42
[email protected]e95d3aca2010-01-11 22:47:4343namespace {
44
45HostCache* CreateDefaultCache() {
[email protected]b59ff372009-07-15 22:04:3246 static const size_t kMaxHostCacheEntries = 100;
[email protected]112bd462009-12-10 07:23:4047
48 HostCache* cache = new HostCache(
49 kMaxHostCacheEntries,
50 base::TimeDelta::FromMinutes(1),
[email protected]72bceac2010-06-17 21:45:0851 base::TimeDelta::FromSeconds(0)); // Disable caching of failed DNS.
[email protected]112bd462009-12-10 07:23:4052
[email protected]e95d3aca2010-01-11 22:47:4353 return cache;
54}
55
56} // anonymous namespace
57
[email protected]ee094b82010-08-24 15:55:5158HostResolver* CreateSystemHostResolver(size_t max_concurrent_resolves,
59 NetLog* net_log) {
[email protected]68ad3ee2010-01-30 03:45:3960 // Maximum of 50 concurrent threads.
61 // TODO(eroman): Adjust this, do some A/B experiments.
[email protected]962b98212010-07-17 03:37:5162 static const size_t kDefaultMaxJobs = 50u;
63
64 if (max_concurrent_resolves == HostResolver::kDefaultParallelism)
65 max_concurrent_resolves = kDefaultMaxJobs;
[email protected]68ad3ee2010-01-30 03:45:3966
[email protected]66761b952010-06-25 21:30:3867 HostResolverImpl* resolver =
[email protected]962b98212010-07-17 03:37:5168 new HostResolverImpl(NULL, CreateDefaultCache(),
[email protected]ee094b82010-08-24 15:55:5169 max_concurrent_resolves, net_log);
[email protected]68ad3ee2010-01-30 03:45:3970
71 return resolver;
[email protected]b59ff372009-07-15 22:04:3272}
73
74static int ResolveAddrInfo(HostResolverProc* resolver_proc,
[email protected]123ab1e32009-10-21 19:12:5775 const std::string& host,
76 AddressFamily address_family,
[email protected]5ea28dea2010-04-08 15:35:1377 HostResolverFlags host_resolver_flags,
[email protected]21526002010-05-16 19:42:4678 AddressList* out,
79 int* os_error) {
[email protected]b59ff372009-07-15 22:04:3280 if (resolver_proc) {
81 // Use the custom procedure.
[email protected]5ea28dea2010-04-08 15:35:1382 return resolver_proc->Resolve(host, address_family,
[email protected]21526002010-05-16 19:42:4683 host_resolver_flags, out, os_error);
[email protected]b59ff372009-07-15 22:04:3284 } else {
85 // Use the system procedure (getaddrinfo).
[email protected]5ea28dea2010-04-08 15:35:1386 return SystemHostResolverProc(host, address_family,
[email protected]21526002010-05-16 19:42:4687 host_resolver_flags, out, os_error);
[email protected]b59ff372009-07-15 22:04:3288 }
89}
90
[email protected]21526002010-05-16 19:42:4691// Extra parameters to attach to the NetLog when the resolve failed.
92class HostResolveFailedParams : public NetLog::EventParameters {
93 public:
[email protected]ee094b82010-08-24 15:55:5194 HostResolveFailedParams(int net_error, int os_error)
[email protected]21526002010-05-16 19:42:4695 : net_error_(net_error),
[email protected]ee094b82010-08-24 15:55:5196 os_error_(os_error) {
[email protected]21526002010-05-16 19:42:4697 }
98
99 virtual Value* ToValue() const {
100 DictionaryValue* dict = new DictionaryValue();
[email protected]ccaff652010-07-31 06:28:20101 dict->SetInteger("net_error", net_error_);
[email protected]21526002010-05-16 19:42:46102
103 if (os_error_) {
[email protected]ccaff652010-07-31 06:28:20104 dict->SetInteger("os_error", os_error_);
[email protected]21526002010-05-16 19:42:46105#if defined(OS_POSIX)
[email protected]ccaff652010-07-31 06:28:20106 dict->SetString("os_error_string", gai_strerror(os_error_));
[email protected]21526002010-05-16 19:42:46107#elif defined(OS_WIN)
108 // Map the error code to a human-readable string.
109 LPWSTR error_string = NULL;
110 int size = FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
111 FORMAT_MESSAGE_FROM_SYSTEM,
112 0, // Use the internal message table.
113 os_error_,
114 0, // Use default language.
115 (LPWSTR)&error_string,
116 0, // Buffer size.
117 0); // Arguments (unused).
[email protected]ccaff652010-07-31 06:28:20118 dict->SetString("os_error_string", WideToUTF8(error_string));
[email protected]21526002010-05-16 19:42:46119 LocalFree(error_string);
120#endif
121 }
122
123 return dict;
124 }
125
126 private:
127 const int net_error_;
128 const int os_error_;
[email protected]ee094b82010-08-24 15:55:51129};
130
131// Parameters representing the information in a RequestInfo object, along with
132// the associated NetLog::Source.
133class RequestInfoParameters : public NetLog::EventParameters {
134 public:
135 RequestInfoParameters(const HostResolver::RequestInfo& info,
136 const NetLog::Source& source)
137 : info_(info), source_(source) {}
138
139 virtual Value* ToValue() const {
140 DictionaryValue* dict = new DictionaryValue();
[email protected]930cc742010-09-15 22:54:10141 dict->SetString("host", info_.host_port_pair().ToString());
[email protected]ee094b82010-08-24 15:55:51142 dict->SetInteger("address_family",
143 static_cast<int>(info_.address_family()));
144 dict->SetBoolean("allow_cached_response", info_.allow_cached_response());
145 dict->SetBoolean("is_speculative", info_.is_speculative());
146 dict->SetInteger("priority", info_.priority());
147
148 if (source_.is_valid())
149 dict->Set("source_dependency", source_.ToValue());
150
151 return dict;
152 }
153
154 private:
155 const HostResolver::RequestInfo info_;
156 const NetLog::Source source_;
157};
158
159// Parameters associated with the creation of a HostResolveImpl::Job.
160class JobCreationParameters : public NetLog::EventParameters {
161 public:
162 JobCreationParameters(const std::string& host, const NetLog::Source& source)
163 : host_(host), source_(source) {}
164
165 virtual Value* ToValue() const {
166 DictionaryValue* dict = new DictionaryValue();
167 dict->SetString("host", host_);
168 dict->Set("source_dependency", source_.ToValue());
169 return dict;
170 }
171
172 private:
173 const std::string host_;
174 const NetLog::Source source_;
[email protected]21526002010-05-16 19:42:46175};
176
177// Gets a list of the likely error codes that getaddrinfo() can return
178// (non-exhaustive). These are the error codes that we will track via
179// a histogram.
180std::vector<int> GetAllGetAddrinfoOSErrors() {
181 int os_errors[] = {
182#if defined(OS_POSIX)
183 EAI_ADDRFAMILY,
184 EAI_AGAIN,
185 EAI_BADFLAGS,
186 EAI_FAIL,
187 EAI_FAMILY,
188 EAI_MEMORY,
189 EAI_NODATA,
190 EAI_NONAME,
191 EAI_SERVICE,
192 EAI_SOCKTYPE,
193 EAI_SYSTEM,
194#elif defined(OS_WIN)
195 // See: http://msdn.microsoft.com/en-us/library/ms738520(VS.85).aspx
196 WSA_NOT_ENOUGH_MEMORY,
197 WSAEAFNOSUPPORT,
198 WSAEINVAL,
199 WSAESOCKTNOSUPPORT,
200 WSAHOST_NOT_FOUND,
201 WSANO_DATA,
202 WSANO_RECOVERY,
203 WSANOTINITIALISED,
204 WSATRY_AGAIN,
205 WSATYPE_NOT_FOUND,
206#endif
207 };
208
209 // Histogram enumerations require positive numbers.
210 std::vector<int> errors;
211 for (size_t i = 0; i < arraysize(os_errors); ++i) {
212 errors.push_back(std::abs(os_errors[i]));
213 // Also add N+1 for each error, so the bucket that contains our expected
214 // error is of size 1. That way if we get unexpected error codes, they
215 // won't fall into the same buckets as the expected ones.
216 errors.push_back(std::abs(os_errors[i]) + 1);
217 }
218 return errors;
219}
220
[email protected]b59ff372009-07-15 22:04:32221//-----------------------------------------------------------------------------
222
223class HostResolverImpl::Request {
224 public:
[email protected]ee094b82010-08-24 15:55:51225 Request(const BoundNetLog& source_net_log,
226 const BoundNetLog& request_net_log,
[email protected]54e13772009-08-14 03:01:09227 int id,
228 const RequestInfo& info,
229 CompletionCallback* callback,
[email protected]b59ff372009-07-15 22:04:32230 AddressList* addresses)
[email protected]ee094b82010-08-24 15:55:51231 : source_net_log_(source_net_log),
232 request_net_log_(request_net_log),
[email protected]54e13772009-08-14 03:01:09233 id_(id),
234 info_(info),
235 job_(NULL),
236 callback_(callback),
237 addresses_(addresses) {
238 }
[email protected]b59ff372009-07-15 22:04:32239
240 // Mark the request as cancelled.
241 void MarkAsCancelled() {
242 job_ = NULL;
243 callback_ = NULL;
244 addresses_ = NULL;
245 }
246
247 bool was_cancelled() const {
248 return callback_ == NULL;
249 }
250
251 void set_job(Job* job) {
252 DCHECK(job != NULL);
253 // Identify which job the request is waiting on.
254 job_ = job;
255 }
256
257 void OnComplete(int error, const AddressList& addrlist) {
258 if (error == OK)
259 addresses_->SetFrom(addrlist, port());
[email protected]ef4c40c2010-09-01 14:42:03260 CompletionCallback* callback = callback_;
261 MarkAsCancelled();
262 callback->Run(error);
[email protected]b59ff372009-07-15 22:04:32263 }
264
265 int port() const {
266 return info_.port();
267 }
268
269 Job* job() const {
270 return job_;
271 }
272
[email protected]ee094b82010-08-24 15:55:51273 const BoundNetLog& source_net_log() {
274 return source_net_log_;
275 }
276
277 const BoundNetLog& request_net_log() {
278 return request_net_log_;
[email protected]54e13772009-08-14 03:01:09279 }
280
[email protected]b59ff372009-07-15 22:04:32281 int id() const {
282 return id_;
283 }
284
285 const RequestInfo& info() const {
286 return info_;
287 }
288
289 private:
[email protected]ee094b82010-08-24 15:55:51290 BoundNetLog source_net_log_;
291 BoundNetLog request_net_log_;
[email protected]54e13772009-08-14 03:01:09292
[email protected]b59ff372009-07-15 22:04:32293 // Unique ID for this request. Used by observers to identify requests.
294 int id_;
295
296 // The request info that started the request.
297 RequestInfo info_;
298
299 // The resolve job (running in worker pool) that this request is dependent on.
300 Job* job_;
301
302 // The user's callback to invoke when the request completes.
303 CompletionCallback* callback_;
304
305 // The address list to save result into.
306 AddressList* addresses_;
307
308 DISALLOW_COPY_AND_ASSIGN(Request);
309};
310
311//-----------------------------------------------------------------------------
312
313// This class represents a request to the worker pool for a "getaddrinfo()"
314// call.
315class HostResolverImpl::Job
316 : public base::RefCountedThreadSafe<HostResolverImpl::Job> {
317 public:
[email protected]ee094b82010-08-24 15:55:51318 Job(int id,
319 HostResolverImpl* resolver,
320 const Key& key,
321 const BoundNetLog& source_net_log,
322 NetLog* net_log)
323 : id_(id),
324 key_(key),
325 resolver_(resolver),
326 origin_loop_(MessageLoop::current()),
327 resolver_proc_(resolver->effective_resolver_proc()),
328 error_(OK),
329 os_error_(0),
330 had_non_speculative_request_(false),
331 net_log_(BoundNetLog::Make(net_log,
332 NetLog::SOURCE_HOST_RESOLVER_IMPL_JOB)) {
333 net_log_.BeginEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_JOB,
334 new JobCreationParameters(key.hostname,
335 source_net_log.source()));
[email protected]b59ff372009-07-15 22:04:32336 }
337
[email protected]b59ff372009-07-15 22:04:32338 // Attaches a request to this job. The job takes ownership of |req| and will
339 // take care to delete it.
340 void AddRequest(Request* req) {
[email protected]ee094b82010-08-24 15:55:51341 req->request_net_log().BeginEvent(
342 NetLog::TYPE_HOST_RESOLVER_IMPL_JOB_ATTACH,
343 new NetLogSourceParameter("source_dependency", net_log_.source()));
344
[email protected]b59ff372009-07-15 22:04:32345 req->set_job(this);
346 requests_.push_back(req);
[email protected]252b699b2010-02-05 21:38:06347
348 if (!req->info().is_speculative())
349 had_non_speculative_request_ = true;
[email protected]b59ff372009-07-15 22:04:32350 }
351
352 // Called from origin loop.
353 void Start() {
[email protected]252b699b2010-02-05 21:38:06354 start_time_ = base::TimeTicks::Now();
355
[email protected]b59ff372009-07-15 22:04:32356 // Dispatch the job to a worker thread.
357 if (!WorkerPool::PostTask(FROM_HERE,
358 NewRunnableMethod(this, &Job::DoLookup), true)) {
359 NOTREACHED();
360
361 // Since we could be running within Resolve() right now, we can't just
362 // call OnLookupComplete(). Instead we must wait until Resolve() has
363 // returned (IO_PENDING).
364 error_ = ERR_UNEXPECTED;
365 MessageLoop::current()->PostTask(
366 FROM_HERE, NewRunnableMethod(this, &Job::OnLookupComplete));
367 }
368 }
369
370 // Cancels the current job. Callable from origin thread.
371 void Cancel() {
[email protected]ee094b82010-08-24 15:55:51372 net_log_.AddEvent(NetLog::TYPE_CANCELLED, NULL);
373
[email protected]b59ff372009-07-15 22:04:32374 HostResolver* resolver = resolver_;
375 resolver_ = NULL;
376
377 // Mark the job as cancelled, so when worker thread completes it will
378 // not try to post completion to origin loop.
379 {
380 AutoLock locked(origin_loop_lock_);
381 origin_loop_ = NULL;
382 }
383
[email protected]ee094b82010-08-24 15:55:51384 // End here to prevent issues when a Job outlives the HostResolver that
385 // spawned it.
386 net_log_.EndEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_JOB, NULL);
387
[email protected]1877a2212009-09-18 21:09:26388 // We will call HostResolverImpl::CancelRequest(Request*) on each one
[email protected]27f99c82009-10-29 22:21:00389 // in order to notify any observers.
[email protected]b59ff372009-07-15 22:04:32390 for (RequestsList::const_iterator it = requests_.begin();
391 it != requests_.end(); ++it) {
392 HostResolverImpl::Request* req = *it;
393 if (!req->was_cancelled())
394 resolver->CancelRequest(req);
395 }
396 }
397
398 // Called from origin thread.
399 bool was_cancelled() const {
400 return resolver_ == NULL;
401 }
402
403 // Called from origin thread.
[email protected]123ab1e32009-10-21 19:12:57404 const Key& key() const {
405 return key_;
[email protected]b59ff372009-07-15 22:04:32406 }
407
[email protected]a2fbebe2010-02-05 01:40:12408 int id() const {
409 return id_;
410 }
411
[email protected]252b699b2010-02-05 21:38:06412 base::TimeTicks start_time() const {
413 return start_time_;
414 }
415
[email protected]b59ff372009-07-15 22:04:32416 // Called from origin thread.
417 const RequestsList& requests() const {
418 return requests_;
419 }
420
[email protected]68ad3ee2010-01-30 03:45:39421 // Returns the first request attached to the job.
422 const Request* initial_request() const {
423 DCHECK_EQ(origin_loop_, MessageLoop::current());
424 DCHECK(!requests_.empty());
425 return requests_[0];
426 }
427
[email protected]137af622010-02-05 02:14:35428 // Returns true if |req_info| can be fulfilled by this job.
429 bool CanServiceRequest(const RequestInfo& req_info) const {
430 return key_ == resolver_->GetEffectiveKeyForRequest(req_info);
431 }
432
[email protected]b59ff372009-07-15 22:04:32433 private:
[email protected]5389bc72009-11-05 23:34:24434 friend class base::RefCountedThreadSafe<HostResolverImpl::Job>;
435
436 ~Job() {
437 // Free the requests attached to this job.
438 STLDeleteElements(&requests_);
439 }
440
[email protected]6c710ee2010-05-07 07:51:16441 // WARNING: This code runs inside a worker pool. The shutdown code cannot
442 // wait for it to finish, so we must be very careful here about using other
443 // objects (like MessageLoops, Singletons, etc). During shutdown these objects
444 // may no longer exist.
[email protected]b59ff372009-07-15 22:04:32445 void DoLookup() {
446 // Running on the worker thread
[email protected]123ab1e32009-10-21 19:12:57447 error_ = ResolveAddrInfo(resolver_proc_,
448 key_.hostname,
449 key_.address_family,
[email protected]5ea28dea2010-04-08 15:35:13450 key_.host_resolver_flags,
[email protected]21526002010-05-16 19:42:46451 &results_,
452 &os_error_);
[email protected]b59ff372009-07-15 22:04:32453
[email protected]b59ff372009-07-15 22:04:32454 // The origin loop could go away while we are trying to post to it, so we
455 // need to call its PostTask method inside a lock. See ~HostResolver.
456 {
457 AutoLock locked(origin_loop_lock_);
458 if (origin_loop_) {
[email protected]6c710ee2010-05-07 07:51:16459 origin_loop_->PostTask(FROM_HERE,
460 NewRunnableMethod(this, &Job::OnLookupComplete));
[email protected]b59ff372009-07-15 22:04:32461 }
462 }
[email protected]b59ff372009-07-15 22:04:32463 }
464
465 // Callback for when DoLookup() completes (runs on origin thread).
466 void OnLookupComplete() {
467 // Should be running on origin loop.
468 // TODO(eroman): this is being hit by URLRequestTest.CancelTest*,
469 // because MessageLoop::current() == NULL.
470 //DCHECK_EQ(origin_loop_, MessageLoop::current());
471 DCHECK(error_ || results_.head());
472
[email protected]252b699b2010-02-05 21:38:06473 base::TimeDelta job_duration = base::TimeTicks::Now() - start_time_;
474
[email protected]252b699b2010-02-05 21:38:06475 if (had_non_speculative_request_) {
476 // TODO(eroman): Add histogram for job times of non-speculative
477 // requests.
478 }
479
[email protected]21526002010-05-16 19:42:46480 if (error_ != OK) {
481 UMA_HISTOGRAM_CUSTOM_ENUMERATION("Net.OSErrorsForGetAddrinfo",
482 std::abs(os_error_),
483 GetAllGetAddrinfoOSErrors());
484 }
[email protected]f2d8c4212010-02-02 00:56:35485
[email protected]b59ff372009-07-15 22:04:32486 if (was_cancelled())
487 return;
488
[email protected]ee094b82010-08-24 15:55:51489 scoped_refptr<NetLog::EventParameters> params;
490 if (error_ != OK) {
491 params = new HostResolveFailedParams(error_, os_error_);
492 } else {
493 params = new AddressListNetLogParam(results_);
494 }
495
496 // End here to prevent issues when a Job outlives the HostResolver that
497 // spawned it.
498 net_log_.EndEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_JOB, params);
499
[email protected]b59ff372009-07-15 22:04:32500 DCHECK(!requests_.empty());
501
502 // Use the port number of the first request.
503 if (error_ == OK)
504 results_.SetPort(requests_[0]->port());
505
[email protected]21526002010-05-16 19:42:46506 resolver_->OnJobComplete(this, error_, os_error_, results_);
[email protected]b59ff372009-07-15 22:04:32507 }
508
[email protected]f2d8c4212010-02-02 00:56:35509 // Immutable. Can be read from either thread,
510 const int id_;
511
[email protected]b59ff372009-07-15 22:04:32512 // Set on the origin thread, read on the worker thread.
[email protected]123ab1e32009-10-21 19:12:57513 Key key_;
[email protected]b59ff372009-07-15 22:04:32514
515 // Only used on the origin thread (where Resolve was called).
516 HostResolverImpl* resolver_;
517 RequestsList requests_; // The requests waiting on this job.
518
519 // Used to post ourselves onto the origin thread.
520 Lock origin_loop_lock_;
521 MessageLoop* origin_loop_;
522
523 // Hold an owning reference to the HostResolverProc that we are going to use.
524 // This may not be the current resolver procedure by the time we call
525 // ResolveAddrInfo, but that's OK... we'll use it anyways, and the owning
526 // reference ensures that it remains valid until we are done.
527 scoped_refptr<HostResolverProc> resolver_proc_;
528
529 // Assigned on the worker thread, read on the origin thread.
530 int error_;
[email protected]21526002010-05-16 19:42:46531 int os_error_;
[email protected]252b699b2010-02-05 21:38:06532
533 // True if a non-speculative request was ever attached to this job
534 // (regardless of whether or not it was later cancelled.
535 // This boolean is used for histogramming the duration of jobs used to
536 // service non-speculative requests.
537 bool had_non_speculative_request_;
538
[email protected]b59ff372009-07-15 22:04:32539 AddressList results_;
540
[email protected]252b699b2010-02-05 21:38:06541 // The time when the job was started.
542 base::TimeTicks start_time_;
543
[email protected]ee094b82010-08-24 15:55:51544 BoundNetLog net_log_;
545
[email protected]b59ff372009-07-15 22:04:32546 DISALLOW_COPY_AND_ASSIGN(Job);
547};
548
549//-----------------------------------------------------------------------------
550
[email protected]0f8f1b432010-03-16 19:06:03551// This class represents a request to the worker pool for a "probe for IPv6
552// support" call.
553class HostResolverImpl::IPv6ProbeJob
554 : public base::RefCountedThreadSafe<HostResolverImpl::IPv6ProbeJob> {
555 public:
556 explicit IPv6ProbeJob(HostResolverImpl* resolver)
557 : resolver_(resolver),
558 origin_loop_(MessageLoop::current()) {
[email protected]a9af7112010-05-08 00:56:01559 DCHECK(!was_cancelled());
[email protected]0f8f1b432010-03-16 19:06:03560 }
561
562 void Start() {
[email protected]a9af7112010-05-08 00:56:01563 if (was_cancelled())
564 return;
[email protected]0f8f1b432010-03-16 19:06:03565 DCHECK(IsOnOriginThread());
[email protected]f092e64b2010-03-17 00:39:18566 const bool kIsSlow = true;
[email protected]0f8f1b432010-03-16 19:06:03567 WorkerPool::PostTask(
[email protected]f092e64b2010-03-17 00:39:18568 FROM_HERE, NewRunnableMethod(this, &IPv6ProbeJob::DoProbe), kIsSlow);
[email protected]0f8f1b432010-03-16 19:06:03569 }
570
571 // Cancels the current job.
572 void Cancel() {
[email protected]a9af7112010-05-08 00:56:01573 if (was_cancelled())
574 return;
[email protected]0f8f1b432010-03-16 19:06:03575 DCHECK(IsOnOriginThread());
576 resolver_ = NULL; // Read/write ONLY on origin thread.
577 {
578 AutoLock locked(origin_loop_lock_);
579 // Origin loop may be destroyed before we can use it!
[email protected]a9af7112010-05-08 00:56:01580 origin_loop_ = NULL; // Write ONLY on origin thread.
[email protected]0f8f1b432010-03-16 19:06:03581 }
582 }
583
[email protected]0f8f1b432010-03-16 19:06:03584 private:
585 friend class base::RefCountedThreadSafe<HostResolverImpl::IPv6ProbeJob>;
586
587 ~IPv6ProbeJob() {
588 }
589
[email protected]a9af7112010-05-08 00:56:01590 // Should be run on |orgin_thread_|, but that may not be well defined now.
591 bool was_cancelled() const {
592 if (!resolver_ || !origin_loop_) {
593 DCHECK(!resolver_);
594 DCHECK(!origin_loop_);
595 return true;
596 }
597 return false;
598 }
599
[email protected]0f8f1b432010-03-16 19:06:03600 // Run on worker thread.
601 void DoProbe() {
602 // Do actual testing on this thread, as it takes 40-100ms.
603 AddressFamily family = IPv6Supported() ? ADDRESS_FAMILY_UNSPECIFIED
604 : ADDRESS_FAMILY_IPV4;
605
606 Task* reply = NewRunnableMethod(this, &IPv6ProbeJob::OnProbeComplete,
607 family);
608
609 // The origin loop could go away while we are trying to post to it, so we
610 // need to call its PostTask method inside a lock. See ~HostResolver.
611 {
612 AutoLock locked(origin_loop_lock_);
613 if (origin_loop_) {
614 origin_loop_->PostTask(FROM_HERE, reply);
615 return;
616 }
617 }
618
619 // We didn't post, so delete the reply.
620 delete reply;
621 }
622
623 // Callback for when DoProbe() completes (runs on origin thread).
624 void OnProbeComplete(AddressFamily address_family) {
[email protected]a9af7112010-05-08 00:56:01625 if (was_cancelled())
626 return;
[email protected]0f8f1b432010-03-16 19:06:03627 DCHECK(IsOnOriginThread());
[email protected]a9af7112010-05-08 00:56:01628 resolver_->IPv6ProbeSetDefaultAddressFamily(address_family);
[email protected]0f8f1b432010-03-16 19:06:03629 }
630
631 bool IsOnOriginThread() const {
632 return !MessageLoop::current() || origin_loop_ == MessageLoop::current();
633 }
634
635 // Used/set only on origin thread.
636 HostResolverImpl* resolver_;
637
638 // Used to post ourselves onto the origin thread.
639 Lock origin_loop_lock_;
640 MessageLoop* origin_loop_;
641
642 DISALLOW_COPY_AND_ASSIGN(IPv6ProbeJob);
643};
644
645//-----------------------------------------------------------------------------
646
[email protected]68ad3ee2010-01-30 03:45:39647// We rely on the priority enum values being sequential having starting at 0,
648// and increasing for lower priorities.
649COMPILE_ASSERT(HIGHEST == 0u &&
650 LOWEST > HIGHEST &&
[email protected]c9c6f5c2010-07-31 01:30:03651 IDLE > LOWEST &&
652 NUM_PRIORITIES > IDLE,
[email protected]68ad3ee2010-01-30 03:45:39653 priority_indexes_incompatible);
654
655// JobPool contains all the information relating to queued requests, including
656// the limits on how many jobs are allowed to be used for this category of
657// requests.
658class HostResolverImpl::JobPool {
659 public:
660 JobPool(size_t max_outstanding_jobs, size_t max_pending_requests)
661 : num_outstanding_jobs_(0u) {
662 SetConstraints(max_outstanding_jobs, max_pending_requests);
663 }
664
665 ~JobPool() {
666 // Free the pending requests.
667 for (size_t i = 0; i < arraysize(pending_requests_); ++i)
668 STLDeleteElements(&pending_requests_[i]);
669 }
670
671 // Sets the constraints for this pool. See SetPoolConstraints() for the
672 // specific meaning of these parameters.
673 void SetConstraints(size_t max_outstanding_jobs,
674 size_t max_pending_requests) {
[email protected]b1f031dd2010-03-02 23:19:33675 CHECK_NE(max_outstanding_jobs, 0u);
[email protected]68ad3ee2010-01-30 03:45:39676 max_outstanding_jobs_ = max_outstanding_jobs;
677 max_pending_requests_ = max_pending_requests;
678 }
679
680 // Returns the number of pending requests enqueued to this pool.
681 // A pending request is one waiting to be attached to a job.
682 size_t GetNumPendingRequests() const {
683 size_t total = 0u;
684 for (size_t i = 0u; i < arraysize(pending_requests_); ++i)
685 total += pending_requests_[i].size();
686 return total;
687 }
688
689 bool HasPendingRequests() const {
690 return GetNumPendingRequests() > 0u;
691 }
692
693 // Enqueues a request to this pool. As a result of enqueing this request,
694 // the queue may have reached its maximum size. In this case, a request is
695 // evicted from the queue, and returned. Otherwise returns NULL. The caller
696 // is responsible for freeing the evicted request.
697 Request* InsertPendingRequest(Request* req) {
[email protected]ee094b82010-08-24 15:55:51698 req->request_net_log().BeginEvent(
699 NetLog::TYPE_HOST_RESOLVER_IMPL_JOB_POOL_QUEUE,
700 NULL);
701
[email protected]68ad3ee2010-01-30 03:45:39702 PendingRequestsQueue& q = pending_requests_[req->info().priority()];
703 q.push_back(req);
704
705 // If the queue is too big, kick out the lowest priority oldest request.
706 if (GetNumPendingRequests() > max_pending_requests_) {
707 // Iterate over the queues from lowest priority to highest priority.
708 for (int i = static_cast<int>(arraysize(pending_requests_)) - 1;
709 i >= 0; --i) {
710 PendingRequestsQueue& q = pending_requests_[i];
711 if (!q.empty()) {
712 Request* req = q.front();
713 q.pop_front();
[email protected]ee094b82010-08-24 15:55:51714 req->request_net_log().AddEvent(
715 NetLog::TYPE_HOST_RESOLVER_IMPL_JOB_POOL_QUEUE_EVICTED, NULL);
716 req->request_net_log().EndEvent(
717 NetLog::TYPE_HOST_RESOLVER_IMPL_JOB_POOL_QUEUE, NULL);
[email protected]68ad3ee2010-01-30 03:45:39718 return req;
719 }
720 }
721 }
722
723 return NULL;
724 }
725
726 // Erases |req| from this container. Caller is responsible for freeing
727 // |req| afterwards.
728 void RemovePendingRequest(Request* req) {
729 PendingRequestsQueue& q = pending_requests_[req->info().priority()];
730 PendingRequestsQueue::iterator it = std::find(q.begin(), q.end(), req);
731 DCHECK(it != q.end());
732 q.erase(it);
[email protected]ee094b82010-08-24 15:55:51733 req->request_net_log().EndEvent(
734 NetLog::TYPE_HOST_RESOLVER_IMPL_JOB_POOL_QUEUE, NULL);
[email protected]68ad3ee2010-01-30 03:45:39735 }
736
737 // Removes and returns the highest priority pending request.
738 Request* RemoveTopPendingRequest() {
739 DCHECK(HasPendingRequests());
740
741 for (size_t i = 0u; i < arraysize(pending_requests_); ++i) {
742 PendingRequestsQueue& q = pending_requests_[i];
743 if (!q.empty()) {
744 Request* req = q.front();
745 q.pop_front();
[email protected]ee094b82010-08-24 15:55:51746 req->request_net_log().EndEvent(
747 NetLog::TYPE_HOST_RESOLVER_IMPL_JOB_POOL_QUEUE, NULL);
[email protected]68ad3ee2010-01-30 03:45:39748 return req;
749 }
750 }
751
752 NOTREACHED();
753 return NULL;
754 }
755
756 // Keeps track of a job that was just added/removed, and belongs to this pool.
757 void AdjustNumOutstandingJobs(int offset) {
758 DCHECK(offset == 1 || (offset == -1 && num_outstanding_jobs_ > 0u));
759 num_outstanding_jobs_ += offset;
760 }
761
[email protected]35ddc282010-09-21 23:42:06762 void ResetNumOutstandingJobs() {
763 num_outstanding_jobs_ = 0;
764 }
765
[email protected]68ad3ee2010-01-30 03:45:39766 // Returns true if a new job can be created for this pool.
767 bool CanCreateJob() const {
768 return num_outstanding_jobs_ + 1u <= max_outstanding_jobs_;
769 }
770
771 // Removes any pending requests from the queue which are for the
[email protected]137af622010-02-05 02:14:35772 // same (hostname / effective address-family) as |job|, and attaches them to
773 // |job|.
[email protected]68ad3ee2010-01-30 03:45:39774 void MoveRequestsToJob(Job* job) {
775 for (size_t i = 0u; i < arraysize(pending_requests_); ++i) {
776 PendingRequestsQueue& q = pending_requests_[i];
777 PendingRequestsQueue::iterator req_it = q.begin();
778 while (req_it != q.end()) {
779 Request* req = *req_it;
[email protected]137af622010-02-05 02:14:35780 if (job->CanServiceRequest(req->info())) {
[email protected]68ad3ee2010-01-30 03:45:39781 // Job takes ownership of |req|.
782 job->AddRequest(req);
783 req_it = q.erase(req_it);
784 } else {
785 ++req_it;
786 }
787 }
788 }
789 }
790
791 private:
792 typedef std::deque<Request*> PendingRequestsQueue;
793
794 // Maximum number of concurrent jobs allowed to be started for requests
795 // belonging to this pool.
796 size_t max_outstanding_jobs_;
797
798 // The current number of running jobs that were started for requests
799 // belonging to this pool.
800 size_t num_outstanding_jobs_;
801
802 // The maximum number of requests we allow to be waiting on a job,
803 // for this pool.
804 size_t max_pending_requests_;
805
806 // The requests which are waiting to be started for this pool.
807 PendingRequestsQueue pending_requests_[NUM_PRIORITIES];
808};
809
810//-----------------------------------------------------------------------------
811
[email protected]e95d3aca2010-01-11 22:47:43812HostResolverImpl::HostResolverImpl(
813 HostResolverProc* resolver_proc,
814 HostCache* cache,
[email protected]ee094b82010-08-24 15:55:51815 size_t max_jobs,
816 NetLog* net_log)
[email protected]112bd462009-12-10 07:23:40817 : cache_(cache),
[email protected]68ad3ee2010-01-30 03:45:39818 max_jobs_(max_jobs),
[email protected]123ab1e32009-10-21 19:12:57819 next_request_id_(0),
[email protected]f2d8c4212010-02-02 00:56:35820 next_job_id_(0),
[email protected]123ab1e32009-10-21 19:12:57821 resolver_proc_(resolver_proc),
[email protected]0c7798452009-10-26 17:59:51822 default_address_family_(ADDRESS_FAMILY_UNSPECIFIED),
[email protected]e95d3aca2010-01-11 22:47:43823 shutdown_(false),
[email protected]2f3bc65c2010-07-23 17:47:10824 ipv6_probe_monitoring_(false),
[email protected]ee094b82010-08-24 15:55:51825 additional_resolver_flags_(0),
826 net_log_(net_log) {
[email protected]68ad3ee2010-01-30 03:45:39827 DCHECK_GT(max_jobs, 0u);
828
829 // It is cumbersome to expose all of the constraints in the constructor,
830 // so we choose some defaults, which users can override later.
831 job_pools_[POOL_NORMAL] = new JobPool(max_jobs, 100u * max_jobs);
832
[email protected]b59ff372009-07-15 22:04:32833#if defined(OS_WIN)
834 EnsureWinsockInit();
835#endif
[email protected]2f3bc65c2010-07-23 17:47:10836#if defined(OS_LINUX)
837 if (HaveOnlyLoopbackAddresses())
838 additional_resolver_flags_ |= HOST_RESOLVER_LOOPBACK_ONLY;
839#endif
[email protected]66761b952010-06-25 21:30:38840 NetworkChangeNotifier::AddObserver(this);
[email protected]b59ff372009-07-15 22:04:32841}
842
843HostResolverImpl::~HostResolverImpl() {
844 // Cancel the outstanding jobs. Those jobs may contain several attached
845 // requests, which will also be cancelled.
[email protected]0f8f1b432010-03-16 19:06:03846 DiscardIPv6ProbeJob();
847
[email protected]ef4c40c2010-09-01 14:42:03848 CancelAllJobs();
[email protected]b59ff372009-07-15 22:04:32849
850 // In case we are being deleted during the processing of a callback.
851 if (cur_completing_job_)
852 cur_completing_job_->Cancel();
[email protected]e95d3aca2010-01-11 22:47:43853
[email protected]66761b952010-06-25 21:30:38854 NetworkChangeNotifier::RemoveObserver(this);
[email protected]61a86c42010-04-19 22:45:53855
[email protected]68ad3ee2010-01-30 03:45:39856 // Delete the job pools.
857 for (size_t i = 0u; i < arraysize(job_pools_); ++i)
858 delete job_pools_[i];
[email protected]b59ff372009-07-15 22:04:32859}
860
[email protected]684970b2009-08-14 04:54:46861int HostResolverImpl::Resolve(const RequestInfo& info,
[email protected]b59ff372009-07-15 22:04:32862 AddressList* addresses,
863 CompletionCallback* callback,
[email protected]684970b2009-08-14 04:54:46864 RequestHandle* out_req,
[email protected]ee094b82010-08-24 15:55:51865 const BoundNetLog& source_net_log) {
[email protected]1ac6af92010-06-03 21:00:14866 DCHECK(CalledOnValidThread());
867
[email protected]b59ff372009-07-15 22:04:32868 if (shutdown_)
869 return ERR_UNEXPECTED;
870
871 // Choose a unique ID number for observers to see.
872 int request_id = next_request_id_++;
873
[email protected]ee094b82010-08-24 15:55:51874 // Make a log item for the request.
875 BoundNetLog request_net_log = BoundNetLog::Make(net_log_,
876 NetLog::SOURCE_HOST_RESOLVER_IMPL_REQUEST);
877
[email protected]9e743cd2010-03-16 07:03:53878 // Update the net log and notify registered observers.
[email protected]ee094b82010-08-24 15:55:51879 OnStartRequest(source_net_log, request_net_log, request_id, info);
[email protected]b59ff372009-07-15 22:04:32880
[email protected]123ab1e32009-10-21 19:12:57881 // Build a key that identifies the request in the cache and in the
882 // outstanding jobs map.
[email protected]137af622010-02-05 02:14:35883 Key key = GetEffectiveKeyForRequest(info);
[email protected]123ab1e32009-10-21 19:12:57884
[email protected]eaf3a3b2010-09-03 20:34:27885 // Check for IP literal.
886 IPAddressNumber ip_number;
887 if (ParseIPLiteralToNumber(info.hostname(), &ip_number)) {
888 DCHECK_EQ(key.host_resolver_flags &
889 ~(HOST_RESOLVER_CANONNAME | HOST_RESOLVER_LOOPBACK_ONLY |
890 HOST_RESOLVER_DEFAULT_FAMILY_SET_DUE_TO_NO_IPV6),
891 0) << " Unhandled flag";
892 bool ipv6_disabled = default_address_family_ == ADDRESS_FAMILY_IPV4 &&
893 !ipv6_probe_monitoring_;
894 int net_error = OK;
895 if (ip_number.size() == 16 && ipv6_disabled) {
896 net_error = ERR_NAME_NOT_RESOLVED;
897 } else {
898 AddressList result(ip_number, info.port(),
899 (key.host_resolver_flags & HOST_RESOLVER_CANONNAME));
900 *addresses = result;
901 }
902 // Update the net log and notify registered observers.
903 OnFinishRequest(source_net_log, request_net_log, request_id, info,
904 net_error, 0 /* os_error (unknown since from cache) */);
905 return net_error;
906 }
907
[email protected]b59ff372009-07-15 22:04:32908 // If we have an unexpired cache entry, use it.
[email protected]112bd462009-12-10 07:23:40909 if (info.allow_cached_response() && cache_.get()) {
910 const HostCache::Entry* cache_entry = cache_->Lookup(
[email protected]123ab1e32009-10-21 19:12:57911 key, base::TimeTicks::Now());
[email protected]b59ff372009-07-15 22:04:32912 if (cache_entry) {
[email protected]ee094b82010-08-24 15:55:51913 request_net_log.AddEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_CACHE_HIT, NULL);
[email protected]21526002010-05-16 19:42:46914 int net_error = cache_entry->error;
915 if (net_error == OK)
[email protected]112bd462009-12-10 07:23:40916 addresses->SetFrom(cache_entry->addrlist, info.port());
[email protected]b59ff372009-07-15 22:04:32917
[email protected]9e743cd2010-03-16 07:03:53918 // Update the net log and notify registered observers.
[email protected]ee094b82010-08-24 15:55:51919 OnFinishRequest(source_net_log, request_net_log, request_id, info,
920 net_error,
921 0 /* os_error (unknown since from cache) */);
[email protected]b59ff372009-07-15 22:04:32922
[email protected]21526002010-05-16 19:42:46923 return net_error;
[email protected]b59ff372009-07-15 22:04:32924 }
925 }
926
927 // If no callback was specified, do a synchronous resolution.
928 if (!callback) {
929 AddressList addrlist;
[email protected]21526002010-05-16 19:42:46930 int os_error = 0;
[email protected]b59ff372009-07-15 22:04:32931 int error = ResolveAddrInfo(
[email protected]5ea28dea2010-04-08 15:35:13932 effective_resolver_proc(), key.hostname, key.address_family,
[email protected]21526002010-05-16 19:42:46933 key.host_resolver_flags, &addrlist, &os_error);
[email protected]b59ff372009-07-15 22:04:32934 if (error == OK) {
935 addrlist.SetPort(info.port());
936 *addresses = addrlist;
937 }
938
939 // Write to cache.
[email protected]112bd462009-12-10 07:23:40940 if (cache_.get())
941 cache_->Set(key, error, addrlist, base::TimeTicks::Now());
[email protected]b59ff372009-07-15 22:04:32942
[email protected]9e743cd2010-03-16 07:03:53943 // Update the net log and notify registered observers.
[email protected]ee094b82010-08-24 15:55:51944 OnFinishRequest(source_net_log, request_net_log, request_id, info, error,
945 os_error);
[email protected]b59ff372009-07-15 22:04:32946
947 return error;
948 }
949
950 // Create a handle for this request, and pass it back to the user if they
951 // asked for it (out_req != NULL).
[email protected]ee094b82010-08-24 15:55:51952 Request* req = new Request(source_net_log, request_net_log, request_id, info,
953 callback, addresses);
[email protected]b59ff372009-07-15 22:04:32954 if (out_req)
955 *out_req = reinterpret_cast<RequestHandle>(req);
956
957 // Next we need to attach our request to a "job". This job is responsible for
958 // calling "getaddrinfo(hostname)" on a worker thread.
959 scoped_refptr<Job> job;
960
[email protected]123ab1e32009-10-21 19:12:57961 // If there is already an outstanding job to resolve |key|, use
[email protected]b59ff372009-07-15 22:04:32962 // it. This prevents starting concurrent resolves for the same hostname.
[email protected]123ab1e32009-10-21 19:12:57963 job = FindOutstandingJob(key);
[email protected]b59ff372009-07-15 22:04:32964 if (job) {
965 job->AddRequest(req);
966 } else {
[email protected]68ad3ee2010-01-30 03:45:39967 JobPool* pool = GetPoolForRequest(req);
968 if (CanCreateJobForPool(*pool)) {
969 CreateAndStartJob(req);
970 } else {
971 return EnqueueRequest(pool, req);
972 }
[email protected]b59ff372009-07-15 22:04:32973 }
974
975 // Completion happens during OnJobComplete(Job*).
976 return ERR_IO_PENDING;
977}
978
979// See OnJobComplete(Job*) for why it is important not to clean out
980// cancelled requests from Job::requests_.
981void HostResolverImpl::CancelRequest(RequestHandle req_handle) {
[email protected]1ac6af92010-06-03 21:00:14982 DCHECK(CalledOnValidThread());
[email protected]bf0b51c2009-08-01 23:46:40983 if (shutdown_) {
[email protected]ff1f61b92009-08-03 23:20:23984 // TODO(eroman): temp hack for: http://crbug.com/18373
985 // Because we destroy outstanding requests during Shutdown(),
986 // |req_handle| is already cancelled.
[email protected]bf0b51c2009-08-01 23:46:40987 LOG(ERROR) << "Called HostResolverImpl::CancelRequest() after Shutdown().";
988 StackTrace().PrintBacktrace();
989 return;
990 }
[email protected]b59ff372009-07-15 22:04:32991 Request* req = reinterpret_cast<Request*>(req_handle);
992 DCHECK(req);
[email protected]68ad3ee2010-01-30 03:45:39993
994 scoped_ptr<Request> request_deleter; // Frees at end of function.
995
996 if (!req->job()) {
997 // If the request was not attached to a job yet, it must have been
998 // enqueued into a pool. Remove it from that pool's queue.
999 // Otherwise if it was attached to a job, the job is responsible for
1000 // deleting it.
1001 JobPool* pool = GetPoolForRequest(req);
1002 pool->RemovePendingRequest(req);
1003 request_deleter.reset(req);
[email protected]ee094b82010-08-24 15:55:511004 } else {
1005 req->request_net_log().EndEvent(
1006 NetLog::TYPE_HOST_RESOLVER_IMPL_JOB_ATTACH, NULL);
[email protected]68ad3ee2010-01-30 03:45:391007 }
1008
[email protected]b59ff372009-07-15 22:04:321009 // NULL out the fields of req, to mark it as cancelled.
1010 req->MarkAsCancelled();
[email protected]ee094b82010-08-24 15:55:511011 OnCancelRequest(req->source_net_log(), req->request_net_log(), req->id(),
1012 req->info());
[email protected]b59ff372009-07-15 22:04:321013}
1014
[email protected]e95d3aca2010-01-11 22:47:431015void HostResolverImpl::AddObserver(HostResolver::Observer* observer) {
[email protected]1ac6af92010-06-03 21:00:141016 DCHECK(CalledOnValidThread());
[email protected]b59ff372009-07-15 22:04:321017 observers_.push_back(observer);
1018}
1019
[email protected]e95d3aca2010-01-11 22:47:431020void HostResolverImpl::RemoveObserver(HostResolver::Observer* observer) {
[email protected]1ac6af92010-06-03 21:00:141021 DCHECK(CalledOnValidThread());
[email protected]b59ff372009-07-15 22:04:321022 ObserversList::iterator it =
1023 std::find(observers_.begin(), observers_.end(), observer);
1024
1025 // Observer must exist.
1026 DCHECK(it != observers_.end());
1027
1028 observers_.erase(it);
1029}
1030
[email protected]0f8f1b432010-03-16 19:06:031031void HostResolverImpl::SetDefaultAddressFamily(AddressFamily address_family) {
[email protected]1ac6af92010-06-03 21:00:141032 DCHECK(CalledOnValidThread());
[email protected]0f8f1b432010-03-16 19:06:031033 ipv6_probe_monitoring_ = false;
1034 DiscardIPv6ProbeJob();
1035 default_address_family_ = address_family;
1036}
1037
[email protected]f7d310e2010-10-07 16:25:111038AddressFamily HostResolverImpl::GetDefaultAddressFamily() const {
1039 return default_address_family_;
1040}
1041
[email protected]0f8f1b432010-03-16 19:06:031042void HostResolverImpl::ProbeIPv6Support() {
[email protected]1ac6af92010-06-03 21:00:141043 DCHECK(CalledOnValidThread());
[email protected]0f8f1b432010-03-16 19:06:031044 DCHECK(!ipv6_probe_monitoring_);
1045 ipv6_probe_monitoring_ = true;
[email protected]61a86c42010-04-19 22:45:531046 OnIPAddressChanged(); // Give initial setup call.
[email protected]0f8f1b432010-03-16 19:06:031047}
1048
[email protected]b59ff372009-07-15 22:04:321049void HostResolverImpl::Shutdown() {
[email protected]1ac6af92010-06-03 21:00:141050 DCHECK(CalledOnValidThread());
[email protected]b59ff372009-07-15 22:04:321051
1052 // Cancel the outstanding jobs.
[email protected]ef4c40c2010-09-01 14:42:031053 CancelAllJobs();
[email protected]0a175512010-04-20 03:09:251054 DiscardIPv6ProbeJob();
[email protected]be5c6162010-07-27 21:12:511055
1056 shutdown_ = true;
[email protected]b59ff372009-07-15 22:04:321057}
1058
[email protected]68ad3ee2010-01-30 03:45:391059void HostResolverImpl::SetPoolConstraints(JobPoolIndex pool_index,
1060 size_t max_outstanding_jobs,
1061 size_t max_pending_requests) {
[email protected]1ac6af92010-06-03 21:00:141062 DCHECK(CalledOnValidThread());
[email protected]b1f031dd2010-03-02 23:19:331063 CHECK_GE(pool_index, 0);
1064 CHECK_LT(pool_index, POOL_COUNT);
[email protected]68ad3ee2010-01-30 03:45:391065 CHECK(jobs_.empty()) << "Can only set constraints during setup";
1066 JobPool* pool = job_pools_[pool_index];
1067 pool->SetConstraints(max_outstanding_jobs, max_pending_requests);
1068}
1069
[email protected]b59ff372009-07-15 22:04:321070void HostResolverImpl::AddOutstandingJob(Job* job) {
[email protected]123ab1e32009-10-21 19:12:571071 scoped_refptr<Job>& found_job = jobs_[job->key()];
[email protected]b59ff372009-07-15 22:04:321072 DCHECK(!found_job);
1073 found_job = job;
[email protected]68ad3ee2010-01-30 03:45:391074
1075 JobPool* pool = GetPoolForRequest(job->initial_request());
1076 pool->AdjustNumOutstandingJobs(1);
[email protected]b59ff372009-07-15 22:04:321077}
1078
[email protected]123ab1e32009-10-21 19:12:571079HostResolverImpl::Job* HostResolverImpl::FindOutstandingJob(const Key& key) {
1080 JobMap::iterator it = jobs_.find(key);
[email protected]b59ff372009-07-15 22:04:321081 if (it != jobs_.end())
1082 return it->second;
1083 return NULL;
1084}
1085
1086void HostResolverImpl::RemoveOutstandingJob(Job* job) {
[email protected]123ab1e32009-10-21 19:12:571087 JobMap::iterator it = jobs_.find(job->key());
[email protected]b59ff372009-07-15 22:04:321088 DCHECK(it != jobs_.end());
1089 DCHECK_EQ(it->second.get(), job);
1090 jobs_.erase(it);
[email protected]68ad3ee2010-01-30 03:45:391091
1092 JobPool* pool = GetPoolForRequest(job->initial_request());
1093 pool->AdjustNumOutstandingJobs(-1);
[email protected]b59ff372009-07-15 22:04:321094}
1095
1096void HostResolverImpl::OnJobComplete(Job* job,
[email protected]21526002010-05-16 19:42:461097 int net_error,
1098 int os_error,
[email protected]27f99c82009-10-29 22:21:001099 const AddressList& addrlist) {
[email protected]b59ff372009-07-15 22:04:321100 RemoveOutstandingJob(job);
1101
1102 // Write result to the cache.
[email protected]112bd462009-12-10 07:23:401103 if (cache_.get())
[email protected]21526002010-05-16 19:42:461104 cache_->Set(job->key(), net_error, addrlist, base::TimeTicks::Now());
[email protected]b59ff372009-07-15 22:04:321105
[email protected]ef4c40c2010-09-01 14:42:031106 OnJobCompleteInternal(job, net_error, os_error, addrlist);
1107}
1108
1109void HostResolverImpl::AbortJob(Job* job) {
1110 OnJobCompleteInternal(job, ERR_ABORTED, 0 /* no os_error */, AddressList());
1111}
1112
1113void HostResolverImpl::OnJobCompleteInternal(
1114 Job* job,
1115 int net_error,
1116 int os_error,
1117 const AddressList& addrlist) {
[email protected]b59ff372009-07-15 22:04:321118 // Make a note that we are executing within OnJobComplete() in case the
1119 // HostResolver is deleted by a callback invocation.
1120 DCHECK(!cur_completing_job_);
1121 cur_completing_job_ = job;
1122
[email protected]68ad3ee2010-01-30 03:45:391123 // Try to start any queued requests now that a job-slot has freed up.
1124 ProcessQueuedRequests();
1125
[email protected]b59ff372009-07-15 22:04:321126 // Complete all of the requests that were attached to the job.
1127 for (RequestsList::const_iterator it = job->requests().begin();
1128 it != job->requests().end(); ++it) {
1129 Request* req = *it;
1130 if (!req->was_cancelled()) {
1131 DCHECK_EQ(job, req->job());
[email protected]ee094b82010-08-24 15:55:511132 req->request_net_log().EndEvent(
1133 NetLog::TYPE_HOST_RESOLVER_IMPL_JOB_ATTACH, NULL);
[email protected]b59ff372009-07-15 22:04:321134
[email protected]9e743cd2010-03-16 07:03:531135 // Update the net log and notify registered observers.
[email protected]ee094b82010-08-24 15:55:511136 OnFinishRequest(req->source_net_log(), req->request_net_log(), req->id(),
1137 req->info(), net_error, os_error);
[email protected]b59ff372009-07-15 22:04:321138
[email protected]21526002010-05-16 19:42:461139 req->OnComplete(net_error, addrlist);
[email protected]b59ff372009-07-15 22:04:321140
1141 // Check if the job was cancelled as a result of running the callback.
1142 // (Meaning that |this| was deleted).
1143 if (job->was_cancelled())
1144 return;
1145 }
1146 }
1147
1148 cur_completing_job_ = NULL;
1149}
1150
[email protected]ee094b82010-08-24 15:55:511151void HostResolverImpl::OnStartRequest(const BoundNetLog& source_net_log,
1152 const BoundNetLog& request_net_log,
[email protected]54e13772009-08-14 03:01:091153 int request_id,
1154 const RequestInfo& info) {
[email protected]ee094b82010-08-24 15:55:511155 source_net_log.BeginEvent(
1156 NetLog::TYPE_HOST_RESOLVER_IMPL,
1157 new NetLogSourceParameter("source_dependency", request_net_log.source()));
1158
1159 request_net_log.BeginEvent(
1160 NetLog::TYPE_HOST_RESOLVER_IMPL_REQUEST,
1161 new RequestInfoParameters(info, source_net_log.source()));
[email protected]54e13772009-08-14 03:01:091162
1163 // Notify the observers of the start.
1164 if (!observers_.empty()) {
[email protected]54e13772009-08-14 03:01:091165 for (ObserversList::iterator it = observers_.begin();
1166 it != observers_.end(); ++it) {
1167 (*it)->OnStartResolution(request_id, info);
1168 }
[email protected]b59ff372009-07-15 22:04:321169 }
1170}
1171
[email protected]ee094b82010-08-24 15:55:511172void HostResolverImpl::OnFinishRequest(const BoundNetLog& source_net_log,
1173 const BoundNetLog& request_net_log,
[email protected]54e13772009-08-14 03:01:091174 int request_id,
1175 const RequestInfo& info,
[email protected]21526002010-05-16 19:42:461176 int net_error,
[email protected]ee094b82010-08-24 15:55:511177 int os_error) {
[email protected]21526002010-05-16 19:42:461178 bool was_resolved = net_error == OK;
1179
[email protected]54e13772009-08-14 03:01:091180 // Notify the observers of the completion.
1181 if (!observers_.empty()) {
[email protected]54e13772009-08-14 03:01:091182 for (ObserversList::iterator it = observers_.begin();
1183 it != observers_.end(); ++it) {
1184 (*it)->OnFinishResolutionWithStatus(request_id, was_resolved, info);
1185 }
[email protected]b59ff372009-07-15 22:04:321186 }
[email protected]54e13772009-08-14 03:01:091187
[email protected]ee094b82010-08-24 15:55:511188 // Log some extra parameters on failure for synchronous requests.
[email protected]21526002010-05-16 19:42:461189 scoped_refptr<NetLog::EventParameters> params;
[email protected]ee094b82010-08-24 15:55:511190 if (!was_resolved) {
1191 params = new HostResolveFailedParams(net_error, os_error);
1192 }
[email protected]21526002010-05-16 19:42:461193
[email protected]ee094b82010-08-24 15:55:511194 request_net_log.EndEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_REQUEST, params);
1195 source_net_log.EndEvent(NetLog::TYPE_HOST_RESOLVER_IMPL, NULL);
[email protected]b59ff372009-07-15 22:04:321196}
1197
[email protected]ee094b82010-08-24 15:55:511198void HostResolverImpl::OnCancelRequest(const BoundNetLog& source_net_log,
1199 const BoundNetLog& request_net_log,
[email protected]54e13772009-08-14 03:01:091200 int request_id,
1201 const RequestInfo& info) {
[email protected]ee094b82010-08-24 15:55:511202 request_net_log.AddEvent(NetLog::TYPE_CANCELLED, NULL);
[email protected]54e13772009-08-14 03:01:091203
1204 // Notify the observers of the cancellation.
1205 if (!observers_.empty()) {
[email protected]54e13772009-08-14 03:01:091206 for (ObserversList::iterator it = observers_.begin();
1207 it != observers_.end(); ++it) {
1208 (*it)->OnCancelResolution(request_id, info);
1209 }
[email protected]b59ff372009-07-15 22:04:321210 }
[email protected]54e13772009-08-14 03:01:091211
[email protected]ee094b82010-08-24 15:55:511212 request_net_log.EndEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_REQUEST, NULL);
1213 source_net_log.EndEvent(NetLog::TYPE_HOST_RESOLVER_IMPL, NULL);
[email protected]b59ff372009-07-15 22:04:321214}
1215
[email protected]61a86c42010-04-19 22:45:531216void HostResolverImpl::OnIPAddressChanged() {
[email protected]e95d3aca2010-01-11 22:47:431217 if (cache_.get())
1218 cache_->clear();
[email protected]0f8f1b432010-03-16 19:06:031219 if (ipv6_probe_monitoring_) {
[email protected]0a175512010-04-20 03:09:251220 DCHECK(!shutdown_);
1221 if (shutdown_)
1222 return;
[email protected]0f8f1b432010-03-16 19:06:031223 DiscardIPv6ProbeJob();
1224 ipv6_probe_job_ = new IPv6ProbeJob(this);
1225 ipv6_probe_job_->Start();
1226 }
[email protected]2f3bc65c2010-07-23 17:47:101227#if defined(OS_LINUX)
1228 if (HaveOnlyLoopbackAddresses()) {
1229 additional_resolver_flags_ |= HOST_RESOLVER_LOOPBACK_ONLY;
1230 } else {
1231 additional_resolver_flags_ &= ~HOST_RESOLVER_LOOPBACK_ONLY;
1232 }
1233#endif
[email protected]35ddc282010-09-21 23:42:061234 AbortAllInProgressJobs();
1235 // |this| may be deleted inside AbortAllInProgressJobs().
[email protected]0f8f1b432010-03-16 19:06:031236}
1237
1238void HostResolverImpl::DiscardIPv6ProbeJob() {
1239 if (ipv6_probe_job_.get()) {
1240 ipv6_probe_job_->Cancel();
1241 ipv6_probe_job_ = NULL;
1242 }
1243}
1244
1245void HostResolverImpl::IPv6ProbeSetDefaultAddressFamily(
1246 AddressFamily address_family) {
1247 DCHECK(address_family == ADDRESS_FAMILY_UNSPECIFIED ||
1248 address_family == ADDRESS_FAMILY_IPV4);
[email protected]f092e64b2010-03-17 00:39:181249 if (default_address_family_ != address_family) {
1250 LOG(INFO) << "IPv6Probe forced AddressFamily setting to "
1251 << ((address_family == ADDRESS_FAMILY_UNSPECIFIED)
1252 ? "ADDRESS_FAMILY_UNSPECIFIED"
1253 : "ADDRESS_FAMILY_IPV4");
1254 }
[email protected]0f8f1b432010-03-16 19:06:031255 default_address_family_ = address_family;
1256 // Drop reference since the job has called us back.
1257 DiscardIPv6ProbeJob();
[email protected]e95d3aca2010-01-11 22:47:431258}
1259
[email protected]68ad3ee2010-01-30 03:45:391260// static
1261HostResolverImpl::JobPoolIndex HostResolverImpl::GetJobPoolIndexForRequest(
1262 const Request* req) {
1263 return POOL_NORMAL;
1264}
1265
1266bool HostResolverImpl::CanCreateJobForPool(const JobPool& pool) const {
1267 DCHECK_LE(jobs_.size(), max_jobs_);
1268
1269 // We can't create another job if it would exceed the global total.
1270 if (jobs_.size() + 1 > max_jobs_)
1271 return false;
1272
1273 // Check whether the pool's constraints are met.
1274 return pool.CanCreateJob();
1275}
1276
1277void HostResolverImpl::ProcessQueuedRequests() {
1278 // Find the highest priority request that can be scheduled.
1279 Request* top_req = NULL;
1280 for (size_t i = 0; i < arraysize(job_pools_); ++i) {
1281 JobPool* pool = job_pools_[i];
1282 if (pool->HasPendingRequests() && CanCreateJobForPool(*pool)) {
1283 top_req = pool->RemoveTopPendingRequest();
1284 break;
1285 }
1286 }
1287
1288 if (!top_req)
1289 return;
1290
1291 scoped_refptr<Job> job = CreateAndStartJob(top_req);
1292
1293 // Search for any other pending request which can piggy-back off this job.
1294 for (size_t pool_i = 0; pool_i < POOL_COUNT; ++pool_i) {
1295 JobPool* pool = job_pools_[pool_i];
1296 pool->MoveRequestsToJob(job);
1297 }
1298}
1299
[email protected]137af622010-02-05 02:14:351300HostResolverImpl::Key HostResolverImpl::GetEffectiveKeyForRequest(
1301 const RequestInfo& info) const {
[email protected]eaf3a3b2010-09-03 20:34:271302 HostResolverFlags effective_flags =
1303 info.host_resolver_flags() | additional_resolver_flags_;
[email protected]137af622010-02-05 02:14:351304 AddressFamily effective_address_family = info.address_family();
[email protected]eaf3a3b2010-09-03 20:34:271305 if (effective_address_family == ADDRESS_FAMILY_UNSPECIFIED &&
1306 default_address_family_ != ADDRESS_FAMILY_UNSPECIFIED) {
[email protected]137af622010-02-05 02:14:351307 effective_address_family = default_address_family_;
[email protected]eaf3a3b2010-09-03 20:34:271308 if (ipv6_probe_monitoring_)
1309 effective_flags |= HOST_RESOLVER_DEFAULT_FAMILY_SET_DUE_TO_NO_IPV6;
1310 }
1311 return Key(info.hostname(), effective_address_family, effective_flags);
[email protected]137af622010-02-05 02:14:351312}
1313
[email protected]68ad3ee2010-01-30 03:45:391314HostResolverImpl::Job* HostResolverImpl::CreateAndStartJob(Request* req) {
1315 DCHECK(CanCreateJobForPool(*GetPoolForRequest(req)));
[email protected]137af622010-02-05 02:14:351316 Key key = GetEffectiveKeyForRequest(req->info());
[email protected]ee094b82010-08-24 15:55:511317
1318 req->request_net_log().AddEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_CREATE_JOB,
1319 NULL);
1320
1321 scoped_refptr<Job> job = new Job(next_job_id_++, this, key,
1322 req->request_net_log(), net_log_);
[email protected]68ad3ee2010-01-30 03:45:391323 job->AddRequest(req);
1324 AddOutstandingJob(job);
1325 job->Start();
[email protected]ee094b82010-08-24 15:55:511326
[email protected]68ad3ee2010-01-30 03:45:391327 return job.get();
1328}
1329
1330int HostResolverImpl::EnqueueRequest(JobPool* pool, Request* req) {
1331 scoped_ptr<Request> req_evicted_from_queue(
1332 pool->InsertPendingRequest(req));
1333
1334 // If the queue has become too large, we need to kick something out.
1335 if (req_evicted_from_queue.get()) {
1336 Request* r = req_evicted_from_queue.get();
1337 int error = ERR_HOST_RESOLVER_QUEUE_TOO_LARGE;
1338
[email protected]ee094b82010-08-24 15:55:511339 OnFinishRequest(r->source_net_log(), r->request_net_log(), r->id(),
1340 r->info(), error,
1341 0 /* os_error (not applicable) */);
[email protected]68ad3ee2010-01-30 03:45:391342
1343 if (r == req)
1344 return error;
1345
1346 r->OnComplete(error, AddressList());
1347 }
1348
1349 return ERR_IO_PENDING;
1350}
1351
[email protected]ef4c40c2010-09-01 14:42:031352void HostResolverImpl::CancelAllJobs() {
1353 JobMap jobs;
1354 jobs.swap(jobs_);
1355 for (JobMap::iterator it = jobs.begin(); it != jobs.end(); ++it)
1356 it->second->Cancel();
1357}
1358
[email protected]35ddc282010-09-21 23:42:061359void HostResolverImpl::AbortAllInProgressJobs() {
1360 for (size_t i = 0; i < arraysize(job_pools_); ++i)
1361 job_pools_[i]->ResetNumOutstandingJobs();
[email protected]ef4c40c2010-09-01 14:42:031362 JobMap jobs;
1363 jobs.swap(jobs_);
1364 for (JobMap::iterator it = jobs.begin(); it != jobs.end(); ++it) {
1365 AbortJob(it->second);
1366 it->second->Cancel();
1367 }
1368}
1369
[email protected]b59ff372009-07-15 22:04:321370} // namespace net