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

100.0% Lines (39/0/39) 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 191x std::error_code on_set_option(
49 int fd,
50 int level,
51 int optname,
52 void const* data,
53 std::size_t size) noexcept
54 {
55 191x if (::setsockopt(
56 191x fd, level, optname, data, static_cast<socklen_t>(size)) !=
57 0)
58 5x return make_err(errno);
59 186x return {};
60 }
61 22977x static void pre_shutdown(int) noexcept {}
62 7469x static void pre_destroy(int) noexcept {}
63 };
64
65 struct write_policy
66 {
67 75x static ssize_t write(int fd, iovec* iovecs, int count) noexcept
68 {
69 75x msghdr msg{};
70 75x msg.msg_iov = iovecs;
71 75x msg.msg_iovlen = static_cast<std::size_t>(count);
72
73 ssize_t n;
74 do
75 {
76 76x n = ::sendmsg(fd, &msg, MSG_NOSIGNAL);
77 }
78 76x while (n < 0 && errno == EINTR);
79 75x return n;
80 }
81
82 static ssize_t
83 98995x write_one(int fd, void const* data, std::size_t size) noexcept
84 {
85 ssize_t n;
86 do
87 {
88 98996x n = ::send(fd, data, size, MSG_NOSIGNAL);
89 }
90 98996x while (n < 0 && errno == EINTR);
91 98995x return n;
92 }
93 };
94
95 struct accept_policy
96 {
97 static int
98 4962x do_accept(int fd, sockaddr_storage& peer, socklen_t& addrlen) noexcept
99 {
100 4962x addrlen = sizeof(peer);
101 int new_fd;
102 do
103 {
104 4963x new_fd = ::accept4(
105 fd, reinterpret_cast<sockaddr*>(&peer), &addrlen,
106 SOCK_NONBLOCK | SOCK_CLOEXEC);
107 }
108 4963x while (new_fd < 0 && errno == EINTR);
109 4962x return new_fd;
110 }
111 };
112
113 // Create a nonblocking, close-on-exec socket using Linux's atomic flags.
114 3114x static int create_socket(int family, int type, int protocol) noexcept
115 {
116 3114x return ::socket(family, type | SOCK_NONBLOCK | SOCK_CLOEXEC, protocol);
117 }
118
119 // Apply protocol-specific options after socket creation.
120 // For IP sockets, sets IPV6_V6ONLY on AF_INET6 (best-effort).
121 2647x static std::error_code configure_ip_socket(int fd, int family) noexcept
122 {
123 2647x if (family == AF_INET6)
124 {
125 22x int one = 1;
126 std::ignore =
127 22x ::setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &one, sizeof(one));
128 }
129 2647x return {};
130 }
131
132 // Apply protocol-specific options for acceptor sockets.
133 // For IP acceptors, sets IPV6_V6ONLY=0 (dual-stack, best-effort).
134 342x static std::error_code configure_ip_acceptor(int fd, int family) noexcept
135 {
136 342x if (family == AF_INET6)
137 {
138 11x int val = 0;
139 std::ignore =
140 11x ::setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &val, sizeof(val));
141 }
142 342x return {};
143 }
144
145 // No extra configuration needed for local (unix) sockets on epoll.
146 116x static std::error_code configure_local_socket(int /*fd*/) noexcept
147 {
148 116x return {};
149 }
150
151 // Non-mutating validation for fds adopted via assign(). Used when
152 // the caller retains fd ownership responsibility.
153 168x static std::error_code validate_assigned_fd(int /*fd*/) noexcept
154 {
155 168x return {};
156 }
157 };
158
159 } // namespace boost::corosio::detail
160
161 #endif // BOOST_COROSIO_HAS_EPOLL
162
163 #endif // BOOST_COROSIO_NATIVE_DETAIL_EPOLL_EPOLL_TRAITS_HPP
164