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, 49   int fd,
50   int level, 50   int level,
51   int optname, 51   int optname,
52   void const* data, 52   void const* data,
53   std::size_t size) noexcept 53   std::size_t size) noexcept
54   { 54   {
HITCBC 55   191 if (::setsockopt( 55   191 if (::setsockopt(
HITCBC 56   191 fd, level, optname, data, static_cast<socklen_t>(size)) != 56   191 fd, level, optname, data, static_cast<socklen_t>(size)) !=
57   0) 57   0)
HITCBC 58   5 return make_err(errno); 58   5 return make_err(errno);
HITCBC 59   186 return {}; 59   186 return {};
60   } 60   }
HITCBC 61   22478 static void pre_shutdown(int) noexcept {} 61   22613 static void pre_shutdown(int) noexcept {}
HITCBC 62   7303 static void pre_destroy(int) noexcept {} 62   7348 static void pre_destroy(int) noexcept {}
63   }; 63   };
64   64  
65   struct write_policy 65   struct write_policy
66   { 66   {
HITCBC 67   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
68   { 68   {
HITCBC 69   75 msghdr msg{}; 69   75 msghdr msg{};
HITCBC 70   75 msg.msg_iov = iovecs; 70   75 msg.msg_iov = iovecs;
HITCBC 71   75 msg.msg_iovlen = static_cast<std::size_t>(count); 71   75 msg.msg_iovlen = static_cast<std::size_t>(count);
72   72  
73   ssize_t n; 73   ssize_t n;
74   do 74   do
75   { 75   {
HITCBC 76   76 n = ::sendmsg(fd, &msg, MSG_NOSIGNAL); 76   76 n = ::sendmsg(fd, &msg, MSG_NOSIGNAL);
77   } 77   }
HITCBC 78   76 while (n < 0 && errno == EINTR); 78   76 while (n < 0 && errno == EINTR);
HITCBC 79   75 return n; 79   75 return n;
80   } 80   }
81   81  
82   static ssize_t 82   static ssize_t
HITCBC 83   100487 write_one(int fd, void const* data, std::size_t size) noexcept 83   115962 write_one(int fd, void const* data, std::size_t size) noexcept
84   { 84   {
85   ssize_t n; 85   ssize_t n;
86   do 86   do
87   { 87   {
HITCBC 88   100488 n = ::send(fd, data, size, MSG_NOSIGNAL); 88   115963 n = ::send(fd, data, size, MSG_NOSIGNAL);
89   } 89   }
HITCBC 90   100488 while (n < 0 && errno == EINTR); 90   115963 while (n < 0 && errno == EINTR);
HITCBC 91   100487 return n; 91   115962 return n;
92   } 92   }
93   }; 93   };
94   94  
95   struct accept_policy 95   struct accept_policy
96   { 96   {
97   static int 97   static int
HITCBC 98   4852 do_accept(int fd, sockaddr_storage& peer, socklen_t& addrlen) noexcept 98   4882 do_accept(int fd, sockaddr_storage& peer, socklen_t& addrlen) noexcept
99   { 99   {
HITCBC 100   4852 addrlen = sizeof(peer); 100   4882 addrlen = sizeof(peer);
101   int new_fd; 101   int new_fd;
102   do 102   do
103   { 103   {
HITCBC 104   4853 new_fd = ::accept4( 104   4883 new_fd = ::accept4(
105   fd, reinterpret_cast<sockaddr*>(&peer), &addrlen, 105   fd, reinterpret_cast<sockaddr*>(&peer), &addrlen,
106   SOCK_NONBLOCK | SOCK_CLOEXEC); 106   SOCK_NONBLOCK | SOCK_CLOEXEC);
107   } 107   }
HITCBC 108   4853 while (new_fd < 0 && errno == EINTR); 108   4883 while (new_fd < 0 && errno == EINTR);
HITCBC 109   4852 return new_fd; 109   4882 return new_fd;
110   } 110   }
111   }; 111   };
112   112  
113   // 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 114   3058 static int create_socket(int family, int type, int protocol) noexcept 114   3073 static int create_socket(int family, int type, int protocol) noexcept
115   { 115   {
HITCBC 116   3058 return ::socket(family, type | SOCK_NONBLOCK | SOCK_CLOEXEC, protocol); 116   3073 return ::socket(family, type | SOCK_NONBLOCK | SOCK_CLOEXEC, protocol);
117   } 117   }
118   118  
119   // Apply protocol-specific options after socket creation. 119   // Apply protocol-specific options after socket creation.
120   // For IP sockets, sets IPV6_V6ONLY on AF_INET6 (best-effort). 120   // For IP sockets, sets IPV6_V6ONLY on AF_INET6 (best-effort).
HITCBC 121   2591 static std::error_code configure_ip_socket(int fd, int family) noexcept 121   2606 static std::error_code configure_ip_socket(int fd, int family) noexcept
122   { 122   {
HITCBC 123   2591 if (family == AF_INET6) 123   2606 if (family == AF_INET6)
124   { 124   {
HITCBC 125   22 int one = 1; 125   22 int one = 1;
126   std::ignore = 126   std::ignore =
HITCBC 127   22 ::setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &one, sizeof(one)); 127   22 ::setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &one, sizeof(one));
128   } 128   }
HITCBC 129   2591 return {}; 129   2606 return {};
130   } 130   }
131   131  
132   // Apply protocol-specific options for acceptor sockets. 132   // Apply protocol-specific options for acceptor sockets.
133   // For IP acceptors, sets IPV6_V6ONLY=0 (dual-stack, best-effort). 133   // For IP acceptors, sets IPV6_V6ONLY=0 (dual-stack, best-effort).
HITCBC 134   342 static std::error_code configure_ip_acceptor(int fd, int family) noexcept 134   342 static std::error_code configure_ip_acceptor(int fd, int family) noexcept
135   { 135   {
HITCBC 136   342 if (family == AF_INET6) 136   342 if (family == AF_INET6)
137   { 137   {
HITCBC 138   11 int val = 0; 138   11 int val = 0;
139   std::ignore = 139   std::ignore =
HITCBC 140   11 ::setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &val, sizeof(val)); 140   11 ::setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &val, sizeof(val));
141   } 141   }
HITCBC 142   342 return {}; 142   342 return {};
143   } 143   }
144   144  
145   // No extra configuration needed for local (unix) sockets on epoll. 145   // No extra configuration needed for local (unix) sockets on epoll.
HITCBC 146   116 static std::error_code configure_local_socket(int /*fd*/) noexcept 146   116 static std::error_code 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.
HITCBC 153   168 static std::error_code validate_assigned_fd(int /*fd*/) noexcept 153   168 static std::error_code validate_assigned_fd(int /*fd*/) noexcept
154   { 154   {
HITCBC 155   168 return {}; 155   168 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