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