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

Generated by: LCOV version 2.3