LCOV - code coverage report
Current view: top level - src/util - sock.h (source / functions) Hit Total Coverage
Test: fuzz_coverage.info Lines: 0 11 0.0 %
Date: 2023-09-26 12:08:55 Functions: 0 3 0.0 %

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

Generated by: LCOV version 1.14