LCOV - code coverage report
Current view: top level - corosio/native/detail - native_socket_base.hpp (source / functions) Coverage Total Hit Missed
Test: coverage_remapped.info Lines: 100.0 % 34 34
Test Date: 2026-09-25 21:36:35 Functions: 83.8 % 74 62 12

           TLA  Line data    Source code
       1                 : //
       2                 : // Copyright (c) 2026 Michael Vandeberg
       3                 : //
       4                 : // Distributed under the Boost Software License, Version 1.0. (See accompanying
       5                 : // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
       6                 : //
       7                 : // Official repository: https://github.com/cppalliance/corosio
       8                 : //
       9                 : 
      10                 : #ifndef BOOST_COROSIO_NATIVE_DETAIL_NATIVE_SOCKET_BASE_HPP
      11                 : #define BOOST_COROSIO_NATIVE_DETAIL_NATIVE_SOCKET_BASE_HPP
      12                 : 
      13                 : #include <boost/corosio/detail/native_handle.hpp>
      14                 : #include <boost/corosio/endpoint.hpp>
      15                 : #include <boost/corosio/native/detail/endpoint_convert.hpp>
      16                 : #include <boost/corosio/native/detail/make_err.hpp>
      17                 : 
      18                 : #include <memory>
      19                 : #include <system_error>
      20                 : 
      21                 : #include <errno.h>
      22                 : #include <sys/socket.h>
      23                 : 
      24                 : /*
      25                 :     Readiness/completion-agnostic socket base for the POSIX-fd backends.
      26                 : 
      27                 :     Holds the part of a socket impl that does not care whether the backend
      28                 :     is readiness-based (epoll/kqueue/select, which park ops on a
      29                 :     descriptor_state) or completion-based (io_uring, which submits SQEs):
      30                 :     the file descriptor, the cached local endpoint, the impl lifecycle
      31                 :     bases (enable_shared_from_this + the service's intrusive tracking node),
      32                 :     and the synchronous accessors (native_handle / options / bind).
      33                 : 
      34                 :     reactor_basic_socket derives from this and adds the readiness machinery
      35                 :     (descriptor_state, register_op, the cancel/close that deregister from
      36                 :     the reactor). io_uring's socket impls derive from it and add their op
      37                 :     slots + SQE submission. This is the socket-layer analogue of io_uring
      38                 :     deriving from reactor_scheduler: io_uring sockets share the reactor's
      39                 :     readiness-agnostic socket surface, while the on-EAGAIN action (park vs
      40                 :     submit-SQE) and the op model stay backend-specific.
      41                 : 
      42                 :     @tparam Derived   The concrete socket type (CRTP, for shared_from_this
      43                 :                       and the intrusive node).
      44                 :     @tparam ImplBase  The public vtable base (tcp_socket::implementation,
      45                 :                       udp_socket::implementation, ...).
      46                 :     @tparam Endpoint  The endpoint type (endpoint or local_endpoint).
      47                 : */
      48                 : 
      49                 : namespace boost::corosio::detail {
      50                 : 
      51                 : template<class Derived, class ImplBase, class Endpoint = endpoint>
      52                 : class native_socket_base
      53                 :     : public ImplBase
      54                 :     , public std::enable_shared_from_this<Derived>
      55                 : {
      56                 : protected:
      57                 :     // CRTP base: not publicly constructible. The check's preferred fix
      58                 :     // (private ctor + `friend Derived`) is infeasible here — the reactor
      59                 :     // sockets reach this base through intermediate templates
      60                 :     // (reactor_stream_socket -> reactor_basic_socket) that are not `Derived`,
      61                 :     // so a private ctor would stop those intermediates from constructing it.
      62                 :     // Protected is the correct access; suppress the private-only suggestion.
      63                 :     // NOLINTNEXTLINE(bugprone-crtp-constructor-accessibility)
      64 HIT       14678 :     native_socket_base() = default;
      65                 : 
      66                 :     int fd_ = -1;
      67                 :     // mutable so a derived const local_endpoint() override can lazily fill
      68                 :     // it via getsockname() on first read (io_uring's lazy_pending state).
      69                 :     mutable Endpoint local_endpoint_;
      70                 : 
      71                 : public:
      72           14678 :     ~native_socket_base() override = default;
      73                 : 
      74                 :     /// Return the underlying file descriptor.
      75           45855 :     native_handle_type native_handle() const noexcept override
      76                 :     {
      77           45855 :         return fd_;
      78                 :     }
      79                 : 
      80             585 :     corosio::family family() const noexcept override
      81                 :     {
      82             585 :         return to_family(socket_family(fd_));
      83                 :     }
      84                 : 
      85                 :     /// Return the cached local endpoint.
      86             194 :     Endpoint local_endpoint() const noexcept override
      87                 :     {
      88             194 :         return local_endpoint_;
      89                 :     }
      90                 : 
      91                 :     /// Return true if the socket has an open file descriptor.
      92                 :     bool is_open() const noexcept
      93                 :     {
      94                 :         return fd_ >= 0;
      95                 :     }
      96                 : 
      97                 :     /// Set a socket option.
      98             117 :     std::error_code set_option(
      99                 :         int level,
     100                 :         int optname,
     101                 :         void const* data,
     102                 :         std::size_t size) noexcept override
     103                 :     {
     104             117 :         if (::setsockopt(
     105             117 :                 fd_, level, optname, data, static_cast<socklen_t>(size)) != 0)
     106               8 :             return make_err(errno);
     107             109 :         return {};
     108                 :     }
     109                 : 
     110                 :     /// Get a socket option.
     111                 :     std::error_code
     112             170 :     get_option(int level, int optname, void* data, std::size_t* size)
     113                 :         const noexcept override
     114                 :     {
     115             170 :         socklen_t len = static_cast<socklen_t>(*size);
     116             170 :         if (::getsockopt(fd_, level, optname, data, &len) != 0)
     117              13 :             return make_err(errno);
     118             157 :         *size = static_cast<std::size_t>(len);
     119             157 :         return {};
     120                 :     }
     121                 : 
     122                 :     /// Assign the file descriptor.
     123            4488 :     void set_socket(int fd) noexcept
     124                 :     {
     125            4488 :         fd_ = fd;
     126            4488 :     }
     127                 : 
     128                 :     /// Cache the local endpoint.
     129                 :     void set_local_endpoint(Endpoint ep) noexcept
     130                 :     {
     131                 :         local_endpoint_ = ep;
     132                 :     }
     133                 : 
     134                 :     /** Bind the socket to a local endpoint.
     135                 : 
     136                 :         Calls ::bind() and caches the resulting local endpoint via
     137                 :         getsockname(). Readiness-agnostic; usable by any fd backend.
     138                 : 
     139                 :         @param ep The endpoint to bind to.
     140                 :         @return Error code on failure, empty on success.
     141                 :     */
     142             270 :     std::error_code do_bind(Endpoint const& ep) noexcept
     143                 :     {
     144             270 :         sockaddr_storage storage{};
     145             270 :         socklen_t addrlen = to_sockaddr(ep, socket_family(fd_), storage);
     146             270 :         if (::bind(fd_, reinterpret_cast<sockaddr*>(&storage), addrlen) != 0)
     147              20 :             return make_err(errno);
     148                 : 
     149             250 :         sockaddr_storage local_storage{};
     150             250 :         socklen_t local_len = sizeof(local_storage);
     151             250 :         if (::getsockname(
     152             250 :                 fd_, reinterpret_cast<sockaddr*>(&local_storage), &local_len) ==
     153                 :             0)
     154             189 :             local_endpoint_ =
     155             250 :                 from_sockaddr_as(local_storage, local_len, Endpoint{});
     156                 : 
     157             250 :         return {};
     158                 :     }
     159                 : };
     160                 : 
     161                 : } // namespace boost::corosio::detail
     162                 : 
     163                 : #endif // BOOST_COROSIO_NATIVE_DETAIL_NATIVE_SOCKET_BASE_HPP
        

Generated by: LCOV version 2.3