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