LCOV - code coverage report
Current view: top level - corosio/native/detail/reactor - reactor_service_finals.hpp (source / functions) Coverage Total Hit
Test: coverage_remapped.info Lines: 100.0 % 125 125
Test Date: 2026-10-08 17:58:26 Functions: 100.0 % 78 78

           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_REACTOR_REACTOR_SERVICE_FINALS_HPP
      11                 : #define BOOST_COROSIO_NATIVE_DETAIL_REACTOR_REACTOR_SERVICE_FINALS_HPP
      12                 : 
      13                 : /* Parameterized service implementation bases for reactor backends.
      14                 : 
      15                 :    One template per protocol (TCP, local stream, UDP, local datagram,
      16                 :    acceptor). Named per-backend classes (e.g. epoll_tcp_service) inherit
      17                 :    from these as final. The Derived parameter (CRTP) flows through to
      18                 :    reactor_socket_service so construct() creates the correct named type.
      19                 : */
      20                 : 
      21                 : #include <boost/corosio/native/detail/reactor/reactor_socket_finals.hpp>
      22                 : #include <boost/corosio/native/detail/reactor/reactor_socket_service.hpp>
      23                 : #include <boost/corosio/native/detail/reactor/reactor_acceptor_service.hpp>
      24                 : #include <boost/corosio/detail/tcp_service.hpp>
      25                 : #include <boost/corosio/detail/tcp_acceptor_service.hpp>
      26                 : #include <boost/corosio/detail/udp_service.hpp>
      27                 : #include <boost/corosio/detail/local_stream_service.hpp>
      28                 : #include <boost/corosio/detail/local_stream_acceptor_service.hpp>
      29                 : #include <boost/corosio/detail/local_datagram_service.hpp>
      30                 : 
      31                 : #include <boost/corosio/native/detail/endpoint_convert.hpp>
      32                 : #include <boost/corosio/native/detail/make_err.hpp>
      33                 : #include <boost/corosio/native/detail/validate_fd.hpp>
      34                 : 
      35                 : #include <system_error>
      36                 : #include <type_traits>
      37                 : 
      38                 : #include <sys/socket.h>
      39                 : #include <unistd.h>
      40                 : 
      41                 : namespace boost::corosio::detail {
      42                 : 
      43                 : // ============================================================
      44                 : // Shared socket creation helpers
      45                 : // ============================================================
      46                 : 
      47                 : template<class Traits, class SocketFinal>
      48                 : std::error_code
      49 HIT        5189 : do_open_socket(
      50                 :     SocketFinal* socket_impl,
      51                 :     int family,
      52                 :     int type,
      53                 :     int protocol,
      54                 :     bool is_ip) noexcept
      55                 : {
      56            5189 :     socket_impl->close_socket();
      57                 : 
      58            5189 :     int fd = Traits::create_socket(family, type, protocol);
      59            5189 :     if (fd < 0)
      60               6 :         return make_err(errno);
      61                 : 
      62            5183 :     std::error_code ec = is_ip ? Traits::configure_ip_socket(fd, family)
      63             142 :                                : Traits::configure_local_socket(fd);
      64                 : 
      65            5183 :     if (ec)
      66                 :     {
      67               4 :         ::close(fd);
      68               4 :         return ec;
      69                 :     }
      70                 : 
      71            5179 :     if (auto ec = socket_impl->init_and_register(fd))
      72                 :     {
      73               2 :         ::close(fd);
      74               2 :         return ec;
      75                 :     }
      76            5177 :     return {};
      77                 : }
      78                 : 
      79                 : template<class Traits, class SocketFinal>
      80                 : std::error_code
      81             348 : do_assign_fd(
      82                 :     SocketFinal* socket_impl, int fd, int expected_type, bool is_ip) noexcept
      83                 : {
      84                 :     // The public assign() guarantees the object is closed.
      85             348 :     if (auto ec = validate_socket_fd(fd, expected_type, is_ip))
      86              48 :         return ec;
      87                 : 
      88                 :     // Adopt-only: do not mutate the caller's fd flags. Callers
      89                 :     // pass fds they have already configured (e.g., from socketpair
      90                 :     // or SCM_RIGHTS). Only non-mutating validation is performed.
      91             300 :     if (auto ec = Traits::validate_assigned_fd(fd))
      92               1 :         return ec;
      93                 : 
      94             299 :     if (auto ec = socket_impl->init_and_register(fd))
      95               1 :         return ec;
      96                 : 
      97                 :     // Best-effort: refresh endpoint caches.
      98                 :     using endpoint_type =
      99                 :         std::remove_cvref_t<decltype(socket_impl->local_endpoint())>;
     100                 : 
     101             298 :     endpoint_type local_ep{};
     102             298 :     sockaddr_storage local_storage{};
     103             298 :     socklen_t local_len = sizeof(local_storage);
     104             298 :     if (::getsockname(
     105             298 :             fd, reinterpret_cast<sockaddr*>(&local_storage), &local_len) == 0)
     106             298 :         local_ep = from_sockaddr_as(local_storage, local_len, endpoint_type{});
     107                 : 
     108             298 :     endpoint_type remote_ep{};
     109             298 :     sockaddr_storage peer_storage{};
     110             298 :     socklen_t peer_len = sizeof(peer_storage);
     111             298 :     if (::getpeername(
     112             298 :             fd, reinterpret_cast<sockaddr*>(&peer_storage), &peer_len) == 0)
     113             294 :         remote_ep = from_sockaddr_as(peer_storage, peer_len, endpoint_type{});
     114                 : 
     115             298 :     socket_impl->set_endpoints(local_ep, remote_ep);
     116                 : 
     117             298 :     return {};
     118                 : }
     119                 : 
     120                 : template<class Traits, class AccFinal>
     121                 : std::error_code
     122             733 : do_open_acceptor(
     123                 :     AccFinal* acc_impl, int family, int type, int protocol, bool is_ip) noexcept
     124                 : {
     125             733 :     acc_impl->close_socket();
     126                 : 
     127             733 :     int fd = Traits::create_socket(family, type, protocol);
     128             733 :     if (fd < 0)
     129               9 :         return make_err(errno);
     130                 : 
     131             724 :     std::error_code ec = is_ip ? Traits::configure_ip_acceptor(fd, family)
     132              85 :                                : Traits::configure_local_socket(fd);
     133                 : 
     134             724 :     if (ec)
     135                 :     {
     136               4 :         ::close(fd);
     137               4 :         return ec;
     138                 :     }
     139                 : 
     140             720 :     acc_impl->init_acceptor_fd(fd);
     141             720 :     return {};
     142                 : }
     143                 : 
     144                 : // Acceptor twin of do_assign_fd: always SOCK_STREAM, and refreshes
     145                 : // only the local endpoint because listeners have no peer. Listen
     146                 : // state is not verified; accept() surfaces the error naturally if
     147                 : // the descriptor is not listening.
     148                 : template<class Traits, class AccFinal>
     149                 : std::error_code
     150              23 : do_assign_acceptor_fd(AccFinal* acc_impl, int fd, bool is_ip) noexcept
     151                 : {
     152                 :     // The public assign() guarantees the object is closed.
     153              23 :     if (auto ec = validate_socket_fd(fd, SOCK_STREAM, is_ip))
     154               8 :         return ec;
     155                 : 
     156              15 :     if (auto ec = Traits::validate_assigned_fd(fd))
     157               1 :         return ec;
     158                 : 
     159              14 :     if (auto ec = acc_impl->init_and_register(fd))
     160               1 :         return ec;
     161                 : 
     162                 :     using endpoint_type =
     163                 :         std::remove_cvref_t<decltype(acc_impl->local_endpoint())>;
     164                 : 
     165              13 :     endpoint_type local_ep{};
     166              13 :     sockaddr_storage local_storage{};
     167              13 :     socklen_t local_len = sizeof(local_storage);
     168              13 :     if (::getsockname(
     169              13 :             fd, reinterpret_cast<sockaddr*>(&local_storage), &local_len) == 0)
     170              13 :         local_ep = from_sockaddr_as(local_storage, local_len, endpoint_type{});
     171                 : 
     172              13 :     acc_impl->set_local_endpoint(local_ep);
     173                 : 
     174              13 :     return {};
     175                 : }
     176                 : 
     177                 : // ============================================================
     178                 : // TCP service
     179                 : // ============================================================
     180                 : 
     181                 : template<class Derived, class Traits, class SocketFinal>
     182                 : class reactor_tcp_service_impl
     183                 :     : public reactor_socket_service<
     184                 :           Derived,
     185                 :           tcp_service,
     186                 :           typename Traits::scheduler_type,
     187                 :           SocketFinal>
     188                 : {
     189                 :     using base_service = reactor_socket_service<
     190                 :         Derived,
     191                 :         tcp_service,
     192                 :         typename Traits::scheduler_type,
     193                 :         SocketFinal>;
     194                 :     friend Derived;
     195                 :     friend base_service;
     196                 : 
     197             751 :     explicit reactor_tcp_service_impl(capy::execution_context& ctx)
     198             751 :         : base_service(ctx)
     199                 :     {
     200             751 :     }
     201                 : 
     202                 : public:
     203                 :     static constexpr bool needs_park_notification =
     204                 :         Traits::needs_park_notification;
     205                 : 
     206            4722 :     std::error_code open_socket(
     207                 :         tcp_socket::implementation& impl,
     208                 :         int family,
     209                 :         int type,
     210                 :         int protocol) override
     211                 :     {
     212            4722 :         return do_open_socket<Traits>(
     213            4722 :             static_cast<SocketFinal*>(&impl), family, type, protocol, true);
     214                 :     }
     215                 : 
     216              23 :     std::error_code assign_socket(
     217                 :         tcp_socket::implementation& impl, native_handle_type fd) override
     218                 :     {
     219              23 :         return do_assign_fd<Traits>(
     220              23 :             static_cast<SocketFinal*>(&impl), fd, SOCK_STREAM, true);
     221                 :     }
     222                 : 
     223                 :     std::error_code
     224              19 :     bind_socket(tcp_socket::implementation& impl, endpoint ep) override
     225                 :     {
     226              19 :         return static_cast<SocketFinal*>(&impl)->do_bind(ep);
     227                 :     }
     228                 : 
     229               9 :     void pre_shutdown(SocketFinal* impl) noexcept
     230                 :     {
     231               9 :         impl->hook_.pre_shutdown(impl->native_handle());
     232               9 :     }
     233                 : 
     234           14102 :     void pre_destroy(SocketFinal* impl) noexcept
     235                 :     {
     236           14102 :         impl->hook_.pre_destroy(impl->native_handle());
     237           14102 :     }
     238                 : };
     239                 : 
     240                 : // ============================================================
     241                 : // Local stream service
     242                 : // ============================================================
     243                 : 
     244                 : template<class Derived, class Traits, class SocketFinal>
     245                 : class reactor_local_stream_service_impl
     246                 :     : public reactor_socket_service<
     247                 :           Derived,
     248                 :           local_stream_service,
     249                 :           typename Traits::scheduler_type,
     250                 :           SocketFinal>
     251                 : {
     252                 :     using base_service = reactor_socket_service<
     253                 :         Derived,
     254                 :         local_stream_service,
     255                 :         typename Traits::scheduler_type,
     256                 :         SocketFinal>;
     257                 :     friend Derived;
     258                 :     friend base_service;
     259                 : 
     260             211 :     explicit reactor_local_stream_service_impl(capy::execution_context& ctx)
     261             211 :         : base_service(ctx)
     262                 :     {
     263             211 :     }
     264                 : 
     265                 : public:
     266                 :     static constexpr bool needs_park_notification =
     267                 :         Traits::needs_park_notification;
     268                 : 
     269              51 :     std::error_code open_socket(
     270                 :         local_stream_socket::implementation& impl,
     271                 :         int family,
     272                 :         int type,
     273                 :         int protocol) override
     274                 :     {
     275              51 :         return do_open_socket<Traits>(
     276              51 :             static_cast<SocketFinal*>(&impl), family, type, protocol, false);
     277                 :     }
     278                 : 
     279             171 :     std::error_code assign_socket(
     280                 :         local_stream_socket::implementation& impl,
     281                 :         native_handle_type fd) override
     282                 :     {
     283             171 :         return do_assign_fd<Traits>(
     284             171 :             static_cast<SocketFinal*>(&impl), fd, SOCK_STREAM, false);
     285                 :     }
     286                 : };
     287                 : 
     288                 : // ============================================================
     289                 : // UDP service
     290                 : // ============================================================
     291                 : 
     292                 : template<class Derived, class Traits, class SocketFinal>
     293                 : class reactor_udp_service_impl
     294                 :     : public reactor_socket_service<
     295                 :           Derived,
     296                 :           udp_service,
     297                 :           typename Traits::scheduler_type,
     298                 :           SocketFinal>
     299                 : {
     300                 :     using base_service = reactor_socket_service<
     301                 :         Derived,
     302                 :         udp_service,
     303                 :         typename Traits::scheduler_type,
     304                 :         SocketFinal>;
     305                 :     friend Derived;
     306                 :     friend base_service;
     307                 : 
     308             250 :     explicit reactor_udp_service_impl(capy::execution_context& ctx)
     309             250 :         : base_service(ctx)
     310                 :     {
     311             250 :     }
     312                 : 
     313                 : public:
     314                 :     static constexpr bool needs_park_notification =
     315                 :         Traits::needs_park_notification;
     316                 : 
     317             325 :     std::error_code open_datagram_socket(
     318                 :         udp_socket::implementation& impl,
     319                 :         int family,
     320                 :         int type,
     321                 :         int protocol) override
     322                 :     {
     323             325 :         return do_open_socket<Traits>(
     324             325 :             static_cast<SocketFinal*>(&impl), family, type, protocol, true);
     325                 :     }
     326                 : 
     327              14 :     std::error_code assign_socket(
     328                 :         udp_socket::implementation& impl, native_handle_type fd) override
     329                 :     {
     330              14 :         return do_assign_fd<Traits>(
     331              14 :             static_cast<SocketFinal*>(&impl), fd, SOCK_DGRAM, true);
     332                 :     }
     333                 : 
     334                 :     std::error_code
     335             183 :     bind_datagram(udp_socket::implementation& impl, endpoint ep) override
     336                 :     {
     337             183 :         return static_cast<SocketFinal*>(&impl)->do_bind(ep);
     338                 :     }
     339                 : };
     340                 : 
     341                 : // ============================================================
     342                 : // Local datagram service
     343                 : // ============================================================
     344                 : 
     345                 : template<class Derived, class Traits, class SocketFinal>
     346                 : class reactor_local_dgram_service_impl
     347                 :     : public reactor_socket_service<
     348                 :           Derived,
     349                 :           local_datagram_service,
     350                 :           typename Traits::scheduler_type,
     351                 :           SocketFinal>
     352                 : {
     353                 :     using base_service = reactor_socket_service<
     354                 :         Derived,
     355                 :         local_datagram_service,
     356                 :         typename Traits::scheduler_type,
     357                 :         SocketFinal>;
     358                 :     friend Derived;
     359                 :     friend base_service;
     360                 : 
     361             157 :     explicit reactor_local_dgram_service_impl(capy::execution_context& ctx)
     362             157 :         : base_service(ctx)
     363                 :     {
     364             157 :     }
     365                 : 
     366                 : public:
     367                 :     static constexpr bool needs_park_notification =
     368                 :         Traits::needs_park_notification;
     369                 : 
     370              91 :     std::error_code open_socket(
     371                 :         local_datagram_socket::implementation& impl,
     372                 :         int family,
     373                 :         int type,
     374                 :         int protocol) override
     375                 :     {
     376              91 :         return do_open_socket<Traits>(
     377              91 :             static_cast<SocketFinal*>(&impl), family, type, protocol, false);
     378                 :     }
     379                 : 
     380             140 :     std::error_code assign_socket(
     381                 :         local_datagram_socket::implementation& impl,
     382                 :         native_handle_type fd) override
     383                 :     {
     384             140 :         return do_assign_fd<Traits>(
     385             140 :             static_cast<SocketFinal*>(&impl), fd, SOCK_DGRAM, false);
     386                 :     }
     387                 : 
     388              68 :     std::error_code bind_socket(
     389                 :         local_datagram_socket::implementation& impl,
     390                 :         corosio::local_endpoint ep) override
     391                 :     {
     392              68 :         return static_cast<SocketFinal*>(&impl)->do_bind(ep);
     393                 :     }
     394                 : };
     395                 : 
     396                 : // ============================================================
     397                 : // Acceptor service
     398                 : // ============================================================
     399                 : 
     400                 : template<
     401                 :     class Derived,
     402                 :     class Traits,
     403                 :     class ServiceBase,
     404                 :     class AccFinal,
     405                 :     class StreamServiceFinal,
     406                 :     class Endpoint>
     407                 : class reactor_acceptor_service_impl
     408                 :     : public reactor_acceptor_service<
     409                 :           Derived,
     410                 :           ServiceBase,
     411                 :           typename Traits::scheduler_type,
     412                 :           AccFinal,
     413                 :           StreamServiceFinal>
     414                 : {
     415                 :     using base_service = reactor_acceptor_service<
     416                 :         Derived,
     417                 :         ServiceBase,
     418                 :         typename Traits::scheduler_type,
     419                 :         AccFinal,
     420                 :         StreamServiceFinal>;
     421                 :     friend Derived;
     422                 :     friend base_service;
     423                 : 
     424             710 :     explicit reactor_acceptor_service_impl(capy::execution_context& ctx)
     425             710 :         : base_service(ctx)
     426                 :     {
     427                 :         // The acceptor hands accepted fds to the stream service, so
     428                 :         // get-or-create it: with services created on first use it may
     429                 :         // not exist yet when the acceptor service comes up.
     430             710 :         this->stream_svc_ =
     431             710 :             &this->ctx_.template use_service<StreamServiceFinal>();
     432             710 :     }
     433                 : 
     434                 : public:
     435                 :     static constexpr bool needs_park_notification =
     436                 :         Traits::needs_park_notification;
     437                 : 
     438             733 :     std::error_code open_acceptor_socket(
     439                 :         typename AccFinal::impl_base_type& impl,
     440                 :         int family,
     441                 :         int type,
     442                 :         int protocol) override
     443                 :     {
     444             733 :         return do_open_acceptor<Traits>(
     445                 :             static_cast<AccFinal*>(&impl), family, type, protocol,
     446             733 :             std::is_same_v<Endpoint, endpoint>);
     447                 :     }
     448                 : 
     449              23 :     std::error_code assign_socket(
     450                 :         typename AccFinal::impl_base_type& impl, native_handle_type fd) override
     451                 :     {
     452              23 :         return do_assign_acceptor_fd<Traits>(
     453                 :             static_cast<AccFinal*>(&impl), fd,
     454              23 :             std::is_same_v<Endpoint, endpoint>);
     455                 :     }
     456                 : 
     457                 :     std::error_code
     458             692 :     bind_acceptor(typename AccFinal::impl_base_type& impl, Endpoint ep) override
     459                 :     {
     460             692 :         return static_cast<AccFinal*>(&impl)->do_bind(ep);
     461                 :     }
     462                 : 
     463             648 :     std::error_code listen_acceptor(
     464                 :         typename AccFinal::impl_base_type& impl, int backlog) override
     465                 :     {
     466             648 :         return static_cast<AccFinal*>(&impl)->do_listen(backlog);
     467                 :     }
     468                 : };
     469                 : 
     470                 : } // namespace boost::corosio::detail
     471                 : 
     472                 : #endif // BOOST_COROSIO_NATIVE_DETAIL_REACTOR_REACTOR_SERVICE_FINALS_HPP
        

Generated by: LCOV version 2.3