fuzz coverage

Coverage Report

Created: 2026-04-24 13:48

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/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
}