include/boost/corosio/native/native_udp_socket.hpp

100.0% Lines (135/0/135) 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) :217 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) :217 5x 100.0% 100.0% boost::corosio::native_udp_socket<boost::corosio::epoll_t{}>::native_connect_awaitable::await_ready() const :223 5x 100.0% 88.0% boost::corosio::native_udp_socket<boost::corosio::select_t{}>::native_connect_awaitable::await_ready() const :223 5x 100.0% 88.0% boost::corosio::native_udp_socket<boost::corosio::epoll_t{}>::native_connect_awaitable::await_resume() const :230 5x 100.0% 100.0% boost::corosio::native_udp_socket<boost::corosio::select_t{}>::native_connect_awaitable::await_resume() const :230 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*) :237 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*) :237 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) :256 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) :256 4x 100.0% 100.0% boost::corosio::native_udp_socket<boost::corosio::epoll_t{}>::native_send_awaitable<boost::capy::const_buffer>::await_ready() const :266 4x 100.0% 100.0% boost::corosio::native_udp_socket<boost::corosio::select_t{}>::native_send_awaitable<boost::capy::const_buffer>::await_ready() const :266 4x 100.0% 100.0% boost::corosio::native_udp_socket<boost::corosio::epoll_t{}>::native_send_awaitable<boost::capy::const_buffer>::await_resume() const :273 4x 100.0% 86.0% boost::corosio::native_udp_socket<boost::corosio::select_t{}>::native_send_awaitable<boost::capy::const_buffer>::await_resume() const :273 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*) :280 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*) :280 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) :300 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) :300 3x 100.0% 100.0% boost::corosio::native_udp_socket<boost::corosio::epoll_t{}>::native_recv_awaitable<boost::capy::mutable_buffer>::await_ready() const :310 3x 100.0% 100.0% boost::corosio::native_udp_socket<boost::corosio::select_t{}>::native_recv_awaitable<boost::capy::mutable_buffer>::await_ready() const :310 3x 100.0% 100.0% boost::corosio::native_udp_socket<boost::corosio::epoll_t{}>::native_recv_awaitable<boost::capy::mutable_buffer>::await_resume() const :317 3x 100.0% 86.0% boost::corosio::native_udp_socket<boost::corosio::select_t{}>::native_recv_awaitable<boost::capy::mutable_buffer>::await_resume() const :317 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*) :324 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*) :324 2x 100.0% 77.0% boost::corosio::native_udp_socket<boost::corosio::epoll_t{}>::native_udp_socket(boost::capy::execution_context&) :339 21x 100.0% 100.0% boost::corosio::native_udp_socket<boost::corosio::select_t{}>::native_udp_socket(boost::capy::execution_context&) :339 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{}>&&) :356 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{}>&&) :356 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) :391 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) :391 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) :411 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) :411 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&) :424 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&) :424 6x 100.0% 100.0% boost::corosio::native_udp_socket<boost::corosio::epoll_t{}>::connect(boost::corosio::endpoint) :444 5x 100.0% 90.0% boost::corosio::native_udp_socket<boost::corosio::select_t{}>::connect(boost::corosio::endpoint) :444 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) :465 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) :465 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&) :475 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&) :475 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) :493 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) :493 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&) :503 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&) :503 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_IO_URING
31 #include <boost/corosio/native/detail/io_uring/io_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_,
123 18x token_, &ec_, &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_,
170 30x token_, &ec_, &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 12x return self_.get_impl().wait(
206 12x h, env->executor, w_, token_, &ec_);
207 }
208 };
209
210 struct native_connect_awaitable
211 {
212 native_udp_socket& self_;
213 endpoint endpoint_;
214 std::stop_token token_;
215 mutable std::error_code ec_;
216
217 10x native_connect_awaitable(native_udp_socket& self, endpoint ep) noexcept
218 10x : self_(self)
219 10x , endpoint_(ep)
220 {
221 10x }
222
223 10x bool await_ready() const noexcept
224 {
225 // A pre-set ec_ means the initiator failed before
226 // dispatch (e.g. a closed object).
227 10x return static_cast<bool>(ec_) || token_.stop_requested();
228 }
229
230 10x [[nodiscard]] capy::io_result<> await_resume() const noexcept
231 {
232 10x if (token_.stop_requested())
233 2x return {make_error_code(std::errc::operation_canceled)};
234 8x return {ec_};
235 }
236
237 10x auto await_suspend(std::coroutine_handle<> h, capy::io_env const* env)
238 -> std::coroutine_handle<>
239 {
240 10x token_ = env->stop_token;
241 30x return self_.get_impl().connect(
242 30x h, env->executor, endpoint_, token_, &ec_);
243 }
244 };
245
246 template<class ConstBufferSequence>
247 struct native_send_awaitable
248 {
249 native_udp_socket& self_;
250 ConstBufferSequence buffers_;
251 int flags_;
252 std::stop_token token_;
253 mutable std::error_code ec_;
254 mutable std::size_t bytes_transferred_ = 0;
255
256 8x native_send_awaitable(
257 native_udp_socket& self,
258 ConstBufferSequence buffers,
259 int flags) noexcept
260 8x : self_(self)
261 8x , buffers_(std::move(buffers))
262 8x , flags_(flags)
263 {
264 8x }
265
266 8x bool await_ready() const noexcept
267 {
268 // A pre-set ec_ means the initiator failed before
269 // dispatch (e.g. a closed object).
270 8x return static_cast<bool>(ec_) || token_.stop_requested();
271 }
272
273 8x [[nodiscard]] capy::io_result<std::size_t> await_resume() const noexcept
274 {
275 8x if (token_.stop_requested())
276 2x return {make_error_code(std::errc::operation_canceled), 0};
277 6x return {ec_, bytes_transferred_};
278 }
279
280 6x auto await_suspend(std::coroutine_handle<> h, capy::io_env const* env)
281 -> std::coroutine_handle<>
282 {
283 6x token_ = env->stop_token;
284 18x return self_.get_impl().send(
285 6x h, env->executor, buffers_, flags_,
286 18x token_, &ec_, &bytes_transferred_);
287 }
288 };
289
290 template<class MutableBufferSequence>
291 struct native_recv_awaitable
292 {
293 native_udp_socket& self_;
294 MutableBufferSequence buffers_;
295 int flags_;
296 std::stop_token token_;
297 mutable std::error_code ec_;
298 mutable std::size_t bytes_transferred_ = 0;
299
300 6x native_recv_awaitable(
301 native_udp_socket& self,
302 MutableBufferSequence buffers,
303 int flags) noexcept
304 6x : self_(self)
305 6x , buffers_(std::move(buffers))
306 6x , flags_(flags)
307 {
308 6x }
309
310 6x bool await_ready() const noexcept
311 {
312 // A pre-set ec_ means the initiator failed before
313 // dispatch (e.g. a closed object).
314 6x return static_cast<bool>(ec_) || token_.stop_requested();
315 }
316
317 6x [[nodiscard]] capy::io_result<std::size_t> await_resume() const noexcept
318 {
319 6x if (token_.stop_requested())
320 2x return {make_error_code(std::errc::operation_canceled), 0};
321 4x return {ec_, bytes_transferred_};
322 }
323
324 4x auto await_suspend(std::coroutine_handle<> h, capy::io_env const* env)
325 -> std::coroutine_handle<>
326 {
327 4x token_ = env->stop_token;
328 12x return self_.get_impl().recv(
329 4x h, env->executor, buffers_, flags_,
330 12x token_, &ec_, &bytes_transferred_);
331 }
332 };
333
334 public:
335 /** Construct a native UDP socket from an execution context.
336
337 @param ctx The execution context that will own this socket.
338 */
339 42x explicit native_udp_socket(capy::execution_context& ctx)
340 42x : udp_socket(create_handle<service_type>(ctx))
341 {
342 42x }
343
344 /** Construct a native UDP socket from an executor.
345
346 @param ex The executor whose context will own the socket.
347 */
348 template<class Ex>
349 requires(!std::same_as<std::remove_cvref_t<Ex>, native_udp_socket>) &&
350 capy::Executor<Ex>
351 explicit native_udp_socket(Ex const& ex) : native_udp_socket(ex.context())
352 {
353 }
354
355 /// Move construct.
356 2x native_udp_socket(native_udp_socket&&) noexcept = default;
357
358 /// Move assign.
359 native_udp_socket& operator=(native_udp_socket&&) noexcept = default;
360
361 native_udp_socket(native_udp_socket const&) = delete;
362 native_udp_socket& operator=(native_udp_socket const&) = delete;
363
364 /** Send a datagram to the specified destination.
365
366 Calls the backend implementation directly, bypassing virtual
367 dispatch. Otherwise identical to @ref udp_socket::send_to.
368
369 @param buffers The buffer sequence containing data to send.
370 @param dest The destination endpoint.
371 @param flags Message flags.
372
373 @return An awaitable yielding `(error_code, std::size_t)`.
374
375 A closed socket reports `errc::bad_file_descriptor`.
376 */
377 template<capy::ConstBufferSequence CB>
378 8x [[nodiscard]] auto send_to(
379 CB const& buffers,
380 endpoint dest,
381 corosio::message_flags flags)
382 {
383 8x native_send_to_awaitable<CB> aw(*this, buffers, dest, static_cast<int>(flags));
384 8x if (!is_open())
385 2x aw.ec_ = make_error_code(std::errc::bad_file_descriptor);
386 8x return aw;
387 }
388
389 /// @overload
390 template<capy::ConstBufferSequence CB>
391 8x [[nodiscard]] auto send_to(CB const& buffers, endpoint dest)
392 {
393 8x return send_to(buffers, dest, corosio::message_flags::none);
394 }
395
396 /** Receive a datagram and capture the sender's endpoint.
397
398 Calls the backend implementation directly, bypassing virtual
399 dispatch. Otherwise identical to @ref udp_socket::recv_from.
400
401 @param buffers The buffer sequence to receive data into.
402 @param source Reference to an endpoint that will be set to
403 the sender's address on successful completion.
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 12x [[nodiscard]] auto recv_from(
412 MB const& buffers,
413 endpoint& source,
414 corosio::message_flags flags)
415 {
416 12x native_recv_from_awaitable<MB> aw(*this, buffers, source, static_cast<int>(flags));
417 12x if (!is_open())
418 2x aw.ec_ = make_error_code(std::errc::bad_file_descriptor);
419 12x return aw;
420 }
421
422 /// @overload
423 template<capy::MutableBufferSequence MB>
424 12x [[nodiscard]] auto recv_from(MB const& buffers, endpoint& source)
425 {
426 12x return recv_from(buffers, source, corosio::message_flags::none);
427 }
428
429 /** Asynchronously connect to set the default peer.
430
431 Calls the backend implementation directly, bypassing virtual
432 dispatch. Otherwise identical to @ref udp_socket::connect.
433
434 If the socket is not already open, it is opened automatically
435 using the address family of @p ep.
436
437 @param ep The remote endpoint to connect to.
438
439 @return An awaitable yielding `io_result<>`.
440
441 If the socket needs to be opened and the open fails, the
442 awaitable completes immediately with that error.
443 */
444 10x [[nodiscard]] auto connect(endpoint ep)
445 {
446 10x native_connect_awaitable aw(*this, ep);
447 10x if (!is_open())
448 4x aw.ec_ = open(ep.is_v6() ? udp::v6() : udp::v4());
449 10x return aw;
450 }
451
452 /** Send a datagram to the connected peer.
453
454 Calls the backend implementation directly, bypassing virtual
455 dispatch. Otherwise identical to @ref udp_socket::send.
456
457 @param buffers The buffer sequence containing data to send.
458 @param flags Message flags.
459
460 @return An awaitable yielding `(error_code, std::size_t)`.
461
462 A closed socket reports `errc::bad_file_descriptor`.
463 */
464 template<capy::ConstBufferSequence CB>
465 8x [[nodiscard]] auto send(CB const& buffers, corosio::message_flags flags)
466 {
467 8x native_send_awaitable<CB> aw(*this, buffers, static_cast<int>(flags));
468 8x if (!is_open())
469 2x aw.ec_ = make_error_code(std::errc::bad_file_descriptor);
470 8x return aw;
471 }
472
473 /// @overload
474 template<capy::ConstBufferSequence CB>
475 8x [[nodiscard]] auto send(CB const& buffers)
476 {
477 8x return send(buffers, corosio::message_flags::none);
478 }
479
480 /** Receive a datagram from the connected peer.
481
482 Calls the backend implementation directly, bypassing virtual
483 dispatch. Otherwise identical to @ref udp_socket::recv.
484
485 @param buffers The buffer sequence to receive data into.
486 @param flags Message flags (e.g. message_flags::peek).
487
488 @return An awaitable yielding `(error_code, std::size_t)`.
489
490 A closed socket reports `errc::bad_file_descriptor`.
491 */
492 template<capy::MutableBufferSequence MB>
493 6x [[nodiscard]] auto recv(MB const& buffers, corosio::message_flags flags)
494 {
495 6x native_recv_awaitable<MB> aw(*this, buffers, static_cast<int>(flags));
496 6x if (!is_open())
497 2x aw.ec_ = make_error_code(std::errc::bad_file_descriptor);
498 6x return aw;
499 }
500
501 /// @overload
502 template<capy::MutableBufferSequence MB>
503 6x [[nodiscard]] auto recv(MB const& buffers)
504 {
505 6x return recv(buffers, corosio::message_flags::none);
506 }
507
508 /** Asynchronously wait for the socket to be ready.
509
510 Calls the backend implementation directly, bypassing virtual
511 dispatch. Otherwise identical to @ref udp_socket::wait.
512
513 @param w The wait direction (read, write, or error).
514
515 @return An awaitable yielding `io_result<>`.
516 */
517 4x [[nodiscard]] auto wait(wait_type w)
518 {
519 4x return native_wait_awaitable(*this, w);
520 }
521 };
522
523 } // namespace boost::corosio
524
525 #endif // BOOST_COROSIO_NATIVE_NATIVE_UDP_SOCKET_HPP
526