/root/bitcoin/src/test/util/net.h
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 | | #ifndef BITCOIN_TEST_UTIL_NET_H |
6 | | #define BITCOIN_TEST_UTIL_NET_H |
7 | | |
8 | | #include <attributes.h> |
9 | | #include <compat/compat.h> |
10 | | #include <netmessagemaker.h> |
11 | | #include <net.h> |
12 | | #include <net_permissions.h> |
13 | | #include <net_processing.h> |
14 | | #include <netaddress.h> |
15 | | #include <node/connection_types.h> |
16 | | #include <node/eviction.h> |
17 | | #include <span.h> |
18 | | #include <sync.h> |
19 | | #include <util/sock.h> |
20 | | |
21 | | #include <algorithm> |
22 | | #include <array> |
23 | | #include <cassert> |
24 | | #include <chrono> |
25 | | #include <condition_variable> |
26 | | #include <cstdint> |
27 | | #include <cstring> |
28 | | #include <memory> |
29 | | #include <optional> |
30 | | #include <string> |
31 | | #include <unordered_map> |
32 | | #include <vector> |
33 | | |
34 | | class FastRandomContext; |
35 | | |
36 | | struct ConnmanTestMsg : public CConnman { |
37 | | using CConnman::CConnman; |
38 | | |
39 | | void SetMsgProc(NetEventsInterface* msgproc) |
40 | 0 | { |
41 | 0 | m_msgproc = msgproc; |
42 | 0 | } |
43 | | |
44 | 0 | void SetAddrman(AddrMan& in) { addrman = in; } |
45 | | |
46 | | void SetPeerConnectTimeout(std::chrono::seconds timeout) |
47 | 0 | { |
48 | 0 | m_peer_connect_timeout = timeout; |
49 | 0 | } |
50 | | |
51 | | void ResetAddrCache(); |
52 | | void ResetMaxOutboundCycle(); |
53 | | /// Reset the internal state. |
54 | | void Reset(); |
55 | | |
56 | | std::vector<CNode*> TestNodes() |
57 | 0 | { |
58 | 0 | LOCK(m_nodes_mutex); |
59 | 0 | return m_nodes; |
60 | 0 | } |
61 | | |
62 | | void AddTestNode(CNode& node) |
63 | 0 | { |
64 | 0 | LOCK(m_nodes_mutex); |
65 | 0 | m_nodes.push_back(&node); |
66 | |
|
67 | 0 | if (node.IsManualOrFullOutboundConn()) ++m_network_conn_counts[node.addr.GetNetwork()]; Branch (67:13): [True: 0, False: 0]
|
68 | 0 | } |
69 | | |
70 | | void ClearTestNodes() |
71 | 0 | { |
72 | 0 | LOCK(m_nodes_mutex); |
73 | 0 | for (CNode* node : m_nodes) { Branch (73:26): [True: 0, False: 0]
|
74 | 0 | delete node; |
75 | 0 | } |
76 | 0 | m_nodes.clear(); |
77 | 0 | } |
78 | | |
79 | | void CreateNodeFromAcceptedSocketPublic(std::unique_ptr<Sock> sock, |
80 | | NetPermissionFlags permissions, |
81 | | const CAddress& addr_bind, |
82 | | const CAddress& addr_peer) |
83 | 0 | { |
84 | 0 | CreateNodeFromAcceptedSocket(std::move(sock), permissions, addr_bind, addr_peer); |
85 | 0 | } |
86 | | |
87 | | bool InitBindsPublic(const CConnman::Options& options) |
88 | 0 | { |
89 | 0 | return InitBinds(options); |
90 | 0 | } |
91 | | |
92 | | void SocketHandlerPublic() |
93 | 0 | { |
94 | 0 | SocketHandler(); |
95 | 0 | } |
96 | | |
97 | | void Handshake(CNode& node, |
98 | | bool successfully_connected, |
99 | | ServiceFlags remote_services, |
100 | | ServiceFlags local_services, |
101 | | int32_t version, |
102 | | bool relay_txs) |
103 | | EXCLUSIVE_LOCKS_REQUIRED(NetEventsInterface::g_msgproc_mutex); |
104 | | |
105 | | bool ProcessMessagesOnce(CNode& node) EXCLUSIVE_LOCKS_REQUIRED(NetEventsInterface::g_msgproc_mutex) |
106 | 0 | { |
107 | 0 | return m_msgproc->ProcessMessages(node, flagInterruptMsgProc); |
108 | 0 | } |
109 | | |
110 | | void NodeReceiveMsgBytes(CNode& node, std::span<const uint8_t> msg_bytes, bool& complete) const; |
111 | | |
112 | | bool ReceiveMsgFrom(CNode& node, CSerializedNetMsg&& ser_msg) const; |
113 | | void FlushSendBuffer(CNode& node) const; |
114 | | |
115 | 0 | bool AlreadyConnectedToAddressPublic(const CNetAddr& addr) { return AlreadyConnectedToAddress(addr); }; |
116 | | |
117 | | CNode* ConnectNodePublic(PeerManager& peerman, const char* pszDest, ConnectionType conn_type) |
118 | | EXCLUSIVE_LOCKS_REQUIRED(!m_unused_i2p_sessions_mutex); |
119 | | }; |
120 | | |
121 | | constexpr ServiceFlags ALL_SERVICE_FLAGS[]{ |
122 | | NODE_NONE, |
123 | | NODE_NETWORK, |
124 | | NODE_BLOOM, |
125 | | NODE_WITNESS, |
126 | | NODE_COMPACT_FILTERS, |
127 | | NODE_NETWORK_LIMITED, |
128 | | NODE_P2P_V2, |
129 | | }; |
130 | | |
131 | | constexpr NetPermissionFlags ALL_NET_PERMISSION_FLAGS[]{ |
132 | | NetPermissionFlags::None, |
133 | | NetPermissionFlags::BloomFilter, |
134 | | NetPermissionFlags::Relay, |
135 | | NetPermissionFlags::ForceRelay, |
136 | | NetPermissionFlags::NoBan, |
137 | | NetPermissionFlags::Mempool, |
138 | | NetPermissionFlags::Addr, |
139 | | NetPermissionFlags::Download, |
140 | | NetPermissionFlags::Implicit, |
141 | | NetPermissionFlags::All, |
142 | | }; |
143 | | |
144 | | constexpr ConnectionType ALL_CONNECTION_TYPES[]{ |
145 | | ConnectionType::INBOUND, |
146 | | ConnectionType::OUTBOUND_FULL_RELAY, |
147 | | ConnectionType::MANUAL, |
148 | | ConnectionType::FEELER, |
149 | | ConnectionType::BLOCK_RELAY, |
150 | | ConnectionType::ADDR_FETCH, |
151 | | ConnectionType::PRIVATE_BROADCAST, |
152 | | }; |
153 | | |
154 | | constexpr auto ALL_NETWORKS = std::array{ |
155 | | Network::NET_UNROUTABLE, |
156 | | Network::NET_IPV4, |
157 | | Network::NET_IPV6, |
158 | | Network::NET_ONION, |
159 | | Network::NET_I2P, |
160 | | Network::NET_CJDNS, |
161 | | Network::NET_INTERNAL, |
162 | | }; |
163 | | |
164 | | /** |
165 | | * A mocked Sock alternative that succeeds on all operations. |
166 | | * Returns infinite amount of 0x0 bytes on reads. |
167 | | */ |
168 | | class ZeroSock : public Sock |
169 | | { |
170 | | public: |
171 | | ZeroSock(); |
172 | | |
173 | | ~ZeroSock() override; |
174 | | |
175 | | ssize_t Send(const void*, size_t len, int) const override; |
176 | | |
177 | | ssize_t Recv(void* buf, size_t len, int flags) const override; |
178 | | |
179 | | int Connect(const sockaddr*, socklen_t) const override; |
180 | | |
181 | | int Bind(const sockaddr*, socklen_t) const override; |
182 | | |
183 | | int Listen(int) const override; |
184 | | |
185 | | std::unique_ptr<Sock> Accept(sockaddr* addr, socklen_t* addr_len) const override; |
186 | | |
187 | | int GetSockOpt(int level, int opt_name, void* opt_val, socklen_t* opt_len) const override; |
188 | | |
189 | | int SetSockOpt(int, int, const void*, socklen_t) const override; |
190 | | |
191 | | int GetSockName(sockaddr* name, socklen_t* name_len) const override; |
192 | | |
193 | | bool SetNonBlocking() const override; |
194 | | |
195 | | bool IsSelectable() const override; |
196 | | |
197 | | bool Wait(std::chrono::milliseconds timeout, |
198 | | Event requested, |
199 | | Event* occurred = nullptr) const override; |
200 | | |
201 | | bool WaitMany(std::chrono::milliseconds timeout, EventsPerSock& events_per_sock) const override; |
202 | | |
203 | | private: |
204 | | ZeroSock& operator=(Sock&& other) override; |
205 | | }; |
206 | | |
207 | | /** |
208 | | * A mocked Sock alternative that returns a statically contained data upon read and succeeds |
209 | | * and ignores all writes. The data to be returned is given to the constructor and when it is |
210 | | * exhausted an EOF is returned by further reads. |
211 | | */ |
212 | | class StaticContentsSock : public ZeroSock |
213 | | { |
214 | | public: |
215 | | explicit StaticContentsSock(const std::string& contents); |
216 | | |
217 | | /** |
218 | | * Return parts of the contents that was provided at construction until it is exhausted |
219 | | * and then return 0 (EOF). |
220 | | */ |
221 | | ssize_t Recv(void* buf, size_t len, int flags) const override; |
222 | | |
223 | | bool IsConnected(std::string&) const override |
224 | 0 | { |
225 | 0 | return true; |
226 | 0 | } |
227 | | |
228 | | private: |
229 | | StaticContentsSock& operator=(Sock&& other) override; |
230 | | |
231 | | const std::string m_contents; |
232 | | mutable size_t m_consumed{0}; |
233 | | }; |
234 | | |
235 | | /** |
236 | | * A mocked Sock alternative that allows providing the data to be returned by Recv() |
237 | | * and inspecting the data that has been supplied to Send(). |
238 | | */ |
239 | | class DynSock : public ZeroSock |
240 | | { |
241 | | public: |
242 | | /** |
243 | | * Unidirectional bytes or CNetMessage queue (FIFO). |
244 | | */ |
245 | | class Pipe |
246 | | { |
247 | | public: |
248 | | /** |
249 | | * Get bytes and remove them from the pipe. |
250 | | * @param[in] buf Destination to write bytes to. |
251 | | * @param[in] len Write up to this number of bytes. |
252 | | * @param[in] flags Same as the flags of `recv(2)`. Just `MSG_PEEK` is honored. |
253 | | * @return The number of bytes written to `buf`. `0` if `Eof()` has been called. |
254 | | * If no bytes are available then `-1` is returned and `errno` is set to `EAGAIN`. |
255 | | */ |
256 | | ssize_t GetBytes(void* buf, size_t len, int flags = 0) EXCLUSIVE_LOCKS_REQUIRED(!m_mutex); |
257 | | |
258 | | /** |
259 | | * Deserialize a `CNetMessage` and remove it from the pipe. |
260 | | * If not enough bytes are available then the function will wait. If parsing fails |
261 | | * or EOF is signaled to the pipe, then `std::nullopt` is returned. |
262 | | */ |
263 | | std::optional<CNetMessage> GetNetMsg() EXCLUSIVE_LOCKS_REQUIRED(!m_mutex); |
264 | | |
265 | | /** |
266 | | * Push bytes to the pipe. |
267 | | */ |
268 | | void PushBytes(const void* buf, size_t len) EXCLUSIVE_LOCKS_REQUIRED(!m_mutex); |
269 | | |
270 | | /** |
271 | | * Construct and push CNetMessage to the pipe. |
272 | | */ |
273 | | template <typename... Args> |
274 | | void PushNetMsg(const std::string& type, Args&&... payload) EXCLUSIVE_LOCKS_REQUIRED(!m_mutex); |
275 | | |
276 | | /** |
277 | | * Signal end-of-file on the receiving end (`GetBytes()` or `GetNetMsg()`). |
278 | | */ |
279 | | void Eof() EXCLUSIVE_LOCKS_REQUIRED(!m_mutex); |
280 | | |
281 | | private: |
282 | | /** |
283 | | * Return when there is some data to read or EOF has been signaled. |
284 | | * @param[in,out] lock Unique lock that must have been derived from `m_mutex` by `WAIT_LOCK(m_mutex, lock)`. |
285 | | */ |
286 | | void WaitForDataOrEof(UniqueLock<Mutex>& lock) EXCLUSIVE_LOCKS_REQUIRED(m_mutex); |
287 | | |
288 | | Mutex m_mutex; |
289 | | std::condition_variable m_cond; |
290 | | std::vector<uint8_t> m_data GUARDED_BY(m_mutex); |
291 | | bool m_eof GUARDED_BY(m_mutex){false}; |
292 | | }; |
293 | | |
294 | | struct Pipes { |
295 | | Pipe recv; |
296 | | Pipe send; |
297 | | }; |
298 | | |
299 | | /** |
300 | | * A basic thread-safe queue, used for queuing sockets to be returned by Accept(). |
301 | | */ |
302 | | class Queue |
303 | | { |
304 | | public: |
305 | | using S = std::unique_ptr<DynSock>; |
306 | | |
307 | | void Push(S s) EXCLUSIVE_LOCKS_REQUIRED(!m_mutex) |
308 | 0 | { |
309 | 0 | LOCK(m_mutex); |
310 | 0 | m_queue.push(std::move(s)); |
311 | 0 | } |
312 | | |
313 | | std::optional<S> Pop() EXCLUSIVE_LOCKS_REQUIRED(!m_mutex) |
314 | 0 | { |
315 | 0 | LOCK(m_mutex); |
316 | 0 | if (m_queue.empty()) { Branch (316:17): [True: 0, False: 0]
|
317 | 0 | return std::nullopt; |
318 | 0 | } |
319 | 0 | S front{std::move(m_queue.front())}; |
320 | 0 | m_queue.pop(); |
321 | 0 | return front; |
322 | 0 | } |
323 | | |
324 | | bool Empty() const EXCLUSIVE_LOCKS_REQUIRED(!m_mutex) |
325 | 0 | { |
326 | 0 | LOCK(m_mutex); |
327 | 0 | return m_queue.empty(); |
328 | 0 | } |
329 | | |
330 | | private: |
331 | | mutable Mutex m_mutex; |
332 | | std::queue<S> m_queue GUARDED_BY(m_mutex); |
333 | | }; |
334 | | |
335 | | /** |
336 | | * Create a new mocked sock. |
337 | | * @param[in] pipes Send/recv pipes used by the Send() and Recv() methods. |
338 | | * @param[in] accept_sockets Sockets to return by the Accept() method. |
339 | | */ |
340 | | explicit DynSock(std::shared_ptr<Pipes> pipes, Queue* accept_sockets LIFETIMEBOUND); |
341 | | |
342 | | /** |
343 | | * Create a new mocked sock that represents a connected socket. It has pipes |
344 | | * for data transport but there is no queue because connected sockets do |
345 | | * not introduce new connected sockets. |
346 | | * @param[in] pipes Send/recv pipes used by the Send() and Recv() methods. |
347 | | */ |
348 | | explicit DynSock(std::shared_ptr<Pipes> pipes); |
349 | | |
350 | | ~DynSock(); |
351 | | |
352 | | ssize_t Recv(void* buf, size_t len, int flags) const override; |
353 | | |
354 | | ssize_t Send(const void* buf, size_t len, int) const override; |
355 | | |
356 | | std::unique_ptr<Sock> Accept(sockaddr* addr, socklen_t* addr_len) const override; |
357 | | |
358 | | bool Wait(std::chrono::milliseconds timeout, |
359 | | Event requested, |
360 | | Event* occurred = nullptr) const override; |
361 | | |
362 | | bool WaitMany(std::chrono::milliseconds timeout, EventsPerSock& events_per_sock) const override; |
363 | | |
364 | | private: |
365 | | DynSock& operator=(Sock&&) override; |
366 | | |
367 | | std::shared_ptr<Pipes> m_pipes; |
368 | | Queue* const m_accept_sockets; |
369 | | }; |
370 | | |
371 | | template <typename... Args> |
372 | | void DynSock::Pipe::PushNetMsg(const std::string& type, Args&&... payload) |
373 | | { |
374 | | auto msg = NetMsg::Make(type, std::forward<Args>(payload)...); |
375 | | V1Transport transport{NodeId{0}}; |
376 | | |
377 | | const bool queued{transport.SetMessageToSend(msg)}; |
378 | | assert(queued); |
379 | | |
380 | | LOCK(m_mutex); |
381 | | |
382 | | for (;;) { |
383 | | const auto& [bytes, _more, _msg_type] = transport.GetBytesToSend(/*have_next_message=*/true); |
384 | | if (bytes.empty()) { |
385 | | break; |
386 | | } |
387 | | m_data.insert(m_data.end(), bytes.begin(), bytes.end()); |
388 | | transport.MarkBytesSent(bytes.size()); |
389 | | } |
390 | | |
391 | | m_cond.notify_all(); |
392 | | } |
393 | | |
394 | | std::vector<NodeEvictionCandidate> GetRandomNodeEvictionCandidates(int n_candidates, FastRandomContext& random_context); |
395 | | |
396 | | #endif // BITCOIN_TEST_UTIL_NET_H |