include/boost/corosio/native/detail/epoll/epoll_traits.hpp

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