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