include/boost/corosio/native/native_udp_socket.hpp

92.3% Lines (120/130) 100.0% List of functions (72/72)
native_udp_socket.hpp
f(x) Functions (72)
Function Calls Lines Blocks
boost::corosio::native_udp_socket<boost::corosio::epoll_t{}>::get_impl() :85 13x 100.0% 100.0% boost::corosio::native_udp_socket<boost::corosio::select_t{}>::get_impl() :85 13x 100.0% 100.0% boost::corosio::native_udp_socket<boost::corosio::epoll_t{}>::native_send_to_awaitable<boost::capy::const_buffer>::native_send_to_awaitable(boost::corosio::native_udp_socket<boost::corosio::epoll_t{}>&, boost::capy::const_buffer, boost::corosio::endpoint, int) :101 2x 100.0% 100.0% boost::corosio::native_udp_socket<boost::corosio::select_t{}>::native_send_to_awaitable<boost::capy::const_buffer>::native_send_to_awaitable(boost::corosio::native_udp_socket<boost::corosio::select_t{}>&, boost::capy::const_buffer, boost::corosio::endpoint, int) :101 2x 100.0% 100.0% boost::corosio::native_udp_socket<boost::corosio::epoll_t{}>::native_send_to_awaitable<boost::capy::const_buffer>::await_ready() const :113 2x 100.0% 100.0% boost::corosio::native_udp_socket<boost::corosio::select_t{}>::native_send_to_awaitable<boost::capy::const_buffer>::await_ready() const :113 2x 100.0% 100.0% boost::corosio::native_udp_socket<boost::corosio::epoll_t{}>::native_send_to_awaitable<boost::capy::const_buffer>::await_resume() const :118 2x 75.0% 67.0% boost::corosio::native_udp_socket<boost::corosio::select_t{}>::native_send_to_awaitable<boost::capy::const_buffer>::await_resume() const :118 2x 75.0% 67.0% boost::corosio::native_udp_socket<boost::corosio::epoll_t{}>::native_send_to_awaitable<boost::capy::const_buffer>::await_suspend(std::__n4861::coroutine_handle<void>, boost::capy::io_env const*) :125 2x 100.0% 77.0% boost::corosio::native_udp_socket<boost::corosio::select_t{}>::native_send_to_awaitable<boost::capy::const_buffer>::await_suspend(std::__n4861::coroutine_handle<void>, boost::capy::io_env const*) :125 2x 100.0% 77.0% boost::corosio::native_udp_socket<boost::corosio::epoll_t{}>::native_recv_from_awaitable<boost::capy::mutable_buffer>::native_recv_from_awaitable(boost::corosio::native_udp_socket<boost::corosio::epoll_t{}>&, boost::capy::mutable_buffer, boost::corosio::endpoint&, int) :146 4x 100.0% 100.0% boost::corosio::native_udp_socket<boost::corosio::select_t{}>::native_recv_from_awaitable<boost::capy::mutable_buffer>::native_recv_from_awaitable(boost::corosio::native_udp_socket<boost::corosio::select_t{}>&, boost::capy::mutable_buffer, boost::corosio::endpoint&, int) :146 4x 100.0% 100.0% boost::corosio::native_udp_socket<boost::corosio::epoll_t{}>::native_recv_from_awaitable<boost::capy::mutable_buffer>::await_ready() const :158 4x 100.0% 100.0% boost::corosio::native_udp_socket<boost::corosio::select_t{}>::native_recv_from_awaitable<boost::capy::mutable_buffer>::await_ready() const :158 4x 100.0% 100.0% boost::corosio::native_udp_socket<boost::corosio::epoll_t{}>::native_recv_from_awaitable<boost::capy::mutable_buffer>::await_resume() const :163 4x 75.0% 67.0% boost::corosio::native_udp_socket<boost::corosio::select_t{}>::native_recv_from_awaitable<boost::capy::mutable_buffer>::await_resume() const :163 4x 75.0% 67.0% boost::corosio::native_udp_socket<boost::corosio::epoll_t{}>::native_recv_from_awaitable<boost::capy::mutable_buffer>::await_suspend(std::__n4861::coroutine_handle<void>, boost::capy::io_env const*) :170 4x 100.0% 77.0% boost::corosio::native_udp_socket<boost::corosio::select_t{}>::native_recv_from_awaitable<boost::capy::mutable_buffer>::await_suspend(std::__n4861::coroutine_handle<void>, boost::capy::io_env const*) :170 4x 100.0% 77.0% boost::corosio::native_udp_socket<boost::corosio::epoll_t{}>::native_wait_awaitable::native_wait_awaitable(boost::corosio::native_udp_socket<boost::corosio::epoll_t{}>&, boost::corosio::wait_type) :187 1x 100.0% 100.0% boost::corosio::native_udp_socket<boost::corosio::select_t{}>::native_wait_awaitable::native_wait_awaitable(boost::corosio::native_udp_socket<boost::corosio::select_t{}>&, boost::corosio::wait_type) :187 1x 100.0% 100.0% boost::corosio::native_udp_socket<boost::corosio::epoll_t{}>::native_wait_awaitable::await_ready() const :193 1x 100.0% 100.0% boost::corosio::native_udp_socket<boost::corosio::select_t{}>::native_wait_awaitable::await_ready() const :193 1x 100.0% 100.0% boost::corosio::native_udp_socket<boost::corosio::epoll_t{}>::native_wait_awaitable::await_resume() const :198 1x 75.0% 67.0% boost::corosio::native_udp_socket<boost::corosio::select_t{}>::native_wait_awaitable::await_resume() const :198 1x 75.0% 67.0% boost::corosio::native_udp_socket<boost::corosio::epoll_t{}>::native_wait_awaitable::await_suspend(std::__n4861::coroutine_handle<void>, boost::capy::io_env const*) :205 1x 100.0% 82.0% boost::corosio::native_udp_socket<boost::corosio::select_t{}>::native_wait_awaitable::await_suspend(std::__n4861::coroutine_handle<void>, boost::capy::io_env const*) :205 1x 100.0% 82.0% boost::corosio::native_udp_socket<boost::corosio::epoll_t{}>::native_connect_awaitable::native_connect_awaitable(boost::corosio::native_udp_socket<boost::corosio::epoll_t{}>&, boost::corosio::endpoint) :221 3x 100.0% 100.0% boost::corosio::native_udp_socket<boost::corosio::select_t{}>::native_connect_awaitable::native_connect_awaitable(boost::corosio::native_udp_socket<boost::corosio::select_t{}>&, boost::corosio::endpoint) :221 3x 100.0% 100.0% boost::corosio::native_udp_socket<boost::corosio::epoll_t{}>::native_connect_awaitable::await_ready() const :227 3x 100.0% 100.0% boost::corosio::native_udp_socket<boost::corosio::select_t{}>::native_connect_awaitable::await_ready() const :227 3x 100.0% 100.0% boost::corosio::native_udp_socket<boost::corosio::epoll_t{}>::native_connect_awaitable::await_resume() const :232 3x 75.0% 67.0% boost::corosio::native_udp_socket<boost::corosio::select_t{}>::native_connect_awaitable::await_resume() const :232 3x 75.0% 67.0% boost::corosio::native_udp_socket<boost::corosio::epoll_t{}>::native_connect_awaitable::await_suspend(std::__n4861::coroutine_handle<void>, boost::capy::io_env const*) :239 3x 100.0% 82.0% boost::corosio::native_udp_socket<boost::corosio::select_t{}>::native_connect_awaitable::await_suspend(std::__n4861::coroutine_handle<void>, boost::capy::io_env const*) :239 3x 100.0% 82.0% boost::corosio::native_udp_socket<boost::corosio::epoll_t{}>::native_send_awaitable<boost::capy::const_buffer>::native_send_awaitable(boost::corosio::native_udp_socket<boost::corosio::epoll_t{}>&, boost::capy::const_buffer, int) :258 2x 100.0% 100.0% boost::corosio::native_udp_socket<boost::corosio::select_t{}>::native_send_awaitable<boost::capy::const_buffer>::native_send_awaitable(boost::corosio::native_udp_socket<boost::corosio::select_t{}>&, boost::capy::const_buffer, int) :258 2x 100.0% 100.0% boost::corosio::native_udp_socket<boost::corosio::epoll_t{}>::native_send_awaitable<boost::capy::const_buffer>::await_ready() const :268 2x 100.0% 100.0% boost::corosio::native_udp_socket<boost::corosio::select_t{}>::native_send_awaitable<boost::capy::const_buffer>::await_ready() const :268 2x 100.0% 100.0% boost::corosio::native_udp_socket<boost::corosio::epoll_t{}>::native_send_awaitable<boost::capy::const_buffer>::await_resume() const :273 2x 75.0% 67.0% boost::corosio::native_udp_socket<boost::corosio::select_t{}>::native_send_awaitable<boost::capy::const_buffer>::await_resume() const :273 2x 75.0% 67.0% boost::corosio::native_udp_socket<boost::corosio::epoll_t{}>::native_send_awaitable<boost::capy::const_buffer>::await_suspend(std::__n4861::coroutine_handle<void>, boost::capy::io_env const*) :280 2x 100.0% 77.0% boost::corosio::native_udp_socket<boost::corosio::select_t{}>::native_send_awaitable<boost::capy::const_buffer>::await_suspend(std::__n4861::coroutine_handle<void>, boost::capy::io_env const*) :280 2x 100.0% 77.0% boost::corosio::native_udp_socket<boost::corosio::epoll_t{}>::native_recv_awaitable<boost::capy::mutable_buffer>::native_recv_awaitable(boost::corosio::native_udp_socket<boost::corosio::epoll_t{}>&, boost::capy::mutable_buffer, int) :300 1x 100.0% 100.0% boost::corosio::native_udp_socket<boost::corosio::select_t{}>::native_recv_awaitable<boost::capy::mutable_buffer>::native_recv_awaitable(boost::corosio::native_udp_socket<boost::corosio::select_t{}>&, boost::capy::mutable_buffer, int) :300 1x 100.0% 100.0% boost::corosio::native_udp_socket<boost::corosio::epoll_t{}>::native_recv_awaitable<boost::capy::mutable_buffer>::await_ready() const :310 1x 100.0% 100.0% boost::corosio::native_udp_socket<boost::corosio::select_t{}>::native_recv_awaitable<boost::capy::mutable_buffer>::await_ready() const :310 1x 100.0% 100.0% boost::corosio::native_udp_socket<boost::corosio::epoll_t{}>::native_recv_awaitable<boost::capy::mutable_buffer>::await_resume() const :315 1x 75.0% 67.0% boost::corosio::native_udp_socket<boost::corosio::select_t{}>::native_recv_awaitable<boost::capy::mutable_buffer>::await_resume() const :315 1x 75.0% 67.0% boost::corosio::native_udp_socket<boost::corosio::epoll_t{}>::native_recv_awaitable<boost::capy::mutable_buffer>::await_suspend(std::__n4861::coroutine_handle<void>, boost::capy::io_env const*) :322 1x 100.0% 77.0% boost::corosio::native_udp_socket<boost::corosio::select_t{}>::native_recv_awaitable<boost::capy::mutable_buffer>::await_suspend(std::__n4861::coroutine_handle<void>, boost::capy::io_env const*) :322 1x 100.0% 77.0% boost::corosio::native_udp_socket<boost::corosio::epoll_t{}>::native_udp_socket(boost::capy::execution_context&) :337 18x 100.0% 100.0% boost::corosio::native_udp_socket<boost::corosio::select_t{}>::native_udp_socket(boost::capy::execution_context&) :337 18x 100.0% 100.0% boost::corosio::native_udp_socket<boost::corosio::epoll_t{}>::native_udp_socket(boost::corosio::native_udp_socket<boost::corosio::epoll_t{}>&&) :354 1x 100.0% 100.0% boost::corosio::native_udp_socket<boost::corosio::select_t{}>::native_udp_socket(boost::corosio::native_udp_socket<boost::corosio::select_t{}>&&) :354 1x 100.0% 100.0% auto boost::corosio::native_udp_socket<boost::corosio::epoll_t{}>::send_to<boost::capy::const_buffer>(boost::capy::const_buffer const&, boost::corosio::endpoint, boost::corosio::message_flags) :374 2x 75.0% 80.0% auto boost::corosio::native_udp_socket<boost::corosio::select_t{}>::send_to<boost::capy::const_buffer>(boost::capy::const_buffer const&, boost::corosio::endpoint, boost::corosio::message_flags) :374 2x 75.0% 80.0% auto boost::corosio::native_udp_socket<boost::corosio::epoll_t{}>::send_to<boost::capy::const_buffer>(boost::capy::const_buffer const&, boost::corosio::endpoint) :387 2x 100.0% 100.0% auto boost::corosio::native_udp_socket<boost::corosio::select_t{}>::send_to<boost::capy::const_buffer>(boost::capy::const_buffer const&, boost::corosio::endpoint) :387 2x 100.0% 100.0% auto boost::corosio::native_udp_socket<boost::corosio::epoll_t{}>::recv_from<boost::capy::mutable_buffer>(boost::capy::mutable_buffer const&, boost::corosio::endpoint&, boost::corosio::message_flags) :405 4x 75.0% 80.0% auto boost::corosio::native_udp_socket<boost::corosio::select_t{}>::recv_from<boost::capy::mutable_buffer>(boost::capy::mutable_buffer const&, boost::corosio::endpoint&, boost::corosio::message_flags) :405 4x 75.0% 80.0% auto boost::corosio::native_udp_socket<boost::corosio::epoll_t{}>::recv_from<boost::capy::mutable_buffer>(boost::capy::mutable_buffer const&, boost::corosio::endpoint&) :418 4x 100.0% 100.0% auto boost::corosio::native_udp_socket<boost::corosio::select_t{}>::recv_from<boost::capy::mutable_buffer>(boost::capy::mutable_buffer const&, boost::corosio::endpoint&) :418 4x 100.0% 100.0% boost::corosio::native_udp_socket<boost::corosio::epoll_t{}>::connect(boost::corosio::endpoint) :438 3x 100.0% 89.0% boost::corosio::native_udp_socket<boost::corosio::select_t{}>::connect(boost::corosio::endpoint) :438 3x 100.0% 89.0% auto boost::corosio::native_udp_socket<boost::corosio::epoll_t{}>::send<boost::capy::const_buffer>(boost::capy::const_buffer const&, boost::corosio::message_flags) :458 2x 75.0% 80.0% auto boost::corosio::native_udp_socket<boost::corosio::select_t{}>::send<boost::capy::const_buffer>(boost::capy::const_buffer const&, boost::corosio::message_flags) :458 2x 75.0% 80.0% auto boost::corosio::native_udp_socket<boost::corosio::epoll_t{}>::send<boost::capy::const_buffer>(boost::capy::const_buffer const&) :468 2x 100.0% 100.0% auto boost::corosio::native_udp_socket<boost::corosio::select_t{}>::send<boost::capy::const_buffer>(boost::capy::const_buffer const&) :468 2x 100.0% 100.0% auto boost::corosio::native_udp_socket<boost::corosio::epoll_t{}>::recv<boost::capy::mutable_buffer>(boost::capy::mutable_buffer const&, boost::corosio::message_flags) :486 1x 75.0% 80.0% auto boost::corosio::native_udp_socket<boost::corosio::select_t{}>::recv<boost::capy::mutable_buffer>(boost::capy::mutable_buffer const&, boost::corosio::message_flags) :486 1x 75.0% 80.0% auto boost::corosio::native_udp_socket<boost::corosio::epoll_t{}>::recv<boost::capy::mutable_buffer>(boost::capy::mutable_buffer const&) :496 1x 100.0% 100.0% auto boost::corosio::native_udp_socket<boost::corosio::select_t{}>::recv<boost::capy::mutable_buffer>(boost::capy::mutable_buffer const&) :496 1x 100.0% 100.0%
Line TLA Hits 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_NATIVE_UDP_SOCKET_HPP
11 #define BOOST_COROSIO_NATIVE_NATIVE_UDP_SOCKET_HPP
12
13 #include <boost/corosio/udp_socket.hpp>
14 #include <boost/corosio/backend.hpp>
15
16 #ifndef BOOST_COROSIO_MRDOCS
17 #if BOOST_COROSIO_HAS_EPOLL
18 #include <boost/corosio/native/detail/epoll/epoll_types.hpp>
19 #endif
20
21 #if BOOST_COROSIO_HAS_SELECT
22 #include <boost/corosio/native/detail/select/select_types.hpp>
23 #endif
24
25 #if BOOST_COROSIO_HAS_KQUEUE
26 #include <boost/corosio/native/detail/kqueue/kqueue_types.hpp>
27 #endif
28
29 #if BOOST_COROSIO_HAS_IO_URING
30 #include <boost/corosio/native/detail/io_uring/io_uring_types.hpp>
31 #endif
32
33 #if BOOST_COROSIO_HAS_IOCP
34 #include <boost/corosio/native/detail/iocp/win_udp_service.hpp>
35 #endif
36 #endif // !BOOST_COROSIO_MRDOCS
37
38 namespace boost::corosio {
39
40 /** An asynchronous UDP socket with devirtualized I/O operations.
41
42 This class template inherits from @ref udp_socket and shadows
43 the async operations (`send_to`, `recv_from`, `connect`, `send`,
44 `recv`) with versions that call the backend implementation
45 directly, allowing the compiler to inline through the entire
46 call chain.
47
48 Non-async operations (`open`, `close`, `cancel`, `bind`,
49 socket options) remain unchanged and dispatch through the
50 compiled library.
51
52 A `native_udp_socket` IS-A `udp_socket` and can be passed to
53 any function expecting `udp_socket&`, in which case virtual
54 dispatch is used transparently.
55
56 @tparam Backend A backend tag value (e.g., `epoll`)
57 whose type provides the concrete implementation types.
58
59 @par Thread Safety
60 Same as @ref udp_socket.
61
62 @par Example
63 @code
64 #include <boost/corosio/native/native_udp_socket.hpp>
65
66 native_io_context<epoll> ctx;
67 native_udp_socket<epoll> s(ctx);
68 s.open();
69 s.bind(endpoint(ipv4_address::any(), 9000));
70 char buf[1024];
71 endpoint sender;
72 auto [ec, n] = co_await s.recv_from(
73 capy::mutable_buffer(buf, sizeof(buf)), sender);
74 @endcode
75
76 @see udp_socket, epoll_t
77 */
78 template<auto Backend>
79 class native_udp_socket : public udp_socket
80 {
81 using backend_type = decltype(Backend);
82 using impl_type = typename backend_type::udp_socket_type;
83 using service_type = typename backend_type::udp_service_type;
84
85 26x impl_type& get_impl() noexcept
86 {
87 26x return *static_cast<impl_type*>(h_.get());
88 }
89
90 template<class ConstBufferSequence>
91 struct native_send_to_awaitable
92 {
93 native_udp_socket& self_;
94 ConstBufferSequence buffers_;
95 endpoint dest_;
96 int flags_;
97 std::stop_token token_;
98 mutable std::error_code ec_;
99 mutable std::size_t bytes_transferred_ = 0;
100
101 4x native_send_to_awaitable(
102 native_udp_socket& self,
103 ConstBufferSequence buffers,
104 endpoint dest,
105 int flags) noexcept
106 4x : self_(self)
107 4x , buffers_(std::move(buffers))
108 4x , dest_(dest)
109 4x , flags_(flags)
110 {
111 4x }
112
113 4x bool await_ready() const noexcept
114 {
115 4x return token_.stop_requested();
116 }
117
118 4x capy::io_result<std::size_t> await_resume() const noexcept
119 {
120 4x if (token_.stop_requested())
121 return {make_error_code(std::errc::operation_canceled), 0};
122 4x return {ec_, bytes_transferred_};
123 }
124
125 4x auto await_suspend(std::coroutine_handle<> h, capy::io_env const* env)
126 -> std::coroutine_handle<>
127 {
128 4x token_ = env->stop_token;
129 12x return self_.get_impl().send_to(
130 4x h, env->executor, buffers_, dest_, flags_,
131 12x token_, &ec_, &bytes_transferred_);
132 }
133 };
134
135 template<class MutableBufferSequence>
136 struct native_recv_from_awaitable
137 {
138 native_udp_socket& self_;
139 MutableBufferSequence buffers_;
140 endpoint& source_;
141 int flags_;
142 std::stop_token token_;
143 mutable std::error_code ec_;
144 mutable std::size_t bytes_transferred_ = 0;
145
146 8x native_recv_from_awaitable(
147 native_udp_socket& self,
148 MutableBufferSequence buffers,
149 endpoint& source,
150 int flags) noexcept
151 8x : self_(self)
152 8x , buffers_(std::move(buffers))
153 8x , source_(source)
154 8x , flags_(flags)
155 {
156 8x }
157
158 8x bool await_ready() const noexcept
159 {
160 8x return token_.stop_requested();
161 }
162
163 8x capy::io_result<std::size_t> await_resume() const noexcept
164 {
165 8x if (token_.stop_requested())
166 return {make_error_code(std::errc::operation_canceled), 0};
167 8x return {ec_, bytes_transferred_};
168 }
169
170 8x auto await_suspend(std::coroutine_handle<> h, capy::io_env const* env)
171 -> std::coroutine_handle<>
172 {
173 8x token_ = env->stop_token;
174 24x return self_.get_impl().recv_from(
175 8x h, env->executor, buffers_, &source_, flags_,
176 24x token_, &ec_, &bytes_transferred_);
177 }
178 };
179
180 struct native_wait_awaitable
181 {
182 native_udp_socket& self_;
183 wait_type w_;
184 std::stop_token token_;
185 mutable std::error_code ec_;
186
187 2x native_wait_awaitable(native_udp_socket& self, wait_type w) noexcept
188 2x : self_(self)
189 2x , w_(w)
190 {
191 2x }
192
193 2x bool await_ready() const noexcept
194 {
195 2x return token_.stop_requested();
196 }
197
198 2x capy::io_result<> await_resume() const noexcept
199 {
200 2x if (token_.stop_requested())
201 return {make_error_code(std::errc::operation_canceled)};
202 2x return {ec_};
203 }
204
205 2x auto await_suspend(std::coroutine_handle<> h, capy::io_env const* env)
206 -> std::coroutine_handle<>
207 {
208 2x token_ = env->stop_token;
209 6x return self_.get_impl().wait(
210 6x h, env->executor, w_, token_, &ec_);
211 }
212 };
213
214 struct native_connect_awaitable
215 {
216 native_udp_socket& self_;
217 endpoint endpoint_;
218 std::stop_token token_;
219 mutable std::error_code ec_;
220
221 6x native_connect_awaitable(native_udp_socket& self, endpoint ep) noexcept
222 6x : self_(self)
223 6x , endpoint_(ep)
224 {
225 6x }
226
227 6x bool await_ready() const noexcept
228 {
229 6x return token_.stop_requested();
230 }
231
232 6x capy::io_result<> await_resume() const noexcept
233 {
234 6x if (token_.stop_requested())
235 return {make_error_code(std::errc::operation_canceled)};
236 6x return {ec_};
237 }
238
239 6x auto await_suspend(std::coroutine_handle<> h, capy::io_env const* env)
240 -> std::coroutine_handle<>
241 {
242 6x token_ = env->stop_token;
243 18x return self_.get_impl().connect(
244 18x h, env->executor, endpoint_, token_, &ec_);
245 }
246 };
247
248 template<class ConstBufferSequence>
249 struct native_send_awaitable
250 {
251 native_udp_socket& self_;
252 ConstBufferSequence buffers_;
253 int flags_;
254 std::stop_token token_;
255 mutable std::error_code ec_;
256 mutable std::size_t bytes_transferred_ = 0;
257
258 4x native_send_awaitable(
259 native_udp_socket& self,
260 ConstBufferSequence buffers,
261 int flags) noexcept
262 4x : self_(self)
263 4x , buffers_(std::move(buffers))
264 4x , flags_(flags)
265 {
266 4x }
267
268 4x bool await_ready() const noexcept
269 {
270 4x return token_.stop_requested();
271 }
272
273 4x capy::io_result<std::size_t> await_resume() const noexcept
274 {
275 4x if (token_.stop_requested())
276 return {make_error_code(std::errc::operation_canceled), 0};
277 4x return {ec_, bytes_transferred_};
278 }
279
280 4x auto await_suspend(std::coroutine_handle<> h, capy::io_env const* env)
281 -> std::coroutine_handle<>
282 {
283 4x token_ = env->stop_token;
284 12x return self_.get_impl().send(
285 4x h, env->executor, buffers_, flags_,
286 12x token_, &ec_, &bytes_transferred_);
287 }
288 };
289
290 template<class MutableBufferSequence>
291 struct native_recv_awaitable
292 {
293 native_udp_socket& self_;
294 MutableBufferSequence buffers_;
295 int flags_;
296 std::stop_token token_;
297 mutable std::error_code ec_;
298 mutable std::size_t bytes_transferred_ = 0;
299
300 2x native_recv_awaitable(
301 native_udp_socket& self,
302 MutableBufferSequence buffers,
303 int flags) noexcept
304 2x : self_(self)
305 2x , buffers_(std::move(buffers))
306 2x , flags_(flags)
307 {
308 2x }
309
310 2x bool await_ready() const noexcept
311 {
312 2x return token_.stop_requested();
313 }
314
315 2x capy::io_result<std::size_t> await_resume() const noexcept
316 {
317 2x if (token_.stop_requested())
318 return {make_error_code(std::errc::operation_canceled), 0};
319 2x return {ec_, bytes_transferred_};
320 }
321
322 2x auto await_suspend(std::coroutine_handle<> h, capy::io_env const* env)
323 -> std::coroutine_handle<>
324 {
325 2x token_ = env->stop_token;
326 6x return self_.get_impl().recv(
327 2x h, env->executor, buffers_, flags_,
328 6x token_, &ec_, &bytes_transferred_);
329 }
330 };
331
332 public:
333 /** Construct a native UDP socket from an execution context.
334
335 @param ctx The execution context that will own this socket.
336 */
337 36x explicit native_udp_socket(capy::execution_context& ctx)
338 36x : udp_socket(create_handle<service_type>(ctx))
339 {
340 36x }
341
342 /** Construct a native UDP socket from an executor.
343
344 @param ex The executor whose context will own the socket.
345 */
346 template<class Ex>
347 requires(!std::same_as<std::remove_cvref_t<Ex>, native_udp_socket>) &&
348 capy::Executor<Ex>
349 explicit native_udp_socket(Ex const& ex) : native_udp_socket(ex.context())
350 {
351 }
352
353 /// Move construct.
354 2x native_udp_socket(native_udp_socket&&) noexcept = default;
355
356 /// Move assign.
357 native_udp_socket& operator=(native_udp_socket&&) noexcept = default;
358
359 native_udp_socket(native_udp_socket const&) = delete;
360 native_udp_socket& operator=(native_udp_socket const&) = delete;
361
362 /** Send a datagram to the specified destination.
363
364 Calls the backend implementation directly, bypassing virtual
365 dispatch. Otherwise identical to @ref udp_socket::send_to.
366
367 @param buffers The buffer sequence containing data to send.
368 @param dest The destination endpoint.
369 @param flags Message flags.
370
371 @return An awaitable yielding `(error_code, std::size_t)`.
372 */
373 template<capy::ConstBufferSequence CB>
374 4x auto send_to(
375 CB const& buffers,
376 endpoint dest,
377 corosio::message_flags flags)
378 {
379 4x if (!is_open())
380 detail::throw_logic_error("send_to: socket not open");
381 return native_send_to_awaitable<CB>(
382 4x *this, buffers, dest, static_cast<int>(flags));
383 }
384
385 /// @overload
386 template<capy::ConstBufferSequence CB>
387 4x auto send_to(CB const& buffers, endpoint dest)
388 {
389 4x return send_to(buffers, dest, corosio::message_flags::none);
390 }
391
392 /** Receive a datagram and capture the sender's endpoint.
393
394 Calls the backend implementation directly, bypassing virtual
395 dispatch. Otherwise identical to @ref udp_socket::recv_from.
396
397 @param buffers The buffer sequence to receive data into.
398 @param source Reference to an endpoint that will be set to
399 the sender's address on successful completion.
400 @param flags Message flags (e.g. message_flags::peek).
401
402 @return An awaitable yielding `(error_code, std::size_t)`.
403 */
404 template<capy::MutableBufferSequence MB>
405 8x auto recv_from(
406 MB const& buffers,
407 endpoint& source,
408 corosio::message_flags flags)
409 {
410 8x if (!is_open())
411 detail::throw_logic_error("recv_from: socket not open");
412 return native_recv_from_awaitable<MB>(
413 8x *this, buffers, source, static_cast<int>(flags));
414 }
415
416 /// @overload
417 template<capy::MutableBufferSequence MB>
418 8x auto recv_from(MB const& buffers, endpoint& source)
419 {
420 8x return recv_from(buffers, source, corosio::message_flags::none);
421 }
422
423 /** Asynchronously connect to set the default peer.
424
425 Calls the backend implementation directly, bypassing virtual
426 dispatch. Otherwise identical to @ref udp_socket::connect.
427
428 If the socket is not already open, it is opened automatically
429 using the address family of @p ep.
430
431 @param ep The remote endpoint to connect to.
432
433 @return An awaitable yielding `io_result<>`.
434
435 @throws std::system_error if the socket needs to be opened
436 and the open fails.
437 */
438 6x auto connect(endpoint ep)
439 {
440 6x if (!is_open())
441 4x open(ep.is_v6() ? udp::v6() : udp::v4());
442 6x return native_connect_awaitable(*this, ep);
443 }
444
445 /** Send a datagram to the connected peer.
446
447 Calls the backend implementation directly, bypassing virtual
448 dispatch. Otherwise identical to @ref udp_socket::send.
449
450 @param buffers The buffer sequence containing data to send.
451 @param flags Message flags.
452
453 @return An awaitable yielding `(error_code, std::size_t)`.
454
455 @throws std::logic_error if the socket is not open.
456 */
457 template<capy::ConstBufferSequence CB>
458 4x auto send(CB const& buffers, corosio::message_flags flags)
459 {
460 4x if (!is_open())
461 detail::throw_logic_error("send: socket not open");
462 return native_send_awaitable<CB>(
463 4x *this, buffers, static_cast<int>(flags));
464 }
465
466 /// @overload
467 template<capy::ConstBufferSequence CB>
468 4x auto send(CB const& buffers)
469 {
470 4x return send(buffers, corosio::message_flags::none);
471 }
472
473 /** Receive a datagram from the connected peer.
474
475 Calls the backend implementation directly, bypassing virtual
476 dispatch. Otherwise identical to @ref udp_socket::recv.
477
478 @param buffers The buffer sequence to receive data into.
479 @param flags Message flags (e.g. message_flags::peek).
480
481 @return An awaitable yielding `(error_code, std::size_t)`.
482
483 @throws std::logic_error if the socket is not open.
484 */
485 template<capy::MutableBufferSequence MB>
486 2x auto recv(MB const& buffers, corosio::message_flags flags)
487 {
488 2x if (!is_open())
489 detail::throw_logic_error("recv: socket not open");
490 return native_recv_awaitable<MB>(
491 2x *this, buffers, static_cast<int>(flags));
492 }
493
494 /// @overload
495 template<capy::MutableBufferSequence MB>
496 2x auto recv(MB const& buffers)
497 {
498 2x return recv(buffers, corosio::message_flags::none);
499 }
500
501 /** Asynchronously wait for the socket to be ready.
502
503 Calls the backend implementation directly, bypassing virtual
504 dispatch. Otherwise identical to @ref udp_socket::wait.
505
506 @param w The wait direction (read, write, or error).
507
508 @return An awaitable yielding `io_result<>`.
509 */
510 2x [[nodiscard]] auto wait(wait_type w)
511 {
512 2x return native_wait_awaitable(*this, w);
513 }
514 };
515
516 } // namespace boost::corosio
517
518 #endif // BOOST_COROSIO_NATIVE_NATIVE_UDP_SOCKET_HPP
519