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 -
    explicit epoll_udp_service(capy::execution_context& ctx)
 
51 -
        : reactor_socket_service(ctx)
 
52 -
    {
 
53 -
    }
 
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 -
epoll_send_to_op::cancel() noexcept
 
68 -
{
 
69 -
    if (socket_impl_)
 
70 -
        socket_impl_->cancel_single_op(*this);
 
71 -
    else
 
72 -
        request_cancel();
 
73 -
}
 
74 -

 
75 -
inline void
 
76 -
epoll_recv_from_op::cancel() noexcept
 
77 -
{
 
78 -
    if (socket_impl_)
 
79 -
        socket_impl_->cancel_single_op(*this);
 
80 -
    else
 
81 -
        request_cancel();
 
82 -
}
 
83 -

 
84 -
// Cancellation for connected-mode ops
 
85 -

 
86 -
inline void
 
87 -
epoll_udp_connect_op::cancel() noexcept
 
88 -
{
 
89 -
    if (socket_impl_)
 
90 -
        socket_impl_->cancel_single_op(*this);
 
91 -
    else
 
92 -
        request_cancel();
 
93 -
}
 
94 -

 
95 -
inline void
 
96 -
epoll_send_op::cancel() noexcept
 
97 -
{
 
98 -
    if (socket_impl_)
 
99 -
        socket_impl_->cancel_single_op(*this);
 
100 -
    else
 
101 -
        request_cancel();
 
102 -
}
 
103 -

 
104 -
inline void
 
105 -
epoll_recv_op::cancel() noexcept
 
106 -
{
 
107 -
    if (socket_impl_)
 
108 -
        socket_impl_->cancel_single_op(*this);
 
109 -
    else
 
110 -
        request_cancel();
 
111 -
}
 
112 -

 
113 -
// Completion handlers
 
114 -

 
115 -
inline void
 
116 -
epoll_datagram_op::operator()()
 
117 -
{
 
118 -
    complete_io_op(*this);
 
119 -
}
 
120 -

 
121 -
inline void
 
122 -
epoll_recv_from_op::operator()()
 
123 -
{
 
124 -
    complete_datagram_op(*this, this->source_out);
 
125 -
}
 
126 -

 
127 -
inline void
 
128 -
epoll_udp_connect_op::operator()()
 
129 -
{
 
130 -
    complete_connect_op(*this);
 
131 -
}
 
132 -

 
133 -
inline void
 
134 -
epoll_recv_op::operator()()
 
135 -
{
 
136 -
    complete_io_op(*this);
 
137 -
}
 
138 -

 
139 -
// Socket construction/destruction
 
140 -

 
141 -
inline epoll_udp_socket::epoll_udp_socket(epoll_udp_service& svc) noexcept
 
142 -
    : reactor_datagram_socket(svc)
 
143 -
{
 
144 -
}
 
145 -

 
146 -
inline epoll_udp_socket::~epoll_udp_socket() = default;
 
147 -

 
148 -
// Connectionless I/O
 
149 -

 
150 -
inline std::coroutine_handle<>
 
151 -
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 -
    return do_send_to(h, ex, buf, dest, token, ec, bytes_out);
 
161 -
}
 
162 -

 
163 -
inline std::coroutine_handle<>
 
164 -
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 -
    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 -
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 -
    return do_connect(h, ex, ep, token, ec);
 
187 -
}
 
188 -

 
189 -
inline std::coroutine_handle<>
 
190 -
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 -
    return do_send(h, ex, buf, token, ec, bytes_out);
 
199 -
}
 
200 -

 
201 -
inline std::coroutine_handle<>
 
202 -
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 -
    return do_recv(h, ex, buf, token, ec, bytes_out);
 
211 -
}
 
212 -

 
213 -
inline endpoint
 
214 -
epoll_udp_socket::remote_endpoint() const noexcept
 
215 -
{
 
216 -
    return reactor_datagram_socket::remote_endpoint();
 
217 -
}
 
218 -

 
219 -
inline void
 
220 -
epoll_udp_socket::cancel() noexcept
 
221 -
{
 
222 -
    do_cancel();
 
223 -
}
 
224 -

 
225 -
inline void
 
226 -
epoll_udp_socket::close_socket() noexcept
 
227 -
{
 
228 -
    do_close_socket();
 
229 -
}
 
230 -

 
231 -
inline std::error_code
 
232 -
epoll_udp_service::open_datagram_socket(
 
233 -
    udp_socket::implementation& impl, int family, int type, int protocol)
 
234 -
{
 
235 -
    auto* epoll_impl = static_cast<epoll_udp_socket*>(&impl);
 
236 -
    epoll_impl->close_socket();
 
237 -

 
238 -
    int fd = ::socket(family, type | SOCK_NONBLOCK | SOCK_CLOEXEC, protocol);
 
239 -
    if (fd < 0)
 
240 -
        return make_err(errno);
 
241 -

 
242 -
    if (family == AF_INET6)
 
243 -
    {
 
244 -
        int one = 1;
 
245 -
        ::setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &one, sizeof(one));
 
246 -
    }
 
247 -

 
248 -
    epoll_impl->fd_ = fd;
 
249 -

 
250 -
    epoll_impl->desc_state_.fd = fd;
 
251 -
    {
 
252 -
        std::lock_guard lock(epoll_impl->desc_state_.mutex);
 
253 -
        epoll_impl->desc_state_.read_op    = nullptr;
 
254 -
        epoll_impl->desc_state_.write_op   = nullptr;
 
255 -
        epoll_impl->desc_state_.connect_op = nullptr;
 
256 -
    }
 
257 -
    scheduler().register_descriptor(fd, &epoll_impl->desc_state_);
 
258 -

 
259 -
    return {};
 
260 -
}
 
261 -

 
262 -
inline std::error_code
 
263 -
epoll_udp_service::bind_datagram(udp_socket::implementation& impl, endpoint ep)
 
264 -
{
 
265 -
    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