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 271 : explicit epoll_udp_service(capy::execution_context& ctx)
51 271 : : reactor_socket_service(ctx)
52 : {
53 271 : }
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 39 : inline epoll_udp_socket::epoll_udp_socket(epoll_udp_service& svc) noexcept
142 39 : : reactor_datagram_socket(svc)
143 : {
144 39 : }
145 :
146 39 : 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 : std::stop_token token,
157 : std::error_code* ec,
158 : std::size_t* bytes_out)
159 : {
160 11 : return do_send_to(h, ex, buf, dest, token, ec, bytes_out);
161 : }
162 :
163 : inline std::coroutine_handle<>
164 16 : epoll_udp_socket::recv_from(
165 : std::coroutine_handle<> h,
166 : capy::executor_ref ex,
167 : buffer_param buf,
168 : endpoint* source,
169 : std::stop_token token,
170 : std::error_code* ec,
171 : std::size_t* bytes_out)
172 : {
173 16 : return do_recv_from(h, ex, buf, source, token, ec, bytes_out);
174 : }
175 :
176 : // Connected-mode I/O
177 :
178 : inline std::coroutine_handle<>
179 6 : epoll_udp_socket::connect(
180 : std::coroutine_handle<> h,
181 : capy::executor_ref ex,
182 : endpoint ep,
183 : std::stop_token token,
184 : std::error_code* ec)
185 : {
186 6 : return do_connect(h, ex, ep, token, ec);
187 : }
188 :
189 : inline std::coroutine_handle<>
190 3 : epoll_udp_socket::send(
191 : std::coroutine_handle<> h,
192 : capy::executor_ref ex,
193 : buffer_param buf,
194 : std::stop_token token,
195 : std::error_code* ec,
196 : std::size_t* bytes_out)
197 : {
198 3 : return do_send(h, ex, buf, token, ec, bytes_out);
199 : }
200 :
201 : inline std::coroutine_handle<>
202 2 : epoll_udp_socket::recv(
203 : std::coroutine_handle<> h,
204 : capy::executor_ref ex,
205 : buffer_param buf,
206 : std::stop_token token,
207 : std::error_code* ec,
208 : std::size_t* bytes_out)
209 : {
210 2 : return do_recv(h, ex, buf, token, ec, bytes_out);
211 : }
212 :
213 : inline endpoint
214 2 : epoll_udp_socket::remote_endpoint() const noexcept
215 : {
216 2 : return reactor_datagram_socket::remote_endpoint();
217 : }
218 :
219 : inline void
220 2 : epoll_udp_socket::cancel() noexcept
221 : {
222 2 : do_cancel();
223 2 : }
224 :
225 : inline void
226 152 : epoll_udp_socket::close_socket() noexcept
227 : {
228 152 : do_close_socket();
229 152 : }
230 :
231 : inline std::error_code
232 37 : epoll_udp_service::open_datagram_socket(
233 : udp_socket::implementation& impl, int family, int type, int protocol)
234 : {
235 37 : auto* epoll_impl = static_cast<epoll_udp_socket*>(&impl);
236 37 : epoll_impl->close_socket();
237 :
238 37 : int fd = ::socket(family, type | SOCK_NONBLOCK | SOCK_CLOEXEC, protocol);
239 37 : if (fd < 0)
240 MIS 0 : return make_err(errno);
241 :
242 HIT 37 : if (family == AF_INET6)
243 : {
244 7 : int one = 1;
245 7 : ::setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &one, sizeof(one));
246 : }
247 :
248 37 : epoll_impl->fd_ = fd;
249 :
250 37 : epoll_impl->desc_state_.fd = fd;
251 : {
252 37 : std::lock_guard lock(epoll_impl->desc_state_.mutex);
253 37 : epoll_impl->desc_state_.read_op = nullptr;
254 37 : epoll_impl->desc_state_.write_op = nullptr;
255 37 : epoll_impl->desc_state_.connect_op = nullptr;
256 37 : }
257 37 : scheduler().register_descriptor(fd, &epoll_impl->desc_state_);
258 :
259 37 : return {};
260 : }
261 :
262 : inline std::error_code
263 21 : epoll_udp_service::bind_datagram(udp_socket::implementation& impl, endpoint ep)
264 : {
265 21 : return static_cast<epoll_udp_socket*>(&impl)->do_bind(ep);
266 : }
267 :
268 : } // namespace boost::corosio::detail
269 :
270 : #endif // BOOST_COROSIO_HAS_EPOLL
271 :
272 : #endif // BOOST_COROSIO_NATIVE_DETAIL_EPOLL_EPOLL_UDP_SERVICE_HPP
|