97.14% Lines (34/35) 100.00% Functions (10/10)
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   28586 static void pre_shutdown(int) noexcept {} 57   36398 static void pre_shutdown(int) noexcept {}
HITCBC 58   9515 static void pre_destroy(int) noexcept {} 58   12119 static void pre_destroy(int) noexcept {}
59   }; 59   };
60   60  
61   struct write_policy 61   struct write_policy
62   { 62   {
HITCBC 63   108144 static ssize_t write(int fd, iovec* iovecs, int count) noexcept 63   109987 static ssize_t write(int fd, iovec* iovecs, int count) noexcept
64   { 64   {
HITCBC 65   108144 msghdr msg{}; 65   109987 msghdr msg{};
HITCBC 66   108144 msg.msg_iov = iovecs; 66   109987 msg.msg_iov = iovecs;
HITCBC 67   108144 msg.msg_iovlen = static_cast<std::size_t>(count); 67   109987 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   108144 n = ::sendmsg(fd, &msg, MSG_NOSIGNAL); 72   109987 n = ::sendmsg(fd, &msg, MSG_NOSIGNAL);
73   } 73   }
HITCBC 74   108144 while (n < 0 && errno == EINTR); 74   109987 while (n < 0 && errno == EINTR);
HITCBC 75   108144 return n; 75   109987 return n;
76   } 76   }
77   }; 77   };
78   78  
79   struct accept_policy 79   struct accept_policy
80   { 80   {
HITCBC 81   6304 static int do_accept( 81   8040 static int do_accept(
82   int fd, sockaddr_storage& peer, socklen_t& addrlen) noexcept 82   int fd, sockaddr_storage& peer, socklen_t& addrlen) noexcept
83   { 83   {
HITCBC 84   6304 addrlen = sizeof(peer); 84   8040 addrlen = sizeof(peer);
85   int new_fd; 85   int new_fd;
86   do 86   do
87   { 87   {
HITCBC 88   6304 new_fd = ::accept4( 88   8040 new_fd = ::accept4(
89   fd, reinterpret_cast<sockaddr*>(&peer), &addrlen, 89   fd, reinterpret_cast<sockaddr*>(&peer), &addrlen,
90   SOCK_NONBLOCK | SOCK_CLOEXEC); 90   SOCK_NONBLOCK | SOCK_CLOEXEC);
91   } 91   }
HITCBC 92   6304 while (new_fd < 0 && errno == EINTR); 92   8040 while (new_fd < 0 && errno == EINTR);
HITCBC 93   6304 return new_fd; 93   8040 return new_fd;
94   } 94   }
95   }; 95   };
96   96  
97   // Create a nonblocking, close-on-exec socket using Linux's atomic flags. 97   // Create a nonblocking, close-on-exec socket using Linux's atomic flags.
HITCBC 98   3329 static int create_socket(int family, int type, int protocol) noexcept 98   4197 static int create_socket(int family, int type, int protocol) noexcept
99   { 99   {
HITCBC 100   3329 return ::socket(family, type | SOCK_NONBLOCK | SOCK_CLOEXEC, protocol); 100   4197 return ::socket(family, type | SOCK_NONBLOCK | SOCK_CLOEXEC, protocol);
101   } 101   }
102   102  
103   // Apply protocol-specific options after socket creation. 103   // Apply protocol-specific options after socket creation.
104   // For IP sockets, sets IPV6_V6ONLY on AF_INET6 (best-effort). 104   // For IP sockets, sets IPV6_V6ONLY on AF_INET6 (best-effort).
105   static std::error_code 105   static std::error_code
HITCBC 106   3215 configure_ip_socket(int fd, int family) noexcept 106   4083 configure_ip_socket(int fd, int family) noexcept
107   { 107   {
HITCBC 108   3215 if (family == AF_INET6) 108   4083 if (family == AF_INET6)
109   { 109   {
HITCBC 110   14 int one = 1; 110   14 int one = 1;
HITCBC 111   14 (void)::setsockopt( 111   14 (void)::setsockopt(
112   fd, IPPROTO_IPV6, IPV6_V6ONLY, &one, sizeof(one)); 112   fd, IPPROTO_IPV6, IPV6_V6ONLY, &one, sizeof(one));
113   } 113   }
HITCBC 114   3215 return {}; 114   4083 return {};
115   } 115   }
116   116  
117   // Apply protocol-specific options for acceptor sockets. 117   // Apply protocol-specific options for acceptor sockets.
118   // For IP acceptors, sets IPV6_V6ONLY=0 (dual-stack, best-effort). 118   // For IP acceptors, sets IPV6_V6ONLY=0 (dual-stack, best-effort).
119   static std::error_code 119   static std::error_code
HITCBC 120   94 configure_ip_acceptor(int fd, int family) noexcept 120   94 configure_ip_acceptor(int fd, int family) noexcept
121   { 121   {
HITCBC 122   94 if (family == AF_INET6) 122   94 if (family == AF_INET6)
123   { 123   {
HITCBC 124   9 int val = 0; 124   9 int val = 0;
HITCBC 125   9 (void)::setsockopt( 125   9 (void)::setsockopt(
126   fd, IPPROTO_IPV6, IPV6_V6ONLY, &val, sizeof(val)); 126   fd, IPPROTO_IPV6, IPV6_V6ONLY, &val, sizeof(val));
127   } 127   }
HITCBC 128   94 return {}; 128   94 return {};
129   } 129   }
130   130  
131   // No extra configuration needed for local (unix) sockets on epoll. 131   // No extra configuration needed for local (unix) sockets on epoll.
132   static std::error_code 132   static std::error_code
HITCBC 133   20 configure_local_socket(int /*fd*/) noexcept 133   20 configure_local_socket(int /*fd*/) noexcept
134   { 134   {
HITCBC 135   20 return {}; 135   20 return {};
136   } 136   }
137   137  
138   // Non-mutating validation for fds adopted via assign(). Used when 138   // Non-mutating validation for fds adopted via assign(). Used when
139   // the caller retains fd ownership responsibility. 139   // the caller retains fd ownership responsibility.
140   static std::error_code 140   static std::error_code
HITCBC 141   14 validate_assigned_fd(int /*fd*/) noexcept 141   14 validate_assigned_fd(int /*fd*/) noexcept
142   { 142   {
HITCBC 143   14 return {}; 143   14 return {};
144   } 144   }
145   }; 145   };
146   146  
147   } // namespace boost::corosio::detail 147   } // namespace boost::corosio::detail
148   148  
149   #endif // BOOST_COROSIO_HAS_EPOLL 149   #endif // BOOST_COROSIO_HAS_EPOLL
150   150  
151   #endif // BOOST_COROSIO_NATIVE_DETAIL_EPOLL_EPOLL_TRAITS_HPP 151   #endif // BOOST_COROSIO_NATIVE_DETAIL_EPOLL_EPOLL_TRAITS_HPP