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