/root/bitcoin/src/util/sock.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_UTIL_SOCK_H |
6 | | #define BITCOIN_UTIL_SOCK_H |
7 | | |
8 | | #include <compat/compat.h> |
9 | | #include <util/threadinterrupt.h> |
10 | | #include <util/time.h> |
11 | | |
12 | | #include <chrono> |
13 | | #include <memory> |
14 | | #include <span> |
15 | | #include <string> |
16 | | #include <unordered_map> |
17 | | |
18 | | /** |
19 | | * Maximum time to wait for I/O readiness. |
20 | | * It will take up until this time to break off in case of an interruption. |
21 | | */ |
22 | | static constexpr auto MAX_WAIT_FOR_IO = 1s; |
23 | | |
24 | | inline bool IOErrorIsPermanent(int err) |
25 | 0 | { |
26 | 0 | return err != WSAEAGAIN && err != WSAEINTR && err != WSAEWOULDBLOCK && err != WSAEINPROGRESS; Line | Count | Source | 62 | 0 | #define WSAEAGAIN EAGAIN |
| return err != WSAEAGAIN && err != WSAEINTR && err != WSAEWOULDBLOCK && err != WSAEINPROGRESS; Line | Count | Source | 64 | 0 | #define WSAEINTR EINTR |
| return err != WSAEAGAIN && err != WSAEINTR && err != WSAEWOULDBLOCK && err != WSAEINPROGRESS; Line | Count | Source | 61 | 0 | #define WSAEWOULDBLOCK EWOULDBLOCK |
| return err != WSAEAGAIN && err != WSAEINTR && err != WSAEWOULDBLOCK && err != WSAEINPROGRESS; Line | Count | Source | 65 | 0 | #define WSAEINPROGRESS EINPROGRESS |
|
27 | 0 | } |
28 | | |
29 | | /** |
30 | | * RAII helper class that manages a socket and closes it automatically when it goes out of scope. |
31 | | */ |
32 | | class Sock |
33 | | { |
34 | | public: |
35 | | Sock() = delete; |
36 | | |
37 | | /** |
38 | | * Take ownership of an existent socket. |
39 | | */ |
40 | | explicit Sock(SOCKET s); |
41 | | |
42 | | /** |
43 | | * Copy constructor, disabled because closing the same socket twice is undesirable. |
44 | | */ |
45 | | Sock(const Sock&) = delete; |
46 | | |
47 | | /** |
48 | | * Move constructor, grab the socket from another object and close ours (if set). |
49 | | */ |
50 | | Sock(Sock&& other); |
51 | | |
52 | | /** |
53 | | * Destructor, close the socket or do nothing if empty. |
54 | | */ |
55 | | virtual ~Sock(); |
56 | | |
57 | | /** |
58 | | * Copy assignment operator, disabled because closing the same socket twice is undesirable. |
59 | | */ |
60 | | Sock& operator=(const Sock&) = delete; |
61 | | |
62 | | /** |
63 | | * Move assignment operator, grab the socket from another object and close ours (if set). |
64 | | */ |
65 | | virtual Sock& operator=(Sock&& other); |
66 | | |
67 | | /** |
68 | | * send(2) wrapper. Equivalent to `send(m_socket, data, len, flags);`. Code that uses this |
69 | | * wrapper can be unit tested if this method is overridden by a mock Sock implementation. |
70 | | */ |
71 | | [[nodiscard]] virtual ssize_t Send(const void* data, size_t len, int flags) const; |
72 | | |
73 | | /** |
74 | | * recv(2) wrapper. Equivalent to `recv(m_socket, buf, len, flags);`. Code that uses this |
75 | | * wrapper can be unit tested if this method is overridden by a mock Sock implementation. |
76 | | */ |
77 | | [[nodiscard]] virtual ssize_t Recv(void* buf, size_t len, int flags) const; |
78 | | |
79 | | /** |
80 | | * connect(2) wrapper. Equivalent to `connect(m_socket, addr, addrlen)`. Code that uses this |
81 | | * wrapper can be unit tested if this method is overridden by a mock Sock implementation. |
82 | | */ |
83 | | [[nodiscard]] virtual int Connect(const sockaddr* addr, socklen_t addr_len) const; |
84 | | |
85 | | /** |
86 | | * bind(2) wrapper. Equivalent to `bind(m_socket, addr, addr_len)`. Code that uses this |
87 | | * wrapper can be unit tested if this method is overridden by a mock Sock implementation. |
88 | | */ |
89 | | [[nodiscard]] virtual int Bind(const sockaddr* addr, socklen_t addr_len) const; |
90 | | |
91 | | /** |
92 | | * listen(2) wrapper. Equivalent to `listen(m_socket, backlog)`. Code that uses this |
93 | | * wrapper can be unit tested if this method is overridden by a mock Sock implementation. |
94 | | */ |
95 | | [[nodiscard]] virtual int Listen(int backlog) const; |
96 | | |
97 | | /** |
98 | | * accept(2) wrapper. Equivalent to `std::make_unique<Sock>(accept(m_socket, addr, addr_len))`. |
99 | | * Code that uses this wrapper can be unit tested if this method is overridden by a mock Sock |
100 | | * implementation. |
101 | | * The returned unique_ptr is empty if `accept()` failed in which case errno will be set. |
102 | | */ |
103 | | [[nodiscard]] virtual std::unique_ptr<Sock> Accept(sockaddr* addr, socklen_t* addr_len) const; |
104 | | |
105 | | /** |
106 | | * getsockopt(2) wrapper. Equivalent to |
107 | | * `getsockopt(m_socket, level, opt_name, opt_val, opt_len)`. Code that uses this |
108 | | * wrapper can be unit tested if this method is overridden by a mock Sock implementation. |
109 | | */ |
110 | | [[nodiscard]] virtual int GetSockOpt(int level, |
111 | | int opt_name, |
112 | | void* opt_val, |
113 | | socklen_t* opt_len) const; |
114 | | |
115 | | /** |
116 | | * setsockopt(2) wrapper. Equivalent to |
117 | | * `setsockopt(m_socket, level, opt_name, opt_val, opt_len)`. Code that uses this |
118 | | * wrapper can be unit tested if this method is overridden by a mock Sock implementation. |
119 | | */ |
120 | | [[nodiscard]] virtual int SetSockOpt(int level, |
121 | | int opt_name, |
122 | | const void* opt_val, |
123 | | socklen_t opt_len) const; |
124 | | |
125 | | /** |
126 | | * getsockname(2) wrapper. Equivalent to |
127 | | * `getsockname(m_socket, name, name_len)`. Code that uses this |
128 | | * wrapper can be unit tested if this method is overridden by a mock Sock implementation. |
129 | | */ |
130 | | [[nodiscard]] virtual int GetSockName(sockaddr* name, socklen_t* name_len) const; |
131 | | |
132 | | /** |
133 | | * Set the non-blocking option on the socket. |
134 | | * @return true if set successfully |
135 | | */ |
136 | | [[nodiscard]] virtual bool SetNonBlocking() const; |
137 | | |
138 | | /** |
139 | | * Check if the underlying socket can be used for `select(2)` (or the `Wait()` method). |
140 | | * @return true if selectable |
141 | | */ |
142 | | [[nodiscard]] virtual bool IsSelectable() const; |
143 | | |
144 | | using Event = uint8_t; |
145 | | |
146 | | /** |
147 | | * If passed to `Wait()`, then it will wait for readiness to read from the socket. |
148 | | */ |
149 | | static constexpr Event RECV = 0b001; |
150 | | |
151 | | /** |
152 | | * If passed to `Wait()`, then it will wait for readiness to send to the socket. |
153 | | */ |
154 | | static constexpr Event SEND = 0b010; |
155 | | |
156 | | /** |
157 | | * Ignored if passed to `Wait()`, but could be set in the occurred events if an |
158 | | * exceptional condition has occurred on the socket or if it has been disconnected. |
159 | | */ |
160 | | static constexpr Event ERR = 0b100; |
161 | | |
162 | | /** |
163 | | * Wait for readiness for input (recv) or output (send). |
164 | | * @param[in] timeout Wait this much for at least one of the requested events to occur. |
165 | | * @param[in] requested Wait for those events, bitwise-or of `RECV` and `SEND`. |
166 | | * @param[out] occurred If not nullptr and the function returns `true`, then this |
167 | | * indicates which of the requested events occurred (`ERR` will be added, even if |
168 | | * not requested, if an exceptional event occurs on the socket). |
169 | | * A timeout is indicated by return value of `true` and `occurred` being set to 0. |
170 | | * @return true on success (or timeout, if `occurred` of 0 is returned), false otherwise |
171 | | */ |
172 | | [[nodiscard]] virtual bool Wait(std::chrono::milliseconds timeout, |
173 | | Event requested, |
174 | | Event* occurred = nullptr) const; |
175 | | |
176 | | /** |
177 | | * Auxiliary requested/occurred events to wait for in `WaitMany()`. |
178 | | */ |
179 | | struct Events { |
180 | 0 | explicit Events(Event req) : requested{req} {} |
181 | | Event requested; |
182 | | Event occurred{0}; |
183 | | }; |
184 | | |
185 | | struct HashSharedPtrSock { |
186 | | size_t operator()(const std::shared_ptr<const Sock>& s) const |
187 | 0 | { |
188 | 0 | return s ? s->m_socket : std::numeric_limits<SOCKET>::max(); |
189 | 0 | } |
190 | | }; |
191 | | |
192 | | struct EqualSharedPtrSock { |
193 | | bool operator()(const std::shared_ptr<const Sock>& lhs, |
194 | | const std::shared_ptr<const Sock>& rhs) const |
195 | 0 | { |
196 | 0 | if (lhs && rhs) { |
197 | 0 | return lhs->m_socket == rhs->m_socket; |
198 | 0 | } |
199 | 0 | if (!lhs && !rhs) { |
200 | 0 | return true; |
201 | 0 | } |
202 | 0 | return false; |
203 | 0 | } |
204 | | }; |
205 | | |
206 | | /** |
207 | | * On which socket to wait for what events in `WaitMany()`. |
208 | | * The `shared_ptr` is copied into the map to ensure that the `Sock` object |
209 | | * is not destroyed (its destructor would close the underlying socket). |
210 | | * If this happens shortly before or after we call `poll(2)` and a new |
211 | | * socket gets created under the same file descriptor number then the report |
212 | | * from `WaitMany()` will be bogus. |
213 | | */ |
214 | | using EventsPerSock = std::unordered_map<std::shared_ptr<const Sock>, Events, HashSharedPtrSock, EqualSharedPtrSock>; |
215 | | |
216 | | /** |
217 | | * Same as `Wait()`, but wait on many sockets within the same timeout. |
218 | | * @param[in] timeout Wait this long for at least one of the requested events to occur. |
219 | | * @param[in,out] events_per_sock Wait for the requested events on these sockets and set |
220 | | * `occurred` for the events that actually occurred. |
221 | | * @return true on success (or timeout, if all `what[].occurred` are returned as 0), |
222 | | * false otherwise |
223 | | */ |
224 | | [[nodiscard]] virtual bool WaitMany(std::chrono::milliseconds timeout, |
225 | | EventsPerSock& events_per_sock) const; |
226 | | |
227 | | /* Higher level, convenience, methods. These may throw. */ |
228 | | |
229 | | /** |
230 | | * Send the given data, retrying on transient errors. |
231 | | * @param[in] data Data to send. |
232 | | * @param[in] timeout Timeout for the entire operation. |
233 | | * @param[in] interrupt If this is signaled then the operation is canceled. |
234 | | * @throws std::runtime_error if the operation cannot be completed. In this case only some of |
235 | | * the data will be written to the socket. |
236 | | */ |
237 | | virtual void SendComplete(std::span<const unsigned char> data, |
238 | | std::chrono::milliseconds timeout, |
239 | | CThreadInterrupt& interrupt) const; |
240 | | |
241 | | /** |
242 | | * Convenience method, equivalent to `SendComplete(MakeUCharSpan(data), timeout, interrupt)`. |
243 | | */ |
244 | | virtual void SendComplete(std::span<const char> data, |
245 | | std::chrono::milliseconds timeout, |
246 | | CThreadInterrupt& interrupt) const; |
247 | | |
248 | | /** |
249 | | * Read from socket until a terminator character is encountered. Will never consume bytes past |
250 | | * the terminator from the socket. |
251 | | * @param[in] terminator Character up to which to read from the socket. |
252 | | * @param[in] timeout Timeout for the entire operation. |
253 | | * @param[in] interrupt If this is signaled then the operation is canceled. |
254 | | * @param[in] max_data The maximum amount of data (in bytes) to receive. If this many bytes |
255 | | * are received and there is still no terminator, then this method will throw an exception. |
256 | | * @return The data that has been read, without the terminating character. |
257 | | * @throws std::runtime_error if the operation cannot be completed. In this case some bytes may |
258 | | * have been consumed from the socket. |
259 | | */ |
260 | | [[nodiscard]] virtual std::string RecvUntilTerminator(uint8_t terminator, |
261 | | std::chrono::milliseconds timeout, |
262 | | CThreadInterrupt& interrupt, |
263 | | size_t max_data) const; |
264 | | |
265 | | /** |
266 | | * Check if still connected. |
267 | | * @param[out] errmsg The error string, if the socket has been disconnected. |
268 | | * @return true if connected |
269 | | */ |
270 | | [[nodiscard]] virtual bool IsConnected(std::string& errmsg) const; |
271 | | |
272 | | /** |
273 | | * Check if the internal socket is equal to `s`. Use only in tests. |
274 | | */ |
275 | | bool operator==(SOCKET s) const; |
276 | | |
277 | | protected: |
278 | | /** |
279 | | * Contained socket. `INVALID_SOCKET` designates the object is empty. |
280 | | */ |
281 | | SOCKET m_socket; |
282 | | |
283 | | private: |
284 | | /** |
285 | | * Close `m_socket` if it is not `INVALID_SOCKET`. |
286 | | */ |
287 | | void Close(); |
288 | | }; |
289 | | |
290 | | /** Return readable error string for a network error code */ |
291 | | std::string NetworkErrorString(int err); |
292 | | |
293 | | #endif // BITCOIN_UTIL_SOCK_H |