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   155 std::error_code on_set_option( 48   184 std::error_code on_set_option(
49   int fd, int level, int optname, 49   int fd, int level, int optname,
50   void const* data, std::size_t size) noexcept 50   void const* data, std::size_t size) noexcept
51   { 51   {
HITCBC 52   155 if (::setsockopt( 52   184 if (::setsockopt(
53   fd, level, optname, data, 53   fd, level, optname, data,
HITCBC 54   155 static_cast<socklen_t>(size)) != 0) 54   184 static_cast<socklen_t>(size)) != 0)
HITCBC 55   2 return make_err(errno); 55   5 return make_err(errno);
HITCBC 56   153 return {}; 56   179 return {};
57   } 57   }
HITCBC 58   21097 static void pre_shutdown(int) noexcept {} 58   29544 static void pre_shutdown(int) noexcept {}
HITCBC 59   6912 static void pre_destroy(int) noexcept {} 59   9675 static void pre_destroy(int) noexcept {}
60   }; 60   };
61   61  
62   struct write_policy 62   struct write_policy
63   { 63   {
HITCBC 64   71 static ssize_t write(int fd, iovec* iovecs, int count) noexcept 64   75 static ssize_t write(int fd, iovec* iovecs, int count) noexcept
65   { 65   {
HITCBC 66   71 msghdr msg{}; 66   75 msghdr msg{};
HITCBC 67   71 msg.msg_iov = iovecs; 67   75 msg.msg_iov = iovecs;
HITCBC 68   71 msg.msg_iovlen = static_cast<std::size_t>(count); 68   75 msg.msg_iovlen = static_cast<std::size_t>(count);
69   69  
70   ssize_t n; 70   ssize_t n;
71   do 71   do
72   { 72   {
HITCBC 73   71 n = ::sendmsg(fd, &msg, MSG_NOSIGNAL); 73   76 n = ::sendmsg(fd, &msg, MSG_NOSIGNAL);
74   } 74   }
HITCBC 75   71 while (n < 0 && errno == EINTR); 75   76 while (n < 0 && errno == EINTR);
HITCBC 76   71 return n; 76   75 return n;
77   } 77   }
78   78  
HITCBC 79   111121 static ssize_t write_one( 79   105619 static ssize_t write_one(
80   int fd, void const* data, std::size_t size) noexcept 80   int fd, void const* data, std::size_t size) noexcept
81   { 81   {
82   ssize_t n; 82   ssize_t n;
83   do 83   do
84   { 84   {
HITCBC 85   111121 n = ::send(fd, data, size, MSG_NOSIGNAL); 85   105620 n = ::send(fd, data, size, MSG_NOSIGNAL);
86   } 86   }
HITCBC 87   111121 while (n < 0 && errno == EINTR); 87   105620 while (n < 0 && errno == EINTR);
HITCBC 88   111121 return n; 88   105619 return n;
89   } 89   }
90   }; 90   };
91   91  
92   struct accept_policy 92   struct accept_policy
93   { 93   {
HITCBC 94   4540 static int do_accept( 94   6367 static int do_accept(
95   int fd, sockaddr_storage& peer, socklen_t& addrlen) noexcept 95   int fd, sockaddr_storage& peer, socklen_t& addrlen) noexcept
96   { 96   {
HITCBC 97   4540 addrlen = sizeof(peer); 97   6367 addrlen = sizeof(peer);
98   int new_fd; 98   int new_fd;
99   do 99   do
100   { 100   {
HITCBC 101   4540 new_fd = ::accept4( 101   6368 new_fd = ::accept4(
102   fd, reinterpret_cast<sockaddr*>(&peer), &addrlen, 102   fd, reinterpret_cast<sockaddr*>(&peer), &addrlen,
103   SOCK_NONBLOCK | SOCK_CLOEXEC); 103   SOCK_NONBLOCK | SOCK_CLOEXEC);
104   } 104   }
HITCBC 105   4540 while (new_fd < 0 && errno == EINTR); 105   6368 while (new_fd < 0 && errno == EINTR);
HITCBC 106   4540 return new_fd; 106   6367 return new_fd;
107   } 107   }
108   }; 108   };
109   109  
110   // 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 111   2762 static int create_socket(int family, int type, int protocol) noexcept 111   3755 static int create_socket(int family, int type, int protocol) noexcept
112   { 112   {
HITCBC 113   2762 return ::socket(family, type | SOCK_NONBLOCK | SOCK_CLOEXEC, protocol); 113   3755 return ::socket(family, type | SOCK_NONBLOCK | SOCK_CLOEXEC, protocol);
114   } 114   }
115   115  
116   // Apply protocol-specific options after socket creation. 116   // Apply protocol-specific options after socket creation.
117   // For IP sockets, sets IPV6_V6ONLY on AF_INET6 (best-effort). 117   // For IP sockets, sets IPV6_V6ONLY on AF_INET6 (best-effort).
118   static std::error_code 118   static std::error_code
HITCBC 119   2420 configure_ip_socket(int fd, int family) noexcept 119   3357 configure_ip_socket(int fd, int family) noexcept
120   { 120   {
HITCBC 121   2420 if (family == AF_INET6) 121   3357 if (family == AF_INET6)
122   { 122   {
HITCBC 123   21 int one = 1; 123   22 int one = 1;
HITCBC 124   42 std::ignore = ::setsockopt( 124   44 std::ignore = ::setsockopt(
HITCBC 125   21 fd, IPPROTO_IPV6, IPV6_V6ONLY, &one, sizeof(one)); 125   22 fd, IPPROTO_IPV6, IPV6_V6ONLY, &one, sizeof(one));
126   } 126   }
HITCBC 127   2420 return {}; 127   3357 return {};
128   } 128   }
129   129  
130   // Apply protocol-specific options for acceptor sockets. 130   // Apply protocol-specific options for acceptor sockets.
131   // For IP acceptors, sets IPV6_V6ONLY=0 (dual-stack, best-effort). 131   // For IP acceptors, sets IPV6_V6ONLY=0 (dual-stack, best-effort).
132   static std::error_code 132   static std::error_code
HITCBC 133   246 configure_ip_acceptor(int fd, int family) noexcept 133   284 configure_ip_acceptor(int fd, int family) noexcept
134   { 134   {
HITCBC 135   246 if (family == AF_INET6) 135   284 if (family == AF_INET6)
136   { 136   {
HITCBC 137   11 int val = 0; 137   11 int val = 0;
HITCBC 138   22 std::ignore = ::setsockopt( 138   22 std::ignore = ::setsockopt(
HITCBC 139   11 fd, IPPROTO_IPV6, IPV6_V6ONLY, &val, sizeof(val)); 139   11 fd, IPPROTO_IPV6, IPV6_V6ONLY, &val, sizeof(val));
140   } 140   }
HITCBC 141   246 return {}; 141   284 return {};
142   } 142   }
143   143  
144   // No extra configuration needed for local (unix) sockets on epoll. 144   // No extra configuration needed for local (unix) sockets on epoll.
145   static std::error_code 145   static std::error_code
HITCBC 146   96 configure_local_socket(int /*fd*/) noexcept 146   105 configure_local_socket(int /*fd*/) noexcept
147   { 147   {
HITCBC 148   96 return {}; 148   105 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.
153   static std::error_code 153   static std::error_code
HITCBC 154   120 validate_assigned_fd(int /*fd*/) noexcept 154   159 validate_assigned_fd(int /*fd*/) noexcept
155   { 155   {
HITCBC 156   120 return {}; 156   159 return {};
157   } 157   }
158   }; 158   };
159   159  
160   } // namespace boost::corosio::detail 160   } // namespace boost::corosio::detail
161   161  
162   #endif // BOOST_COROSIO_HAS_EPOLL 162   #endif // BOOST_COROSIO_HAS_EPOLL
163   163  
164   #endif // BOOST_COROSIO_NATIVE_DETAIL_EPOLL_EPOLL_TRAITS_HPP 164   #endif // BOOST_COROSIO_NATIVE_DETAIL_EPOLL_EPOLL_TRAITS_HPP