blob: bd4abb44ef1efffa19c6510526e69848da24561f [file] [log] [blame]
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "net/dns/dns_session.h"
#include "base/basictypes.h"
#include "base/bind.h"
#include "base/rand_util.h"
#include "base/stl_util.h"
#include "base/time.h"
#include "net/base/ip_endpoint.h"
#include "net/base/net_errors.h"
#include "net/dns/dns_config_service.h"
#include "net/dns/dns_socket_pool.h"
namespace net {
DnsSession::SocketLease::SocketLease(scoped_refptr<DnsSession> session,
unsigned server_index,
scoped_ptr<DatagramClientSocket> socket)
: session_(session), server_index_(server_index), socket_(socket.Pass()) {}
DnsSession::SocketLease::~SocketLease() {
session_->FreeSocket(server_index_, socket_.Pass());
}
DnsSession::DnsSession(const DnsConfig& config,
scoped_ptr<DnsSocketPool> socket_pool,
const RandIntCallback& rand_int_callback,
NetLog* net_log)
: config_(config),
socket_pool_(socket_pool.Pass()),
rand_callback_(base::Bind(rand_int_callback, 0, kuint16max)),
net_log_(net_log),
server_index_(0) {
socket_pool_->Initialize(&config_.nameservers, net_log);
}
DnsSession::~DnsSession() {
}
int DnsSession::NextQueryId() const {
return rand_callback_.Run();
}
int DnsSession::NextFirstServerIndex() {
int index = server_index_;
if (config_.rotate)
server_index_ = (server_index_ + 1) % config_.nameservers.size();
return index;
}
base::TimeDelta DnsSession::NextTimeout(int attempt) {
// The timeout doubles every full round (each nameserver once).
// TODO(szym): Adapt timeout to observed RTT. http://crbug.com/110197
return config_.timeout * (1 << (attempt / config_.nameservers.size()));
}
// Allocate a socket, already connected to the server address.
scoped_ptr<DnsSession::SocketLease> DnsSession::AllocateSocket(
unsigned server_index,
const NetLog::Source& source) {
scoped_ptr<DatagramClientSocket> socket;
socket = socket_pool_->AllocateSocket(server_index);
if (!socket.get())
return scoped_ptr<SocketLease>(NULL);
socket->NetLog().BeginEvent(
NetLog::TYPE_SOCKET_IN_USE,
source.ToEventParametersCallback());
SocketLease* lease = new SocketLease(this, server_index, socket.Pass());
return scoped_ptr<SocketLease>(lease);
}
// Release a socket.
void DnsSession::FreeSocket(
unsigned server_index,
scoped_ptr<DatagramClientSocket> socket) {
DCHECK(socket.get());
socket->NetLog().EndEvent(NetLog::TYPE_SOCKET_IN_USE);
socket_pool_->FreeSocket(server_index, socket.Pass());
}
} // namespace net