mirror of
https://github.com/klzgrad/naiveproxy.git
synced 2024-12-01 01:36:09 +03:00
223 lines
6.8 KiB
C++
223 lines
6.8 KiB
C++
// 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/macros.h"
|
|
#include "base/rand_util.h"
|
|
#include "net/base/address_list.h"
|
|
#include "net/base/ip_endpoint.h"
|
|
#include "net/base/net_errors.h"
|
|
#include "net/log/net_log_source.h"
|
|
#include "net/socket/client_socket_factory.h"
|
|
#include "net/socket/datagram_client_socket.h"
|
|
#include "net/socket/stream_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. Freed sockets are not retained.
|
|
|
|
// 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;
|
|
#else
|
|
const DatagramSocket::BindType kBindType = DatagramSocket::RANDOM_BIND;
|
|
const unsigned kInitialPoolSize = 0;
|
|
const unsigned kAllocateMinSize = 1;
|
|
#endif
|
|
|
|
} // namespace
|
|
|
|
DnsSocketPool::DnsSocketPool(ClientSocketFactory* socket_factory,
|
|
const RandIntCallback& rand_int_callback)
|
|
: socket_factory_(socket_factory),
|
|
rand_int_callback_(rand_int_callback),
|
|
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;
|
|
}
|
|
|
|
std::unique_ptr<StreamSocket> DnsSocketPool::CreateTCPSocket(
|
|
unsigned server_index,
|
|
const NetLogSource& source) {
|
|
DCHECK_LT(server_index, nameservers_->size());
|
|
|
|
return std::unique_ptr<StreamSocket>(
|
|
socket_factory_->CreateTransportClientSocket(
|
|
AddressList((*nameservers_)[server_index]), NULL, net_log_, source));
|
|
}
|
|
|
|
std::unique_ptr<DatagramClientSocket> DnsSocketPool::CreateConnectedSocket(
|
|
unsigned server_index) {
|
|
DCHECK_LT(server_index, nameservers_->size());
|
|
|
|
std::unique_ptr<DatagramClientSocket> socket;
|
|
|
|
NetLogSource no_source;
|
|
socket = socket_factory_->CreateDatagramClientSocket(kBindType, net_log_,
|
|
no_source);
|
|
|
|
if (socket.get()) {
|
|
int rv = socket->Connect((*nameservers_)[server_index]);
|
|
if (rv != OK) {
|
|
DVLOG(1) << "Failed to connect socket: " << rv;
|
|
socket.reset();
|
|
}
|
|
} else {
|
|
DVLOG(1) << "Failed to create socket.";
|
|
}
|
|
|
|
return socket;
|
|
}
|
|
|
|
int DnsSocketPool::GetRandomInt(int min, int max) {
|
|
return rand_int_callback_.Run(min, max);
|
|
}
|
|
|
|
class NullDnsSocketPool : public DnsSocketPool {
|
|
public:
|
|
NullDnsSocketPool(ClientSocketFactory* factory,
|
|
const RandIntCallback& rand_int_callback)
|
|
: DnsSocketPool(factory, rand_int_callback) {}
|
|
|
|
void Initialize(const std::vector<IPEndPoint>* nameservers,
|
|
NetLog* net_log) override {
|
|
InitializeInternal(nameservers, net_log);
|
|
}
|
|
|
|
std::unique_ptr<DatagramClientSocket> AllocateSocket(
|
|
unsigned server_index) override {
|
|
return CreateConnectedSocket(server_index);
|
|
}
|
|
|
|
void FreeSocket(unsigned server_index,
|
|
std::unique_ptr<DatagramClientSocket> socket) override {}
|
|
|
|
private:
|
|
DISALLOW_COPY_AND_ASSIGN(NullDnsSocketPool);
|
|
};
|
|
|
|
// static
|
|
std::unique_ptr<DnsSocketPool> DnsSocketPool::CreateNull(
|
|
ClientSocketFactory* factory,
|
|
const RandIntCallback& rand_int_callback) {
|
|
return std::unique_ptr<DnsSocketPool>(
|
|
new NullDnsSocketPool(factory, rand_int_callback));
|
|
}
|
|
|
|
class DefaultDnsSocketPool : public DnsSocketPool {
|
|
public:
|
|
DefaultDnsSocketPool(ClientSocketFactory* factory,
|
|
const RandIntCallback& rand_int_callback)
|
|
: DnsSocketPool(factory, rand_int_callback){};
|
|
|
|
~DefaultDnsSocketPool() override;
|
|
|
|
void Initialize(const std::vector<IPEndPoint>* nameservers,
|
|
NetLog* net_log) override;
|
|
|
|
std::unique_ptr<DatagramClientSocket> AllocateSocket(
|
|
unsigned server_index) override;
|
|
|
|
void FreeSocket(unsigned server_index,
|
|
std::unique_ptr<DatagramClientSocket> socket) override;
|
|
|
|
private:
|
|
void FillPool(unsigned server_index, unsigned size);
|
|
|
|
typedef std::vector<std::unique_ptr<DatagramClientSocket>> SocketVector;
|
|
|
|
std::vector<SocketVector> pools_;
|
|
|
|
DISALLOW_COPY_AND_ASSIGN(DefaultDnsSocketPool);
|
|
};
|
|
|
|
DnsSocketPool::~DnsSocketPool() = default;
|
|
|
|
// static
|
|
std::unique_ptr<DnsSocketPool> DnsSocketPool::CreateDefault(
|
|
ClientSocketFactory* factory,
|
|
const RandIntCallback& rand_int_callback) {
|
|
return std::unique_ptr<DnsSocketPool>(
|
|
new DefaultDnsSocketPool(factory, rand_int_callback));
|
|
}
|
|
|
|
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() = default;
|
|
|
|
std::unique_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) {
|
|
DVLOG(1) << "No DNS sockets available in pool " << server_index << "!";
|
|
return std::unique_ptr<DatagramClientSocket>();
|
|
}
|
|
|
|
if (pool.size() < kAllocateMinSize) {
|
|
DVLOG(1) << "Low DNS port entropy: wanted " << kAllocateMinSize
|
|
<< " sockets to choose from, but only have " << pool.size()
|
|
<< " in pool " << server_index << ".";
|
|
}
|
|
|
|
unsigned socket_index = GetRandomInt(0, pool.size() - 1);
|
|
std::unique_ptr<DatagramClientSocket> socket = std::move(pool[socket_index]);
|
|
pool[socket_index] = std::move(pool.back());
|
|
pool.pop_back();
|
|
|
|
return socket;
|
|
}
|
|
|
|
void DefaultDnsSocketPool::FreeSocket(
|
|
unsigned server_index,
|
|
std::unique_ptr<DatagramClientSocket> socket) {
|
|
DCHECK_LT(server_index, pools_.size());
|
|
}
|
|
|
|
void DefaultDnsSocketPool::FillPool(unsigned server_index, unsigned size) {
|
|
SocketVector& pool = pools_[server_index];
|
|
|
|
for (unsigned pool_index = pool.size(); pool_index < size; ++pool_index) {
|
|
std::unique_ptr<DatagramClientSocket> socket =
|
|
CreateConnectedSocket(server_index);
|
|
if (!socket)
|
|
break;
|
|
pool.push_back(std::move(socket));
|
|
}
|
|
}
|
|
|
|
} // namespace net
|