Bitcoin Core  22.99.0
P2P Digital Currency
sock.cpp
Go to the documentation of this file.
1 // Copyright (c) 2020-2021 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 <compat.h>
6 #include <logging.h>
7 #include <threadinterrupt.h>
8 #include <tinyformat.h>
9 #include <util/sock.h>
10 #include <util/system.h>
11 #include <util/time.h>
12 
13 #include <memory>
14 #include <stdexcept>
15 #include <string>
16 
17 #ifdef WIN32
18 #include <codecvt>
19 #include <locale>
20 #endif
21 
22 #ifdef USE_POLL
23 #include <poll.h>
24 #endif
25 
26 static inline bool IOErrorIsPermanent(int err)
27 {
28  return err != WSAEAGAIN && err != WSAEINTR && err != WSAEWOULDBLOCK && err != WSAEINPROGRESS;
29 }
30 
31 Sock::Sock() : m_socket(INVALID_SOCKET) {}
32 
33 Sock::Sock(SOCKET s) : m_socket(s) {}
34 
35 Sock::Sock(Sock&& other)
36 {
37  m_socket = other.m_socket;
38  other.m_socket = INVALID_SOCKET;
39 }
40 
42 
44 {
45  Reset();
46  m_socket = other.m_socket;
47  other.m_socket = INVALID_SOCKET;
48  return *this;
49 }
50 
51 SOCKET Sock::Get() const { return m_socket; }
52 
54 {
55  const SOCKET s = m_socket;
57  return s;
58 }
59 
61 
62 ssize_t Sock::Send(const void* data, size_t len, int flags) const
63 {
64  return send(m_socket, static_cast<const char*>(data), len, flags);
65 }
66 
67 ssize_t Sock::Recv(void* buf, size_t len, int flags) const
68 {
69  return recv(m_socket, static_cast<char*>(buf), len, flags);
70 }
71 
72 int Sock::Connect(const sockaddr* addr, socklen_t addr_len) const
73 {
74  return connect(m_socket, addr, addr_len);
75 }
76 
77 std::unique_ptr<Sock> Sock::Accept(sockaddr* addr, socklen_t* addr_len) const
78 {
79 #ifdef WIN32
80  static constexpr auto ERR = INVALID_SOCKET;
81 #else
82  static constexpr auto ERR = SOCKET_ERROR;
83 #endif
84 
85  std::unique_ptr<Sock> sock;
86 
87  const auto socket = accept(m_socket, addr, addr_len);
88  if (socket != ERR) {
89  try {
90  sock = std::make_unique<Sock>(socket);
91  } catch (const std::exception&) {
92 #ifdef WIN32
93  closesocket(socket);
94 #else
95  close(socket);
96 #endif
97  }
98  }
99 
100  return sock;
101 }
102 
103 int Sock::GetSockOpt(int level, int opt_name, void* opt_val, socklen_t* opt_len) const
104 {
105  return getsockopt(m_socket, level, opt_name, static_cast<char*>(opt_val), opt_len);
106 }
107 
108 bool Sock::Wait(std::chrono::milliseconds timeout, Event requested, Event* occurred) const
109 {
110 #ifdef USE_POLL
111  pollfd fd;
112  fd.fd = m_socket;
113  fd.events = 0;
114  if (requested & RECV) {
115  fd.events |= POLLIN;
116  }
117  if (requested & SEND) {
118  fd.events |= POLLOUT;
119  }
120 
121  if (poll(&fd, 1, count_milliseconds(timeout)) == SOCKET_ERROR) {
122  return false;
123  }
124 
125  if (occurred != nullptr) {
126  *occurred = 0;
127  if (fd.revents & POLLIN) {
128  *occurred |= RECV;
129  }
130  if (fd.revents & POLLOUT) {
131  *occurred |= SEND;
132  }
133  }
134 
135  return true;
136 #else
138  return false;
139  }
140 
141  fd_set fdset_recv;
142  fd_set fdset_send;
143  FD_ZERO(&fdset_recv);
144  FD_ZERO(&fdset_send);
145 
146  if (requested & RECV) {
147  FD_SET(m_socket, &fdset_recv);
148  }
149 
150  if (requested & SEND) {
151  FD_SET(m_socket, &fdset_send);
152  }
153 
154  timeval timeout_struct = MillisToTimeval(timeout);
155 
156  if (select(m_socket + 1, &fdset_recv, &fdset_send, nullptr, &timeout_struct) == SOCKET_ERROR) {
157  return false;
158  }
159 
160  if (occurred != nullptr) {
161  *occurred = 0;
162  if (FD_ISSET(m_socket, &fdset_recv)) {
163  *occurred |= RECV;
164  }
165  if (FD_ISSET(m_socket, &fdset_send)) {
166  *occurred |= SEND;
167  }
168  }
169 
170  return true;
171 #endif /* USE_POLL */
172 }
173 
174 void Sock::SendComplete(const std::string& data,
175  std::chrono::milliseconds timeout,
176  CThreadInterrupt& interrupt) const
177 {
178  const auto deadline = GetTime<std::chrono::milliseconds>() + timeout;
179  size_t sent{0};
180 
181  for (;;) {
182  const ssize_t ret{Send(data.data() + sent, data.size() - sent, MSG_NOSIGNAL)};
183 
184  if (ret > 0) {
185  sent += static_cast<size_t>(ret);
186  if (sent == data.size()) {
187  break;
188  }
189  } else {
190  const int err{WSAGetLastError()};
191  if (IOErrorIsPermanent(err)) {
192  throw std::runtime_error(strprintf("send(): %s", NetworkErrorString(err)));
193  }
194  }
195 
196  const auto now = GetTime<std::chrono::milliseconds>();
197 
198  if (now >= deadline) {
199  throw std::runtime_error(strprintf(
200  "Send timeout (sent only %u of %u bytes before that)", sent, data.size()));
201  }
202 
203  if (interrupt) {
204  throw std::runtime_error(strprintf(
205  "Send interrupted (sent only %u of %u bytes before that)", sent, data.size()));
206  }
207 
208  // Wait for a short while (or the socket to become ready for sending) before retrying
209  // if nothing was sent.
210  const auto wait_time = std::min(deadline - now, std::chrono::milliseconds{MAX_WAIT_FOR_IO});
211  (void)Wait(wait_time, SEND);
212  }
213 }
214 
215 std::string Sock::RecvUntilTerminator(uint8_t terminator,
216  std::chrono::milliseconds timeout,
217  CThreadInterrupt& interrupt,
218  size_t max_data) const
219 {
220  const auto deadline = GetTime<std::chrono::milliseconds>() + timeout;
221  std::string data;
222  bool terminator_found{false};
223 
224  // We must not consume any bytes past the terminator from the socket.
225  // One option is to read one byte at a time and check if we have read a terminator.
226  // However that is very slow. Instead, we peek at what is in the socket and only read
227  // as many bytes as possible without crossing the terminator.
228  // Reading 64 MiB of random data with 262526 terminator chars takes 37 seconds to read
229  // one byte at a time VS 0.71 seconds with the "peek" solution below. Reading one byte
230  // at a time is about 50 times slower.
231 
232  for (;;) {
233  if (data.size() >= max_data) {
234  throw std::runtime_error(
235  strprintf("Received too many bytes without a terminator (%u)", data.size()));
236  }
237 
238  char buf[512];
239 
240  const ssize_t peek_ret{Recv(buf, std::min(sizeof(buf), max_data - data.size()), MSG_PEEK)};
241 
242  switch (peek_ret) {
243  case -1: {
244  const int err{WSAGetLastError()};
245  if (IOErrorIsPermanent(err)) {
246  throw std::runtime_error(strprintf("recv(): %s", NetworkErrorString(err)));
247  }
248  break;
249  }
250  case 0:
251  throw std::runtime_error("Connection unexpectedly closed by peer");
252  default:
253  auto end = buf + peek_ret;
254  auto terminator_pos = std::find(buf, end, terminator);
255  terminator_found = terminator_pos != end;
256 
257  const size_t try_len{terminator_found ? terminator_pos - buf + 1 :
258  static_cast<size_t>(peek_ret)};
259 
260  const ssize_t read_ret{Recv(buf, try_len, 0)};
261 
262  if (read_ret < 0 || static_cast<size_t>(read_ret) != try_len) {
263  throw std::runtime_error(
264  strprintf("recv() returned %u bytes on attempt to read %u bytes but previous "
265  "peek claimed %u bytes are available",
266  read_ret, try_len, peek_ret));
267  }
268 
269  // Don't include the terminator in the output.
270  const size_t append_len{terminator_found ? try_len - 1 : try_len};
271 
272  data.append(buf, buf + append_len);
273 
274  if (terminator_found) {
275  return data;
276  }
277  }
278 
279  const auto now = GetTime<std::chrono::milliseconds>();
280 
281  if (now >= deadline) {
282  throw std::runtime_error(strprintf(
283  "Receive timeout (received %u bytes without terminator before that)", data.size()));
284  }
285 
286  if (interrupt) {
287  throw std::runtime_error(strprintf(
288  "Receive interrupted (received %u bytes without terminator before that)",
289  data.size()));
290  }
291 
292  // Wait for a short while (or the socket to become ready for reading) before retrying.
293  const auto wait_time = std::min(deadline - now, std::chrono::milliseconds{MAX_WAIT_FOR_IO});
294  (void)Wait(wait_time, RECV);
295  }
296 }
297 
298 bool Sock::IsConnected(std::string& errmsg) const
299 {
300  if (m_socket == INVALID_SOCKET) {
301  errmsg = "not connected";
302  return false;
303  }
304 
305  char c;
306  switch (Recv(&c, sizeof(c), MSG_PEEK)) {
307  case -1: {
308  const int err = WSAGetLastError();
309  if (IOErrorIsPermanent(err)) {
310  errmsg = NetworkErrorString(err);
311  return false;
312  }
313  return true;
314  }
315  case 0:
316  errmsg = "closed";
317  return false;
318  default:
319  return true;
320  }
321 }
322 
323 #ifdef WIN32
324 std::string NetworkErrorString(int err)
325 {
326  wchar_t buf[256];
327  buf[0] = 0;
328  if(FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_MAX_WIDTH_MASK,
329  nullptr, err, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
330  buf, ARRAYSIZE(buf), nullptr))
331  {
332  return strprintf("%s (%d)", std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>,wchar_t>().to_bytes(buf), err);
333  }
334  else
335  {
336  return strprintf("Unknown error (%d)", err);
337  }
338 }
339 #else
340 std::string NetworkErrorString(int err)
341 {
342  char buf[256];
343  buf[0] = 0;
344  /* Too bad there are two incompatible implementations of the
345  * thread-safe strerror. */
346  const char *s;
347 #ifdef STRERROR_R_CHAR_P /* GNU variant can return a pointer outside the passed buffer */
348  s = strerror_r(err, buf, sizeof(buf));
349 #else /* POSIX variant always returns message in buffer */
350  s = buf;
351  if (strerror_r(err, buf, sizeof(buf)))
352  buf[0] = 0;
353 #endif
354  return strprintf("%s (%d)", s, err);
355 }
356 #endif
357 
358 bool CloseSocket(SOCKET& hSocket)
359 {
360  if (hSocket == INVALID_SOCKET)
361  return false;
362 #ifdef WIN32
363  int ret = closesocket(hSocket);
364 #else
365  int ret = close(hSocket);
366 #endif
367  if (ret) {
368  LogPrintf("Socket close failed: %d. Error: %s\n", hSocket, NetworkErrorString(WSAGetLastError()));
369  }
370  hSocket = INVALID_SOCKET;
371  return ret != SOCKET_ERROR;
372 }
threadinterrupt.h
Sock::m_socket
SOCKET m_socket
Contained socket.
Definition: sock.h:185
Sock::operator=
Sock & operator=(const Sock &)=delete
Copy assignment operator, disabled because closing the same socket twice is undesirable.
Sock::Connect
virtual int Connect(const sockaddr *addr, socklen_t addr_len) const
connect(2) wrapper.
Definition: sock.cpp:72
flags
int flags
Definition: bitcoin-tx.cpp:525
WSAEINPROGRESS
#define WSAEINPROGRESS
Definition: compat.h:50
Sock::SendComplete
virtual void SendComplete(const std::string &data, std::chrono::milliseconds timeout, CThreadInterrupt &interrupt) const
Send the given data, retrying on transient errors.
Definition: sock.cpp:174
WSAGetLastError
#define WSAGetLastError()
Definition: compat.h:43
Sock::Reset
virtual void Reset()
Close if non-empty.
Definition: sock.cpp:60
tinyformat.h
CloseSocket
bool CloseSocket(SOCKET &hSocket)
Close socket and set hSocket to INVALID_SOCKET.
Definition: sock.cpp:358
Sock
RAII helper class that manages a socket.
Definition: sock.h:26
Sock::RecvUntilTerminator
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:215
INVALID_SOCKET
#define INVALID_SOCKET
Definition: compat.h:53
IsSelectableSocket
static bool IsSelectableSocket(const SOCKET &s)
Definition: compat.h:100
compat.h
Sock::Recv
virtual ssize_t Recv(void *buf, size_t len, int flags) const
recv(2) wrapper.
Definition: sock.cpp:67
Sock::Wait
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:108
Sock::Accept
virtual std::unique_ptr< Sock > Accept(sockaddr *addr, socklen_t *addr_len) const
accept(2) wrapper.
Definition: sock.cpp:77
Sock::SEND
static constexpr Event SEND
If passed to Wait(), then it will wait for readiness to send to the socket.
Definition: sock.h:128
time.h
LogPrintf
#define LogPrintf(...)
Definition: logging.h:187
Sock::GetSockOpt
virtual int GetSockOpt(int level, int opt_name, void *opt_val, socklen_t *opt_len) const
getsockopt(2) wrapper.
Definition: sock.cpp:103
NetworkErrorString
std::string NetworkErrorString(int err)
Return readable error string for a network error code.
Definition: sock.cpp:340
Sock::Send
virtual ssize_t Send(const void *data, size_t len, int flags) const
send(2) wrapper.
Definition: sock.cpp:62
SOCKET_ERROR
#define SOCKET_ERROR
Definition: compat.h:54
WSAEWOULDBLOCK
#define WSAEWOULDBLOCK
Definition: compat.h:46
system.h
Sock::Sock
Sock()
Default constructor, creates an empty object that does nothing when destroyed.
Definition: sock.cpp:31
strprintf
#define strprintf
Format arguments and return the string or write to given std::ostream (see tinyformat::format doc for...
Definition: tinyformat.h:1164
Sock::Get
virtual SOCKET Get() const
Get the value of the contained socket.
Definition: sock.cpp:51
Sock::IsConnected
virtual bool IsConnected(std::string &errmsg) const
Check if still connected.
Definition: sock.cpp:298
Sock::Event
uint8_t Event
Definition: sock.h:118
MSG_NOSIGNAL
#define MSG_NOSIGNAL
Definition: compat.h:110
MillisToTimeval
struct timeval MillisToTimeval(int64_t nTimeout)
Convert milliseconds to a struct timeval for e.g.
Definition: time.cpp:172
count_milliseconds
constexpr int64_t count_milliseconds(std::chrono::milliseconds t)
Definition: time.h:30
WSAEINTR
#define WSAEINTR
Definition: compat.h:49
MAX_WAIT_FOR_IO
static constexpr auto MAX_WAIT_FOR_IO
Maximum time to wait for I/O readiness.
Definition: sock.h:20
Sock::Release
virtual SOCKET Release()
Get the value of the contained socket and drop ownership.
Definition: sock.cpp:53
wallet::send
RPCHelpMan send()
Definition: spend.cpp:964
Sock::RECV
static constexpr Event RECV
If passed to Wait(), then it will wait for readiness to read from the socket.
Definition: sock.h:123
IOErrorIsPermanent
static bool IOErrorIsPermanent(int err)
Definition: sock.cpp:26
Sock::~Sock
virtual ~Sock()
Destructor, close the socket or do nothing if empty.
Definition: sock.cpp:41
CThreadInterrupt
Definition: threadinterrupt.h:19
sock.h
WSAEAGAIN
#define WSAEAGAIN
Definition: compat.h:47
SOCKET
unsigned int SOCKET
Definition: compat.h:41