Coverage Report

Created: 2026-09-01 13:33

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/root/bitcoin/src/test/util/net.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 <test/util/net.h>
6
7
#include <net.h>
8
#include <net_processing.h>
9
#include <netaddress.h>
10
#include <netmessagemaker.h>
11
#include <node/connection_types.h>
12
#include <node/eviction.h>
13
#include <protocol.h>
14
#include <random.h>
15
#include <serialize.h>
16
#include <span.h>
17
#include <sync.h>
18
19
#include <chrono>
20
#include <optional>
21
#include <vector>
22
23
void ConnmanTestMsg::Handshake(CNode& node,
24
                               bool successfully_connected,
25
                               ServiceFlags remote_services,
26
                               ServiceFlags local_services,
27
                               int32_t version,
28
                               bool relay_txs)
29
20.5k
{
30
20.5k
    auto& peerman{static_cast<PeerManager&>(*m_msgproc)};
31
20.5k
    auto& connman{*this};
32
33
20.5k
    peerman.InitializeNode(node, local_services);
34
20.5k
    peerman.SendMessages(node);
35
20.5k
    FlushSendBuffer(node); // Drop the version message added by SendMessages.
36
37
20.5k
    CSerializedNetMsg msg_version{
38
20.5k
        NetMsg::Make(NetMsgType::VERSION,
39
20.5k
                version,                                        //
40
20.5k
                Using<CustomUintFormatter<8>>(remote_services), //
41
20.5k
                int64_t{},                                      // dummy time
42
20.5k
                int64_t{},                                      // ignored service bits
43
20.5k
                CNetAddr::V1(CService{}),                       // dummy
44
20.5k
                int64_t{},                                      // ignored service bits
45
20.5k
                CNetAddr::V1(CService{}),                       // ignored
46
20.5k
                uint64_t{1},                                    // dummy nonce
47
20.5k
                std::string{},                                  // dummy subver
48
20.5k
                int32_t{},                                      // dummy starting_height
49
20.5k
                relay_txs),
50
20.5k
    };
51
52
20.5k
    (void)connman.ReceiveMsgFrom(node, std::move(msg_version));
53
20.5k
    node.fPauseSend = false;
54
20.5k
    connman.ProcessMessagesOnce(node);
55
20.5k
    peerman.SendMessages(node);
56
20.5k
    FlushSendBuffer(node); // Drop the verack message added by SendMessages.
57
20.5k
    if (node.fDisconnect) return;
  Branch (57:9): [True: 4.79k, False: 15.7k]
58
20.5k
    assert(node.nVersion == version);
  Branch (58:5): [True: 15.7k, False: 0]
59
15.7k
    assert(node.GetCommonVersion() == std::min(version, node.AdvertisedVersion()));
  Branch (59:5): [True: 15.7k, False: 0]
60
15.7k
    CNodeStateStats statestats;
61
15.7k
    assert(peerman.GetNodeStateStats(node.GetId(), statestats));
  Branch (61:5): [True: 15.7k, False: 0]
62
15.7k
    assert(statestats.m_relay_txs == (relay_txs && !node.IsBlockOnlyConn()));
  Branch (62:5): [True: 12.6k, False: 3.12k]
  Branch (62:5): [True: 11.8k, False: 786]
  Branch (62:5): [True: 15.7k, False: 0]
63
15.7k
    assert(statestats.their_services == remote_services);
  Branch (63:5): [True: 15.7k, False: 0]
64
15.7k
    if (successfully_connected) {
  Branch (64:9): [True: 13.3k, False: 2.39k]
65
13.3k
        CSerializedNetMsg msg_verack{NetMsg::Make(NetMsgType::VERACK)};
66
13.3k
        (void)connman.ReceiveMsgFrom(node, std::move(msg_verack));
67
13.3k
        node.fPauseSend = false;
68
13.3k
        connman.ProcessMessagesOnce(node);
69
13.3k
        peerman.SendMessages(node);
70
13.3k
        assert(node.fSuccessfullyConnected == true);
  Branch (70:9): [True: 13.3k, False: 0]
71
13.3k
    }
72
15.7k
}
73
74
9.33k
void ConnmanTestMsg::ResetAddrCache() { m_addr_response_caches = {}; }
75
76
void ConnmanTestMsg::ResetMaxOutboundCycle()
77
9.33k
{
78
9.33k
    LOCK(m_total_bytes_sent_mutex);
79
9.33k
    nMaxOutboundCycleStartTime = 0s;
80
9.33k
    nMaxOutboundTotalBytesSentInCycle = 0;
81
9.33k
}
82
83
void ConnmanTestMsg::Reset()
84
9.33k
{
85
9.33k
    ResetAddrCache();
86
9.33k
    ResetMaxOutboundCycle();
87
9.33k
    m_private_broadcast.m_outbound_tor_ok_at_least_once.store(false);
88
9.33k
    m_private_broadcast.m_num_to_open.store(0);
89
9.33k
}
90
91
void ConnmanTestMsg::NodeReceiveMsgBytes(CNode& node, std::span<const uint8_t> msg_bytes, bool& complete) const
92
949k
{
93
949k
    assert(node.ReceiveMsgBytes(msg_bytes, complete));
  Branch (93:5): [True: 949k, False: 0]
94
949k
    if (complete) {
  Branch (94:9): [True: 472k, False: 477k]
95
472k
        node.MarkReceivedMsgsForProcessing();
96
472k
    }
97
949k
}
98
99
void ConnmanTestMsg::FlushSendBuffer(CNode& node) const
100
493k
{
101
493k
    LOCK(node.cs_vSend);
102
493k
    node.vSendMsg.clear();
103
493k
    node.m_send_memusage = 0;
104
542k
    while (true) {
  Branch (104:12): [Folded - Ignored]
105
542k
        const auto& [to_send, _more, _msg_type] = node.m_transport->GetBytesToSend(false);
106
542k
        if (to_send.empty()) break;
  Branch (106:13): [True: 493k, False: 49.2k]
107
49.2k
        node.m_transport->MarkBytesSent(to_send.size());
108
49.2k
    }
109
493k
}
110
111
bool ConnmanTestMsg::ReceiveMsgFrom(CNode& node, CSerializedNetMsg&& ser_msg) const
112
486k
{
113
486k
    bool queued = node.m_transport->SetMessageToSend(ser_msg);
114
486k
    assert(queued);
  Branch (114:5): [True: 486k, False: 0]
115
486k
    bool complete{false};
116
1.43M
    while (true) {
  Branch (116:12): [Folded - Ignored]
117
1.43M
        const auto& [to_send, _more, _msg_type] = node.m_transport->GetBytesToSend(false);
118
1.43M
        if (to_send.empty()) break;
  Branch (118:13): [True: 486k, False: 949k]
119
949k
        NodeReceiveMsgBytes(node, to_send, complete);
120
949k
        node.m_transport->MarkBytesSent(to_send.size());
121
949k
    }
122
486k
    return complete;
123
486k
}
124
125
CNode* ConnmanTestMsg::ConnectNodePublic(PeerManager& peerman, const char* pszDest, ConnectionType conn_type)
126
0
{
127
0
    CNode* node = ConnectNode(CAddress{}, pszDest, /*fCountFailure=*/false, conn_type, /*use_v2transport=*/true, /*proxy_override=*/std::nullopt);
128
0
    if (!node) return nullptr;
  Branch (128:9): [True: 0, False: 0]
129
0
    node->SetCommonVersion(PROTOCOL_VERSION);
130
0
    peerman.InitializeNode(*node, ServiceFlags(NODE_NETWORK | NODE_WITNESS));
131
0
    node->fSuccessfullyConnected = true;
132
0
    AddTestNode(*node);
133
0
    return node;
134
0
}
135
136
std::vector<NodeEvictionCandidate> GetRandomNodeEvictionCandidates(int n_candidates, FastRandomContext& random_context)
137
0
{
138
0
    std::vector<NodeEvictionCandidate> candidates;
139
0
    candidates.reserve(n_candidates);
140
0
    for (int id = 0; id < n_candidates; ++id) {
  Branch (140:22): [True: 0, False: 0]
141
0
        candidates.push_back({
142
0
            .id=id,
143
0
            .m_connected=NodeSeconds{std::chrono::seconds{random_context.randrange(100)}},
144
0
            .m_min_ping_time=std::chrono::microseconds{random_context.randrange(100)},
145
0
            .m_last_block_time=std::chrono::seconds{random_context.randrange(100)},
146
0
            .m_last_tx_time=std::chrono::seconds{random_context.randrange(100)},
147
0
            .fRelevantServices=random_context.randbool(),
148
0
            .m_relay_txs=random_context.randbool(),
149
0
            .fBloomFilter=random_context.randbool(),
150
0
            .nKeyedNetGroup=random_context.randrange(100u),
151
0
            .prefer_evict=random_context.randbool(),
152
0
            .m_is_local=random_context.randbool(),
153
0
            .m_network=ALL_NETWORKS[random_context.randrange(ALL_NETWORKS.size())],
154
0
            .m_noban=false,
155
0
            .m_conn_type=ConnectionType::INBOUND,
156
0
        });
157
0
    }
158
0
    return candidates;
159
0
}
160
161
// Have different ZeroSock (or others that inherit from it) objects have different
162
// m_socket because EqualSharedPtrSock compares m_socket and we want to avoid two
163
// different objects comparing as equal.
164
static std::atomic<SOCKET> g_mocked_sock_fd{0};
165
166
0
ZeroSock::ZeroSock() : Sock{g_mocked_sock_fd++} {}
167
168
// Sock::~Sock() would try to close(2) m_socket if it is not INVALID_SOCKET, avoid that.
169
0
ZeroSock::~ZeroSock() { m_socket = INVALID_SOCKET; }
170
171
0
ssize_t ZeroSock::Send(const void*, size_t len, int) const { return len; }
172
173
ssize_t ZeroSock::Recv(void* buf, size_t len, int flags) const
174
0
{
175
0
    memset(buf, 0x0, len);
176
0
    return len;
177
0
}
178
179
0
int ZeroSock::Connect(const sockaddr*, socklen_t) const { return 0; }
180
181
0
int ZeroSock::Bind(const sockaddr*, socklen_t) const { return 0; }
182
183
0
int ZeroSock::Listen(int) const { return 0; }
184
185
std::unique_ptr<Sock> ZeroSock::Accept(sockaddr* addr, socklen_t* addr_len) const
186
0
{
187
0
    if (addr != nullptr) {
  Branch (187:9): [True: 0, False: 0]
188
        // Pretend all connections come from 5.5.5.5:6789
189
0
        memset(addr, 0x00, *addr_len);
190
0
        const socklen_t write_len = static_cast<socklen_t>(sizeof(sockaddr_in));
191
0
        if (*addr_len >= write_len) {
  Branch (191:13): [True: 0, False: 0]
192
0
            *addr_len = write_len;
193
0
            sockaddr_in* addr_in = reinterpret_cast<sockaddr_in*>(addr);
194
0
            addr_in->sin_family = AF_INET;
195
0
            memset(&addr_in->sin_addr, 0x05, sizeof(addr_in->sin_addr));
196
0
            addr_in->sin_port = htons(6789);
197
0
        }
198
0
    }
199
0
    return std::make_unique<ZeroSock>();
200
0
}
201
202
int ZeroSock::GetSockOpt(int level, int opt_name, void* opt_val, socklen_t* opt_len) const
203
0
{
204
0
    std::memset(opt_val, 0x0, *opt_len);
205
0
    return 0;
206
0
}
207
208
0
int ZeroSock::SetSockOpt(int, int, const void*, socklen_t) const { return 0; }
209
210
int ZeroSock::GetSockName(sockaddr* name, socklen_t* name_len) const
211
0
{
212
0
    std::memset(name, 0x0, *name_len);
213
0
    return 0;
214
0
}
215
216
0
bool ZeroSock::SetNonBlocking() const { return true; }
217
218
0
bool ZeroSock::IsSelectable() const { return true; }
219
220
bool ZeroSock::Wait(std::chrono::milliseconds timeout, Event requested, Event* occurred) const
221
0
{
222
0
    if (occurred != nullptr) {
  Branch (222:9): [True: 0, False: 0]
223
0
        *occurred = requested;
224
0
    }
225
0
    return true;
226
0
}
227
228
bool ZeroSock::WaitMany(std::chrono::milliseconds timeout, EventsPerSock& events_per_sock) const
229
0
{
230
0
    for (auto& [sock, events] : events_per_sock) {
  Branch (230:31): [True: 0, False: 0]
231
0
        (void)sock;
232
0
        events.occurred = events.requested;
233
0
    }
234
0
    return true;
235
0
}
236
237
ZeroSock& ZeroSock::operator=(Sock&& other)
238
0
{
239
0
    assert(false && "Move of Sock into ZeroSock not allowed.");
  Branch (239:5): [Folded - Ignored]
  Branch (239:5): [Folded - Ignored]
  Branch (239:5): [Folded - Ignored]
240
0
    return *this;
241
0
}
242
243
StaticContentsSock::StaticContentsSock(const std::string& contents)
244
0
    : m_contents{contents}
245
0
{
246
0
}
247
248
ssize_t StaticContentsSock::Recv(void* buf, size_t len, int flags) const
249
0
{
250
0
    const size_t consume_bytes{std::min(len, m_contents.size() - m_consumed)};
251
0
    std::memcpy(buf, m_contents.data() + m_consumed, consume_bytes);
252
0
    if ((flags & MSG_PEEK) == 0) {
  Branch (252:9): [True: 0, False: 0]
253
0
        m_consumed += consume_bytes;
254
0
    }
255
0
    return consume_bytes;
256
0
}
257
258
StaticContentsSock& StaticContentsSock::operator=(Sock&& other)
259
0
{
260
0
    assert(false && "Move of Sock into StaticContentsSock not allowed.");
  Branch (260:5): [Folded - Ignored]
  Branch (260:5): [Folded - Ignored]
  Branch (260:5): [Folded - Ignored]
261
0
    return *this;
262
0
}
263
264
ssize_t DynSock::Pipe::GetBytes(void* buf, size_t len, int flags)
265
0
{
266
0
    WAIT_LOCK(m_mutex, lock);
267
268
0
    if (m_data.empty()) {
  Branch (268:9): [True: 0, False: 0]
269
0
        if (m_eof) {
  Branch (269:13): [True: 0, False: 0]
270
0
            return 0;
271
0
        }
272
0
        errno = EAGAIN; // Same as recv(2) on a non-blocking socket.
273
0
        return -1;
274
0
    }
275
276
0
    const size_t read_bytes{std::min(len, m_data.size())};
277
278
0
    std::memcpy(buf, m_data.data(), read_bytes);
279
0
    if ((flags & MSG_PEEK) == 0) {
  Branch (279:9): [True: 0, False: 0]
280
0
        m_data.erase(m_data.begin(), m_data.begin() + read_bytes);
281
0
    }
282
283
0
    return read_bytes;
284
0
}
285
286
std::optional<CNetMessage> DynSock::Pipe::GetNetMsg()
287
0
{
288
0
    V1Transport transport{NodeId{0}};
289
290
0
    {
291
0
        WAIT_LOCK(m_mutex, lock);
292
293
0
        WaitForDataOrEof(lock);
294
0
        if (m_eof && m_data.empty()) {
  Branch (294:13): [True: 0, False: 0]
  Branch (294:22): [True: 0, False: 0]
295
0
            return std::nullopt;
296
0
        }
297
298
0
        for (;;) {
299
0
            std::span<const uint8_t> s{m_data};
300
0
            if (!transport.ReceivedBytes(s)) {  // Consumed bytes are removed from the front of s.
  Branch (300:17): [True: 0, False: 0]
301
0
                return std::nullopt;
302
0
            }
303
0
            m_data.erase(m_data.begin(), m_data.begin() + m_data.size() - s.size());
304
0
            if (transport.ReceivedMessageComplete()) {
  Branch (304:17): [True: 0, False: 0]
305
0
                break;
306
0
            }
307
0
            if (m_data.empty()) {
  Branch (307:17): [True: 0, False: 0]
308
0
                WaitForDataOrEof(lock);
309
0
                if (m_eof && m_data.empty()) {
  Branch (309:21): [True: 0, False: 0]
  Branch (309:30): [True: 0, False: 0]
310
0
                    return std::nullopt;
311
0
                }
312
0
            }
313
0
        }
314
0
    }
315
316
0
    bool reject{false};
317
0
    CNetMessage msg{transport.GetReceivedMessage(/*time=*/{}, reject)};
318
0
    if (reject) {
  Branch (318:9): [True: 0, False: 0]
319
0
        return std::nullopt;
320
0
    }
321
0
    return std::make_optional<CNetMessage>(std::move(msg));
322
0
}
323
324
void DynSock::Pipe::PushBytes(const void* buf, size_t len)
325
0
{
326
0
    LOCK(m_mutex);
327
0
    const uint8_t* b = static_cast<const uint8_t*>(buf);
328
0
    m_data.insert(m_data.end(), b, b + len);
329
0
    m_cond.notify_all();
330
0
}
331
332
void DynSock::Pipe::Eof()
333
0
{
334
0
    LOCK(m_mutex);
335
0
    m_eof = true;
336
0
    m_cond.notify_all();
337
0
}
338
339
void DynSock::Pipe::WaitForDataOrEof(UniqueLock<Mutex>& lock)
340
0
{
341
0
    Assert(lock.mutex() == &m_mutex);
342
343
0
    m_cond.wait(lock, [&]() EXCLUSIVE_LOCKS_REQUIRED(m_mutex) {
344
0
        AssertLockHeld(m_mutex);
345
0
        return !m_data.empty() || m_eof;
  Branch (345:16): [True: 0, False: 0]
  Branch (345:35): [True: 0, False: 0]
346
0
    });
347
0
}
348
349
DynSock::DynSock(std::shared_ptr<Pipes> pipes, Queue* accept_sockets)
350
0
    : m_pipes{pipes}, m_accept_sockets{accept_sockets}
351
0
{
352
0
}
353
354
DynSock::DynSock(std::shared_ptr<Pipes> pipes)
355
0
    : m_pipes{pipes}, m_accept_sockets{}
356
0
{
357
0
}
358
359
DynSock::~DynSock()
360
0
{
361
0
    m_pipes->send.Eof();
362
0
}
363
364
ssize_t DynSock::Recv(void* buf, size_t len, int flags) const
365
0
{
366
0
    return m_pipes->recv.GetBytes(buf, len, flags);
367
0
}
368
369
ssize_t DynSock::Send(const void* buf, size_t len, int) const
370
0
{
371
0
    m_pipes->send.PushBytes(buf, len);
372
0
    return len;
373
0
}
374
375
std::unique_ptr<Sock> DynSock::Accept(sockaddr* addr, socklen_t* addr_len) const
376
0
{
377
0
    assert(m_accept_sockets && "Accept() called on non-listening DynSock");
  Branch (377:5): [True: 0, False: 0]
  Branch (377:5): [Folded - Ignored]
  Branch (377:5): [True: 0, False: 0]
378
0
    ZeroSock::Accept(addr, addr_len);
379
0
    return m_accept_sockets->Pop().value_or(nullptr);
380
0
}
381
382
bool DynSock::Wait(std::chrono::milliseconds timeout,
383
                   Event requested,
384
                   Event* occurred) const
385
0
{
386
0
    EventsPerSock ev;
387
0
    ev.emplace(this, Events{requested});
388
0
    const bool ret{WaitMany(timeout, ev)};
389
0
    if (occurred != nullptr) {
  Branch (389:9): [True: 0, False: 0]
390
0
        *occurred = ev.begin()->second.occurred;
391
0
    }
392
0
    return ret;
393
0
}
394
395
bool DynSock::WaitMany(std::chrono::milliseconds timeout, EventsPerSock& events_per_sock) const
396
0
{
397
0
    const auto deadline = std::chrono::steady_clock::now() + timeout;
398
0
    bool at_least_one_event_occurred{false};
399
400
0
    for (;;) {
401
        // Check all sockets for readiness without waiting.
402
0
        for (auto& [sock, events] : events_per_sock) {
  Branch (402:35): [True: 0, False: 0]
403
0
            if ((events.requested & Sock::SendEvent) != 0) {
  Branch (403:17): [True: 0, False: 0]
404
                // Always ready for Send().
405
0
                events.occurred |= Sock::SendEvent;
406
0
                at_least_one_event_occurred = true;
407
0
            }
408
409
0
            if ((events.requested & Sock::RecvEvent) != 0) {
  Branch (409:17): [True: 0, False: 0]
410
0
                auto dyn_sock = reinterpret_cast<const DynSock*>(sock.get());
411
0
                uint8_t b;
412
0
                if (dyn_sock->m_pipes->recv.GetBytes(&b, 1, MSG_PEEK) == 1 || (dyn_sock->m_accept_sockets && !dyn_sock->m_accept_sockets->Empty())) {
  Branch (412:21): [True: 0, False: 0]
  Branch (412:80): [True: 0, False: 0]
  Branch (412:110): [True: 0, False: 0]
413
0
                    events.occurred |= Sock::RecvEvent;
414
0
                    at_least_one_event_occurred = true;
415
0
                }
416
0
            }
417
0
        }
418
419
0
        if (at_least_one_event_occurred || std::chrono::steady_clock::now() > deadline) {
  Branch (419:13): [True: 0, False: 0]
  Branch (419:13): [True: 0, False: 0]
  Branch (419:44): [True: 0, False: 0]
420
0
            break;
421
0
        }
422
423
0
        std::this_thread::sleep_for(10ms);
424
0
    }
425
426
0
    return true;
427
0
}
428
429
DynSock& DynSock::operator=(Sock&&)
430
0
{
431
0
    assert(false && "Move of Sock into DynSock not allowed.");
  Branch (431:5): [Folded - Ignored]
  Branch (431:5): [Folded - Ignored]
  Branch (431:5): [Folded - Ignored]
432
0
    return *this;
433
0
}