LCOV - code coverage report
Current view: top level - corosio/native/detail/select - select_udp_service.hpp (source / functions) Coverage Total Hit Missed
Test: coverage_remapped.info Lines: 68.2 % 107 73 34
Test Date: 2026-03-17 15:52:49 Functions: 78.3 % 23 18 5

           TLA  Line data    Source code
       1                 : //
       2                 : // Copyright (c) 2026 Steve Gerbino
       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_SELECT_SELECT_UDP_SERVICE_HPP
      11                 : #define BOOST_COROSIO_NATIVE_DETAIL_SELECT_SELECT_UDP_SERVICE_HPP
      12                 : 
      13                 : #include <boost/corosio/detail/platform.hpp>
      14                 : 
      15                 : #if BOOST_COROSIO_HAS_SELECT
      16                 : 
      17                 : #include <boost/corosio/detail/config.hpp>
      18                 : #include <boost/corosio/detail/udp_service.hpp>
      19                 : 
      20                 : #include <boost/corosio/native/detail/select/select_udp_socket.hpp>
      21                 : #include <boost/corosio/native/detail/select/select_scheduler.hpp>
      22                 : #include <boost/corosio/native/detail/reactor/reactor_socket_service.hpp>
      23                 : 
      24                 : #include <boost/corosio/native/detail/reactor/reactor_op_complete.hpp>
      25                 : 
      26                 : #include <coroutine>
      27                 : #include <mutex>
      28                 : 
      29                 : #include <errno.h>
      30                 : #include <fcntl.h>
      31                 : #include <netinet/in.h>
      32                 : #include <sys/select.h>
      33                 : #include <sys/socket.h>
      34                 : #include <unistd.h>
      35                 : 
      36                 : namespace boost::corosio::detail {
      37                 : 
      38                 : /** select UDP service implementation.
      39                 : 
      40                 :     Inherits from udp_service to enable runtime polymorphism.
      41                 :     Uses key_type = udp_service for service lookup.
      42                 : */
      43                 : class BOOST_COROSIO_DECL select_udp_service final
      44                 :     : public reactor_socket_service<
      45                 :           select_udp_service,
      46                 :           udp_service,
      47                 :           select_scheduler,
      48                 :           select_udp_socket>
      49                 : {
      50                 : public:
      51 HIT         195 :     explicit select_udp_service(capy::execution_context& ctx)
      52             195 :         : reactor_socket_service(ctx)
      53                 :     {
      54             195 :     }
      55                 : 
      56                 :     std::error_code open_datagram_socket(
      57                 :         udp_socket::implementation& impl,
      58                 :         int family,
      59                 :         int type,
      60                 :         int protocol) override;
      61                 :     std::error_code
      62                 :     bind_datagram(udp_socket::implementation& impl, endpoint ep) override;
      63                 : };
      64                 : 
      65                 : // Cancellation for connectionless ops
      66                 : 
      67                 : inline void
      68 MIS           0 : select_send_to_op::cancel() noexcept
      69                 : {
      70               0 :     if (socket_impl_)
      71               0 :         socket_impl_->cancel_single_op(*this);
      72                 :     else
      73               0 :         request_cancel();
      74               0 : }
      75                 : 
      76                 : inline void
      77 HIT           1 : select_recv_from_op::cancel() noexcept
      78                 : {
      79               1 :     if (socket_impl_)
      80               1 :         socket_impl_->cancel_single_op(*this);
      81                 :     else
      82 MIS           0 :         request_cancel();
      83 HIT           1 : }
      84                 : 
      85                 : // Cancellation for connected-mode ops
      86                 : 
      87                 : inline void
      88 MIS           0 : select_udp_connect_op::cancel() noexcept
      89                 : {
      90               0 :     if (socket_impl_)
      91               0 :         socket_impl_->cancel_single_op(*this);
      92                 :     else
      93               0 :         request_cancel();
      94               0 : }
      95                 : 
      96                 : inline void
      97               0 : select_send_op::cancel() noexcept
      98                 : {
      99               0 :     if (socket_impl_)
     100               0 :         socket_impl_->cancel_single_op(*this);
     101                 :     else
     102               0 :         request_cancel();
     103               0 : }
     104                 : 
     105                 : inline void
     106               0 : select_recv_op::cancel() noexcept
     107                 : {
     108               0 :     if (socket_impl_)
     109               0 :         socket_impl_->cancel_single_op(*this);
     110                 :     else
     111               0 :         request_cancel();
     112               0 : }
     113                 : 
     114                 : // Completion handlers
     115                 : 
     116                 : inline void
     117 HIT           8 : select_datagram_op::operator()()
     118                 : {
     119               8 :     complete_io_op(*this);
     120               8 : }
     121                 : 
     122                 : inline void
     123               7 : select_recv_from_op::operator()()
     124                 : {
     125               7 :     complete_datagram_op(*this, this->source_out);
     126               7 : }
     127                 : 
     128                 : inline void
     129               5 : select_udp_connect_op::operator()()
     130                 : {
     131               5 :     complete_connect_op(*this);
     132               5 : }
     133                 : 
     134                 : inline void
     135               2 : select_recv_op::operator()()
     136                 : {
     137               2 :     complete_io_op(*this);
     138               2 : }
     139                 : 
     140                 : // Socket construction/destruction
     141                 : 
     142              39 : inline select_udp_socket::select_udp_socket(select_udp_service& svc) noexcept
     143              39 :     : reactor_datagram_socket(svc)
     144                 : {
     145              39 : }
     146                 : 
     147              39 : inline select_udp_socket::~select_udp_socket() = default;
     148                 : 
     149                 : // Connectionless I/O
     150                 : 
     151                 : inline std::coroutine_handle<>
     152              11 : select_udp_socket::send_to(
     153                 :     std::coroutine_handle<> h,
     154                 :     capy::executor_ref ex,
     155                 :     buffer_param buf,
     156                 :     endpoint dest,
     157                 :     std::stop_token token,
     158                 :     std::error_code* ec,
     159                 :     std::size_t* bytes_out)
     160                 : {
     161              11 :     auto result = do_send_to(h, ex, buf, dest, token, ec, bytes_out);
     162              11 :     if (result == std::noop_coroutine())
     163               8 :         svc_.scheduler().notify_reactor();
     164              11 :     return result;
     165                 : }
     166                 : 
     167                 : inline std::coroutine_handle<>
     168              16 : select_udp_socket::recv_from(
     169                 :     std::coroutine_handle<> h,
     170                 :     capy::executor_ref ex,
     171                 :     buffer_param buf,
     172                 :     endpoint* source,
     173                 :     std::stop_token token,
     174                 :     std::error_code* ec,
     175                 :     std::size_t* bytes_out)
     176                 : {
     177              16 :     return do_recv_from(h, ex, buf, source, token, ec, bytes_out);
     178                 : }
     179                 : 
     180                 : // Connected-mode I/O
     181                 : 
     182                 : inline std::coroutine_handle<>
     183               6 : select_udp_socket::connect(
     184                 :     std::coroutine_handle<> h,
     185                 :     capy::executor_ref ex,
     186                 :     endpoint ep,
     187                 :     std::stop_token token,
     188                 :     std::error_code* ec)
     189                 : {
     190               6 :     auto result = do_connect(h, ex, ep, token, ec);
     191               6 :     if (result == std::noop_coroutine())
     192               5 :         svc_.scheduler().notify_reactor();
     193               6 :     return result;
     194                 : }
     195                 : 
     196                 : inline std::coroutine_handle<>
     197               3 : select_udp_socket::send(
     198                 :     std::coroutine_handle<> h,
     199                 :     capy::executor_ref ex,
     200                 :     buffer_param buf,
     201                 :     std::stop_token token,
     202                 :     std::error_code* ec,
     203                 :     std::size_t* bytes_out)
     204                 : {
     205               3 :     auto result = do_send(h, ex, buf, token, ec, bytes_out);
     206               3 :     if (result == std::noop_coroutine())
     207 MIS           0 :         svc_.scheduler().notify_reactor();
     208 HIT           3 :     return result;
     209                 : }
     210                 : 
     211                 : inline std::coroutine_handle<>
     212               2 : select_udp_socket::recv(
     213                 :     std::coroutine_handle<> h,
     214                 :     capy::executor_ref ex,
     215                 :     buffer_param buf,
     216                 :     std::stop_token token,
     217                 :     std::error_code* ec,
     218                 :     std::size_t* bytes_out)
     219                 : {
     220               2 :     return do_recv(h, ex, buf, token, ec, bytes_out);
     221                 : }
     222                 : 
     223                 : inline endpoint
     224               2 : select_udp_socket::remote_endpoint() const noexcept
     225                 : {
     226               2 :     return reactor_datagram_socket::remote_endpoint();
     227                 : }
     228                 : 
     229                 : inline void
     230               2 : select_udp_socket::cancel() noexcept
     231                 : {
     232               2 :     do_cancel();
     233               2 : }
     234                 : 
     235                 : inline void
     236             152 : select_udp_socket::close_socket() noexcept
     237                 : {
     238             152 :     do_close_socket();
     239             152 : }
     240                 : 
     241                 : inline std::error_code
     242              37 : select_udp_service::open_datagram_socket(
     243                 :     udp_socket::implementation& impl, int family, int type, int protocol)
     244                 : {
     245              37 :     auto* select_impl = static_cast<select_udp_socket*>(&impl);
     246              37 :     select_impl->close_socket();
     247                 : 
     248              37 :     int fd = ::socket(family, type, protocol);
     249              37 :     if (fd < 0)
     250 MIS           0 :         return make_err(errno);
     251                 : 
     252 HIT          37 :     if (family == AF_INET6)
     253                 :     {
     254               7 :         int one = 1;
     255               7 :         ::setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &one, sizeof(one));
     256                 :     }
     257                 : 
     258              37 :     int flags = ::fcntl(fd, F_GETFL, 0);
     259              37 :     if (flags == -1)
     260                 :     {
     261 MIS           0 :         int errn = errno;
     262               0 :         ::close(fd);
     263               0 :         return make_err(errn);
     264                 :     }
     265 HIT          37 :     if (::fcntl(fd, F_SETFL, flags | O_NONBLOCK) == -1)
     266                 :     {
     267 MIS           0 :         int errn = errno;
     268               0 :         ::close(fd);
     269               0 :         return make_err(errn);
     270                 :     }
     271 HIT          37 :     if (::fcntl(fd, F_SETFD, FD_CLOEXEC) == -1)
     272                 :     {
     273 MIS           0 :         int errn = errno;
     274               0 :         ::close(fd);
     275               0 :         return make_err(errn);
     276                 :     }
     277                 : 
     278 HIT          37 :     if (fd >= FD_SETSIZE)
     279                 :     {
     280 MIS           0 :         ::close(fd);
     281               0 :         return make_err(EMFILE);
     282                 :     }
     283                 : 
     284                 : #ifdef SO_NOSIGPIPE
     285                 :     {
     286                 :         int one = 1;
     287                 :         ::setsockopt(fd, SOL_SOCKET, SO_NOSIGPIPE, &one, sizeof(one));
     288                 :     }
     289                 : #endif
     290                 : 
     291 HIT          37 :     select_impl->fd_ = fd;
     292                 : 
     293              37 :     select_impl->desc_state_.fd = fd;
     294                 :     {
     295              37 :         std::lock_guard lock(select_impl->desc_state_.mutex);
     296              37 :         select_impl->desc_state_.read_op    = nullptr;
     297              37 :         select_impl->desc_state_.write_op   = nullptr;
     298              37 :         select_impl->desc_state_.connect_op = nullptr;
     299              37 :     }
     300              37 :     scheduler().register_descriptor(fd, &select_impl->desc_state_);
     301                 : 
     302              37 :     return {};
     303                 : }
     304                 : 
     305                 : inline std::error_code
     306              21 : select_udp_service::bind_datagram(udp_socket::implementation& impl, endpoint ep)
     307                 : {
     308              21 :     return static_cast<select_udp_socket*>(&impl)->do_bind(ep);
     309                 : }
     310                 : 
     311                 : } // namespace boost::corosio::detail
     312                 : 
     313                 : #endif // BOOST_COROSIO_HAS_SELECT
     314                 : 
     315                 : #endif // BOOST_COROSIO_NATIVE_DETAIL_SELECT_SELECT_UDP_SERVICE_HPP
        

Generated by: LCOV version 2.3