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