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