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