include/boost/corosio/native/native_udp_socket.hpp

100.0% Lines (93 / 93) 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() :75 14x 100.0% 100.0% boost::corosio::native_udp_socket<boost::corosio::select_t{}>::get_impl() :75 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) :89 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) :89 4x 100.0% 100.0% boost::corosio::native_udp_socket<boost::corosio::epoll_t{}>::native_send_to_awaitable<boost::capy::const_buffer>::dispatch(boost::capy::continuation&, boost::capy::executor_ref) const :102 2x 100.0% 75.0% boost::corosio::native_udp_socket<boost::corosio::select_t{}>::native_send_to_awaitable<boost::capy::const_buffer>::dispatch(boost::capy::continuation&, boost::capy::executor_ref) const :102 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) :120 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) :120 6x 100.0% 100.0% boost::corosio::native_udp_socket<boost::corosio::epoll_t{}>::native_recv_from_awaitable<boost::capy::mutable_buffer>::dispatch(boost::capy::continuation&, boost::capy::executor_ref) const :133 4x 100.0% 75.0% boost::corosio::native_udp_socket<boost::corosio::select_t{}>::native_recv_from_awaitable<boost::capy::mutable_buffer>::dispatch(boost::capy::continuation&, boost::capy::executor_ref) const :133 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) :146 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) :146 2x 100.0% 100.0% boost::corosio::native_udp_socket<boost::corosio::epoll_t{}>::native_wait_awaitable::dispatch(boost::capy::continuation&, boost::capy::executor_ref) const :153 1x 100.0% 80.0% boost::corosio::native_udp_socket<boost::corosio::select_t{}>::native_wait_awaitable::dispatch(boost::capy::continuation&, boost::capy::executor_ref) const :153 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(boost::capy::continuation&, boost::capy::executor_ref) const :173 4x 100.0% 80.0% boost::corosio::native_udp_socket<boost::corosio::select_t{}>::native_connect_awaitable::dispatch(boost::capy::continuation&, 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(boost::capy::continuation&, 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(boost::capy::continuation&, 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(boost::capy::continuation&, 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(boost::capy::continuation&, 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{}>&&) :267 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{}>&&) :267 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) :300 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) :300 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) :311 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) :311 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) :332 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) :332 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&) :343 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&) :343 6x 100.0% 100.0% boost::corosio::native_udp_socket<boost::corosio::epoll_t{}>::connect(boost::corosio::endpoint) :363 5x 100.0% 100.0% boost::corosio::native_udp_socket<boost::corosio::select_t{}>::connect(boost::corosio::endpoint) :363 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) :384 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) :384 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&) :394 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&) :394 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) :412 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) :412 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&) :422 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&) :422 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 /** Sends and receives UDP datagrams, calling the backend directly.
43
44 This class template inherits from @ref udp_socket. It shadows the
45 async operations (`send_to`, `recv_from`, `connect`, `send`, `recv`)
46 with versions that call the backend implementation directly. The
47 compiler can then inline through the entire call chain.
48
49 Non-async operations (`open`, `close`, `cancel`, `bind`,
50 socket options) remain unchanged and dispatch through the
51 compiled library.
52
53 A `native_udp_socket` IS-A `udp_socket` and can be passed to
54 any function expecting `udp_socket&`, in which case virtual
55 dispatch is used transparently.
56
57 @tparam Backend A backend tag value (e.g., `epoll`)
58 whose type provides the concrete implementation types.
59
60 @par Thread Safety
61 Same as @ref udp_socket.
62
63 @par Example
64 @par !example native_udp_socket
65
66 @see udp_socket, epoll_t
67 */
68 template<auto Backend>
69 class native_udp_socket : public udp_socket
70 {
71 using backend_type = decltype(Backend);
72 using impl_type = typename backend_type::udp_socket_type;
73 using service_type = typename backend_type::udp_service_type;
74
75 28x impl_type& get_impl() noexcept
76 {
77 28x return *static_cast<impl_type*>(h_.get());
78 }
79
80 template<class ConstBufferSequence>
81 struct native_send_to_awaitable
82 : detail::bytes_op_base<native_send_to_awaitable<ConstBufferSequence>>
83 {
84 native_udp_socket& self_;
85 ConstBufferSequence buffers_;
86 endpoint dest_;
87 int flags_;
88
89 8x native_send_to_awaitable(
90 native_udp_socket& self,
91 ConstBufferSequence buffers,
92 endpoint dest,
93 int flags) noexcept
94 8x : self_(self)
95 8x , buffers_(std::move(buffers))
96 8x , dest_(dest)
97 8x , flags_(flags)
98 {
99 8x }
100
101 std::coroutine_handle<>
102 4x dispatch(capy::continuation& cont, capy::executor_ref ex) const
103 {
104 12x return self_.get_impl().send_to(
105 4x cont, ex, buffers_, dest_, flags_, this->token_, &this->ec_,
106 8x &this->bytes_);
107 }
108 };
109
110 template<class MutableBufferSequence>
111 struct native_recv_from_awaitable
112 : detail::bytes_op_base<
113 native_recv_from_awaitable<MutableBufferSequence>>
114 {
115 native_udp_socket& self_;
116 MutableBufferSequence buffers_;
117 endpoint& source_;
118 int flags_;
119
120 12x native_recv_from_awaitable(
121 native_udp_socket& self,
122 MutableBufferSequence buffers,
123 endpoint& source,
124 int flags) noexcept
125 12x : self_(self)
126 12x , buffers_(std::move(buffers))
127 12x , source_(source)
128 12x , flags_(flags)
129 {
130 12x }
131
132 std::coroutine_handle<>
133 8x dispatch(capy::continuation& cont, capy::executor_ref ex) const
134 {
135 24x return self_.get_impl().recv_from(
136 8x cont, ex, buffers_, &source_, flags_, this->token_, &this->ec_,
137 16x &this->bytes_);
138 }
139 };
140
141 struct native_wait_awaitable : detail::void_op_base<native_wait_awaitable>
142 {
143 native_udp_socket& self_;
144 wait_type w_;
145
146 4x native_wait_awaitable(native_udp_socket& self, wait_type w) noexcept
147 4x : self_(self)
148 4x , w_(w)
149 {
150 4x }
151
152 std::coroutine_handle<>
153 2x dispatch(capy::continuation& cont, capy::executor_ref ex) const
154 {
155 4x return self_.get_impl().wait(
156 4x cont, 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(capy::continuation& cont, capy::executor_ref ex) const
174 {
175 24x return self_.get_impl().connect(
176 24x cont, 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(capy::continuation& cont, capy::executor_ref ex) const
200 {
201 12x return self_.get_impl().send(
202 4x cont, 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(capy::continuation& cont, capy::executor_ref ex) const
227 {
228 6x return self_.get_impl().recv(
229 2x cont, 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 owns this socket.
238 */
239 42x explicit native_udp_socket(capy::execution_context& ctx)
240 42x : udp_socket(handle(ctx, ctx.use_service<service_type>()))
241 {
242 42x }
243
244 /** Construct a native UDP socket from an executor.
245
246 @param ex The executor whose context owns the socket.
247
248 @tparam Ex A type satisfying @ref capy::Executor. Must not
249 be `native_udp_socket` itself (disables implicit
250 conversion from move).
251 */
252 template<class Ex>
253 requires(!std::same_as<std::remove_cvref_t<Ex>, native_udp_socket>) &&
254 capy::Executor<Ex>
255 explicit native_udp_socket(Ex const& ex) : native_udp_socket(ex.context())
256 {
257 }
258
259 /** Move construct.
260
261 @param other The socket to move from.
262
263 @pre No awaitables returned by @p other's methods exist.
264 @pre The execution context associated with @p other must
265 outlive this socket.
266 */
267 2x native_udp_socket(native_udp_socket&&) noexcept = default;
268
269 /** Move assign.
270
271 @param other The socket to move from.
272
273 @pre No awaitables returned by either `*this` or @p other's
274 methods exist.
275 @pre The execution context associated with @p other must
276 outlive this socket.
277 */
278 native_udp_socket& operator=(native_udp_socket&&) noexcept = default;
279
280 /// Copy construction is disabled; the handle is uniquely owned.
281 native_udp_socket(native_udp_socket const&) = delete;
282 /// Copy assignment is disabled; the handle is uniquely owned.
283 native_udp_socket& operator=(native_udp_socket const&) = delete;
284
285 /** Send a datagram to the specified destination.
286
287 Calls the backend implementation directly, bypassing virtual
288 dispatch. Otherwise identical to @ref udp_socket::send_to.
289
290 @param buffers The buffer sequence containing data to send.
291 @param dest The destination endpoint.
292 @param flags Message flags.
293
294 @return An awaitable yielding `(error_code, std::size_t)`.
295
296 A closed socket reports `errc::bad_file_descriptor`.
297 */
298 template<capy::ConstBufferSequence CB>
299 [[nodiscard]] auto
300 8x send_to(CB const& buffers, endpoint dest, corosio::message_flags flags)
301 {
302 8x native_send_to_awaitable<CB> aw(
303 *this, buffers, dest, static_cast<int>(flags));
304 8x if (!is_open())
305 2x aw.ec_ = make_error_code(std::errc::bad_file_descriptor);
306 8x return aw;
307 }
308
309 /// @overload
310 template<capy::ConstBufferSequence CB>
311 8x [[nodiscard]] auto send_to(CB const& buffers, endpoint dest)
312 {
313 8x return send_to(buffers, dest, corosio::message_flags::none);
314 }
315
316 /** Receive a datagram and capture the sender's endpoint.
317
318 Calls the backend implementation directly, bypassing virtual
319 dispatch. Otherwise identical to @ref udp_socket::recv_from.
320
321 @param buffers The buffer sequence to receive data into.
322 @param source Reference to an endpoint that receives
323 the sender's address on successful completion.
324 @param flags Message flags (e.g. message_flags::peek).
325
326 @return An awaitable yielding `(error_code, std::size_t)`.
327
328 A closed socket reports `errc::bad_file_descriptor`.
329 */
330 template<capy::MutableBufferSequence MB>
331 [[nodiscard]] auto
332 12x recv_from(MB const& buffers, endpoint& source, corosio::message_flags flags)
333 {
334 12x native_recv_from_awaitable<MB> aw(
335 *this, buffers, source, static_cast<int>(flags));
336 12x if (!is_open())
337 2x aw.ec_ = make_error_code(std::errc::bad_file_descriptor);
338 12x return aw;
339 }
340
341 /// @overload
342 template<capy::MutableBufferSequence MB>
343 12x [[nodiscard]] auto recv_from(MB const& buffers, endpoint& source)
344 {
345 12x return recv_from(buffers, source, corosio::message_flags::none);
346 }
347
348 /** Asynchronously connect to set the default peer.
349
350 Calls the backend implementation directly, bypassing virtual
351 dispatch. Otherwise identical to @ref udp_socket::connect.
352
353 If the socket is not already open, it is opened automatically
354 using the address family of @p ep.
355
356 @param ep The remote endpoint to connect to.
357
358 @return An awaitable yielding `results<>`.
359
360 If the socket needs to be opened and the open fails, the
361 awaitable completes immediately with that error.
362 */
363 10x [[nodiscard]] auto connect(endpoint ep)
364 {
365 10x native_connect_awaitable aw(*this, ep);
366 10x if (!is_open())
367 4x aw.ec_ = open(ep.address().family());
368 10x return aw;
369 }
370
371 /** Send a datagram to the connected peer.
372
373 Calls the backend implementation directly, bypassing virtual
374 dispatch. Otherwise identical to @ref udp_socket::send.
375
376 @param buffers The buffer sequence containing data to send.
377 @param flags Message flags.
378
379 @return An awaitable yielding `(error_code, std::size_t)`.
380
381 A closed socket reports `errc::bad_file_descriptor`.
382 */
383 template<capy::ConstBufferSequence CB>
384 8x [[nodiscard]] auto send(CB const& buffers, corosio::message_flags flags)
385 {
386 8x native_send_awaitable<CB> aw(*this, buffers, static_cast<int>(flags));
387 8x if (!is_open())
388 2x aw.ec_ = make_error_code(std::errc::bad_file_descriptor);
389 8x return aw;
390 }
391
392 /// @overload
393 template<capy::ConstBufferSequence CB>
394 8x [[nodiscard]] auto send(CB const& buffers)
395 {
396 8x return send(buffers, corosio::message_flags::none);
397 }
398
399 /** Receive a datagram from the connected peer.
400
401 Calls the backend implementation directly, bypassing virtual
402 dispatch. Otherwise identical to @ref udp_socket::recv.
403
404 @param buffers The buffer sequence to receive data into.
405 @param flags Message flags (e.g. message_flags::peek).
406
407 @return An awaitable yielding `(error_code, std::size_t)`.
408
409 A closed socket reports `errc::bad_file_descriptor`.
410 */
411 template<capy::MutableBufferSequence MB>
412 6x [[nodiscard]] auto recv(MB const& buffers, corosio::message_flags flags)
413 {
414 6x native_recv_awaitable<MB> aw(*this, buffers, static_cast<int>(flags));
415 6x if (!is_open())
416 2x aw.ec_ = make_error_code(std::errc::bad_file_descriptor);
417 6x return aw;
418 }
419
420 /// @overload
421 template<capy::MutableBufferSequence MB>
422 6x [[nodiscard]] auto recv(MB const& buffers)
423 {
424 6x return recv(buffers, corosio::message_flags::none);
425 }
426
427 /** Asynchronously wait for the socket to be ready.
428
429 Calls the backend implementation directly, bypassing virtual
430 dispatch. Otherwise identical to @ref udp_socket::wait.
431
432 @param w The wait direction (read, write, or error).
433
434 @return An awaitable yielding `results<>`.
435 */
436 4x [[nodiscard]] auto wait(wait_type w)
437 {
438 4x return native_wait_awaitable(*this, w);
439 }
440 };
441
442 } // namespace boost::corosio
443
444 #endif // BOOST_COROSIO_NATIVE_NATIVE_UDP_SOCKET_HPP
445