include/boost/corosio/native/native_udp_socket.hpp

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