Line data Source code
1 : // Copyright (c) 2020-2021 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 <functional>
14 : #include <memory>
15 : #include <string>
16 : #include <unordered_map>
17 :
18 : #if defined(USE_EPOLL)
19 : #define DEFAULT_SOCKETEVENTS "epoll"
20 : #elif defined(USE_KQUEUE)
21 : #define DEFAULT_SOCKETEVENTS "kqueue"
22 : #elif defined(USE_POLL)
23 : #define DEFAULT_SOCKETEVENTS "poll"
24 : #else
25 : #define DEFAULT_SOCKETEVENTS "select"
26 : #endif
27 :
28 : /**
29 : * Maximum time to wait for I/O readiness.
30 : * It will take up until this time to break off in case of an interruption.
31 : */
32 : static constexpr auto MAX_WAIT_FOR_IO = 1s;
33 :
34 : static constexpr size_t MAX_EVENTS = 64;
35 :
36 : enum class SocketEventsMode : int8_t {
37 : Select = 0,
38 : Poll = 1,
39 : EPoll = 2,
40 : KQueue = 3,
41 :
42 : Unknown = -1
43 : };
44 :
45 : struct SocketEventsParams
46 : {
47 : using wrap_fn = std::function<void(std::function<void()>&&)>;
48 :
49 : SocketEventsParams() = delete;
50 278 : SocketEventsParams(SocketEventsMode event_mode) :
51 139 : m_event_mode{event_mode}
52 139 : {
53 139 : assert(m_event_mode != SocketEventsMode::Unknown);
54 278 : }
55 0 : SocketEventsParams(SocketEventsMode event_mode, SOCKET event_fd, wrap_fn wrap_func) :
56 0 : m_event_mode{event_mode},
57 0 : m_event_fd{event_fd},
58 0 : m_wrap_func{wrap_func}
59 0 : {
60 0 : assert(m_event_mode != SocketEventsMode::Unknown);
61 0 : }
62 290 : ~SocketEventsParams() = default;
63 :
64 : public:
65 : /* Choice of API to use in Sock::Wait{,Many}() */
66 : SocketEventsMode m_event_mode{SocketEventsMode::Unknown};
67 : /* File descriptor for event triggered SEMs (and INVALID_SOCKET for the rest) */
68 139 : SOCKET m_event_fd{INVALID_SOCKET};
69 : /* Function that wraps itself around WakeMany()'s API call */
70 141 : wrap_fn m_wrap_func{[](std::function<void()>&& func){func();}};
71 : };
72 :
73 : /* Converts SocketEventsMode value to string with additional check to report modes not compiled for as unknown */
74 3 : constexpr std::string_view SEMToString(const SocketEventsMode val) {
75 3 : switch (val) {
76 : case (SocketEventsMode::Select):
77 0 : return "select";
78 : #ifdef USE_POLL
79 : case (SocketEventsMode::Poll):
80 : return "poll";
81 : #endif /* USE_POLL */
82 : #ifdef USE_EPOLL
83 : case (SocketEventsMode::EPoll):
84 : return "epoll";
85 : #endif /* USE_EPOLL */
86 : #ifdef USE_KQUEUE
87 : case (SocketEventsMode::KQueue):
88 3 : return "kqueue";
89 : #endif /* USE_KQUEUE */
90 : default:
91 0 : return "unknown";
92 : };
93 3 : }
94 :
95 0 : constexpr std::string_view GetSupportedSocketEventsStr()
96 : {
97 0 : return "'select'"
98 : #ifdef USE_POLL
99 : ", 'poll'"
100 : #endif /* USE_POLL */
101 : #ifdef USE_EPOLL
102 : ", 'epoll'"
103 : #endif /* USE_EPOLL */
104 : #ifdef USE_KQUEUE
105 : ", 'kqueue'"
106 : #endif /* USE_KQUEUE */
107 : ;
108 : }
109 :
110 : /* Converts string to SocketEventsMode value with additional check to report modes not compiled for as unknown */
111 627 : constexpr SocketEventsMode SEMFromString(std::string_view str) {
112 627 : if (str == "select") { return SocketEventsMode::Select; }
113 : #ifdef USE_POLL
114 : if (str == "poll") { return SocketEventsMode::Poll; }
115 : #endif /* USE_POLL */
116 : #ifdef USE_EPOLL
117 : if (str == "epoll") { return SocketEventsMode::EPoll; }
118 : #endif /* USE_EPOLL */
119 : #ifdef USE_KQUEUE
120 627 : if (str == "kqueue") { return SocketEventsMode::KQueue; }
121 : #endif /* USE_KQUEUE */
122 0 : return SocketEventsMode::Unknown;
123 627 : }
124 :
125 : /**
126 : * RAII helper class that manages a socket. Mimics `std::unique_ptr`, but instead of a pointer it
127 : * contains a socket and closes it automatically when it goes out of scope.
128 : */
129 : class Sock
130 : {
131 : public:
132 : /**
133 : * Default constructor, creates an empty object that does nothing when destroyed.
134 : */
135 : Sock();
136 :
137 : /**
138 : * Take ownership of an existent socket.
139 : */
140 : explicit Sock(SOCKET s);
141 :
142 : /**
143 : * Copy constructor, disabled because closing the same socket twice is undesirable.
144 : */
145 : Sock(const Sock&) = delete;
146 :
147 : /**
148 : * Move constructor, grab the socket from another object and close ours (if set).
149 : */
150 : Sock(Sock&& other);
151 :
152 : /**
153 : * Destructor, close the socket or do nothing if empty.
154 : */
155 : virtual ~Sock();
156 :
157 : /**
158 : * Copy assignment operator, disabled because closing the same socket twice is undesirable.
159 : */
160 : Sock& operator=(const Sock&) = delete;
161 :
162 : /**
163 : * Move assignment operator, grab the socket from another object and close ours (if set).
164 : */
165 : virtual Sock& operator=(Sock&& other);
166 :
167 : /**
168 : * Get the value of the contained socket.
169 : * @return socket or INVALID_SOCKET if empty
170 : */
171 : [[nodiscard]] virtual SOCKET Get() const;
172 :
173 : /**
174 : * send(2) wrapper. Equivalent to `send(this->Get(), data, len, flags);`. Code that uses this
175 : * wrapper can be unit tested if this method is overridden by a mock Sock implementation.
176 : */
177 : [[nodiscard]] virtual ssize_t Send(const void* data, size_t len, int flags) const;
178 :
179 : /**
180 : * recv(2) wrapper. Equivalent to `recv(this->Get(), buf, len, flags);`. Code that uses this
181 : * wrapper can be unit tested if this method is overridden by a mock Sock implementation.
182 : */
183 : [[nodiscard]] virtual ssize_t Recv(void* buf, size_t len, int flags) const;
184 :
185 : /**
186 : * connect(2) wrapper. Equivalent to `connect(this->Get(), addr, addrlen)`. Code that uses this
187 : * wrapper can be unit tested if this method is overridden by a mock Sock implementation.
188 : */
189 : [[nodiscard]] virtual int Connect(const sockaddr* addr, socklen_t addr_len) const;
190 :
191 : /**
192 : * bind(2) wrapper. Equivalent to `bind(this->Get(), addr, addr_len)`. Code that uses this
193 : * wrapper can be unit tested if this method is overridden by a mock Sock implementation.
194 : */
195 : [[nodiscard]] virtual int Bind(const sockaddr* addr, socklen_t addr_len) const;
196 :
197 : /**
198 : * listen(2) wrapper. Equivalent to `listen(this->Get(), backlog)`. Code that uses this
199 : * wrapper can be unit tested if this method is overridden by a mock Sock implementation.
200 : */
201 : [[nodiscard]] virtual int Listen(int backlog) const;
202 :
203 : /**
204 : * accept(2) wrapper. Equivalent to `std::make_unique<Sock>(accept(this->Get(), addr, addr_len))`.
205 : * Code that uses this wrapper can be unit tested if this method is overridden by a mock Sock
206 : * implementation.
207 : * The returned unique_ptr is empty if `accept()` failed in which case errno will be set.
208 : */
209 : [[nodiscard]] virtual std::unique_ptr<Sock> Accept(sockaddr* addr, socklen_t* addr_len) const;
210 :
211 : /**
212 : * getsockopt(2) wrapper. Equivalent to
213 : * `getsockopt(this->Get(), level, opt_name, opt_val, opt_len)`. Code that uses this
214 : * wrapper can be unit tested if this method is overridden by a mock Sock implementation.
215 : */
216 : [[nodiscard]] virtual int GetSockOpt(int level,
217 : int opt_name,
218 : void* opt_val,
219 : socklen_t* opt_len) const;
220 :
221 : /**
222 : * setsockopt(2) wrapper. Equivalent to
223 : * `setsockopt(this->Get(), level, opt_name, opt_val, opt_len)`. Code that uses this
224 : * wrapper can be unit tested if this method is overridden by a mock Sock implementation.
225 : */
226 : [[nodiscard]] virtual int SetSockOpt(int level,
227 : int opt_name,
228 : const void* opt_val,
229 : socklen_t opt_len) const;
230 :
231 : /**
232 : * getsockname(2) wrapper. Equivalent to
233 : * `getsockname(this->Get(), name, name_len)`. Code that uses this
234 : * wrapper can be unit tested if this method is overridden by a mock Sock implementation.
235 : */
236 : [[nodiscard]] virtual int GetSockName(sockaddr* name, socklen_t* name_len) const;
237 :
238 : /**
239 : * Set the non-blocking option on the socket.
240 : * @return true if set successfully
241 : */
242 : [[nodiscard]] virtual bool SetNonBlocking() const;
243 :
244 : /**
245 : * Check if the underlying socket can be used for `select(2)` (or the `Wait()` method).
246 : * @return true if selectable
247 : */
248 : [[nodiscard]] virtual bool IsSelectable(bool is_select) const;
249 :
250 : using Event = uint8_t;
251 :
252 : /**
253 : * If passed to `Wait()`, then it will wait for readiness to read from the socket.
254 : */
255 : static constexpr Event RECV = 0b001;
256 :
257 : /**
258 : * If passed to `Wait()`, then it will wait for readiness to send to the socket.
259 : */
260 : static constexpr Event SEND = 0b010;
261 :
262 : /**
263 : * Ignored if passed to `Wait()`, but could be set in the occurred events if an
264 : * exceptional condition has occurred on the socket or if it has been disconnected.
265 : */
266 : static constexpr Event ERR = 0b100;
267 :
268 : /**
269 : * Wait for readiness for input (recv) or output (send).
270 : * @param[in] timeout Wait this much for at least one of the requested events to occur.
271 : * @param[in] requested Wait for those events, bitwise-or of `RECV` and `SEND`.
272 : * @param[in] event_params Wait using the API specified.
273 : * @param[out] occurred If not nullptr and the function returns `true`, then this
274 : * indicates which of the requested events occurred (`ERR` will be added, even if
275 : * not requested, if an exceptional event occurs on the socket).
276 : * A timeout is indicated by return value of `true` and `occurred` being set to 0.
277 : * @return true on success (or timeout, if `occurred` of 0 is returned), false otherwise
278 : */
279 : [[nodiscard]] virtual bool Wait(std::chrono::milliseconds timeout,
280 : Event requested,
281 : SocketEventsParams event_params,
282 : Event* occurred = nullptr) const;
283 : /**
284 : * Auxiliary requested/occurred events to wait for in `WaitMany()`.
285 : */
286 : struct Events {
287 4 : explicit Events(Event req, Event ocr = 0) : requested{req}, occurred{ocr} {}
288 : Event requested;
289 : Event occurred;
290 : };
291 :
292 : /**
293 : * On which socket to wait for what events in `WaitMany()`.
294 : *
295 : * Bitcoin:
296 : * The `shared_ptr` is copied into the map to ensure that the `Sock` object
297 : * is not destroyed (its destructor would close the underlying socket).
298 : * If this happens shortly before or after we call `poll(2)` and a new
299 : * socket gets created under the same file descriptor number then the report
300 : * from `WaitMany()` will be bogus.
301 : *
302 : * Dash:
303 : * The raw `SOCKET` file descriptor is copied into the map (generally taken from
304 : * Sock::Get()) to allow sockets managed by external logic (e.g. WakeupPipes) to
305 : * be used without wrapping it into a Sock object and risk handing control over.
306 : */
307 : using EventsPerSock = std::unordered_map<SOCKET, Events>;
308 :
309 : /**
310 : * Same as `Wait()`, but wait on many sockets within the same timeout.
311 : * @param[in] timeout Wait this long for at least one of the requested events to occur.
312 : * @param[in,out] events_per_sock Wait for the requested events on these sockets and set
313 : * `occurred` for the events that actually occurred.
314 : * @return true on success (or timeout, if all `what[].occurred` are returned as 0),
315 : * false otherwise
316 : */
317 : [[nodiscard]] virtual bool WaitMany(std::chrono::milliseconds timeout,
318 : EventsPerSock& events_per_sock,
319 : SocketEventsParams event_params) const;
320 :
321 : /**
322 : * As an EventsPerSock map no longer contains a Sock object (it now contains the raw SOCKET file
323 : * descriptor), we lose access to all the logic implemented in Sock. Except that as WaitMany
324 : * doesn't interact with the raw socket stored within Sock, it can be safely declared as static
325 : * and we can pass all other parameters as arguments as it should ordinarily remain the same for
326 : * entire runtime duration of the program. We keep around the virtual WaitMany to allow mockability
327 : * in tests, so keep in mind that using WaitManyInternal *bypasses* any override for WaitMany.
328 : *
329 : * This doesn't apply to Sock::Wait(), as it populates an EventsPerSock map with its own raw
330 : * socket before passing it to WaitMany.
331 : */
332 : static bool WaitManyInternal(std::chrono::milliseconds timeout,
333 : EventsPerSock& events_per_sock,
334 : SocketEventsParams event_params);
335 : #ifdef USE_EPOLL
336 : static bool WaitManyEPoll(std::chrono::milliseconds timeout,
337 : EventsPerSock& events_per_sock,
338 : SOCKET epoll_fd,
339 : SocketEventsParams::wrap_fn wrap_func);
340 : #endif /* USE_EPOLL */
341 : #ifdef USE_KQUEUE
342 : static bool WaitManyKQueue(std::chrono::milliseconds timeout,
343 : EventsPerSock& events_per_sock,
344 : SOCKET kqueue_fd,
345 : SocketEventsParams::wrap_fn wrap_func);
346 : #endif /* USE_KQUEUE */
347 : #ifdef USE_POLL
348 : static bool WaitManyPoll(std::chrono::milliseconds timeout,
349 : EventsPerSock& events_per_sock,
350 : SocketEventsParams::wrap_fn wrap_func);
351 : #endif /* USE_POLL */
352 : static bool WaitManySelect(std::chrono::milliseconds timeout,
353 : EventsPerSock& events_per_sock,
354 : SocketEventsParams::wrap_fn wrap_func);
355 :
356 : /* Higher level, convenience, methods. These may throw. */
357 :
358 : /**
359 : * Send the given data, retrying on transient errors.
360 : * @param[in] data Data to send.
361 : * @param[in] timeout Timeout for the entire operation.
362 : * @param[in] interrupt If this is signaled then the operation is canceled.
363 : * @throws std::runtime_error if the operation cannot be completed. In this case only some of
364 : * the data will be written to the socket.
365 : */
366 : virtual void SendComplete(const std::string& data,
367 : std::chrono::milliseconds timeout,
368 : CThreadInterrupt& interrupt) const;
369 :
370 : /**
371 : * Read from socket until a terminator character is encountered. Will never consume bytes past
372 : * the terminator from the socket.
373 : * @param[in] terminator Character up to which to read from the socket.
374 : * @param[in] timeout Timeout for the entire operation.
375 : * @param[in] interrupt If this is signaled then the operation is canceled.
376 : * @param[in] max_data The maximum amount of data (in bytes) to receive. If this many bytes
377 : * are received and there is still no terminator, then this method will throw an exception.
378 : * @return The data that has been read, without the terminating character.
379 : * @throws std::runtime_error if the operation cannot be completed. In this case some bytes may
380 : * have been consumed from the socket.
381 : */
382 : [[nodiscard]] virtual std::string RecvUntilTerminator(uint8_t terminator,
383 : std::chrono::milliseconds timeout,
384 : CThreadInterrupt& interrupt,
385 : size_t max_data) const;
386 :
387 : /**
388 : * Check if still connected.
389 : * @param[out] errmsg The error string, if the socket has been disconnected.
390 : * @return true if connected
391 : */
392 : [[nodiscard]] virtual bool IsConnected(std::string& errmsg) const;
393 :
394 : protected:
395 : /**
396 : * Contained socket. `INVALID_SOCKET` designates the object is empty.
397 : */
398 : SOCKET m_socket;
399 :
400 : private:
401 : /**
402 : * Close `m_socket` if it is not `INVALID_SOCKET`.
403 : */
404 : void Close();
405 : };
406 :
407 : /** Return readable error string for a network error code */
408 : std::string NetworkErrorString(int err);
409 :
410 : extern SocketEventsMode g_socket_events_mode;
411 :
412 : #endif // BITCOIN_UTIL_SOCK_H
|