TLA Line data Source code
1 : //
2 : // Copyright (c) 2026 Steve Gerbino
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_UDP_SERVICE_HPP
11 : #define BOOST_COROSIO_NATIVE_DETAIL_EPOLL_EPOLL_UDP_SERVICE_HPP
12 :
13 : #include <boost/corosio/detail/platform.hpp>
14 :
15 : #if BOOST_COROSIO_HAS_EPOLL
16 :
17 : #include <boost/corosio/detail/config.hpp>
18 : #include <boost/corosio/detail/udp_service.hpp>
19 :
20 : #include <boost/corosio/native/detail/epoll/epoll_udp_socket.hpp>
21 : #include <boost/corosio/native/detail/epoll/epoll_scheduler.hpp>
22 : #include <boost/corosio/native/detail/reactor/reactor_socket_service.hpp>
23 :
24 : #include <boost/corosio/native/detail/reactor/reactor_op_complete.hpp>
25 :
26 : #include <coroutine>
27 : #include <mutex>
28 :
29 : #include <errno.h>
30 : #include <netinet/in.h>
31 : #include <sys/epoll.h>
32 : #include <sys/socket.h>
33 : #include <unistd.h>
34 :
35 : namespace boost::corosio::detail {
36 :
37 : /** epoll UDP service implementation.
38 :
39 : Inherits from udp_service to enable runtime polymorphism.
40 : Uses key_type = udp_service for service lookup.
41 : */
42 : class BOOST_COROSIO_DECL epoll_udp_service final
43 : : public reactor_socket_service<
44 : epoll_udp_service,
45 : udp_service,
46 : epoll_scheduler,
47 : epoll_udp_socket>
48 : {
49 : public:
50 HIT 355 : explicit epoll_udp_service(capy::execution_context& ctx)
51 355 : : reactor_socket_service(ctx)
52 : {
53 355 : }
54 :
55 : std::error_code open_datagram_socket(
56 : udp_socket::implementation& impl,
57 : int family,
58 : int type,
59 : int protocol) override;
60 : std::error_code
61 : bind_datagram(udp_socket::implementation& impl, endpoint ep) override;
62 : };
63 :
64 : // Cancellation for connectionless ops
65 :
66 : inline void
67 MIS 0 : epoll_send_to_op::cancel() noexcept
68 : {
69 0 : if (socket_impl_)
70 0 : socket_impl_->cancel_single_op(*this);
71 : else
72 0 : request_cancel();
73 0 : }
74 :
75 : inline void
76 HIT 1 : epoll_recv_from_op::cancel() noexcept
77 : {
78 1 : if (socket_impl_)
79 1 : socket_impl_->cancel_single_op(*this);
80 : else
81 MIS 0 : request_cancel();
82 HIT 1 : }
83 :
84 : // Cancellation for connected-mode ops
85 :
86 : inline void
87 MIS 0 : epoll_udp_connect_op::cancel() noexcept
88 : {
89 0 : if (socket_impl_)
90 0 : socket_impl_->cancel_single_op(*this);
91 : else
92 0 : request_cancel();
93 0 : }
94 :
95 : inline void
96 0 : epoll_send_op::cancel() noexcept
97 : {
98 0 : if (socket_impl_)
99 0 : socket_impl_->cancel_single_op(*this);
100 : else
101 0 : request_cancel();
102 0 : }
103 :
104 : inline void
105 0 : epoll_recv_op::cancel() noexcept
106 : {
107 0 : if (socket_impl_)
108 0 : socket_impl_->cancel_single_op(*this);
109 : else
110 0 : request_cancel();
111 0 : }
112 :
113 : // Completion handlers
114 :
115 : inline void
116 HIT 8 : epoll_datagram_op::operator()()
117 : {
118 8 : complete_io_op(*this);
119 8 : }
120 :
121 : inline void
122 7 : epoll_recv_from_op::operator()()
123 : {
124 7 : complete_datagram_op(*this, this->source_out);
125 7 : }
126 :
127 : inline void
128 5 : epoll_udp_connect_op::operator()()
129 : {
130 5 : complete_connect_op(*this);
131 5 : }
132 :
133 : inline void
134 2 : epoll_recv_op::operator()()
135 : {
136 2 : complete_io_op(*this);
137 2 : }
138 :
139 : // Socket construction/destruction
140 :
141 43 : inline epoll_udp_socket::epoll_udp_socket(epoll_udp_service& svc) noexcept
142 43 : : reactor_datagram_socket(svc)
143 : {
144 43 : }
145 :
146 43 : inline epoll_udp_socket::~epoll_udp_socket() = default;
147 :
148 : // Connectionless I/O
149 :
150 : inline std::coroutine_handle<>
151 11 : epoll_udp_socket::send_to(
152 : std::coroutine_handle<> h,
153 : capy::executor_ref ex,
154 : buffer_param buf,
155 : endpoint dest,
156 : int flags,
157 : std::stop_token token,
158 : std::error_code* ec,
159 : std::size_t* bytes_out)
160 : {
161 11 : return do_send_to(h, ex, buf, dest, flags, token, ec, bytes_out);
162 : }
163 :
164 : inline std::coroutine_handle<>
165 16 : epoll_udp_socket::recv_from(
166 : std::coroutine_handle<> h,
167 : capy::executor_ref ex,
168 : buffer_param buf,
169 : endpoint* source,
170 : int flags,
171 : std::stop_token token,
172 : std::error_code* ec,
173 : std::size_t* bytes_out)
174 : {
175 16 : return do_recv_from(h, ex, buf, source, flags, token, ec, bytes_out);
176 : }
177 :
178 : // Connected-mode I/O
179 :
180 : inline std::coroutine_handle<>
181 6 : epoll_udp_socket::connect(
182 : std::coroutine_handle<> h,
183 : capy::executor_ref ex,
184 : endpoint ep,
185 : std::stop_token token,
186 : std::error_code* ec)
187 : {
188 6 : return do_connect(h, ex, ep, token, ec);
189 : }
190 :
191 : inline std::coroutine_handle<>
192 3 : epoll_udp_socket::send(
193 : std::coroutine_handle<> h,
194 : capy::executor_ref ex,
195 : buffer_param buf,
196 : int flags,
197 : std::stop_token token,
198 : std::error_code* ec,
199 : std::size_t* bytes_out)
200 : {
201 3 : return do_send(h, ex, buf, flags, token, ec, bytes_out);
202 : }
203 :
204 : inline std::coroutine_handle<>
205 2 : epoll_udp_socket::recv(
206 : std::coroutine_handle<> h,
207 : capy::executor_ref ex,
208 : buffer_param buf,
209 : int flags,
210 : std::stop_token token,
211 : std::error_code* ec,
212 : std::size_t* bytes_out)
213 : {
214 2 : return do_recv(h, ex, buf, flags, token, ec, bytes_out);
215 : }
216 :
217 : inline endpoint
218 2 : epoll_udp_socket::remote_endpoint() const noexcept
219 : {
220 2 : return reactor_datagram_socket::remote_endpoint();
221 : }
222 :
223 : inline void
224 2 : epoll_udp_socket::cancel() noexcept
225 : {
226 2 : do_cancel();
227 2 : }
228 :
229 : inline void
230 166 : epoll_udp_socket::close_socket() noexcept
231 : {
232 166 : do_close_socket();
233 166 : }
234 :
235 : inline std::error_code
236 40 : epoll_udp_service::open_datagram_socket(
237 : udp_socket::implementation& impl, int family, int type, int protocol)
238 : {
239 40 : auto* epoll_impl = static_cast<epoll_udp_socket*>(&impl);
240 40 : epoll_impl->close_socket();
241 :
242 40 : int fd = ::socket(family, type | SOCK_NONBLOCK | SOCK_CLOEXEC, protocol);
243 40 : if (fd < 0)
244 MIS 0 : return make_err(errno);
245 :
246 HIT 40 : if (family == AF_INET6)
247 : {
248 7 : int one = 1;
249 7 : ::setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &one, sizeof(one));
250 : }
251 :
252 40 : epoll_impl->fd_ = fd;
253 :
254 40 : epoll_impl->desc_state_.fd = fd;
255 : {
256 40 : std::lock_guard lock(epoll_impl->desc_state_.mutex);
257 40 : epoll_impl->desc_state_.read_op = nullptr;
258 40 : epoll_impl->desc_state_.write_op = nullptr;
259 40 : epoll_impl->desc_state_.connect_op = nullptr;
260 40 : }
261 40 : scheduler().register_descriptor(fd, &epoll_impl->desc_state_);
262 :
263 40 : return {};
264 : }
265 :
266 : inline std::error_code
267 24 : epoll_udp_service::bind_datagram(udp_socket::implementation& impl, endpoint ep)
268 : {
269 24 : return static_cast<epoll_udp_socket*>(&impl)->do_bind(ep);
270 : }
271 :
272 : } // namespace boost::corosio::detail
273 :
274 : #endif // BOOST_COROSIO_HAS_EPOLL
275 :
276 : #endif // BOOST_COROSIO_NATIVE_DETAIL_EPOLL_EPOLL_UDP_SERVICE_HPP
|