1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
|
// 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 size_t kInitialPoolSize = 256;
const size_t kAllocateMinSize = 256;
#else
const DatagramSocket::BindType kBindType = DatagramSocket::RANDOM_BIND;
const size_t kInitialPoolSize = 0;
const size_t 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_(nullptr),
nameservers_(nullptr),
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(
size_t server_index,
const NetLogSource& source) {
DCHECK_LT(server_index, nameservers_->size());
return std::unique_ptr<StreamSocket>(
socket_factory_->CreateTransportClientSocket(
AddressList((*nameservers_)[server_index]), nullptr, net_log_,
source));
}
std::unique_ptr<DatagramClientSocket> DnsSocketPool::CreateConnectedSocket(
size_t 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(
size_t server_index) override {
return CreateConnectedSocket(server_index);
}
void FreeSocket(size_t 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(
size_t server_index) override;
void FreeSocket(size_t server_index,
std::unique_ptr<DatagramClientSocket> socket) override;
private:
void FillPool(size_t server_index, size_t 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 size_t num_servers = nameservers->size();
pools_.resize(num_servers);
for (size_t server_index = 0; server_index < num_servers; ++server_index)
FillPool(server_index, kInitialPoolSize);
}
DefaultDnsSocketPool::~DefaultDnsSocketPool() = default;
std::unique_ptr<DatagramClientSocket> DefaultDnsSocketPool::AllocateSocket(
size_t 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 << ".";
}
size_t 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(
size_t server_index,
std::unique_ptr<DatagramClientSocket> socket) {
DCHECK_LT(server_index, pools_.size());
}
void DefaultDnsSocketPool::FillPool(size_t server_index, size_t size) {
SocketVector& pool = pools_[server_index];
for (size_t 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
|