79.49% Lines (31/39) 90.91% Functions (10/11)
TLA Baseline Branch
Line Hits Code Line Hits Code
1   // 1   //
2   // Copyright (c) 2026 Michael Vandeberg 2   // Copyright (c) 2026 Michael Vandeberg
3   // 3   //
4   // Distributed under the Boost Software License, Version 1.0. (See accompanying 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) 5   // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
6   // 6   //
7   // Official repository: https://github.com/cppalliance/corosio 7   // Official repository: https://github.com/cppalliance/corosio
8   // 8   //
9   9  
10   #ifndef BOOST_COROSIO_NATIVE_DETAIL_EPOLL_EPOLL_TRAITS_HPP 10   #ifndef BOOST_COROSIO_NATIVE_DETAIL_EPOLL_EPOLL_TRAITS_HPP
11   #define BOOST_COROSIO_NATIVE_DETAIL_EPOLL_EPOLL_TRAITS_HPP 11   #define BOOST_COROSIO_NATIVE_DETAIL_EPOLL_EPOLL_TRAITS_HPP
12   12  
13   #include <boost/corosio/detail/platform.hpp> 13   #include <boost/corosio/detail/platform.hpp>
14   14  
15   #if BOOST_COROSIO_HAS_EPOLL 15   #if BOOST_COROSIO_HAS_EPOLL
16   16  
17   #include <boost/corosio/native/detail/make_err.hpp> 17   #include <boost/corosio/native/detail/make_err.hpp>
18   #include <boost/corosio/native/detail/reactor/reactor_descriptor_state.hpp> 18   #include <boost/corosio/native/detail/reactor/reactor_descriptor_state.hpp>
19   19  
20   #include <system_error> 20   #include <system_error>
21   21  
22   #include <errno.h> 22   #include <errno.h>
23   #include <netinet/in.h> 23   #include <netinet/in.h>
24   #include <sys/socket.h> 24   #include <sys/socket.h>
25   25  
26   /* epoll backend traits. 26   /* epoll backend traits.
27   27  
28   Captures the platform-specific behavior of the Linux epoll backend: 28   Captures the platform-specific behavior of the Linux epoll backend:
29   atomic SOCK_NONBLOCK|SOCK_CLOEXEC on socket(), accept4() for 29   atomic SOCK_NONBLOCK|SOCK_CLOEXEC on socket(), accept4() for
30   accepted connections, and sendmsg(MSG_NOSIGNAL) for writes. 30   accepted connections, and sendmsg(MSG_NOSIGNAL) for writes.
31   */ 31   */
32   32  
33   namespace boost::corosio::detail { 33   namespace boost::corosio::detail {
34   34  
35   class epoll_scheduler; 35   class epoll_scheduler;
36   36  
37   struct epoll_traits 37   struct epoll_traits
38   { 38   {
39   using scheduler_type = epoll_scheduler; 39   using scheduler_type = epoll_scheduler;
40   using desc_state_type = reactor_descriptor_state; 40   using desc_state_type = reactor_descriptor_state;
41   41  
42   static constexpr bool needs_write_notification = false; 42   static constexpr bool needs_write_notification = false;
43   43  
44   // No extra per-socket state or lifecycle hooks needed for epoll. 44   // No extra per-socket state or lifecycle hooks needed for epoll.
45   struct stream_socket_hook 45   struct stream_socket_hook
46   { 46   {
HITCBC 47   32 std::error_code on_set_option( 47   32 std::error_code on_set_option(
48   int fd, int level, int optname, 48   int fd, int level, int optname,
49   void const* data, std::size_t size) noexcept 49   void const* data, std::size_t size) noexcept
50   { 50   {
HITCBC 51   32 if (::setsockopt( 51   32 if (::setsockopt(
52   fd, level, optname, data, 52   fd, level, optname, data,
HITCBC 53   32 static_cast<socklen_t>(size)) != 0) 53   32 static_cast<socklen_t>(size)) != 0)
MISUBC 54   return make_err(errno); 54   return make_err(errno);
HITCBC 55   32 return {}; 55   32 return {};
56   } 56   }
HITCBC 57   21710 static void pre_shutdown(int) noexcept {} 57   18753 static void pre_shutdown(int) noexcept {}
HITCBC 58   7223 static void pre_destroy(int) noexcept {} 58   6237 static void pre_destroy(int) noexcept {}
59   }; 59   };
60   60  
61   struct write_policy 61   struct write_policy
62   { 62   {
MISLBC 63   109169 static ssize_t write(int fd, iovec* iovecs, int count) noexcept 63   static ssize_t write(int fd, iovec* iovecs, int count) noexcept
64   { 64   {
MISLBC 65   109169 msghdr msg{}; 65   msghdr msg{};
MISLBC 66   109169 msg.msg_iov = iovecs; 66   msg.msg_iov = iovecs;
MISLBC 67   109169 msg.msg_iovlen = static_cast<std::size_t>(count); 67   msg.msg_iovlen = static_cast<std::size_t>(count);
68   68  
69   ssize_t n; 69   ssize_t n;
70   do 70   do
71   { 71   {
MISLBC 72   109169 n = ::sendmsg(fd, &msg, MSG_NOSIGNAL); 72   n = ::sendmsg(fd, &msg, MSG_NOSIGNAL);
73   } 73   }
MISLBC 74   109169 while (n < 0 && errno == EINTR); 74   while (n < 0 && errno == EINTR);
MISLBC 75   109169 return n; 75   return n;
76   } 76   }
  77 +
HITGNC   78 + 126459 static ssize_t write_one(
  79 + int fd, void const* data, std::size_t size) noexcept
  80 + {
  81 + ssize_t n;
  82 + do
  83 + {
HITGNC   84 + 126459 n = ::send(fd, data, size, MSG_NOSIGNAL);
  85 + }
HITGNC   86 + 126459 while (n < 0 && errno == EINTR);
HITGNC   87 + 126459 return n;
  88 + }
77   }; 89   };
78   90  
79   struct accept_policy 91   struct accept_policy
80   { 92   {
HITCBC 81   4776 static int do_accept( 93   4118 static int do_accept(
82   int fd, sockaddr_storage& peer, socklen_t& addrlen) noexcept 94   int fd, sockaddr_storage& peer, socklen_t& addrlen) noexcept
83   { 95   {
HITCBC 84   4776 addrlen = sizeof(peer); 96   4118 addrlen = sizeof(peer);
85   int new_fd; 97   int new_fd;
86   do 98   do
87   { 99   {
HITCBC 88   4776 new_fd = ::accept4( 100   4118 new_fd = ::accept4(
89   fd, reinterpret_cast<sockaddr*>(&peer), &addrlen, 101   fd, reinterpret_cast<sockaddr*>(&peer), &addrlen,
90   SOCK_NONBLOCK | SOCK_CLOEXEC); 102   SOCK_NONBLOCK | SOCK_CLOEXEC);
91   } 103   }
HITCBC 92   4776 while (new_fd < 0 && errno == EINTR); 104   4118 while (new_fd < 0 && errno == EINTR);
HITCBC 93   4776 return new_fd; 105   4118 return new_fd;
94   } 106   }
95   }; 107   };
96   108  
97   // Create a nonblocking, close-on-exec socket using Linux's atomic flags. 109   // Create a nonblocking, close-on-exec socket using Linux's atomic flags.
HITCBC 98   2565 static int create_socket(int family, int type, int protocol) noexcept 110   2237 static int create_socket(int family, int type, int protocol) noexcept
99   { 111   {
HITCBC 100   2565 return ::socket(family, type | SOCK_NONBLOCK | SOCK_CLOEXEC, protocol); 112   2237 return ::socket(family, type | SOCK_NONBLOCK | SOCK_CLOEXEC, protocol);
101   } 113   }
102   114  
103   // Apply protocol-specific options after socket creation. 115   // Apply protocol-specific options after socket creation.
104   // For IP sockets, sets IPV6_V6ONLY on AF_INET6 (best-effort). 116   // For IP sockets, sets IPV6_V6ONLY on AF_INET6 (best-effort).
105   static std::error_code 117   static std::error_code
HITCBC 106   2451 configure_ip_socket(int fd, int family) noexcept 118   2123 configure_ip_socket(int fd, int family) noexcept
107   { 119   {
HITCBC 108   2451 if (family == AF_INET6) 120   2123 if (family == AF_INET6)
109   { 121   {
HITCBC 110   14 int one = 1; 122   14 int one = 1;
HITCBC 111   14 (void)::setsockopt( 123   14 (void)::setsockopt(
112   fd, IPPROTO_IPV6, IPV6_V6ONLY, &one, sizeof(one)); 124   fd, IPPROTO_IPV6, IPV6_V6ONLY, &one, sizeof(one));
113   } 125   }
HITCBC 114   2451 return {}; 126   2123 return {};
115   } 127   }
116   128  
117   // Apply protocol-specific options for acceptor sockets. 129   // Apply protocol-specific options for acceptor sockets.
118   // For IP acceptors, sets IPV6_V6ONLY=0 (dual-stack, best-effort). 130   // For IP acceptors, sets IPV6_V6ONLY=0 (dual-stack, best-effort).
119   static std::error_code 131   static std::error_code
HITCBC 120   94 configure_ip_acceptor(int fd, int family) noexcept 132   94 configure_ip_acceptor(int fd, int family) noexcept
121   { 133   {
HITCBC 122   94 if (family == AF_INET6) 134   94 if (family == AF_INET6)
123   { 135   {
HITCBC 124   9 int val = 0; 136   9 int val = 0;
HITCBC 125   9 (void)::setsockopt( 137   9 (void)::setsockopt(
126   fd, IPPROTO_IPV6, IPV6_V6ONLY, &val, sizeof(val)); 138   fd, IPPROTO_IPV6, IPV6_V6ONLY, &val, sizeof(val));
127   } 139   }
HITCBC 128   94 return {}; 140   94 return {};
129   } 141   }
130   142  
131   // No extra configuration needed for local (unix) sockets on epoll. 143   // No extra configuration needed for local (unix) sockets on epoll.
132   static std::error_code 144   static std::error_code
HITCBC 133   20 configure_local_socket(int /*fd*/) noexcept 145   20 configure_local_socket(int /*fd*/) noexcept
134   { 146   {
HITCBC 135   20 return {}; 147   20 return {};
136   } 148   }
137   149  
138   // Non-mutating validation for fds adopted via assign(). Used when 150   // Non-mutating validation for fds adopted via assign(). Used when
139   // the caller retains fd ownership responsibility. 151   // the caller retains fd ownership responsibility.
140   static std::error_code 152   static std::error_code
HITCBC 141   14 validate_assigned_fd(int /*fd*/) noexcept 153   14 validate_assigned_fd(int /*fd*/) noexcept
142   { 154   {
HITCBC 143   14 return {}; 155   14 return {};
144   } 156   }
145   }; 157   };
146   158  
147   } // namespace boost::corosio::detail 159   } // namespace boost::corosio::detail
148   160  
149   #endif // BOOST_COROSIO_HAS_EPOLL 161   #endif // BOOST_COROSIO_HAS_EPOLL
150   162  
151   #endif // BOOST_COROSIO_NATIVE_DETAIL_EPOLL_EPOLL_TRAITS_HPP 163   #endif // BOOST_COROSIO_NATIVE_DETAIL_EPOLL_EPOLL_TRAITS_HPP