97.44% Lines (38/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   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   44 std::error_code on_set_option( 47   44 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   44 if (::setsockopt( 51   44 if (::setsockopt(
52   fd, level, optname, data, 52   fd, level, optname, data,
HITCBC 53   44 static_cast<socklen_t>(size)) != 0) 53   44 static_cast<socklen_t>(size)) != 0)
MISUBC 54   return make_err(errno); 54   return make_err(errno);
HITCBC 55   44 return {}; 55   44 return {};
56   } 56   }
HITCBC 57   34820 static void pre_shutdown(int) noexcept {} 57   20964 static void pre_shutdown(int) noexcept {}
HITCBC 58   11542 static void pre_destroy(int) noexcept {} 58   6923 static void pre_destroy(int) noexcept {}
59   }; 59   };
60   60  
61   struct write_policy 61   struct write_policy
62   { 62   {
HITCBC 63   10 static ssize_t write(int fd, iovec* iovecs, int count) noexcept 63   10 static ssize_t write(int fd, iovec* iovecs, int count) noexcept
64   { 64   {
HITCBC 65   10 msghdr msg{}; 65   10 msghdr msg{};
HITCBC 66   10 msg.msg_iov = iovecs; 66   10 msg.msg_iov = iovecs;
HITCBC 67   10 msg.msg_iovlen = static_cast<std::size_t>(count); 67   10 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   {
HITCBC 72   10 n = ::sendmsg(fd, &msg, MSG_NOSIGNAL); 72   10 n = ::sendmsg(fd, &msg, MSG_NOSIGNAL);
73   } 73   }
HITCBC 74   10 while (n < 0 && errno == EINTR); 74   10 while (n < 0 && errno == EINTR);
HITCBC 75   10 return n; 75   10 return n;
76   } 76   }
77   77  
HITCBC 78   106583 static ssize_t write_one( 78   108260 static ssize_t write_one(
79   int fd, void const* data, std::size_t size) noexcept 79   int fd, void const* data, std::size_t size) noexcept
80   { 80   {
81   ssize_t n; 81   ssize_t n;
82   do 82   do
83   { 83   {
HITCBC 84   106583 n = ::send(fd, data, size, MSG_NOSIGNAL); 84   108260 n = ::send(fd, data, size, MSG_NOSIGNAL);
85   } 85   }
HITCBC 86   106583 while (n < 0 && errno == EINTR); 86   108260 while (n < 0 && errno == EINTR);
HITCBC 87   106583 return n; 87   108260 return n;
88   } 88   }
89   }; 89   };
90   90  
91   struct accept_policy 91   struct accept_policy
92   { 92   {
HITCBC 93   7653 static int do_accept( 93   4573 static int do_accept(
94   int fd, sockaddr_storage& peer, socklen_t& addrlen) noexcept 94   int fd, sockaddr_storage& peer, socklen_t& addrlen) noexcept
95   { 95   {
HITCBC 96   7653 addrlen = sizeof(peer); 96   4573 addrlen = sizeof(peer);
97   int new_fd; 97   int new_fd;
98   do 98   do
99   { 99   {
HITCBC 100   7653 new_fd = ::accept4( 100   4573 new_fd = ::accept4(
101   fd, reinterpret_cast<sockaddr*>(&peer), &addrlen, 101   fd, reinterpret_cast<sockaddr*>(&peer), &addrlen,
102   SOCK_NONBLOCK | SOCK_CLOEXEC); 102   SOCK_NONBLOCK | SOCK_CLOEXEC);
103   } 103   }
HITCBC 104   7653 while (new_fd < 0 && errno == EINTR); 104   4573 while (new_fd < 0 && errno == EINTR);
HITCBC 105   7653 return new_fd; 105   4573 return new_fd;
106   } 106   }
107   }; 107   };
108   108  
109   // 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 110   4120 static int create_socket(int family, int type, int protocol) noexcept 110   2581 static int create_socket(int family, int type, int protocol) noexcept
111   { 111   {
HITCBC 112   4120 return ::socket(family, type | SOCK_NONBLOCK | SOCK_CLOEXEC, protocol); 112   2581 return ::socket(family, type | SOCK_NONBLOCK | SOCK_CLOEXEC, protocol);
113   } 113   }
114   114  
115   // Apply protocol-specific options after socket creation. 115   // Apply protocol-specific options after socket creation.
116   // For IP sockets, sets IPV6_V6ONLY on AF_INET6 (best-effort). 116   // For IP sockets, sets IPV6_V6ONLY on AF_INET6 (best-effort).
117   static std::error_code 117   static std::error_code
HITCBC 118   3930 configure_ip_socket(int fd, int family) noexcept 118   2391 configure_ip_socket(int fd, int family) noexcept
119   { 119   {
HITCBC 120   3930 if (family == AF_INET6) 120   2391 if (family == AF_INET6)
121   { 121   {
HITCBC 122   17 int one = 1; 122   17 int one = 1;
HITCBC 123   17 (void)::setsockopt( 123   17 (void)::setsockopt(
124   fd, IPPROTO_IPV6, IPV6_V6ONLY, &one, sizeof(one)); 124   fd, IPPROTO_IPV6, IPV6_V6ONLY, &one, sizeof(one));
125   } 125   }
HITCBC 126   3930 return {}; 126   2391 return {};
127   } 127   }
128   128  
129   // Apply protocol-specific options for acceptor sockets. 129   // Apply protocol-specific options for acceptor sockets.
130   // For IP acceptors, sets IPV6_V6ONLY=0 (dual-stack, best-effort). 130   // For IP acceptors, sets IPV6_V6ONLY=0 (dual-stack, best-effort).
131   static std::error_code 131   static std::error_code
HITCBC 132   130 configure_ip_acceptor(int fd, int family) noexcept 132   130 configure_ip_acceptor(int fd, int family) noexcept
133   { 133   {
HITCBC 134   130 if (family == AF_INET6) 134   130 if (family == AF_INET6)
135   { 135   {
HITCBC 136   9 int val = 0; 136   9 int val = 0;
HITCBC 137   9 (void)::setsockopt( 137   9 (void)::setsockopt(
138   fd, IPPROTO_IPV6, IPV6_V6ONLY, &val, sizeof(val)); 138   fd, IPPROTO_IPV6, IPV6_V6ONLY, &val, sizeof(val));
139   } 139   }
HITCBC 140   130 return {}; 140   130 return {};
141   } 141   }
142   142  
143   // No extra configuration needed for local (unix) sockets on epoll. 143   // No extra configuration needed for local (unix) sockets on epoll.
144   static std::error_code 144   static std::error_code
HITCBC 145   60 configure_local_socket(int /*fd*/) noexcept 145   60 configure_local_socket(int /*fd*/) noexcept
146   { 146   {
HITCBC 147   60 return {}; 147   60 return {};
148   } 148   }
149   149  
150   // Non-mutating validation for fds adopted via assign(). Used when 150   // Non-mutating validation for fds adopted via assign(). Used when
151   // the caller retains fd ownership responsibility. 151   // the caller retains fd ownership responsibility.
152   static std::error_code 152   static std::error_code
HITCBC 153   48 validate_assigned_fd(int /*fd*/) noexcept 153   48 validate_assigned_fd(int /*fd*/) noexcept
154   { 154   {
HITCBC 155   48 return {}; 155   48 return {};
156   } 156   }
157   }; 157   };
158   158  
159   } // namespace boost::corosio::detail 159   } // namespace boost::corosio::detail
160   160  
161   #endif // BOOST_COROSIO_HAS_EPOLL 161   #endif // BOOST_COROSIO_HAS_EPOLL
162   162  
163   #endif // BOOST_COROSIO_NATIVE_DETAIL_EPOLL_EPOLL_TRAITS_HPP 163   #endif // BOOST_COROSIO_NATIVE_DETAIL_EPOLL_EPOLL_TRAITS_HPP