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

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