79.49% Lines (31/39) 90.91% Functions (10/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   32 std::error_code on_set_option( 47   32 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   32 if (::setsockopt( 51   32 if (::setsockopt(
52   fd, level, optname, data, 52   fd, level, optname, data,
HITCBC 53   32 static_cast<socklen_t>(size)) != 0) 53   32 static_cast<socklen_t>(size)) != 0)
MISUBC 54   return make_err(errno); 54   return make_err(errno);
HITCBC 55   32 return {}; 55   32 return {};
56   } 56   }
HITCBC 57   43958 static void pre_shutdown(int) noexcept {} 57   45020 static void pre_shutdown(int) noexcept {}
HITCBC 58   14639 static void pre_destroy(int) noexcept {} 58   14993 static void pre_destroy(int) noexcept {}
59   }; 59   };
60   60  
61   struct write_policy 61   struct write_policy
62   { 62   {
MISUBC 63   static ssize_t write(int fd, iovec* iovecs, int count) noexcept 63   static ssize_t write(int fd, iovec* iovecs, int count) noexcept
64   { 64   {
MISUBC 65   msghdr msg{}; 65   msghdr msg{};
MISUBC 66   msg.msg_iov = iovecs; 66   msg.msg_iov = iovecs;
MISUBC 67   msg.msg_iovlen = static_cast<std::size_t>(count); 67   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   {
MISUBC 72   n = ::sendmsg(fd, &msg, MSG_NOSIGNAL); 72   n = ::sendmsg(fd, &msg, MSG_NOSIGNAL);
73   } 73   }
MISUBC 74   while (n < 0 && errno == EINTR); 74   while (n < 0 && errno == EINTR);
MISUBC 75   return n; 75   return n;
76   } 76   }
77   77  
HITCBC 78   104039 static ssize_t write_one( 78   101236 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   104039 n = ::send(fd, data, size, MSG_NOSIGNAL); 84   101236 n = ::send(fd, data, size, MSG_NOSIGNAL);
85   } 85   }
HITCBC 86   104039 while (n < 0 && errno == EINTR); 86   101236 while (n < 0 && errno == EINTR);
HITCBC 87   104039 return n; 87   101236 return n;
88   } 88   }
89   }; 89   };
90   90  
91   struct accept_policy 91   struct accept_policy
92   { 92   {
HITCBC 93   9720 static int do_accept( 93   9956 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   9720 addrlen = sizeof(peer); 96   9956 addrlen = sizeof(peer);
97   int new_fd; 97   int new_fd;
98   do 98   do
99   { 99   {
HITCBC 100   9720 new_fd = ::accept4( 100   9956 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   9720 while (new_fd < 0 && errno == EINTR); 104   9956 while (new_fd < 0 && errno == EINTR);
HITCBC 105   9720 return new_fd; 105   9956 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   5037 static int create_socket(int family, int type, int protocol) noexcept 110   5155 static int create_socket(int family, int type, int protocol) noexcept
111   { 111   {
HITCBC 112   5037 return ::socket(family, type | SOCK_NONBLOCK | SOCK_CLOEXEC, protocol); 112   5155 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   4923 configure_ip_socket(int fd, int family) noexcept 118   5041 configure_ip_socket(int fd, int family) noexcept
119   { 119   {
HITCBC 120   4923 if (family == AF_INET6) 120   5041 if (family == AF_INET6)
121   { 121   {
HITCBC 122   14 int one = 1; 122   14 int one = 1;
HITCBC 123   14 (void)::setsockopt( 123   14 (void)::setsockopt(
124   fd, IPPROTO_IPV6, IPV6_V6ONLY, &one, sizeof(one)); 124   fd, IPPROTO_IPV6, IPV6_V6ONLY, &one, sizeof(one));
125   } 125   }
HITCBC 126   4923 return {}; 126   5041 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   94 configure_ip_acceptor(int fd, int family) noexcept 132   94 configure_ip_acceptor(int fd, int family) noexcept
133   { 133   {
HITCBC 134   94 if (family == AF_INET6) 134   94 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   94 return {}; 140   94 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   20 configure_local_socket(int /*fd*/) noexcept 145   20 configure_local_socket(int /*fd*/) noexcept
146   { 146   {
HITCBC 147   20 return {}; 147   20 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   14 validate_assigned_fd(int /*fd*/) noexcept 153   14 validate_assigned_fd(int /*fd*/) noexcept
154   { 154   {
HITCBC 155   14 return {}; 155   14 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