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 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 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 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: 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. 152 class 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("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: 183 JobCreationParameters(const std::string& host, const NetLog::Source& source) 184 : host_(host), source_(source) {} 185 186 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. 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: 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. 267 void MarkAsCancelled() { 268 job_ = NULL; 269 callback_ = NULL; 270 addresses_ = NULL; 271 } 272 273 bool was_cancelled() const { 274 return callback_ == NULL; 275 } 276 277 void set_job(Job* job) { 278 DCHECK(job != NULL); 279 // Identify which job the request is waiting on. 280 job_ = job; 281 } 282 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 291 int port() const { 292 return info_.port(); 293 } 294 295 Job* job() const { 296 return job_; 297 } 298 299 const BoundNetLog& source_net_log() { 300 return source_net_log_; 301 } 302 303 const BoundNetLog& request_net_log() { 304 return request_net_log_; 305 } 306 307 int id() const { 308 return id_; 309 } 310 311 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: 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. 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. 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. 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. 432 bool was_cancelled() const { 433 return resolver_ == NULL; 434 } 435 436 // Called from origin thread. 437 const Key& key() const { 438 return key_; 439 } 440 441 int id() const { 442 return id_; 443 } 444 445 base::TimeTicks start_time() const { 446 return start_time_; 447 } 448 449 // Called from origin thread. 450 const RequestsList& requests() const { 451 return requests_; 452 } 453 454 // Returns the first request attached to the job. 455 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. 462 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 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. 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). 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 537 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: 647 explicit IPv6ProbeJob(HostResolverImpl* resolver) 648 : resolver_(resolver), 649 origin_loop_(MessageLoop::current()) { 650 DCHECK(!was_cancelled()); 651 } 652 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. 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 678 ~IPv6ProbeJob() { 679 } 680 681 // Should be run on |orgin_thread_|, but that may not be well defined now. 682 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. 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). 715 void OnProbeComplete(AddressFamily address_family) { 716 if (was_cancelled()) 717 return; 718 DCHECK(IsOnOriginThread()); 719 resolver_->IPv6ProbeSetDefaultAddressFamily(address_family); 720 } 721 722 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: 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 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. 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. 773 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 780 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. 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. 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. 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. 848 void AdjustNumOutstandingJobs(int offset) { 849 DCHECK(offset == 1 || (offset == -1 && num_outstanding_jobs_ > 0u)); 850 num_outstanding_jobs_ += offset; 851 } 852 853 void ResetNumOutstandingJobs() { 854 num_outstanding_jobs_ = 0; 855 } 856 857 // Returns true if a new job can be created for this pool. 858 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|. 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 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 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 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 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 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_. 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 1134 void HostResolverImpl::AddObserver(HostResolver::Observer* observer) { 1135 DCHECK(CalledOnValidThread()); 1136 observers_.push_back(observer); 1137 } 1138 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 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 1157 AddressFamily HostResolverImpl::GetDefaultAddressFamily() const { 1158 return default_address_family_; 1159 } 1160 1161 HostResolverImpl* HostResolverImpl::GetAsHostResolverImpl() { 1162 return this; 1163 } 1164 1165 void HostResolverImpl::Shutdown() { 1166 DCHECK(CalledOnValidThread()); 1167 1168 // Cancel the outstanding jobs. 1169 CancelAllJobs(); 1170 DiscardIPv6ProbeJob(); 1171 1172 shutdown_ = true; 1173 } 1174 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 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 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 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 1214 void HostResolverImpl::AbortJob(Job* job) { 1215 OnJobCompleteInternal(job, ERR_ABORTED, 0 /* no os_error */, AddressList()); 1216 } 1217 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 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 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 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 1323 void HostResolverImpl::DiscardIPv6ProbeJob() { 1324 if (ipv6_probe_job_.get()) { 1325 ipv6_probe_job_->Cancel(); 1326 ipv6_probe_job_ = NULL; 1327 } 1328 } 1329 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 1344 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 1356 HostResolverImpl::JobPoolIndex HostResolverImpl::GetJobPoolIndexForRequest( 1357 const Request* req) { 1358 return POOL_NORMAL; 1359 } 1360 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 1384 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 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 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 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 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 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