host_resolver_impl.cc revision 3f50c38dc070f4bb515c1b64450dae14f316474e
1// Copyright (c) 2010 The Chromium Authors. All rights reserved.
2// 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
7#if defined(OS_WIN)
8#include <Winsock2.h>
9#elif defined(OS_POSIX)
10#include <netdb.h>
11#endif
12
13#include <cmath>
14#include <deque>
15#include <vector>
16
17#include "base/basictypes.h"
18#include "base/compiler_specific.h"
19#include "base/debug/debugger.h"
20#include "base/debug/stack_trace.h"
21#include "base/lock.h"
22#include "base/message_loop.h"
23#include "base/metrics/field_trial.h"
24#include "base/metrics/histogram.h"
25#include "base/stl_util-inl.h"
26#include "base/string_util.h"
27#include "base/threading/worker_pool.h"
28#include "base/time.h"
29#include "base/utf_string_conversions.h"
30#include "base/values.h"
31#include "net/base/address_list.h"
32#include "net/base/address_list_net_log_param.h"
33#include "net/base/host_port_pair.h"
34#include "net/base/host_resolver_proc.h"
35#include "net/base/net_errors.h"
36#include "net/base/net_log.h"
37#include "net/base/net_util.h"
38
39#if defined(OS_WIN)
40#include "net/base/winsock_init.h"
41#endif
42
43namespace net {
44
45namespace {
46
47// We use a separate histogram name for each platform to facilitate the
48// display of error codes by their symbolic name (since each platform has
49// different mappings).
50const char kOSErrorsForGetAddrinfoHistogramName[] =
51#if defined(OS_WIN)
52    "Net.OSErrorsForGetAddrinfo_Win";
53#elif defined(OS_MACOSX)
54    "Net.OSErrorsForGetAddrinfo_Mac";
55#elif defined(OS_LINUX)
56    "Net.OSErrorsForGetAddrinfo_Linux";
57#else
58    "Net.OSErrorsForGetAddrinfo";
59#endif
60
61HostCache* CreateDefaultCache() {
62  static const size_t kMaxHostCacheEntries = 100;
63
64  HostCache* cache = new HostCache(
65      kMaxHostCacheEntries,
66      base::TimeDelta::FromMinutes(1),
67      base::TimeDelta::FromSeconds(0));  // Disable caching of failed DNS.
68
69  return cache;
70}
71
72}  // anonymous namespace
73
74HostResolver* CreateSystemHostResolver(size_t max_concurrent_resolves,
75                                       HostResolverProc* resolver_proc,
76                                       NetLog* net_log) {
77  // Maximum of 8 concurrent resolver threads.
78  // Some routers (or resolvers) appear to start to provide host-not-found if
79  // too many simultaneous resolutions are pending.  This number needs to be
80  // further optimized, but 8 is what FF currently does.
81  static const size_t kDefaultMaxJobs = 8u;
82
83  if (max_concurrent_resolves == HostResolver::kDefaultParallelism)
84    max_concurrent_resolves = kDefaultMaxJobs;
85
86  HostResolverImpl* resolver =
87      new HostResolverImpl(resolver_proc, CreateDefaultCache(),
88                           max_concurrent_resolves, net_log);
89
90  return resolver;
91}
92
93static int ResolveAddrInfo(HostResolverProc* resolver_proc,
94                           const std::string& host,
95                           AddressFamily address_family,
96                           HostResolverFlags host_resolver_flags,
97                           AddressList* out,
98                           int* os_error) {
99  if (resolver_proc) {
100    // Use the custom procedure.
101    return resolver_proc->Resolve(host, address_family,
102                                  host_resolver_flags, out, os_error);
103  } else {
104    // Use the system procedure (getaddrinfo).
105    return SystemHostResolverProc(host, address_family,
106                                  host_resolver_flags, out, os_error);
107  }
108}
109
110// Extra parameters to attach to the NetLog when the resolve failed.
111class HostResolveFailedParams : public NetLog::EventParameters {
112 public:
113  HostResolveFailedParams(int net_error, int os_error)
114      : net_error_(net_error),
115        os_error_(os_error) {
116  }
117
118  virtual Value* ToValue() const {
119    DictionaryValue* dict = new DictionaryValue();
120    dict->SetInteger("net_error", net_error_);
121
122    if (os_error_) {
123      dict->SetInteger("os_error", os_error_);
124#if defined(OS_POSIX)
125      dict->SetString("os_error_string", gai_strerror(os_error_));
126#elif defined(OS_WIN)
127      // Map the error code to a human-readable string.
128      LPWSTR error_string = NULL;
129      int size = FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
130                               FORMAT_MESSAGE_FROM_SYSTEM,
131                               0,  // Use the internal message table.
132                               os_error_,
133                               0,  // Use default language.
134                               (LPWSTR)&error_string,
135                               0,  // Buffer size.
136                               0);  // Arguments (unused).
137      dict->SetString("os_error_string", WideToUTF8(error_string));
138      LocalFree(error_string);
139#endif
140    }
141
142    return dict;
143  }
144
145 private:
146  const int net_error_;
147  const int os_error_;
148};
149
150// Parameters representing the information in a RequestInfo object, along with
151// the associated NetLog::Source.
152class RequestInfoParameters : public NetLog::EventParameters {
153 public:
154  RequestInfoParameters(const HostResolver::RequestInfo& info,
155                        const NetLog::Source& source)
156      : info_(info), source_(source) {}
157
158  virtual Value* ToValue() const {
159    DictionaryValue* dict = new DictionaryValue();
160    dict->SetString("host", info_.host_port_pair().ToString());
161    dict->SetInteger("address_family",
162                     static_cast<int>(info_.address_family()));
163    dict->SetBoolean("allow_cached_response", info_.allow_cached_response());
164    dict->SetBoolean("is_speculative", info_.is_speculative());
165    dict->SetInteger("priority", info_.priority());
166
167    if (source_.is_valid())
168      dict->Set("source_dependency", source_.ToValue());
169
170    return dict;
171  }
172
173 private:
174  const HostResolver::RequestInfo info_;
175  const NetLog::Source source_;
176};
177
178// Parameters associated with the creation of a HostResolveImpl::Job.
179class JobCreationParameters : public NetLog::EventParameters {
180 public:
181  JobCreationParameters(const std::string& host, const NetLog::Source& source)
182      : host_(host), source_(source) {}
183
184  virtual Value* ToValue() const {
185    DictionaryValue* dict = new DictionaryValue();
186    dict->SetString("host", host_);
187    dict->Set("source_dependency", source_.ToValue());
188    return dict;
189  }
190
191 private:
192  const std::string host_;
193  const NetLog::Source source_;
194};
195
196// Gets a list of the likely error codes that getaddrinfo() can return
197// (non-exhaustive). These are the error codes that we will track via
198// a histogram.
199std::vector<int> GetAllGetAddrinfoOSErrors() {
200  int os_errors[] = {
201#if defined(OS_POSIX)
202#ifndef ANDROID
203    // "obsoleted ..." see bionic/libc/include/netdb.h
204    EAI_ADDRFAMILY,
205#endif
206    EAI_AGAIN,
207    EAI_BADFLAGS,
208    EAI_FAIL,
209    EAI_FAMILY,
210    EAI_MEMORY,
211    EAI_NODATA,
212    EAI_NONAME,
213    EAI_SERVICE,
214    EAI_SOCKTYPE,
215    EAI_SYSTEM,
216#elif defined(OS_WIN)
217    // See: http://msdn.microsoft.com/en-us/library/ms738520(VS.85).aspx
218    WSA_NOT_ENOUGH_MEMORY,
219    WSAEAFNOSUPPORT,
220    WSAEINVAL,
221    WSAESOCKTNOSUPPORT,
222    WSAHOST_NOT_FOUND,
223    WSANO_DATA,
224    WSANO_RECOVERY,
225    WSANOTINITIALISED,
226    WSATRY_AGAIN,
227    WSATYPE_NOT_FOUND,
228    // The following are not in doc, but might be to appearing in results :-(.
229    WSA_INVALID_HANDLE,
230#endif
231  };
232
233  // Histogram enumerations require positive numbers.
234  std::vector<int> errors;
235  for (size_t i = 0; i < arraysize(os_errors); ++i) {
236    errors.push_back(std::abs(os_errors[i]));
237    // Also add N+1 for each error, so the bucket that contains our expected
238    // error is of size 1. That way if we get unexpected error codes, they
239    // won't fall into the same buckets as the expected ones.
240    errors.push_back(std::abs(os_errors[i]) + 1);
241  }
242  return errors;
243}
244
245//-----------------------------------------------------------------------------
246
247class HostResolverImpl::Request {
248 public:
249  Request(const BoundNetLog& source_net_log,
250          const BoundNetLog& request_net_log,
251          int id,
252          const RequestInfo& info,
253          CompletionCallback* callback,
254          AddressList* addresses)
255      : source_net_log_(source_net_log),
256        request_net_log_(request_net_log),
257        id_(id),
258        info_(info),
259        job_(NULL),
260        callback_(callback),
261        addresses_(addresses) {
262  }
263
264  // Mark the request as cancelled.
265  void MarkAsCancelled() {
266    job_ = NULL;
267    callback_ = NULL;
268    addresses_ = NULL;
269  }
270
271  bool was_cancelled() const {
272    return callback_ == NULL;
273  }
274
275  void set_job(Job* job) {
276    DCHECK(job != NULL);
277    // Identify which job the request is waiting on.
278    job_ = job;
279  }
280
281  void OnComplete(int error, const AddressList& addrlist) {
282    if (error == OK)
283      addresses_->SetFrom(addrlist, port());
284    CompletionCallback* callback = callback_;
285    MarkAsCancelled();
286    callback->Run(error);
287  }
288
289  int port() const {
290    return info_.port();
291  }
292
293  Job* job() const {
294    return job_;
295  }
296
297  const BoundNetLog& source_net_log() {
298    return source_net_log_;
299  }
300
301  const BoundNetLog& request_net_log() {
302    return request_net_log_;
303  }
304
305  int id() const {
306    return id_;
307  }
308
309  const RequestInfo& info() const {
310    return info_;
311  }
312
313 private:
314  BoundNetLog source_net_log_;
315  BoundNetLog request_net_log_;
316
317  // Unique ID for this request. Used by observers to identify requests.
318  int id_;
319
320  // The request info that started the request.
321  RequestInfo info_;
322
323  // The resolve job (running in worker pool) that this request is dependent on.
324  Job* job_;
325
326  // The user's callback to invoke when the request completes.
327  CompletionCallback* callback_;
328
329  // The address list to save result into.
330  AddressList* addresses_;
331
332  DISALLOW_COPY_AND_ASSIGN(Request);
333};
334
335//------------------------------------------------------------------------------
336
337// Provide a common macro to simplify code and readability. We must use a
338// macros as the underlying HISTOGRAM macro creates static varibles.
339#define DNS_HISTOGRAM(name, time) UMA_HISTOGRAM_CUSTOM_TIMES(name, time, \
340    base::TimeDelta::FromMicroseconds(1), base::TimeDelta::FromHours(1), 100)
341
342// This class represents a request to the worker pool for a "getaddrinfo()"
343// call.
344class HostResolverImpl::Job
345    : public base::RefCountedThreadSafe<HostResolverImpl::Job> {
346 public:
347  Job(int id,
348      HostResolverImpl* resolver,
349      const Key& key,
350      const BoundNetLog& source_net_log,
351      NetLog* net_log)
352     : id_(id),
353       key_(key),
354       resolver_(resolver),
355       origin_loop_(MessageLoop::current()),
356       resolver_proc_(resolver->effective_resolver_proc()),
357       error_(OK),
358       os_error_(0),
359       had_non_speculative_request_(false),
360       net_log_(BoundNetLog::Make(net_log,
361                                  NetLog::SOURCE_HOST_RESOLVER_IMPL_JOB)) {
362    net_log_.BeginEvent(
363        NetLog::TYPE_HOST_RESOLVER_IMPL_JOB,
364        make_scoped_refptr(
365            new JobCreationParameters(key.hostname, source_net_log.source())));
366  }
367
368  // Attaches a request to this job. The job takes ownership of |req| and will
369  // take care to delete it.
370  void AddRequest(Request* req) {
371    req->request_net_log().BeginEvent(
372        NetLog::TYPE_HOST_RESOLVER_IMPL_JOB_ATTACH,
373        make_scoped_refptr(new NetLogSourceParameter(
374            "source_dependency", net_log_.source())));
375
376    req->set_job(this);
377    requests_.push_back(req);
378
379    if (!req->info().is_speculative())
380      had_non_speculative_request_ = true;
381  }
382
383  // Called from origin loop.
384  void Start() {
385    start_time_ = base::TimeTicks::Now();
386
387    // Dispatch the job to a worker thread.
388    if (!base::WorkerPool::PostTask(FROM_HERE,
389            NewRunnableMethod(this, &Job::DoLookup), true)) {
390      NOTREACHED();
391
392      // Since we could be running within Resolve() right now, we can't just
393      // call OnLookupComplete().  Instead we must wait until Resolve() has
394      // returned (IO_PENDING).
395      error_ = ERR_UNEXPECTED;
396      MessageLoop::current()->PostTask(
397          FROM_HERE, NewRunnableMethod(this, &Job::OnLookupComplete));
398    }
399  }
400
401  // Cancels the current job. Callable from origin thread.
402  void Cancel() {
403    net_log_.AddEvent(NetLog::TYPE_CANCELLED, NULL);
404
405    HostResolver* resolver = resolver_;
406    resolver_ = NULL;
407
408    // Mark the job as cancelled, so when worker thread completes it will
409    // not try to post completion to origin loop.
410    {
411      AutoLock locked(origin_loop_lock_);
412      origin_loop_ = NULL;
413    }
414
415    // End here to prevent issues when a Job outlives the HostResolver that
416    // spawned it.
417    net_log_.EndEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_JOB, NULL);
418
419    // We will call HostResolverImpl::CancelRequest(Request*) on each one
420    // in order to notify any observers.
421    for (RequestsList::const_iterator it = requests_.begin();
422         it != requests_.end(); ++it) {
423      HostResolverImpl::Request* req = *it;
424      if (!req->was_cancelled())
425        resolver->CancelRequest(req);
426    }
427  }
428
429  // Called from origin thread.
430  bool was_cancelled() const {
431    return resolver_ == NULL;
432  }
433
434  // Called from origin thread.
435  const Key& key() const {
436    return key_;
437  }
438
439  int id() const {
440    return id_;
441  }
442
443  base::TimeTicks start_time() const {
444    return start_time_;
445  }
446
447  // Called from origin thread.
448  const RequestsList& requests() const {
449    return requests_;
450  }
451
452  // Returns the first request attached to the job.
453  const Request* initial_request() const {
454    DCHECK_EQ(origin_loop_, MessageLoop::current());
455    DCHECK(!requests_.empty());
456    return requests_[0];
457  }
458
459  // Returns true if |req_info| can be fulfilled by this job.
460  bool CanServiceRequest(const RequestInfo& req_info) const {
461    return key_ == resolver_->GetEffectiveKeyForRequest(req_info);
462  }
463
464 private:
465  friend class base::RefCountedThreadSafe<HostResolverImpl::Job>;
466
467  ~Job() {
468    // Free the requests attached to this job.
469    STLDeleteElements(&requests_);
470  }
471
472  // WARNING: This code runs inside a worker pool. The shutdown code cannot
473  // wait for it to finish, so we must be very careful here about using other
474  // objects (like MessageLoops, Singletons, etc). During shutdown these objects
475  // may no longer exist.
476  void DoLookup() {
477    // Running on the worker thread
478    error_ = ResolveAddrInfo(resolver_proc_,
479                             key_.hostname,
480                             key_.address_family,
481                             key_.host_resolver_flags,
482                             &results_,
483                             &os_error_);
484
485    // The origin loop could go away while we are trying to post to it, so we
486    // need to call its PostTask method inside a lock.  See ~HostResolver.
487    {
488      AutoLock locked(origin_loop_lock_);
489      if (origin_loop_) {
490        origin_loop_->PostTask(FROM_HERE,
491                               NewRunnableMethod(this, &Job::OnLookupComplete));
492      }
493    }
494  }
495
496  // Callback for when DoLookup() completes (runs on origin thread).
497  void OnLookupComplete() {
498    // Should be running on origin loop.
499    // TODO(eroman): this is being hit by URLRequestTest.CancelTest*,
500    // because MessageLoop::current() == NULL.
501    //DCHECK_EQ(origin_loop_, MessageLoop::current());
502    DCHECK(error_ || results_.head());
503
504    // Ideally the following code would be part of host_resolver_proc.cc,
505    // however it isn't safe to call NetworkChangeNotifier from worker
506    // threads. So we do it here on the IO thread instead.
507    if (error_ != OK && NetworkChangeNotifier::IsOffline())
508      error_ = ERR_INTERNET_DISCONNECTED;
509
510    RecordPerformanceHistograms();
511
512    if (was_cancelled())
513      return;
514
515    scoped_refptr<NetLog::EventParameters> params;
516    if (error_ != OK) {
517      params = new HostResolveFailedParams(error_, os_error_);
518    } else {
519      params = new AddressListNetLogParam(results_);
520    }
521
522    // End here to prevent issues when a Job outlives the HostResolver that
523    // spawned it.
524    net_log_.EndEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_JOB, params);
525
526    DCHECK(!requests_.empty());
527
528     // Use the port number of the first request.
529    if (error_ == OK)
530      results_.SetPort(requests_[0]->port());
531
532    resolver_->OnJobComplete(this, error_, os_error_, results_);
533  }
534
535  void RecordPerformanceHistograms() const {
536    enum Category {  // Used in HISTOGRAM_ENUMERATION.
537      RESOLVE_SUCCESS,
538      RESOLVE_FAIL,
539      RESOLVE_SPECULATIVE_SUCCESS,
540      RESOLVE_SPECULATIVE_FAIL,
541      RESOLVE_MAX,  // Bounding value.
542    };
543    int category = RESOLVE_MAX;  // Illegal value for later DCHECK only.
544
545    base::TimeDelta duration = base::TimeTicks::Now() - start_time_;
546    if (error_ == OK) {
547      if (had_non_speculative_request_) {
548        category = RESOLVE_SUCCESS;
549        DNS_HISTOGRAM("DNS.ResolveSuccess", duration);
550      } else {
551        category = RESOLVE_SPECULATIVE_SUCCESS;
552        DNS_HISTOGRAM("DNS.ResolveSpeculativeSuccess", duration);
553      }
554    } else {
555      if (had_non_speculative_request_) {
556        category = RESOLVE_FAIL;
557        DNS_HISTOGRAM("DNS.ResolveFail", duration);
558      } else {
559        category = RESOLVE_SPECULATIVE_FAIL;
560        DNS_HISTOGRAM("DNS.ResolveSpeculativeFail", duration);
561      }
562      UMA_HISTOGRAM_CUSTOM_ENUMERATION(kOSErrorsForGetAddrinfoHistogramName,
563                                       std::abs(os_error_),
564                                       GetAllGetAddrinfoOSErrors());
565    }
566    DCHECK_LT(category, static_cast<int>(RESOLVE_MAX));  // Be sure it was set.
567
568    UMA_HISTOGRAM_ENUMERATION("DNS.ResolveCategory", category, RESOLVE_MAX);
569
570    static bool show_speculative_experiment_histograms =
571        base::FieldTrialList::Find("DnsImpact") &&
572        !base::FieldTrialList::Find("DnsImpact")->group_name().empty();
573    if (show_speculative_experiment_histograms) {
574      UMA_HISTOGRAM_ENUMERATION(
575          base::FieldTrial::MakeName("DNS.ResolveCategory", "DnsImpact"),
576          category, RESOLVE_MAX);
577      if (RESOLVE_SUCCESS == category) {
578        DNS_HISTOGRAM(base::FieldTrial::MakeName("DNS.ResolveSuccess",
579                                                 "DnsImpact"), duration);
580      }
581    }
582    static bool show_parallelism_experiment_histograms =
583        base::FieldTrialList::Find("DnsParallelism") &&
584        !base::FieldTrialList::Find("DnsParallelism")->group_name().empty();
585    if (show_parallelism_experiment_histograms) {
586      UMA_HISTOGRAM_ENUMERATION(
587          base::FieldTrial::MakeName("DNS.ResolveCategory", "DnsParallelism"),
588          category, RESOLVE_MAX);
589      if (RESOLVE_SUCCESS == category) {
590        DNS_HISTOGRAM(base::FieldTrial::MakeName("DNS.ResolveSuccess",
591                                                 "DnsParallelism"), duration);
592      }
593    }
594  }
595
596
597
598  // Immutable. Can be read from either thread,
599  const int id_;
600
601  // Set on the origin thread, read on the worker thread.
602  Key key_;
603
604  // Only used on the origin thread (where Resolve was called).
605  HostResolverImpl* resolver_;
606  RequestsList requests_;  // The requests waiting on this job.
607
608  // Used to post ourselves onto the origin thread.
609  Lock origin_loop_lock_;
610  MessageLoop* origin_loop_;
611
612  // Hold an owning reference to the HostResolverProc that we are going to use.
613  // This may not be the current resolver procedure by the time we call
614  // ResolveAddrInfo, but that's OK... we'll use it anyways, and the owning
615  // reference ensures that it remains valid until we are done.
616  scoped_refptr<HostResolverProc> resolver_proc_;
617
618  // Assigned on the worker thread, read on the origin thread.
619  int error_;
620  int os_error_;
621
622  // True if a non-speculative request was ever attached to this job
623  // (regardless of whether or not it was later cancelled.
624  // This boolean is used for histogramming the duration of jobs used to
625  // service non-speculative requests.
626  bool had_non_speculative_request_;
627
628  AddressList results_;
629
630  // The time when the job was started.
631  base::TimeTicks start_time_;
632
633  BoundNetLog net_log_;
634
635  DISALLOW_COPY_AND_ASSIGN(Job);
636};
637
638//-----------------------------------------------------------------------------
639
640// This class represents a request to the worker pool for a "probe for IPv6
641// support" call.
642class HostResolverImpl::IPv6ProbeJob
643    : public base::RefCountedThreadSafe<HostResolverImpl::IPv6ProbeJob> {
644 public:
645  explicit IPv6ProbeJob(HostResolverImpl* resolver)
646      : resolver_(resolver),
647        origin_loop_(MessageLoop::current()) {
648    DCHECK(!was_cancelled());
649  }
650
651  void Start() {
652    if (was_cancelled())
653      return;
654    DCHECK(IsOnOriginThread());
655    const bool kIsSlow = true;
656    base::WorkerPool::PostTask(
657        FROM_HERE, NewRunnableMethod(this, &IPv6ProbeJob::DoProbe), kIsSlow);
658  }
659
660  // Cancels the current job.
661  void Cancel() {
662    if (was_cancelled())
663      return;
664    DCHECK(IsOnOriginThread());
665    resolver_ = NULL;  // Read/write ONLY on origin thread.
666    {
667      AutoLock locked(origin_loop_lock_);
668      // Origin loop may be destroyed before we can use it!
669      origin_loop_ = NULL;  // Write ONLY on origin thread.
670    }
671  }
672
673 private:
674  friend class base::RefCountedThreadSafe<HostResolverImpl::IPv6ProbeJob>;
675
676  ~IPv6ProbeJob() {
677  }
678
679  // Should be run on |orgin_thread_|, but that may not be well defined now.
680  bool was_cancelled() const {
681    if (!resolver_ || !origin_loop_) {
682      DCHECK(!resolver_);
683      DCHECK(!origin_loop_);
684      return true;
685    }
686    return false;
687  }
688
689  // Run on worker thread.
690  void DoProbe() {
691    // Do actual testing on this thread, as it takes 40-100ms.
692    AddressFamily family = IPv6Supported() ? ADDRESS_FAMILY_UNSPECIFIED
693                                           : ADDRESS_FAMILY_IPV4;
694
695    Task* reply = NewRunnableMethod(this, &IPv6ProbeJob::OnProbeComplete,
696                                    family);
697
698    // The origin loop could go away while we are trying to post to it, so we
699    // need to call its PostTask method inside a lock.  See ~HostResolver.
700    {
701      AutoLock locked(origin_loop_lock_);
702      if (origin_loop_) {
703        origin_loop_->PostTask(FROM_HERE, reply);
704        return;
705      }
706    }
707
708    // We didn't post, so delete the reply.
709    delete reply;
710  }
711
712  // Callback for when DoProbe() completes (runs on origin thread).
713  void OnProbeComplete(AddressFamily address_family) {
714    if (was_cancelled())
715      return;
716    DCHECK(IsOnOriginThread());
717    resolver_->IPv6ProbeSetDefaultAddressFamily(address_family);
718  }
719
720  bool IsOnOriginThread() const {
721    return !MessageLoop::current() || origin_loop_ == MessageLoop::current();
722  }
723
724  // Used/set only on origin thread.
725  HostResolverImpl* resolver_;
726
727  // Used to post ourselves onto the origin thread.
728  Lock origin_loop_lock_;
729  MessageLoop* origin_loop_;
730
731  DISALLOW_COPY_AND_ASSIGN(IPv6ProbeJob);
732};
733
734//-----------------------------------------------------------------------------
735
736// We rely on the priority enum values being sequential having starting at 0,
737// and increasing for lower priorities.
738COMPILE_ASSERT(HIGHEST == 0u &&
739               LOWEST > HIGHEST &&
740               IDLE > LOWEST &&
741               NUM_PRIORITIES > IDLE,
742               priority_indexes_incompatible);
743
744// JobPool contains all the information relating to queued requests, including
745// the limits on how many jobs are allowed to be used for this category of
746// requests.
747class HostResolverImpl::JobPool {
748 public:
749  JobPool(size_t max_outstanding_jobs, size_t max_pending_requests)
750      : num_outstanding_jobs_(0u) {
751    SetConstraints(max_outstanding_jobs, max_pending_requests);
752  }
753
754  ~JobPool() {
755    // Free the pending requests.
756    for (size_t i = 0; i < arraysize(pending_requests_); ++i)
757      STLDeleteElements(&pending_requests_[i]);
758  }
759
760  // Sets the constraints for this pool. See SetPoolConstraints() for the
761  // specific meaning of these parameters.
762  void SetConstraints(size_t max_outstanding_jobs,
763                      size_t max_pending_requests) {
764    CHECK_NE(max_outstanding_jobs, 0u);
765    max_outstanding_jobs_ = max_outstanding_jobs;
766    max_pending_requests_ = max_pending_requests;
767  }
768
769  // Returns the number of pending requests enqueued to this pool.
770  // A pending request is one waiting to be attached to a job.
771  size_t GetNumPendingRequests() const {
772    size_t total = 0u;
773    for (size_t i = 0u; i < arraysize(pending_requests_); ++i)
774      total += pending_requests_[i].size();
775    return total;
776  }
777
778  bool HasPendingRequests() const {
779    return GetNumPendingRequests() > 0u;
780  }
781
782  // Enqueues a request to this pool. As a result of enqueing this request,
783  // the queue may have reached its maximum size. In this case, a request is
784  // evicted from the queue, and returned. Otherwise returns NULL. The caller
785  // is responsible for freeing the evicted request.
786  Request* InsertPendingRequest(Request* req) {
787    req->request_net_log().BeginEvent(
788        NetLog::TYPE_HOST_RESOLVER_IMPL_JOB_POOL_QUEUE,
789        NULL);
790
791    PendingRequestsQueue& q = pending_requests_[req->info().priority()];
792    q.push_back(req);
793
794    // If the queue is too big, kick out the lowest priority oldest request.
795    if (GetNumPendingRequests() > max_pending_requests_) {
796      // Iterate over the queues from lowest priority to highest priority.
797      for (int i = static_cast<int>(arraysize(pending_requests_)) - 1;
798           i >= 0; --i) {
799        PendingRequestsQueue& q = pending_requests_[i];
800        if (!q.empty()) {
801          Request* req = q.front();
802          q.pop_front();
803          req->request_net_log().AddEvent(
804              NetLog::TYPE_HOST_RESOLVER_IMPL_JOB_POOL_QUEUE_EVICTED, NULL);
805          req->request_net_log().EndEvent(
806              NetLog::TYPE_HOST_RESOLVER_IMPL_JOB_POOL_QUEUE, NULL);
807          return req;
808        }
809      }
810    }
811
812    return NULL;
813  }
814
815  // Erases |req| from this container. Caller is responsible for freeing
816  // |req| afterwards.
817  void RemovePendingRequest(Request* req) {
818    PendingRequestsQueue& q = pending_requests_[req->info().priority()];
819    PendingRequestsQueue::iterator it = std::find(q.begin(), q.end(), req);
820    DCHECK(it != q.end());
821    q.erase(it);
822    req->request_net_log().EndEvent(
823        NetLog::TYPE_HOST_RESOLVER_IMPL_JOB_POOL_QUEUE, NULL);
824  }
825
826  // Removes and returns the highest priority pending request.
827  Request* RemoveTopPendingRequest() {
828    DCHECK(HasPendingRequests());
829
830    for (size_t i = 0u; i < arraysize(pending_requests_); ++i) {
831      PendingRequestsQueue& q = pending_requests_[i];
832      if (!q.empty()) {
833        Request* req = q.front();
834        q.pop_front();
835        req->request_net_log().EndEvent(
836            NetLog::TYPE_HOST_RESOLVER_IMPL_JOB_POOL_QUEUE, NULL);
837        return req;
838      }
839    }
840
841    NOTREACHED();
842    return NULL;
843  }
844
845  // Keeps track of a job that was just added/removed, and belongs to this pool.
846  void AdjustNumOutstandingJobs(int offset) {
847    DCHECK(offset == 1 || (offset == -1 && num_outstanding_jobs_ > 0u));
848    num_outstanding_jobs_ += offset;
849  }
850
851  void ResetNumOutstandingJobs() {
852    num_outstanding_jobs_ = 0;
853  }
854
855  // Returns true if a new job can be created for this pool.
856  bool CanCreateJob() const {
857    return num_outstanding_jobs_ + 1u <= max_outstanding_jobs_;
858  }
859
860  // Removes any pending requests from the queue which are for the
861  // same (hostname / effective address-family) as |job|, and attaches them to
862  // |job|.
863  void MoveRequestsToJob(Job* job) {
864    for (size_t i = 0u; i < arraysize(pending_requests_); ++i) {
865      PendingRequestsQueue& q = pending_requests_[i];
866      PendingRequestsQueue::iterator req_it = q.begin();
867      while (req_it != q.end()) {
868        Request* req = *req_it;
869        if (job->CanServiceRequest(req->info())) {
870          // Job takes ownership of |req|.
871          job->AddRequest(req);
872          req_it = q.erase(req_it);
873        } else {
874          ++req_it;
875        }
876      }
877    }
878  }
879
880 private:
881  typedef std::deque<Request*> PendingRequestsQueue;
882
883  // Maximum number of concurrent jobs allowed to be started for requests
884  // belonging to this pool.
885  size_t max_outstanding_jobs_;
886
887  // The current number of running jobs that were started for requests
888  // belonging to this pool.
889  size_t num_outstanding_jobs_;
890
891  // The maximum number of requests we allow to be waiting on a job,
892  // for this pool.
893  size_t max_pending_requests_;
894
895  // The requests which are waiting to be started for this pool.
896  PendingRequestsQueue pending_requests_[NUM_PRIORITIES];
897};
898
899//-----------------------------------------------------------------------------
900
901HostResolverImpl::HostResolverImpl(
902    HostResolverProc* resolver_proc,
903    HostCache* cache,
904    size_t max_jobs,
905    NetLog* net_log)
906    : cache_(cache),
907      max_jobs_(max_jobs),
908      next_request_id_(0),
909      next_job_id_(0),
910      resolver_proc_(resolver_proc),
911      default_address_family_(ADDRESS_FAMILY_UNSPECIFIED),
912      shutdown_(false),
913      ipv6_probe_monitoring_(false),
914      additional_resolver_flags_(0),
915      net_log_(net_log) {
916  DCHECK_GT(max_jobs, 0u);
917
918  // It is cumbersome to expose all of the constraints in the constructor,
919  // so we choose some defaults, which users can override later.
920  job_pools_[POOL_NORMAL] = new JobPool(max_jobs, 100u * max_jobs);
921
922#if defined(OS_WIN)
923  EnsureWinsockInit();
924#endif
925#if defined(OS_LINUX)
926  if (HaveOnlyLoopbackAddresses())
927    additional_resolver_flags_ |= HOST_RESOLVER_LOOPBACK_ONLY;
928#endif
929  NetworkChangeNotifier::AddObserver(this);
930}
931
932HostResolverImpl::~HostResolverImpl() {
933  // Cancel the outstanding jobs. Those jobs may contain several attached
934  // requests, which will also be cancelled.
935  DiscardIPv6ProbeJob();
936
937  CancelAllJobs();
938
939  // In case we are being deleted during the processing of a callback.
940  if (cur_completing_job_)
941    cur_completing_job_->Cancel();
942
943  NetworkChangeNotifier::RemoveObserver(this);
944
945  // Delete the job pools.
946  for (size_t i = 0u; i < arraysize(job_pools_); ++i)
947    delete job_pools_[i];
948}
949
950int HostResolverImpl::Resolve(const RequestInfo& info,
951                              AddressList* addresses,
952                              CompletionCallback* callback,
953                              RequestHandle* out_req,
954                              const BoundNetLog& source_net_log) {
955  DCHECK(CalledOnValidThread());
956
957  if (shutdown_)
958    return ERR_UNEXPECTED;
959
960  // Choose a unique ID number for observers to see.
961  int request_id = next_request_id_++;
962
963  // Make a log item for the request.
964  BoundNetLog request_net_log = BoundNetLog::Make(net_log_,
965      NetLog::SOURCE_HOST_RESOLVER_IMPL_REQUEST);
966
967  // Update the net log and notify registered observers.
968  OnStartRequest(source_net_log, request_net_log, request_id, info);
969
970  // Build a key that identifies the request in the cache and in the
971  // outstanding jobs map.
972  Key key = GetEffectiveKeyForRequest(info);
973
974  // Check for IP literal.
975  IPAddressNumber ip_number;
976  if (ParseIPLiteralToNumber(info.hostname(), &ip_number)) {
977    DCHECK_EQ(key.host_resolver_flags &
978                  ~(HOST_RESOLVER_CANONNAME | HOST_RESOLVER_LOOPBACK_ONLY |
979                    HOST_RESOLVER_DEFAULT_FAMILY_SET_DUE_TO_NO_IPV6),
980              0) << " Unhandled flag";
981    bool ipv6_disabled = default_address_family_ == ADDRESS_FAMILY_IPV4 &&
982        !ipv6_probe_monitoring_;
983    int net_error = OK;
984    if (ip_number.size() == 16 && ipv6_disabled) {
985      net_error = ERR_NAME_NOT_RESOLVED;
986    } else {
987      AddressList result(ip_number, info.port(),
988                         (key.host_resolver_flags & HOST_RESOLVER_CANONNAME));
989      *addresses = result;
990    }
991    // Update the net log and notify registered observers.
992    OnFinishRequest(source_net_log, request_net_log, request_id, info,
993                    net_error, 0  /* os_error (unknown since from cache) */);
994    return net_error;
995  }
996
997  // If we have an unexpired cache entry, use it.
998  if (info.allow_cached_response() && cache_.get()) {
999    const HostCache::Entry* cache_entry = cache_->Lookup(
1000        key, base::TimeTicks::Now());
1001    if (cache_entry) {
1002      request_net_log.AddEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_CACHE_HIT, NULL);
1003      int net_error = cache_entry->error;
1004      if (net_error == OK)
1005        addresses->SetFrom(cache_entry->addrlist, info.port());
1006
1007      // Update the net log and notify registered observers.
1008      OnFinishRequest(source_net_log, request_net_log, request_id, info,
1009                      net_error,
1010                      0  /* os_error (unknown since from cache) */);
1011
1012      return net_error;
1013    }
1014  }
1015
1016  // If no callback was specified, do a synchronous resolution.
1017  if (!callback) {
1018    AddressList addrlist;
1019    int os_error = 0;
1020    int error = ResolveAddrInfo(
1021        effective_resolver_proc(), key.hostname, key.address_family,
1022        key.host_resolver_flags, &addrlist, &os_error);
1023    if (error == OK) {
1024      addrlist.SetPort(info.port());
1025      *addresses = addrlist;
1026    }
1027
1028    // Write to cache.
1029    if (cache_.get())
1030      cache_->Set(key, error, addrlist, base::TimeTicks::Now());
1031
1032    // Update the net log and notify registered observers.
1033    OnFinishRequest(source_net_log, request_net_log, request_id, info, error,
1034                    os_error);
1035
1036    return error;
1037  }
1038
1039  // Create a handle for this request, and pass it back to the user if they
1040  // asked for it (out_req != NULL).
1041  Request* req = new Request(source_net_log, request_net_log, request_id, info,
1042                             callback, addresses);
1043  if (out_req)
1044    *out_req = reinterpret_cast<RequestHandle>(req);
1045
1046  // Next we need to attach our request to a "job". This job is responsible for
1047  // calling "getaddrinfo(hostname)" on a worker thread.
1048  scoped_refptr<Job> job;
1049
1050  // If there is already an outstanding job to resolve |key|, use
1051  // it. This prevents starting concurrent resolves for the same hostname.
1052  job = FindOutstandingJob(key);
1053  if (job) {
1054    job->AddRequest(req);
1055  } else {
1056    JobPool* pool = GetPoolForRequest(req);
1057    if (CanCreateJobForPool(*pool)) {
1058      CreateAndStartJob(req);
1059    } else {
1060      return EnqueueRequest(pool, req);
1061    }
1062  }
1063
1064  // Completion happens during OnJobComplete(Job*).
1065  return ERR_IO_PENDING;
1066}
1067
1068// See OnJobComplete(Job*) for why it is important not to clean out
1069// cancelled requests from Job::requests_.
1070void HostResolverImpl::CancelRequest(RequestHandle req_handle) {
1071  DCHECK(CalledOnValidThread());
1072  if (shutdown_) {
1073    // TODO(eroman): temp hack for: http://crbug.com/18373
1074    // Because we destroy outstanding requests during Shutdown(),
1075    // |req_handle| is already cancelled.
1076    LOG(ERROR) << "Called HostResolverImpl::CancelRequest() after Shutdown().";
1077    base::debug::StackTrace().PrintBacktrace();
1078    return;
1079  }
1080  Request* req = reinterpret_cast<Request*>(req_handle);
1081  DCHECK(req);
1082
1083  scoped_ptr<Request> request_deleter;  // Frees at end of function.
1084
1085  if (!req->job()) {
1086    // If the request was not attached to a job yet, it must have been
1087    // enqueued into a pool. Remove it from that pool's queue.
1088    // Otherwise if it was attached to a job, the job is responsible for
1089    // deleting it.
1090    JobPool* pool = GetPoolForRequest(req);
1091    pool->RemovePendingRequest(req);
1092    request_deleter.reset(req);
1093  } else {
1094    req->request_net_log().EndEvent(
1095        NetLog::TYPE_HOST_RESOLVER_IMPL_JOB_ATTACH, NULL);
1096  }
1097
1098  // NULL out the fields of req, to mark it as cancelled.
1099  req->MarkAsCancelled();
1100  OnCancelRequest(req->source_net_log(), req->request_net_log(), req->id(),
1101                  req->info());
1102}
1103
1104void HostResolverImpl::AddObserver(HostResolver::Observer* observer) {
1105  DCHECK(CalledOnValidThread());
1106  observers_.push_back(observer);
1107}
1108
1109void HostResolverImpl::RemoveObserver(HostResolver::Observer* observer) {
1110  DCHECK(CalledOnValidThread());
1111  ObserversList::iterator it =
1112      std::find(observers_.begin(), observers_.end(), observer);
1113
1114  // Observer must exist.
1115  DCHECK(it != observers_.end());
1116
1117  observers_.erase(it);
1118}
1119
1120void HostResolverImpl::SetDefaultAddressFamily(AddressFamily address_family) {
1121  DCHECK(CalledOnValidThread());
1122  ipv6_probe_monitoring_ = false;
1123  DiscardIPv6ProbeJob();
1124  default_address_family_ = address_family;
1125}
1126
1127AddressFamily HostResolverImpl::GetDefaultAddressFamily() const {
1128  return default_address_family_;
1129}
1130
1131void HostResolverImpl::ProbeIPv6Support() {
1132  DCHECK(CalledOnValidThread());
1133  DCHECK(!ipv6_probe_monitoring_);
1134  ipv6_probe_monitoring_ = true;
1135  OnIPAddressChanged();  // Give initial setup call.
1136}
1137
1138HostResolverImpl* HostResolverImpl::GetAsHostResolverImpl() {
1139  return this;
1140}
1141
1142void HostResolverImpl::Shutdown() {
1143  DCHECK(CalledOnValidThread());
1144
1145  // Cancel the outstanding jobs.
1146  CancelAllJobs();
1147  DiscardIPv6ProbeJob();
1148
1149  shutdown_ = true;
1150}
1151
1152void HostResolverImpl::SetPoolConstraints(JobPoolIndex pool_index,
1153                                          size_t max_outstanding_jobs,
1154                                          size_t max_pending_requests) {
1155  DCHECK(CalledOnValidThread());
1156  CHECK_GE(pool_index, 0);
1157  CHECK_LT(pool_index, POOL_COUNT);
1158  CHECK(jobs_.empty()) << "Can only set constraints during setup";
1159  JobPool* pool = job_pools_[pool_index];
1160  pool->SetConstraints(max_outstanding_jobs, max_pending_requests);
1161}
1162
1163void HostResolverImpl::AddOutstandingJob(Job* job) {
1164  scoped_refptr<Job>& found_job = jobs_[job->key()];
1165  DCHECK(!found_job);
1166  found_job = job;
1167
1168  JobPool* pool = GetPoolForRequest(job->initial_request());
1169  pool->AdjustNumOutstandingJobs(1);
1170}
1171
1172HostResolverImpl::Job* HostResolverImpl::FindOutstandingJob(const Key& key) {
1173  JobMap::iterator it = jobs_.find(key);
1174  if (it != jobs_.end())
1175    return it->second;
1176  return NULL;
1177}
1178
1179void HostResolverImpl::RemoveOutstandingJob(Job* job) {
1180  JobMap::iterator it = jobs_.find(job->key());
1181  DCHECK(it != jobs_.end());
1182  DCHECK_EQ(it->second.get(), job);
1183  jobs_.erase(it);
1184
1185  JobPool* pool = GetPoolForRequest(job->initial_request());
1186  pool->AdjustNumOutstandingJobs(-1);
1187}
1188
1189void HostResolverImpl::OnJobComplete(Job* job,
1190                                     int net_error,
1191                                     int os_error,
1192                                     const AddressList& addrlist) {
1193  RemoveOutstandingJob(job);
1194
1195  // Write result to the cache.
1196  if (cache_.get())
1197    cache_->Set(job->key(), net_error, addrlist, base::TimeTicks::Now());
1198
1199  OnJobCompleteInternal(job, net_error, os_error, addrlist);
1200}
1201
1202void HostResolverImpl::AbortJob(Job* job) {
1203  OnJobCompleteInternal(job, ERR_ABORTED, 0 /* no os_error */, AddressList());
1204}
1205
1206void HostResolverImpl::OnJobCompleteInternal(
1207    Job* job,
1208    int net_error,
1209    int os_error,
1210    const AddressList& addrlist) {
1211  // Make a note that we are executing within OnJobComplete() in case the
1212  // HostResolver is deleted by a callback invocation.
1213  DCHECK(!cur_completing_job_);
1214  cur_completing_job_ = job;
1215
1216  // Try to start any queued requests now that a job-slot has freed up.
1217  ProcessQueuedRequests();
1218
1219  // Complete all of the requests that were attached to the job.
1220  for (RequestsList::const_iterator it = job->requests().begin();
1221       it != job->requests().end(); ++it) {
1222    Request* req = *it;
1223    if (!req->was_cancelled()) {
1224      DCHECK_EQ(job, req->job());
1225      req->request_net_log().EndEvent(
1226          NetLog::TYPE_HOST_RESOLVER_IMPL_JOB_ATTACH, NULL);
1227
1228      // Update the net log and notify registered observers.
1229      OnFinishRequest(req->source_net_log(), req->request_net_log(), req->id(),
1230                      req->info(), net_error, os_error);
1231
1232      req->OnComplete(net_error, addrlist);
1233
1234      // Check if the job was cancelled as a result of running the callback.
1235      // (Meaning that |this| was deleted).
1236      if (job->was_cancelled())
1237        return;
1238    }
1239  }
1240
1241  cur_completing_job_ = NULL;
1242}
1243
1244void HostResolverImpl::OnStartRequest(const BoundNetLog& source_net_log,
1245                                      const BoundNetLog& request_net_log,
1246                                      int request_id,
1247                                      const RequestInfo& info) {
1248  source_net_log.BeginEvent(
1249      NetLog::TYPE_HOST_RESOLVER_IMPL,
1250      make_scoped_refptr(new NetLogSourceParameter(
1251          "source_dependency", request_net_log.source())));
1252
1253  request_net_log.BeginEvent(
1254      NetLog::TYPE_HOST_RESOLVER_IMPL_REQUEST,
1255      make_scoped_refptr(new RequestInfoParameters(
1256          info, source_net_log.source())));
1257
1258  // Notify the observers of the start.
1259  if (!observers_.empty()) {
1260    for (ObserversList::iterator it = observers_.begin();
1261         it != observers_.end(); ++it) {
1262      (*it)->OnStartResolution(request_id, info);
1263    }
1264  }
1265}
1266
1267void HostResolverImpl::OnFinishRequest(const BoundNetLog& source_net_log,
1268                                       const BoundNetLog& request_net_log,
1269                                       int request_id,
1270                                       const RequestInfo& info,
1271                                       int net_error,
1272                                       int os_error) {
1273  bool was_resolved = net_error == OK;
1274
1275  // Notify the observers of the completion.
1276  if (!observers_.empty()) {
1277    for (ObserversList::iterator it = observers_.begin();
1278         it != observers_.end(); ++it) {
1279      (*it)->OnFinishResolutionWithStatus(request_id, was_resolved, info);
1280    }
1281  }
1282
1283  // Log some extra parameters on failure for synchronous requests.
1284  scoped_refptr<NetLog::EventParameters> params;
1285  if (!was_resolved) {
1286    params = new HostResolveFailedParams(net_error, os_error);
1287  }
1288
1289  request_net_log.EndEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_REQUEST, params);
1290  source_net_log.EndEvent(NetLog::TYPE_HOST_RESOLVER_IMPL, NULL);
1291}
1292
1293void HostResolverImpl::OnCancelRequest(const BoundNetLog& source_net_log,
1294                                       const BoundNetLog& request_net_log,
1295                                       int request_id,
1296                                       const RequestInfo& info) {
1297  request_net_log.AddEvent(NetLog::TYPE_CANCELLED, NULL);
1298
1299  // Notify the observers of the cancellation.
1300  if (!observers_.empty()) {
1301    for (ObserversList::iterator it = observers_.begin();
1302         it != observers_.end(); ++it) {
1303      (*it)->OnCancelResolution(request_id, info);
1304    }
1305  }
1306
1307  request_net_log.EndEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_REQUEST, NULL);
1308  source_net_log.EndEvent(NetLog::TYPE_HOST_RESOLVER_IMPL, NULL);
1309}
1310
1311void HostResolverImpl::OnIPAddressChanged() {
1312  if (cache_.get())
1313    cache_->clear();
1314  if (ipv6_probe_monitoring_) {
1315    DCHECK(!shutdown_);
1316    if (shutdown_)
1317      return;
1318    DiscardIPv6ProbeJob();
1319    ipv6_probe_job_ = new IPv6ProbeJob(this);
1320    ipv6_probe_job_->Start();
1321  }
1322#if defined(OS_LINUX)
1323  if (HaveOnlyLoopbackAddresses()) {
1324    additional_resolver_flags_ |= HOST_RESOLVER_LOOPBACK_ONLY;
1325  } else {
1326    additional_resolver_flags_ &= ~HOST_RESOLVER_LOOPBACK_ONLY;
1327  }
1328#endif
1329  AbortAllInProgressJobs();
1330  // |this| may be deleted inside AbortAllInProgressJobs().
1331}
1332
1333void HostResolverImpl::DiscardIPv6ProbeJob() {
1334  if (ipv6_probe_job_.get()) {
1335    ipv6_probe_job_->Cancel();
1336    ipv6_probe_job_ = NULL;
1337  }
1338}
1339
1340void HostResolverImpl::IPv6ProbeSetDefaultAddressFamily(
1341    AddressFamily address_family) {
1342  DCHECK(address_family == ADDRESS_FAMILY_UNSPECIFIED ||
1343         address_family == ADDRESS_FAMILY_IPV4);
1344  if (default_address_family_ != address_family) {
1345    VLOG(1) << "IPv6Probe forced AddressFamily setting to "
1346            << ((address_family == ADDRESS_FAMILY_UNSPECIFIED) ?
1347                "ADDRESS_FAMILY_UNSPECIFIED" : "ADDRESS_FAMILY_IPV4");
1348  }
1349  default_address_family_ = address_family;
1350  // Drop reference since the job has called us back.
1351  DiscardIPv6ProbeJob();
1352}
1353
1354// static
1355HostResolverImpl::JobPoolIndex HostResolverImpl::GetJobPoolIndexForRequest(
1356    const Request* req) {
1357  return POOL_NORMAL;
1358}
1359
1360bool HostResolverImpl::CanCreateJobForPool(const JobPool& pool) const {
1361  DCHECK_LE(jobs_.size(), max_jobs_);
1362
1363  // We can't create another job if it would exceed the global total.
1364  if (jobs_.size() + 1 > max_jobs_)
1365    return false;
1366
1367  // Check whether the pool's constraints are met.
1368  return pool.CanCreateJob();
1369}
1370
1371void HostResolverImpl::ProcessQueuedRequests() {
1372  // Find the highest priority request that can be scheduled.
1373  Request* top_req = NULL;
1374  for (size_t i = 0; i < arraysize(job_pools_); ++i) {
1375    JobPool* pool = job_pools_[i];
1376    if (pool->HasPendingRequests() && CanCreateJobForPool(*pool)) {
1377      top_req = pool->RemoveTopPendingRequest();
1378      break;
1379    }
1380  }
1381
1382  if (!top_req)
1383    return;
1384
1385  scoped_refptr<Job> job(CreateAndStartJob(top_req));
1386
1387  // Search for any other pending request which can piggy-back off this job.
1388  for (size_t pool_i = 0; pool_i < POOL_COUNT; ++pool_i) {
1389    JobPool* pool = job_pools_[pool_i];
1390    pool->MoveRequestsToJob(job);
1391  }
1392}
1393
1394HostResolverImpl::Key HostResolverImpl::GetEffectiveKeyForRequest(
1395    const RequestInfo& info) const {
1396  HostResolverFlags effective_flags =
1397      info.host_resolver_flags() | additional_resolver_flags_;
1398  AddressFamily effective_address_family = info.address_family();
1399  if (effective_address_family == ADDRESS_FAMILY_UNSPECIFIED &&
1400      default_address_family_ != ADDRESS_FAMILY_UNSPECIFIED) {
1401    effective_address_family = default_address_family_;
1402    if (ipv6_probe_monitoring_)
1403      effective_flags |= HOST_RESOLVER_DEFAULT_FAMILY_SET_DUE_TO_NO_IPV6;
1404  }
1405  return Key(info.hostname(), effective_address_family, effective_flags);
1406}
1407
1408HostResolverImpl::Job* HostResolverImpl::CreateAndStartJob(Request* req) {
1409  DCHECK(CanCreateJobForPool(*GetPoolForRequest(req)));
1410  Key key = GetEffectiveKeyForRequest(req->info());
1411
1412  req->request_net_log().AddEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_CREATE_JOB,
1413                                  NULL);
1414
1415  scoped_refptr<Job> job(new Job(next_job_id_++, this, key,
1416                                   req->request_net_log(), net_log_));
1417  job->AddRequest(req);
1418  AddOutstandingJob(job);
1419  job->Start();
1420
1421  return job.get();
1422}
1423
1424int HostResolverImpl::EnqueueRequest(JobPool* pool, Request* req) {
1425  scoped_ptr<Request> req_evicted_from_queue(
1426      pool->InsertPendingRequest(req));
1427
1428  // If the queue has become too large, we need to kick something out.
1429  if (req_evicted_from_queue.get()) {
1430    Request* r = req_evicted_from_queue.get();
1431    int error = ERR_HOST_RESOLVER_QUEUE_TOO_LARGE;
1432
1433    OnFinishRequest(r->source_net_log(), r->request_net_log(), r->id(),
1434                    r->info(), error,
1435                    0  /* os_error (not applicable) */);
1436
1437    if (r == req)
1438      return error;
1439
1440    r->OnComplete(error, AddressList());
1441  }
1442
1443  return ERR_IO_PENDING;
1444}
1445
1446void HostResolverImpl::CancelAllJobs() {
1447  JobMap jobs;
1448  jobs.swap(jobs_);
1449  for (JobMap::iterator it = jobs.begin(); it != jobs.end(); ++it)
1450    it->second->Cancel();
1451}
1452
1453void HostResolverImpl::AbortAllInProgressJobs() {
1454  for (size_t i = 0; i < arraysize(job_pools_); ++i)
1455    job_pools_[i]->ResetNumOutstandingJobs();
1456  JobMap jobs;
1457  jobs.swap(jobs_);
1458  for (JobMap::iterator it = jobs.begin(); it != jobs.end(); ++it) {
1459    AbortJob(it->second);
1460    it->second->Cancel();
1461  }
1462}
1463
1464}  // namespace net
1465