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-04-13 22:45:57 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         228 :     explicit select_udp_service(capy::execution_context& ctx)
      52             228 :         : reactor_socket_service(ctx)
      53                 :     {
      54             228 :     }
      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              43 : inline select_udp_socket::select_udp_socket(select_udp_service& svc) noexcept
     143              43 :     : reactor_datagram_socket(svc)
     144                 : {
     145              43 : }
     146                 : 
     147              43 : 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                 :     int flags,
     158                 :     std::stop_token token,
     159                 :     std::error_code* ec,
     160                 :     std::size_t* bytes_out)
     161                 : {
     162              11 :     auto result = do_send_to(h, ex, buf, dest, flags, token, ec, bytes_out);
     163              11 :     if (result == std::noop_coroutine())
     164               8 :         svc_.scheduler().notify_reactor();
     165              11 :     return result;
     166                 : }
     167                 : 
     168                 : inline std::coroutine_handle<>
     169              16 : select_udp_socket::recv_from(
     170                 :     std::coroutine_handle<> h,
     171                 :     capy::executor_ref ex,
     172                 :     buffer_param buf,
     173                 :     endpoint* source,
     174                 :     int flags,
     175                 :     std::stop_token token,
     176                 :     std::error_code* ec,
     177                 :     std::size_t* bytes_out)
     178                 : {
     179              16 :     return do_recv_from(h, ex, buf, source, flags, token, ec, bytes_out);
     180                 : }
     181                 : 
     182                 : // Connected-mode I/O
     183                 : 
     184                 : inline std::coroutine_handle<>
     185               6 : select_udp_socket::connect(
     186                 :     std::coroutine_handle<> h,
     187                 :     capy::executor_ref ex,
     188                 :     endpoint ep,
     189                 :     std::stop_token token,
     190                 :     std::error_code* ec)
     191                 : {
     192               6 :     auto result = do_connect(h, ex, ep, token, ec);
     193               6 :     if (result == std::noop_coroutine())
     194               5 :         svc_.scheduler().notify_reactor();
     195               6 :     return result;
     196                 : }
     197                 : 
     198                 : inline std::coroutine_handle<>
     199               3 : select_udp_socket::send(
     200                 :     std::coroutine_handle<> h,
     201                 :     capy::executor_ref ex,
     202                 :     buffer_param buf,
     203                 :     int flags,
     204                 :     std::stop_token token,
     205                 :     std::error_code* ec,
     206                 :     std::size_t* bytes_out)
     207                 : {
     208               3 :     auto result = do_send(h, ex, buf, flags, token, ec, bytes_out);
     209               3 :     if (result == std::noop_coroutine())
     210 MIS           0 :         svc_.scheduler().notify_reactor();
     211 HIT           3 :     return result;
     212                 : }
     213                 : 
     214                 : inline std::coroutine_handle<>
     215               2 : select_udp_socket::recv(
     216                 :     std::coroutine_handle<> h,
     217                 :     capy::executor_ref ex,
     218                 :     buffer_param buf,
     219                 :     int flags,
     220                 :     std::stop_token token,
     221                 :     std::error_code* ec,
     222                 :     std::size_t* bytes_out)
     223                 : {
     224               2 :     return do_recv(h, ex, buf, flags, token, ec, bytes_out);
     225                 : }
     226                 : 
     227                 : inline endpoint
     228               2 : select_udp_socket::remote_endpoint() const noexcept
     229                 : {
     230               2 :     return reactor_datagram_socket::remote_endpoint();
     231                 : }
     232                 : 
     233                 : inline void
     234               2 : select_udp_socket::cancel() noexcept
     235                 : {
     236               2 :     do_cancel();
     237               2 : }
     238                 : 
     239                 : inline void
     240             166 : select_udp_socket::close_socket() noexcept
     241                 : {
     242             166 :     do_close_socket();
     243             166 : }
     244                 : 
     245                 : inline std::error_code
     246              40 : select_udp_service::open_datagram_socket(
     247                 :     udp_socket::implementation& impl, int family, int type, int protocol)
     248                 : {
     249              40 :     auto* select_impl = static_cast<select_udp_socket*>(&impl);
     250              40 :     select_impl->close_socket();
     251                 : 
     252              40 :     int fd = ::socket(family, type, protocol);
     253              40 :     if (fd < 0)
     254 MIS           0 :         return make_err(errno);
     255                 : 
     256 HIT          40 :     if (family == AF_INET6)
     257                 :     {
     258               7 :         int one = 1;
     259               7 :         ::setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &one, sizeof(one));
     260                 :     }
     261                 : 
     262              40 :     int flags = ::fcntl(fd, F_GETFL, 0);
     263              40 :     if (flags == -1)
     264                 :     {
     265 MIS           0 :         int errn = errno;
     266               0 :         ::close(fd);
     267               0 :         return make_err(errn);
     268                 :     }
     269 HIT          40 :     if (::fcntl(fd, F_SETFL, flags | O_NONBLOCK) == -1)
     270                 :     {
     271 MIS           0 :         int errn = errno;
     272               0 :         ::close(fd);
     273               0 :         return make_err(errn);
     274                 :     }
     275 HIT          40 :     if (::fcntl(fd, F_SETFD, FD_CLOEXEC) == -1)
     276                 :     {
     277 MIS           0 :         int errn = errno;
     278               0 :         ::close(fd);
     279               0 :         return make_err(errn);
     280                 :     }
     281                 : 
     282 HIT          40 :     if (fd >= FD_SETSIZE)
     283                 :     {
     284 MIS           0 :         ::close(fd);
     285               0 :         return make_err(EMFILE);
     286                 :     }
     287                 : 
     288                 : #ifdef SO_NOSIGPIPE
     289                 :     {
     290                 :         int one = 1;
     291                 :         ::setsockopt(fd, SOL_SOCKET, SO_NOSIGPIPE, &one, sizeof(one));
     292                 :     }
     293                 : #endif
     294                 : 
     295 HIT          40 :     select_impl->fd_ = fd;
     296                 : 
     297              40 :     select_impl->desc_state_.fd = fd;
     298                 :     {
     299              40 :         std::lock_guard lock(select_impl->desc_state_.mutex);
     300              40 :         select_impl->desc_state_.read_op    = nullptr;
     301              40 :         select_impl->desc_state_.write_op   = nullptr;
     302              40 :         select_impl->desc_state_.connect_op = nullptr;
     303              40 :     }
     304              40 :     scheduler().register_descriptor(fd, &select_impl->desc_state_);
     305                 : 
     306              40 :     return {};
     307                 : }
     308                 : 
     309                 : inline std::error_code
     310              24 : select_udp_service::bind_datagram(udp_socket::implementation& impl, endpoint ep)
     311                 : {
     312              24 :     return static_cast<select_udp_socket*>(&impl)->do_bind(ep);
     313                 : }
     314                 : 
     315                 : } // namespace boost::corosio::detail
     316                 : 
     317                 : #endif // BOOST_COROSIO_HAS_SELECT
     318                 : 
     319                 : #endif // BOOST_COROSIO_NATIVE_DETAIL_SELECT_SELECT_UDP_SERVICE_HPP
        

Generated by: LCOV version 2.3