blob: aa1ed9cce981d5e1122019ff33078eef9ce2fa06 [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"
30#include "net/base/host_resolver_proc.h"
[email protected]95d9c6532010-08-18 16:38:0031#include "net/base/net_log.h"
[email protected]2bb04442010-08-18 18:01:1532#include "net/base/net_errors.h"
[email protected]0f8f1b432010-03-16 19:06:0333#include "net/base/net_util.h"
[email protected]b59ff372009-07-15 22:04:3234
35#if defined(OS_WIN)
36#include "net/base/winsock_init.h"
37#endif
38
39namespace net {
40
[email protected]e95d3aca2010-01-11 22:47:4341namespace {
42
43HostCache* CreateDefaultCache() {
[email protected]b59ff372009-07-15 22:04:3244 static const size_t kMaxHostCacheEntries = 100;
[email protected]112bd462009-12-10 07:23:4045
46 HostCache* cache = new HostCache(
47 kMaxHostCacheEntries,
48 base::TimeDelta::FromMinutes(1),
[email protected]72bceac2010-06-17 21:45:0849 base::TimeDelta::FromSeconds(0)); // Disable caching of failed DNS.
[email protected]112bd462009-12-10 07:23:4050
[email protected]e95d3aca2010-01-11 22:47:4351 return cache;
52}
53
54} // anonymous namespace
55
[email protected]2bb04442010-08-18 18:01:1556HostResolver* CreateSystemHostResolver(size_t max_concurrent_resolves) {
[email protected]68ad3ee2010-01-30 03:45:3957 // Maximum of 50 concurrent threads.
58 // TODO(eroman): Adjust this, do some A/B experiments.
[email protected]962b98212010-07-17 03:37:5159 static const size_t kDefaultMaxJobs = 50u;
60
61 if (max_concurrent_resolves == HostResolver::kDefaultParallelism)
62 max_concurrent_resolves = kDefaultMaxJobs;
[email protected]68ad3ee2010-01-30 03:45:3963
[email protected]66761b952010-06-25 21:30:3864 HostResolverImpl* resolver =
[email protected]962b98212010-07-17 03:37:5165 new HostResolverImpl(NULL, CreateDefaultCache(),
[email protected]2bb04442010-08-18 18:01:1566 max_concurrent_resolves);
[email protected]68ad3ee2010-01-30 03:45:3967
68 return resolver;
[email protected]b59ff372009-07-15 22:04:3269}
70
71static int ResolveAddrInfo(HostResolverProc* resolver_proc,
[email protected]123ab1e32009-10-21 19:12:5772 const std::string& host,
73 AddressFamily address_family,
[email protected]5ea28dea2010-04-08 15:35:1374 HostResolverFlags host_resolver_flags,
[email protected]21526002010-05-16 19:42:4675 AddressList* out,
76 int* os_error) {
[email protected]b59ff372009-07-15 22:04:3277 if (resolver_proc) {
78 // Use the custom procedure.
[email protected]5ea28dea2010-04-08 15:35:1379 return resolver_proc->Resolve(host, address_family,
[email protected]21526002010-05-16 19:42:4680 host_resolver_flags, out, os_error);
[email protected]b59ff372009-07-15 22:04:3281 } else {
82 // Use the system procedure (getaddrinfo).
[email protected]5ea28dea2010-04-08 15:35:1383 return SystemHostResolverProc(host, address_family,
[email protected]21526002010-05-16 19:42:4684 host_resolver_flags, out, os_error);
[email protected]b59ff372009-07-15 22:04:3285 }
86}
87
[email protected]21526002010-05-16 19:42:4688// Extra parameters to attach to the NetLog when the resolve failed.
89class HostResolveFailedParams : public NetLog::EventParameters {
90 public:
[email protected]2bb04442010-08-18 18:01:1591 HostResolveFailedParams(int net_error, int os_error, bool was_from_cache)
[email protected]21526002010-05-16 19:42:4692 : net_error_(net_error),
[email protected]2bb04442010-08-18 18:01:1593 os_error_(os_error),
94 was_from_cache_(was_from_cache) {
[email protected]21526002010-05-16 19:42:4695 }
96
97 virtual Value* ToValue() const {
98 DictionaryValue* dict = new DictionaryValue();
[email protected]ccaff652010-07-31 06:28:2099 dict->SetInteger("net_error", net_error_);
[email protected]2bb04442010-08-18 18:01:15100 dict->SetBoolean("was_from_cache", was_from_cache_);
[email protected]21526002010-05-16 19:42:46101
102 if (os_error_) {
[email protected]ccaff652010-07-31 06:28:20103 dict->SetInteger("os_error", os_error_);
[email protected]21526002010-05-16 19:42:46104#if defined(OS_POSIX)
[email protected]ccaff652010-07-31 06:28:20105 dict->SetString("os_error_string", gai_strerror(os_error_));
[email protected]21526002010-05-16 19:42:46106#elif defined(OS_WIN)
107 // Map the error code to a human-readable string.
108 LPWSTR error_string = NULL;
109 int size = FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
110 FORMAT_MESSAGE_FROM_SYSTEM,
111 0, // Use the internal message table.
112 os_error_,
113 0, // Use default language.
114 (LPWSTR)&error_string,
115 0, // Buffer size.
116 0); // Arguments (unused).
[email protected]ccaff652010-07-31 06:28:20117 dict->SetString("os_error_string", WideToUTF8(error_string));
[email protected]21526002010-05-16 19:42:46118 LocalFree(error_string);
119#endif
120 }
121
122 return dict;
123 }
124
125 private:
126 const int net_error_;
127 const int os_error_;
[email protected]2bb04442010-08-18 18:01:15128 const bool was_from_cache_;
[email protected]21526002010-05-16 19:42:46129};
130
131// Gets a list of the likely error codes that getaddrinfo() can return
132// (non-exhaustive). These are the error codes that we will track via
133// a histogram.
134std::vector<int> GetAllGetAddrinfoOSErrors() {
135 int os_errors[] = {
136#if defined(OS_POSIX)
137 EAI_ADDRFAMILY,
138 EAI_AGAIN,
139 EAI_BADFLAGS,
140 EAI_FAIL,
141 EAI_FAMILY,
142 EAI_MEMORY,
143 EAI_NODATA,
144 EAI_NONAME,
145 EAI_SERVICE,
146 EAI_SOCKTYPE,
147 EAI_SYSTEM,
148#elif defined(OS_WIN)
149 // See: http://msdn.microsoft.com/en-us/library/ms738520(VS.85).aspx
150 WSA_NOT_ENOUGH_MEMORY,
151 WSAEAFNOSUPPORT,
152 WSAEINVAL,
153 WSAESOCKTNOSUPPORT,
154 WSAHOST_NOT_FOUND,
155 WSANO_DATA,
156 WSANO_RECOVERY,
157 WSANOTINITIALISED,
158 WSATRY_AGAIN,
159 WSATYPE_NOT_FOUND,
160#endif
161 };
162
163 // Histogram enumerations require positive numbers.
164 std::vector<int> errors;
165 for (size_t i = 0; i < arraysize(os_errors); ++i) {
166 errors.push_back(std::abs(os_errors[i]));
167 // Also add N+1 for each error, so the bucket that contains our expected
168 // error is of size 1. That way if we get unexpected error codes, they
169 // won't fall into the same buckets as the expected ones.
170 errors.push_back(std::abs(os_errors[i]) + 1);
171 }
172 return errors;
173}
174
[email protected]b59ff372009-07-15 22:04:32175//-----------------------------------------------------------------------------
176
177class HostResolverImpl::Request {
178 public:
[email protected]2bb04442010-08-18 18:01:15179 Request(const BoundNetLog& net_log,
[email protected]54e13772009-08-14 03:01:09180 int id,
181 const RequestInfo& info,
182 CompletionCallback* callback,
[email protected]b59ff372009-07-15 22:04:32183 AddressList* addresses)
[email protected]2bb04442010-08-18 18:01:15184 : net_log_(net_log),
[email protected]54e13772009-08-14 03:01:09185 id_(id),
186 info_(info),
187 job_(NULL),
188 callback_(callback),
189 addresses_(addresses) {
190 }
[email protected]b59ff372009-07-15 22:04:32191
192 // Mark the request as cancelled.
193 void MarkAsCancelled() {
194 job_ = NULL;
195 callback_ = NULL;
196 addresses_ = NULL;
197 }
198
199 bool was_cancelled() const {
200 return callback_ == NULL;
201 }
202
203 void set_job(Job* job) {
204 DCHECK(job != NULL);
205 // Identify which job the request is waiting on.
206 job_ = job;
207 }
208
209 void OnComplete(int error, const AddressList& addrlist) {
210 if (error == OK)
211 addresses_->SetFrom(addrlist, port());
212 callback_->Run(error);
213 }
214
215 int port() const {
216 return info_.port();
217 }
218
219 Job* job() const {
220 return job_;
221 }
222
[email protected]2bb04442010-08-18 18:01:15223 const BoundNetLog& net_log() {
224 return net_log_;
[email protected]54e13772009-08-14 03:01:09225 }
226
[email protected]b59ff372009-07-15 22:04:32227 int id() const {
228 return id_;
229 }
230
231 const RequestInfo& info() const {
232 return info_;
233 }
234
235 private:
[email protected]2bb04442010-08-18 18:01:15236 BoundNetLog net_log_;
[email protected]54e13772009-08-14 03:01:09237
[email protected]b59ff372009-07-15 22:04:32238 // Unique ID for this request. Used by observers to identify requests.
239 int id_;
240
241 // The request info that started the request.
242 RequestInfo info_;
243
244 // The resolve job (running in worker pool) that this request is dependent on.
245 Job* job_;
246
247 // The user's callback to invoke when the request completes.
248 CompletionCallback* callback_;
249
250 // The address list to save result into.
251 AddressList* addresses_;
252
253 DISALLOW_COPY_AND_ASSIGN(Request);
254};
255
256//-----------------------------------------------------------------------------
257
258// This class represents a request to the worker pool for a "getaddrinfo()"
259// call.
260class HostResolverImpl::Job
261 : public base::RefCountedThreadSafe<HostResolverImpl::Job> {
262 public:
[email protected]2bb04442010-08-18 18:01:15263 Job(int id, HostResolverImpl* resolver, const Key& key)
264 : id_(id),
265 key_(key),
266 resolver_(resolver),
267 origin_loop_(MessageLoop::current()),
268 resolver_proc_(resolver->effective_resolver_proc()),
269 error_(OK),
270 os_error_(0),
271 had_non_speculative_request_(false) {
[email protected]b59ff372009-07-15 22:04:32272 }
273
[email protected]b59ff372009-07-15 22:04:32274 // Attaches a request to this job. The job takes ownership of |req| and will
275 // take care to delete it.
276 void AddRequest(Request* req) {
277 req->set_job(this);
278 requests_.push_back(req);
[email protected]252b699b2010-02-05 21:38:06279
280 if (!req->info().is_speculative())
281 had_non_speculative_request_ = true;
[email protected]b59ff372009-07-15 22:04:32282 }
283
284 // Called from origin loop.
285 void Start() {
[email protected]252b699b2010-02-05 21:38:06286 start_time_ = base::TimeTicks::Now();
287
[email protected]b59ff372009-07-15 22:04:32288 // Dispatch the job to a worker thread.
289 if (!WorkerPool::PostTask(FROM_HERE,
290 NewRunnableMethod(this, &Job::DoLookup), true)) {
291 NOTREACHED();
292
293 // Since we could be running within Resolve() right now, we can't just
294 // call OnLookupComplete(). Instead we must wait until Resolve() has
295 // returned (IO_PENDING).
296 error_ = ERR_UNEXPECTED;
297 MessageLoop::current()->PostTask(
298 FROM_HERE, NewRunnableMethod(this, &Job::OnLookupComplete));
299 }
300 }
301
302 // Cancels the current job. Callable from origin thread.
303 void Cancel() {
304 HostResolver* resolver = resolver_;
305 resolver_ = NULL;
306
307 // Mark the job as cancelled, so when worker thread completes it will
308 // not try to post completion to origin loop.
309 {
310 AutoLock locked(origin_loop_lock_);
311 origin_loop_ = NULL;
312 }
313
[email protected]1877a2212009-09-18 21:09:26314 // We will call HostResolverImpl::CancelRequest(Request*) on each one
[email protected]27f99c82009-10-29 22:21:00315 // in order to notify any observers.
[email protected]b59ff372009-07-15 22:04:32316 for (RequestsList::const_iterator it = requests_.begin();
317 it != requests_.end(); ++it) {
318 HostResolverImpl::Request* req = *it;
319 if (!req->was_cancelled())
320 resolver->CancelRequest(req);
321 }
322 }
323
324 // Called from origin thread.
325 bool was_cancelled() const {
326 return resolver_ == NULL;
327 }
328
329 // Called from origin thread.
[email protected]123ab1e32009-10-21 19:12:57330 const Key& key() const {
331 return key_;
[email protected]b59ff372009-07-15 22:04:32332 }
333
[email protected]a2fbebe2010-02-05 01:40:12334 int id() const {
335 return id_;
336 }
337
[email protected]252b699b2010-02-05 21:38:06338 base::TimeTicks start_time() const {
339 return start_time_;
340 }
341
[email protected]b59ff372009-07-15 22:04:32342 // Called from origin thread.
343 const RequestsList& requests() const {
344 return requests_;
345 }
346
[email protected]68ad3ee2010-01-30 03:45:39347 // Returns the first request attached to the job.
348 const Request* initial_request() const {
349 DCHECK_EQ(origin_loop_, MessageLoop::current());
350 DCHECK(!requests_.empty());
351 return requests_[0];
352 }
353
[email protected]137af622010-02-05 02:14:35354 // Returns true if |req_info| can be fulfilled by this job.
355 bool CanServiceRequest(const RequestInfo& req_info) const {
356 return key_ == resolver_->GetEffectiveKeyForRequest(req_info);
357 }
358
[email protected]b59ff372009-07-15 22:04:32359 private:
[email protected]5389bc72009-11-05 23:34:24360 friend class base::RefCountedThreadSafe<HostResolverImpl::Job>;
361
362 ~Job() {
363 // Free the requests attached to this job.
364 STLDeleteElements(&requests_);
365 }
366
[email protected]6c710ee2010-05-07 07:51:16367 // WARNING: This code runs inside a worker pool. The shutdown code cannot
368 // wait for it to finish, so we must be very careful here about using other
369 // objects (like MessageLoops, Singletons, etc). During shutdown these objects
370 // may no longer exist.
[email protected]b59ff372009-07-15 22:04:32371 void DoLookup() {
372 // Running on the worker thread
[email protected]123ab1e32009-10-21 19:12:57373 error_ = ResolveAddrInfo(resolver_proc_,
374 key_.hostname,
375 key_.address_family,
[email protected]5ea28dea2010-04-08 15:35:13376 key_.host_resolver_flags,
[email protected]21526002010-05-16 19:42:46377 &results_,
378 &os_error_);
[email protected]b59ff372009-07-15 22:04:32379
[email protected]b59ff372009-07-15 22:04:32380 // The origin loop could go away while we are trying to post to it, so we
381 // need to call its PostTask method inside a lock. See ~HostResolver.
382 {
383 AutoLock locked(origin_loop_lock_);
384 if (origin_loop_) {
[email protected]6c710ee2010-05-07 07:51:16385 origin_loop_->PostTask(FROM_HERE,
386 NewRunnableMethod(this, &Job::OnLookupComplete));
[email protected]b59ff372009-07-15 22:04:32387 }
388 }
[email protected]b59ff372009-07-15 22:04:32389 }
390
391 // Callback for when DoLookup() completes (runs on origin thread).
392 void OnLookupComplete() {
393 // Should be running on origin loop.
394 // TODO(eroman): this is being hit by URLRequestTest.CancelTest*,
395 // because MessageLoop::current() == NULL.
396 //DCHECK_EQ(origin_loop_, MessageLoop::current());
397 DCHECK(error_ || results_.head());
398
[email protected]252b699b2010-02-05 21:38:06399 base::TimeDelta job_duration = base::TimeTicks::Now() - start_time_;
400
[email protected]252b699b2010-02-05 21:38:06401 if (had_non_speculative_request_) {
402 // TODO(eroman): Add histogram for job times of non-speculative
403 // requests.
404 }
405
[email protected]21526002010-05-16 19:42:46406 if (error_ != OK) {
407 UMA_HISTOGRAM_CUSTOM_ENUMERATION("Net.OSErrorsForGetAddrinfo",
408 std::abs(os_error_),
409 GetAllGetAddrinfoOSErrors());
410 }
[email protected]f2d8c4212010-02-02 00:56:35411
[email protected]b59ff372009-07-15 22:04:32412 if (was_cancelled())
413 return;
414
415 DCHECK(!requests_.empty());
416
417 // Use the port number of the first request.
418 if (error_ == OK)
419 results_.SetPort(requests_[0]->port());
420
[email protected]21526002010-05-16 19:42:46421 resolver_->OnJobComplete(this, error_, os_error_, results_);
[email protected]b59ff372009-07-15 22:04:32422 }
423
[email protected]f2d8c4212010-02-02 00:56:35424 // Immutable. Can be read from either thread,
425 const int id_;
426
[email protected]b59ff372009-07-15 22:04:32427 // Set on the origin thread, read on the worker thread.
[email protected]123ab1e32009-10-21 19:12:57428 Key key_;
[email protected]b59ff372009-07-15 22:04:32429
430 // Only used on the origin thread (where Resolve was called).
431 HostResolverImpl* resolver_;
432 RequestsList requests_; // The requests waiting on this job.
433
434 // Used to post ourselves onto the origin thread.
435 Lock origin_loop_lock_;
436 MessageLoop* origin_loop_;
437
438 // Hold an owning reference to the HostResolverProc that we are going to use.
439 // This may not be the current resolver procedure by the time we call
440 // ResolveAddrInfo, but that's OK... we'll use it anyways, and the owning
441 // reference ensures that it remains valid until we are done.
442 scoped_refptr<HostResolverProc> resolver_proc_;
443
444 // Assigned on the worker thread, read on the origin thread.
445 int error_;
[email protected]21526002010-05-16 19:42:46446 int os_error_;
[email protected]252b699b2010-02-05 21:38:06447
448 // True if a non-speculative request was ever attached to this job
449 // (regardless of whether or not it was later cancelled.
450 // This boolean is used for histogramming the duration of jobs used to
451 // service non-speculative requests.
452 bool had_non_speculative_request_;
453
[email protected]b59ff372009-07-15 22:04:32454 AddressList results_;
455
[email protected]252b699b2010-02-05 21:38:06456 // The time when the job was started.
457 base::TimeTicks start_time_;
458
[email protected]b59ff372009-07-15 22:04:32459 DISALLOW_COPY_AND_ASSIGN(Job);
460};
461
462//-----------------------------------------------------------------------------
463
[email protected]0f8f1b432010-03-16 19:06:03464// This class represents a request to the worker pool for a "probe for IPv6
465// support" call.
466class HostResolverImpl::IPv6ProbeJob
467 : public base::RefCountedThreadSafe<HostResolverImpl::IPv6ProbeJob> {
468 public:
469 explicit IPv6ProbeJob(HostResolverImpl* resolver)
470 : resolver_(resolver),
471 origin_loop_(MessageLoop::current()) {
[email protected]a9af7112010-05-08 00:56:01472 DCHECK(!was_cancelled());
[email protected]0f8f1b432010-03-16 19:06:03473 }
474
475 void Start() {
[email protected]a9af7112010-05-08 00:56:01476 if (was_cancelled())
477 return;
[email protected]0f8f1b432010-03-16 19:06:03478 DCHECK(IsOnOriginThread());
[email protected]f092e64b2010-03-17 00:39:18479 const bool kIsSlow = true;
[email protected]0f8f1b432010-03-16 19:06:03480 WorkerPool::PostTask(
[email protected]f092e64b2010-03-17 00:39:18481 FROM_HERE, NewRunnableMethod(this, &IPv6ProbeJob::DoProbe), kIsSlow);
[email protected]0f8f1b432010-03-16 19:06:03482 }
483
484 // Cancels the current job.
485 void Cancel() {
[email protected]a9af7112010-05-08 00:56:01486 if (was_cancelled())
487 return;
[email protected]0f8f1b432010-03-16 19:06:03488 DCHECK(IsOnOriginThread());
489 resolver_ = NULL; // Read/write ONLY on origin thread.
490 {
491 AutoLock locked(origin_loop_lock_);
492 // Origin loop may be destroyed before we can use it!
[email protected]a9af7112010-05-08 00:56:01493 origin_loop_ = NULL; // Write ONLY on origin thread.
[email protected]0f8f1b432010-03-16 19:06:03494 }
495 }
496
[email protected]0f8f1b432010-03-16 19:06:03497 private:
498 friend class base::RefCountedThreadSafe<HostResolverImpl::IPv6ProbeJob>;
499
500 ~IPv6ProbeJob() {
501 }
502
[email protected]a9af7112010-05-08 00:56:01503 // Should be run on |orgin_thread_|, but that may not be well defined now.
504 bool was_cancelled() const {
505 if (!resolver_ || !origin_loop_) {
506 DCHECK(!resolver_);
507 DCHECK(!origin_loop_);
508 return true;
509 }
510 return false;
511 }
512
[email protected]0f8f1b432010-03-16 19:06:03513 // Run on worker thread.
514 void DoProbe() {
515 // Do actual testing on this thread, as it takes 40-100ms.
516 AddressFamily family = IPv6Supported() ? ADDRESS_FAMILY_UNSPECIFIED
517 : ADDRESS_FAMILY_IPV4;
518
519 Task* reply = NewRunnableMethod(this, &IPv6ProbeJob::OnProbeComplete,
520 family);
521
522 // The origin loop could go away while we are trying to post to it, so we
523 // need to call its PostTask method inside a lock. See ~HostResolver.
524 {
525 AutoLock locked(origin_loop_lock_);
526 if (origin_loop_) {
527 origin_loop_->PostTask(FROM_HERE, reply);
528 return;
529 }
530 }
531
532 // We didn't post, so delete the reply.
533 delete reply;
534 }
535
536 // Callback for when DoProbe() completes (runs on origin thread).
537 void OnProbeComplete(AddressFamily address_family) {
[email protected]a9af7112010-05-08 00:56:01538 if (was_cancelled())
539 return;
[email protected]0f8f1b432010-03-16 19:06:03540 DCHECK(IsOnOriginThread());
[email protected]a9af7112010-05-08 00:56:01541 resolver_->IPv6ProbeSetDefaultAddressFamily(address_family);
[email protected]0f8f1b432010-03-16 19:06:03542 }
543
544 bool IsOnOriginThread() const {
545 return !MessageLoop::current() || origin_loop_ == MessageLoop::current();
546 }
547
548 // Used/set only on origin thread.
549 HostResolverImpl* resolver_;
550
551 // Used to post ourselves onto the origin thread.
552 Lock origin_loop_lock_;
553 MessageLoop* origin_loop_;
554
555 DISALLOW_COPY_AND_ASSIGN(IPv6ProbeJob);
556};
557
558//-----------------------------------------------------------------------------
559
[email protected]68ad3ee2010-01-30 03:45:39560// We rely on the priority enum values being sequential having starting at 0,
561// and increasing for lower priorities.
562COMPILE_ASSERT(HIGHEST == 0u &&
563 LOWEST > HIGHEST &&
[email protected]c9c6f5c2010-07-31 01:30:03564 IDLE > LOWEST &&
565 NUM_PRIORITIES > IDLE,
[email protected]68ad3ee2010-01-30 03:45:39566 priority_indexes_incompatible);
567
568// JobPool contains all the information relating to queued requests, including
569// the limits on how many jobs are allowed to be used for this category of
570// requests.
571class HostResolverImpl::JobPool {
572 public:
573 JobPool(size_t max_outstanding_jobs, size_t max_pending_requests)
574 : num_outstanding_jobs_(0u) {
575 SetConstraints(max_outstanding_jobs, max_pending_requests);
576 }
577
578 ~JobPool() {
579 // Free the pending requests.
580 for (size_t i = 0; i < arraysize(pending_requests_); ++i)
581 STLDeleteElements(&pending_requests_[i]);
582 }
583
584 // Sets the constraints for this pool. See SetPoolConstraints() for the
585 // specific meaning of these parameters.
586 void SetConstraints(size_t max_outstanding_jobs,
587 size_t max_pending_requests) {
[email protected]b1f031dd2010-03-02 23:19:33588 CHECK_NE(max_outstanding_jobs, 0u);
[email protected]68ad3ee2010-01-30 03:45:39589 max_outstanding_jobs_ = max_outstanding_jobs;
590 max_pending_requests_ = max_pending_requests;
591 }
592
593 // Returns the number of pending requests enqueued to this pool.
594 // A pending request is one waiting to be attached to a job.
595 size_t GetNumPendingRequests() const {
596 size_t total = 0u;
597 for (size_t i = 0u; i < arraysize(pending_requests_); ++i)
598 total += pending_requests_[i].size();
599 return total;
600 }
601
602 bool HasPendingRequests() const {
603 return GetNumPendingRequests() > 0u;
604 }
605
606 // Enqueues a request to this pool. As a result of enqueing this request,
607 // the queue may have reached its maximum size. In this case, a request is
608 // evicted from the queue, and returned. Otherwise returns NULL. The caller
609 // is responsible for freeing the evicted request.
610 Request* InsertPendingRequest(Request* req) {
611 PendingRequestsQueue& q = pending_requests_[req->info().priority()];
612 q.push_back(req);
613
614 // If the queue is too big, kick out the lowest priority oldest request.
615 if (GetNumPendingRequests() > max_pending_requests_) {
616 // Iterate over the queues from lowest priority to highest priority.
617 for (int i = static_cast<int>(arraysize(pending_requests_)) - 1;
618 i >= 0; --i) {
619 PendingRequestsQueue& q = pending_requests_[i];
620 if (!q.empty()) {
621 Request* req = q.front();
622 q.pop_front();
623 return req;
624 }
625 }
626 }
627
628 return NULL;
629 }
630
631 // Erases |req| from this container. Caller is responsible for freeing
632 // |req| afterwards.
633 void RemovePendingRequest(Request* req) {
634 PendingRequestsQueue& q = pending_requests_[req->info().priority()];
635 PendingRequestsQueue::iterator it = std::find(q.begin(), q.end(), req);
636 DCHECK(it != q.end());
637 q.erase(it);
638 }
639
640 // Removes and returns the highest priority pending request.
641 Request* RemoveTopPendingRequest() {
642 DCHECK(HasPendingRequests());
643
644 for (size_t i = 0u; i < arraysize(pending_requests_); ++i) {
645 PendingRequestsQueue& q = pending_requests_[i];
646 if (!q.empty()) {
647 Request* req = q.front();
648 q.pop_front();
649 return req;
650 }
651 }
652
653 NOTREACHED();
654 return NULL;
655 }
656
657 // Keeps track of a job that was just added/removed, and belongs to this pool.
658 void AdjustNumOutstandingJobs(int offset) {
659 DCHECK(offset == 1 || (offset == -1 && num_outstanding_jobs_ > 0u));
660 num_outstanding_jobs_ += offset;
661 }
662
663 // Returns true if a new job can be created for this pool.
664 bool CanCreateJob() const {
665 return num_outstanding_jobs_ + 1u <= max_outstanding_jobs_;
666 }
667
668 // Removes any pending requests from the queue which are for the
[email protected]137af622010-02-05 02:14:35669 // same (hostname / effective address-family) as |job|, and attaches them to
670 // |job|.
[email protected]68ad3ee2010-01-30 03:45:39671 void MoveRequestsToJob(Job* job) {
672 for (size_t i = 0u; i < arraysize(pending_requests_); ++i) {
673 PendingRequestsQueue& q = pending_requests_[i];
674 PendingRequestsQueue::iterator req_it = q.begin();
675 while (req_it != q.end()) {
676 Request* req = *req_it;
[email protected]137af622010-02-05 02:14:35677 if (job->CanServiceRequest(req->info())) {
[email protected]68ad3ee2010-01-30 03:45:39678 // Job takes ownership of |req|.
679 job->AddRequest(req);
680 req_it = q.erase(req_it);
681 } else {
682 ++req_it;
683 }
684 }
685 }
686 }
687
688 private:
689 typedef std::deque<Request*> PendingRequestsQueue;
690
691 // Maximum number of concurrent jobs allowed to be started for requests
692 // belonging to this pool.
693 size_t max_outstanding_jobs_;
694
695 // The current number of running jobs that were started for requests
696 // belonging to this pool.
697 size_t num_outstanding_jobs_;
698
699 // The maximum number of requests we allow to be waiting on a job,
700 // for this pool.
701 size_t max_pending_requests_;
702
703 // The requests which are waiting to be started for this pool.
704 PendingRequestsQueue pending_requests_[NUM_PRIORITIES];
705};
706
707//-----------------------------------------------------------------------------
708
[email protected]e95d3aca2010-01-11 22:47:43709HostResolverImpl::HostResolverImpl(
710 HostResolverProc* resolver_proc,
711 HostCache* cache,
[email protected]2bb04442010-08-18 18:01:15712 size_t max_jobs)
[email protected]112bd462009-12-10 07:23:40713 : cache_(cache),
[email protected]68ad3ee2010-01-30 03:45:39714 max_jobs_(max_jobs),
[email protected]123ab1e32009-10-21 19:12:57715 next_request_id_(0),
[email protected]f2d8c4212010-02-02 00:56:35716 next_job_id_(0),
[email protected]123ab1e32009-10-21 19:12:57717 resolver_proc_(resolver_proc),
[email protected]0c7798452009-10-26 17:59:51718 default_address_family_(ADDRESS_FAMILY_UNSPECIFIED),
[email protected]e95d3aca2010-01-11 22:47:43719 shutdown_(false),
[email protected]2f3bc65c2010-07-23 17:47:10720 ipv6_probe_monitoring_(false),
[email protected]2bb04442010-08-18 18:01:15721 additional_resolver_flags_(0) {
[email protected]68ad3ee2010-01-30 03:45:39722 DCHECK_GT(max_jobs, 0u);
723
724 // It is cumbersome to expose all of the constraints in the constructor,
725 // so we choose some defaults, which users can override later.
726 job_pools_[POOL_NORMAL] = new JobPool(max_jobs, 100u * max_jobs);
727
[email protected]b59ff372009-07-15 22:04:32728#if defined(OS_WIN)
729 EnsureWinsockInit();
730#endif
[email protected]2f3bc65c2010-07-23 17:47:10731#if defined(OS_LINUX)
732 if (HaveOnlyLoopbackAddresses())
733 additional_resolver_flags_ |= HOST_RESOLVER_LOOPBACK_ONLY;
734#endif
[email protected]66761b952010-06-25 21:30:38735 NetworkChangeNotifier::AddObserver(this);
[email protected]b59ff372009-07-15 22:04:32736}
737
738HostResolverImpl::~HostResolverImpl() {
739 // Cancel the outstanding jobs. Those jobs may contain several attached
740 // requests, which will also be cancelled.
[email protected]0f8f1b432010-03-16 19:06:03741 DiscardIPv6ProbeJob();
742
[email protected]b59ff372009-07-15 22:04:32743 for (JobMap::iterator it = jobs_.begin(); it != jobs_.end(); ++it)
744 it->second->Cancel();
745
746 // In case we are being deleted during the processing of a callback.
747 if (cur_completing_job_)
748 cur_completing_job_->Cancel();
[email protected]e95d3aca2010-01-11 22:47:43749
[email protected]66761b952010-06-25 21:30:38750 NetworkChangeNotifier::RemoveObserver(this);
[email protected]61a86c42010-04-19 22:45:53751
[email protected]68ad3ee2010-01-30 03:45:39752 // Delete the job pools.
753 for (size_t i = 0u; i < arraysize(job_pools_); ++i)
754 delete job_pools_[i];
[email protected]b59ff372009-07-15 22:04:32755}
756
[email protected]fc212772010-08-17 18:00:02757// TODO(eroman): Don't create cache entries for hostnames which are simply IP
758// address literals.
[email protected]684970b2009-08-14 04:54:46759int HostResolverImpl::Resolve(const RequestInfo& info,
[email protected]b59ff372009-07-15 22:04:32760 AddressList* addresses,
761 CompletionCallback* callback,
[email protected]684970b2009-08-14 04:54:46762 RequestHandle* out_req,
[email protected]2bb04442010-08-18 18:01:15763 const BoundNetLog& net_log) {
[email protected]1ac6af92010-06-03 21:00:14764 DCHECK(CalledOnValidThread());
765
[email protected]b59ff372009-07-15 22:04:32766 if (shutdown_)
767 return ERR_UNEXPECTED;
768
769 // Choose a unique ID number for observers to see.
770 int request_id = next_request_id_++;
771
[email protected]9e743cd2010-03-16 07:03:53772 // Update the net log and notify registered observers.
[email protected]2bb04442010-08-18 18:01:15773 OnStartRequest(net_log, request_id, info);
[email protected]b59ff372009-07-15 22:04:32774
[email protected]123ab1e32009-10-21 19:12:57775 // Build a key that identifies the request in the cache and in the
776 // outstanding jobs map.
[email protected]137af622010-02-05 02:14:35777 Key key = GetEffectiveKeyForRequest(info);
[email protected]123ab1e32009-10-21 19:12:57778
[email protected]b59ff372009-07-15 22:04:32779 // If we have an unexpired cache entry, use it.
[email protected]112bd462009-12-10 07:23:40780 if (info.allow_cached_response() && cache_.get()) {
781 const HostCache::Entry* cache_entry = cache_->Lookup(
[email protected]123ab1e32009-10-21 19:12:57782 key, base::TimeTicks::Now());
[email protected]b59ff372009-07-15 22:04:32783 if (cache_entry) {
[email protected]21526002010-05-16 19:42:46784 int net_error = cache_entry->error;
785 if (net_error == OK)
[email protected]112bd462009-12-10 07:23:40786 addresses->SetFrom(cache_entry->addrlist, info.port());
[email protected]b59ff372009-07-15 22:04:32787
[email protected]9e743cd2010-03-16 07:03:53788 // Update the net log and notify registered observers.
[email protected]2bb04442010-08-18 18:01:15789 OnFinishRequest(net_log, request_id, info, net_error,
790 0, /* os_error (unknown since from cache) */
791 true /* was_from_cache */);
[email protected]b59ff372009-07-15 22:04:32792
[email protected]21526002010-05-16 19:42:46793 return net_error;
[email protected]b59ff372009-07-15 22:04:32794 }
795 }
796
797 // If no callback was specified, do a synchronous resolution.
798 if (!callback) {
799 AddressList addrlist;
[email protected]21526002010-05-16 19:42:46800 int os_error = 0;
[email protected]b59ff372009-07-15 22:04:32801 int error = ResolveAddrInfo(
[email protected]5ea28dea2010-04-08 15:35:13802 effective_resolver_proc(), key.hostname, key.address_family,
[email protected]21526002010-05-16 19:42:46803 key.host_resolver_flags, &addrlist, &os_error);
[email protected]b59ff372009-07-15 22:04:32804 if (error == OK) {
805 addrlist.SetPort(info.port());
806 *addresses = addrlist;
807 }
808
809 // Write to cache.
[email protected]112bd462009-12-10 07:23:40810 if (cache_.get())
811 cache_->Set(key, error, addrlist, base::TimeTicks::Now());
[email protected]b59ff372009-07-15 22:04:32812
[email protected]9e743cd2010-03-16 07:03:53813 // Update the net log and notify registered observers.
[email protected]2bb04442010-08-18 18:01:15814 OnFinishRequest(net_log, request_id, info, error, os_error,
815 false /* was_from_cache */);
[email protected]b59ff372009-07-15 22:04:32816
817 return error;
818 }
819
820 // Create a handle for this request, and pass it back to the user if they
821 // asked for it (out_req != NULL).
[email protected]2bb04442010-08-18 18:01:15822 Request* req = new Request(net_log, request_id, info, callback, addresses);
[email protected]b59ff372009-07-15 22:04:32823 if (out_req)
824 *out_req = reinterpret_cast<RequestHandle>(req);
825
826 // Next we need to attach our request to a "job". This job is responsible for
827 // calling "getaddrinfo(hostname)" on a worker thread.
828 scoped_refptr<Job> job;
829
[email protected]123ab1e32009-10-21 19:12:57830 // If there is already an outstanding job to resolve |key|, use
[email protected]b59ff372009-07-15 22:04:32831 // it. This prevents starting concurrent resolves for the same hostname.
[email protected]123ab1e32009-10-21 19:12:57832 job = FindOutstandingJob(key);
[email protected]b59ff372009-07-15 22:04:32833 if (job) {
834 job->AddRequest(req);
835 } else {
[email protected]68ad3ee2010-01-30 03:45:39836 JobPool* pool = GetPoolForRequest(req);
837 if (CanCreateJobForPool(*pool)) {
838 CreateAndStartJob(req);
839 } else {
840 return EnqueueRequest(pool, req);
841 }
[email protected]b59ff372009-07-15 22:04:32842 }
843
844 // Completion happens during OnJobComplete(Job*).
845 return ERR_IO_PENDING;
846}
847
848// See OnJobComplete(Job*) for why it is important not to clean out
849// cancelled requests from Job::requests_.
850void HostResolverImpl::CancelRequest(RequestHandle req_handle) {
[email protected]1ac6af92010-06-03 21:00:14851 DCHECK(CalledOnValidThread());
[email protected]bf0b51c2009-08-01 23:46:40852 if (shutdown_) {
[email protected]ff1f61b92009-08-03 23:20:23853 // TODO(eroman): temp hack for: http://crbug.com/18373
854 // Because we destroy outstanding requests during Shutdown(),
855 // |req_handle| is already cancelled.
[email protected]bf0b51c2009-08-01 23:46:40856 LOG(ERROR) << "Called HostResolverImpl::CancelRequest() after Shutdown().";
857 StackTrace().PrintBacktrace();
858 return;
859 }
[email protected]b59ff372009-07-15 22:04:32860 Request* req = reinterpret_cast<Request*>(req_handle);
861 DCHECK(req);
[email protected]68ad3ee2010-01-30 03:45:39862
863 scoped_ptr<Request> request_deleter; // Frees at end of function.
864
865 if (!req->job()) {
866 // If the request was not attached to a job yet, it must have been
867 // enqueued into a pool. Remove it from that pool's queue.
868 // Otherwise if it was attached to a job, the job is responsible for
869 // deleting it.
870 JobPool* pool = GetPoolForRequest(req);
871 pool->RemovePendingRequest(req);
872 request_deleter.reset(req);
873 }
874
[email protected]b59ff372009-07-15 22:04:32875 // NULL out the fields of req, to mark it as cancelled.
876 req->MarkAsCancelled();
[email protected]2bb04442010-08-18 18:01:15877 OnCancelRequest(req->net_log(), req->id(), req->info());
[email protected]b59ff372009-07-15 22:04:32878}
879
[email protected]e95d3aca2010-01-11 22:47:43880void HostResolverImpl::AddObserver(HostResolver::Observer* observer) {
[email protected]1ac6af92010-06-03 21:00:14881 DCHECK(CalledOnValidThread());
[email protected]b59ff372009-07-15 22:04:32882 observers_.push_back(observer);
883}
884
[email protected]e95d3aca2010-01-11 22:47:43885void HostResolverImpl::RemoveObserver(HostResolver::Observer* observer) {
[email protected]1ac6af92010-06-03 21:00:14886 DCHECK(CalledOnValidThread());
[email protected]b59ff372009-07-15 22:04:32887 ObserversList::iterator it =
888 std::find(observers_.begin(), observers_.end(), observer);
889
890 // Observer must exist.
891 DCHECK(it != observers_.end());
892
893 observers_.erase(it);
894}
895
[email protected]0f8f1b432010-03-16 19:06:03896void HostResolverImpl::SetDefaultAddressFamily(AddressFamily address_family) {
[email protected]1ac6af92010-06-03 21:00:14897 DCHECK(CalledOnValidThread());
[email protected]0f8f1b432010-03-16 19:06:03898 ipv6_probe_monitoring_ = false;
899 DiscardIPv6ProbeJob();
900 default_address_family_ = address_family;
901}
902
903void HostResolverImpl::ProbeIPv6Support() {
[email protected]1ac6af92010-06-03 21:00:14904 DCHECK(CalledOnValidThread());
[email protected]0f8f1b432010-03-16 19:06:03905 DCHECK(!ipv6_probe_monitoring_);
906 ipv6_probe_monitoring_ = true;
[email protected]61a86c42010-04-19 22:45:53907 OnIPAddressChanged(); // Give initial setup call.
[email protected]0f8f1b432010-03-16 19:06:03908}
909
[email protected]b59ff372009-07-15 22:04:32910void HostResolverImpl::Shutdown() {
[email protected]1ac6af92010-06-03 21:00:14911 DCHECK(CalledOnValidThread());
[email protected]b59ff372009-07-15 22:04:32912
913 // Cancel the outstanding jobs.
914 for (JobMap::iterator it = jobs_.begin(); it != jobs_.end(); ++it)
915 it->second->Cancel();
916 jobs_.clear();
[email protected]0a175512010-04-20 03:09:25917 DiscardIPv6ProbeJob();
[email protected]be5c6162010-07-27 21:12:51918
919 shutdown_ = true;
[email protected]b59ff372009-07-15 22:04:32920}
921
[email protected]68ad3ee2010-01-30 03:45:39922void HostResolverImpl::SetPoolConstraints(JobPoolIndex pool_index,
923 size_t max_outstanding_jobs,
924 size_t max_pending_requests) {
[email protected]1ac6af92010-06-03 21:00:14925 DCHECK(CalledOnValidThread());
[email protected]b1f031dd2010-03-02 23:19:33926 CHECK_GE(pool_index, 0);
927 CHECK_LT(pool_index, POOL_COUNT);
[email protected]68ad3ee2010-01-30 03:45:39928 CHECK(jobs_.empty()) << "Can only set constraints during setup";
929 JobPool* pool = job_pools_[pool_index];
930 pool->SetConstraints(max_outstanding_jobs, max_pending_requests);
931}
932
[email protected]b59ff372009-07-15 22:04:32933void HostResolverImpl::AddOutstandingJob(Job* job) {
[email protected]123ab1e32009-10-21 19:12:57934 scoped_refptr<Job>& found_job = jobs_[job->key()];
[email protected]b59ff372009-07-15 22:04:32935 DCHECK(!found_job);
936 found_job = job;
[email protected]68ad3ee2010-01-30 03:45:39937
938 JobPool* pool = GetPoolForRequest(job->initial_request());
939 pool->AdjustNumOutstandingJobs(1);
[email protected]b59ff372009-07-15 22:04:32940}
941
[email protected]123ab1e32009-10-21 19:12:57942HostResolverImpl::Job* HostResolverImpl::FindOutstandingJob(const Key& key) {
943 JobMap::iterator it = jobs_.find(key);
[email protected]b59ff372009-07-15 22:04:32944 if (it != jobs_.end())
945 return it->second;
946 return NULL;
947}
948
949void HostResolverImpl::RemoveOutstandingJob(Job* job) {
[email protected]123ab1e32009-10-21 19:12:57950 JobMap::iterator it = jobs_.find(job->key());
[email protected]b59ff372009-07-15 22:04:32951 DCHECK(it != jobs_.end());
952 DCHECK_EQ(it->second.get(), job);
953 jobs_.erase(it);
[email protected]68ad3ee2010-01-30 03:45:39954
955 JobPool* pool = GetPoolForRequest(job->initial_request());
956 pool->AdjustNumOutstandingJobs(-1);
[email protected]b59ff372009-07-15 22:04:32957}
958
959void HostResolverImpl::OnJobComplete(Job* job,
[email protected]21526002010-05-16 19:42:46960 int net_error,
961 int os_error,
[email protected]27f99c82009-10-29 22:21:00962 const AddressList& addrlist) {
[email protected]b59ff372009-07-15 22:04:32963 RemoveOutstandingJob(job);
964
965 // Write result to the cache.
[email protected]112bd462009-12-10 07:23:40966 if (cache_.get())
[email protected]21526002010-05-16 19:42:46967 cache_->Set(job->key(), net_error, addrlist, base::TimeTicks::Now());
[email protected]b59ff372009-07-15 22:04:32968
969 // Make a note that we are executing within OnJobComplete() in case the
970 // HostResolver is deleted by a callback invocation.
971 DCHECK(!cur_completing_job_);
972 cur_completing_job_ = job;
973
[email protected]68ad3ee2010-01-30 03:45:39974 // Try to start any queued requests now that a job-slot has freed up.
975 ProcessQueuedRequests();
976
[email protected]b59ff372009-07-15 22:04:32977 // Complete all of the requests that were attached to the job.
978 for (RequestsList::const_iterator it = job->requests().begin();
979 it != job->requests().end(); ++it) {
980 Request* req = *it;
981 if (!req->was_cancelled()) {
982 DCHECK_EQ(job, req->job());
983
[email protected]9e743cd2010-03-16 07:03:53984 // Update the net log and notify registered observers.
[email protected]2bb04442010-08-18 18:01:15985 OnFinishRequest(req->net_log(), req->id(), req->info(), net_error,
986 os_error, false /* was_from_cache */);
[email protected]b59ff372009-07-15 22:04:32987
[email protected]21526002010-05-16 19:42:46988 req->OnComplete(net_error, addrlist);
[email protected]b59ff372009-07-15 22:04:32989
990 // Check if the job was cancelled as a result of running the callback.
991 // (Meaning that |this| was deleted).
992 if (job->was_cancelled())
993 return;
994 }
995 }
996
997 cur_completing_job_ = NULL;
998}
999
[email protected]2bb04442010-08-18 18:01:151000void HostResolverImpl::OnStartRequest(const BoundNetLog& net_log,
[email protected]54e13772009-08-14 03:01:091001 int request_id,
1002 const RequestInfo& info) {
[email protected]2bb04442010-08-18 18:01:151003 net_log.BeginEvent(NetLog::TYPE_HOST_RESOLVER_IMPL, NULL);
[email protected]54e13772009-08-14 03:01:091004
1005 // Notify the observers of the start.
1006 if (!observers_.empty()) {
[email protected]54e13772009-08-14 03:01:091007 for (ObserversList::iterator it = observers_.begin();
1008 it != observers_.end(); ++it) {
1009 (*it)->OnStartResolution(request_id, info);
1010 }
[email protected]b59ff372009-07-15 22:04:321011 }
1012}
1013
[email protected]2bb04442010-08-18 18:01:151014void HostResolverImpl::OnFinishRequest(const BoundNetLog& net_log,
[email protected]54e13772009-08-14 03:01:091015 int request_id,
1016 const RequestInfo& info,
[email protected]21526002010-05-16 19:42:461017 int net_error,
[email protected]2bb04442010-08-18 18:01:151018 int os_error,
1019 bool was_from_cache) {
[email protected]21526002010-05-16 19:42:461020 bool was_resolved = net_error == OK;
1021
[email protected]54e13772009-08-14 03:01:091022 // Notify the observers of the completion.
1023 if (!observers_.empty()) {
[email protected]54e13772009-08-14 03:01:091024 for (ObserversList::iterator it = observers_.begin();
1025 it != observers_.end(); ++it) {
1026 (*it)->OnFinishResolutionWithStatus(request_id, was_resolved, info);
1027 }
[email protected]b59ff372009-07-15 22:04:321028 }
[email protected]54e13772009-08-14 03:01:091029
[email protected]2bb04442010-08-18 18:01:151030 // Log some extra parameters on failure.
[email protected]21526002010-05-16 19:42:461031 scoped_refptr<NetLog::EventParameters> params;
[email protected]2bb04442010-08-18 18:01:151032 if (!was_resolved)
1033 params = new HostResolveFailedParams(net_error, os_error, was_from_cache);
[email protected]21526002010-05-16 19:42:461034
[email protected]2bb04442010-08-18 18:01:151035 net_log.EndEvent(NetLog::TYPE_HOST_RESOLVER_IMPL, params);
[email protected]b59ff372009-07-15 22:04:321036}
1037
[email protected]2bb04442010-08-18 18:01:151038void HostResolverImpl::OnCancelRequest(const BoundNetLog& net_log,
[email protected]54e13772009-08-14 03:01:091039 int request_id,
1040 const RequestInfo& info) {
[email protected]2bb04442010-08-18 18:01:151041 net_log.AddEvent(NetLog::TYPE_CANCELLED, NULL);
[email protected]54e13772009-08-14 03:01:091042
1043 // Notify the observers of the cancellation.
1044 if (!observers_.empty()) {
[email protected]54e13772009-08-14 03:01:091045 for (ObserversList::iterator it = observers_.begin();
1046 it != observers_.end(); ++it) {
1047 (*it)->OnCancelResolution(request_id, info);
1048 }
[email protected]b59ff372009-07-15 22:04:321049 }
[email protected]54e13772009-08-14 03:01:091050
[email protected]2bb04442010-08-18 18:01:151051 net_log.EndEvent(NetLog::TYPE_HOST_RESOLVER_IMPL, NULL);
[email protected]b59ff372009-07-15 22:04:321052}
1053
[email protected]61a86c42010-04-19 22:45:531054void HostResolverImpl::OnIPAddressChanged() {
[email protected]e95d3aca2010-01-11 22:47:431055 if (cache_.get())
1056 cache_->clear();
[email protected]0f8f1b432010-03-16 19:06:031057 if (ipv6_probe_monitoring_) {
[email protected]0a175512010-04-20 03:09:251058 DCHECK(!shutdown_);
1059 if (shutdown_)
1060 return;
[email protected]0f8f1b432010-03-16 19:06:031061 DiscardIPv6ProbeJob();
1062 ipv6_probe_job_ = new IPv6ProbeJob(this);
1063 ipv6_probe_job_->Start();
1064 }
[email protected]2f3bc65c2010-07-23 17:47:101065#if defined(OS_LINUX)
1066 if (HaveOnlyLoopbackAddresses()) {
1067 additional_resolver_flags_ |= HOST_RESOLVER_LOOPBACK_ONLY;
1068 } else {
1069 additional_resolver_flags_ &= ~HOST_RESOLVER_LOOPBACK_ONLY;
1070 }
1071#endif
[email protected]0f8f1b432010-03-16 19:06:031072}
1073
1074void HostResolverImpl::DiscardIPv6ProbeJob() {
1075 if (ipv6_probe_job_.get()) {
1076 ipv6_probe_job_->Cancel();
1077 ipv6_probe_job_ = NULL;
1078 }
1079}
1080
1081void HostResolverImpl::IPv6ProbeSetDefaultAddressFamily(
1082 AddressFamily address_family) {
1083 DCHECK(address_family == ADDRESS_FAMILY_UNSPECIFIED ||
1084 address_family == ADDRESS_FAMILY_IPV4);
[email protected]f092e64b2010-03-17 00:39:181085 if (default_address_family_ != address_family) {
1086 LOG(INFO) << "IPv6Probe forced AddressFamily setting to "
1087 << ((address_family == ADDRESS_FAMILY_UNSPECIFIED)
1088 ? "ADDRESS_FAMILY_UNSPECIFIED"
1089 : "ADDRESS_FAMILY_IPV4");
1090 }
[email protected]0f8f1b432010-03-16 19:06:031091 default_address_family_ = address_family;
1092 // Drop reference since the job has called us back.
1093 DiscardIPv6ProbeJob();
[email protected]e95d3aca2010-01-11 22:47:431094}
1095
[email protected]68ad3ee2010-01-30 03:45:391096// static
1097HostResolverImpl::JobPoolIndex HostResolverImpl::GetJobPoolIndexForRequest(
1098 const Request* req) {
1099 return POOL_NORMAL;
1100}
1101
1102bool HostResolverImpl::CanCreateJobForPool(const JobPool& pool) const {
1103 DCHECK_LE(jobs_.size(), max_jobs_);
1104
1105 // We can't create another job if it would exceed the global total.
1106 if (jobs_.size() + 1 > max_jobs_)
1107 return false;
1108
1109 // Check whether the pool's constraints are met.
1110 return pool.CanCreateJob();
1111}
1112
1113void HostResolverImpl::ProcessQueuedRequests() {
1114 // Find the highest priority request that can be scheduled.
1115 Request* top_req = NULL;
1116 for (size_t i = 0; i < arraysize(job_pools_); ++i) {
1117 JobPool* pool = job_pools_[i];
1118 if (pool->HasPendingRequests() && CanCreateJobForPool(*pool)) {
1119 top_req = pool->RemoveTopPendingRequest();
1120 break;
1121 }
1122 }
1123
1124 if (!top_req)
1125 return;
1126
1127 scoped_refptr<Job> job = CreateAndStartJob(top_req);
1128
1129 // Search for any other pending request which can piggy-back off this job.
1130 for (size_t pool_i = 0; pool_i < POOL_COUNT; ++pool_i) {
1131 JobPool* pool = job_pools_[pool_i];
1132 pool->MoveRequestsToJob(job);
1133 }
1134}
1135
[email protected]137af622010-02-05 02:14:351136HostResolverImpl::Key HostResolverImpl::GetEffectiveKeyForRequest(
1137 const RequestInfo& info) const {
1138 AddressFamily effective_address_family = info.address_family();
1139 if (effective_address_family == ADDRESS_FAMILY_UNSPECIFIED)
1140 effective_address_family = default_address_family_;
[email protected]5ea28dea2010-04-08 15:35:131141 return Key(info.hostname(), effective_address_family,
[email protected]2f3bc65c2010-07-23 17:47:101142 info.host_resolver_flags() | additional_resolver_flags_);
[email protected]137af622010-02-05 02:14:351143}
1144
[email protected]68ad3ee2010-01-30 03:45:391145HostResolverImpl::Job* HostResolverImpl::CreateAndStartJob(Request* req) {
1146 DCHECK(CanCreateJobForPool(*GetPoolForRequest(req)));
[email protected]137af622010-02-05 02:14:351147 Key key = GetEffectiveKeyForRequest(req->info());
[email protected]2bb04442010-08-18 18:01:151148 scoped_refptr<Job> job = new Job(next_job_id_++, this, key);
[email protected]68ad3ee2010-01-30 03:45:391149 job->AddRequest(req);
1150 AddOutstandingJob(job);
1151 job->Start();
1152 return job.get();
1153}
1154
1155int HostResolverImpl::EnqueueRequest(JobPool* pool, Request* req) {
1156 scoped_ptr<Request> req_evicted_from_queue(
1157 pool->InsertPendingRequest(req));
1158
1159 // If the queue has become too large, we need to kick something out.
1160 if (req_evicted_from_queue.get()) {
1161 Request* r = req_evicted_from_queue.get();
1162 int error = ERR_HOST_RESOLVER_QUEUE_TOO_LARGE;
1163
[email protected]2bb04442010-08-18 18:01:151164 OnFinishRequest(r->net_log(), r->id(), r->info(), error,
1165 0, /* os_error (not applicable) */
1166 false /* was_from_cache */);
[email protected]68ad3ee2010-01-30 03:45:391167
1168 if (r == req)
1169 return error;
1170
1171 r->OnComplete(error, AddressList());
1172 }
1173
1174 return ERR_IO_PENDING;
1175}
1176
[email protected]b59ff372009-07-15 22:04:321177} // namespace net