Coverage Report

Created: 2025-04-14 16:24

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