diff options
author | Zeno Albisser <zeno.albisser@digia.com> | 2013-08-15 21:46:11 +0200 |
---|---|---|
committer | Zeno Albisser <zeno.albisser@digia.com> | 2013-08-15 21:46:11 +0200 |
commit | 679147eead574d186ebf3069647b4c23e8ccace6 (patch) | |
tree | fc247a0ac8ff119f7c8550879ebb6d3dd8d1ff69 /chromium/net/dns/dns_socket_pool.cc | |
download | qtwebengine-chromium-679147eead574d186ebf3069647b4c23e8ccace6.tar.gz |
Initial import.
Diffstat (limited to 'chromium/net/dns/dns_socket_pool.cc')
-rw-r--r-- | chromium/net/dns/dns_socket_pool.cc | 234 |
1 files changed, 234 insertions, 0 deletions
diff --git a/chromium/net/dns/dns_socket_pool.cc b/chromium/net/dns/dns_socket_pool.cc new file mode 100644 index 00000000000..7a7ecd6ee8f --- /dev/null +++ b/chromium/net/dns/dns_socket_pool.cc @@ -0,0 +1,234 @@ +// 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/address_list.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/socket/stream_socket.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<StreamSocket> DnsSocketPool::CreateTCPSocket( + unsigned server_index, + const NetLog::Source& source) { + DCHECK_LT(server_index, nameservers_->size()); + + return scoped_ptr<StreamSocket>( + socket_factory_->CreateTransportClientSocket( + AddressList((*nameservers_)[server_index]), net_log_, source)); +} + +scoped_ptr<DatagramClientSocket> DnsSocketPool::CreateConnectedSocket( + unsigned server_index) { + DCHECK_LT(server_index, nameservers_->size()); + + scoped_ptr<DatagramClientSocket> socket; + + NetLog::Source no_source; + socket = 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>(); + } + + 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 |