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() :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(std::__n4861::coroutine_handle<void>, 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(std::__n4861::coroutine_handle<void>, 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(std::__n4861::coroutine_handle<void>, 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(std::__n4861::coroutine_handle<void>, 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(std::__n4861::coroutine_handle<void>, boost::capy::executor_ref) const :153 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 :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) :165 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) :165 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 :172 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 :172 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) :187 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) :187 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 :198 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 :198 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) :214 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) :214 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 :225 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 :225 1x 100.0% 75.0% boost::corosio::native_udp_socket<boost::corosio::epoll_t{}>::native_udp_socket(boost::capy::execution_context&) :238 21x 100.0% 100.0% boost::corosio::native_udp_socket<boost::corosio::select_t{}>::native_udp_socket(boost::capy::execution_context&) :238 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{}>&&) :266 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{}>&&) :266 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) :299 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) :299 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) :310 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) :310 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) :331 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) :331 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&) :342 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&) :342 6x 100.0% 100.0% boost::corosio::native_udp_socket<boost::corosio::epoll_t{}>::connect(boost::corosio::endpoint) :362 5x 100.0% 100.0% boost::corosio::native_udp_socket<boost::corosio::select_t{}>::connect(boost::corosio::endpoint) :362 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) :383 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) :383 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&) :393 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&) :393 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) :411 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) :411 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&) :421 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&) :421 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(std::coroutine_handle<> h, capy::executor_ref ex) const
103 {
104 12x return self_.get_impl().send_to(
105 4x h, 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(std::coroutine_handle<> h, capy::executor_ref ex) const
134 {
135 24x return self_.get_impl().recv_from(
136 8x h, 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(std::coroutine_handle<> h, capy::executor_ref ex) const
154 {
155 2x return self_.get_impl().wait(h, ex, w_, this->token_, &this->ec_);
156 }
157 };
158
159 struct native_connect_awaitable
160 : detail::void_op_base<native_connect_awaitable>
161 {
162 native_udp_socket& self_;
163 endpoint endpoint_;
164
165 10x native_connect_awaitable(native_udp_socket& self, endpoint ep) noexcept
166 10x : self_(self)
167 10x , endpoint_(ep)
168 {
169 10x }
170
171 std::coroutine_handle<>
172 8x dispatch(std::coroutine_handle<> h, capy::executor_ref ex) const
173 {
174 24x return self_.get_impl().connect(
175 24x h, ex, endpoint_, this->token_, &this->ec_);
176 }
177 };
178
179 template<class ConstBufferSequence>
180 struct native_send_awaitable
181 : detail::bytes_op_base<native_send_awaitable<ConstBufferSequence>>
182 {
183 native_udp_socket& self_;
184 ConstBufferSequence buffers_;
185 int flags_;
186
187 8x native_send_awaitable(
188 native_udp_socket& self,
189 ConstBufferSequence buffers,
190 int flags) noexcept
191 8x : self_(self)
192 8x , buffers_(std::move(buffers))
193 8x , flags_(flags)
194 {
195 8x }
196
197 std::coroutine_handle<>
198 4x dispatch(std::coroutine_handle<> h, capy::executor_ref ex) const
199 {
200 12x return self_.get_impl().send(
201 4x h, ex, buffers_, flags_, this->token_, &this->ec_,
202 8x &this->bytes_);
203 }
204 };
205
206 template<class MutableBufferSequence>
207 struct native_recv_awaitable
208 : detail::bytes_op_base<native_recv_awaitable<MutableBufferSequence>>
209 {
210 native_udp_socket& self_;
211 MutableBufferSequence buffers_;
212 int flags_;
213
214 6x native_recv_awaitable(
215 native_udp_socket& self,
216 MutableBufferSequence buffers,
217 int flags) noexcept
218 6x : self_(self)
219 6x , buffers_(std::move(buffers))
220 6x , flags_(flags)
221 {
222 6x }
223
224 std::coroutine_handle<>
225 2x dispatch(std::coroutine_handle<> h, capy::executor_ref ex) const
226 {
227 6x return self_.get_impl().recv(
228 2x h, ex, buffers_, flags_, this->token_, &this->ec_,
229 4x &this->bytes_);
230 }
231 };
232
233 public:
234 /** Construct a native UDP socket from an execution context.
235
236 @param ctx The execution context that owns this socket.
237 */
238 42x explicit native_udp_socket(capy::execution_context& ctx)
239 42x : udp_socket(create_handle<service_type>(ctx))
240 {
241 42x }
242
243 /** Construct a native UDP socket from an executor.
244
245 @param ex The executor whose context owns the socket.
246
247 @tparam Ex A type satisfying @ref capy::Executor. Must not
248 be `native_udp_socket` itself (disables implicit
249 conversion from move).
250 */
251 template<class Ex>
252 requires(!std::same_as<std::remove_cvref_t<Ex>, native_udp_socket>) &&
253 capy::Executor<Ex>
254 explicit native_udp_socket(Ex const& ex) : native_udp_socket(ex.context())
255 {
256 }
257
258 /** Move construct.
259
260 @param other The socket to move from.
261
262 @pre No awaitables returned by @p other's methods exist.
263 @pre The execution context associated with @p other must
264 outlive this socket.
265 */
266 2x native_udp_socket(native_udp_socket&&) noexcept = default;
267
268 /** Move assign.
269
270 @param other The socket to move from.
271
272 @pre No awaitables returned by either `*this` or @p other's
273 methods exist.
274 @pre The execution context associated with @p other must
275 outlive this socket.
276 */
277 native_udp_socket& operator=(native_udp_socket&&) noexcept = default;
278
279 /// Copy construction is disabled; the handle is uniquely owned.
280 native_udp_socket(native_udp_socket const&) = delete;
281 /// Copy assignment is disabled; the handle is uniquely owned.
282 native_udp_socket& operator=(native_udp_socket const&) = delete;
283
284 /** Send a datagram to the specified destination.
285
286 Calls the backend implementation directly, bypassing virtual
287 dispatch. Otherwise identical to @ref udp_socket::send_to.
288
289 @param buffers The buffer sequence containing data to send.
290 @param dest The destination endpoint.
291 @param flags Message flags.
292
293 @return An awaitable yielding `(error_code, std::size_t)`.
294
295 A closed socket reports `errc::bad_file_descriptor`.
296 */
297 template<capy::ConstBufferSequence CB>
298 [[nodiscard]] auto
299 8x send_to(CB const& buffers, endpoint dest, corosio::message_flags flags)
300 {
301 8x native_send_to_awaitable<CB> aw(
302 *this, buffers, dest, static_cast<int>(flags));
303 8x if (!is_open())
304 2x aw.ec_ = make_error_code(std::errc::bad_file_descriptor);
305 8x return aw;
306 }
307
308 /// @overload
309 template<capy::ConstBufferSequence CB>
310 8x [[nodiscard]] auto send_to(CB const& buffers, endpoint dest)
311 {
312 8x return send_to(buffers, dest, corosio::message_flags::none);
313 }
314
315 /** Receive a datagram and capture the sender's endpoint.
316
317 Calls the backend implementation directly, bypassing virtual
318 dispatch. Otherwise identical to @ref udp_socket::recv_from.
319
320 @param buffers The buffer sequence to receive data into.
321 @param source Reference to an endpoint that receives
322 the sender's address on successful completion.
323 @param flags Message flags (e.g. message_flags::peek).
324
325 @return An awaitable yielding `(error_code, std::size_t)`.
326
327 A closed socket reports `errc::bad_file_descriptor`.
328 */
329 template<capy::MutableBufferSequence MB>
330 [[nodiscard]] auto
331 12x recv_from(MB const& buffers, endpoint& source, corosio::message_flags flags)
332 {
333 12x native_recv_from_awaitable<MB> aw(
334 *this, buffers, source, static_cast<int>(flags));
335 12x if (!is_open())
336 2x aw.ec_ = make_error_code(std::errc::bad_file_descriptor);
337 12x return aw;
338 }
339
340 /// @overload
341 template<capy::MutableBufferSequence MB>
342 12x [[nodiscard]] auto recv_from(MB const& buffers, endpoint& source)
343 {
344 12x return recv_from(buffers, source, corosio::message_flags::none);
345 }
346
347 /** Asynchronously connect to set the default peer.
348
349 Calls the backend implementation directly, bypassing virtual
350 dispatch. Otherwise identical to @ref udp_socket::connect.
351
352 If the socket is not already open, it is opened automatically
353 using the address family of @p ep.
354
355 @param ep The remote endpoint to connect to.
356
357 @return An awaitable yielding `io_result<>`.
358
359 If the socket needs to be opened and the open fails, the
360 awaitable completes immediately with that error.
361 */
362 10x [[nodiscard]] auto connect(endpoint ep)
363 {
364 10x native_connect_awaitable aw(*this, ep);
365 10x if (!is_open())
366 4x aw.ec_ = open(ep.address().family());
367 10x return aw;
368 }
369
370 /** Send a datagram to the connected peer.
371
372 Calls the backend implementation directly, bypassing virtual
373 dispatch. Otherwise identical to @ref udp_socket::send.
374
375 @param buffers The buffer sequence containing data to send.
376 @param flags Message flags.
377
378 @return An awaitable yielding `(error_code, std::size_t)`.
379
380 A closed socket reports `errc::bad_file_descriptor`.
381 */
382 template<capy::ConstBufferSequence CB>
383 8x [[nodiscard]] auto send(CB const& buffers, corosio::message_flags flags)
384 {
385 8x native_send_awaitable<CB> aw(*this, buffers, static_cast<int>(flags));
386 8x if (!is_open())
387 2x aw.ec_ = make_error_code(std::errc::bad_file_descriptor);
388 8x return aw;
389 }
390
391 /// @overload
392 template<capy::ConstBufferSequence CB>
393 8x [[nodiscard]] auto send(CB const& buffers)
394 {
395 8x return send(buffers, corosio::message_flags::none);
396 }
397
398 /** Receive a datagram from the connected peer.
399
400 Calls the backend implementation directly, bypassing virtual
401 dispatch. Otherwise identical to @ref udp_socket::recv.
402
403 @param buffers The buffer sequence to receive data into.
404 @param flags Message flags (e.g. message_flags::peek).
405
406 @return An awaitable yielding `(error_code, std::size_t)`.
407
408 A closed socket reports `errc::bad_file_descriptor`.
409 */
410 template<capy::MutableBufferSequence MB>
411 6x [[nodiscard]] auto recv(MB const& buffers, corosio::message_flags flags)
412 {
413 6x native_recv_awaitable<MB> aw(*this, buffers, static_cast<int>(flags));
414 6x if (!is_open())
415 2x aw.ec_ = make_error_code(std::errc::bad_file_descriptor);
416 6x return aw;
417 }
418
419 /// @overload
420 template<capy::MutableBufferSequence MB>
421 6x [[nodiscard]] auto recv(MB const& buffers)
422 {
423 6x return recv(buffers, corosio::message_flags::none);
424 }
425
426 /** Asynchronously wait for the socket to be ready.
427
428 Calls the backend implementation directly, bypassing virtual
429 dispatch. Otherwise identical to @ref udp_socket::wait.
430
431 @param w The wait direction (read, write, or error).
432
433 @return An awaitable yielding `io_result<>`.
434 */
435 4x [[nodiscard]] auto wait(wait_type w)
436 {
437 4x return native_wait_awaitable(*this, w);
438 }
439 };
440
441 } // namespace boost::corosio
442
443 #endif // BOOST_COROSIO_NATIVE_NATIVE_UDP_SOCKET_HPP
444