// 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" #include "net/socket/stream_socket.h" #include "net/udp/datagram_client_socket.h" namespace net { DnsSession::SocketLease::SocketLease(scoped_refptr session, unsigned server_index, scoped_ptr 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 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 const base::TimeDelta kMaxTimeout = base::TimeDelta::FromSeconds(5); unsigned num_backoffs = attempt / config_.nameservers.size(); return std::min(config_.timeout * (1 << num_backoffs), kMaxTimeout); } // Allocate a socket, already connected to the server address. scoped_ptr DnsSession::AllocateSocket( unsigned server_index, const NetLog::Source& source) { scoped_ptr socket; socket = socket_pool_->AllocateSocket(server_index); if (!socket.get()) return scoped_ptr(NULL); socket->NetLog().BeginEvent( NetLog::TYPE_SOCKET_IN_USE, source.ToEventParametersCallback()); SocketLease* lease = new SocketLease(this, server_index, socket.Pass()); return scoped_ptr(lease); } scoped_ptr DnsSession::CreateTCPSocket( unsigned server_index, const NetLog::Source& source) { return socket_pool_->CreateTCPSocket(server_index, source); } // Release a socket. void DnsSession::FreeSocket( unsigned server_index, scoped_ptr socket) { DCHECK(socket.get()); socket->NetLog().EndEvent(NetLog::TYPE_SOCKET_IN_USE); socket_pool_->FreeSocket(server_index, socket.Pass()); } } // namespace net