| OLD | NEW |
| (Empty) |
| 1 // Copyright (c) 2012 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 <utility> | |
| 15 #include <vector> | |
| 16 | |
| 17 #include "base/basictypes.h" | |
| 18 #include "base/bind.h" | |
| 19 #include "base/bind_helpers.h" | |
| 20 #include "base/callback.h" | |
| 21 #include "base/compiler_specific.h" | |
| 22 #include "base/debug/debugger.h" | |
| 23 #include "base/debug/stack_trace.h" | |
| 24 #include "base/message_loop_proxy.h" | |
| 25 #include "base/metrics/field_trial.h" | |
| 26 #include "base/metrics/histogram.h" | |
| 27 #include "base/stl_util.h" | |
| 28 #include "base/string_util.h" | |
| 29 #include "base/threading/worker_pool.h" | |
| 30 #include "base/time.h" | |
| 31 #include "base/utf_string_conversions.h" | |
| 32 #include "base/values.h" | |
| 33 #include "net/base/address_family.h" | |
| 34 #include "net/base/address_list.h" | |
| 35 #include "net/base/dns_reloader.h" | |
| 36 #include "net/base/host_port_pair.h" | |
| 37 #include "net/base/host_resolver_proc.h" | |
| 38 #include "net/base/net_errors.h" | |
| 39 #include "net/base/net_log.h" | |
| 40 #include "net/base/net_util.h" | |
| 41 #include "net/dns/address_sorter.h" | |
| 42 #include "net/dns/dns_client.h" | |
| 43 #include "net/dns/dns_config_service.h" | |
| 44 #include "net/dns/dns_protocol.h" | |
| 45 #include "net/dns/dns_response.h" | |
| 46 #include "net/dns/dns_transaction.h" | |
| 47 | |
| 48 #if defined(OS_WIN) | |
| 49 #include "net/base/winsock_init.h" | |
| 50 #endif | |
| 51 | |
| 52 namespace net { | |
| 53 | |
| 54 namespace { | |
| 55 | |
| 56 // Limit the size of hostnames that will be resolved to combat issues in | |
| 57 // some platform's resolvers. | |
| 58 const size_t kMaxHostLength = 4096; | |
| 59 | |
| 60 // Default TTL for successful resolutions with ProcTask. | |
| 61 const unsigned kCacheEntryTTLSeconds = 60; | |
| 62 | |
| 63 // Default TTL for unsuccessful resolutions with ProcTask. | |
| 64 const unsigned kNegativeCacheEntryTTLSeconds = 0; | |
| 65 | |
| 66 // Minimum TTL for successful resolutions with DnsTask. | |
| 67 const unsigned kMinimumTTLSeconds = kCacheEntryTTLSeconds; | |
| 68 | |
| 69 // Number of consecutive failures of DnsTask (with successful fallback) before | |
| 70 // the DnsClient is disabled until the next DNS change. | |
| 71 const unsigned kMaximumDnsFailures = 16; | |
| 72 | |
| 73 // We use a separate histogram name for each platform to facilitate the | |
| 74 // display of error codes by their symbolic name (since each platform has | |
| 75 // different mappings). | |
| 76 const char kOSErrorsForGetAddrinfoHistogramName[] = | |
| 77 #if defined(OS_WIN) | |
| 78 "Net.OSErrorsForGetAddrinfo_Win"; | |
| 79 #elif defined(OS_MACOSX) | |
| 80 "Net.OSErrorsForGetAddrinfo_Mac"; | |
| 81 #elif defined(OS_LINUX) | |
| 82 "Net.OSErrorsForGetAddrinfo_Linux"; | |
| 83 #else | |
| 84 "Net.OSErrorsForGetAddrinfo"; | |
| 85 #endif | |
| 86 | |
| 87 // Gets a list of the likely error codes that getaddrinfo() can return | |
| 88 // (non-exhaustive). These are the error codes that we will track via | |
| 89 // a histogram. | |
| 90 std::vector<int> GetAllGetAddrinfoOSErrors() { | |
| 91 int os_errors[] = { | |
| 92 #if defined(OS_POSIX) | |
| 93 #if !defined(OS_FREEBSD) | |
| 94 #if !defined(OS_ANDROID) | |
| 95 // EAI_ADDRFAMILY has been declared obsolete in Android's and | |
| 96 // FreeBSD's netdb.h. | |
| 97 EAI_ADDRFAMILY, | |
| 98 #endif | |
| 99 // EAI_NODATA has been declared obsolete in FreeBSD's netdb.h. | |
| 100 EAI_NODATA, | |
| 101 #endif | |
| 102 EAI_AGAIN, | |
| 103 EAI_BADFLAGS, | |
| 104 EAI_FAIL, | |
| 105 EAI_FAMILY, | |
| 106 EAI_MEMORY, | |
| 107 EAI_NONAME, | |
| 108 EAI_SERVICE, | |
| 109 EAI_SOCKTYPE, | |
| 110 EAI_SYSTEM, | |
| 111 #elif defined(OS_WIN) | |
| 112 // See: http://msdn.microsoft.com/en-us/library/ms738520(VS.85).aspx | |
| 113 WSA_NOT_ENOUGH_MEMORY, | |
| 114 WSAEAFNOSUPPORT, | |
| 115 WSAEINVAL, | |
| 116 WSAESOCKTNOSUPPORT, | |
| 117 WSAHOST_NOT_FOUND, | |
| 118 WSANO_DATA, | |
| 119 WSANO_RECOVERY, | |
| 120 WSANOTINITIALISED, | |
| 121 WSATRY_AGAIN, | |
| 122 WSATYPE_NOT_FOUND, | |
| 123 // The following are not in doc, but might be to appearing in results :-(. | |
| 124 WSA_INVALID_HANDLE, | |
| 125 #endif | |
| 126 }; | |
| 127 | |
| 128 // Ensure all errors are positive, as histogram only tracks positive values. | |
| 129 for (size_t i = 0; i < arraysize(os_errors); ++i) { | |
| 130 os_errors[i] = std::abs(os_errors[i]); | |
| 131 } | |
| 132 | |
| 133 return base::CustomHistogram::ArrayToCustomRanges(os_errors, | |
| 134 arraysize(os_errors)); | |
| 135 } | |
| 136 | |
| 137 enum DnsResolveStatus { | |
| 138 RESOLVE_STATUS_DNS_SUCCESS = 0, | |
| 139 RESOLVE_STATUS_PROC_SUCCESS, | |
| 140 RESOLVE_STATUS_FAIL, | |
| 141 RESOLVE_STATUS_SUSPECT_NETBIOS, | |
| 142 RESOLVE_STATUS_MAX | |
| 143 }; | |
| 144 | |
| 145 void UmaAsyncDnsResolveStatus(DnsResolveStatus result) { | |
| 146 UMA_HISTOGRAM_ENUMERATION("AsyncDNS.ResolveStatus", | |
| 147 result, | |
| 148 RESOLVE_STATUS_MAX); | |
| 149 } | |
| 150 | |
| 151 bool ResemblesNetBIOSName(const std::string& hostname) { | |
| 152 return (hostname.size() < 16) && (hostname.find('.') == std::string::npos); | |
| 153 } | |
| 154 | |
| 155 // True if |hostname| ends with either ".local" or ".local.". | |
| 156 bool ResemblesMulticastDNSName(const std::string& hostname) { | |
| 157 DCHECK(!hostname.empty()); | |
| 158 const char kSuffix[] = ".local."; | |
| 159 const size_t kSuffixLen = sizeof(kSuffix) - 1; | |
| 160 const size_t kSuffixLenTrimmed = kSuffixLen - 1; | |
| 161 if (hostname[hostname.size() - 1] == '.') { | |
| 162 return hostname.size() > kSuffixLen && | |
| 163 !hostname.compare(hostname.size() - kSuffixLen, kSuffixLen, kSuffix); | |
| 164 } | |
| 165 return hostname.size() > kSuffixLenTrimmed && | |
| 166 !hostname.compare(hostname.size() - kSuffixLenTrimmed, kSuffixLenTrimmed, | |
| 167 kSuffix, kSuffixLenTrimmed); | |
| 168 } | |
| 169 | |
| 170 // Provide a common macro to simplify code and readability. We must use a | |
| 171 // macro as the underlying HISTOGRAM macro creates static variables. | |
| 172 #define DNS_HISTOGRAM(name, time) UMA_HISTOGRAM_CUSTOM_TIMES(name, time, \ | |
| 173 base::TimeDelta::FromMilliseconds(1), base::TimeDelta::FromHours(1), 100) | |
| 174 | |
| 175 // A macro to simplify code and readability. | |
| 176 #define DNS_HISTOGRAM_BY_PRIORITY(basename, priority, time) \ | |
| 177 do { \ | |
| 178 switch (priority) { \ | |
| 179 case HIGHEST: DNS_HISTOGRAM(basename "_HIGHEST", time); break; \ | |
| 180 case MEDIUM: DNS_HISTOGRAM(basename "_MEDIUM", time); break; \ | |
| 181 case LOW: DNS_HISTOGRAM(basename "_LOW", time); break; \ | |
| 182 case LOWEST: DNS_HISTOGRAM(basename "_LOWEST", time); break; \ | |
| 183 case IDLE: DNS_HISTOGRAM(basename "_IDLE", time); break; \ | |
| 184 default: NOTREACHED(); break; \ | |
| 185 } \ | |
| 186 DNS_HISTOGRAM(basename, time); \ | |
| 187 } while (0) | |
| 188 | |
| 189 // Record time from Request creation until a valid DNS response. | |
| 190 void RecordTotalTime(bool had_dns_config, | |
| 191 bool speculative, | |
| 192 base::TimeDelta duration) { | |
| 193 if (had_dns_config) { | |
| 194 if (speculative) { | |
| 195 DNS_HISTOGRAM("AsyncDNS.TotalTime_speculative", duration); | |
| 196 } else { | |
| 197 DNS_HISTOGRAM("AsyncDNS.TotalTime", duration); | |
| 198 } | |
| 199 } else { | |
| 200 if (speculative) { | |
| 201 DNS_HISTOGRAM("DNS.TotalTime_speculative", duration); | |
| 202 } else { | |
| 203 DNS_HISTOGRAM("DNS.TotalTime", duration); | |
| 204 } | |
| 205 } | |
| 206 } | |
| 207 | |
| 208 void RecordTTL(base::TimeDelta ttl) { | |
| 209 UMA_HISTOGRAM_CUSTOM_TIMES("AsyncDNS.TTL", ttl, | |
| 210 base::TimeDelta::FromSeconds(1), | |
| 211 base::TimeDelta::FromDays(1), 100); | |
| 212 } | |
| 213 | |
| 214 //----------------------------------------------------------------------------- | |
| 215 | |
| 216 // Wraps call to SystemHostResolverProc as an instance of HostResolverProc. | |
| 217 // TODO(szym): This should probably be declared in host_resolver_proc.h. | |
| 218 class CallSystemHostResolverProc : public HostResolverProc { | |
| 219 public: | |
| 220 CallSystemHostResolverProc() : HostResolverProc(NULL) {} | |
| 221 virtual int Resolve(const std::string& hostname, | |
| 222 AddressFamily address_family, | |
| 223 HostResolverFlags host_resolver_flags, | |
| 224 AddressList* addr_list, | |
| 225 int* os_error) OVERRIDE { | |
| 226 return SystemHostResolverProc(hostname, | |
| 227 address_family, | |
| 228 host_resolver_flags, | |
| 229 addr_list, | |
| 230 os_error); | |
| 231 } | |
| 232 | |
| 233 protected: | |
| 234 virtual ~CallSystemHostResolverProc() {} | |
| 235 }; | |
| 236 | |
| 237 AddressList EnsurePortOnAddressList(const AddressList& list, uint16 port) { | |
| 238 if (list.empty() || list.front().port() == port) | |
| 239 return list; | |
| 240 return AddressList::CopyWithPort(list, port); | |
| 241 } | |
| 242 | |
| 243 // Creates NetLog parameters when the resolve failed. | |
| 244 base::Value* NetLogProcTaskFailedCallback(uint32 attempt_number, | |
| 245 int net_error, | |
| 246 int os_error, | |
| 247 NetLog::LogLevel /* log_level */) { | |
| 248 DictionaryValue* dict = new DictionaryValue(); | |
| 249 if (attempt_number) | |
| 250 dict->SetInteger("attempt_number", attempt_number); | |
| 251 | |
| 252 dict->SetInteger("net_error", net_error); | |
| 253 | |
| 254 if (os_error) { | |
| 255 dict->SetInteger("os_error", os_error); | |
| 256 #if defined(OS_POSIX) | |
| 257 dict->SetString("os_error_string", gai_strerror(os_error)); | |
| 258 #elif defined(OS_WIN) | |
| 259 // Map the error code to a human-readable string. | |
| 260 LPWSTR error_string = NULL; | |
| 261 int size = FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | | |
| 262 FORMAT_MESSAGE_FROM_SYSTEM, | |
| 263 0, // Use the internal message table. | |
| 264 os_error, | |
| 265 0, // Use default language. | |
| 266 (LPWSTR)&error_string, | |
| 267 0, // Buffer size. | |
| 268 0); // Arguments (unused). | |
| 269 dict->SetString("os_error_string", WideToUTF8(error_string)); | |
| 270 LocalFree(error_string); | |
| 271 #endif | |
| 272 } | |
| 273 | |
| 274 return dict; | |
| 275 } | |
| 276 | |
| 277 // Creates NetLog parameters when the DnsTask failed. | |
| 278 base::Value* NetLogDnsTaskFailedCallback(int net_error, | |
| 279 int dns_error, | |
| 280 NetLog::LogLevel /* log_level */) { | |
| 281 DictionaryValue* dict = new DictionaryValue(); | |
| 282 dict->SetInteger("net_error", net_error); | |
| 283 if (dns_error) | |
| 284 dict->SetInteger("dns_error", dns_error); | |
| 285 return dict; | |
| 286 }; | |
| 287 | |
| 288 // Creates NetLog parameters containing the information in a RequestInfo object, | |
| 289 // along with the associated NetLog::Source. | |
| 290 base::Value* NetLogRequestInfoCallback(const NetLog::Source& source, | |
| 291 const HostResolver::RequestInfo* info, | |
| 292 NetLog::LogLevel /* log_level */) { | |
| 293 DictionaryValue* dict = new DictionaryValue(); | |
| 294 source.AddToEventParameters(dict); | |
| 295 | |
| 296 dict->SetString("host", info->host_port_pair().ToString()); | |
| 297 dict->SetInteger("address_family", | |
| 298 static_cast<int>(info->address_family())); | |
| 299 dict->SetBoolean("allow_cached_response", info->allow_cached_response()); | |
| 300 dict->SetBoolean("is_speculative", info->is_speculative()); | |
| 301 dict->SetInteger("priority", info->priority()); | |
| 302 return dict; | |
| 303 } | |
| 304 | |
| 305 // Creates NetLog parameters for the creation of a HostResolverImpl::Job. | |
| 306 base::Value* NetLogJobCreationCallback(const NetLog::Source& source, | |
| 307 const std::string* host, | |
| 308 NetLog::LogLevel /* log_level */) { | |
| 309 DictionaryValue* dict = new DictionaryValue(); | |
| 310 source.AddToEventParameters(dict); | |
| 311 dict->SetString("host", *host); | |
| 312 return dict; | |
| 313 } | |
| 314 | |
| 315 // Creates NetLog parameters for HOST_RESOLVER_IMPL_JOB_ATTACH/DETACH events. | |
| 316 base::Value* NetLogJobAttachCallback(const NetLog::Source& source, | |
| 317 RequestPriority priority, | |
| 318 NetLog::LogLevel /* log_level */) { | |
| 319 DictionaryValue* dict = new DictionaryValue(); | |
| 320 source.AddToEventParameters(dict); | |
| 321 dict->SetInteger("priority", priority); | |
| 322 return dict; | |
| 323 } | |
| 324 | |
| 325 // Creates NetLog parameters for the DNS_CONFIG_CHANGED event. | |
| 326 base::Value* NetLogDnsConfigCallback(const DnsConfig* config, | |
| 327 NetLog::LogLevel /* log_level */) { | |
| 328 return config->ToValue(); | |
| 329 } | |
| 330 | |
| 331 // The logging routines are defined here because some requests are resolved | |
| 332 // without a Request object. | |
| 333 | |
| 334 // Logs when a request has just been started. | |
| 335 void LogStartRequest(const BoundNetLog& source_net_log, | |
| 336 const BoundNetLog& request_net_log, | |
| 337 const HostResolver::RequestInfo& info) { | |
| 338 source_net_log.BeginEvent( | |
| 339 NetLog::TYPE_HOST_RESOLVER_IMPL, | |
| 340 request_net_log.source().ToEventParametersCallback()); | |
| 341 | |
| 342 request_net_log.BeginEvent( | |
| 343 NetLog::TYPE_HOST_RESOLVER_IMPL_REQUEST, | |
| 344 base::Bind(&NetLogRequestInfoCallback, source_net_log.source(), &info)); | |
| 345 } | |
| 346 | |
| 347 // Logs when a request has just completed (before its callback is run). | |
| 348 void LogFinishRequest(const BoundNetLog& source_net_log, | |
| 349 const BoundNetLog& request_net_log, | |
| 350 const HostResolver::RequestInfo& info, | |
| 351 int net_error) { | |
| 352 request_net_log.EndEventWithNetErrorCode( | |
| 353 NetLog::TYPE_HOST_RESOLVER_IMPL_REQUEST, net_error); | |
| 354 source_net_log.EndEvent(NetLog::TYPE_HOST_RESOLVER_IMPL); | |
| 355 } | |
| 356 | |
| 357 // Logs when a request has been cancelled. | |
| 358 void LogCancelRequest(const BoundNetLog& source_net_log, | |
| 359 const BoundNetLog& request_net_log, | |
| 360 const HostResolverImpl::RequestInfo& info) { | |
| 361 request_net_log.AddEvent(NetLog::TYPE_CANCELLED); | |
| 362 request_net_log.EndEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_REQUEST); | |
| 363 source_net_log.EndEvent(NetLog::TYPE_HOST_RESOLVER_IMPL); | |
| 364 } | |
| 365 | |
| 366 //----------------------------------------------------------------------------- | |
| 367 | |
| 368 // Keeps track of the highest priority. | |
| 369 class PriorityTracker { | |
| 370 public: | |
| 371 explicit PriorityTracker(RequestPriority initial_priority) | |
| 372 : highest_priority_(initial_priority), total_count_(0) { | |
| 373 memset(counts_, 0, sizeof(counts_)); | |
| 374 } | |
| 375 | |
| 376 RequestPriority highest_priority() const { | |
| 377 return highest_priority_; | |
| 378 } | |
| 379 | |
| 380 size_t total_count() const { | |
| 381 return total_count_; | |
| 382 } | |
| 383 | |
| 384 void Add(RequestPriority req_priority) { | |
| 385 ++total_count_; | |
| 386 ++counts_[req_priority]; | |
| 387 if (highest_priority_ < req_priority) | |
| 388 highest_priority_ = req_priority; | |
| 389 } | |
| 390 | |
| 391 void Remove(RequestPriority req_priority) { | |
| 392 DCHECK_GT(total_count_, 0u); | |
| 393 DCHECK_GT(counts_[req_priority], 0u); | |
| 394 --total_count_; | |
| 395 --counts_[req_priority]; | |
| 396 size_t i; | |
| 397 for (i = highest_priority_; i > MINIMUM_PRIORITY && !counts_[i]; --i); | |
| 398 highest_priority_ = static_cast<RequestPriority>(i); | |
| 399 | |
| 400 // In absence of requests, default to MINIMUM_PRIORITY. | |
| 401 if (total_count_ == 0) | |
| 402 DCHECK_EQ(MINIMUM_PRIORITY, highest_priority_); | |
| 403 } | |
| 404 | |
| 405 private: | |
| 406 RequestPriority highest_priority_; | |
| 407 size_t total_count_; | |
| 408 size_t counts_[NUM_PRIORITIES]; | |
| 409 }; | |
| 410 | |
| 411 } // namespace | |
| 412 | |
| 413 //----------------------------------------------------------------------------- | |
| 414 | |
| 415 // Holds the data for a request that could not be completed synchronously. | |
| 416 // It is owned by a Job. Canceled Requests are only marked as canceled rather | |
| 417 // than removed from the Job's |requests_| list. | |
| 418 class HostResolverImpl::Request { | |
| 419 public: | |
| 420 Request(const BoundNetLog& source_net_log, | |
| 421 const BoundNetLog& request_net_log, | |
| 422 const RequestInfo& info, | |
| 423 const CompletionCallback& callback, | |
| 424 AddressList* addresses) | |
| 425 : source_net_log_(source_net_log), | |
| 426 request_net_log_(request_net_log), | |
| 427 info_(info), | |
| 428 job_(NULL), | |
| 429 callback_(callback), | |
| 430 addresses_(addresses), | |
| 431 request_time_(base::TimeTicks::Now()) { | |
| 432 } | |
| 433 | |
| 434 // Mark the request as canceled. | |
| 435 void MarkAsCanceled() { | |
| 436 job_ = NULL; | |
| 437 addresses_ = NULL; | |
| 438 callback_.Reset(); | |
| 439 } | |
| 440 | |
| 441 bool was_canceled() const { | |
| 442 return callback_.is_null(); | |
| 443 } | |
| 444 | |
| 445 void set_job(Job* job) { | |
| 446 DCHECK(job); | |
| 447 // Identify which job the request is waiting on. | |
| 448 job_ = job; | |
| 449 } | |
| 450 | |
| 451 // Prepare final AddressList and call completion callback. | |
| 452 void OnComplete(int error, const AddressList& addr_list) { | |
| 453 DCHECK(!was_canceled()); | |
| 454 if (error == OK) | |
| 455 *addresses_ = EnsurePortOnAddressList(addr_list, info_.port()); | |
| 456 CompletionCallback callback = callback_; | |
| 457 MarkAsCanceled(); | |
| 458 callback.Run(error); | |
| 459 } | |
| 460 | |
| 461 Job* job() const { | |
| 462 return job_; | |
| 463 } | |
| 464 | |
| 465 // NetLog for the source, passed in HostResolver::Resolve. | |
| 466 const BoundNetLog& source_net_log() { | |
| 467 return source_net_log_; | |
| 468 } | |
| 469 | |
| 470 // NetLog for this request. | |
| 471 const BoundNetLog& request_net_log() { | |
| 472 return request_net_log_; | |
| 473 } | |
| 474 | |
| 475 const RequestInfo& info() const { | |
| 476 return info_; | |
| 477 } | |
| 478 | |
| 479 base::TimeTicks request_time() const { | |
| 480 return request_time_; | |
| 481 } | |
| 482 | |
| 483 private: | |
| 484 BoundNetLog source_net_log_; | |
| 485 BoundNetLog request_net_log_; | |
| 486 | |
| 487 // The request info that started the request. | |
| 488 RequestInfo info_; | |
| 489 | |
| 490 // The resolve job that this request is dependent on. | |
| 491 Job* job_; | |
| 492 | |
| 493 // The user's callback to invoke when the request completes. | |
| 494 CompletionCallback callback_; | |
| 495 | |
| 496 // The address list to save result into. | |
| 497 AddressList* addresses_; | |
| 498 | |
| 499 const base::TimeTicks request_time_; | |
| 500 | |
| 501 DISALLOW_COPY_AND_ASSIGN(Request); | |
| 502 }; | |
| 503 | |
| 504 //------------------------------------------------------------------------------ | |
| 505 | |
| 506 // Calls HostResolverProc on the WorkerPool. Performs retries if necessary. | |
| 507 // | |
| 508 // Whenever we try to resolve the host, we post a delayed task to check if host | |
| 509 // resolution (OnLookupComplete) is completed or not. If the original attempt | |
| 510 // hasn't completed, then we start another attempt for host resolution. We take | |
| 511 // the results from the first attempt that finishes and ignore the results from | |
| 512 // all other attempts. | |
| 513 // | |
| 514 // TODO(szym): Move to separate source file for testing and mocking. | |
| 515 // | |
| 516 class HostResolverImpl::ProcTask | |
| 517 : public base::RefCountedThreadSafe<HostResolverImpl::ProcTask> { | |
| 518 public: | |
| 519 typedef base::Callback<void(int net_error, | |
| 520 const AddressList& addr_list)> Callback; | |
| 521 | |
| 522 ProcTask(const Key& key, | |
| 523 const ProcTaskParams& params, | |
| 524 const Callback& callback, | |
| 525 const BoundNetLog& job_net_log) | |
| 526 : key_(key), | |
| 527 params_(params), | |
| 528 callback_(callback), | |
| 529 origin_loop_(base::MessageLoopProxy::current()), | |
| 530 attempt_number_(0), | |
| 531 completed_attempt_number_(0), | |
| 532 completed_attempt_error_(ERR_UNEXPECTED), | |
| 533 had_non_speculative_request_(false), | |
| 534 net_log_(job_net_log) { | |
| 535 if (!params_.resolver_proc) | |
| 536 params_.resolver_proc = HostResolverProc::GetDefault(); | |
| 537 // If default is unset, use the system proc. | |
| 538 if (!params_.resolver_proc) | |
| 539 params_.resolver_proc = new CallSystemHostResolverProc(); | |
| 540 } | |
| 541 | |
| 542 void Start() { | |
| 543 DCHECK(origin_loop_->BelongsToCurrentThread()); | |
| 544 net_log_.BeginEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_PROC_TASK); | |
| 545 StartLookupAttempt(); | |
| 546 } | |
| 547 | |
| 548 // Cancels this ProcTask. It will be orphaned. Any outstanding resolve | |
| 549 // attempts running on worker threads will continue running. Only once all the | |
| 550 // attempts complete will the final reference to this ProcTask be released. | |
| 551 void Cancel() { | |
| 552 DCHECK(origin_loop_->BelongsToCurrentThread()); | |
| 553 | |
| 554 if (was_canceled() || was_completed()) | |
| 555 return; | |
| 556 | |
| 557 callback_.Reset(); | |
| 558 net_log_.EndEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_PROC_TASK); | |
| 559 } | |
| 560 | |
| 561 void set_had_non_speculative_request() { | |
| 562 DCHECK(origin_loop_->BelongsToCurrentThread()); | |
| 563 had_non_speculative_request_ = true; | |
| 564 } | |
| 565 | |
| 566 bool was_canceled() const { | |
| 567 DCHECK(origin_loop_->BelongsToCurrentThread()); | |
| 568 return callback_.is_null(); | |
| 569 } | |
| 570 | |
| 571 bool was_completed() const { | |
| 572 DCHECK(origin_loop_->BelongsToCurrentThread()); | |
| 573 return completed_attempt_number_ > 0; | |
| 574 } | |
| 575 | |
| 576 private: | |
| 577 friend class base::RefCountedThreadSafe<ProcTask>; | |
| 578 ~ProcTask() {} | |
| 579 | |
| 580 void StartLookupAttempt() { | |
| 581 DCHECK(origin_loop_->BelongsToCurrentThread()); | |
| 582 base::TimeTicks start_time = base::TimeTicks::Now(); | |
| 583 ++attempt_number_; | |
| 584 // Dispatch the lookup attempt to a worker thread. | |
| 585 if (!base::WorkerPool::PostTask( | |
| 586 FROM_HERE, | |
| 587 base::Bind(&ProcTask::DoLookup, this, start_time, attempt_number_), | |
| 588 true)) { | |
| 589 NOTREACHED(); | |
| 590 | |
| 591 // Since we could be running within Resolve() right now, we can't just | |
| 592 // call OnLookupComplete(). Instead we must wait until Resolve() has | |
| 593 // returned (IO_PENDING). | |
| 594 origin_loop_->PostTask( | |
| 595 FROM_HERE, | |
| 596 base::Bind(&ProcTask::OnLookupComplete, this, AddressList(), | |
| 597 start_time, attempt_number_, ERR_UNEXPECTED, 0)); | |
| 598 return; | |
| 599 } | |
| 600 | |
| 601 net_log_.AddEvent( | |
| 602 NetLog::TYPE_HOST_RESOLVER_IMPL_ATTEMPT_STARTED, | |
| 603 NetLog::IntegerCallback("attempt_number", attempt_number_)); | |
| 604 | |
| 605 // If we don't get the results within a given time, RetryIfNotComplete | |
| 606 // will start a new attempt on a different worker thread if none of our | |
| 607 // outstanding attempts have completed yet. | |
| 608 if (attempt_number_ <= params_.max_retry_attempts) { | |
| 609 origin_loop_->PostDelayedTask( | |
| 610 FROM_HERE, | |
| 611 base::Bind(&ProcTask::RetryIfNotComplete, this), | |
| 612 params_.unresponsive_delay); | |
| 613 } | |
| 614 } | |
| 615 | |
| 616 // WARNING: This code runs inside a worker pool. The shutdown code cannot | |
| 617 // wait for it to finish, so we must be very careful here about using other | |
| 618 // objects (like MessageLoops, Singletons, etc). During shutdown these objects | |
| 619 // may no longer exist. Multiple DoLookups() could be running in parallel, so | |
| 620 // any state inside of |this| must not mutate . | |
| 621 void DoLookup(const base::TimeTicks& start_time, | |
| 622 const uint32 attempt_number) { | |
| 623 AddressList results; | |
| 624 int os_error = 0; | |
| 625 // Running on the worker thread | |
| 626 int error = params_.resolver_proc->Resolve(key_.hostname, | |
| 627 key_.address_family, | |
| 628 key_.host_resolver_flags, | |
| 629 &results, | |
| 630 &os_error); | |
| 631 | |
| 632 origin_loop_->PostTask( | |
| 633 FROM_HERE, | |
| 634 base::Bind(&ProcTask::OnLookupComplete, this, results, start_time, | |
| 635 attempt_number, error, os_error)); | |
| 636 } | |
| 637 | |
| 638 // Makes next attempt if DoLookup() has not finished (runs on origin thread). | |
| 639 void RetryIfNotComplete() { | |
| 640 DCHECK(origin_loop_->BelongsToCurrentThread()); | |
| 641 | |
| 642 if (was_completed() || was_canceled()) | |
| 643 return; | |
| 644 | |
| 645 params_.unresponsive_delay *= params_.retry_factor; | |
| 646 StartLookupAttempt(); | |
| 647 } | |
| 648 | |
| 649 // Callback for when DoLookup() completes (runs on origin thread). | |
| 650 void OnLookupComplete(const AddressList& results, | |
| 651 const base::TimeTicks& start_time, | |
| 652 const uint32 attempt_number, | |
| 653 int error, | |
| 654 const int os_error) { | |
| 655 DCHECK(origin_loop_->BelongsToCurrentThread()); | |
| 656 DCHECK(error || !results.empty()); | |
| 657 | |
| 658 bool was_retry_attempt = attempt_number > 1; | |
| 659 | |
| 660 // Ideally the following code would be part of host_resolver_proc.cc, | |
| 661 // however it isn't safe to call NetworkChangeNotifier from worker threads. | |
| 662 // So we do it here on the IO thread instead. | |
| 663 if (error != OK && NetworkChangeNotifier::IsOffline()) | |
| 664 error = ERR_INTERNET_DISCONNECTED; | |
| 665 | |
| 666 // If this is the first attempt that is finishing later, then record data | |
| 667 // for the first attempt. Won't contaminate with retry attempt's data. | |
| 668 if (!was_retry_attempt) | |
| 669 RecordPerformanceHistograms(start_time, error, os_error); | |
| 670 | |
| 671 RecordAttemptHistograms(start_time, attempt_number, error, os_error); | |
| 672 | |
| 673 if (was_canceled()) | |
| 674 return; | |
| 675 | |
| 676 NetLog::ParametersCallback net_log_callback; | |
| 677 if (error != OK) { | |
| 678 net_log_callback = base::Bind(&NetLogProcTaskFailedCallback, | |
| 679 attempt_number, | |
| 680 error, | |
| 681 os_error); | |
| 682 } else { | |
| 683 net_log_callback = NetLog::IntegerCallback("attempt_number", | |
| 684 attempt_number); | |
| 685 } | |
| 686 net_log_.AddEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_ATTEMPT_FINISHED, | |
| 687 net_log_callback); | |
| 688 | |
| 689 if (was_completed()) | |
| 690 return; | |
| 691 | |
| 692 // Copy the results from the first worker thread that resolves the host. | |
| 693 results_ = results; | |
| 694 completed_attempt_number_ = attempt_number; | |
| 695 completed_attempt_error_ = error; | |
| 696 | |
| 697 if (was_retry_attempt) { | |
| 698 // If retry attempt finishes before 1st attempt, then get stats on how | |
| 699 // much time is saved by having spawned an extra attempt. | |
| 700 retry_attempt_finished_time_ = base::TimeTicks::Now(); | |
| 701 } | |
| 702 | |
| 703 if (error != OK) { | |
| 704 net_log_callback = base::Bind(&NetLogProcTaskFailedCallback, | |
| 705 0, error, os_error); | |
| 706 } else { | |
| 707 net_log_callback = results_.CreateNetLogCallback(); | |
| 708 } | |
| 709 net_log_.EndEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_PROC_TASK, | |
| 710 net_log_callback); | |
| 711 | |
| 712 callback_.Run(error, results_); | |
| 713 } | |
| 714 | |
| 715 void RecordPerformanceHistograms(const base::TimeTicks& start_time, | |
| 716 const int error, | |
| 717 const int os_error) const { | |
| 718 DCHECK(origin_loop_->BelongsToCurrentThread()); | |
| 719 enum Category { // Used in HISTOGRAM_ENUMERATION. | |
| 720 RESOLVE_SUCCESS, | |
| 721 RESOLVE_FAIL, | |
| 722 RESOLVE_SPECULATIVE_SUCCESS, | |
| 723 RESOLVE_SPECULATIVE_FAIL, | |
| 724 RESOLVE_MAX, // Bounding value. | |
| 725 }; | |
| 726 int category = RESOLVE_MAX; // Illegal value for later DCHECK only. | |
| 727 | |
| 728 base::TimeDelta duration = base::TimeTicks::Now() - start_time; | |
| 729 if (error == OK) { | |
| 730 if (had_non_speculative_request_) { | |
| 731 category = RESOLVE_SUCCESS; | |
| 732 DNS_HISTOGRAM("DNS.ResolveSuccess", duration); | |
| 733 } else { | |
| 734 category = RESOLVE_SPECULATIVE_SUCCESS; | |
| 735 DNS_HISTOGRAM("DNS.ResolveSpeculativeSuccess", duration); | |
| 736 } | |
| 737 | |
| 738 // Log DNS lookups based on |address_family|. This will help us determine | |
| 739 // if IPv4 or IPv4/6 lookups are faster or slower. | |
| 740 switch(key_.address_family) { | |
| 741 case ADDRESS_FAMILY_IPV4: | |
| 742 DNS_HISTOGRAM("DNS.ResolveSuccess_FAMILY_IPV4", duration); | |
| 743 break; | |
| 744 case ADDRESS_FAMILY_IPV6: | |
| 745 DNS_HISTOGRAM("DNS.ResolveSuccess_FAMILY_IPV6", duration); | |
| 746 break; | |
| 747 case ADDRESS_FAMILY_UNSPECIFIED: | |
| 748 DNS_HISTOGRAM("DNS.ResolveSuccess_FAMILY_UNSPEC", duration); | |
| 749 break; | |
| 750 } | |
| 751 } else { | |
| 752 if (had_non_speculative_request_) { | |
| 753 category = RESOLVE_FAIL; | |
| 754 DNS_HISTOGRAM("DNS.ResolveFail", duration); | |
| 755 } else { | |
| 756 category = RESOLVE_SPECULATIVE_FAIL; | |
| 757 DNS_HISTOGRAM("DNS.ResolveSpeculativeFail", duration); | |
| 758 } | |
| 759 // Log DNS lookups based on |address_family|. This will help us determine | |
| 760 // if IPv4 or IPv4/6 lookups are faster or slower. | |
| 761 switch(key_.address_family) { | |
| 762 case ADDRESS_FAMILY_IPV4: | |
| 763 DNS_HISTOGRAM("DNS.ResolveFail_FAMILY_IPV4", duration); | |
| 764 break; | |
| 765 case ADDRESS_FAMILY_IPV6: | |
| 766 DNS_HISTOGRAM("DNS.ResolveFail_FAMILY_IPV6", duration); | |
| 767 break; | |
| 768 case ADDRESS_FAMILY_UNSPECIFIED: | |
| 769 DNS_HISTOGRAM("DNS.ResolveFail_FAMILY_UNSPEC", duration); | |
| 770 break; | |
| 771 } | |
| 772 UMA_HISTOGRAM_CUSTOM_ENUMERATION(kOSErrorsForGetAddrinfoHistogramName, | |
| 773 std::abs(os_error), | |
| 774 GetAllGetAddrinfoOSErrors()); | |
| 775 } | |
| 776 DCHECK_LT(category, static_cast<int>(RESOLVE_MAX)); // Be sure it was set. | |
| 777 | |
| 778 UMA_HISTOGRAM_ENUMERATION("DNS.ResolveCategory", category, RESOLVE_MAX); | |
| 779 | |
| 780 static const bool show_parallelism_experiment_histograms = | |
| 781 base::FieldTrialList::TrialExists("DnsParallelism"); | |
| 782 if (show_parallelism_experiment_histograms) { | |
| 783 UMA_HISTOGRAM_ENUMERATION( | |
| 784 base::FieldTrial::MakeName("DNS.ResolveCategory", "DnsParallelism"), | |
| 785 category, RESOLVE_MAX); | |
| 786 if (RESOLVE_SUCCESS == category) { | |
| 787 DNS_HISTOGRAM(base::FieldTrial::MakeName("DNS.ResolveSuccess", | |
| 788 "DnsParallelism"), duration); | |
| 789 } | |
| 790 } | |
| 791 } | |
| 792 | |
| 793 void RecordAttemptHistograms(const base::TimeTicks& start_time, | |
| 794 const uint32 attempt_number, | |
| 795 const int error, | |
| 796 const int os_error) const { | |
| 797 DCHECK(origin_loop_->BelongsToCurrentThread()); | |
| 798 bool first_attempt_to_complete = | |
| 799 completed_attempt_number_ == attempt_number; | |
| 800 bool is_first_attempt = (attempt_number == 1); | |
| 801 | |
| 802 if (first_attempt_to_complete) { | |
| 803 // If this was first attempt to complete, then record the resolution | |
| 804 // status of the attempt. | |
| 805 if (completed_attempt_error_ == OK) { | |
| 806 UMA_HISTOGRAM_ENUMERATION( | |
| 807 "DNS.AttemptFirstSuccess", attempt_number, 100); | |
| 808 } else { | |
| 809 UMA_HISTOGRAM_ENUMERATION( | |
| 810 "DNS.AttemptFirstFailure", attempt_number, 100); | |
| 811 } | |
| 812 } | |
| 813 | |
| 814 if (error == OK) | |
| 815 UMA_HISTOGRAM_ENUMERATION("DNS.AttemptSuccess", attempt_number, 100); | |
| 816 else | |
| 817 UMA_HISTOGRAM_ENUMERATION("DNS.AttemptFailure", attempt_number, 100); | |
| 818 | |
| 819 // If first attempt didn't finish before retry attempt, then calculate stats | |
| 820 // on how much time is saved by having spawned an extra attempt. | |
| 821 if (!first_attempt_to_complete && is_first_attempt && !was_canceled()) { | |
| 822 DNS_HISTOGRAM("DNS.AttemptTimeSavedByRetry", | |
| 823 base::TimeTicks::Now() - retry_attempt_finished_time_); | |
| 824 } | |
| 825 | |
| 826 if (was_canceled() || !first_attempt_to_complete) { | |
| 827 // Count those attempts which completed after the job was already canceled | |
| 828 // OR after the job was already completed by an earlier attempt (so in | |
| 829 // effect). | |
| 830 UMA_HISTOGRAM_ENUMERATION("DNS.AttemptDiscarded", attempt_number, 100); | |
| 831 | |
| 832 // Record if job is canceled. | |
| 833 if (was_canceled()) | |
| 834 UMA_HISTOGRAM_ENUMERATION("DNS.AttemptCancelled", attempt_number, 100); | |
| 835 } | |
| 836 | |
| 837 base::TimeDelta duration = base::TimeTicks::Now() - start_time; | |
| 838 if (error == OK) | |
| 839 DNS_HISTOGRAM("DNS.AttemptSuccessDuration", duration); | |
| 840 else | |
| 841 DNS_HISTOGRAM("DNS.AttemptFailDuration", duration); | |
| 842 } | |
| 843 | |
| 844 // Set on the origin thread, read on the worker thread. | |
| 845 Key key_; | |
| 846 | |
| 847 // Holds an owning reference to the HostResolverProc that we are going to use. | |
| 848 // This may not be the current resolver procedure by the time we call | |
| 849 // ResolveAddrInfo, but that's OK... we'll use it anyways, and the owning | |
| 850 // reference ensures that it remains valid until we are done. | |
| 851 ProcTaskParams params_; | |
| 852 | |
| 853 // The listener to the results of this ProcTask. | |
| 854 Callback callback_; | |
| 855 | |
| 856 // Used to post ourselves onto the origin thread. | |
| 857 scoped_refptr<base::MessageLoopProxy> origin_loop_; | |
| 858 | |
| 859 // Keeps track of the number of attempts we have made so far to resolve the | |
| 860 // host. Whenever we start an attempt to resolve the host, we increase this | |
| 861 // number. | |
| 862 uint32 attempt_number_; | |
| 863 | |
| 864 // The index of the attempt which finished first (or 0 if the job is still in | |
| 865 // progress). | |
| 866 uint32 completed_attempt_number_; | |
| 867 | |
| 868 // The result (a net error code) from the first attempt to complete. | |
| 869 int completed_attempt_error_; | |
| 870 | |
| 871 // The time when retry attempt was finished. | |
| 872 base::TimeTicks retry_attempt_finished_time_; | |
| 873 | |
| 874 // True if a non-speculative request was ever attached to this job | |
| 875 // (regardless of whether or not it was later canceled. | |
| 876 // This boolean is used for histogramming the duration of jobs used to | |
| 877 // service non-speculative requests. | |
| 878 bool had_non_speculative_request_; | |
| 879 | |
| 880 AddressList results_; | |
| 881 | |
| 882 BoundNetLog net_log_; | |
| 883 | |
| 884 DISALLOW_COPY_AND_ASSIGN(ProcTask); | |
| 885 }; | |
| 886 | |
| 887 //----------------------------------------------------------------------------- | |
| 888 | |
| 889 // Wraps a call to TestIPv6Support to be executed on the WorkerPool as it takes | |
| 890 // 40-100ms. | |
| 891 class HostResolverImpl::IPv6ProbeJob { | |
| 892 public: | |
| 893 IPv6ProbeJob(const base::WeakPtr<HostResolverImpl>& resolver, NetLog* net_log) | |
| 894 : resolver_(resolver), | |
| 895 net_log_(BoundNetLog::Make(net_log, NetLog::SOURCE_IPV6_PROBE_JOB)), | |
| 896 result_(false, IPV6_SUPPORT_MAX, OK) { | |
| 897 DCHECK(resolver); | |
| 898 net_log_.BeginEvent(NetLog::TYPE_IPV6_PROBE_RUNNING); | |
| 899 const bool kIsSlow = true; | |
| 900 base::WorkerPool::PostTaskAndReply( | |
| 901 FROM_HERE, | |
| 902 base::Bind(&IPv6ProbeJob::DoProbe, base::Unretained(this)), | |
| 903 base::Bind(&IPv6ProbeJob::OnProbeComplete, base::Owned(this)), | |
| 904 kIsSlow); | |
| 905 } | |
| 906 | |
| 907 virtual ~IPv6ProbeJob() {} | |
| 908 | |
| 909 private: | |
| 910 // Runs on worker thread. | |
| 911 void DoProbe() { | |
| 912 result_ = TestIPv6Support(); | |
| 913 } | |
| 914 | |
| 915 void OnProbeComplete() { | |
| 916 net_log_.EndEvent(NetLog::TYPE_IPV6_PROBE_RUNNING, | |
| 917 base::Bind(&IPv6SupportResult::ToNetLogValue, | |
| 918 base::Unretained(&result_))); | |
| 919 if (!resolver_) | |
| 920 return; | |
| 921 resolver_->IPv6ProbeSetDefaultAddressFamily( | |
| 922 result_.ipv6_supported ? ADDRESS_FAMILY_UNSPECIFIED | |
| 923 : ADDRESS_FAMILY_IPV4); | |
| 924 } | |
| 925 | |
| 926 // Used/set only on origin thread. | |
| 927 base::WeakPtr<HostResolverImpl> resolver_; | |
| 928 | |
| 929 BoundNetLog net_log_; | |
| 930 | |
| 931 IPv6SupportResult result_; | |
| 932 | |
| 933 DISALLOW_COPY_AND_ASSIGN(IPv6ProbeJob); | |
| 934 }; | |
| 935 | |
| 936 // Wraps a call to HaveOnlyLoopbackAddresses to be executed on the WorkerPool as | |
| 937 // it takes 40-100ms and should not block initialization. | |
| 938 class HostResolverImpl::LoopbackProbeJob { | |
| 939 public: | |
| 940 explicit LoopbackProbeJob(const base::WeakPtr<HostResolverImpl>& resolver) | |
| 941 : resolver_(resolver), | |
| 942 result_(false) { | |
| 943 DCHECK(resolver); | |
| 944 const bool kIsSlow = true; | |
| 945 base::WorkerPool::PostTaskAndReply( | |
| 946 FROM_HERE, | |
| 947 base::Bind(&LoopbackProbeJob::DoProbe, base::Unretained(this)), | |
| 948 base::Bind(&LoopbackProbeJob::OnProbeComplete, base::Owned(this)), | |
| 949 kIsSlow); | |
| 950 } | |
| 951 | |
| 952 virtual ~LoopbackProbeJob() {} | |
| 953 | |
| 954 private: | |
| 955 // Runs on worker thread. | |
| 956 void DoProbe() { | |
| 957 result_ = HaveOnlyLoopbackAddresses(); | |
| 958 } | |
| 959 | |
| 960 void OnProbeComplete() { | |
| 961 if (!resolver_) | |
| 962 return; | |
| 963 resolver_->SetHaveOnlyLoopbackAddresses(result_); | |
| 964 } | |
| 965 | |
| 966 // Used/set only on origin thread. | |
| 967 base::WeakPtr<HostResolverImpl> resolver_; | |
| 968 | |
| 969 bool result_; | |
| 970 | |
| 971 DISALLOW_COPY_AND_ASSIGN(LoopbackProbeJob); | |
| 972 }; | |
| 973 | |
| 974 //----------------------------------------------------------------------------- | |
| 975 | |
| 976 // Resolves the hostname using DnsTransaction. | |
| 977 // TODO(szym): This could be moved to separate source file as well. | |
| 978 class HostResolverImpl::DnsTask : public base::SupportsWeakPtr<DnsTask> { | |
| 979 public: | |
| 980 typedef base::Callback<void(int net_error, | |
| 981 const AddressList& addr_list, | |
| 982 base::TimeDelta ttl)> Callback; | |
| 983 | |
| 984 DnsTask(DnsClient* client, | |
| 985 const Key& key, | |
| 986 const Callback& callback, | |
| 987 const BoundNetLog& job_net_log) | |
| 988 : client_(client), | |
| 989 family_(key.address_family), | |
| 990 callback_(callback), | |
| 991 net_log_(job_net_log) { | |
| 992 DCHECK(client); | |
| 993 DCHECK(!callback.is_null()); | |
| 994 | |
| 995 // If unspecified, do IPv4 first, because suffix search will be faster. | |
| 996 uint16 qtype = (family_ == ADDRESS_FAMILY_IPV6) ? | |
| 997 dns_protocol::kTypeAAAA : | |
| 998 dns_protocol::kTypeA; | |
| 999 transaction_ = client_->GetTransactionFactory()->CreateTransaction( | |
| 1000 key.hostname, | |
| 1001 qtype, | |
| 1002 base::Bind(&DnsTask::OnTransactionComplete, base::Unretained(this), | |
| 1003 true /* first_query */, base::TimeTicks::Now()), | |
| 1004 net_log_); | |
| 1005 } | |
| 1006 | |
| 1007 int Start() { | |
| 1008 net_log_.BeginEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_DNS_TASK); | |
| 1009 return transaction_->Start(); | |
| 1010 } | |
| 1011 | |
| 1012 private: | |
| 1013 void OnTransactionComplete(bool first_query, | |
| 1014 const base::TimeTicks& start_time, | |
| 1015 DnsTransaction* transaction, | |
| 1016 int net_error, | |
| 1017 const DnsResponse* response) { | |
| 1018 DCHECK(transaction); | |
| 1019 base::TimeDelta duration = base::TimeTicks::Now() - start_time; | |
| 1020 // Run |callback_| last since the owning Job will then delete this DnsTask. | |
| 1021 if (net_error != OK) { | |
| 1022 DNS_HISTOGRAM("AsyncDNS.TransactionFailure", duration); | |
| 1023 OnFailure(net_error, DnsResponse::DNS_PARSE_OK); | |
| 1024 return; | |
| 1025 } | |
| 1026 | |
| 1027 CHECK(response); | |
| 1028 DNS_HISTOGRAM("AsyncDNS.TransactionSuccess", duration); | |
| 1029 switch (transaction->GetType()) { | |
| 1030 case dns_protocol::kTypeA: | |
| 1031 DNS_HISTOGRAM("AsyncDNS.TransactionSuccess_A", duration); | |
| 1032 break; | |
| 1033 case dns_protocol::kTypeAAAA: | |
| 1034 DNS_HISTOGRAM("AsyncDNS.TransactionSuccess_AAAA", duration); | |
| 1035 break; | |
| 1036 } | |
| 1037 AddressList addr_list; | |
| 1038 base::TimeDelta ttl; | |
| 1039 DnsResponse::Result result = response->ParseToAddressList(&addr_list, &ttl); | |
| 1040 UMA_HISTOGRAM_ENUMERATION("AsyncDNS.ParseToAddressList", | |
| 1041 result, | |
| 1042 DnsResponse::DNS_PARSE_RESULT_MAX); | |
| 1043 if (result != DnsResponse::DNS_PARSE_OK) { | |
| 1044 // Fail even if the other query succeeds. | |
| 1045 OnFailure(ERR_DNS_MALFORMED_RESPONSE, result); | |
| 1046 return; | |
| 1047 } | |
| 1048 | |
| 1049 bool needs_sort = false; | |
| 1050 if (first_query) { | |
| 1051 DCHECK(client_->GetConfig()) << | |
| 1052 "Transaction should have been aborted when config changed!"; | |
| 1053 if (family_ == ADDRESS_FAMILY_IPV6) { | |
| 1054 needs_sort = (addr_list.size() > 1); | |
| 1055 } else if (family_ == ADDRESS_FAMILY_UNSPECIFIED) { | |
| 1056 first_addr_list_ = addr_list; | |
| 1057 first_ttl_ = ttl; | |
| 1058 // Use fully-qualified domain name to avoid search. | |
| 1059 transaction_ = client_->GetTransactionFactory()->CreateTransaction( | |
| 1060 response->GetDottedName() + ".", | |
| 1061 dns_protocol::kTypeAAAA, | |
| 1062 base::Bind(&DnsTask::OnTransactionComplete, base::Unretained(this), | |
| 1063 false /* first_query */, base::TimeTicks::Now()), | |
| 1064 net_log_); | |
| 1065 net_error = transaction_->Start(); | |
| 1066 if (net_error != ERR_IO_PENDING) | |
| 1067 OnFailure(net_error, DnsResponse::DNS_PARSE_OK); | |
| 1068 return; | |
| 1069 } | |
| 1070 } else { | |
| 1071 DCHECK_EQ(ADDRESS_FAMILY_UNSPECIFIED, family_); | |
| 1072 bool has_ipv6_addresses = !addr_list.empty(); | |
| 1073 if (!first_addr_list_.empty()) { | |
| 1074 ttl = std::min(ttl, first_ttl_); | |
| 1075 // Place IPv4 addresses after IPv6. | |
| 1076 addr_list.insert(addr_list.end(), first_addr_list_.begin(), | |
| 1077 first_addr_list_.end()); | |
| 1078 } | |
| 1079 needs_sort = (has_ipv6_addresses && addr_list.size() > 1); | |
| 1080 } | |
| 1081 | |
| 1082 if (addr_list.empty()) { | |
| 1083 // TODO(szym): Don't fallback to ProcTask in this case. | |
| 1084 OnFailure(ERR_NAME_NOT_RESOLVED, DnsResponse::DNS_PARSE_OK); | |
| 1085 return; | |
| 1086 } | |
| 1087 | |
| 1088 if (needs_sort) { | |
| 1089 // Sort could complete synchronously. | |
| 1090 client_->GetAddressSorter()->Sort( | |
| 1091 addr_list, | |
| 1092 base::Bind(&DnsTask::OnSortComplete, | |
| 1093 AsWeakPtr(), | |
| 1094 base::TimeTicks::Now(), | |
| 1095 ttl)); | |
| 1096 } else { | |
| 1097 OnSuccess(addr_list, ttl); | |
| 1098 } | |
| 1099 } | |
| 1100 | |
| 1101 void OnSortComplete(base::TimeTicks start_time, | |
| 1102 base::TimeDelta ttl, | |
| 1103 bool success, | |
| 1104 const AddressList& addr_list) { | |
| 1105 if (!success) { | |
| 1106 DNS_HISTOGRAM("AsyncDNS.SortFailure", | |
| 1107 base::TimeTicks::Now() - start_time); | |
| 1108 OnFailure(ERR_DNS_SORT_ERROR, DnsResponse::DNS_PARSE_OK); | |
| 1109 return; | |
| 1110 } | |
| 1111 | |
| 1112 DNS_HISTOGRAM("AsyncDNS.SortSuccess", | |
| 1113 base::TimeTicks::Now() - start_time); | |
| 1114 | |
| 1115 // AddressSorter prunes unusable destinations. | |
| 1116 if (addr_list.empty()) { | |
| 1117 LOG(WARNING) << "Address list empty after RFC3484 sort"; | |
| 1118 OnFailure(ERR_NAME_NOT_RESOLVED, DnsResponse::DNS_PARSE_OK); | |
| 1119 return; | |
| 1120 } | |
| 1121 | |
| 1122 OnSuccess(addr_list, ttl); | |
| 1123 } | |
| 1124 | |
| 1125 void OnFailure(int net_error, DnsResponse::Result result) { | |
| 1126 DCHECK_NE(OK, net_error); | |
| 1127 net_log_.EndEvent( | |
| 1128 NetLog::TYPE_HOST_RESOLVER_IMPL_DNS_TASK, | |
| 1129 base::Bind(&NetLogDnsTaskFailedCallback, net_error, result)); | |
| 1130 callback_.Run(net_error, AddressList(), base::TimeDelta()); | |
| 1131 } | |
| 1132 | |
| 1133 void OnSuccess(const AddressList& addr_list, base::TimeDelta ttl) { | |
| 1134 net_log_.EndEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_DNS_TASK, | |
| 1135 addr_list.CreateNetLogCallback()); | |
| 1136 callback_.Run(OK, addr_list, ttl); | |
| 1137 } | |
| 1138 | |
| 1139 DnsClient* client_; | |
| 1140 AddressFamily family_; | |
| 1141 // The listener to the results of this DnsTask. | |
| 1142 Callback callback_; | |
| 1143 const BoundNetLog net_log_; | |
| 1144 | |
| 1145 scoped_ptr<DnsTransaction> transaction_; | |
| 1146 | |
| 1147 // Results from the first transaction. Used only if |family_| is unspecified. | |
| 1148 AddressList first_addr_list_; | |
| 1149 base::TimeDelta first_ttl_; | |
| 1150 | |
| 1151 DISALLOW_COPY_AND_ASSIGN(DnsTask); | |
| 1152 }; | |
| 1153 | |
| 1154 //----------------------------------------------------------------------------- | |
| 1155 | |
| 1156 // Aggregates all Requests for the same Key. Dispatched via PriorityDispatch. | |
| 1157 class HostResolverImpl::Job : public PrioritizedDispatcher::Job { | |
| 1158 public: | |
| 1159 // Creates new job for |key| where |request_net_log| is bound to the | |
| 1160 // request that spawned it. | |
| 1161 Job(const base::WeakPtr<HostResolverImpl>& resolver, | |
| 1162 const Key& key, | |
| 1163 RequestPriority priority, | |
| 1164 const BoundNetLog& request_net_log) | |
| 1165 : resolver_(resolver), | |
| 1166 key_(key), | |
| 1167 priority_tracker_(priority), | |
| 1168 had_non_speculative_request_(false), | |
| 1169 had_dns_config_(false), | |
| 1170 dns_task_error_(OK), | |
| 1171 creation_time_(base::TimeTicks::Now()), | |
| 1172 priority_change_time_(creation_time_), | |
| 1173 net_log_(BoundNetLog::Make(request_net_log.net_log(), | |
| 1174 NetLog::SOURCE_HOST_RESOLVER_IMPL_JOB)) { | |
| 1175 request_net_log.AddEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_CREATE_JOB); | |
| 1176 | |
| 1177 net_log_.BeginEvent( | |
| 1178 NetLog::TYPE_HOST_RESOLVER_IMPL_JOB, | |
| 1179 base::Bind(&NetLogJobCreationCallback, | |
| 1180 request_net_log.source(), | |
| 1181 &key_.hostname)); | |
| 1182 } | |
| 1183 | |
| 1184 virtual ~Job() { | |
| 1185 if (is_running()) { | |
| 1186 // |resolver_| was destroyed with this Job still in flight. | |
| 1187 // Clean-up, record in the log, but don't run any callbacks. | |
| 1188 if (is_proc_running()) { | |
| 1189 proc_task_->Cancel(); | |
| 1190 proc_task_ = NULL; | |
| 1191 } | |
| 1192 // Clean up now for nice NetLog. | |
| 1193 dns_task_.reset(NULL); | |
| 1194 net_log_.EndEventWithNetErrorCode(NetLog::TYPE_HOST_RESOLVER_IMPL_JOB, | |
| 1195 ERR_ABORTED); | |
| 1196 } else if (is_queued()) { | |
| 1197 // |resolver_| was destroyed without running this Job. | |
| 1198 // TODO(szym): is there any benefit in having this distinction? | |
| 1199 net_log_.AddEvent(NetLog::TYPE_CANCELLED); | |
| 1200 net_log_.EndEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_JOB); | |
| 1201 } | |
| 1202 // else CompleteRequests logged EndEvent. | |
| 1203 | |
| 1204 // Log any remaining Requests as cancelled. | |
| 1205 for (RequestsList::const_iterator it = requests_.begin(); | |
| 1206 it != requests_.end(); ++it) { | |
| 1207 Request* req = *it; | |
| 1208 if (req->was_canceled()) | |
| 1209 continue; | |
| 1210 DCHECK_EQ(this, req->job()); | |
| 1211 LogCancelRequest(req->source_net_log(), req->request_net_log(), | |
| 1212 req->info()); | |
| 1213 } | |
| 1214 } | |
| 1215 | |
| 1216 // Add this job to the dispatcher. | |
| 1217 void Schedule() { | |
| 1218 handle_ = resolver_->dispatcher_.Add(this, priority()); | |
| 1219 } | |
| 1220 | |
| 1221 void AddRequest(scoped_ptr<Request> req) { | |
| 1222 DCHECK_EQ(key_.hostname, req->info().hostname()); | |
| 1223 | |
| 1224 req->set_job(this); | |
| 1225 priority_tracker_.Add(req->info().priority()); | |
| 1226 | |
| 1227 req->request_net_log().AddEvent( | |
| 1228 NetLog::TYPE_HOST_RESOLVER_IMPL_JOB_ATTACH, | |
| 1229 net_log_.source().ToEventParametersCallback()); | |
| 1230 | |
| 1231 net_log_.AddEvent( | |
| 1232 NetLog::TYPE_HOST_RESOLVER_IMPL_JOB_REQUEST_ATTACH, | |
| 1233 base::Bind(&NetLogJobAttachCallback, | |
| 1234 req->request_net_log().source(), | |
| 1235 priority())); | |
| 1236 | |
| 1237 // TODO(szym): Check if this is still needed. | |
| 1238 if (!req->info().is_speculative()) { | |
| 1239 had_non_speculative_request_ = true; | |
| 1240 if (proc_task_) | |
| 1241 proc_task_->set_had_non_speculative_request(); | |
| 1242 } | |
| 1243 | |
| 1244 requests_.push_back(req.release()); | |
| 1245 | |
| 1246 UpdatePriority(); | |
| 1247 } | |
| 1248 | |
| 1249 // Marks |req| as cancelled. If it was the last active Request, also finishes | |
| 1250 // this Job, marking it as cancelled, and deletes it. | |
| 1251 void CancelRequest(Request* req) { | |
| 1252 DCHECK_EQ(key_.hostname, req->info().hostname()); | |
| 1253 DCHECK(!req->was_canceled()); | |
| 1254 | |
| 1255 // Don't remove it from |requests_| just mark it canceled. | |
| 1256 req->MarkAsCanceled(); | |
| 1257 LogCancelRequest(req->source_net_log(), req->request_net_log(), | |
| 1258 req->info()); | |
| 1259 | |
| 1260 priority_tracker_.Remove(req->info().priority()); | |
| 1261 net_log_.AddEvent( | |
| 1262 NetLog::TYPE_HOST_RESOLVER_IMPL_JOB_REQUEST_DETACH, | |
| 1263 base::Bind(&NetLogJobAttachCallback, | |
| 1264 req->request_net_log().source(), | |
| 1265 priority())); | |
| 1266 | |
| 1267 if (num_active_requests() > 0) { | |
| 1268 UpdatePriority(); | |
| 1269 } else { | |
| 1270 // If we were called from a Request's callback within CompleteRequests, | |
| 1271 // that Request could not have been cancelled, so num_active_requests() | |
| 1272 // could not be 0. Therefore, we are not in CompleteRequests(). | |
| 1273 CompleteRequestsWithError(OK /* cancelled */); | |
| 1274 } | |
| 1275 } | |
| 1276 | |
| 1277 // Called from AbortAllInProgressJobs. Completes all requests and destroys | |
| 1278 // the job. This currently assumes the abort is due to a network change. | |
| 1279 void Abort() { | |
| 1280 DCHECK(is_running()); | |
| 1281 CompleteRequestsWithError(ERR_NETWORK_CHANGED); | |
| 1282 } | |
| 1283 | |
| 1284 // If DnsTask present, abort it and fall back to ProcTask. | |
| 1285 void AbortDnsTask() { | |
| 1286 if (dns_task_) { | |
| 1287 dns_task_.reset(); | |
| 1288 dns_task_error_ = OK; | |
| 1289 StartProcTask(); | |
| 1290 } | |
| 1291 } | |
| 1292 | |
| 1293 // Called by HostResolverImpl when this job is evicted due to queue overflow. | |
| 1294 // Completes all requests and destroys the job. | |
| 1295 void OnEvicted() { | |
| 1296 DCHECK(!is_running()); | |
| 1297 DCHECK(is_queued()); | |
| 1298 handle_.Reset(); | |
| 1299 | |
| 1300 net_log_.AddEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_JOB_EVICTED); | |
| 1301 | |
| 1302 // This signals to CompleteRequests that this job never ran. | |
| 1303 CompleteRequestsWithError(ERR_HOST_RESOLVER_QUEUE_TOO_LARGE); | |
| 1304 } | |
| 1305 | |
| 1306 // Attempts to serve the job from HOSTS. Returns true if succeeded and | |
| 1307 // this Job was destroyed. | |
| 1308 bool ServeFromHosts() { | |
| 1309 DCHECK_GT(num_active_requests(), 0u); | |
| 1310 AddressList addr_list; | |
| 1311 if (resolver_->ServeFromHosts(key(), | |
| 1312 requests_.front()->info(), | |
| 1313 &addr_list)) { | |
| 1314 // This will destroy the Job. | |
| 1315 CompleteRequests( | |
| 1316 HostCache::Entry(OK, MakeAddressListForRequest(addr_list)), | |
| 1317 base::TimeDelta()); | |
| 1318 return true; | |
| 1319 } | |
| 1320 return false; | |
| 1321 } | |
| 1322 | |
| 1323 const Key key() const { | |
| 1324 return key_; | |
| 1325 } | |
| 1326 | |
| 1327 bool is_queued() const { | |
| 1328 return !handle_.is_null(); | |
| 1329 } | |
| 1330 | |
| 1331 bool is_running() const { | |
| 1332 return is_dns_running() || is_proc_running(); | |
| 1333 } | |
| 1334 | |
| 1335 private: | |
| 1336 void UpdatePriority() { | |
| 1337 if (is_queued()) { | |
| 1338 if (priority() != static_cast<RequestPriority>(handle_.priority())) | |
| 1339 priority_change_time_ = base::TimeTicks::Now(); | |
| 1340 handle_ = resolver_->dispatcher_.ChangePriority(handle_, priority()); | |
| 1341 } | |
| 1342 } | |
| 1343 | |
| 1344 AddressList MakeAddressListForRequest(const AddressList& list) const { | |
| 1345 if (requests_.empty()) | |
| 1346 return list; | |
| 1347 return AddressList::CopyWithPort(list, requests_.front()->info().port()); | |
| 1348 } | |
| 1349 | |
| 1350 // PriorityDispatch::Job: | |
| 1351 virtual void Start() OVERRIDE { | |
| 1352 DCHECK(!is_running()); | |
| 1353 handle_.Reset(); | |
| 1354 | |
| 1355 net_log_.AddEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_JOB_STARTED); | |
| 1356 | |
| 1357 had_dns_config_ = resolver_->HaveDnsConfig(); | |
| 1358 | |
| 1359 base::TimeTicks now = base::TimeTicks::Now(); | |
| 1360 base::TimeDelta queue_time = now - creation_time_; | |
| 1361 base::TimeDelta queue_time_after_change = now - priority_change_time_; | |
| 1362 | |
| 1363 if (had_dns_config_) { | |
| 1364 DNS_HISTOGRAM_BY_PRIORITY("AsyncDNS.JobQueueTime", priority(), | |
| 1365 queue_time); | |
| 1366 DNS_HISTOGRAM_BY_PRIORITY("AsyncDNS.JobQueueTimeAfterChange", priority(), | |
| 1367 queue_time_after_change); | |
| 1368 } else { | |
| 1369 DNS_HISTOGRAM_BY_PRIORITY("DNS.JobQueueTime", priority(), queue_time); | |
| 1370 DNS_HISTOGRAM_BY_PRIORITY("DNS.JobQueueTimeAfterChange", priority(), | |
| 1371 queue_time_after_change); | |
| 1372 } | |
| 1373 | |
| 1374 // Caution: Job::Start must not complete synchronously. | |
| 1375 if (had_dns_config_ && !ResemblesMulticastDNSName(key_.hostname)) { | |
| 1376 StartDnsTask(); | |
| 1377 } else { | |
| 1378 StartProcTask(); | |
| 1379 } | |
| 1380 } | |
| 1381 | |
| 1382 // TODO(szym): Since DnsTransaction does not consume threads, we can increase | |
| 1383 // the limits on |dispatcher_|. But in order to keep the number of WorkerPool | |
| 1384 // threads low, we will need to use an "inner" PrioritizedDispatcher with | |
| 1385 // tighter limits. | |
| 1386 void StartProcTask() { | |
| 1387 DCHECK(!is_dns_running()); | |
| 1388 proc_task_ = new ProcTask( | |
| 1389 key_, | |
| 1390 resolver_->proc_params_, | |
| 1391 base::Bind(&Job::OnProcTaskComplete, base::Unretained(this), | |
| 1392 base::TimeTicks::Now()), | |
| 1393 net_log_); | |
| 1394 | |
| 1395 if (had_non_speculative_request_) | |
| 1396 proc_task_->set_had_non_speculative_request(); | |
| 1397 // Start() could be called from within Resolve(), hence it must NOT directly | |
| 1398 // call OnProcTaskComplete, for example, on synchronous failure. | |
| 1399 proc_task_->Start(); | |
| 1400 } | |
| 1401 | |
| 1402 // Called by ProcTask when it completes. | |
| 1403 void OnProcTaskComplete(base::TimeTicks start_time, | |
| 1404 int net_error, | |
| 1405 const AddressList& addr_list) { | |
| 1406 DCHECK(is_proc_running()); | |
| 1407 | |
| 1408 if (!resolver_->resolved_known_ipv6_hostname_ && | |
| 1409 net_error == OK && | |
| 1410 key_.address_family == ADDRESS_FAMILY_UNSPECIFIED) { | |
| 1411 if (key_.hostname == "www.google.com") { | |
| 1412 resolver_->resolved_known_ipv6_hostname_ = true; | |
| 1413 bool got_ipv6_address = false; | |
| 1414 for (size_t i = 0; i < addr_list.size(); ++i) { | |
| 1415 if (addr_list[i].GetFamily() == ADDRESS_FAMILY_IPV6) | |
| 1416 got_ipv6_address = true; | |
| 1417 } | |
| 1418 UMA_HISTOGRAM_BOOLEAN("Net.UnspecResolvedIPv6", got_ipv6_address); | |
| 1419 } | |
| 1420 } | |
| 1421 | |
| 1422 if (dns_task_error_ != OK) { | |
| 1423 base::TimeDelta duration = base::TimeTicks::Now() - start_time; | |
| 1424 if (net_error == OK) { | |
| 1425 DNS_HISTOGRAM("AsyncDNS.FallbackSuccess", duration); | |
| 1426 if ((dns_task_error_ == ERR_NAME_NOT_RESOLVED) && | |
| 1427 ResemblesNetBIOSName(key_.hostname)) { | |
| 1428 UmaAsyncDnsResolveStatus(RESOLVE_STATUS_SUSPECT_NETBIOS); | |
| 1429 } else { | |
| 1430 UmaAsyncDnsResolveStatus(RESOLVE_STATUS_PROC_SUCCESS); | |
| 1431 } | |
| 1432 UMA_HISTOGRAM_CUSTOM_ENUMERATION("AsyncDNS.ResolveError", | |
| 1433 std::abs(dns_task_error_), | |
| 1434 GetAllErrorCodesForUma()); | |
| 1435 resolver_->OnDnsTaskResolve(dns_task_error_); | |
| 1436 } else { | |
| 1437 DNS_HISTOGRAM("AsyncDNS.FallbackFail", duration); | |
| 1438 UmaAsyncDnsResolveStatus(RESOLVE_STATUS_FAIL); | |
| 1439 } | |
| 1440 } | |
| 1441 | |
| 1442 base::TimeDelta ttl = | |
| 1443 base::TimeDelta::FromSeconds(kNegativeCacheEntryTTLSeconds); | |
| 1444 if (net_error == OK) | |
| 1445 ttl = base::TimeDelta::FromSeconds(kCacheEntryTTLSeconds); | |
| 1446 | |
| 1447 // Don't store the |ttl| in cache since it's not obtained from the server. | |
| 1448 CompleteRequests( | |
| 1449 HostCache::Entry(net_error, MakeAddressListForRequest(addr_list)), | |
| 1450 ttl); | |
| 1451 } | |
| 1452 | |
| 1453 void StartDnsTask() { | |
| 1454 DCHECK(resolver_->HaveDnsConfig()); | |
| 1455 dns_task_.reset(new DnsTask( | |
| 1456 resolver_->dns_client_.get(), | |
| 1457 key_, | |
| 1458 base::Bind(&Job::OnDnsTaskComplete, base::Unretained(this), | |
| 1459 base::TimeTicks::Now()), | |
| 1460 net_log_)); | |
| 1461 | |
| 1462 int rv = dns_task_->Start(); | |
| 1463 if (rv != ERR_IO_PENDING) { | |
| 1464 DCHECK_NE(OK, rv); | |
| 1465 dns_task_error_ = rv; | |
| 1466 dns_task_.reset(); | |
| 1467 StartProcTask(); | |
| 1468 } | |
| 1469 } | |
| 1470 | |
| 1471 // Called by DnsTask when it completes. | |
| 1472 void OnDnsTaskComplete(base::TimeTicks start_time, | |
| 1473 int net_error, | |
| 1474 const AddressList& addr_list, | |
| 1475 base::TimeDelta ttl) { | |
| 1476 DCHECK(is_dns_running()); | |
| 1477 | |
| 1478 base::TimeDelta duration = base::TimeTicks::Now() - start_time; | |
| 1479 if (net_error != OK) { | |
| 1480 DNS_HISTOGRAM("AsyncDNS.ResolveFail", duration); | |
| 1481 | |
| 1482 dns_task_error_ = net_error; | |
| 1483 dns_task_.reset(); | |
| 1484 | |
| 1485 // TODO(szym): Run ServeFromHosts now if nsswitch.conf says so. | |
| 1486 // http://crbug.com/117655 | |
| 1487 | |
| 1488 // TODO(szym): Some net errors indicate lack of connectivity. Starting | |
| 1489 // ProcTask in that case is a waste of time. | |
| 1490 StartProcTask(); | |
| 1491 return; | |
| 1492 } | |
| 1493 DNS_HISTOGRAM("AsyncDNS.ResolveSuccess", duration); | |
| 1494 // Log DNS lookups based on |address_family|. | |
| 1495 switch(key_.address_family) { | |
| 1496 case ADDRESS_FAMILY_IPV4: | |
| 1497 DNS_HISTOGRAM("AsyncDNS.ResolveSuccess_FAMILY_IPV4", duration); | |
| 1498 break; | |
| 1499 case ADDRESS_FAMILY_IPV6: | |
| 1500 DNS_HISTOGRAM("AsyncDNS.ResolveSuccess_FAMILY_IPV6", duration); | |
| 1501 break; | |
| 1502 case ADDRESS_FAMILY_UNSPECIFIED: | |
| 1503 DNS_HISTOGRAM("AsyncDNS.ResolveSuccess_FAMILY_UNSPEC", duration); | |
| 1504 break; | |
| 1505 } | |
| 1506 | |
| 1507 UmaAsyncDnsResolveStatus(RESOLVE_STATUS_DNS_SUCCESS); | |
| 1508 RecordTTL(ttl); | |
| 1509 | |
| 1510 resolver_->OnDnsTaskResolve(OK); | |
| 1511 | |
| 1512 base::TimeDelta bounded_ttl = | |
| 1513 std::max(ttl, base::TimeDelta::FromSeconds(kMinimumTTLSeconds)); | |
| 1514 | |
| 1515 CompleteRequests( | |
| 1516 HostCache::Entry(net_error, MakeAddressListForRequest(addr_list), ttl), | |
| 1517 bounded_ttl); | |
| 1518 } | |
| 1519 | |
| 1520 // Performs Job's last rites. Completes all Requests. Deletes this. | |
| 1521 void CompleteRequests(const HostCache::Entry& entry, | |
| 1522 base::TimeDelta ttl) { | |
| 1523 CHECK(resolver_); | |
| 1524 | |
| 1525 // This job must be removed from resolver's |jobs_| now to make room for a | |
| 1526 // new job with the same key in case one of the OnComplete callbacks decides | |
| 1527 // to spawn one. Consequently, the job deletes itself when CompleteRequests | |
| 1528 // is done. | |
| 1529 scoped_ptr<Job> self_deleter(this); | |
| 1530 | |
| 1531 resolver_->RemoveJob(this); | |
| 1532 | |
| 1533 if (is_running()) { | |
| 1534 DCHECK(!is_queued()); | |
| 1535 if (is_proc_running()) { | |
| 1536 proc_task_->Cancel(); | |
| 1537 proc_task_ = NULL; | |
| 1538 } | |
| 1539 dns_task_.reset(); | |
| 1540 | |
| 1541 // Signal dispatcher that a slot has opened. | |
| 1542 resolver_->dispatcher_.OnJobFinished(); | |
| 1543 } else if (is_queued()) { | |
| 1544 resolver_->dispatcher_.Cancel(handle_); | |
| 1545 handle_.Reset(); | |
| 1546 } | |
| 1547 | |
| 1548 if (num_active_requests() == 0) { | |
| 1549 net_log_.AddEvent(NetLog::TYPE_CANCELLED); | |
| 1550 net_log_.EndEventWithNetErrorCode(NetLog::TYPE_HOST_RESOLVER_IMPL_JOB, | |
| 1551 OK); | |
| 1552 return; | |
| 1553 } | |
| 1554 | |
| 1555 net_log_.EndEventWithNetErrorCode(NetLog::TYPE_HOST_RESOLVER_IMPL_JOB, | |
| 1556 entry.error); | |
| 1557 | |
| 1558 DCHECK(!requests_.empty()); | |
| 1559 | |
| 1560 if (entry.error == OK) { | |
| 1561 // Record this histogram here, when we know the system has a valid DNS | |
| 1562 // configuration. | |
| 1563 UMA_HISTOGRAM_BOOLEAN("AsyncDNS.HaveDnsConfig", | |
| 1564 resolver_->received_dns_config_); | |
| 1565 } | |
| 1566 | |
| 1567 bool did_complete = (entry.error != ERR_NETWORK_CHANGED) && | |
| 1568 (entry.error != ERR_HOST_RESOLVER_QUEUE_TOO_LARGE); | |
| 1569 if (did_complete) | |
| 1570 resolver_->CacheResult(key_, entry, ttl); | |
| 1571 | |
| 1572 // Complete all of the requests that were attached to the job. | |
| 1573 for (RequestsList::const_iterator it = requests_.begin(); | |
| 1574 it != requests_.end(); ++it) { | |
| 1575 Request* req = *it; | |
| 1576 | |
| 1577 if (req->was_canceled()) | |
| 1578 continue; | |
| 1579 | |
| 1580 DCHECK_EQ(this, req->job()); | |
| 1581 // Update the net log and notify registered observers. | |
| 1582 LogFinishRequest(req->source_net_log(), req->request_net_log(), | |
| 1583 req->info(), entry.error); | |
| 1584 if (did_complete) { | |
| 1585 // Record effective total time from creation to completion. | |
| 1586 RecordTotalTime(had_dns_config_, req->info().is_speculative(), | |
| 1587 base::TimeTicks::Now() - req->request_time()); | |
| 1588 } | |
| 1589 req->OnComplete(entry.error, entry.addrlist); | |
| 1590 | |
| 1591 // Check if the resolver was destroyed as a result of running the | |
| 1592 // callback. If it was, we could continue, but we choose to bail. | |
| 1593 if (!resolver_) | |
| 1594 return; | |
| 1595 } | |
| 1596 } | |
| 1597 | |
| 1598 // Convenience wrapper for CompleteRequests in case of failure. | |
| 1599 void CompleteRequestsWithError(int net_error) { | |
| 1600 CompleteRequests(HostCache::Entry(net_error, AddressList()), | |
| 1601 base::TimeDelta()); | |
| 1602 } | |
| 1603 | |
| 1604 RequestPriority priority() const { | |
| 1605 return priority_tracker_.highest_priority(); | |
| 1606 } | |
| 1607 | |
| 1608 // Number of non-canceled requests in |requests_|. | |
| 1609 size_t num_active_requests() const { | |
| 1610 return priority_tracker_.total_count(); | |
| 1611 } | |
| 1612 | |
| 1613 bool is_dns_running() const { | |
| 1614 return dns_task_.get() != NULL; | |
| 1615 } | |
| 1616 | |
| 1617 bool is_proc_running() const { | |
| 1618 return proc_task_.get() != NULL; | |
| 1619 } | |
| 1620 | |
| 1621 base::WeakPtr<HostResolverImpl> resolver_; | |
| 1622 | |
| 1623 Key key_; | |
| 1624 | |
| 1625 // Tracks the highest priority across |requests_|. | |
| 1626 PriorityTracker priority_tracker_; | |
| 1627 | |
| 1628 bool had_non_speculative_request_; | |
| 1629 | |
| 1630 // Distinguishes measurements taken while DnsClient was fully configured. | |
| 1631 bool had_dns_config_; | |
| 1632 | |
| 1633 // Result of DnsTask. | |
| 1634 int dns_task_error_; | |
| 1635 | |
| 1636 const base::TimeTicks creation_time_; | |
| 1637 base::TimeTicks priority_change_time_; | |
| 1638 | |
| 1639 BoundNetLog net_log_; | |
| 1640 | |
| 1641 // Resolves the host using a HostResolverProc. | |
| 1642 scoped_refptr<ProcTask> proc_task_; | |
| 1643 | |
| 1644 // Resolves the host using a DnsTransaction. | |
| 1645 scoped_ptr<DnsTask> dns_task_; | |
| 1646 | |
| 1647 // All Requests waiting for the result of this Job. Some can be canceled. | |
| 1648 RequestsList requests_; | |
| 1649 | |
| 1650 // A handle used in |HostResolverImpl::dispatcher_|. | |
| 1651 PrioritizedDispatcher::Handle handle_; | |
| 1652 }; | |
| 1653 | |
| 1654 //----------------------------------------------------------------------------- | |
| 1655 | |
| 1656 HostResolverImpl::ProcTaskParams::ProcTaskParams( | |
| 1657 HostResolverProc* resolver_proc, | |
| 1658 size_t max_retry_attempts) | |
| 1659 : resolver_proc(resolver_proc), | |
| 1660 max_retry_attempts(max_retry_attempts), | |
| 1661 unresponsive_delay(base::TimeDelta::FromMilliseconds(6000)), | |
| 1662 retry_factor(2) { | |
| 1663 } | |
| 1664 | |
| 1665 HostResolverImpl::ProcTaskParams::~ProcTaskParams() {} | |
| 1666 | |
| 1667 HostResolverImpl::HostResolverImpl( | |
| 1668 scoped_ptr<HostCache> cache, | |
| 1669 const PrioritizedDispatcher::Limits& job_limits, | |
| 1670 const ProcTaskParams& proc_params, | |
| 1671 NetLog* net_log) | |
| 1672 : cache_(cache.Pass()), | |
| 1673 dispatcher_(job_limits), | |
| 1674 max_queued_jobs_(job_limits.total_jobs * 100u), | |
| 1675 proc_params_(proc_params), | |
| 1676 net_log_(net_log), | |
| 1677 default_address_family_(ADDRESS_FAMILY_UNSPECIFIED), | |
| 1678 weak_ptr_factory_(this), | |
| 1679 probe_weak_ptr_factory_(this), | |
| 1680 received_dns_config_(false), | |
| 1681 num_dns_failures_(0), | |
| 1682 ipv6_probe_monitoring_(false), | |
| 1683 resolved_known_ipv6_hostname_(false), | |
| 1684 additional_resolver_flags_(0) { | |
| 1685 | |
| 1686 DCHECK_GE(dispatcher_.num_priorities(), static_cast<size_t>(NUM_PRIORITIES)); | |
| 1687 | |
| 1688 // Maximum of 4 retry attempts for host resolution. | |
| 1689 static const size_t kDefaultMaxRetryAttempts = 4u; | |
| 1690 | |
| 1691 if (proc_params_.max_retry_attempts == HostResolver::kDefaultRetryAttempts) | |
| 1692 proc_params_.max_retry_attempts = kDefaultMaxRetryAttempts; | |
| 1693 | |
| 1694 #if defined(OS_WIN) | |
| 1695 EnsureWinsockInit(); | |
| 1696 #endif | |
| 1697 #if defined(OS_POSIX) && !defined(OS_MACOSX) | |
| 1698 new LoopbackProbeJob(weak_ptr_factory_.GetWeakPtr()); | |
| 1699 #endif | |
| 1700 NetworkChangeNotifier::AddIPAddressObserver(this); | |
| 1701 NetworkChangeNotifier::AddDNSObserver(this); | |
| 1702 #if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_OPENBSD) && \ | |
| 1703 !defined(OS_ANDROID) | |
| 1704 EnsureDnsReloaderInit(); | |
| 1705 #endif | |
| 1706 | |
| 1707 // TODO(szym): Remove when received_dns_config_ is removed, once | |
| 1708 // http://crbug.com/137914 is resolved. | |
| 1709 { | |
| 1710 DnsConfig dns_config; | |
| 1711 NetworkChangeNotifier::GetDnsConfig(&dns_config); | |
| 1712 received_dns_config_ = dns_config.IsValid(); | |
| 1713 } | |
| 1714 } | |
| 1715 | |
| 1716 HostResolverImpl::~HostResolverImpl() { | |
| 1717 // This will also cancel all outstanding requests. | |
| 1718 STLDeleteValues(&jobs_); | |
| 1719 | |
| 1720 NetworkChangeNotifier::RemoveIPAddressObserver(this); | |
| 1721 NetworkChangeNotifier::RemoveDNSObserver(this); | |
| 1722 } | |
| 1723 | |
| 1724 void HostResolverImpl::SetMaxQueuedJobs(size_t value) { | |
| 1725 DCHECK_EQ(0u, dispatcher_.num_queued_jobs()); | |
| 1726 DCHECK_GT(value, 0u); | |
| 1727 max_queued_jobs_ = value; | |
| 1728 } | |
| 1729 | |
| 1730 int HostResolverImpl::Resolve(const RequestInfo& info, | |
| 1731 AddressList* addresses, | |
| 1732 const CompletionCallback& callback, | |
| 1733 RequestHandle* out_req, | |
| 1734 const BoundNetLog& source_net_log) { | |
| 1735 DCHECK(addresses); | |
| 1736 DCHECK(CalledOnValidThread()); | |
| 1737 DCHECK_EQ(false, callback.is_null()); | |
| 1738 | |
| 1739 // Make a log item for the request. | |
| 1740 BoundNetLog request_net_log = BoundNetLog::Make(net_log_, | |
| 1741 NetLog::SOURCE_HOST_RESOLVER_IMPL_REQUEST); | |
| 1742 | |
| 1743 LogStartRequest(source_net_log, request_net_log, info); | |
| 1744 | |
| 1745 // Build a key that identifies the request in the cache and in the | |
| 1746 // outstanding jobs map. | |
| 1747 Key key = GetEffectiveKeyForRequest(info); | |
| 1748 | |
| 1749 int rv = ResolveHelper(key, info, addresses, request_net_log); | |
| 1750 if (rv != ERR_DNS_CACHE_MISS) { | |
| 1751 LogFinishRequest(source_net_log, request_net_log, info, rv); | |
| 1752 RecordTotalTime(HaveDnsConfig(), info.is_speculative(), base::TimeDelta()); | |
| 1753 return rv; | |
| 1754 } | |
| 1755 | |
| 1756 // Next we need to attach our request to a "job". This job is responsible for | |
| 1757 // calling "getaddrinfo(hostname)" on a worker thread. | |
| 1758 | |
| 1759 JobMap::iterator jobit = jobs_.find(key); | |
| 1760 Job* job; | |
| 1761 if (jobit == jobs_.end()) { | |
| 1762 job = new Job(weak_ptr_factory_.GetWeakPtr(), key, info.priority(), | |
| 1763 request_net_log); | |
| 1764 job->Schedule(); | |
| 1765 | |
| 1766 // Check for queue overflow. | |
| 1767 if (dispatcher_.num_queued_jobs() > max_queued_jobs_) { | |
| 1768 Job* evicted = static_cast<Job*>(dispatcher_.EvictOldestLowest()); | |
| 1769 DCHECK(evicted); | |
| 1770 evicted->OnEvicted(); // Deletes |evicted|. | |
| 1771 if (evicted == job) { | |
| 1772 rv = ERR_HOST_RESOLVER_QUEUE_TOO_LARGE; | |
| 1773 LogFinishRequest(source_net_log, request_net_log, info, rv); | |
| 1774 return rv; | |
| 1775 } | |
| 1776 } | |
| 1777 jobs_.insert(jobit, std::make_pair(key, job)); | |
| 1778 } else { | |
| 1779 job = jobit->second; | |
| 1780 } | |
| 1781 | |
| 1782 // Can't complete synchronously. Create and attach request. | |
| 1783 scoped_ptr<Request> req(new Request(source_net_log, | |
| 1784 request_net_log, | |
| 1785 info, | |
| 1786 callback, | |
| 1787 addresses)); | |
| 1788 if (out_req) | |
| 1789 *out_req = reinterpret_cast<RequestHandle>(req.get()); | |
| 1790 | |
| 1791 job->AddRequest(req.Pass()); | |
| 1792 // Completion happens during Job::CompleteRequests(). | |
| 1793 return ERR_IO_PENDING; | |
| 1794 } | |
| 1795 | |
| 1796 int HostResolverImpl::ResolveHelper(const Key& key, | |
| 1797 const RequestInfo& info, | |
| 1798 AddressList* addresses, | |
| 1799 const BoundNetLog& request_net_log) { | |
| 1800 // The result of |getaddrinfo| for empty hosts is inconsistent across systems. | |
| 1801 // On Windows it gives the default interface's address, whereas on Linux it | |
| 1802 // gives an error. We will make it fail on all platforms for consistency. | |
| 1803 if (info.hostname().empty() || info.hostname().size() > kMaxHostLength) | |
| 1804 return ERR_NAME_NOT_RESOLVED; | |
| 1805 | |
| 1806 int net_error = ERR_UNEXPECTED; | |
| 1807 if (ResolveAsIP(key, info, &net_error, addresses)) | |
| 1808 return net_error; | |
| 1809 if (ServeFromCache(key, info, &net_error, addresses)) { | |
| 1810 request_net_log.AddEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_CACHE_HIT); | |
| 1811 return net_error; | |
| 1812 } | |
| 1813 // TODO(szym): Do not do this if nsswitch.conf instructs not to. | |
| 1814 // http://crbug.com/117655 | |
| 1815 if (ServeFromHosts(key, info, addresses)) { | |
| 1816 request_net_log.AddEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_HOSTS_HIT); | |
| 1817 return OK; | |
| 1818 } | |
| 1819 return ERR_DNS_CACHE_MISS; | |
| 1820 } | |
| 1821 | |
| 1822 int HostResolverImpl::ResolveFromCache(const RequestInfo& info, | |
| 1823 AddressList* addresses, | |
| 1824 const BoundNetLog& source_net_log) { | |
| 1825 DCHECK(CalledOnValidThread()); | |
| 1826 DCHECK(addresses); | |
| 1827 | |
| 1828 // Make a log item for the request. | |
| 1829 BoundNetLog request_net_log = BoundNetLog::Make(net_log_, | |
| 1830 NetLog::SOURCE_HOST_RESOLVER_IMPL_REQUEST); | |
| 1831 | |
| 1832 // Update the net log and notify registered observers. | |
| 1833 LogStartRequest(source_net_log, request_net_log, info); | |
| 1834 | |
| 1835 Key key = GetEffectiveKeyForRequest(info); | |
| 1836 | |
| 1837 int rv = ResolveHelper(key, info, addresses, request_net_log); | |
| 1838 LogFinishRequest(source_net_log, request_net_log, info, rv); | |
| 1839 return rv; | |
| 1840 } | |
| 1841 | |
| 1842 void HostResolverImpl::CancelRequest(RequestHandle req_handle) { | |
| 1843 DCHECK(CalledOnValidThread()); | |
| 1844 Request* req = reinterpret_cast<Request*>(req_handle); | |
| 1845 DCHECK(req); | |
| 1846 Job* job = req->job(); | |
| 1847 DCHECK(job); | |
| 1848 job->CancelRequest(req); | |
| 1849 } | |
| 1850 | |
| 1851 void HostResolverImpl::SetDefaultAddressFamily(AddressFamily address_family) { | |
| 1852 DCHECK(CalledOnValidThread()); | |
| 1853 default_address_family_ = address_family; | |
| 1854 ipv6_probe_monitoring_ = false; | |
| 1855 } | |
| 1856 | |
| 1857 AddressFamily HostResolverImpl::GetDefaultAddressFamily() const { | |
| 1858 return default_address_family_; | |
| 1859 } | |
| 1860 | |
| 1861 void HostResolverImpl::ProbeIPv6Support() { | |
| 1862 DCHECK(CalledOnValidThread()); | |
| 1863 DCHECK(!ipv6_probe_monitoring_); | |
| 1864 ipv6_probe_monitoring_ = true; | |
| 1865 OnIPAddressChanged(); | |
| 1866 } | |
| 1867 | |
| 1868 void HostResolverImpl::SetDnsClientEnabled(bool enabled) { | |
| 1869 DCHECK(CalledOnValidThread()); | |
| 1870 #if defined(ENABLE_BUILT_IN_DNS) | |
| 1871 if (enabled && !dns_client_) { | |
| 1872 SetDnsClient(DnsClient::CreateClient(net_log_)); | |
| 1873 } else if (!enabled && dns_client_) { | |
| 1874 SetDnsClient(scoped_ptr<DnsClient>()); | |
| 1875 } | |
| 1876 #endif | |
| 1877 } | |
| 1878 | |
| 1879 HostCache* HostResolverImpl::GetHostCache() { | |
| 1880 return cache_.get(); | |
| 1881 } | |
| 1882 | |
| 1883 base::Value* HostResolverImpl::GetDnsConfigAsValue() const { | |
| 1884 // Check if async DNS is disabled. | |
| 1885 if (!dns_client_.get()) | |
| 1886 return NULL; | |
| 1887 | |
| 1888 // Check if async DNS is enabled, but we currently have no configuration | |
| 1889 // for it. | |
| 1890 const DnsConfig* dns_config = dns_client_->GetConfig(); | |
| 1891 if (dns_config == NULL) | |
| 1892 return new DictionaryValue(); | |
| 1893 | |
| 1894 return dns_config->ToValue(); | |
| 1895 } | |
| 1896 | |
| 1897 bool HostResolverImpl::ResolveAsIP(const Key& key, | |
| 1898 const RequestInfo& info, | |
| 1899 int* net_error, | |
| 1900 AddressList* addresses) { | |
| 1901 DCHECK(addresses); | |
| 1902 DCHECK(net_error); | |
| 1903 IPAddressNumber ip_number; | |
| 1904 if (!ParseIPLiteralToNumber(key.hostname, &ip_number)) | |
| 1905 return false; | |
| 1906 | |
| 1907 DCHECK_EQ(key.host_resolver_flags & | |
| 1908 ~(HOST_RESOLVER_CANONNAME | HOST_RESOLVER_LOOPBACK_ONLY | | |
| 1909 HOST_RESOLVER_DEFAULT_FAMILY_SET_DUE_TO_NO_IPV6), | |
| 1910 0) << " Unhandled flag"; | |
| 1911 bool ipv6_disabled = (default_address_family_ == ADDRESS_FAMILY_IPV4) && | |
| 1912 !ipv6_probe_monitoring_; | |
| 1913 *net_error = OK; | |
| 1914 if ((ip_number.size() == kIPv6AddressSize) && ipv6_disabled) { | |
| 1915 *net_error = ERR_NAME_NOT_RESOLVED; | |
| 1916 } else { | |
| 1917 *addresses = AddressList::CreateFromIPAddress(ip_number, info.port()); | |
| 1918 if (key.host_resolver_flags & HOST_RESOLVER_CANONNAME) | |
| 1919 addresses->SetDefaultCanonicalName(); | |
| 1920 } | |
| 1921 return true; | |
| 1922 } | |
| 1923 | |
| 1924 bool HostResolverImpl::ServeFromCache(const Key& key, | |
| 1925 const RequestInfo& info, | |
| 1926 int* net_error, | |
| 1927 AddressList* addresses) { | |
| 1928 DCHECK(addresses); | |
| 1929 DCHECK(net_error); | |
| 1930 if (!info.allow_cached_response() || !cache_.get()) | |
| 1931 return false; | |
| 1932 | |
| 1933 const HostCache::Entry* cache_entry = cache_->Lookup( | |
| 1934 key, base::TimeTicks::Now()); | |
| 1935 if (!cache_entry) | |
| 1936 return false; | |
| 1937 | |
| 1938 *net_error = cache_entry->error; | |
| 1939 if (*net_error == OK) { | |
| 1940 if (cache_entry->has_ttl()) | |
| 1941 RecordTTL(cache_entry->ttl); | |
| 1942 *addresses = EnsurePortOnAddressList(cache_entry->addrlist, info.port()); | |
| 1943 } | |
| 1944 return true; | |
| 1945 } | |
| 1946 | |
| 1947 bool HostResolverImpl::ServeFromHosts(const Key& key, | |
| 1948 const RequestInfo& info, | |
| 1949 AddressList* addresses) { | |
| 1950 DCHECK(addresses); | |
| 1951 if (!HaveDnsConfig()) | |
| 1952 return false; | |
| 1953 | |
| 1954 // HOSTS lookups are case-insensitive. | |
| 1955 std::string hostname = StringToLowerASCII(key.hostname); | |
| 1956 | |
| 1957 // If |address_family| is ADDRESS_FAMILY_UNSPECIFIED other implementations | |
| 1958 // (glibc and c-ares) return the first matching line. We have more | |
| 1959 // flexibility, but lose implicit ordering. | |
| 1960 // TODO(szym) http://crbug.com/117850 | |
| 1961 const DnsHosts& hosts = dns_client_->GetConfig()->hosts; | |
| 1962 DnsHosts::const_iterator it = hosts.find( | |
| 1963 DnsHostsKey(hostname, | |
| 1964 key.address_family == ADDRESS_FAMILY_UNSPECIFIED ? | |
| 1965 ADDRESS_FAMILY_IPV4 : key.address_family)); | |
| 1966 | |
| 1967 if (it == hosts.end()) { | |
| 1968 if (key.address_family != ADDRESS_FAMILY_UNSPECIFIED) | |
| 1969 return false; | |
| 1970 | |
| 1971 it = hosts.find(DnsHostsKey(hostname, ADDRESS_FAMILY_IPV6)); | |
| 1972 if (it == hosts.end()) | |
| 1973 return false; | |
| 1974 } | |
| 1975 | |
| 1976 *addresses = AddressList::CreateFromIPAddress(it->second, info.port()); | |
| 1977 return true; | |
| 1978 } | |
| 1979 | |
| 1980 void HostResolverImpl::CacheResult(const Key& key, | |
| 1981 const HostCache::Entry& entry, | |
| 1982 base::TimeDelta ttl) { | |
| 1983 if (cache_.get()) | |
| 1984 cache_->Set(key, entry, base::TimeTicks::Now(), ttl); | |
| 1985 } | |
| 1986 | |
| 1987 void HostResolverImpl::RemoveJob(Job* job) { | |
| 1988 DCHECK(job); | |
| 1989 JobMap::iterator it = jobs_.find(job->key()); | |
| 1990 if (it != jobs_.end() && it->second == job) | |
| 1991 jobs_.erase(it); | |
| 1992 } | |
| 1993 | |
| 1994 void HostResolverImpl::IPv6ProbeSetDefaultAddressFamily( | |
| 1995 AddressFamily address_family) { | |
| 1996 DCHECK(address_family == ADDRESS_FAMILY_UNSPECIFIED || | |
| 1997 address_family == ADDRESS_FAMILY_IPV4); | |
| 1998 if (!ipv6_probe_monitoring_) | |
| 1999 return; | |
| 2000 if (default_address_family_ != address_family) { | |
| 2001 VLOG(1) << "IPv6Probe forced AddressFamily setting to " | |
| 2002 << ((address_family == ADDRESS_FAMILY_UNSPECIFIED) ? | |
| 2003 "ADDRESS_FAMILY_UNSPECIFIED" : "ADDRESS_FAMILY_IPV4"); | |
| 2004 } | |
| 2005 default_address_family_ = address_family; | |
| 2006 } | |
| 2007 | |
| 2008 void HostResolverImpl::SetHaveOnlyLoopbackAddresses(bool result) { | |
| 2009 if (result) { | |
| 2010 additional_resolver_flags_ |= HOST_RESOLVER_LOOPBACK_ONLY; | |
| 2011 } else { | |
| 2012 additional_resolver_flags_ &= ~HOST_RESOLVER_LOOPBACK_ONLY; | |
| 2013 } | |
| 2014 } | |
| 2015 | |
| 2016 HostResolverImpl::Key HostResolverImpl::GetEffectiveKeyForRequest( | |
| 2017 const RequestInfo& info) const { | |
| 2018 HostResolverFlags effective_flags = | |
| 2019 info.host_resolver_flags() | additional_resolver_flags_; | |
| 2020 AddressFamily effective_address_family = info.address_family(); | |
| 2021 if (effective_address_family == ADDRESS_FAMILY_UNSPECIFIED && | |
| 2022 default_address_family_ != ADDRESS_FAMILY_UNSPECIFIED) { | |
| 2023 effective_address_family = default_address_family_; | |
| 2024 if (ipv6_probe_monitoring_) | |
| 2025 effective_flags |= HOST_RESOLVER_DEFAULT_FAMILY_SET_DUE_TO_NO_IPV6; | |
| 2026 } | |
| 2027 return Key(info.hostname(), effective_address_family, effective_flags); | |
| 2028 } | |
| 2029 | |
| 2030 void HostResolverImpl::AbortAllInProgressJobs() { | |
| 2031 // In Abort, a Request callback could spawn new Jobs with matching keys, so | |
| 2032 // first collect and remove all running jobs from |jobs_|. | |
| 2033 ScopedVector<Job> jobs_to_abort; | |
| 2034 for (JobMap::iterator it = jobs_.begin(); it != jobs_.end(); ) { | |
| 2035 Job* job = it->second; | |
| 2036 if (job->is_running()) { | |
| 2037 jobs_to_abort.push_back(job); | |
| 2038 jobs_.erase(it++); | |
| 2039 } else { | |
| 2040 DCHECK(job->is_queued()); | |
| 2041 ++it; | |
| 2042 } | |
| 2043 } | |
| 2044 | |
| 2045 // Check if no dispatcher slots leaked out. | |
| 2046 DCHECK_EQ(dispatcher_.num_running_jobs(), jobs_to_abort.size()); | |
| 2047 | |
| 2048 // Life check to bail once |this| is deleted. | |
| 2049 base::WeakPtr<HostResolverImpl> self = weak_ptr_factory_.GetWeakPtr(); | |
| 2050 | |
| 2051 // Then Abort them. | |
| 2052 for (size_t i = 0; self && i < jobs_to_abort.size(); ++i) { | |
| 2053 jobs_to_abort[i]->Abort(); | |
| 2054 jobs_to_abort[i] = NULL; | |
| 2055 } | |
| 2056 } | |
| 2057 | |
| 2058 void HostResolverImpl::TryServingAllJobsFromHosts() { | |
| 2059 if (!HaveDnsConfig()) | |
| 2060 return; | |
| 2061 | |
| 2062 // TODO(szym): Do not do this if nsswitch.conf instructs not to. | |
| 2063 // http://crbug.com/117655 | |
| 2064 | |
| 2065 // Life check to bail once |this| is deleted. | |
| 2066 base::WeakPtr<HostResolverImpl> self = weak_ptr_factory_.GetWeakPtr(); | |
| 2067 | |
| 2068 for (JobMap::iterator it = jobs_.begin(); self && it != jobs_.end(); ) { | |
| 2069 Job* job = it->second; | |
| 2070 ++it; | |
| 2071 // This could remove |job| from |jobs_|, but iterator will remain valid. | |
| 2072 job->ServeFromHosts(); | |
| 2073 } | |
| 2074 } | |
| 2075 | |
| 2076 void HostResolverImpl::OnIPAddressChanged() { | |
| 2077 resolved_known_ipv6_hostname_ = false; | |
| 2078 // Abandon all ProbeJobs. | |
| 2079 probe_weak_ptr_factory_.InvalidateWeakPtrs(); | |
| 2080 if (cache_.get()) | |
| 2081 cache_->clear(); | |
| 2082 if (ipv6_probe_monitoring_) | |
| 2083 new IPv6ProbeJob(probe_weak_ptr_factory_.GetWeakPtr(), net_log_); | |
| 2084 #if defined(OS_POSIX) && !defined(OS_MACOSX) | |
| 2085 new LoopbackProbeJob(probe_weak_ptr_factory_.GetWeakPtr()); | |
| 2086 #endif | |
| 2087 AbortAllInProgressJobs(); | |
| 2088 // |this| may be deleted inside AbortAllInProgressJobs(). | |
| 2089 } | |
| 2090 | |
| 2091 void HostResolverImpl::OnDNSChanged() { | |
| 2092 DnsConfig dns_config; | |
| 2093 NetworkChangeNotifier::GetDnsConfig(&dns_config); | |
| 2094 if (net_log_) { | |
| 2095 net_log_->AddGlobalEntry( | |
| 2096 NetLog::TYPE_DNS_CONFIG_CHANGED, | |
| 2097 base::Bind(&NetLogDnsConfigCallback, &dns_config)); | |
| 2098 } | |
| 2099 | |
| 2100 // TODO(szym): Remove once http://crbug.com/137914 is resolved. | |
| 2101 received_dns_config_ = dns_config.IsValid(); | |
| 2102 | |
| 2103 num_dns_failures_ = 0; | |
| 2104 | |
| 2105 // We want a new DnsSession in place, before we Abort running Jobs, so that | |
| 2106 // the newly started jobs use the new config. | |
| 2107 if (dns_client_.get()) { | |
| 2108 dns_client_->SetConfig(dns_config); | |
| 2109 if (dns_config.IsValid()) | |
| 2110 UMA_HISTOGRAM_BOOLEAN("AsyncDNS.DnsClientEnabled", true); | |
| 2111 } | |
| 2112 | |
| 2113 // If the DNS server has changed, existing cached info could be wrong so we | |
| 2114 // have to drop our internal cache :( Note that OS level DNS caches, such | |
| 2115 // as NSCD's cache should be dropped automatically by the OS when | |
| 2116 // resolv.conf changes so we don't need to do anything to clear that cache. | |
| 2117 if (cache_.get()) | |
| 2118 cache_->clear(); | |
| 2119 | |
| 2120 // Life check to bail once |this| is deleted. | |
| 2121 base::WeakPtr<HostResolverImpl> self = weak_ptr_factory_.GetWeakPtr(); | |
| 2122 | |
| 2123 // Existing jobs will have been sent to the original server so they need to | |
| 2124 // be aborted. | |
| 2125 AbortAllInProgressJobs(); | |
| 2126 | |
| 2127 // |this| may be deleted inside AbortAllInProgressJobs(). | |
| 2128 if (self) | |
| 2129 TryServingAllJobsFromHosts(); | |
| 2130 } | |
| 2131 | |
| 2132 bool HostResolverImpl::HaveDnsConfig() const { | |
| 2133 // Use DnsClient only if it's fully configured and there is no override by | |
| 2134 // ScopedDefaultHostResolverProc. | |
| 2135 // The alternative is to use NetworkChangeNotifier to override DnsConfig, | |
| 2136 // but that would introduce construction order requirements for NCN and SDHRP. | |
| 2137 return (dns_client_.get() != NULL) && | |
| 2138 (dns_client_->GetConfig() != NULL) && | |
| 2139 !(proc_params_.resolver_proc == NULL && | |
| 2140 HostResolverProc::GetDefault() != NULL); | |
| 2141 } | |
| 2142 | |
| 2143 void HostResolverImpl::OnDnsTaskResolve(int net_error) { | |
| 2144 DCHECK(dns_client_); | |
| 2145 if (net_error == OK) { | |
| 2146 num_dns_failures_ = 0; | |
| 2147 return; | |
| 2148 } | |
| 2149 ++num_dns_failures_; | |
| 2150 if (num_dns_failures_ < kMaximumDnsFailures) | |
| 2151 return; | |
| 2152 // Disable DnsClient until the next DNS change. | |
| 2153 for (JobMap::iterator it = jobs_.begin(); it != jobs_.end(); ++it) | |
| 2154 it->second->AbortDnsTask(); | |
| 2155 dns_client_->SetConfig(DnsConfig()); | |
| 2156 UMA_HISTOGRAM_BOOLEAN("AsyncDNS.DnsClientEnabled", false); | |
| 2157 UMA_HISTOGRAM_CUSTOM_ENUMERATION("AsyncDNS.DnsClientDisabledReason", | |
| 2158 std::abs(net_error), | |
| 2159 GetAllErrorCodesForUma()); | |
| 2160 } | |
| 2161 | |
| 2162 void HostResolverImpl::SetDnsClient(scoped_ptr<DnsClient> dns_client) { | |
| 2163 if (HaveDnsConfig()) { | |
| 2164 for (JobMap::iterator it = jobs_.begin(); it != jobs_.end(); ++it) | |
| 2165 it->second->AbortDnsTask(); | |
| 2166 } | |
| 2167 dns_client_ = dns_client.Pass(); | |
| 2168 if (!dns_client_ || dns_client_->GetConfig() || | |
| 2169 num_dns_failures_ >= kMaximumDnsFailures) { | |
| 2170 return; | |
| 2171 } | |
| 2172 DnsConfig dns_config; | |
| 2173 NetworkChangeNotifier::GetDnsConfig(&dns_config); | |
| 2174 dns_client_->SetConfig(dns_config); | |
| 2175 num_dns_failures_ = 0; | |
| 2176 if (dns_config.IsValid()) | |
| 2177 UMA_HISTOGRAM_BOOLEAN("AsyncDNS.DnsClientEnabled", true); | |
| 2178 } | |
| 2179 | |
| 2180 } // namespace net | |
| OLD | NEW |