include/boost/corosio/native/native_local_datagram_socket.hpp

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