LCOV - code coverage report
Current view: top level - src/util - sock.h (source / functions) Hit Total Coverage
Test: total_coverage.info Lines: 24 29 82.8 %
Date: 2026-06-25 07:23:43 Functions: 14 15 93.3 %

          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       24646 :     SocketEventsParams(SocketEventsMode event_mode) :
      51       12323 :         m_event_mode{event_mode}
      52       12323 :     {
      53       12323 :         assert(m_event_mode != SocketEventsMode::Unknown);
      54       24646 :     }
      55    59569126 :     SocketEventsParams(SocketEventsMode event_mode, SOCKET event_fd, wrap_fn wrap_func) :
      56    29784563 :         m_event_mode{event_mode},
      57    29784563 :         m_event_fd{event_fd},
      58    29784563 :         m_wrap_func{wrap_func}
      59    29784563 :     {
      60    29784563 :         assert(m_event_mode != SocketEventsMode::Unknown);
      61    59569126 :     }
      62    59630331 :     ~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       12323 :     SOCKET m_event_fd{INVALID_SOCKET};
      69             :     /* Function that wraps itself around WakeMany()'s API call */
      70       18417 :     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        4199 : constexpr std::string_view SEMToString(const SocketEventsMode val) {
      75        4199 :     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        4199 :             return "kqueue";
      89             : #endif /* USE_KQUEUE */
      90             :         default:
      91           0 :             return "unknown";
      92             :     };
      93        4199 : }
      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        3572 : constexpr SocketEventsMode SEMFromString(std::string_view str) {
     112        3572 :     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        3572 :     if (str == "kqueue") { return SocketEventsMode::KQueue; }
     121             : #endif /* USE_KQUEUE */
     122           0 :     return SocketEventsMode::Unknown;
     123        3572 : }
     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   195366888 :         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

Generated by: LCOV version 1.16