100.00% Lines (41/41) 100.00% Functions (11/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   #include <tuple> 21   #include <tuple>
22   22  
23   #include <errno.h> 23   #include <errno.h>
24   #include <netinet/in.h> 24   #include <netinet/in.h>
25   #include <sys/socket.h> 25   #include <sys/socket.h>
26   26  
27   /* epoll backend traits. 27   /* epoll backend traits.
28   28  
29   Captures the platform-specific behavior of the Linux epoll backend: 29   Captures the platform-specific behavior of the Linux epoll backend:
30   atomic SOCK_NONBLOCK|SOCK_CLOEXEC on socket(), accept4() for 30   atomic SOCK_NONBLOCK|SOCK_CLOEXEC on socket(), accept4() for
31   accepted connections, and sendmsg(MSG_NOSIGNAL) for writes. 31   accepted connections, and sendmsg(MSG_NOSIGNAL) for writes.
32   */ 32   */
33   33  
34   namespace boost::corosio::detail { 34   namespace boost::corosio::detail {
35   35  
36   class epoll_scheduler; 36   class epoll_scheduler;
37   37  
38   struct epoll_traits 38   struct epoll_traits
39   { 39   {
40 - using scheduler_type = epoll_scheduler; 40 + using scheduler_type = epoll_scheduler;
41 - using desc_state_type = reactor_descriptor_state; 41 + using desc_state_type = reactor_descriptor_state;
42   42  
43   static constexpr bool needs_write_notification = false; 43   static constexpr bool needs_write_notification = false;
44   44  
45   // No extra per-socket state or lifecycle hooks needed for epoll. 45   // No extra per-socket state or lifecycle hooks needed for epoll.
46   struct stream_socket_hook 46   struct stream_socket_hook
47   { 47   {
HITCBC 48   191 std::error_code on_set_option( 48   191 std::error_code on_set_option(
49 - int fd, 49 + int fd, int level, int optname,
50 - int level, 50 + void const* data, std::size_t size) noexcept
51 - int optname,  
52 - void const* data,  
53 - std::size_t size) noexcept  
54   { 51   {
HITCBC 55   191 if (::setsockopt( 52   191 if (::setsockopt(
ECB 56 - 191 fd, level, optname, data, static_cast<socklen_t>(size)) != 53 + fd, level, optname, data,
HITGIC 57 - 0) 54 + 191 static_cast<socklen_t>(size)) != 0)
HITCBC 58   5 return make_err(errno); 55   5 return make_err(errno);
HITCBC 59   186 return {}; 56   186 return {};
60   } 57   }
HITCBC 61   23661 static void pre_shutdown(int) noexcept {} 58   22230 static void pre_shutdown(int) noexcept {}
HITCBC 62   7697 static void pre_destroy(int) noexcept {} 59   7220 static void pre_destroy(int) noexcept {}
63   }; 60   };
64   61  
65   struct write_policy 62   struct write_policy
66   { 63   {
HITCBC 67   75 static ssize_t write(int fd, iovec* iovecs, int count) noexcept 64   75 static ssize_t write(int fd, iovec* iovecs, int count) noexcept
68   { 65   {
HITCBC 69   75 msghdr msg{}; 66   75 msghdr msg{};
HITCBC 70   75 msg.msg_iov = iovecs; 67   75 msg.msg_iov = iovecs;
HITCBC 71   75 msg.msg_iovlen = static_cast<std::size_t>(count); 68   75 msg.msg_iovlen = static_cast<std::size_t>(count);
72   69  
73   ssize_t n; 70   ssize_t n;
74   do 71   do
75   { 72   {
HITCBC 76   76 n = ::sendmsg(fd, &msg, MSG_NOSIGNAL); 73   76 n = ::sendmsg(fd, &msg, MSG_NOSIGNAL);
77   } 74   }
HITCBC 78   76 while (n < 0 && errno == EINTR); 75   76 while (n < 0 && errno == EINTR);
HITCBC 79   75 return n; 76   75 return n;
80   } 77   }
81   78  
HITGIC 82 - static ssize_t 79 + 106862 static ssize_t write_one(
ECB 83 - 107755 write_one(int fd, void const* data, std::size_t size) noexcept 80 + int fd, void const* data, std::size_t size) noexcept
84   { 81   {
85   ssize_t n; 82   ssize_t n;
86   do 83   do
87   { 84   {
HITCBC 88   107756 n = ::send(fd, data, size, MSG_NOSIGNAL); 85   106863 n = ::send(fd, data, size, MSG_NOSIGNAL);
89   } 86   }
HITCBC 90   107756 while (n < 0 && errno == EINTR); 87   106863 while (n < 0 && errno == EINTR);
HITCBC 91   107755 return n; 88   106862 return n;
92   } 89   }
93   }; 90   };
94   91  
95   struct accept_policy 92   struct accept_policy
96   { 93   {
HITGIC 97 - static int 94 + 4796 static int do_accept(
ECB 98 - 5114 do_accept(int fd, sockaddr_storage& peer, socklen_t& addrlen) noexcept 95 + int fd, sockaddr_storage& peer, socklen_t& addrlen) noexcept
99   { 96   {
HITCBC 100   5114 addrlen = sizeof(peer); 97   4796 addrlen = sizeof(peer);
101   int new_fd; 98   int new_fd;
102   do 99   do
103   { 100   {
HITCBC 104   5115 new_fd = ::accept4( 101   4797 new_fd = ::accept4(
105   fd, reinterpret_cast<sockaddr*>(&peer), &addrlen, 102   fd, reinterpret_cast<sockaddr*>(&peer), &addrlen,
106   SOCK_NONBLOCK | SOCK_CLOEXEC); 103   SOCK_NONBLOCK | SOCK_CLOEXEC);
107   } 104   }
HITCBC 108   5115 while (new_fd < 0 && errno == EINTR); 105   4797 while (new_fd < 0 && errno == EINTR);
HITCBC 109   5114 return new_fd; 106   4796 return new_fd;
110   } 107   }
111   }; 108   };
112   109  
113   // Create a nonblocking, close-on-exec socket using Linux's atomic flags. 110   // Create a nonblocking, close-on-exec socket using Linux's atomic flags.
HITCBC 114   3190 static int create_socket(int family, int type, int protocol) noexcept 111   3031 static int create_socket(int family, int type, int protocol) noexcept
115   { 112   {
HITCBC 116   3190 return ::socket(family, type | SOCK_NONBLOCK | SOCK_CLOEXEC, protocol); 113   3031 return ::socket(family, type | SOCK_NONBLOCK | SOCK_CLOEXEC, protocol);
117   } 114   }
118   115  
119   // Apply protocol-specific options after socket creation. 116   // Apply protocol-specific options after socket creation.
120   // For IP sockets, sets IPV6_V6ONLY on AF_INET6 (best-effort). 117   // For IP sockets, sets IPV6_V6ONLY on AF_INET6 (best-effort).
ECB 121 - 2723 static std::error_code configure_ip_socket(int fd, int family) noexcept 118 + static std::error_code
HITGNC   119 + 2564 configure_ip_socket(int fd, int family) noexcept
122   { 120   {
HITCBC 123   2723 if (family == AF_INET6) 121   2564 if (family == AF_INET6)
124   { 122   {
HITCBC 125   22 int one = 1; 123   22 int one = 1;
HITGIC 126 - std::ignore = 124 + 44 std::ignore = ::setsockopt(
HITCBC 127 - 22 ::setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &one, sizeof(one)); 125 + 22 fd, IPPROTO_IPV6, IPV6_V6ONLY, &one, sizeof(one));
128   } 126   }
HITCBC 129   2723 return {}; 127   2564 return {};
130   } 128   }
131   129  
132   // Apply protocol-specific options for acceptor sockets. 130   // Apply protocol-specific options for acceptor sockets.
133   // For IP acceptors, sets IPV6_V6ONLY=0 (dual-stack, best-effort). 131   // For IP acceptors, sets IPV6_V6ONLY=0 (dual-stack, best-effort).
ECB 134 - 342 static std::error_code configure_ip_acceptor(int fd, int family) noexcept 132 + static std::error_code
HITGNC   133 + 342 configure_ip_acceptor(int fd, int family) noexcept
135   { 134   {
HITCBC 136   342 if (family == AF_INET6) 135   342 if (family == AF_INET6)
137   { 136   {
HITCBC 138   11 int val = 0; 137   11 int val = 0;
HITGIC 139 - std::ignore = 138 + 22 std::ignore = ::setsockopt(
HITCBC 140 - 11 ::setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &val, sizeof(val)); 139 + 11 fd, IPPROTO_IPV6, IPV6_V6ONLY, &val, sizeof(val));
141   } 140   }
HITCBC 142   342 return {}; 141   342 return {};
143   } 142   }
144   143  
145   // No extra configuration needed for local (unix) sockets on epoll. 144   // No extra configuration needed for local (unix) sockets on epoll.
ECB 146 - 116 static std::error_code configure_local_socket(int /*fd*/) noexcept 145 + static std::error_code
HITGNC   146 + 116 configure_local_socket(int /*fd*/) noexcept
147   { 147   {
HITCBC 148   116 return {}; 148   116 return {};
149   } 149   }
150   150  
151   // Non-mutating validation for fds adopted via assign(). Used when 151   // Non-mutating validation for fds adopted via assign(). Used when
152   // the caller retains fd ownership responsibility. 152   // the caller retains fd ownership responsibility.
ECB 153 - 168 static std::error_code validate_assigned_fd(int /*fd*/) noexcept 153 + static std::error_code
HITGNC   154 + 168 validate_assigned_fd(int /*fd*/) noexcept
154   { 155   {
HITCBC 155   168 return {}; 156   168 return {};
156   } 157   }
157   }; 158   };
158   159  
159   } // namespace boost::corosio::detail 160   } // namespace boost::corosio::detail
160   161  
161   #endif // BOOST_COROSIO_HAS_EPOLL 162   #endif // BOOST_COROSIO_HAS_EPOLL
162   163  
163   #endif // BOOST_COROSIO_NATIVE_DETAIL_EPOLL_EPOLL_TRAITS_HPP 164   #endif // BOOST_COROSIO_NATIVE_DETAIL_EPOLL_EPOLL_TRAITS_HPP