blob: cdcd7ce0f4974fdfc4858397e74ac28fe767f27c [file] [log] [blame]
[email protected]d0d49dd82012-01-26 00:03:591// Copyright (c) 2012 The Chromium Authors. All rights reserved.
[email protected]7556ea22011-12-08 19:29:152// 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/dns_session.h"
6
avi65168052015-12-01 19:27:077#include <stdint.h>
danakj22f90e72016-04-16 01:55:408
avi65168052015-12-01 19:27:079#include <limits>
dchengc7eeda422015-12-26 03:56:4810#include <utility>
avi65168052015-12-01 19:27:0711
[email protected]7556ea22011-12-08 19:29:1512#include "base/bind.h"
[email protected]a6c84f42013-06-07 20:39:3813#include "base/lazy_instance.h"
Avi Drissman13fc8932015-12-20 04:40:4614#include "base/macros.h"
danakj22f90e72016-04-16 01:55:4015#include "base/memory/ptr_util.h"
ttuttlecf1158bf2016-03-18 16:37:4416#include "base/metrics/field_trial.h"
asvitkinec3c93722015-06-17 14:48:3717#include "base/metrics/histogram_macros.h"
[email protected]ae1b30b2013-05-23 23:06:0318#include "base/metrics/sample_vector.h"
[email protected]120d38d2012-12-14 01:42:3219#include "base/rand_util.h"
20#include "base/stl_util.h"
[email protected]66e96c42013-06-28 15:20:3121#include "base/time/time.h"
juliatuttled7fa5852016-07-29 13:16:5722#include "base/values.h"
[email protected]7556ea22011-12-08 19:29:1523#include "net/base/ip_endpoint.h"
[email protected]120d38d2012-12-14 01:42:3224#include "net/base/net_errors.h"
[email protected]7556ea22011-12-08 19:29:1525#include "net/dns/dns_config_service.h"
[email protected]120d38d2012-12-14 01:42:3226#include "net/dns/dns_socket_pool.h"
ttuttlecf1158bf2016-03-18 16:37:4427#include "net/dns/dns_util.h"
mikecirone8b85c432016-09-08 19:11:0028#include "net/log/net_log_event_type.h"
mikecironef22f9812016-10-04 03:40:1929#include "net/log/net_log_source.h"
30#include "net/log/net_log_with_source.h"
tfarina5dd13c22016-11-16 12:08:2631#include "net/socket/datagram_client_socket.h"
[email protected]bdb65982012-12-20 20:44:5932#include "net/socket/stream_socket.h"
[email protected]7556ea22011-12-08 19:29:1533
34namespace net {
35
[email protected]ae1b30b2013-05-23 23:06:0336namespace {
ttuttlecf1158bf2016-03-18 16:37:4437
[email protected]ae1b30b2013-05-23 23:06:0338// Set min timeout, in case we are talking to a local DNS proxy.
39const unsigned kMinTimeoutMs = 10;
40
ttuttlecf1158bf2016-03-18 16:37:4441// Default maximum timeout between queries, even with exponential backoff.
42// (Can be overridden by field trial.)
43const unsigned kDefaultMaxTimeoutMs = 5000;
44
45// Maximum RTT that will fit in the RTT histograms.
46const int32_t kRTTMaxMs = 30000;
[email protected]ae1b30b2013-05-23 23:06:0347// Number of buckets in the histogram of observed RTTs.
ttuttlecf1158bf2016-03-18 16:37:4448const size_t kRTTBucketCount = 350;
[email protected]ae1b30b2013-05-23 23:06:0349// Target percentile in the RTT histogram used for retransmission timeout.
50const unsigned kRTOPercentile = 99;
ttuttlecf1158bf2016-03-18 16:37:4451
[email protected]ae1b30b2013-05-23 23:06:0352} // namespace
53
[email protected]a6c84f42013-06-07 20:39:3854// Runtime statistics of DNS server.
55struct DnsSession::ServerStats {
56 ServerStats(base::TimeDelta rtt_estimate_param, RttBuckets* buckets)
57 : last_failure_count(0), rtt_estimate(rtt_estimate_param) {
58 rtt_histogram.reset(new base::SampleVector(buckets));
[email protected]a144bd22013-07-29 21:53:1059 // Seed histogram with 2 samples at |rtt_estimate| timeout.
pkasting6b68a162014-12-01 22:10:2960 rtt_histogram->Accumulate(
61 static_cast<base::HistogramBase::Sample>(rtt_estimate.InMilliseconds()),
62 2);
[email protected]a6c84f42013-06-07 20:39:3863 }
64
65 // Count of consecutive failures after last success.
66 int last_failure_count;
67
68 // Last time when server returned failure or timeout.
69 base::Time last_failure;
70 // Last time when server returned success.
71 base::Time last_success;
72
73 // Estimated RTT using moving average.
74 base::TimeDelta rtt_estimate;
75 // Estimated error in the above.
76 base::TimeDelta rtt_deviation;
77
78 // A histogram of observed RTT .
danakj22f90e72016-04-16 01:55:4079 std::unique_ptr<base::SampleVector> rtt_histogram;
[email protected]a6c84f42013-06-07 20:39:3880
81 DISALLOW_COPY_AND_ASSIGN(ServerStats);
82};
83
84// static
85base::LazyInstance<DnsSession::RttBuckets>::Leaky DnsSession::rtt_buckets_ =
86 LAZY_INSTANCE_INITIALIZER;
87
88DnsSession::RttBuckets::RttBuckets() : base::BucketRanges(kRTTBucketCount + 1) {
ttuttlecf1158bf2016-03-18 16:37:4489 base::Histogram::InitializeBucketRanges(1, kRTTMaxMs, this);
[email protected]a6c84f42013-06-07 20:39:3890}
91
danakj22f90e72016-04-16 01:55:4092DnsSession::SocketLease::SocketLease(
93 scoped_refptr<DnsSession> session,
94 unsigned server_index,
95 std::unique_ptr<DatagramClientSocket> socket)
dchengc7eeda422015-12-26 03:56:4896 : session_(session),
97 server_index_(server_index),
98 socket_(std::move(socket)) {}
[email protected]120d38d2012-12-14 01:42:3299
100DnsSession::SocketLease::~SocketLease() {
dchengc7eeda422015-12-26 03:56:48101 session_->FreeSocket(server_index_, std::move(socket_));
[email protected]120d38d2012-12-14 01:42:32102}
103
[email protected]7556ea22011-12-08 19:29:15104DnsSession::DnsSession(const DnsConfig& config,
danakj22f90e72016-04-16 01:55:40105 std::unique_ptr<DnsSocketPool> socket_pool,
[email protected]7556ea22011-12-08 19:29:15106 const RandIntCallback& rand_int_callback,
107 NetLog* net_log)
108 : config_(config),
dchengc7eeda422015-12-26 03:56:48109 socket_pool_(std::move(socket_pool)),
avi65168052015-12-01 19:27:07110 rand_callback_(base::Bind(rand_int_callback,
111 0,
112 std::numeric_limits<uint16_t>::max())),
[email protected]7556ea22011-12-08 19:29:15113 net_log_(net_log),
[email protected]a6c84f42013-06-07 20:39:38114 server_index_(0) {
[email protected]120d38d2012-12-14 01:42:32115 socket_pool_->Initialize(&config_.nameservers, net_log);
drbasicf0d1b262016-08-23 06:10:42116 UMA_HISTOGRAM_CUSTOM_COUNTS("AsyncDNS.ServerCount",
117 config_.nameservers.size(), 1, 10, 11);
ttuttlecf1158bf2016-03-18 16:37:44118 UpdateTimeouts(NetworkChangeNotifier::GetConnectionType());
119 InitializeServerStats();
120 NetworkChangeNotifier::AddConnectionTypeObserver(this);
[email protected]120d38d2012-12-14 01:42:32121}
122
[email protected]a6c84f42013-06-07 20:39:38123DnsSession::~DnsSession() {
124 RecordServerStats();
ttuttlecf1158bf2016-03-18 16:37:44125 NetworkChangeNotifier::RemoveConnectionTypeObserver(this);
126}
127
128void DnsSession::UpdateTimeouts(NetworkChangeNotifier::ConnectionType type) {
129 initial_timeout_ = GetTimeDeltaForConnectionTypeFromFieldTrialOrDefault(
130 "AsyncDnsInitialTimeoutMsByConnectionType", config_.timeout, type);
131 max_timeout_ = GetTimeDeltaForConnectionTypeFromFieldTrialOrDefault(
132 "AsyncDnsMaxTimeoutMsByConnectionType",
133 base::TimeDelta::FromMilliseconds(kDefaultMaxTimeoutMs), type);
134}
135
136void DnsSession::InitializeServerStats() {
137 server_stats_.clear();
138 for (size_t i = 0; i < config_.nameservers.size(); ++i) {
ricea2deef682016-09-09 08:04:07139 server_stats_.push_back(base::MakeUnique<ServerStats>(
140 initial_timeout_, rtt_buckets_.Pointer()));
ttuttlecf1158bf2016-03-18 16:37:44141 }
142}
143
144void DnsSession::OnConnectionTypeChanged(
145 NetworkChangeNotifier::ConnectionType type) {
146 UpdateTimeouts(type);
147 const char* kTrialName = "AsyncDnsFlushServerStatsOnConnectionTypeChange";
148 if (base::FieldTrialList::FindFullName(kTrialName) == "enable") {
149 RecordServerStats();
150 InitializeServerStats();
151 }
[email protected]a6c84f42013-06-07 20:39:38152}
[email protected]7556ea22011-12-08 19:29:15153
avi65168052015-12-01 19:27:07154uint16_t DnsSession::NextQueryId() const {
155 return static_cast<uint16_t>(rand_callback_.Run());
pkasting6b68a162014-12-01 22:10:29156}
[email protected]7556ea22011-12-08 19:29:15157
[email protected]a6c84f42013-06-07 20:39:38158unsigned DnsSession::NextFirstServerIndex() {
159 unsigned index = NextGoodServerIndex(server_index_);
[email protected]7556ea22011-12-08 19:29:15160 if (config_.rotate)
161 server_index_ = (server_index_ + 1) % config_.nameservers.size();
[email protected]d0d49dd82012-01-26 00:03:59162 return index;
[email protected]7556ea22011-12-08 19:29:15163}
164
[email protected]a6c84f42013-06-07 20:39:38165unsigned DnsSession::NextGoodServerIndex(unsigned server_index) {
166 unsigned index = server_index;
167 base::Time oldest_server_failure(base::Time::Now());
168 unsigned oldest_server_failure_index = 0;
169
170 UMA_HISTOGRAM_BOOLEAN("AsyncDNS.ServerIsGood",
171 server_stats_[server_index]->last_failure.is_null());
172
173 do {
174 base::Time cur_server_failure = server_stats_[index]->last_failure;
175 // If number of failures on this server doesn't exceed number of allowed
176 // attempts, return its index.
177 if (server_stats_[server_index]->last_failure_count < config_.attempts) {
178 return index;
179 }
180 // Track oldest failed server.
181 if (cur_server_failure < oldest_server_failure) {
182 oldest_server_failure = cur_server_failure;
183 oldest_server_failure_index = index;
184 }
185 index = (index + 1) % config_.nameservers.size();
186 } while (index != server_index);
187
188 // If we are here it means that there are no successful servers, so we have
189 // to use one that has failed oldest.
190 return oldest_server_failure_index;
191}
192
193void DnsSession::RecordServerFailure(unsigned server_index) {
drbasicf0d1b262016-08-23 06:10:42194 UMA_HISTOGRAM_CUSTOM_COUNTS("AsyncDNS.ServerFailureIndex", server_index, 1,
195 10, 11);
[email protected]a6c84f42013-06-07 20:39:38196 ++(server_stats_[server_index]->last_failure_count);
197 server_stats_[server_index]->last_failure = base::Time::Now();
198}
199
200void DnsSession::RecordServerSuccess(unsigned server_index) {
201 if (server_stats_[server_index]->last_success.is_null()) {
202 UMA_HISTOGRAM_COUNTS_100("AsyncDNS.ServerFailuresAfterNetworkChange",
203 server_stats_[server_index]->last_failure_count);
204 } else {
205 UMA_HISTOGRAM_COUNTS_100("AsyncDNS.ServerFailuresBeforeSuccess",
206 server_stats_[server_index]->last_failure_count);
207 }
208 server_stats_[server_index]->last_failure_count = 0;
209 server_stats_[server_index]->last_failure = base::Time();
210 server_stats_[server_index]->last_success = base::Time::Now();
211}
212
[email protected]ae1b30b2013-05-23 23:06:03213void DnsSession::RecordRTT(unsigned server_index, base::TimeDelta rtt) {
[email protected]a6c84f42013-06-07 20:39:38214 DCHECK_LT(server_index, server_stats_.size());
[email protected]ae1b30b2013-05-23 23:06:03215
216 // For measurement, assume it is the first attempt (no backoff).
217 base::TimeDelta timeout_jacobson = NextTimeoutFromJacobson(server_index, 0);
218 base::TimeDelta timeout_histogram = NextTimeoutFromHistogram(server_index, 0);
219 UMA_HISTOGRAM_TIMES("AsyncDNS.TimeoutErrorJacobson", rtt - timeout_jacobson);
220 UMA_HISTOGRAM_TIMES("AsyncDNS.TimeoutErrorHistogram",
221 rtt - timeout_histogram);
222 UMA_HISTOGRAM_TIMES("AsyncDNS.TimeoutErrorJacobsonUnder",
223 timeout_jacobson - rtt);
224 UMA_HISTOGRAM_TIMES("AsyncDNS.TimeoutErrorHistogramUnder",
225 timeout_histogram - rtt);
226
227 // Jacobson/Karels algorithm for TCP.
228 // Using parameters: alpha = 1/8, delta = 1/4, beta = 4
[email protected]a6c84f42013-06-07 20:39:38229 base::TimeDelta& estimate = server_stats_[server_index]->rtt_estimate;
230 base::TimeDelta& deviation = server_stats_[server_index]->rtt_deviation;
[email protected]ae1b30b2013-05-23 23:06:03231 base::TimeDelta current_error = rtt - estimate;
232 estimate += current_error / 8; // * alpha
233 base::TimeDelta abs_error = base::TimeDelta::FromInternalValue(
234 std::abs(current_error.ToInternalValue()));
235 deviation += (abs_error - deviation) / 4; // * delta
236
237 // Histogram-based method.
pkasting6b68a162014-12-01 22:10:29238 server_stats_[server_index]->rtt_histogram->Accumulate(
239 static_cast<base::HistogramBase::Sample>(rtt.InMilliseconds()), 1);
[email protected]ae1b30b2013-05-23 23:06:03240}
241
242void DnsSession::RecordLostPacket(unsigned server_index, int attempt) {
243 base::TimeDelta timeout_jacobson =
244 NextTimeoutFromJacobson(server_index, attempt);
245 base::TimeDelta timeout_histogram =
246 NextTimeoutFromHistogram(server_index, attempt);
247 UMA_HISTOGRAM_TIMES("AsyncDNS.TimeoutSpentJacobson", timeout_jacobson);
248 UMA_HISTOGRAM_TIMES("AsyncDNS.TimeoutSpentHistogram", timeout_histogram);
249}
250
[email protected]a6c84f42013-06-07 20:39:38251void DnsSession::RecordServerStats() {
252 for (size_t index = 0; index < server_stats_.size(); ++index) {
253 if (server_stats_[index]->last_failure_count) {
254 if (server_stats_[index]->last_success.is_null()) {
255 UMA_HISTOGRAM_COUNTS("AsyncDNS.ServerFailuresWithoutSuccess",
256 server_stats_[index]->last_failure_count);
257 } else {
258 UMA_HISTOGRAM_COUNTS("AsyncDNS.ServerFailuresAfterSuccess",
259 server_stats_[index]->last_failure_count);
260 }
261 }
262 }
263}
264
265
[email protected]ae1b30b2013-05-23 23:06:03266base::TimeDelta DnsSession::NextTimeout(unsigned server_index, int attempt) {
ttuttlecf1158bf2016-03-18 16:37:44267 // Respect initial timeout (from config or field trial) if it exceeds max.
268 if (initial_timeout_ > max_timeout_)
269 return initial_timeout_;
[email protected]a144bd22013-07-29 21:53:10270 return NextTimeoutFromHistogram(server_index, attempt);
[email protected]7556ea22011-12-08 19:29:15271}
272
[email protected]120d38d2012-12-14 01:42:32273// Allocate a socket, already connected to the server address.
danakj22f90e72016-04-16 01:55:40274std::unique_ptr<DnsSession::SocketLease> DnsSession::AllocateSocket(
275 unsigned server_index,
mikecironef22f9812016-10-04 03:40:19276 const NetLogSource& source) {
danakj22f90e72016-04-16 01:55:40277 std::unique_ptr<DatagramClientSocket> socket;
[email protected]120d38d2012-12-14 01:42:32278
279 socket = socket_pool_->AllocateSocket(server_index);
[email protected]dd946bb2013-06-12 22:53:01280 if (!socket.get())
danakj22f90e72016-04-16 01:55:40281 return std::unique_ptr<SocketLease>();
[email protected]120d38d2012-12-14 01:42:32282
mikecirone8b85c432016-09-08 19:11:00283 socket->NetLog().BeginEvent(NetLogEventType::SOCKET_IN_USE,
[email protected]ae1b30b2013-05-23 23:06:03284 source.ToEventParametersCallback());
[email protected]120d38d2012-12-14 01:42:32285
dchengc7eeda422015-12-26 03:56:48286 SocketLease* lease = new SocketLease(this, server_index, std::move(socket));
danakj22f90e72016-04-16 01:55:40287 return std::unique_ptr<SocketLease>(lease);
[email protected]120d38d2012-12-14 01:42:32288}
289
danakj22f90e72016-04-16 01:55:40290std::unique_ptr<StreamSocket> DnsSession::CreateTCPSocket(
291 unsigned server_index,
mikecironef22f9812016-10-04 03:40:19292 const NetLogSource& source) {
[email protected]bdb65982012-12-20 20:44:59293 return socket_pool_->CreateTCPSocket(server_index, source);
294}
295
juliatuttled7fa5852016-07-29 13:16:57296void DnsSession::ApplyPersistentData(const base::Value& data) {}
297
298std::unique_ptr<const base::Value> DnsSession::GetPersistentData() const {
299 return std::unique_ptr<const base::Value>();
300}
301
[email protected]120d38d2012-12-14 01:42:32302// Release a socket.
[email protected]ae1b30b2013-05-23 23:06:03303void DnsSession::FreeSocket(unsigned server_index,
danakj22f90e72016-04-16 01:55:40304 std::unique_ptr<DatagramClientSocket> socket) {
[email protected]120d38d2012-12-14 01:42:32305 DCHECK(socket.get());
306
mikecirone8b85c432016-09-08 19:11:00307 socket->NetLog().EndEvent(NetLogEventType::SOCKET_IN_USE);
[email protected]120d38d2012-12-14 01:42:32308
dchengc7eeda422015-12-26 03:56:48309 socket_pool_->FreeSocket(server_index, std::move(socket));
[email protected]120d38d2012-12-14 01:42:32310}
[email protected]7556ea22011-12-08 19:29:15311
[email protected]ae1b30b2013-05-23 23:06:03312base::TimeDelta DnsSession::NextTimeoutFromJacobson(unsigned server_index,
313 int attempt) {
[email protected]a6c84f42013-06-07 20:39:38314 DCHECK_LT(server_index, server_stats_.size());
[email protected]ae1b30b2013-05-23 23:06:03315
[email protected]a6c84f42013-06-07 20:39:38316 base::TimeDelta timeout = server_stats_[server_index]->rtt_estimate +
317 4 * server_stats_[server_index]->rtt_deviation;
[email protected]ae1b30b2013-05-23 23:06:03318
319 timeout = std::max(timeout, base::TimeDelta::FromMilliseconds(kMinTimeoutMs));
320
321 // The timeout doubles every full round.
322 unsigned num_backoffs = attempt / config_.nameservers.size();
323
ttuttlecf1158bf2016-03-18 16:37:44324 return std::min(timeout * (1 << num_backoffs), max_timeout_);
[email protected]ae1b30b2013-05-23 23:06:03325}
326
327base::TimeDelta DnsSession::NextTimeoutFromHistogram(unsigned server_index,
328 int attempt) {
[email protected]a6c84f42013-06-07 20:39:38329 DCHECK_LT(server_index, server_stats_.size());
[email protected]ae1b30b2013-05-23 23:06:03330
mostynb91e0da982015-01-20 19:17:27331 static_assert(std::numeric_limits<base::HistogramBase::Count>::is_signed,
332 "histogram base count assumed to be signed");
[email protected]ae1b30b2013-05-23 23:06:03333
334 // Use fixed percentile of observed samples.
[email protected]a6c84f42013-06-07 20:39:38335 const base::SampleVector& samples =
336 *server_stats_[server_index]->rtt_histogram;
337
[email protected]ae1b30b2013-05-23 23:06:03338 base::HistogramBase::Count total = samples.TotalCount();
339 base::HistogramBase::Count remaining_count = kRTOPercentile * total / 100;
340 size_t index = 0;
[email protected]a6c84f42013-06-07 20:39:38341 while (remaining_count > 0 && index < rtt_buckets_.Get().size()) {
[email protected]ae1b30b2013-05-23 23:06:03342 remaining_count -= samples.GetCountAtIndex(index);
343 ++index;
344 }
345
346 base::TimeDelta timeout =
[email protected]a6c84f42013-06-07 20:39:38347 base::TimeDelta::FromMilliseconds(rtt_buckets_.Get().range(index));
[email protected]ae1b30b2013-05-23 23:06:03348
349 timeout = std::max(timeout, base::TimeDelta::FromMilliseconds(kMinTimeoutMs));
350
351 // The timeout still doubles every full round.
352 unsigned num_backoffs = attempt / config_.nameservers.size();
353
ttuttlecf1158bf2016-03-18 16:37:44354 return std::min(timeout * (1 << num_backoffs), max_timeout_);
[email protected]ae1b30b2013-05-23 23:06:03355}
356
[email protected]7556ea22011-12-08 19:29:15357} // namespace net