include/boost/corosio/native/native_udp_socket.hpp

100.0% Lines (92/92) 100.0% List of functions (25/25) 100.0% Branches (18/18)
native_udp_socket.hpp
f(x) Functions (25)
Function Calls Lines Branches Blocks
boost::corosio::native_udp_socket<boost::corosio::iocp_t{}>::get_impl() :75 14x 100.0% – 100.0% boost::corosio::native_udp_socket<boost::corosio::iocp_t{}>::native_send_to_awaitable<boost::capy::const_buffer>::native_send_to_awaitable(boost::corosio::native_udp_socket<boost::corosio::iocp_t{}>&, boost::capy::const_buffer, boost::corosio::endpoint, int) :89 4x 100.0% – 100.0% boost::corosio::native_udp_socket<boost::corosio::iocp_t{}>::native_send_to_awaitable<boost::capy::const_buffer>::dispatch(std::__n4861::coroutine_handle<void>, boost::capy::executor_ref) const :102 2x 100.0% 100.0% 75.0% boost::corosio::native_udp_socket<boost::corosio::iocp_t{}>::native_recv_from_awaitable<boost::capy::mutable_buffer>::native_recv_from_awaitable(boost::corosio::native_udp_socket<boost::corosio::iocp_t{}>&, boost::capy::mutable_buffer, boost::corosio::endpoint&, int) :120 6x 100.0% – 100.0% boost::corosio::native_udp_socket<boost::corosio::iocp_t{}>::native_recv_from_awaitable<boost::capy::mutable_buffer>::dispatch(std::__n4861::coroutine_handle<void>, boost::capy::executor_ref) const :133 4x 100.0% 100.0% 75.0% boost::corosio::native_udp_socket<boost::corosio::iocp_t{}>::native_wait_awaitable::native_wait_awaitable(boost::corosio::native_udp_socket<boost::corosio::iocp_t{}>&, boost::corosio::wait_type) :146 2x 100.0% – 100.0% boost::corosio::native_udp_socket<boost::corosio::iocp_t{}>::native_wait_awaitable::dispatch(std::__n4861::coroutine_handle<void>, boost::capy::executor_ref) const :153 1x 100.0% 100.0% 80.0% boost::corosio::native_udp_socket<boost::corosio::iocp_t{}>::native_connect_awaitable::native_connect_awaitable(boost::corosio::native_udp_socket<boost::corosio::iocp_t{}>&, boost::corosio::endpoint) :165 5x 100.0% – 100.0% boost::corosio::native_udp_socket<boost::corosio::iocp_t{}>::native_connect_awaitable::dispatch(std::__n4861::coroutine_handle<void>, boost::capy::executor_ref) const :172 4x 100.0% 100.0% 80.0% boost::corosio::native_udp_socket<boost::corosio::iocp_t{}>::native_send_awaitable<boost::capy::const_buffer>::native_send_awaitable(boost::corosio::native_udp_socket<boost::corosio::iocp_t{}>&, boost::capy::const_buffer, int) :187 4x 100.0% – 100.0% boost::corosio::native_udp_socket<boost::corosio::iocp_t{}>::native_send_awaitable<boost::capy::const_buffer>::dispatch(std::__n4861::coroutine_handle<void>, boost::capy::executor_ref) const :198 2x 100.0% 100.0% 75.0% boost::corosio::native_udp_socket<boost::corosio::iocp_t{}>::native_recv_awaitable<boost::capy::mutable_buffer>::native_recv_awaitable(boost::corosio::native_udp_socket<boost::corosio::iocp_t{}>&, boost::capy::mutable_buffer, int) :214 3x 100.0% – 100.0% boost::corosio::native_udp_socket<boost::corosio::iocp_t{}>::native_recv_awaitable<boost::capy::mutable_buffer>::dispatch(std::__n4861::coroutine_handle<void>, boost::capy::executor_ref) const :225 1x 100.0% 100.0% 75.0% boost::corosio::native_udp_socket<boost::corosio::iocp_t{}>::native_udp_socket(boost::capy::execution_context&) :238 21x 100.0% 100.0% 100.0% boost::corosio::native_udp_socket<boost::corosio::iocp_t{}>::native_udp_socket(boost::corosio::native_udp_socket<boost::corosio::iocp_t{}>&&) :266 1x 100.0% – 100.0% auto boost::corosio::native_udp_socket<boost::corosio::iocp_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% 100.0% auto boost::corosio::native_udp_socket<boost::corosio::iocp_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::iocp_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% 100.0% auto boost::corosio::native_udp_socket<boost::corosio::iocp_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::iocp_t{}>::connect(boost::corosio::endpoint) :362 5x 100.0% 100.0% 100.0% auto boost::corosio::native_udp_socket<boost::corosio::iocp_t{}>::send<boost::capy::const_buffer>(boost::capy::const_buffer const&, boost::corosio::message_flags) :383 4x 100.0% 100.0% 100.0% auto boost::corosio::native_udp_socket<boost::corosio::iocp_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::iocp_t{}>::recv<boost::capy::mutable_buffer>(boost::capy::mutable_buffer const&, boost::corosio::message_flags) :411 3x 100.0% 100.0% 100.0% auto boost::corosio::native_udp_socket<boost::corosio::iocp_t{}>::recv<boost::capy::mutable_buffer>(boost::capy::mutable_buffer const&) :421 3x 100.0% – 100.0% boost::corosio::native_udp_socket<boost::corosio::iocp_t{}>::wait(boost::corosio::wait_type) :435 2x 100.0% – 100.0%
Line Branch 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 14x impl_type& get_impl() noexcept
76 {
77 14x 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 4x native_send_to_awaitable(
90 native_udp_socket& self,
91 ConstBufferSequence buffers,
92 endpoint dest,
93 int flags) noexcept
94 4x : self_(self)
95 4x , buffers_(std::move(buffers))
96 4x , dest_(dest)
97 4x , flags_(flags)
98 {
99 4x }
100
101 std::coroutine_handle<>
102 2x dispatch(std::coroutine_handle<> h, capy::executor_ref ex) const
103 {
104
1/1
✓ Branch 5 → 6 taken 2 times.
6x return self_.get_impl().send_to(
105 2x h, ex, buffers_, dest_, flags_, this->token_, &this->ec_,
106 4x &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 6x native_recv_from_awaitable(
121 native_udp_socket& self,
122 MutableBufferSequence buffers,
123 endpoint& source,
124 int flags) noexcept
125 6x : self_(self)
126 6x , buffers_(std::move(buffers))
127 6x , source_(source)
128 6x , flags_(flags)
129 {
130 6x }
131
132 std::coroutine_handle<>
133 4x dispatch(std::coroutine_handle<> h, capy::executor_ref ex) const
134 {
135
1/1
✓ Branch 5 → 6 taken 4 times.
12x return self_.get_impl().recv_from(
136 4x h, ex, buffers_, &source_, flags_, this->token_, &this->ec_,
137 8x &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 2x native_wait_awaitable(native_udp_socket& self, wait_type w) noexcept
147 2x : self_(self)
148 2x , w_(w)
149 {
150 2x }
151
152 std::coroutine_handle<>
153 1x dispatch(std::coroutine_handle<> h, capy::executor_ref ex) const
154 {
155
1/1
✓ Branch 4 → 5 taken 1 time.
1x 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 5x native_connect_awaitable(native_udp_socket& self, endpoint ep) noexcept
166 5x : self_(self)
167 5x , endpoint_(ep)
168 {
169 5x }
170
171 std::coroutine_handle<>
172 4x dispatch(std::coroutine_handle<> h, capy::executor_ref ex) const
173 {
174
1/1
✓ Branch 4 → 5 taken 4 times.
12x return self_.get_impl().connect(
175 12x 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 4x native_send_awaitable(
188 native_udp_socket& self,
189 ConstBufferSequence buffers,
190 int flags) noexcept
191 4x : self_(self)
192 4x , buffers_(std::move(buffers))
193 4x , flags_(flags)
194 {
195 4x }
196
197 std::coroutine_handle<>
198 2x dispatch(std::coroutine_handle<> h, capy::executor_ref ex) const
199 {
200
1/1
✓ Branch 5 → 6 taken 2 times.
6x return self_.get_impl().send(
201 2x h, ex, buffers_, flags_, this->token_, &this->ec_,
202 4x &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 3x native_recv_awaitable(
215 native_udp_socket& self,
216 MutableBufferSequence buffers,
217 int flags) noexcept
218 3x : self_(self)
219 3x , buffers_(std::move(buffers))
220 3x , flags_(flags)
221 {
222 3x }
223
224 std::coroutine_handle<>
225 1x dispatch(std::coroutine_handle<> h, capy::executor_ref ex) const
226 {
227
1/1
✓ Branch 5 → 6 taken 1 time.
3x return self_.get_impl().recv(
228 1x h, ex, buffers_, flags_, this->token_, &this->ec_,
229 2x &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 21x explicit native_udp_socket(capy::execution_context& ctx)
239
2/2
✓ Branch 2 → 3 taken 21 times.
✓ Branch 3 → 4 taken 21 times.
21x : udp_socket(handle(ctx, ctx.use_service<service_type>()))
240 {
241 21x }
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 1x 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 4x send_to(CB const& buffers, endpoint dest, corosio::message_flags flags)
300 {
301 4x native_send_to_awaitable<CB> aw(
302 *this, buffers, dest, static_cast<int>(flags));
303
2/2
✓ Branch 4 → 5 taken 1 time.
✓ Branch 4 → 6 taken 3 times.
4x if (!is_open())
304 1x aw.ec_ = make_error_code(std::errc::bad_file_descriptor);
305 4x return aw;
306 }
307
308 /// @overload
309 template<capy::ConstBufferSequence CB>
310 4x [[nodiscard]] auto send_to(CB const& buffers, endpoint dest)
311 {
312 4x 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 6x recv_from(MB const& buffers, endpoint& source, corosio::message_flags flags)
332 {
333 6x native_recv_from_awaitable<MB> aw(
334 *this, buffers, source, static_cast<int>(flags));
335
2/2
✓ Branch 4 → 5 taken 1 time.
✓ Branch 4 → 6 taken 5 times.
6x if (!is_open())
336 1x aw.ec_ = make_error_code(std::errc::bad_file_descriptor);
337 6x return aw;
338 }
339
340 /// @overload
341 template<capy::MutableBufferSequence MB>
342 6x [[nodiscard]] auto recv_from(MB const& buffers, endpoint& source)
343 {
344 6x 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 5x [[nodiscard]] auto connect(endpoint ep)
363 {
364 5x native_connect_awaitable aw(*this, ep);
365
2/2
✓ Branch 4 → 5 taken 2 times.
✓ Branch 4 → 9 taken 3 times.
5x if (!is_open())
366 2x aw.ec_ = open(ep.address().family());
367 5x 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 4x [[nodiscard]] auto send(CB const& buffers, corosio::message_flags flags)
384 {
385 4x native_send_awaitable<CB> aw(*this, buffers, static_cast<int>(flags));
386
2/2
✓ Branch 4 → 5 taken 1 time.
✓ Branch 4 → 6 taken 3 times.
4x if (!is_open())
387 1x aw.ec_ = make_error_code(std::errc::bad_file_descriptor);
388 4x return aw;
389 }
390
391 /// @overload
392 template<capy::ConstBufferSequence CB>
393 4x [[nodiscard]] auto send(CB const& buffers)
394 {
395 4x 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 3x [[nodiscard]] auto recv(MB const& buffers, corosio::message_flags flags)
412 {
413 3x native_recv_awaitable<MB> aw(*this, buffers, static_cast<int>(flags));
414
2/2
✓ Branch 4 → 5 taken 1 time.
✓ Branch 4 → 6 taken 2 times.
3x if (!is_open())
415 1x aw.ec_ = make_error_code(std::errc::bad_file_descriptor);
416 3x return aw;
417 }
418
419 /// @overload
420 template<capy::MutableBufferSequence MB>
421 3x [[nodiscard]] auto recv(MB const& buffers)
422 {
423 3x 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 2x [[nodiscard]] auto wait(wait_type w)
436 {
437 2x return native_wait_awaitable(*this, w);
438 }
439 };
440
441 } // namespace boost::corosio
442
443 #endif // BOOST_COROSIO_NATIVE_NATIVE_UDP_SOCKET_HPP
444