include/boost/corosio/native/native_udp_socket.hpp

89.1% Lines (49/55) 100.0% List of functions (36/36) 50.0% Branches (16/32)
f(x) Functions (36)
Function Calls Lines Branches Blocks
boost::corosio::native_udp_socket<boost::corosio::kqueue_t{}>::~native_udp_socket() :74 20x 100.0% 100.0% boost::corosio::native_udp_socket<boost::corosio::select_t{}>::~native_udp_socket() :74 20x 100.0% 100.0% boost::corosio::native_udp_socket<boost::corosio::kqueue_t{}>::get_impl() :80 4x 100.0% 100.0% boost::corosio::native_udp_socket<boost::corosio::select_t{}>::get_impl() :80 4x 100.0% 100.0% boost::corosio::native_udp_socket<boost::corosio::kqueue_t{}>::native_send_to_awaitable<boost::capy::const_buffer>::native_send_to_awaitable(boost::corosio::native_udp_socket<boost::corosio::kqueue_t{}>::native_send_to_awaitable<boost::capy::const_buffer>&&) :86 2x 100.0% 100.0% boost::corosio::native_udp_socket<boost::corosio::kqueue_t{}>::native_send_to_awaitable<boost::capy::const_buffer>::~native_send_to_awaitable() :86 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{}>::native_send_to_awaitable<boost::capy::const_buffer>&&) :86 2x 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() :86 4x 100.0% 100.0% boost::corosio::native_udp_socket<boost::corosio::kqueue_t{}>::native_send_to_awaitable<boost::capy::const_buffer>::native_send_to_awaitable(boost::corosio::native_udp_socket<boost::corosio::kqueue_t{}>&, boost::capy::const_buffer, boost::corosio::endpoint) :95 2x 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) :95 2x 100.0% 100.0% boost::corosio::native_udp_socket<boost::corosio::kqueue_t{}>::native_send_to_awaitable<boost::capy::const_buffer>::await_ready() const :105 1x 100.0% 100.0% boost::corosio::native_udp_socket<boost::corosio::select_t{}>::native_send_to_awaitable<boost::capy::const_buffer>::await_ready() const :105 1x 100.0% 100.0% boost::corosio::native_udp_socket<boost::corosio::kqueue_t{}>::native_send_to_awaitable<boost::capy::const_buffer>::await_resume() const :110 1x 80.0% 50.0% 75.0% boost::corosio::native_udp_socket<boost::corosio::select_t{}>::native_send_to_awaitable<boost::capy::const_buffer>::await_resume() const :110 1x 100.0% 75.0% boost::corosio::native_udp_socket<boost::corosio::kqueue_t{}>::native_send_to_awaitable<boost::capy::const_buffer>::await_suspend(std::__1::coroutine_handle<void>, boost::capy::io_env const*) :117 1x 83.3% 50.0% 50.0% boost::corosio::native_udp_socket<boost::corosio::select_t{}>::native_send_to_awaitable<boost::capy::const_buffer>::await_suspend(std::__1::coroutine_handle<void>, boost::capy::io_env const*) :117 1x 100.0% 50.0% boost::corosio::native_udp_socket<boost::corosio::kqueue_t{}>::native_recv_from_awaitable<boost::capy::mutable_buffer>::native_recv_from_awaitable(boost::corosio::native_udp_socket<boost::corosio::kqueue_t{}>::native_recv_from_awaitable<boost::capy::mutable_buffer>&&) :128 6x 100.0% 100.0% boost::corosio::native_udp_socket<boost::corosio::kqueue_t{}>::native_recv_from_awaitable<boost::capy::mutable_buffer>::~native_recv_from_awaitable() :128 12x 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{}>::native_recv_from_awaitable<boost::capy::mutable_buffer>&&) :128 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() :128 12x 100.0% 100.0% boost::corosio::native_udp_socket<boost::corosio::kqueue_t{}>::native_recv_from_awaitable<boost::capy::mutable_buffer>::native_recv_from_awaitable(boost::corosio::native_udp_socket<boost::corosio::kqueue_t{}>&, boost::capy::mutable_buffer, boost::corosio::endpoint&) :137 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&) :137 6x 100.0% 100.0% boost::corosio::native_udp_socket<boost::corosio::kqueue_t{}>::native_recv_from_awaitable<boost::capy::mutable_buffer>::await_ready() const :147 3x 100.0% 100.0% boost::corosio::native_udp_socket<boost::corosio::select_t{}>::native_recv_from_awaitable<boost::capy::mutable_buffer>::await_ready() const :147 3x 100.0% 100.0% boost::corosio::native_udp_socket<boost::corosio::kqueue_t{}>::native_recv_from_awaitable<boost::capy::mutable_buffer>::await_resume() const :152 3x 80.0% 50.0% 75.0% boost::corosio::native_udp_socket<boost::corosio::select_t{}>::native_recv_from_awaitable<boost::capy::mutable_buffer>::await_resume() const :152 3x 100.0% 75.0% boost::corosio::native_udp_socket<boost::corosio::kqueue_t{}>::native_recv_from_awaitable<boost::capy::mutable_buffer>::await_suspend(std::__1::coroutine_handle<void>, boost::capy::io_env const*) :159 3x 83.3% 50.0% 50.0% boost::corosio::native_udp_socket<boost::corosio::select_t{}>::native_recv_from_awaitable<boost::capy::mutable_buffer>::await_suspend(std::__1::coroutine_handle<void>, boost::capy::io_env const*) :159 3x 100.0% 50.0% boost::corosio::native_udp_socket<boost::corosio::kqueue_t{}>::native_udp_socket(boost::capy::execution_context&) :174 18x 100.0% 100.0% boost::corosio::native_udp_socket<boost::corosio::select_t{}>::native_udp_socket(boost::capy::execution_context&) :174 18x 100.0% 100.0% boost::corosio::native_udp_socket<boost::corosio::kqueue_t{}>::native_udp_socket(boost::corosio::native_udp_socket<boost::corosio::kqueue_t{}>&&) :191 2x 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{}>&&) :191 2x 100.0% 100.0% auto boost::corosio::native_udp_socket<boost::corosio::kqueue_t{}>::send_to<boost::capy::const_buffer>(boost::capy::const_buffer const&, boost::corosio::endpoint) :210 1x 75.0% 50.0% 66.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) :210 1x 100.0% 66.0% auto boost::corosio::native_udp_socket<boost::corosio::kqueue_t{}>::recv_from<boost::capy::mutable_buffer>(boost::capy::mutable_buffer const&, boost::corosio::endpoint&) :229 3x 75.0% 50.0% 66.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&) :229 3x 100.0% 66.0%
Line Branch 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_udp_service.hpp>
19 #endif
20
21 #if BOOST_COROSIO_HAS_SELECT
22 #include <boost/corosio/native/detail/select/select_udp_service.hpp>
23 #endif
24
25 #if BOOST_COROSIO_HAS_KQUEUE
26 #include <boost/corosio/native/detail/kqueue/kqueue_udp_service.hpp>
27 #endif
28
29 #if BOOST_COROSIO_HAS_IOCP
30 #include <boost/corosio/native/detail/iocp/win_udp_service.hpp>
31 #endif
32 #endif // !BOOST_COROSIO_MRDOCS
33
34 namespace boost::corosio {
35
36 /** An asynchronous UDP socket with devirtualized I/O operations.
37
38 This class template inherits from @ref udp_socket and shadows
39 the async operations (`send_to`, `recv_from`) with versions
40 that call the backend implementation directly, allowing the
41 compiler to inline through the entire call chain.
42
43 Non-async operations (`open`, `close`, `cancel`, `bind`,
44 socket options) remain unchanged and dispatch through the
45 compiled library.
46
47 A `native_udp_socket` IS-A `udp_socket` and can be passed to
48 any function expecting `udp_socket&`, in which case virtual
49 dispatch is used transparently.
50
51 @tparam Backend A backend tag value (e.g., `epoll`)
52 whose type provides the concrete implementation types.
53
54 @par Thread Safety
55 Same as @ref udp_socket.
56
57 @par Example
58 @code
59 #include <boost/corosio/native/native_udp_socket.hpp>
60
61 native_io_context<epoll> ctx;
62 native_udp_socket<epoll> s(ctx);
63 s.open();
64 s.bind(endpoint(ipv4_address::any(), 9000));
65 char buf[1024];
66 endpoint sender;
67 auto [ec, n] = co_await s.recv_from(
68 capy::mutable_buffer(buf, sizeof(buf)), sender);
69 @endcode
70
71 @see udp_socket, epoll_t
72 */
73 template<auto Backend>
74 class native_udp_socket : public udp_socket
75 {
76 using backend_type = decltype(Backend);
77 using impl_type = typename backend_type::udp_socket_type;
78 using service_type = typename backend_type::udp_service_type;
79
80 8x impl_type& get_impl() noexcept
81 {
82 8x return *static_cast<impl_type*>(h_.get());
83 }
84
85 template<class ConstBufferSequence>
86 struct native_send_to_awaitable
87 {
88 native_udp_socket& self_;
89 ConstBufferSequence buffers_;
90 endpoint dest_;
91 std::stop_token token_;
92 mutable std::error_code ec_;
93 2x mutable std::size_t bytes_transferred_ = 0;
94
95 6x native_send_to_awaitable(
96 native_udp_socket& self,
97 ConstBufferSequence buffers,
98 endpoint dest) noexcept
99 2x : self_(self)
100 2x , buffers_(std::move(buffers))
101 2x , dest_(dest)
102 2x {
103 4x }
104
105 2x bool await_ready() const noexcept
106 {
107 2x return token_.stop_requested();
108 }
109
110 2x capy::io_result<std::size_t> await_resume() const noexcept
111 {
112
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 1 time.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 time.
2x if (token_.stop_requested())
113 return {make_error_code(std::errc::operation_canceled), 0};
114 2x return {ec_, bytes_transferred_};
115 2x }
116
117 2x auto await_suspend(std::coroutine_handle<> h, capy::io_env const* env)
118 -> std::coroutine_handle<>
119 {
120 2x token_ = env->stop_token;
121
4/8
✓ Branch 0 taken 1 time.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 time.
✗ Branch 3 not taken.
✓ Branch 4 taken 1 time.
✗ Branch 5 not taken.
✓ Branch 6 taken 1 time.
✗ Branch 7 not taken.
4x return self_.get_impl().send_to(
122 2x h, env->executor, buffers_, dest_, token_, &ec_,
123 2x &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 std::stop_token token_;
134 mutable std::error_code ec_;
135 6x mutable std::size_t bytes_transferred_ = 0;
136
137 18x native_recv_from_awaitable(
138 native_udp_socket& self,
139 MutableBufferSequence buffers,
140 endpoint& source) noexcept
141 6x : self_(self)
142 6x , buffers_(std::move(buffers))
143 6x , source_(source)
144 6x {
145 12x }
146
147 6x bool await_ready() const noexcept
148 {
149 6x return token_.stop_requested();
150 }
151
152 6x capy::io_result<std::size_t> await_resume() const noexcept
153 {
154
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 3 times.
6x if (token_.stop_requested())
155 return {make_error_code(std::errc::operation_canceled), 0};
156 6x return {ec_, bytes_transferred_};
157 6x }
158
159 6x auto await_suspend(std::coroutine_handle<> h, capy::io_env const* env)
160 -> std::coroutine_handle<>
161 {
162 6x token_ = env->stop_token;
163
4/8
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 3 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 3 times.
✗ Branch 7 not taken.
12x return self_.get_impl().recv_from(
164 6x h, env->executor, buffers_, &source_, token_, &ec_,
165 6x &bytes_transferred_);
166 }
167 };
168
169 public:
170 /** Construct a native UDP socket from an execution context.
171
172 @param ctx The execution context that will own this socket.
173 */
174 36x explicit native_udp_socket(capy::execution_context& ctx)
175 18x : udp_socket(create_handle<service_type>(ctx))
176 36x {
177 36x }
178
179 /** Construct a native UDP socket from an executor.
180
181 @param ex The executor whose context will own the socket.
182 */
183 template<class Ex>
184 requires(!std::same_as<std::remove_cvref_t<Ex>, native_udp_socket>) &&
185 capy::Executor<Ex>
186 explicit native_udp_socket(Ex const& ex) : native_udp_socket(ex.context())
187 {
188 }
189
190 /// Move construct.
191 4x native_udp_socket(native_udp_socket&&) noexcept = default;
192
193 /// Move assign.
194 native_udp_socket& operator=(native_udp_socket&&) noexcept = default;
195
196 native_udp_socket(native_udp_socket const&) = delete;
197 native_udp_socket& operator=(native_udp_socket const&) = delete;
198
199 /** Send a datagram to the specified destination.
200
201 Calls the backend implementation directly, bypassing virtual
202 dispatch. Otherwise identical to @ref udp_socket::send_to.
203
204 @param buffers The buffer sequence containing data to send.
205 @param dest The destination endpoint.
206
207 @return An awaitable yielding `(error_code, std::size_t)`.
208 */
209 template<capy::ConstBufferSequence CB>
210 2x auto send_to(CB const& buffers, endpoint dest)
211 {
212
2/4
✓ Branch 0 taken 1 time.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 time.
✗ Branch 3 not taken.
2x if (!is_open())
213 detail::throw_logic_error("send_to: socket not open");
214 2x return native_send_to_awaitable<CB>(*this, buffers, dest);
215 }
216
217 /** Receive a datagram and capture the sender's endpoint.
218
219 Calls the backend implementation directly, bypassing virtual
220 dispatch. Otherwise identical to @ref udp_socket::recv_from.
221
222 @param buffers The buffer sequence to receive data into.
223 @param source Reference to an endpoint that will be set to
224 the sender's address on successful completion.
225
226 @return An awaitable yielding `(error_code, std::size_t)`.
227 */
228 template<capy::MutableBufferSequence MB>
229 6x auto recv_from(MB const& buffers, endpoint& source)
230 {
231
2/4
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
6x if (!is_open())
232 detail::throw_logic_error("recv_from: socket not open");
233 6x return native_recv_from_awaitable<MB>(*this, buffers, source);
234 }
235 };
236
237 } // namespace boost::corosio
238
239 #endif // BOOST_COROSIO_NATIVE_NATIVE_UDP_SOCKET_HPP
240