blob: 1f89af4e2df1440a84789390eac6e0b40a26edd4 [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"
[email protected]b59ff372009-07-15 22:04:326
[email protected]21526002010-05-16 19:42:467#if defined(OS_WIN)
8#include <Winsock2.h>
9#elif defined(OS_POSIX)
10#include <netdb.h>
11#endif
12
[email protected]68ad3ee2010-01-30 03:45:3913#include <cmath>
14#include <deque>
[email protected]21526002010-05-16 19:42:4615#include <vector>
[email protected]68ad3ee2010-01-30 03:45:3916
17#include "base/basictypes.h"
[email protected]b59ff372009-07-15 22:04:3218#include "base/compiler_specific.h"
[email protected]bf0b51c2009-08-01 23:46:4019#include "base/debug_util.h"
[email protected]f2d8c4212010-02-02 00:56:3520#include "base/lock.h"
[email protected]b59ff372009-07-15 22:04:3221#include "base/message_loop.h"
22#include "base/stl_util-inl.h"
23#include "base/string_util.h"
24#include "base/time.h"
[email protected]21526002010-05-16 19:42:4625#include "base/values.h"
[email protected]b59ff372009-07-15 22:04:3226#include "base/worker_pool.h"
27#include "net/base/address_list.h"
28#include "net/base/host_resolver_proc.h"
[email protected]9e743cd2010-03-16 07:03:5329#include "net/base/net_log.h"
[email protected]b59ff372009-07-15 22:04:3230#include "net/base/net_errors.h"
[email protected]0f8f1b432010-03-16 19:06:0331#include "net/base/net_util.h"
[email protected]e95d3aca2010-01-11 22:47:4332#include "net/base/network_change_notifier.h"
[email protected]b59ff372009-07-15 22:04:3233
34#if defined(OS_WIN)
35#include "net/base/winsock_init.h"
36#endif
37
38namespace net {
39
[email protected]e95d3aca2010-01-11 22:47:4340namespace {
41
42HostCache* CreateDefaultCache() {
[email protected]b59ff372009-07-15 22:04:3243 static const size_t kMaxHostCacheEntries = 100;
[email protected]112bd462009-12-10 07:23:4044
45 HostCache* cache = new HostCache(
46 kMaxHostCacheEntries,
47 base::TimeDelta::FromMinutes(1),
[email protected]50781562010-04-08 20:34:4548 base::TimeDelta::FromMinutes(1));
[email protected]112bd462009-12-10 07:23:4049
[email protected]e95d3aca2010-01-11 22:47:4350 return cache;
51}
52
53} // anonymous namespace
54
[email protected]d13c3272010-02-04 00:24:5155HostResolver* CreateSystemHostResolver(
56 NetworkChangeNotifier* network_change_notifier) {
[email protected]68ad3ee2010-01-30 03:45:3957 // Maximum of 50 concurrent threads.
58 // TODO(eroman): Adjust this, do some A/B experiments.
59 static const size_t kMaxJobs = 50u;
60
[email protected]68ad3ee2010-01-30 03:45:3961 HostResolverImpl* resolver = new HostResolverImpl(
[email protected]d13c3272010-02-04 00:24:5162 NULL, CreateDefaultCache(), network_change_notifier, kMaxJobs);
[email protected]68ad3ee2010-01-30 03:45:3963
64 return resolver;
[email protected]b59ff372009-07-15 22:04:3265}
66
67static int ResolveAddrInfo(HostResolverProc* resolver_proc,
[email protected]123ab1e32009-10-21 19:12:5768 const std::string& host,
69 AddressFamily address_family,
[email protected]5ea28dea2010-04-08 15:35:1370 HostResolverFlags host_resolver_flags,
[email protected]21526002010-05-16 19:42:4671 AddressList* out,
72 int* os_error) {
[email protected]b59ff372009-07-15 22:04:3273 if (resolver_proc) {
74 // Use the custom procedure.
[email protected]5ea28dea2010-04-08 15:35:1375 return resolver_proc->Resolve(host, address_family,
[email protected]21526002010-05-16 19:42:4676 host_resolver_flags, out, os_error);
[email protected]b59ff372009-07-15 22:04:3277 } else {
78 // Use the system procedure (getaddrinfo).
[email protected]5ea28dea2010-04-08 15:35:1379 return SystemHostResolverProc(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 }
82}
83
[email protected]21526002010-05-16 19:42:4684// Extra parameters to attach to the NetLog when the resolve failed.
85class HostResolveFailedParams : public NetLog::EventParameters {
86 public:
87 HostResolveFailedParams(int net_error, int os_error, bool was_from_cache)
88 : net_error_(net_error),
89 os_error_(os_error),
90 was_from_cache_(was_from_cache) {
91 }
92
93 virtual Value* ToValue() const {
94 DictionaryValue* dict = new DictionaryValue();
95 dict->SetInteger(L"net_error", net_error_);
96 dict->SetBoolean(L"was_from_cache", was_from_cache_);
97
98 if (os_error_) {
99 dict->SetInteger(L"os_error", os_error_);
100#if defined(OS_POSIX)
101 dict->SetString(L"os_error_string", gai_strerror(os_error_));
102#elif defined(OS_WIN)
103 // Map the error code to a human-readable string.
104 LPWSTR error_string = NULL;
105 int size = FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
106 FORMAT_MESSAGE_FROM_SYSTEM,
107 0, // Use the internal message table.
108 os_error_,
109 0, // Use default language.
110 (LPWSTR)&error_string,
111 0, // Buffer size.
112 0); // Arguments (unused).
113 dict->SetString(L"os_error_string", error_string);
114 LocalFree(error_string);
115#endif
116 }
117
118 return dict;
119 }
120
121 private:
122 const int net_error_;
123 const int os_error_;
124 const bool was_from_cache_;
125};
126
127// Gets a list of the likely error codes that getaddrinfo() can return
128// (non-exhaustive). These are the error codes that we will track via
129// a histogram.
130std::vector<int> GetAllGetAddrinfoOSErrors() {
131 int os_errors[] = {
132#if defined(OS_POSIX)
133 EAI_ADDRFAMILY,
134 EAI_AGAIN,
135 EAI_BADFLAGS,
136 EAI_FAIL,
137 EAI_FAMILY,
138 EAI_MEMORY,
139 EAI_NODATA,
140 EAI_NONAME,
141 EAI_SERVICE,
142 EAI_SOCKTYPE,
143 EAI_SYSTEM,
144#elif defined(OS_WIN)
145 // See: http://msdn.microsoft.com/en-us/library/ms738520(VS.85).aspx
146 WSA_NOT_ENOUGH_MEMORY,
147 WSAEAFNOSUPPORT,
148 WSAEINVAL,
149 WSAESOCKTNOSUPPORT,
150 WSAHOST_NOT_FOUND,
151 WSANO_DATA,
152 WSANO_RECOVERY,
153 WSANOTINITIALISED,
154 WSATRY_AGAIN,
155 WSATYPE_NOT_FOUND,
156#endif
157 };
158
159 // Histogram enumerations require positive numbers.
160 std::vector<int> errors;
161 for (size_t i = 0; i < arraysize(os_errors); ++i) {
162 errors.push_back(std::abs(os_errors[i]));
163 // Also add N+1 for each error, so the bucket that contains our expected
164 // error is of size 1. That way if we get unexpected error codes, they
165 // won't fall into the same buckets as the expected ones.
166 errors.push_back(std::abs(os_errors[i]) + 1);
167 }
168 return errors;
169}
170
[email protected]b59ff372009-07-15 22:04:32171//-----------------------------------------------------------------------------
172
173class HostResolverImpl::Request {
174 public:
[email protected]9e743cd2010-03-16 07:03:53175 Request(const BoundNetLog& net_log,
[email protected]54e13772009-08-14 03:01:09176 int id,
177 const RequestInfo& info,
178 CompletionCallback* callback,
[email protected]b59ff372009-07-15 22:04:32179 AddressList* addresses)
[email protected]9e743cd2010-03-16 07:03:53180 : net_log_(net_log),
[email protected]54e13772009-08-14 03:01:09181 id_(id),
182 info_(info),
183 job_(NULL),
184 callback_(callback),
185 addresses_(addresses) {
186 }
[email protected]b59ff372009-07-15 22:04:32187
188 // Mark the request as cancelled.
189 void MarkAsCancelled() {
190 job_ = NULL;
191 callback_ = NULL;
192 addresses_ = NULL;
193 }
194
195 bool was_cancelled() const {
196 return callback_ == NULL;
197 }
198
199 void set_job(Job* job) {
200 DCHECK(job != NULL);
201 // Identify which job the request is waiting on.
202 job_ = job;
203 }
204
205 void OnComplete(int error, const AddressList& addrlist) {
206 if (error == OK)
207 addresses_->SetFrom(addrlist, port());
208 callback_->Run(error);
209 }
210
211 int port() const {
212 return info_.port();
213 }
214
215 Job* job() const {
216 return job_;
217 }
218
[email protected]9e743cd2010-03-16 07:03:53219 const BoundNetLog& net_log() {
220 return net_log_;
[email protected]54e13772009-08-14 03:01:09221 }
222
[email protected]b59ff372009-07-15 22:04:32223 int id() const {
224 return id_;
225 }
226
227 const RequestInfo& info() const {
228 return info_;
229 }
230
231 private:
[email protected]9e743cd2010-03-16 07:03:53232 BoundNetLog net_log_;
[email protected]54e13772009-08-14 03:01:09233
[email protected]b59ff372009-07-15 22:04:32234 // Unique ID for this request. Used by observers to identify requests.
235 int id_;
236
237 // The request info that started the request.
238 RequestInfo info_;
239
240 // The resolve job (running in worker pool) that this request is dependent on.
241 Job* job_;
242
243 // The user's callback to invoke when the request completes.
244 CompletionCallback* callback_;
245
246 // The address list to save result into.
247 AddressList* addresses_;
248
249 DISALLOW_COPY_AND_ASSIGN(Request);
250};
251
252//-----------------------------------------------------------------------------
253
[email protected]b59ff372009-07-15 22:04:32254// This class represents a request to the worker pool for a "getaddrinfo()"
255// call.
256class HostResolverImpl::Job
257 : public base::RefCountedThreadSafe<HostResolverImpl::Job> {
258 public:
[email protected]6e76d8d2010-05-10 23:13:56259 Job(int id, HostResolverImpl* resolver, const Key& key)
[email protected]0f8f1b432010-03-16 19:06:03260 : id_(id),
261 key_(key),
[email protected]b59ff372009-07-15 22:04:32262 resolver_(resolver),
263 origin_loop_(MessageLoop::current()),
264 resolver_proc_(resolver->effective_resolver_proc()),
[email protected]252b699b2010-02-05 21:38:06265 error_(OK),
[email protected]21526002010-05-16 19:42:46266 os_error_(0),
[email protected]252b699b2010-02-05 21:38:06267 had_non_speculative_request_(false) {
[email protected]b59ff372009-07-15 22:04:32268 }
269
[email protected]b59ff372009-07-15 22:04:32270 // Attaches a request to this job. The job takes ownership of |req| and will
271 // take care to delete it.
272 void AddRequest(Request* req) {
[email protected]b59ff372009-07-15 22:04:32273 req->set_job(this);
274 requests_.push_back(req);
[email protected]252b699b2010-02-05 21:38:06275
276 if (!req->info().is_speculative())
277 had_non_speculative_request_ = true;
[email protected]b59ff372009-07-15 22:04:32278 }
279
280 // Called from origin loop.
281 void Start() {
[email protected]252b699b2010-02-05 21:38:06282 start_time_ = base::TimeTicks::Now();
283
[email protected]b59ff372009-07-15 22:04:32284 // Dispatch the job to a worker thread.
285 if (!WorkerPool::PostTask(FROM_HERE,
286 NewRunnableMethod(this, &Job::DoLookup), true)) {
287 NOTREACHED();
288
289 // Since we could be running within Resolve() right now, we can't just
290 // call OnLookupComplete(). Instead we must wait until Resolve() has
291 // returned (IO_PENDING).
292 error_ = ERR_UNEXPECTED;
293 MessageLoop::current()->PostTask(
294 FROM_HERE, NewRunnableMethod(this, &Job::OnLookupComplete));
295 }
296 }
297
298 // Cancels the current job. Callable from origin thread.
299 void Cancel() {
300 HostResolver* resolver = resolver_;
301 resolver_ = NULL;
302
[email protected]b59ff372009-07-15 22:04:32303 // Mark the job as cancelled, so when worker thread completes it will
304 // not try to post completion to origin loop.
305 {
306 AutoLock locked(origin_loop_lock_);
307 origin_loop_ = NULL;
308 }
309
[email protected]1877a2212009-09-18 21:09:26310 // We will call HostResolverImpl::CancelRequest(Request*) on each one
[email protected]27f99c82009-10-29 22:21:00311 // in order to notify any observers.
[email protected]b59ff372009-07-15 22:04:32312 for (RequestsList::const_iterator it = requests_.begin();
313 it != requests_.end(); ++it) {
314 HostResolverImpl::Request* req = *it;
315 if (!req->was_cancelled())
316 resolver->CancelRequest(req);
317 }
318 }
319
320 // Called from origin thread.
321 bool was_cancelled() const {
322 return resolver_ == NULL;
323 }
324
325 // Called from origin thread.
[email protected]123ab1e32009-10-21 19:12:57326 const Key& key() const {
327 return key_;
[email protected]b59ff372009-07-15 22:04:32328 }
329
[email protected]a2fbebe2010-02-05 01:40:12330 int id() const {
331 return id_;
332 }
333
[email protected]252b699b2010-02-05 21:38:06334 base::TimeTicks start_time() const {
335 return start_time_;
336 }
337
[email protected]b59ff372009-07-15 22:04:32338 // Called from origin thread.
339 const RequestsList& requests() const {
340 return requests_;
341 }
342
[email protected]68ad3ee2010-01-30 03:45:39343 // Returns the first request attached to the job.
344 const Request* initial_request() const {
345 DCHECK_EQ(origin_loop_, MessageLoop::current());
346 DCHECK(!requests_.empty());
347 return requests_[0];
348 }
349
[email protected]137af622010-02-05 02:14:35350 // Returns true if |req_info| can be fulfilled by this job.
351 bool CanServiceRequest(const RequestInfo& req_info) const {
352 return key_ == resolver_->GetEffectiveKeyForRequest(req_info);
353 }
354
[email protected]b59ff372009-07-15 22:04:32355 private:
[email protected]5389bc72009-11-05 23:34:24356 friend class base::RefCountedThreadSafe<HostResolverImpl::Job>;
357
358 ~Job() {
359 // Free the requests attached to this job.
360 STLDeleteElements(&requests_);
361 }
362
[email protected]6c710ee2010-05-07 07:51:16363 // WARNING: This code runs inside a worker pool. The shutdown code cannot
364 // wait for it to finish, so we must be very careful here about using other
365 // objects (like MessageLoops, Singletons, etc). During shutdown these objects
366 // may no longer exist.
[email protected]b59ff372009-07-15 22:04:32367 void DoLookup() {
[email protected]b59ff372009-07-15 22:04:32368 // Running on the worker thread
[email protected]123ab1e32009-10-21 19:12:57369 error_ = ResolveAddrInfo(resolver_proc_,
370 key_.hostname,
371 key_.address_family,
[email protected]5ea28dea2010-04-08 15:35:13372 key_.host_resolver_flags,
[email protected]21526002010-05-16 19:42:46373 &results_,
374 &os_error_);
[email protected]b59ff372009-07-15 22:04:32375
[email protected]b59ff372009-07-15 22:04:32376 // The origin loop could go away while we are trying to post to it, so we
377 // need to call its PostTask method inside a lock. See ~HostResolver.
378 {
379 AutoLock locked(origin_loop_lock_);
380 if (origin_loop_) {
[email protected]6c710ee2010-05-07 07:51:16381 origin_loop_->PostTask(FROM_HERE,
382 NewRunnableMethod(this, &Job::OnLookupComplete));
[email protected]b59ff372009-07-15 22:04:32383 }
384 }
[email protected]b59ff372009-07-15 22:04:32385 }
386
387 // Callback for when DoLookup() completes (runs on origin thread).
388 void OnLookupComplete() {
389 // Should be running on origin loop.
390 // TODO(eroman): this is being hit by URLRequestTest.CancelTest*,
391 // because MessageLoop::current() == NULL.
392 //DCHECK_EQ(origin_loop_, MessageLoop::current());
393 DCHECK(error_ || results_.head());
394
[email protected]252b699b2010-02-05 21:38:06395 base::TimeDelta job_duration = base::TimeTicks::Now() - start_time_;
396
[email protected]252b699b2010-02-05 21:38:06397 if (had_non_speculative_request_) {
398 // TODO(eroman): Add histogram for job times of non-speculative
399 // requests.
400 }
401
[email protected]21526002010-05-16 19:42:46402 if (error_ != OK) {
403 UMA_HISTOGRAM_CUSTOM_ENUMERATION("Net.OSErrorsForGetAddrinfo",
404 std::abs(os_error_),
405 GetAllGetAddrinfoOSErrors());
406 }
[email protected]f2d8c4212010-02-02 00:56:35407
[email protected]b59ff372009-07-15 22:04:32408 if (was_cancelled())
409 return;
410
411 DCHECK(!requests_.empty());
412
413 // Use the port number of the first request.
414 if (error_ == OK)
415 results_.SetPort(requests_[0]->port());
416
[email protected]21526002010-05-16 19:42:46417 resolver_->OnJobComplete(this, error_, os_error_, results_);
[email protected]b59ff372009-07-15 22:04:32418 }
419
[email protected]f2d8c4212010-02-02 00:56:35420 // Immutable. Can be read from either thread,
421 const int id_;
422
[email protected]b59ff372009-07-15 22:04:32423 // Set on the origin thread, read on the worker thread.
[email protected]123ab1e32009-10-21 19:12:57424 Key key_;
[email protected]b59ff372009-07-15 22:04:32425
426 // Only used on the origin thread (where Resolve was called).
427 HostResolverImpl* resolver_;
428 RequestsList requests_; // The requests waiting on this job.
429
430 // Used to post ourselves onto the origin thread.
431 Lock origin_loop_lock_;
432 MessageLoop* origin_loop_;
433
434 // Hold an owning reference to the HostResolverProc that we are going to use.
435 // This may not be the current resolver procedure by the time we call
436 // ResolveAddrInfo, but that's OK... we'll use it anyways, and the owning
437 // reference ensures that it remains valid until we are done.
438 scoped_refptr<HostResolverProc> resolver_proc_;
439
[email protected]b59ff372009-07-15 22:04:32440 // Assigned on the worker thread, read on the origin thread.
441 int error_;
[email protected]21526002010-05-16 19:42:46442 int os_error_;
[email protected]252b699b2010-02-05 21:38:06443
444 // True if a non-speculative request was ever attached to this job
445 // (regardless of whether or not it was later cancelled.
446 // This boolean is used for histogramming the duration of jobs used to
447 // service non-speculative requests.
448 bool had_non_speculative_request_;
449
[email protected]b59ff372009-07-15 22:04:32450 AddressList results_;
451
[email protected]252b699b2010-02-05 21:38:06452 // The time when the job was started.
453 base::TimeTicks start_time_;
454
[email protected]b59ff372009-07-15 22:04:32455 DISALLOW_COPY_AND_ASSIGN(Job);
456};
457
458//-----------------------------------------------------------------------------
459
[email protected]0f8f1b432010-03-16 19:06:03460// This class represents a request to the worker pool for a "probe for IPv6
461// support" call.
462class HostResolverImpl::IPv6ProbeJob
463 : public base::RefCountedThreadSafe<HostResolverImpl::IPv6ProbeJob> {
464 public:
465 explicit IPv6ProbeJob(HostResolverImpl* resolver)
466 : resolver_(resolver),
467 origin_loop_(MessageLoop::current()) {
[email protected]a9af7112010-05-08 00:56:01468 DCHECK(!was_cancelled());
[email protected]0f8f1b432010-03-16 19:06:03469 }
470
471 void Start() {
[email protected]a9af7112010-05-08 00:56:01472 if (was_cancelled())
473 return;
[email protected]0f8f1b432010-03-16 19:06:03474 DCHECK(IsOnOriginThread());
[email protected]f092e64b2010-03-17 00:39:18475 const bool kIsSlow = true;
[email protected]0f8f1b432010-03-16 19:06:03476 WorkerPool::PostTask(
[email protected]f092e64b2010-03-17 00:39:18477 FROM_HERE, NewRunnableMethod(this, &IPv6ProbeJob::DoProbe), kIsSlow);
[email protected]0f8f1b432010-03-16 19:06:03478 }
479
480 // Cancels the current job.
481 void Cancel() {
[email protected]a9af7112010-05-08 00:56:01482 if (was_cancelled())
483 return;
[email protected]0f8f1b432010-03-16 19:06:03484 DCHECK(IsOnOriginThread());
485 resolver_ = NULL; // Read/write ONLY on origin thread.
486 {
487 AutoLock locked(origin_loop_lock_);
488 // Origin loop may be destroyed before we can use it!
[email protected]a9af7112010-05-08 00:56:01489 origin_loop_ = NULL; // Write ONLY on origin thread.
[email protected]0f8f1b432010-03-16 19:06:03490 }
491 }
492
[email protected]0f8f1b432010-03-16 19:06:03493 private:
494 friend class base::RefCountedThreadSafe<HostResolverImpl::IPv6ProbeJob>;
495
496 ~IPv6ProbeJob() {
497 }
498
[email protected]a9af7112010-05-08 00:56:01499 // Should be run on |orgin_thread_|, but that may not be well defined now.
500 bool was_cancelled() const {
501 if (!resolver_ || !origin_loop_) {
502 DCHECK(!resolver_);
503 DCHECK(!origin_loop_);
504 return true;
505 }
506 return false;
507 }
508
[email protected]0f8f1b432010-03-16 19:06:03509 // Run on worker thread.
510 void DoProbe() {
511 // Do actual testing on this thread, as it takes 40-100ms.
512 AddressFamily family = IPv6Supported() ? ADDRESS_FAMILY_UNSPECIFIED
513 : ADDRESS_FAMILY_IPV4;
514
515 Task* reply = NewRunnableMethod(this, &IPv6ProbeJob::OnProbeComplete,
516 family);
517
518 // The origin loop could go away while we are trying to post to it, so we
519 // need to call its PostTask method inside a lock. See ~HostResolver.
520 {
521 AutoLock locked(origin_loop_lock_);
522 if (origin_loop_) {
523 origin_loop_->PostTask(FROM_HERE, reply);
524 return;
525 }
526 }
527
528 // We didn't post, so delete the reply.
529 delete reply;
530 }
531
532 // Callback for when DoProbe() completes (runs on origin thread).
533 void OnProbeComplete(AddressFamily address_family) {
[email protected]a9af7112010-05-08 00:56:01534 if (was_cancelled())
535 return;
[email protected]0f8f1b432010-03-16 19:06:03536 DCHECK(IsOnOriginThread());
[email protected]a9af7112010-05-08 00:56:01537 resolver_->IPv6ProbeSetDefaultAddressFamily(address_family);
[email protected]0f8f1b432010-03-16 19:06:03538 }
539
540 bool IsOnOriginThread() const {
541 return !MessageLoop::current() || origin_loop_ == MessageLoop::current();
542 }
543
544 // Used/set only on origin thread.
545 HostResolverImpl* resolver_;
546
547 // Used to post ourselves onto the origin thread.
548 Lock origin_loop_lock_;
549 MessageLoop* origin_loop_;
550
551 DISALLOW_COPY_AND_ASSIGN(IPv6ProbeJob);
552};
553
554//-----------------------------------------------------------------------------
555
[email protected]68ad3ee2010-01-30 03:45:39556// We rely on the priority enum values being sequential having starting at 0,
557// and increasing for lower priorities.
558COMPILE_ASSERT(HIGHEST == 0u &&
559 LOWEST > HIGHEST &&
560 NUM_PRIORITIES > LOWEST,
561 priority_indexes_incompatible);
562
563// JobPool contains all the information relating to queued requests, including
564// the limits on how many jobs are allowed to be used for this category of
565// requests.
566class HostResolverImpl::JobPool {
567 public:
568 JobPool(size_t max_outstanding_jobs, size_t max_pending_requests)
569 : num_outstanding_jobs_(0u) {
570 SetConstraints(max_outstanding_jobs, max_pending_requests);
571 }
572
573 ~JobPool() {
574 // Free the pending requests.
575 for (size_t i = 0; i < arraysize(pending_requests_); ++i)
576 STLDeleteElements(&pending_requests_[i]);
577 }
578
579 // Sets the constraints for this pool. See SetPoolConstraints() for the
580 // specific meaning of these parameters.
581 void SetConstraints(size_t max_outstanding_jobs,
582 size_t max_pending_requests) {
[email protected]b1f031dd2010-03-02 23:19:33583 CHECK_NE(max_outstanding_jobs, 0u);
[email protected]68ad3ee2010-01-30 03:45:39584 max_outstanding_jobs_ = max_outstanding_jobs;
585 max_pending_requests_ = max_pending_requests;
586 }
587
588 // Returns the number of pending requests enqueued to this pool.
589 // A pending request is one waiting to be attached to a job.
590 size_t GetNumPendingRequests() const {
591 size_t total = 0u;
592 for (size_t i = 0u; i < arraysize(pending_requests_); ++i)
593 total += pending_requests_[i].size();
594 return total;
595 }
596
597 bool HasPendingRequests() const {
598 return GetNumPendingRequests() > 0u;
599 }
600
601 // Enqueues a request to this pool. As a result of enqueing this request,
602 // the queue may have reached its maximum size. In this case, a request is
603 // evicted from the queue, and returned. Otherwise returns NULL. The caller
604 // is responsible for freeing the evicted request.
605 Request* InsertPendingRequest(Request* req) {
606 PendingRequestsQueue& q = pending_requests_[req->info().priority()];
607 q.push_back(req);
608
609 // If the queue is too big, kick out the lowest priority oldest request.
610 if (GetNumPendingRequests() > max_pending_requests_) {
611 // Iterate over the queues from lowest priority to highest priority.
612 for (int i = static_cast<int>(arraysize(pending_requests_)) - 1;
613 i >= 0; --i) {
614 PendingRequestsQueue& q = pending_requests_[i];
615 if (!q.empty()) {
616 Request* req = q.front();
617 q.pop_front();
618 return req;
619 }
620 }
621 }
622
623 return NULL;
624 }
625
626 // Erases |req| from this container. Caller is responsible for freeing
627 // |req| afterwards.
628 void RemovePendingRequest(Request* req) {
629 PendingRequestsQueue& q = pending_requests_[req->info().priority()];
630 PendingRequestsQueue::iterator it = std::find(q.begin(), q.end(), req);
631 DCHECK(it != q.end());
632 q.erase(it);
633 }
634
635 // Removes and returns the highest priority pending request.
636 Request* RemoveTopPendingRequest() {
637 DCHECK(HasPendingRequests());
638
639 for (size_t i = 0u; i < arraysize(pending_requests_); ++i) {
640 PendingRequestsQueue& q = pending_requests_[i];
641 if (!q.empty()) {
642 Request* req = q.front();
643 q.pop_front();
644 return req;
645 }
646 }
647
648 NOTREACHED();
649 return NULL;
650 }
651
652 // Keeps track of a job that was just added/removed, and belongs to this pool.
653 void AdjustNumOutstandingJobs(int offset) {
654 DCHECK(offset == 1 || (offset == -1 && num_outstanding_jobs_ > 0u));
655 num_outstanding_jobs_ += offset;
656 }
657
658 // Returns true if a new job can be created for this pool.
659 bool CanCreateJob() const {
660 return num_outstanding_jobs_ + 1u <= max_outstanding_jobs_;
661 }
662
663 // Removes any pending requests from the queue which are for the
[email protected]137af622010-02-05 02:14:35664 // same (hostname / effective address-family) as |job|, and attaches them to
665 // |job|.
[email protected]68ad3ee2010-01-30 03:45:39666 void MoveRequestsToJob(Job* job) {
667 for (size_t i = 0u; i < arraysize(pending_requests_); ++i) {
668 PendingRequestsQueue& q = pending_requests_[i];
669 PendingRequestsQueue::iterator req_it = q.begin();
670 while (req_it != q.end()) {
671 Request* req = *req_it;
[email protected]137af622010-02-05 02:14:35672 if (job->CanServiceRequest(req->info())) {
[email protected]68ad3ee2010-01-30 03:45:39673 // Job takes ownership of |req|.
674 job->AddRequest(req);
675 req_it = q.erase(req_it);
676 } else {
677 ++req_it;
678 }
679 }
680 }
681 }
682
683 private:
684 typedef std::deque<Request*> PendingRequestsQueue;
685
686 // Maximum number of concurrent jobs allowed to be started for requests
687 // belonging to this pool.
688 size_t max_outstanding_jobs_;
689
690 // The current number of running jobs that were started for requests
691 // belonging to this pool.
692 size_t num_outstanding_jobs_;
693
694 // The maximum number of requests we allow to be waiting on a job,
695 // for this pool.
696 size_t max_pending_requests_;
697
698 // The requests which are waiting to be started for this pool.
699 PendingRequestsQueue pending_requests_[NUM_PRIORITIES];
700};
701
702//-----------------------------------------------------------------------------
703
[email protected]e95d3aca2010-01-11 22:47:43704HostResolverImpl::HostResolverImpl(
705 HostResolverProc* resolver_proc,
706 HostCache* cache,
[email protected]d13c3272010-02-04 00:24:51707 NetworkChangeNotifier* network_change_notifier,
[email protected]68ad3ee2010-01-30 03:45:39708 size_t max_jobs)
[email protected]112bd462009-12-10 07:23:40709 : cache_(cache),
[email protected]68ad3ee2010-01-30 03:45:39710 max_jobs_(max_jobs),
[email protected]123ab1e32009-10-21 19:12:57711 next_request_id_(0),
[email protected]f2d8c4212010-02-02 00:56:35712 next_job_id_(0),
[email protected]123ab1e32009-10-21 19:12:57713 resolver_proc_(resolver_proc),
[email protected]0c7798452009-10-26 17:59:51714 default_address_family_(ADDRESS_FAMILY_UNSPECIFIED),
[email protected]e95d3aca2010-01-11 22:47:43715 shutdown_(false),
[email protected]0f8f1b432010-03-16 19:06:03716 network_change_notifier_(network_change_notifier),
717 ipv6_probe_monitoring_(false) {
[email protected]68ad3ee2010-01-30 03:45:39718 DCHECK_GT(max_jobs, 0u);
719
720 // It is cumbersome to expose all of the constraints in the constructor,
721 // so we choose some defaults, which users can override later.
722 job_pools_[POOL_NORMAL] = new JobPool(max_jobs, 100u * max_jobs);
723
[email protected]b59ff372009-07-15 22:04:32724#if defined(OS_WIN)
725 EnsureWinsockInit();
726#endif
[email protected]61a86c42010-04-19 22:45:53727 if (network_change_notifier_)
728 network_change_notifier_->AddObserver(this);
[email protected]b59ff372009-07-15 22:04:32729}
730
731HostResolverImpl::~HostResolverImpl() {
732 // Cancel the outstanding jobs. Those jobs may contain several attached
733 // requests, which will also be cancelled.
[email protected]0f8f1b432010-03-16 19:06:03734 DiscardIPv6ProbeJob();
735
[email protected]b59ff372009-07-15 22:04:32736 for (JobMap::iterator it = jobs_.begin(); it != jobs_.end(); ++it)
737 it->second->Cancel();
738
739 // In case we are being deleted during the processing of a callback.
740 if (cur_completing_job_)
741 cur_completing_job_->Cancel();
[email protected]e95d3aca2010-01-11 22:47:43742
[email protected]61a86c42010-04-19 22:45:53743 if (network_change_notifier_)
744 network_change_notifier_->RemoveObserver(this);
745
[email protected]68ad3ee2010-01-30 03:45:39746 // Delete the job pools.
747 for (size_t i = 0u; i < arraysize(job_pools_); ++i)
748 delete job_pools_[i];
[email protected]b59ff372009-07-15 22:04:32749}
750
751// TODO(eroman): Don't create cache entries for hostnames which are simply IP
752// address literals.
[email protected]684970b2009-08-14 04:54:46753int HostResolverImpl::Resolve(const RequestInfo& info,
[email protected]b59ff372009-07-15 22:04:32754 AddressList* addresses,
755 CompletionCallback* callback,
[email protected]684970b2009-08-14 04:54:46756 RequestHandle* out_req,
[email protected]9e743cd2010-03-16 07:03:53757 const BoundNetLog& net_log) {
[email protected]b59ff372009-07-15 22:04:32758 if (shutdown_)
759 return ERR_UNEXPECTED;
760
761 // Choose a unique ID number for observers to see.
762 int request_id = next_request_id_++;
763
[email protected]9e743cd2010-03-16 07:03:53764 // Update the net log and notify registered observers.
765 OnStartRequest(net_log, request_id, info);
[email protected]b59ff372009-07-15 22:04:32766
[email protected]123ab1e32009-10-21 19:12:57767 // Build a key that identifies the request in the cache and in the
768 // outstanding jobs map.
[email protected]137af622010-02-05 02:14:35769 Key key = GetEffectiveKeyForRequest(info);
[email protected]123ab1e32009-10-21 19:12:57770
[email protected]b59ff372009-07-15 22:04:32771 // If we have an unexpired cache entry, use it.
[email protected]112bd462009-12-10 07:23:40772 if (info.allow_cached_response() && cache_.get()) {
773 const HostCache::Entry* cache_entry = cache_->Lookup(
[email protected]123ab1e32009-10-21 19:12:57774 key, base::TimeTicks::Now());
[email protected]b59ff372009-07-15 22:04:32775 if (cache_entry) {
[email protected]21526002010-05-16 19:42:46776 int net_error = cache_entry->error;
777 if (net_error == OK)
[email protected]112bd462009-12-10 07:23:40778 addresses->SetFrom(cache_entry->addrlist, info.port());
[email protected]b59ff372009-07-15 22:04:32779
[email protected]9e743cd2010-03-16 07:03:53780 // Update the net log and notify registered observers.
[email protected]21526002010-05-16 19:42:46781 OnFinishRequest(net_log, request_id, info, net_error,
782 0, /* os_error (unknown since from cache) */
783 true /* was_from_cache */);
[email protected]b59ff372009-07-15 22:04:32784
[email protected]21526002010-05-16 19:42:46785 return net_error;
[email protected]b59ff372009-07-15 22:04:32786 }
787 }
788
789 // If no callback was specified, do a synchronous resolution.
790 if (!callback) {
791 AddressList addrlist;
[email protected]21526002010-05-16 19:42:46792 int os_error = 0;
[email protected]b59ff372009-07-15 22:04:32793 int error = ResolveAddrInfo(
[email protected]5ea28dea2010-04-08 15:35:13794 effective_resolver_proc(), key.hostname, key.address_family,
[email protected]21526002010-05-16 19:42:46795 key.host_resolver_flags, &addrlist, &os_error);
[email protected]b59ff372009-07-15 22:04:32796 if (error == OK) {
797 addrlist.SetPort(info.port());
798 *addresses = addrlist;
799 }
800
801 // Write to cache.
[email protected]112bd462009-12-10 07:23:40802 if (cache_.get())
803 cache_->Set(key, error, addrlist, base::TimeTicks::Now());
[email protected]b59ff372009-07-15 22:04:32804
[email protected]9e743cd2010-03-16 07:03:53805 // Update the net log and notify registered observers.
[email protected]21526002010-05-16 19:42:46806 OnFinishRequest(net_log, request_id, info, error, os_error,
807 false /* was_from_cache */);
[email protected]b59ff372009-07-15 22:04:32808
809 return error;
810 }
811
812 // Create a handle for this request, and pass it back to the user if they
813 // asked for it (out_req != NULL).
[email protected]9e743cd2010-03-16 07:03:53814 Request* req = new Request(net_log, request_id, info, callback, addresses);
[email protected]b59ff372009-07-15 22:04:32815 if (out_req)
816 *out_req = reinterpret_cast<RequestHandle>(req);
817
818 // Next we need to attach our request to a "job". This job is responsible for
819 // calling "getaddrinfo(hostname)" on a worker thread.
820 scoped_refptr<Job> job;
821
[email protected]123ab1e32009-10-21 19:12:57822 // If there is already an outstanding job to resolve |key|, use
[email protected]b59ff372009-07-15 22:04:32823 // it. This prevents starting concurrent resolves for the same hostname.
[email protected]123ab1e32009-10-21 19:12:57824 job = FindOutstandingJob(key);
[email protected]b59ff372009-07-15 22:04:32825 if (job) {
826 job->AddRequest(req);
827 } else {
[email protected]68ad3ee2010-01-30 03:45:39828 JobPool* pool = GetPoolForRequest(req);
829 if (CanCreateJobForPool(*pool)) {
830 CreateAndStartJob(req);
831 } else {
832 return EnqueueRequest(pool, req);
833 }
[email protected]b59ff372009-07-15 22:04:32834 }
835
836 // Completion happens during OnJobComplete(Job*).
837 return ERR_IO_PENDING;
838}
839
840// See OnJobComplete(Job*) for why it is important not to clean out
841// cancelled requests from Job::requests_.
842void HostResolverImpl::CancelRequest(RequestHandle req_handle) {
[email protected]bf0b51c2009-08-01 23:46:40843 if (shutdown_) {
[email protected]ff1f61b92009-08-03 23:20:23844 // TODO(eroman): temp hack for: http://crbug.com/18373
845 // Because we destroy outstanding requests during Shutdown(),
846 // |req_handle| is already cancelled.
[email protected]bf0b51c2009-08-01 23:46:40847 LOG(ERROR) << "Called HostResolverImpl::CancelRequest() after Shutdown().";
848 StackTrace().PrintBacktrace();
849 return;
850 }
[email protected]b59ff372009-07-15 22:04:32851 Request* req = reinterpret_cast<Request*>(req_handle);
852 DCHECK(req);
[email protected]68ad3ee2010-01-30 03:45:39853
854 scoped_ptr<Request> request_deleter; // Frees at end of function.
855
856 if (!req->job()) {
857 // If the request was not attached to a job yet, it must have been
858 // enqueued into a pool. Remove it from that pool's queue.
859 // Otherwise if it was attached to a job, the job is responsible for
860 // deleting it.
861 JobPool* pool = GetPoolForRequest(req);
862 pool->RemovePendingRequest(req);
863 request_deleter.reset(req);
864 }
865
[email protected]b59ff372009-07-15 22:04:32866 // NULL out the fields of req, to mark it as cancelled.
867 req->MarkAsCancelled();
[email protected]9e743cd2010-03-16 07:03:53868 OnCancelRequest(req->net_log(), req->id(), req->info());
[email protected]b59ff372009-07-15 22:04:32869}
870
[email protected]e95d3aca2010-01-11 22:47:43871void HostResolverImpl::AddObserver(HostResolver::Observer* observer) {
[email protected]b59ff372009-07-15 22:04:32872 observers_.push_back(observer);
873}
874
[email protected]e95d3aca2010-01-11 22:47:43875void HostResolverImpl::RemoveObserver(HostResolver::Observer* observer) {
[email protected]b59ff372009-07-15 22:04:32876 ObserversList::iterator it =
877 std::find(observers_.begin(), observers_.end(), observer);
878
879 // Observer must exist.
880 DCHECK(it != observers_.end());
881
882 observers_.erase(it);
883}
884
[email protected]0f8f1b432010-03-16 19:06:03885void HostResolverImpl::SetDefaultAddressFamily(AddressFamily address_family) {
886 ipv6_probe_monitoring_ = false;
887 DiscardIPv6ProbeJob();
888 default_address_family_ = address_family;
889}
890
891void HostResolverImpl::ProbeIPv6Support() {
892 DCHECK(!ipv6_probe_monitoring_);
893 ipv6_probe_monitoring_ = true;
[email protected]61a86c42010-04-19 22:45:53894 OnIPAddressChanged(); // Give initial setup call.
[email protected]0f8f1b432010-03-16 19:06:03895}
896
[email protected]b59ff372009-07-15 22:04:32897void HostResolverImpl::Shutdown() {
898 shutdown_ = true;
899
900 // Cancel the outstanding jobs.
901 for (JobMap::iterator it = jobs_.begin(); it != jobs_.end(); ++it)
902 it->second->Cancel();
903 jobs_.clear();
[email protected]0a175512010-04-20 03:09:25904 DiscardIPv6ProbeJob();
[email protected]b59ff372009-07-15 22:04:32905}
906
[email protected]68ad3ee2010-01-30 03:45:39907void HostResolverImpl::SetPoolConstraints(JobPoolIndex pool_index,
908 size_t max_outstanding_jobs,
909 size_t max_pending_requests) {
[email protected]b1f031dd2010-03-02 23:19:33910 CHECK_GE(pool_index, 0);
911 CHECK_LT(pool_index, POOL_COUNT);
[email protected]68ad3ee2010-01-30 03:45:39912 CHECK(jobs_.empty()) << "Can only set constraints during setup";
913 JobPool* pool = job_pools_[pool_index];
914 pool->SetConstraints(max_outstanding_jobs, max_pending_requests);
915}
916
[email protected]b59ff372009-07-15 22:04:32917void HostResolverImpl::AddOutstandingJob(Job* job) {
[email protected]123ab1e32009-10-21 19:12:57918 scoped_refptr<Job>& found_job = jobs_[job->key()];
[email protected]b59ff372009-07-15 22:04:32919 DCHECK(!found_job);
920 found_job = job;
[email protected]68ad3ee2010-01-30 03:45:39921
922 JobPool* pool = GetPoolForRequest(job->initial_request());
923 pool->AdjustNumOutstandingJobs(1);
[email protected]b59ff372009-07-15 22:04:32924}
925
[email protected]123ab1e32009-10-21 19:12:57926HostResolverImpl::Job* HostResolverImpl::FindOutstandingJob(const Key& key) {
927 JobMap::iterator it = jobs_.find(key);
[email protected]b59ff372009-07-15 22:04:32928 if (it != jobs_.end())
929 return it->second;
930 return NULL;
931}
932
933void HostResolverImpl::RemoveOutstandingJob(Job* job) {
[email protected]123ab1e32009-10-21 19:12:57934 JobMap::iterator it = jobs_.find(job->key());
[email protected]b59ff372009-07-15 22:04:32935 DCHECK(it != jobs_.end());
936 DCHECK_EQ(it->second.get(), job);
937 jobs_.erase(it);
[email protected]68ad3ee2010-01-30 03:45:39938
939 JobPool* pool = GetPoolForRequest(job->initial_request());
940 pool->AdjustNumOutstandingJobs(-1);
[email protected]b59ff372009-07-15 22:04:32941}
942
943void HostResolverImpl::OnJobComplete(Job* job,
[email protected]21526002010-05-16 19:42:46944 int net_error,
945 int os_error,
[email protected]27f99c82009-10-29 22:21:00946 const AddressList& addrlist) {
[email protected]b59ff372009-07-15 22:04:32947 RemoveOutstandingJob(job);
948
949 // Write result to the cache.
[email protected]112bd462009-12-10 07:23:40950 if (cache_.get())
[email protected]21526002010-05-16 19:42:46951 cache_->Set(job->key(), net_error, addrlist, base::TimeTicks::Now());
[email protected]b59ff372009-07-15 22:04:32952
953 // Make a note that we are executing within OnJobComplete() in case the
954 // HostResolver is deleted by a callback invocation.
955 DCHECK(!cur_completing_job_);
956 cur_completing_job_ = job;
957
[email protected]68ad3ee2010-01-30 03:45:39958 // Try to start any queued requests now that a job-slot has freed up.
959 ProcessQueuedRequests();
960
[email protected]b59ff372009-07-15 22:04:32961 // Complete all of the requests that were attached to the job.
962 for (RequestsList::const_iterator it = job->requests().begin();
963 it != job->requests().end(); ++it) {
964 Request* req = *it;
965 if (!req->was_cancelled()) {
966 DCHECK_EQ(job, req->job());
967
[email protected]9e743cd2010-03-16 07:03:53968 // Update the net log and notify registered observers.
[email protected]21526002010-05-16 19:42:46969 OnFinishRequest(req->net_log(), req->id(), req->info(), net_error,
970 os_error, false /* was_from_cache */);
[email protected]b59ff372009-07-15 22:04:32971
[email protected]21526002010-05-16 19:42:46972 req->OnComplete(net_error, addrlist);
[email protected]b59ff372009-07-15 22:04:32973
974 // Check if the job was cancelled as a result of running the callback.
975 // (Meaning that |this| was deleted).
976 if (job->was_cancelled())
977 return;
978 }
979 }
980
981 cur_completing_job_ = NULL;
982}
983
[email protected]9e743cd2010-03-16 07:03:53984void HostResolverImpl::OnStartRequest(const BoundNetLog& net_log,
[email protected]54e13772009-08-14 03:01:09985 int request_id,
986 const RequestInfo& info) {
[email protected]ec11be62010-04-28 19:28:09987 net_log.BeginEvent(NetLog::TYPE_HOST_RESOLVER_IMPL, NULL);
[email protected]54e13772009-08-14 03:01:09988
[email protected]54e13772009-08-14 03:01:09989 // Notify the observers of the start.
990 if (!observers_.empty()) {
[email protected]54e13772009-08-14 03:01:09991 for (ObserversList::iterator it = observers_.begin();
992 it != observers_.end(); ++it) {
993 (*it)->OnStartResolution(request_id, info);
994 }
[email protected]b59ff372009-07-15 22:04:32995 }
996}
997
[email protected]9e743cd2010-03-16 07:03:53998void HostResolverImpl::OnFinishRequest(const BoundNetLog& net_log,
[email protected]54e13772009-08-14 03:01:09999 int request_id,
1000 const RequestInfo& info,
[email protected]21526002010-05-16 19:42:461001 int net_error,
1002 int os_error,
1003 bool was_from_cache) {
1004 bool was_resolved = net_error == OK;
1005
[email protected]54e13772009-08-14 03:01:091006 // Notify the observers of the completion.
1007 if (!observers_.empty()) {
[email protected]54e13772009-08-14 03:01:091008 for (ObserversList::iterator it = observers_.begin();
1009 it != observers_.end(); ++it) {
1010 (*it)->OnFinishResolutionWithStatus(request_id, was_resolved, info);
1011 }
[email protected]b59ff372009-07-15 22:04:321012 }
[email protected]54e13772009-08-14 03:01:091013
[email protected]21526002010-05-16 19:42:461014 // Log some extra parameters on failure.
1015 scoped_refptr<NetLog::EventParameters> params;
1016 if (!was_resolved)
1017 params = new HostResolveFailedParams(net_error, os_error, was_from_cache);
1018
1019 net_log.EndEvent(NetLog::TYPE_HOST_RESOLVER_IMPL, params);
[email protected]b59ff372009-07-15 22:04:321020}
1021
[email protected]9e743cd2010-03-16 07:03:531022void HostResolverImpl::OnCancelRequest(const BoundNetLog& net_log,
[email protected]54e13772009-08-14 03:01:091023 int request_id,
1024 const RequestInfo& info) {
[email protected]ec11be62010-04-28 19:28:091025 net_log.AddEvent(NetLog::TYPE_CANCELLED, NULL);
[email protected]54e13772009-08-14 03:01:091026
[email protected]54e13772009-08-14 03:01:091027 // Notify the observers of the cancellation.
1028 if (!observers_.empty()) {
[email protected]54e13772009-08-14 03:01:091029 for (ObserversList::iterator it = observers_.begin();
1030 it != observers_.end(); ++it) {
1031 (*it)->OnCancelResolution(request_id, info);
1032 }
[email protected]b59ff372009-07-15 22:04:321033 }
[email protected]54e13772009-08-14 03:01:091034
[email protected]ec11be62010-04-28 19:28:091035 net_log.EndEvent(NetLog::TYPE_HOST_RESOLVER_IMPL, NULL);
[email protected]b59ff372009-07-15 22:04:321036}
1037
[email protected]61a86c42010-04-19 22:45:531038void HostResolverImpl::OnIPAddressChanged() {
[email protected]e95d3aca2010-01-11 22:47:431039 if (cache_.get())
1040 cache_->clear();
[email protected]0f8f1b432010-03-16 19:06:031041 if (ipv6_probe_monitoring_) {
[email protected]0a175512010-04-20 03:09:251042 DCHECK(!shutdown_);
1043 if (shutdown_)
1044 return;
[email protected]0f8f1b432010-03-16 19:06:031045 DiscardIPv6ProbeJob();
1046 ipv6_probe_job_ = new IPv6ProbeJob(this);
1047 ipv6_probe_job_->Start();
1048 }
1049}
1050
1051void HostResolverImpl::DiscardIPv6ProbeJob() {
1052 if (ipv6_probe_job_.get()) {
1053 ipv6_probe_job_->Cancel();
1054 ipv6_probe_job_ = NULL;
1055 }
1056}
1057
1058void HostResolverImpl::IPv6ProbeSetDefaultAddressFamily(
1059 AddressFamily address_family) {
1060 DCHECK(address_family == ADDRESS_FAMILY_UNSPECIFIED ||
1061 address_family == ADDRESS_FAMILY_IPV4);
[email protected]f092e64b2010-03-17 00:39:181062 if (default_address_family_ != address_family) {
1063 LOG(INFO) << "IPv6Probe forced AddressFamily setting to "
1064 << ((address_family == ADDRESS_FAMILY_UNSPECIFIED)
1065 ? "ADDRESS_FAMILY_UNSPECIFIED"
1066 : "ADDRESS_FAMILY_IPV4");
1067 }
[email protected]0f8f1b432010-03-16 19:06:031068 default_address_family_ = address_family;
1069 // Drop reference since the job has called us back.
1070 DiscardIPv6ProbeJob();
[email protected]e95d3aca2010-01-11 22:47:431071}
1072
[email protected]68ad3ee2010-01-30 03:45:391073// static
1074HostResolverImpl::JobPoolIndex HostResolverImpl::GetJobPoolIndexForRequest(
1075 const Request* req) {
1076 return POOL_NORMAL;
1077}
1078
1079bool HostResolverImpl::CanCreateJobForPool(const JobPool& pool) const {
1080 DCHECK_LE(jobs_.size(), max_jobs_);
1081
1082 // We can't create another job if it would exceed the global total.
1083 if (jobs_.size() + 1 > max_jobs_)
1084 return false;
1085
1086 // Check whether the pool's constraints are met.
1087 return pool.CanCreateJob();
1088}
1089
1090void HostResolverImpl::ProcessQueuedRequests() {
1091 // Find the highest priority request that can be scheduled.
1092 Request* top_req = NULL;
1093 for (size_t i = 0; i < arraysize(job_pools_); ++i) {
1094 JobPool* pool = job_pools_[i];
1095 if (pool->HasPendingRequests() && CanCreateJobForPool(*pool)) {
1096 top_req = pool->RemoveTopPendingRequest();
1097 break;
1098 }
1099 }
1100
1101 if (!top_req)
1102 return;
1103
1104 scoped_refptr<Job> job = CreateAndStartJob(top_req);
1105
1106 // Search for any other pending request which can piggy-back off this job.
1107 for (size_t pool_i = 0; pool_i < POOL_COUNT; ++pool_i) {
1108 JobPool* pool = job_pools_[pool_i];
1109 pool->MoveRequestsToJob(job);
1110 }
1111}
1112
[email protected]137af622010-02-05 02:14:351113HostResolverImpl::Key HostResolverImpl::GetEffectiveKeyForRequest(
1114 const RequestInfo& info) const {
1115 AddressFamily effective_address_family = info.address_family();
1116 if (effective_address_family == ADDRESS_FAMILY_UNSPECIFIED)
1117 effective_address_family = default_address_family_;
[email protected]5ea28dea2010-04-08 15:35:131118 return Key(info.hostname(), effective_address_family,
1119 info.host_resolver_flags());
[email protected]137af622010-02-05 02:14:351120}
1121
[email protected]68ad3ee2010-01-30 03:45:391122HostResolverImpl::Job* HostResolverImpl::CreateAndStartJob(Request* req) {
1123 DCHECK(CanCreateJobForPool(*GetPoolForRequest(req)));
[email protected]137af622010-02-05 02:14:351124 Key key = GetEffectiveKeyForRequest(req->info());
[email protected]6e76d8d2010-05-10 23:13:561125 scoped_refptr<Job> job = new Job(next_job_id_++, this, key);
[email protected]68ad3ee2010-01-30 03:45:391126 job->AddRequest(req);
1127 AddOutstandingJob(job);
1128 job->Start();
1129 return job.get();
1130}
1131
1132int HostResolverImpl::EnqueueRequest(JobPool* pool, Request* req) {
[email protected]68ad3ee2010-01-30 03:45:391133 scoped_ptr<Request> req_evicted_from_queue(
1134 pool->InsertPendingRequest(req));
1135
1136 // If the queue has become too large, we need to kick something out.
1137 if (req_evicted_from_queue.get()) {
1138 Request* r = req_evicted_from_queue.get();
1139 int error = ERR_HOST_RESOLVER_QUEUE_TOO_LARGE;
1140
[email protected]21526002010-05-16 19:42:461141 OnFinishRequest(r->net_log(), r->id(), r->info(), error,
1142 0, /* os_error (not applicable) */
1143 false /* was_from_cache */);
[email protected]68ad3ee2010-01-30 03:45:391144
1145 if (r == req)
1146 return error;
1147
1148 r->OnComplete(error, AddressList());
1149 }
1150
1151 return ERR_IO_PENDING;
1152}
1153
[email protected]b59ff372009-07-15 22:04:321154} // namespace net