100.00% Lines (39/39) 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, int level, int optname, 49 + int fd,
50 - void const* data, std::size_t size) noexcept 50 + int level,
  51 + int optname,
  52 + void const* data,
  53 + std::size_t size) noexcept
51   { 54   {
HITCBC 52   191 if (::setsockopt( 55   191 if (::setsockopt(
HITGIC 53 - fd, level, optname, data, 56 + 191 fd, level, optname, data, static_cast<socklen_t>(size)) !=
ECB 54 - 191 static_cast<socklen_t>(size)) != 0) 57 + 0)
HITCBC 55   5 return make_err(errno); 58   5 return make_err(errno);
HITCBC 56   186 return {}; 59   186 return {};
57   } 60   }
HITCBC 58   22910 static void pre_shutdown(int) noexcept {} 61   22977 static void pre_shutdown(int) noexcept {}
HITCBC 59   7447 static void pre_destroy(int) noexcept {} 62   7469 static void pre_destroy(int) noexcept {}
60   }; 63   };
61   64  
62   struct write_policy 65   struct write_policy
63   { 66   {
HITCBC 64   75 static ssize_t write(int fd, iovec* iovecs, int count) noexcept 67   75 static ssize_t write(int fd, iovec* iovecs, int count) noexcept
65   { 68   {
HITCBC 66   75 msghdr msg{}; 69   75 msghdr msg{};
HITCBC 67   75 msg.msg_iov = iovecs; 70   75 msg.msg_iov = iovecs;
HITCBC 68   75 msg.msg_iovlen = static_cast<std::size_t>(count); 71   75 msg.msg_iovlen = static_cast<std::size_t>(count);
69   72  
70   ssize_t n; 73   ssize_t n;
71   do 74   do
72   { 75   {
HITCBC 73   76 n = ::sendmsg(fd, &msg, MSG_NOSIGNAL); 76   76 n = ::sendmsg(fd, &msg, MSG_NOSIGNAL);
74   } 77   }
HITCBC 75   76 while (n < 0 && errno == EINTR); 78   76 while (n < 0 && errno == EINTR);
HITCBC 76   75 return n; 79   75 return n;
77   } 80   }
78   81  
ECB 79 - 106917 static ssize_t write_one( 82 + static ssize_t
HITGIC 80 - int fd, void const* data, std::size_t size) noexcept 83 + 98995 write_one(int fd, void const* data, std::size_t size) noexcept
81   { 84   {
82   ssize_t n; 85   ssize_t n;
83   do 86   do
84   { 87   {
HITCBC 85   106918 n = ::send(fd, data, size, MSG_NOSIGNAL); 88   98996 n = ::send(fd, data, size, MSG_NOSIGNAL);
86   } 89   }
HITCBC 87   106918 while (n < 0 && errno == EINTR); 90   98996 while (n < 0 && errno == EINTR);
HITCBC 88   106917 return n; 91   98995 return n;
89   } 92   }
90   }; 93   };
91   94  
92   struct accept_policy 95   struct accept_policy
93   { 96   {
ECB 94 - 4948 static int do_accept( 97 + static int
HITGIC 95 - int fd, sockaddr_storage& peer, socklen_t& addrlen) noexcept 98 + 4962 do_accept(int fd, sockaddr_storage& peer, socklen_t& addrlen) noexcept
96   { 99   {
HITCBC 97   4948 addrlen = sizeof(peer); 100   4962 addrlen = sizeof(peer);
98   int new_fd; 101   int new_fd;
99   do 102   do
100   { 103   {
HITCBC 101   4949 new_fd = ::accept4( 104   4963 new_fd = ::accept4(
102   fd, reinterpret_cast<sockaddr*>(&peer), &addrlen, 105   fd, reinterpret_cast<sockaddr*>(&peer), &addrlen,
103   SOCK_NONBLOCK | SOCK_CLOEXEC); 106   SOCK_NONBLOCK | SOCK_CLOEXEC);
104   } 107   }
HITCBC 105   4949 while (new_fd < 0 && errno == EINTR); 108   4963 while (new_fd < 0 && errno == EINTR);
HITCBC 106   4948 return new_fd; 109   4962 return new_fd;
107   } 110   }
108   }; 111   };
109   112  
110   // Create a nonblocking, close-on-exec socket using Linux's atomic flags. 113   // Create a nonblocking, close-on-exec socket using Linux's atomic flags.
HITCBC 111   3106 static int create_socket(int family, int type, int protocol) noexcept 114   3114 static int create_socket(int family, int type, int protocol) noexcept
112   { 115   {
HITCBC 113   3106 return ::socket(family, type | SOCK_NONBLOCK | SOCK_CLOEXEC, protocol); 116   3114 return ::socket(family, type | SOCK_NONBLOCK | SOCK_CLOEXEC, protocol);
114   } 117   }
115   118  
116   // Apply protocol-specific options after socket creation. 119   // Apply protocol-specific options after socket creation.
117   // For IP sockets, sets IPV6_V6ONLY on AF_INET6 (best-effort). 120   // For IP sockets, sets IPV6_V6ONLY on AF_INET6 (best-effort).
HITGIC 118 - static std::error_code 121 + 2647 static std::error_code configure_ip_socket(int fd, int family) noexcept
DCB 119 - 2639 configure_ip_socket(int fd, int family) noexcept  
120   { 122   {
HITCBC 121   2639 if (family == AF_INET6) 123   2647 if (family == AF_INET6)
122   { 124   {
HITCBC 123   22 int one = 1; 125   22 int one = 1;
ECB 124 - 44 std::ignore = ::setsockopt( 126 + std::ignore =
HITCBC 125 - 22 fd, IPPROTO_IPV6, IPV6_V6ONLY, &one, sizeof(one)); 127 + 22 ::setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &one, sizeof(one));
126   } 128   }
HITCBC 127   2639 return {}; 129   2647 return {};
128   } 130   }
129   131  
130   // Apply protocol-specific options for acceptor sockets. 132   // Apply protocol-specific options for acceptor sockets.
131   // For IP acceptors, sets IPV6_V6ONLY=0 (dual-stack, best-effort). 133   // For IP acceptors, sets IPV6_V6ONLY=0 (dual-stack, best-effort).
HITGIC 132 - static std::error_code 134 + 342 static std::error_code configure_ip_acceptor(int fd, int family) noexcept
DCB 133 - 342 configure_ip_acceptor(int fd, int family) noexcept  
134   { 135   {
HITCBC 135   342 if (family == AF_INET6) 136   342 if (family == AF_INET6)
136   { 137   {
HITCBC 137   11 int val = 0; 138   11 int val = 0;
ECB 138 - 22 std::ignore = ::setsockopt( 139 + std::ignore =
HITCBC 139 - 11 fd, IPPROTO_IPV6, IPV6_V6ONLY, &val, sizeof(val)); 140 + 11 ::setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &val, sizeof(val));
140   } 141   }
HITCBC 141   342 return {}; 142   342 return {};
142   } 143   }
143   144  
144   // No extra configuration needed for local (unix) sockets on epoll. 145   // No extra configuration needed for local (unix) sockets on epoll.
HITGIC 145 - static std::error_code 146 + 116 static std::error_code configure_local_socket(int /*fd*/) noexcept
DCB 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.
HITGIC 153 - static std::error_code 153 + 168 static std::error_code validate_assigned_fd(int /*fd*/) noexcept
DCB 154 - 168 validate_assigned_fd(int /*fd*/) noexcept  
155   { 154   {
HITCBC 156   168 return {}; 155   168 return {};
157   } 156   }
158   }; 157   };
159   158  
160   } // namespace boost::corosio::detail 159   } // namespace boost::corosio::detail
161   160  
162   #endif // BOOST_COROSIO_HAS_EPOLL 161   #endif // BOOST_COROSIO_HAS_EPOLL
163   162  
164   #endif // BOOST_COROSIO_NATIVE_DETAIL_EPOLL_EPOLL_TRAITS_HPP 163   #endif // BOOST_COROSIO_NATIVE_DETAIL_EPOLL_EPOLL_TRAITS_HPP