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