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