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