TLA Line data 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 HIT 32 : std::error_code on_set_option(
48 : int fd, int level, int optname,
49 : void const* data, std::size_t size) noexcept
50 : {
51 32 : if (::setsockopt(
52 : fd, level, optname, data,
53 32 : static_cast<socklen_t>(size)) != 0)
54 MIS 0 : return make_err(errno);
55 HIT 32 : return {};
56 : }
57 42397 : static void pre_shutdown(int) noexcept {}
58 14121 : static void pre_destroy(int) noexcept {}
59 : };
60 :
61 : struct write_policy
62 : {
63 110970 : static ssize_t write(int fd, iovec* iovecs, int count) noexcept
64 : {
65 110970 : msghdr msg{};
66 110970 : msg.msg_iov = iovecs;
67 110970 : msg.msg_iovlen = static_cast<std::size_t>(count);
68 :
69 : ssize_t n;
70 : do
71 : {
72 110970 : n = ::sendmsg(fd, &msg, MSG_NOSIGNAL);
73 : }
74 110970 : while (n < 0 && errno == EINTR);
75 110970 : return n;
76 : }
77 : };
78 :
79 : struct accept_policy
80 : {
81 9378 : static int do_accept(
82 : int fd, sockaddr_storage& peer, socklen_t& addrlen) noexcept
83 : {
84 9378 : addrlen = sizeof(peer);
85 : int new_fd;
86 : do
87 : {
88 9378 : new_fd = ::accept4(
89 : fd, reinterpret_cast<sockaddr*>(&peer), &addrlen,
90 : SOCK_NONBLOCK | SOCK_CLOEXEC);
91 : }
92 9378 : while (new_fd < 0 && errno == EINTR);
93 9378 : return new_fd;
94 : }
95 : };
96 :
97 : // Create a nonblocking, close-on-exec socket using Linux's atomic flags.
98 4848 : static int create_socket(int family, int type, int protocol) noexcept
99 : {
100 4848 : 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 4746 : configure_ip_socket(int fd, int family) noexcept
107 : {
108 4746 : if (family == AF_INET6)
109 : {
110 13 : int one = 1;
111 13 : (void)::setsockopt(
112 : fd, IPPROTO_IPV6, IPV6_V6ONLY, &one, sizeof(one));
113 : }
114 4746 : 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 82 : configure_ip_acceptor(int fd, int family) noexcept
121 : {
122 82 : if (family == AF_INET6)
123 : {
124 8 : int val = 0;
125 8 : (void)::setsockopt(
126 : fd, IPPROTO_IPV6, IPV6_V6ONLY, &val, sizeof(val));
127 : }
128 82 : return {};
129 : }
130 :
131 : // No extra configuration needed for local (unix) sockets on epoll.
132 : static std::error_code
133 20 : configure_local_socket(int /*fd*/) noexcept
134 : {
135 20 : 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 14 : validate_assigned_fd(int /*fd*/) noexcept
142 : {
143 14 : 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
|