Branch data Line data Source code
1 : : // Copyright (c) 2020-2022 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 : : #ifndef BITCOIN_TEST_UTIL_NET_H
6 : : #define BITCOIN_TEST_UTIL_NET_H
7 : :
8 : : #include <compat/compat.h>
9 : : #include <node/eviction.h>
10 : : #include <netaddress.h>
11 : : #include <netmessagemaker.h>
12 : : #include <net.h>
13 : : #include <util/sock.h>
14 : : #include <sync.h>
15 : :
16 : : #include <array>
17 : : #include <cassert>
18 : : #include <chrono>
19 : : #include <condition_variable>
20 : : #include <cstring>
21 : : #include <memory>
22 : : #include <optional>
23 : : #include <string>
24 : : #include <vector>
25 : :
26 : 0 : struct ConnmanTestMsg : public CConnman {
27 : 0 : using CConnman::CConnman;
28 : :
29 : : void SetPeerConnectTimeout(std::chrono::seconds timeout)
30 : : {
31 : : m_peer_connect_timeout = timeout;
32 : : }
33 : :
34 : 0 : void AddTestNode(CNode& node)
35 : : {
36 : 0 : LOCK(m_nodes_mutex);
37 [ # # ]: 0 : m_nodes.push_back(&node);
38 : :
39 [ # # ][ # # ]: 0 : if (node.IsManualOrFullOutboundConn()) ++m_network_conn_counts[node.addr.GetNetwork()];
[ # # ]
40 : 0 : }
41 : :
42 : 0 : void ClearTestNodes()
43 : : {
44 : 0 : LOCK(m_nodes_mutex);
45 [ # # ]: 0 : for (CNode* node : m_nodes) {
46 [ # # ]: 0 : delete node;
47 : : }
48 : 0 : m_nodes.clear();
49 : 0 : }
50 : :
51 : : void Handshake(CNode& node,
52 : : bool successfully_connected,
53 : : ServiceFlags remote_services,
54 : : ServiceFlags local_services,
55 : : int32_t version,
56 : : bool relay_txs)
57 : : EXCLUSIVE_LOCKS_REQUIRED(NetEventsInterface::g_msgproc_mutex);
58 : :
59 : 0 : void ProcessMessagesOnce(CNode& node) EXCLUSIVE_LOCKS_REQUIRED(NetEventsInterface::g_msgproc_mutex) { m_msgproc->ProcessMessages(&node, flagInterruptMsgProc); }
60 : :
61 : : void NodeReceiveMsgBytes(CNode& node, Span<const uint8_t> msg_bytes, bool& complete) const;
62 : :
63 : : bool ReceiveMsgFrom(CNode& node, CSerializedNetMsg&& ser_msg) const;
64 : : void FlushSendBuffer(CNode& node) const;
65 : : };
66 : :
67 : : constexpr ServiceFlags ALL_SERVICE_FLAGS[]{
68 : : NODE_NONE,
69 : : NODE_NETWORK,
70 : : NODE_BLOOM,
71 : : NODE_WITNESS,
72 : : NODE_COMPACT_FILTERS,
73 : : NODE_NETWORK_LIMITED,
74 : : NODE_P2P_V2,
75 : : };
76 : :
77 : : constexpr NetPermissionFlags ALL_NET_PERMISSION_FLAGS[]{
78 : : NetPermissionFlags::None,
79 : : NetPermissionFlags::BloomFilter,
80 : : NetPermissionFlags::Relay,
81 : : NetPermissionFlags::ForceRelay,
82 : : NetPermissionFlags::NoBan,
83 : : NetPermissionFlags::Mempool,
84 : : NetPermissionFlags::Addr,
85 : : NetPermissionFlags::Download,
86 : : NetPermissionFlags::Implicit,
87 : : NetPermissionFlags::All,
88 : : };
89 : :
90 : : constexpr ConnectionType ALL_CONNECTION_TYPES[]{
91 : : ConnectionType::INBOUND,
92 : : ConnectionType::OUTBOUND_FULL_RELAY,
93 : : ConnectionType::MANUAL,
94 : : ConnectionType::FEELER,
95 : : ConnectionType::BLOCK_RELAY,
96 : : ConnectionType::ADDR_FETCH,
97 : : };
98 : :
99 : : constexpr auto ALL_NETWORKS = std::array{
100 : : Network::NET_UNROUTABLE,
101 : : Network::NET_IPV4,
102 : : Network::NET_IPV6,
103 : : Network::NET_ONION,
104 : : Network::NET_I2P,
105 : : Network::NET_CJDNS,
106 : : Network::NET_INTERNAL,
107 : : };
108 : :
109 : : std::vector<NodeEvictionCandidate> GetRandomNodeEvictionCandidates(int n_candidates, FastRandomContext& random_context);
110 : :
111 : : /**
112 : : * A mocked Sock alternative that succeeds on all operations.
113 : : * Returns infinite amount of 0x0 bytes on reads.
114 : : */
115 : : class ZeroSock : public Sock
116 : : {
117 : : public:
118 : : ZeroSock();
119 : :
120 : : ~ZeroSock() override;
121 : :
122 : : ssize_t Send(const void*, size_t len, int) const override;
123 : :
124 : : ssize_t Recv(void* buf, size_t len, int flags) const override;
125 : :
126 : : int Connect(const sockaddr*, socklen_t) const override;
127 : :
128 : : int Bind(const sockaddr*, socklen_t) const override;
129 : :
130 : : int Listen(int) const override;
131 : :
132 : : std::unique_ptr<Sock> Accept(sockaddr* addr, socklen_t* addr_len) const override;
133 : :
134 : : int GetSockOpt(int level, int opt_name, void* opt_val, socklen_t* opt_len) const override;
135 : :
136 : : int SetSockOpt(int, int, const void*, socklen_t) const override;
137 : :
138 : : int GetSockName(sockaddr* name, socklen_t* name_len) const override;
139 : :
140 : : bool SetNonBlocking() const override;
141 : :
142 : : bool IsSelectable() const override;
143 : :
144 : : bool Wait(std::chrono::milliseconds timeout,
145 : : Event requested,
146 : : Event* occurred = nullptr) const override;
147 : :
148 : : bool WaitMany(std::chrono::milliseconds timeout, EventsPerSock& events_per_sock) const override;
149 : :
150 : : private:
151 : : ZeroSock& operator=(Sock&& other) override;
152 : : };
153 : :
154 : : /**
155 : : * A mocked Sock alternative that returns a statically contained data upon read and succeeds
156 : : * and ignores all writes. The data to be returned is given to the constructor and when it is
157 : : * exhausted an EOF is returned by further reads.
158 : : */
159 : 0 : class StaticContentsSock : public ZeroSock
160 : : {
161 : : public:
162 : : explicit StaticContentsSock(const std::string& contents);
163 : :
164 : : /**
165 : : * Return parts of the contents that was provided at construction until it is exhausted
166 : : * and then return 0 (EOF).
167 : : */
168 : : ssize_t Recv(void* buf, size_t len, int flags) const override;
169 : :
170 : 0 : bool IsConnected(std::string&) const override
171 : : {
172 : 0 : return true;
173 : : }
174 : :
175 : : private:
176 : : StaticContentsSock& operator=(Sock&& other) override;
177 : :
178 : : const std::string m_contents;
179 : : mutable size_t m_consumed{0};
180 : : };
181 : :
182 : : /**
183 : : * A mocked Sock alternative that allows providing the data to be returned by Recv()
184 : : * and inspecting the data that has been supplied to Send().
185 : : */
186 : : class DynSock : public ZeroSock
187 : : {
188 : : public:
189 : : /**
190 : : * Unidirectional bytes or CNetMessage queue (FIFO).
191 : : */
192 : 288 : class Pipe
193 : : {
194 : : public:
195 : : /**
196 : : * Get bytes and remove them from the pipe.
197 : : * @param[in] buf Destination to write bytes to.
198 : : * @param[in] len Write up to this number of bytes.
199 : : * @param[in] flags Same as the flags of `recv(2)`. Just `MSG_PEEK` is honored.
200 : : * @return The number of bytes written to `buf`. `0` if `Eof()` has been called.
201 : : * If no bytes are available then `-1` is returned and `errno` is set to `EAGAIN`.
202 : : */
203 : : ssize_t GetBytes(void* buf, size_t len, int flags = 0) EXCLUSIVE_LOCKS_REQUIRED(!m_mutex);
204 : :
205 : : /**
206 : : * Deserialize a `CNetMessage` and remove it from the pipe.
207 : : * If not enough bytes are available then the function will wait. If parsing fails
208 : : * or EOF is signaled to the pipe, then `std::nullopt` is returned.
209 : : */
210 : : std::optional<CNetMessage> GetNetMsg() EXCLUSIVE_LOCKS_REQUIRED(!m_mutex);
211 : :
212 : : /**
213 : : * Push bytes to the pipe.
214 : : */
215 : : void PushBytes(const void* buf, size_t len) EXCLUSIVE_LOCKS_REQUIRED(!m_mutex);
216 : :
217 : : /**
218 : : * Construct and push CNetMessage to the pipe.
219 : : */
220 : : template <typename... Args>
221 : : void PushNetMsg(const std::string& type, Args&&... payload) EXCLUSIVE_LOCKS_REQUIRED(!m_mutex);
222 : :
223 : : /**
224 : : * Signal end-of-file on the receiving end (`GetBytes()` or `GetNetMsg()`).
225 : : */
226 : : void Eof() EXCLUSIVE_LOCKS_REQUIRED(!m_mutex);
227 : :
228 : : private:
229 : : Mutex m_mutex;
230 : : std::condition_variable m_cond;
231 : : std::vector<uint8_t> m_data GUARDED_BY(m_mutex);
232 : 288 : bool m_eof GUARDED_BY(m_mutex){false};
233 : : };
234 : :
235 : 0 : struct Pipes {
236 : : Pipe recv;
237 : : Pipe send;
238 : : };
239 : :
240 : : explicit DynSock(std::shared_ptr<Pipes> pipes);
241 : :
242 : : ~DynSock();
243 : :
244 : : ssize_t Recv(void* buf, size_t len, int flags) const override;
245 : :
246 : : ssize_t Send(const void* buf, size_t len, int) const override;
247 : :
248 : : bool Wait(std::chrono::milliseconds timeout,
249 : : Event requested,
250 : : Event* occurred = nullptr) const override;
251 : :
252 : : bool WaitMany(std::chrono::milliseconds timeout, EventsPerSock& events_per_sock) const override;
253 : :
254 : : private:
255 : : DynSock& operator=(Sock&&) override;
256 : :
257 : : std::shared_ptr<Pipes> m_pipes;
258 : : };
259 : :
260 : : template <typename... Args>
261 : 5823 : void DynSock::Pipe::PushNetMsg(const std::string& type, Args&&... payload)
262 : : {
263 [ + - ][ + - ]: 5823 : auto msg = CNetMsgMaker(INIT_PROTO_VERSION).Make(type, std::forward<Args>(payload)...);
[ + - ]
264 : 5823 : V1Transport transport{NodeId{0}, SER_NETWORK, INIT_PROTO_VERSION};
265 : :
266 : 5823 : const bool queued{transport.SetMessageToSend(msg)};
267 [ + + ][ + - ]: 5823 : assert(queued);
[ + - ]
268 : :
269 [ + + ][ + + ]: 5823 : LOCK(m_mutex);
[ - + ]
270 : :
271 : 17325 : for (;;) {
272 : 17325 : const auto& [bytes, _more, _msg_type] = transport.GetBytesToSend(/*have_next_message=*/true);
273 [ + + ][ + + ]: 17325 : if (bytes.empty()) {
[ + + ]
274 : 5823 : break;
275 : : }
276 [ + - ][ + - ]: 34506 : m_data.insert(m_data.end(), bytes.begin(), bytes.end());
[ + - ][ + - ]
[ + - ][ + - ]
[ + - ][ + - ]
[ + - ]
277 : 11502 : transport.MarkBytesSent(bytes.size());
278 : : }
279 : :
280 : 5823 : m_cond.notify_all();
281 : 5823 : }
282 : :
283 : : #endif // BITCOIN_TEST_UTIL_NET_H
|