include/boost/corosio/native/native_udp_socket.hpp

100.0% Lines (92 / 92) 100.0% Functions (48 / 48)
native_udp_socket.hpp
f(x) Functions (48)
Function Calls Lines Blocks
boost::corosio::native_udp_socket<boost::corosio::epoll_t{}>::get_impl() :76 14x 100.0% 100.0% boost::corosio::native_udp_socket<boost::corosio::select_t{}>::get_impl() :76 14x 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) :90 4x 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) :90 4x 100.0% 100.0% boost::corosio::native_udp_socket<boost::corosio::epoll_t{}>::native_send_to_awaitable<boost::capy::const_buffer>::dispatch(std::__n4861::coroutine_handle<void>, boost::capy::executor_ref) const :103 2x 100.0% 75.0% boost::corosio::native_udp_socket<boost::corosio::select_t{}>::native_send_to_awaitable<boost::capy::const_buffer>::dispatch(std::__n4861::coroutine_handle<void>, boost::capy::executor_ref) const :103 2x 100.0% 75.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) :121 6x 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) :121 6x 100.0% 100.0% boost::corosio::native_udp_socket<boost::corosio::epoll_t{}>::native_recv_from_awaitable<boost::capy::mutable_buffer>::dispatch(std::__n4861::coroutine_handle<void>, boost::capy::executor_ref) const :134 4x 100.0% 75.0% boost::corosio::native_udp_socket<boost::corosio::select_t{}>::native_recv_from_awaitable<boost::capy::mutable_buffer>::dispatch(std::__n4861::coroutine_handle<void>, boost::capy::executor_ref) const :134 4x 100.0% 75.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) :147 2x 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) :147 2x 100.0% 100.0% boost::corosio::native_udp_socket<boost::corosio::epoll_t{}>::native_wait_awaitable::dispatch(std::__n4861::coroutine_handle<void>, boost::capy::executor_ref) const :154 1x 100.0% 80.0% boost::corosio::native_udp_socket<boost::corosio::select_t{}>::native_wait_awaitable::dispatch(std::__n4861::coroutine_handle<void>, boost::capy::executor_ref) const :154 1x 100.0% 80.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) :166 5x 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) :166 5x 100.0% 100.0% boost::corosio::native_udp_socket<boost::corosio::epoll_t{}>::native_connect_awaitable::dispatch(std::__n4861::coroutine_handle<void>, boost::capy::executor_ref) const :173 4x 100.0% 80.0% boost::corosio::native_udp_socket<boost::corosio::select_t{}>::native_connect_awaitable::dispatch(std::__n4861::coroutine_handle<void>, boost::capy::executor_ref) const :173 4x 100.0% 80.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) :188 4x 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) :188 4x 100.0% 100.0% boost::corosio::native_udp_socket<boost::corosio::epoll_t{}>::native_send_awaitable<boost::capy::const_buffer>::dispatch(std::__n4861::coroutine_handle<void>, boost::capy::executor_ref) const :199 2x 100.0% 75.0% boost::corosio::native_udp_socket<boost::corosio::select_t{}>::native_send_awaitable<boost::capy::const_buffer>::dispatch(std::__n4861::coroutine_handle<void>, boost::capy::executor_ref) const :199 2x 100.0% 75.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) :215 3x 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) :215 3x 100.0% 100.0% boost::corosio::native_udp_socket<boost::corosio::epoll_t{}>::native_recv_awaitable<boost::capy::mutable_buffer>::dispatch(std::__n4861::coroutine_handle<void>, boost::capy::executor_ref) const :226 1x 100.0% 75.0% boost::corosio::native_udp_socket<boost::corosio::select_t{}>::native_recv_awaitable<boost::capy::mutable_buffer>::dispatch(std::__n4861::coroutine_handle<void>, boost::capy::executor_ref) const :226 1x 100.0% 75.0% boost::corosio::native_udp_socket<boost::corosio::epoll_t{}>::native_udp_socket(boost::capy::execution_context&) :239 21x 100.0% 100.0% boost::corosio::native_udp_socket<boost::corosio::select_t{}>::native_udp_socket(boost::capy::execution_context&) :239 21x 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{}>&&) :256 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{}>&&) :256 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) :279 4x 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, boost::corosio::message_flags) :279 4x 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) :290 4x 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) :290 4x 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) :311 6x 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&, boost::corosio::message_flags) :311 6x 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&) :322 6x 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&) :322 6x 100.0% 100.0% boost::corosio::native_udp_socket<boost::corosio::epoll_t{}>::connect(boost::corosio::endpoint) :342 5x 100.0% 100.0% boost::corosio::native_udp_socket<boost::corosio::select_t{}>::connect(boost::corosio::endpoint) :342 5x 100.0% 100.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) :363 4x 100.0% 100.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) :363 4x 100.0% 100.0% auto boost::corosio::native_udp_socket<boost::corosio::epoll_t{}>::send<boost::capy::const_buffer>(boost::capy::const_buffer const&) :373 4x 100.0% 100.0% auto boost::corosio::native_udp_socket<boost::corosio::select_t{}>::send<boost::capy::const_buffer>(boost::capy::const_buffer const&) :373 4x 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) :391 3x 100.0% 100.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) :391 3x 100.0% 100.0% auto boost::corosio::native_udp_socket<boost::corosio::epoll_t{}>::recv<boost::capy::mutable_buffer>(boost::capy::mutable_buffer const&) :401 3x 100.0% 100.0% auto boost::corosio::native_udp_socket<boost::corosio::select_t{}>::recv<boost::capy::mutable_buffer>(boost::capy::mutable_buffer const&) :401 3x 100.0% 100.0%
Line TLA Hits Source Code
1 //
2 // Copyright (c) 2026 Steve Gerbino
3 // Copyright (c) 2026 Michael Vandeberg
4 //
5 // Distributed under the Boost Software License, Version 1.0. (See accompanying
6 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
7 //
8 // Official repository: https://github.com/cppalliance/corosio
9 //
10
11 #ifndef BOOST_COROSIO_NATIVE_NATIVE_UDP_SOCKET_HPP
12 #define BOOST_COROSIO_NATIVE_NATIVE_UDP_SOCKET_HPP
13
14 #include <boost/corosio/udp_socket.hpp>
15 #include <boost/corosio/backend.hpp>
16 #include <boost/corosio/detail/op_base.hpp>
17
18 #ifndef BOOST_COROSIO_MRDOCS
19 #if BOOST_COROSIO_HAS_EPOLL
20 #include <boost/corosio/native/detail/epoll/epoll_types.hpp>
21 #endif
22
23 #if BOOST_COROSIO_HAS_SELECT
24 #include <boost/corosio/native/detail/select/select_types.hpp>
25 #endif
26
27 #if BOOST_COROSIO_HAS_KQUEUE
28 #include <boost/corosio/native/detail/kqueue/kqueue_types.hpp>
29 #endif
30
31 #if BOOST_COROSIO_HAS_URING
32 #include <boost/corosio/native/detail/uring/uring_types.hpp>
33 #endif
34
35 #if BOOST_COROSIO_HAS_IOCP
36 #include <boost/corosio/native/detail/iocp/win_udp_service.hpp>
37 #endif
38 #endif // !BOOST_COROSIO_MRDOCS
39
40 namespace boost::corosio {
41
42 /** An asynchronous UDP socket with devirtualized I/O operations.
43
44 This class template inherits from @ref udp_socket and shadows
45 the async operations (`send_to`, `recv_from`, `connect`, `send`,
46 `recv`) with versions that call the backend implementation
47 directly, allowing the compiler to inline through the entire
48 call chain.
49
50 Non-async operations (`open`, `close`, `cancel`, `bind`,
51 socket options) remain unchanged and dispatch through the
52 compiled library.
53
54 A `native_udp_socket` IS-A `udp_socket` and can be passed to
55 any function expecting `udp_socket&`, in which case virtual
56 dispatch is used transparently.
57
58 @tparam Backend A backend tag value (e.g., `epoll`)
59 whose type provides the concrete implementation types.
60
61 @par Thread Safety
62 Same as @ref udp_socket.
63
64 @par Example
65 @par !example native_udp_socket
66
67 @see udp_socket, epoll_t
68 */
69 template<auto Backend>
70 class native_udp_socket : public udp_socket
71 {
72 using backend_type = decltype(Backend);
73 using impl_type = typename backend_type::udp_socket_type;
74 using service_type = typename backend_type::udp_service_type;
75
76 28x impl_type& get_impl() noexcept
77 {
78 28x return *static_cast<impl_type*>(h_.get());
79 }
80
81 template<class ConstBufferSequence>
82 struct native_send_to_awaitable
83 : detail::bytes_op_base<native_send_to_awaitable<ConstBufferSequence>>
84 {
85 native_udp_socket& self_;
86 ConstBufferSequence buffers_;
87 endpoint dest_;
88 int flags_;
89
90 8x native_send_to_awaitable(
91 native_udp_socket& self,
92 ConstBufferSequence buffers,
93 endpoint dest,
94 int flags) noexcept
95 8x : self_(self)
96 8x , buffers_(std::move(buffers))
97 8x , dest_(dest)
98 8x , flags_(flags)
99 {
100 8x }
101
102 std::coroutine_handle<>
103 4x dispatch(std::coroutine_handle<> h, capy::executor_ref ex) const
104 {
105 12x return self_.get_impl().send_to(
106 4x h, ex, buffers_, dest_, flags_, this->token_, &this->ec_,
107 8x &this->bytes_);
108 }
109 };
110
111 template<class MutableBufferSequence>
112 struct native_recv_from_awaitable
113 : detail::bytes_op_base<
114 native_recv_from_awaitable<MutableBufferSequence>>
115 {
116 native_udp_socket& self_;
117 MutableBufferSequence buffers_;
118 endpoint& source_;
119 int flags_;
120
121 12x native_recv_from_awaitable(
122 native_udp_socket& self,
123 MutableBufferSequence buffers,
124 endpoint& source,
125 int flags) noexcept
126 12x : self_(self)
127 12x , buffers_(std::move(buffers))
128 12x , source_(source)
129 12x , flags_(flags)
130 {
131 12x }
132
133 std::coroutine_handle<>
134 8x dispatch(std::coroutine_handle<> h, capy::executor_ref ex) const
135 {
136 24x return self_.get_impl().recv_from(
137 8x h, ex, buffers_, &source_, flags_, this->token_, &this->ec_,
138 16x &this->bytes_);
139 }
140 };
141
142 struct native_wait_awaitable : detail::void_op_base<native_wait_awaitable>
143 {
144 native_udp_socket& self_;
145 wait_type w_;
146
147 4x native_wait_awaitable(native_udp_socket& self, wait_type w) noexcept
148 4x : self_(self)
149 4x , w_(w)
150 {
151 4x }
152
153 std::coroutine_handle<>
154 2x dispatch(std::coroutine_handle<> h, capy::executor_ref ex) const
155 {
156 2x return self_.get_impl().wait(h, ex, w_, this->token_, &this->ec_);
157 }
158 };
159
160 struct native_connect_awaitable
161 : detail::void_op_base<native_connect_awaitable>
162 {
163 native_udp_socket& self_;
164 endpoint endpoint_;
165
166 10x native_connect_awaitable(native_udp_socket& self, endpoint ep) noexcept
167 10x : self_(self)
168 10x , endpoint_(ep)
169 {
170 10x }
171
172 std::coroutine_handle<>
173 8x dispatch(std::coroutine_handle<> h, capy::executor_ref ex) const
174 {
175 24x return self_.get_impl().connect(
176 24x h, ex, endpoint_, this->token_, &this->ec_);
177 }
178 };
179
180 template<class ConstBufferSequence>
181 struct native_send_awaitable
182 : detail::bytes_op_base<native_send_awaitable<ConstBufferSequence>>
183 {
184 native_udp_socket& self_;
185 ConstBufferSequence buffers_;
186 int flags_;
187
188 8x native_send_awaitable(
189 native_udp_socket& self,
190 ConstBufferSequence buffers,
191 int flags) noexcept
192 8x : self_(self)
193 8x , buffers_(std::move(buffers))
194 8x , flags_(flags)
195 {
196 8x }
197
198 std::coroutine_handle<>
199 4x dispatch(std::coroutine_handle<> h, capy::executor_ref ex) const
200 {
201 12x return self_.get_impl().send(
202 4x h, ex, buffers_, flags_, this->token_, &this->ec_,
203 8x &this->bytes_);
204 }
205 };
206
207 template<class MutableBufferSequence>
208 struct native_recv_awaitable
209 : detail::bytes_op_base<native_recv_awaitable<MutableBufferSequence>>
210 {
211 native_udp_socket& self_;
212 MutableBufferSequence buffers_;
213 int flags_;
214
215 6x native_recv_awaitable(
216 native_udp_socket& self,
217 MutableBufferSequence buffers,
218 int flags) noexcept
219 6x : self_(self)
220 6x , buffers_(std::move(buffers))
221 6x , flags_(flags)
222 {
223 6x }
224
225 std::coroutine_handle<>
226 2x dispatch(std::coroutine_handle<> h, capy::executor_ref ex) const
227 {
228 6x return self_.get_impl().recv(
229 2x h, ex, buffers_, flags_, this->token_, &this->ec_,
230 4x &this->bytes_);
231 }
232 };
233
234 public:
235 /** Construct a native UDP socket from an execution context.
236
237 @param ctx The execution context that will own this socket.
238 */
239 42x explicit native_udp_socket(capy::execution_context& ctx)
240 42x : udp_socket(create_handle<service_type>(ctx))
241 {
242 42x }
243
244 /** Construct a native UDP socket from an executor.
245
246 @param ex The executor whose context will own the socket.
247 */
248 template<class Ex>
249 requires(!std::same_as<std::remove_cvref_t<Ex>, native_udp_socket>) &&
250 capy::Executor<Ex>
251 explicit native_udp_socket(Ex const& ex) : native_udp_socket(ex.context())
252 {
253 }
254
255 /// Move construct.
256 2x native_udp_socket(native_udp_socket&&) noexcept = default;
257
258 /// Move assign.
259 native_udp_socket& operator=(native_udp_socket&&) noexcept = default;
260
261 native_udp_socket(native_udp_socket const&) = delete;
262 native_udp_socket& operator=(native_udp_socket const&) = delete;
263
264 /** Send a datagram to the specified destination.
265
266 Calls the backend implementation directly, bypassing virtual
267 dispatch. Otherwise identical to @ref udp_socket::send_to.
268
269 @param buffers The buffer sequence containing data to send.
270 @param dest The destination endpoint.
271 @param flags Message flags.
272
273 @return An awaitable yielding `(error_code, std::size_t)`.
274
275 A closed socket reports `errc::bad_file_descriptor`.
276 */
277 template<capy::ConstBufferSequence CB>
278 [[nodiscard]] auto
279 8x send_to(CB const& buffers, endpoint dest, corosio::message_flags flags)
280 {
281 8x native_send_to_awaitable<CB> aw(
282 *this, buffers, dest, static_cast<int>(flags));
283 8x if (!is_open())
284 2x aw.ec_ = make_error_code(std::errc::bad_file_descriptor);
285 8x return aw;
286 }
287
288 /// @overload
289 template<capy::ConstBufferSequence CB>
290 8x [[nodiscard]] auto send_to(CB const& buffers, endpoint dest)
291 {
292 8x return send_to(buffers, dest, corosio::message_flags::none);
293 }
294
295 /** Receive a datagram and capture the sender's endpoint.
296
297 Calls the backend implementation directly, bypassing virtual
298 dispatch. Otherwise identical to @ref udp_socket::recv_from.
299
300 @param buffers The buffer sequence to receive data into.
301 @param source Reference to an endpoint that will be set to
302 the sender's address on successful completion.
303 @param flags Message flags (e.g. message_flags::peek).
304
305 @return An awaitable yielding `(error_code, std::size_t)`.
306
307 A closed socket reports `errc::bad_file_descriptor`.
308 */
309 template<capy::MutableBufferSequence MB>
310 [[nodiscard]] auto
311 12x recv_from(MB const& buffers, endpoint& source, corosio::message_flags flags)
312 {
313 12x native_recv_from_awaitable<MB> aw(
314 *this, buffers, source, static_cast<int>(flags));
315 12x if (!is_open())
316 2x aw.ec_ = make_error_code(std::errc::bad_file_descriptor);
317 12x return aw;
318 }
319
320 /// @overload
321 template<capy::MutableBufferSequence MB>
322 12x [[nodiscard]] auto recv_from(MB const& buffers, endpoint& source)
323 {
324 12x return recv_from(buffers, source, corosio::message_flags::none);
325 }
326
327 /** Asynchronously connect to set the default peer.
328
329 Calls the backend implementation directly, bypassing virtual
330 dispatch. Otherwise identical to @ref udp_socket::connect.
331
332 If the socket is not already open, it is opened automatically
333 using the address family of @p ep.
334
335 @param ep The remote endpoint to connect to.
336
337 @return An awaitable yielding `io_result<>`.
338
339 If the socket needs to be opened and the open fails, the
340 awaitable completes immediately with that error.
341 */
342 10x [[nodiscard]] auto connect(endpoint ep)
343 {
344 10x native_connect_awaitable aw(*this, ep);
345 10x if (!is_open())
346 4x aw.ec_ = open(ep.address().family());
347 10x return aw;
348 }
349
350 /** Send a datagram to the connected peer.
351
352 Calls the backend implementation directly, bypassing virtual
353 dispatch. Otherwise identical to @ref udp_socket::send.
354
355 @param buffers The buffer sequence containing data to send.
356 @param flags Message flags.
357
358 @return An awaitable yielding `(error_code, std::size_t)`.
359
360 A closed socket reports `errc::bad_file_descriptor`.
361 */
362 template<capy::ConstBufferSequence CB>
363 8x [[nodiscard]] auto send(CB const& buffers, corosio::message_flags flags)
364 {
365 8x native_send_awaitable<CB> aw(*this, buffers, static_cast<int>(flags));
366 8x if (!is_open())
367 2x aw.ec_ = make_error_code(std::errc::bad_file_descriptor);
368 8x return aw;
369 }
370
371 /// @overload
372 template<capy::ConstBufferSequence CB>
373 8x [[nodiscard]] auto send(CB const& buffers)
374 {
375 8x return send(buffers, corosio::message_flags::none);
376 }
377
378 /** Receive a datagram from the connected peer.
379
380 Calls the backend implementation directly, bypassing virtual
381 dispatch. Otherwise identical to @ref udp_socket::recv.
382
383 @param buffers The buffer sequence to receive data into.
384 @param flags Message flags (e.g. message_flags::peek).
385
386 @return An awaitable yielding `(error_code, std::size_t)`.
387
388 A closed socket reports `errc::bad_file_descriptor`.
389 */
390 template<capy::MutableBufferSequence MB>
391 6x [[nodiscard]] auto recv(MB const& buffers, corosio::message_flags flags)
392 {
393 6x native_recv_awaitable<MB> aw(*this, buffers, static_cast<int>(flags));
394 6x if (!is_open())
395 2x aw.ec_ = make_error_code(std::errc::bad_file_descriptor);
396 6x return aw;
397 }
398
399 /// @overload
400 template<capy::MutableBufferSequence MB>
401 6x [[nodiscard]] auto recv(MB const& buffers)
402 {
403 6x return recv(buffers, corosio::message_flags::none);
404 }
405
406 /** Asynchronously wait for the socket to be ready.
407
408 Calls the backend implementation directly, bypassing virtual
409 dispatch. Otherwise identical to @ref udp_socket::wait.
410
411 @param w The wait direction (read, write, or error).
412
413 @return An awaitable yielding `io_result<>`.
414 */
415 4x [[nodiscard]] auto wait(wait_type w)
416 {
417 4x return native_wait_awaitable(*this, w);
418 }
419 };
420
421 } // namespace boost::corosio
422
423 #endif // BOOST_COROSIO_NATIVE_NATIVE_UDP_SOCKET_HPP
424