Bitcoin Core 32.99.0
P2P Digital Currency
Loading...
Searching...
No Matches
sock.cpp
Go to the documentation of this file.
1// Copyright (c) 2020-present The Bitcoin Core developers
2// Distributed under the MIT software license, see the accompanying
3// file COPYING or http://www.opensource.org/licenses/mit-license.php.
4
5#include <util/sock.h>
6
7#include <compat/compat.h>
8#include <span.h>
9#include <tinyformat.h>
10#include <util/check.h>
11#include <util/log.h>
12#include <util/syserror.h>
13#include <util/threadinterrupt.h>
14#include <util/time.h>
15
16#include <algorithm>
17#include <compare>
18#include <exception>
19#include <memory>
20#include <stdexcept>
21#include <string>
22#include <utility>
23#include <vector>
24
25#ifdef USE_POLL
26#include <poll.h>
27#endif
28
29Sock::Sock(SOCKET s) : m_socket(s) {}
30
32{
33 m_socket = other.m_socket;
34 other.m_socket = INVALID_SOCKET;
35}
36
38
40{
41 Close();
42 m_socket = other.m_socket;
43 other.m_socket = INVALID_SOCKET;
44 return *this;
45}
46
47ssize_t Sock::Send(const void* data, size_t len, int flags) const
48{
49 return send(m_socket, static_cast<const char*>(data), len, flags);
50}
51
52ssize_t Sock::Recv(void* buf, size_t len, int flags) const
53{
54 return recv(m_socket, static_cast<char*>(buf), len, flags);
55}
56
58{
59 return connect(m_socket, addr, addr_len);
60}
61
62int Sock::Bind(const sockaddr* addr, socklen_t addr_len) const
63{
64 return bind(m_socket, addr, addr_len);
65}
66
67int Sock::Listen(int backlog) const
68{
69 return listen(m_socket, backlog);
70}
71
72std::unique_ptr<Sock> Sock::Accept(sockaddr* addr, socklen_t* addr_len) const
73{
74#ifdef WIN32
75 static constexpr auto accept_error = INVALID_SOCKET;
76#else
77 static constexpr auto accept_error = SOCKET_ERROR;
78#endif
79
80 std::unique_ptr<Sock> sock;
81
82 const auto socket = accept(m_socket, addr, addr_len);
83 if (socket != accept_error) {
84 try {
85 sock = std::make_unique<Sock>(socket);
86 } catch (const std::exception&) {
87#ifdef WIN32
89#else
90 close(socket);
91#endif
92 }
93 }
94
95 return sock;
96}
97
98int Sock::GetSockOpt(int level, int opt_name, void* opt_val, socklen_t* opt_len) const
99{
100 return getsockopt(m_socket, level, opt_name, static_cast<char*>(opt_val), opt_len);
101}
102
103int Sock::SetSockOpt(int level, int opt_name, const void* opt_val, socklen_t opt_len) const
104{
105 return setsockopt(m_socket, level, opt_name, static_cast<const char*>(opt_val), opt_len);
106}
107
112
114{
115#ifdef WIN32
116 u_long on{1};
118 return false;
119 }
120#else
121 const int flags{fcntl(m_socket, F_GETFL, 0)};
122 if (flags == SOCKET_ERROR) {
123 return false;
124 }
126 return false;
127 }
128#endif
129 return true;
130}
131
133{
134#if defined(USE_POLL) || defined(WIN32)
135 return true;
136#else
137 return m_socket < FD_SETSIZE;
138#endif
139}
140
141bool Sock::Wait(std::chrono::milliseconds timeout, Event requested, Event* occurred) const
142{
143 // We need a `shared_ptr` holding `this` for `WaitMany()`, but don't want
144 // `this` to be destroyed when the `shared_ptr` goes out of scope at the
145 // end of this function.
146 // Create it with an aliasing shared_ptr that points to `this` without
147 // owning it.
148 std::shared_ptr<const Sock> shared{std::shared_ptr<const Sock>{}, this};
149
150 EventsPerSock events_per_sock{std::make_pair(shared, Events{requested})};
151
152 if (!WaitMany(timeout, events_per_sock)) {
153 return false;
154 }
155
156 if (occurred != nullptr) {
157 *occurred = events_per_sock.begin()->second.occurred;
158 }
159
160 return true;
161}
162
163bool Sock::WaitMany(std::chrono::milliseconds timeout, EventsPerSock& events_per_sock) const
164{
165 timeout = std::min<std::chrono::milliseconds>(timeout, MAX_WAIT_TIMEOUT);
166
167#ifdef USE_POLL
168 std::vector<pollfd> pfds;
169 for (const auto& [sock, events] : events_per_sock) {
170 pfds.emplace_back();
171 auto& pfd = pfds.back();
172 pfd.fd = sock->m_socket;
173 if (events.requested & RecvEvent) {
174 pfd.events |= POLLIN;
175 }
176 if (events.requested & SendEvent) {
177 pfd.events |= POLLOUT;
178 }
179 }
180
181 if (poll(pfds.data(), pfds.size(), count_milliseconds(timeout)) == SOCKET_ERROR) {
182 return false;
183 }
184
185 assert(pfds.size() == events_per_sock.size());
186 size_t i{0};
187 for (auto& [sock, events] : events_per_sock) {
188 assert(sock->m_socket == static_cast<SOCKET>(pfds[i].fd));
189 events.occurred = 0;
190 if (pfds[i].revents & POLLIN) {
191 events.occurred |= RecvEvent;
192 }
193 if (pfds[i].revents & POLLOUT) {
194 events.occurred |= SendEvent;
195 }
196 if (pfds[i].revents & (POLLERR | POLLHUP)) {
197 events.occurred |= ErrorEvent;
198 }
199 ++i;
200 }
201
202 return true;
203#else
204 fd_set recv;
205 fd_set send;
206 fd_set err;
207 FD_ZERO(&recv);
208 FD_ZERO(&send);
209 FD_ZERO(&err);
211
212 for (const auto& [sock, events] : events_per_sock) {
213 if (!sock->IsSelectable()) {
214 return false;
215 }
216 const auto& s = sock->m_socket;
217 if (events.requested & RecvEvent) {
218 FD_SET(s, &recv);
219 FD_SET(s, &err);
220 }
221 if (events.requested & SendEvent) {
222 FD_SET(s, &send);
223 }
224 if (events.requested & (RecvEvent | SendEvent)) {
225 socket_max = std::max(socket_max, s);
226 }
227 }
228
229 timeval tv = MillisToTimeval(timeout);
230
231 if (select(socket_max + 1, &recv, &send, &err, &tv) == SOCKET_ERROR) {
232 return false;
233 }
234
235 for (auto& [sock, events] : events_per_sock) {
236 const auto& s = sock->m_socket;
237 events.occurred = 0;
238 if (FD_ISSET(s, &recv)) {
239 events.occurred |= RecvEvent;
240 }
241 if (FD_ISSET(s, &send)) {
242 events.occurred |= SendEvent;
243 }
244 if (FD_ISSET(s, &err)) {
245 events.occurred |= ErrorEvent;
246 }
247 }
248
249 return true;
250#endif /* USE_POLL */
251}
252
253void Sock::SendComplete(std::span<const unsigned char> data,
254 std::chrono::milliseconds timeout,
255 CThreadInterrupt& interrupt) const
256{
257 const auto deadline = GetTime<std::chrono::milliseconds>() + timeout;
258 size_t sent{0};
259
260 for (;;) {
261 const ssize_t ret{Send(data.data() + sent, data.size() - sent, MSG_NOSIGNAL)};
262
263 if (ret > 0) {
264 sent += static_cast<size_t>(ret);
265 if (sent == data.size()) {
266 break;
267 }
268 } else {
269 const int err{WSAGetLastError()};
270 if (IOErrorIsPermanent(err)) {
271 throw std::runtime_error(strprintf("send(): %s", NetworkErrorString(err)));
272 }
273 }
274
275 const auto now = GetTime<std::chrono::milliseconds>();
276
277 if (now >= deadline) {
278 throw std::runtime_error(strprintf(
279 "Send timeout (sent only %u of %u bytes before that)", sent, data.size()));
280 }
281
282 if (interrupt) {
283 throw std::runtime_error(strprintf(
284 "Send interrupted (sent only %u of %u bytes before that)", sent, data.size()));
285 }
286
287 // Wait for a short while (or the socket to become ready for sending) before retrying
288 // if nothing was sent.
289 const auto wait_time = std::min(deadline - now, std::chrono::milliseconds{MAX_WAIT_FOR_IO});
291 }
292}
293
294void Sock::SendComplete(std::span<const char> data,
295 std::chrono::milliseconds timeout,
296 CThreadInterrupt& interrupt) const
297{
298 SendComplete(MakeUCharSpan(data), timeout, interrupt);
299}
300
302 std::chrono::milliseconds timeout,
303 CThreadInterrupt& interrupt,
304 size_t max_data) const
305{
306 const auto deadline = GetTime<std::chrono::milliseconds>() + timeout;
307 std::string data;
308 bool terminator_found{false};
309
310 // We must not consume any bytes past the terminator from the socket.
311 // One option is to read one byte at a time and check if we have read a terminator.
312 // However that is very slow. Instead, we peek at what is in the socket and only read
313 // as many bytes as possible without crossing the terminator.
314 // Reading 64 MiB of random data with 262526 terminator chars takes 37 seconds to read
315 // one byte at a time VS 0.71 seconds with the "peek" solution below. Reading one byte
316 // at a time is about 50 times slower.
317
318 for (;;) {
319 if (data.size() >= max_data) {
320 throw std::runtime_error(
321 strprintf("Received too many bytes without a terminator (%u)", data.size()));
322 }
323
324 char buf[512];
325
326 const ssize_t peek_ret{Recv(buf, std::min(sizeof(buf), max_data - data.size()), MSG_PEEK)};
327
328 switch (peek_ret) {
329 case -1: {
330 const int err{WSAGetLastError()};
331 if (IOErrorIsPermanent(err)) {
332 throw std::runtime_error(strprintf("recv(): %s", NetworkErrorString(err)));
333 }
334 break;
335 }
336 case 0:
337 throw std::runtime_error("Connection unexpectedly closed by peer");
338 default:
339 auto end = buf + peek_ret;
340 auto terminator_pos = std::find(buf, end, terminator);
342
343 const size_t try_len{terminator_found ? terminator_pos - buf + 1 :
344 static_cast<size_t>(peek_ret)};
345
346 const ssize_t read_ret{Recv(buf, try_len, 0)};
347
348 if (read_ret < 0 || static_cast<size_t>(read_ret) != try_len) {
349 throw std::runtime_error(
350 strprintf("recv() returned %u bytes on attempt to read %u bytes but previous "
351 "peek claimed %u bytes are available",
353 }
354
355 // Don't include the terminator in the output.
356 const size_t append_len{terminator_found ? try_len - 1 : try_len};
357
358 data.append(buf, buf + append_len);
359
360 if (terminator_found) {
361 return data;
362 }
363 }
364
365 const auto now = GetTime<std::chrono::milliseconds>();
366
367 if (now >= deadline) {
368 throw std::runtime_error(strprintf(
369 "Receive timeout (received %u bytes without terminator before that)", data.size()));
370 }
371
372 if (interrupt) {
373 throw std::runtime_error(strprintf(
374 "Receive interrupted (received %u bytes without terminator before that)",
375 data.size()));
376 }
377
378 // Wait for a short while (or the socket to become ready for reading) before retrying.
379 const auto wait_time = std::min(deadline - now, std::chrono::milliseconds{MAX_WAIT_FOR_IO});
381 }
382}
383
384bool Sock::IsConnected(std::string& errmsg) const
385{
386 if (m_socket == INVALID_SOCKET) {
387 errmsg = "not connected";
388 return false;
389 }
390
391 char c;
392 switch (Recv(&c, sizeof(c), MSG_PEEK)) {
393 case -1: {
394 const int err = WSAGetLastError();
395 if (IOErrorIsPermanent(err)) {
397 return false;
398 }
399 return true;
400 }
401 case 0:
402 errmsg = "closed";
403 return false;
404 default:
405 return true;
406 }
407}
408
410{
411 if (m_socket == INVALID_SOCKET) {
412 return;
413 }
414#ifdef WIN32
415 int ret = closesocket(m_socket);
416#else
417 int ret = close(m_socket);
418#endif
419 if (ret) {
420 LogWarning("Error closing socket %d: %s", m_socket, NetworkErrorString(WSAGetLastError()));
421 }
423}
424
426{
427 return m_socket == s;
428};
429
430std::string NetworkErrorString(int err)
431{
432#if defined(WIN32)
433 return Win32ErrorString(err);
434#else
435 // On BSD sockets implementations, NetworkErrorString is the same as SysErrorString.
436 return SysErrorString(err);
437#endif
438}
int ret
int flags
A helper class for interruptible sleeps.
RAII helper class that manages a socket and closes it automatically when it goes out of scope.
Definition sock.h:35
static constexpr Event RecvEvent
If passed to Wait(), then it will wait for readiness to read from the socket.
Definition sock.h:151
virtual std::unique_ptr< Sock > Accept(sockaddr *addr, socklen_t *addr_len) const
accept(2) wrapper.
Definition sock.cpp:72
virtual ssize_t Send(const void *data, size_t len, int flags) const
send(2) wrapper.
Definition sock.cpp:47
SOCKET m_socket
Contained socket.
Definition sock.h:293
Sock & operator=(const Sock &)=delete
Copy assignment operator, disabled because closing the same socket twice is undesirable.
virtual int Bind(const sockaddr *addr, socklen_t addr_len) const
bind(2) wrapper.
Definition sock.cpp:62
virtual bool Wait(std::chrono::milliseconds timeout, Event requested, Event *occurred=nullptr) const
Wait for readiness for input (recv) or output (send).
Definition sock.cpp:141
virtual ~Sock()
Destructor, close the socket or do nothing if empty.
Definition sock.cpp:37
virtual void SendComplete(std::span< const unsigned char > data, std::chrono::milliseconds timeout, CThreadInterrupt &interrupt) const
Send the given data, retrying on transient errors.
Definition sock.cpp:253
uint8_t Event
Definition sock.h:146
static constexpr Event SendEvent
If passed to Wait(), then it will wait for readiness to send to the socket.
Definition sock.h:156
virtual int GetSockName(sockaddr *name, socklen_t *name_len) const
getsockname(2) wrapper.
Definition sock.cpp:108
void Close()
Close m_socket if it is not INVALID_SOCKET.
Definition sock.cpp:409
virtual bool WaitMany(std::chrono::milliseconds timeout, EventsPerSock &events_per_sock) const
Same as Wait(), but wait on many sockets within the same timeout.
Definition sock.cpp:163
virtual bool IsConnected(std::string &errmsg) const
Check if still connected.
Definition sock.cpp:384
virtual int SetSockOpt(int level, int opt_name, const void *opt_val, socklen_t opt_len) const
setsockopt(2) wrapper.
Definition sock.cpp:103
static constexpr Event ErrorEvent
Ignored if passed to Wait(), but could be set in the occurred events if an exceptional condition has ...
Definition sock.h:162
virtual int GetSockOpt(int level, int opt_name, void *opt_val, socklen_t *opt_len) const
getsockopt(2) wrapper.
Definition sock.cpp:98
virtual int Connect(const sockaddr *addr, socklen_t addr_len) const
connect(2) wrapper.
Definition sock.cpp:57
virtual ssize_t Recv(void *buf, size_t len, int flags) const
recv(2) wrapper.
Definition sock.cpp:52
Sock()=delete
virtual std::string RecvUntilTerminator(uint8_t terminator, std::chrono::milliseconds timeout, CThreadInterrupt &interrupt, size_t max_data) const
Read from socket until a terminator character is encountered.
Definition sock.cpp:301
virtual int Listen(int backlog) const
listen(2) wrapper.
Definition sock.cpp:67
virtual bool SetNonBlocking() const
Set the non-blocking option on the socket.
Definition sock.cpp:113
std::unordered_map< std::shared_ptr< const Sock >, Events, HashSharedPtrSock, EqualSharedPtrSock > EventsPerSock
On which socket to wait for what events in WaitMany().
Definition sock.h:225
virtual bool IsSelectable() const
Check if the underlying socket can be used for select(2) (or the Wait() method).
Definition sock.cpp:132
bool operator==(SOCKET s) const
Check if the internal socket is equal to s.
Definition sock.cpp:425
static constexpr std::chrono::seconds MAX_WAIT_TIMEOUT
Maximum timeout supported by Wait() and WaitMany() (about 24.8 days).
Definition sock.h:170
static const PrecomputedData data
Precomputed COutPoint and CCoins values.
#define INVALID_SOCKET
Definition compat.h:67
#define SOCKET_ERROR
Definition compat.h:68
#define WSAGetLastError()
Definition compat.h:59
#define MSG_NOSIGNAL
Definition compat.h:110
unsigned int SOCKET
Definition compat.h:57
#define LogWarning(...)
Definition log.h:137
const char * name
Definition rest.cpp:71
std::string NetworkErrorString(int err)
Return readable error string for a network error code.
Definition sock.cpp:430
constexpr auto MAX_WAIT_FOR_IO
Maximum time to wait for I/O readiness.
Definition sock.h:24
bool IOErrorIsPermanent(int err)
Definition sock.h:26
std::string NetworkErrorString(int err)
Return readable error string for a network error code.
Definition sock.cpp:430
constexpr auto MakeUCharSpan(const V &v) -> decltype(UCharSpanCast(std::span{v}))
Like the std::span constructor, but for (const) unsigned char member types only.
Definition span.h:111
Auxiliary requested/occurred events to wait for in WaitMany().
Definition sock.h:190
std::string SysErrorString(int err)
Return system error string from errno value.
Definition syserror.cpp:18
#define strprintf
Format arguments and return the string or write to given std::ostream (see tinyformat::format doc for...
struct timeval MillisToTimeval(int64_t nTimeout)
Convert milliseconds to a struct timeval for e.g.
Definition time.cpp:149
constexpr int64_t count_milliseconds(std::chrono::milliseconds t)
Definition time.h:98
constexpr auto Ticks(Dur2 d)
Helper to count the seconds of a duration/time_point.
Definition time.h:82
assert(!tx.IsCoinBase())