| Index: net/dns/dns_socket_pool.cc
|
| diff --git a/net/dns/dns_socket_pool.cc b/net/dns/dns_socket_pool.cc
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..9f55550cf3e806727183893427587d6ff75ca959
|
| --- /dev/null
|
| +++ b/net/dns/dns_socket_pool.cc
|
| @@ -0,0 +1,222 @@
|
| +// 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_socket_pool.h"
|
| +
|
| +#include "base/logging.h"
|
| +#include "base/rand_util.h"
|
| +#include "base/stl_util.h"
|
| +#include "net/base/ip_endpoint.h"
|
| +#include "net/base/net_errors.h"
|
| +#include "net/base/rand_callback.h"
|
| +#include "net/socket/client_socket_factory.h"
|
| +#include "net/udp/datagram_client_socket.h"
|
| +
|
| +namespace net {
|
| +
|
| +namespace {
|
| +
|
| +// When we initialize the SocketPool, we allocate kInitialPoolSize sockets.
|
| +// When we allocate a socket, we ensure we have at least kAllocateMinSize
|
| +// sockets to choose from. When we free a socket, we retain it if we have
|
| +// less than kRetainMaxSize sockets in the pool.
|
| +
|
| +// On Windows, we can't request specific (random) ports, since that will
|
| +// trigger firewall prompts, so request default ones, but keep a pile of
|
| +// them. Everywhere else, request fresh, random ports each time.
|
| +#if defined(OS_WIN)
|
| +const DatagramSocket::BindType kBindType = DatagramSocket::DEFAULT_BIND;
|
| +const unsigned kInitialPoolSize = 256;
|
| +const unsigned kAllocateMinSize = 256;
|
| +const unsigned kRetainMaxSize = 0;
|
| +#else
|
| +const DatagramSocket::BindType kBindType = DatagramSocket::RANDOM_BIND;
|
| +const unsigned kInitialPoolSize = 0;
|
| +const unsigned kAllocateMinSize = 1;
|
| +const unsigned kRetainMaxSize = 0;
|
| +#endif
|
| +
|
| +} // namespace
|
| +
|
| +DnsSocketPool::DnsSocketPool(ClientSocketFactory* socket_factory)
|
| + : socket_factory_(socket_factory),
|
| + net_log_(NULL),
|
| + nameservers_(NULL),
|
| + initialized_(false) {
|
| +}
|
| +
|
| +void DnsSocketPool::InitializeInternal(
|
| + const std::vector<IPEndPoint>* nameservers,
|
| + NetLog* net_log) {
|
| + DCHECK(nameservers);
|
| + DCHECK(!initialized_);
|
| +
|
| + net_log_ = net_log;
|
| + nameservers_ = nameservers;
|
| + initialized_ = true;
|
| +}
|
| +
|
| +scoped_ptr<DatagramClientSocket> DnsSocketPool::CreateConnectedSocket(
|
| + unsigned server_index) {
|
| + DCHECK_LT(server_index, nameservers_->size());
|
| +
|
| + scoped_ptr<DatagramClientSocket> socket;
|
| +
|
| + NetLog::Source no_source;
|
| + socket.reset(socket_factory_->CreateDatagramClientSocket(
|
| + kBindType, base::Bind(&base::RandInt), net_log_, no_source));
|
| +
|
| + if (socket.get()) {
|
| + int rv = socket->Connect((*nameservers_)[server_index]);
|
| + if (rv != OK) {
|
| + LOG(WARNING) << "Failed to connect socket: " << rv;
|
| + socket.reset();
|
| + }
|
| + } else {
|
| + LOG(WARNING) << "Failed to create socket.";
|
| + }
|
| +
|
| + return socket.Pass();
|
| +}
|
| +
|
| +class NullDnsSocketPool : public DnsSocketPool {
|
| + public:
|
| + NullDnsSocketPool(ClientSocketFactory* factory)
|
| + : DnsSocketPool(factory) {
|
| + }
|
| +
|
| + virtual void Initialize(
|
| + const std::vector<IPEndPoint>* nameservers,
|
| + NetLog* net_log) OVERRIDE {
|
| + InitializeInternal(nameservers, net_log);
|
| + }
|
| +
|
| + virtual scoped_ptr<DatagramClientSocket> AllocateSocket(
|
| + unsigned server_index) OVERRIDE {
|
| + return CreateConnectedSocket(server_index);
|
| + }
|
| +
|
| + virtual void FreeSocket(
|
| + unsigned server_index,
|
| + scoped_ptr<DatagramClientSocket> socket) OVERRIDE {
|
| + }
|
| +
|
| + private:
|
| + DISALLOW_COPY_AND_ASSIGN(NullDnsSocketPool);
|
| +};
|
| +
|
| +// static
|
| +scoped_ptr<DnsSocketPool> DnsSocketPool::CreateNull(
|
| + ClientSocketFactory* factory) {
|
| + return scoped_ptr<DnsSocketPool>(new NullDnsSocketPool(factory));
|
| +}
|
| +
|
| +class DefaultDnsSocketPool : public DnsSocketPool {
|
| + public:
|
| + DefaultDnsSocketPool(ClientSocketFactory* factory)
|
| + : DnsSocketPool(factory) {
|
| + };
|
| +
|
| + virtual ~DefaultDnsSocketPool();
|
| +
|
| + virtual void Initialize(
|
| + const std::vector<IPEndPoint>* nameservers,
|
| + NetLog* net_log) OVERRIDE;
|
| +
|
| + virtual scoped_ptr<DatagramClientSocket> AllocateSocket(
|
| + unsigned server_index) OVERRIDE;
|
| +
|
| + virtual void FreeSocket(
|
| + unsigned server_index,
|
| + scoped_ptr<DatagramClientSocket> socket) OVERRIDE;
|
| +
|
| + private:
|
| + void FillPool(unsigned server_index, unsigned size);
|
| +
|
| + typedef std::vector<DatagramClientSocket*> SocketVector;
|
| +
|
| + std::vector<SocketVector> pools_;
|
| +
|
| + DISALLOW_COPY_AND_ASSIGN(DefaultDnsSocketPool);
|
| +};
|
| +
|
| +// static
|
| +scoped_ptr<DnsSocketPool> DnsSocketPool::CreateDefault(
|
| + ClientSocketFactory* factory) {
|
| + return scoped_ptr<DnsSocketPool>(new DefaultDnsSocketPool(factory));
|
| +}
|
| +
|
| +void DefaultDnsSocketPool::Initialize(
|
| + const std::vector<IPEndPoint>* nameservers,
|
| + NetLog* net_log) {
|
| + InitializeInternal(nameservers, net_log);
|
| +
|
| + DCHECK(pools_.empty());
|
| + const unsigned num_servers = nameservers->size();
|
| + pools_.resize(num_servers);
|
| + for (unsigned server_index = 0; server_index < num_servers; ++server_index)
|
| + FillPool(server_index, kInitialPoolSize);
|
| +}
|
| +
|
| +DefaultDnsSocketPool::~DefaultDnsSocketPool() {
|
| + unsigned num_servers = pools_.size();
|
| + for (unsigned server_index = 0; server_index < num_servers; ++server_index) {
|
| + SocketVector& pool = pools_[server_index];
|
| + STLDeleteElements(&pool);
|
| + }
|
| +}
|
| +
|
| +scoped_ptr<DatagramClientSocket> DefaultDnsSocketPool::AllocateSocket(
|
| + unsigned server_index) {
|
| + DCHECK_LT(server_index, pools_.size());
|
| + SocketVector& pool = pools_[server_index];
|
| +
|
| + FillPool(server_index, kAllocateMinSize);
|
| + if (pool.size() == 0) {
|
| + LOG(WARNING) << "No DNS sockets available in pool " << server_index << "!";
|
| + return scoped_ptr<DatagramClientSocket>(NULL);
|
| + }
|
| +
|
| + if (pool.size() < kAllocateMinSize) {
|
| + LOG(WARNING) << "Low DNS port entropy: wanted " << kAllocateMinSize
|
| + << " sockets to choose from, but only have " << pool.size()
|
| + << " in pool " << server_index << ".";
|
| + }
|
| +
|
| + unsigned socket_index = base::RandInt(0, pool.size() - 1);
|
| + DatagramClientSocket* socket = pool[socket_index];
|
| + pool[socket_index] = pool.back();
|
| + pool.pop_back();
|
| +
|
| + return scoped_ptr<DatagramClientSocket>(socket);
|
| +}
|
| +
|
| +void DefaultDnsSocketPool::FreeSocket(
|
| + unsigned server_index,
|
| + scoped_ptr<DatagramClientSocket> socket) {
|
| + DCHECK_LT(server_index, pools_.size());
|
| +
|
| + // In some builds, kRetainMaxSize will be 0 if we never reuse sockets.
|
| + // In that case, don't compile this code to avoid a "tautological
|
| + // comparison" warning from clang.
|
| +#if kRetainMaxSize > 0
|
| + SocketVector& pool = pools_[server_index];
|
| + if (pool.size() < kRetainMaxSize)
|
| + pool.push_back(socket.release());
|
| +#endif
|
| +}
|
| +
|
| +void DefaultDnsSocketPool::FillPool(unsigned server_index, unsigned size) {
|
| + SocketVector& pool = pools_[server_index];
|
| +
|
| + for (unsigned pool_index = pool.size(); pool_index < size; ++pool_index) {
|
| + DatagramClientSocket* socket =
|
| + CreateConnectedSocket(server_index).release();
|
| + if (!socket)
|
| + break;
|
| + pool.push_back(socket);
|
| + }
|
| +}
|
| +
|
| +} // namespace net
|
|
|