15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved. 25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file. 45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/dns/dns_session.h" 65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/basictypes.h" 85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/bind.h" 9868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/lazy_instance.h" 1090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include "base/metrics/histogram.h" 1190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include "base/metrics/sample_vector.h" 122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/rand_util.h" 132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/stl_util.h" 14eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "base/time/time.h" 155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/base/ip_endpoint.h" 162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "net/base/net_errors.h" 175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/dns/dns_config_service.h" 182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "net/dns/dns_socket_pool.h" 192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "net/socket/stream_socket.h" 202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "net/udp/datagram_client_socket.h" 215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace net { 235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)namespace { 2590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)// Never exceed max timeout. 2690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)const unsigned kMaxTimeoutMs = 5000; 2790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)// Set min timeout, in case we are talking to a local DNS proxy. 2890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)const unsigned kMinTimeoutMs = 10; 2990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) 3090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)// Number of buckets in the histogram of observed RTTs. 3190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)const size_t kRTTBucketCount = 100; 3290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)// Target percentile in the RTT histogram used for retransmission timeout. 3390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)const unsigned kRTOPercentile = 99; 3490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)} // namespace 3590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) 36868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)// Runtime statistics of DNS server. 37868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)struct DnsSession::ServerStats { 38868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) ServerStats(base::TimeDelta rtt_estimate_param, RttBuckets* buckets) 39868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) : last_failure_count(0), rtt_estimate(rtt_estimate_param) { 40868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) rtt_histogram.reset(new base::SampleVector(buckets)); 41558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch // Seed histogram with 2 samples at |rtt_estimate| timeout. 42558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch rtt_histogram->Accumulate(rtt_estimate.InMilliseconds(), 2); 43868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) } 44868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 45868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) // Count of consecutive failures after last success. 46868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) int last_failure_count; 47868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 48868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) // Last time when server returned failure or timeout. 49868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) base::Time last_failure; 50868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) // Last time when server returned success. 51868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) base::Time last_success; 52868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 53868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) // Estimated RTT using moving average. 54868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) base::TimeDelta rtt_estimate; 55868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) // Estimated error in the above. 56868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) base::TimeDelta rtt_deviation; 57868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 58868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) // A histogram of observed RTT . 59868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) scoped_ptr<base::SampleVector> rtt_histogram; 60868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 61868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) DISALLOW_COPY_AND_ASSIGN(ServerStats); 62868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)}; 63868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 64868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)// static 65868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)base::LazyInstance<DnsSession::RttBuckets>::Leaky DnsSession::rtt_buckets_ = 66868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) LAZY_INSTANCE_INITIALIZER; 67868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 68868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)DnsSession::RttBuckets::RttBuckets() : base::BucketRanges(kRTTBucketCount + 1) { 69eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch base::Histogram::InitializeBucketRanges(1, 5000, this); 70868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)} 71868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)DnsSession::SocketLease::SocketLease(scoped_refptr<DnsSession> session, 732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) unsigned server_index, 742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) scoped_ptr<DatagramClientSocket> socket) 752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) : session_(session), server_index_(server_index), socket_(socket.Pass()) {} 762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)DnsSession::SocketLease::~SocketLease() { 782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) session_->FreeSocket(server_index_, socket_.Pass()); 792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)DnsSession::DnsSession(const DnsConfig& config, 822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) scoped_ptr<DnsSocketPool> socket_pool, 835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const RandIntCallback& rand_int_callback, 845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NetLog* net_log) 855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) : config_(config), 862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) socket_pool_(socket_pool.Pass()), 875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) rand_callback_(base::Bind(rand_int_callback, 0, kuint16max)), 885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) net_log_(net_log), 89868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) server_index_(0) { 902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) socket_pool_->Initialize(&config_.nameservers, net_log); 91868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) UMA_HISTOGRAM_CUSTOM_COUNTS( 92868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) "AsyncDNS.ServerCount", config_.nameservers.size(), 0, 10, 10); 9390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) for (size_t i = 0; i < config_.nameservers.size(); ++i) { 94868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) server_stats_.push_back(new ServerStats(config_.timeout, 95868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) rtt_buckets_.Pointer())); 9690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) } 975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 99868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)DnsSession::~DnsSession() { 100868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) RecordServerStats(); 101868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)} 10290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) 10390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)int DnsSession::NextQueryId() const { return rand_callback_.Run(); } 1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 105868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)unsigned DnsSession::NextFirstServerIndex() { 106868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) unsigned index = NextGoodServerIndex(server_index_); 1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (config_.rotate) 1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) server_index_ = (server_index_ + 1) % config_.nameservers.size(); 1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return index; 1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 112868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)unsigned DnsSession::NextGoodServerIndex(unsigned server_index) { 113868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) unsigned index = server_index; 114868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) base::Time oldest_server_failure(base::Time::Now()); 115868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) unsigned oldest_server_failure_index = 0; 116868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 117868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) UMA_HISTOGRAM_BOOLEAN("AsyncDNS.ServerIsGood", 118868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) server_stats_[server_index]->last_failure.is_null()); 119868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 120868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) do { 121868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) base::Time cur_server_failure = server_stats_[index]->last_failure; 122868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) // If number of failures on this server doesn't exceed number of allowed 123868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) // attempts, return its index. 124868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) if (server_stats_[server_index]->last_failure_count < config_.attempts) { 125868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) return index; 126868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) } 127868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) // Track oldest failed server. 128868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) if (cur_server_failure < oldest_server_failure) { 129868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) oldest_server_failure = cur_server_failure; 130868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) oldest_server_failure_index = index; 131868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) } 132868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) index = (index + 1) % config_.nameservers.size(); 133868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) } while (index != server_index); 134868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 135868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) // If we are here it means that there are no successful servers, so we have 136868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) // to use one that has failed oldest. 137868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) return oldest_server_failure_index; 138868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)} 139868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 140868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)void DnsSession::RecordServerFailure(unsigned server_index) { 141868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) UMA_HISTOGRAM_CUSTOM_COUNTS( 142868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) "AsyncDNS.ServerFailureIndex", server_index, 0, 10, 10); 143868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) ++(server_stats_[server_index]->last_failure_count); 144868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) server_stats_[server_index]->last_failure = base::Time::Now(); 145868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)} 146868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 147868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)void DnsSession::RecordServerSuccess(unsigned server_index) { 148868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) if (server_stats_[server_index]->last_success.is_null()) { 149868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) UMA_HISTOGRAM_COUNTS_100("AsyncDNS.ServerFailuresAfterNetworkChange", 150868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) server_stats_[server_index]->last_failure_count); 151868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) } else { 152868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) UMA_HISTOGRAM_COUNTS_100("AsyncDNS.ServerFailuresBeforeSuccess", 153868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) server_stats_[server_index]->last_failure_count); 154868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) } 155868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) server_stats_[server_index]->last_failure_count = 0; 156868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) server_stats_[server_index]->last_failure = base::Time(); 157868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) server_stats_[server_index]->last_success = base::Time::Now(); 158868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)} 159868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 16090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)void DnsSession::RecordRTT(unsigned server_index, base::TimeDelta rtt) { 161868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) DCHECK_LT(server_index, server_stats_.size()); 16290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) 16390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) // For measurement, assume it is the first attempt (no backoff). 16490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) base::TimeDelta timeout_jacobson = NextTimeoutFromJacobson(server_index, 0); 16590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) base::TimeDelta timeout_histogram = NextTimeoutFromHistogram(server_index, 0); 16690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) UMA_HISTOGRAM_TIMES("AsyncDNS.TimeoutErrorJacobson", rtt - timeout_jacobson); 16790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) UMA_HISTOGRAM_TIMES("AsyncDNS.TimeoutErrorHistogram", 16890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) rtt - timeout_histogram); 16990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) UMA_HISTOGRAM_TIMES("AsyncDNS.TimeoutErrorJacobsonUnder", 17090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) timeout_jacobson - rtt); 17190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) UMA_HISTOGRAM_TIMES("AsyncDNS.TimeoutErrorHistogramUnder", 17290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) timeout_histogram - rtt); 17390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) 17490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) // Jacobson/Karels algorithm for TCP. 17590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) // Using parameters: alpha = 1/8, delta = 1/4, beta = 4 176868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) base::TimeDelta& estimate = server_stats_[server_index]->rtt_estimate; 177868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) base::TimeDelta& deviation = server_stats_[server_index]->rtt_deviation; 17890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) base::TimeDelta current_error = rtt - estimate; 17990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) estimate += current_error / 8; // * alpha 18090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) base::TimeDelta abs_error = base::TimeDelta::FromInternalValue( 18190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) std::abs(current_error.ToInternalValue())); 18290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) deviation += (abs_error - deviation) / 4; // * delta 18390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) 18490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) // Histogram-based method. 185868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) server_stats_[server_index]->rtt_histogram 186868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) ->Accumulate(rtt.InMilliseconds(), 1); 18790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)} 18890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) 18990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)void DnsSession::RecordLostPacket(unsigned server_index, int attempt) { 19090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) base::TimeDelta timeout_jacobson = 19190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) NextTimeoutFromJacobson(server_index, attempt); 19290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) base::TimeDelta timeout_histogram = 19390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) NextTimeoutFromHistogram(server_index, attempt); 19490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) UMA_HISTOGRAM_TIMES("AsyncDNS.TimeoutSpentJacobson", timeout_jacobson); 19590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) UMA_HISTOGRAM_TIMES("AsyncDNS.TimeoutSpentHistogram", timeout_histogram); 19690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)} 19790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) 198868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)void DnsSession::RecordServerStats() { 199868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) for (size_t index = 0; index < server_stats_.size(); ++index) { 200868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) if (server_stats_[index]->last_failure_count) { 201868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) if (server_stats_[index]->last_success.is_null()) { 202868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) UMA_HISTOGRAM_COUNTS("AsyncDNS.ServerFailuresWithoutSuccess", 203868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) server_stats_[index]->last_failure_count); 204868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) } else { 205868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) UMA_HISTOGRAM_COUNTS("AsyncDNS.ServerFailuresAfterSuccess", 206868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) server_stats_[index]->last_failure_count); 207868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) } 208868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) } 209868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) } 210868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)} 211868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 212868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 21390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)base::TimeDelta DnsSession::NextTimeout(unsigned server_index, int attempt) { 214558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch // Respect config timeout if it exceeds |kMaxTimeoutMs|. 215558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch if (config_.timeout.InMilliseconds() >= kMaxTimeoutMs) 216558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch return config_.timeout; 217558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch return NextTimeoutFromHistogram(server_index, attempt); 2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Allocate a socket, already connected to the server address. 2212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)scoped_ptr<DnsSession::SocketLease> DnsSession::AllocateSocket( 22290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) unsigned server_index, const NetLog::Source& source) { 2232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) scoped_ptr<DatagramClientSocket> socket; 2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) socket = socket_pool_->AllocateSocket(server_index); 2267d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) if (!socket.get()) 2277d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) return scoped_ptr<SocketLease>(); 2282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 22990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) socket->NetLog().BeginEvent(NetLog::TYPE_SOCKET_IN_USE, 23090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) source.ToEventParametersCallback()); 2312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) SocketLease* lease = new SocketLease(this, server_index, socket.Pass()); 2332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return scoped_ptr<SocketLease>(lease); 2342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 2352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)scoped_ptr<StreamSocket> DnsSession::CreateTCPSocket( 23790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) unsigned server_index, const NetLog::Source& source) { 2382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return socket_pool_->CreateTCPSocket(server_index, source); 2392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 2402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Release a socket. 24290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)void DnsSession::FreeSocket(unsigned server_index, 24390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) scoped_ptr<DatagramClientSocket> socket) { 2442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DCHECK(socket.get()); 2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) socket->NetLog().EndEvent(NetLog::TYPE_SOCKET_IN_USE); 2472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) socket_pool_->FreeSocket(server_index, socket.Pass()); 2492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 2502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 25190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)base::TimeDelta DnsSession::NextTimeoutFromJacobson(unsigned server_index, 25290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) int attempt) { 253868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) DCHECK_LT(server_index, server_stats_.size()); 25490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) 255868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) base::TimeDelta timeout = server_stats_[server_index]->rtt_estimate + 256868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 4 * server_stats_[server_index]->rtt_deviation; 25790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) 25890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) timeout = std::max(timeout, base::TimeDelta::FromMilliseconds(kMinTimeoutMs)); 25990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) 26090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) // The timeout doubles every full round. 26190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) unsigned num_backoffs = attempt / config_.nameservers.size(); 26290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) 26390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) return std::min(timeout * (1 << num_backoffs), 26490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) base::TimeDelta::FromMilliseconds(kMaxTimeoutMs)); 26590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)} 26690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) 26790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)base::TimeDelta DnsSession::NextTimeoutFromHistogram(unsigned server_index, 26890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) int attempt) { 269868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) DCHECK_LT(server_index, server_stats_.size()); 27090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) 27190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) COMPILE_ASSERT(std::numeric_limits<base::HistogramBase::Count>::is_signed, 27290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) histogram_base_count_assumed_to_be_signed); 27390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) 27490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) // Use fixed percentile of observed samples. 275868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) const base::SampleVector& samples = 276868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) *server_stats_[server_index]->rtt_histogram; 277868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 27890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) base::HistogramBase::Count total = samples.TotalCount(); 27990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) base::HistogramBase::Count remaining_count = kRTOPercentile * total / 100; 28090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) size_t index = 0; 281868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) while (remaining_count > 0 && index < rtt_buckets_.Get().size()) { 28290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) remaining_count -= samples.GetCountAtIndex(index); 28390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) ++index; 28490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) } 28590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) 28690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) base::TimeDelta timeout = 287868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) base::TimeDelta::FromMilliseconds(rtt_buckets_.Get().range(index)); 28890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) 28990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) timeout = std::max(timeout, base::TimeDelta::FromMilliseconds(kMinTimeoutMs)); 29090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) 29190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) // The timeout still doubles every full round. 29290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) unsigned num_backoffs = attempt / config_.nameservers.size(); 29390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) 29490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) return std::min(timeout * (1 << num_backoffs), 29590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) base::TimeDelta::FromMilliseconds(kMaxTimeoutMs)); 29690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)} 29790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) 2982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} // namespace net 299