Coverage Report

Created: 2026-10-07 13:27

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