include/boost/corosio/native/native_udp_socket.hpp

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