include/boost/corosio/native/native_udp_socket.hpp

92.3% Lines (48/52) 100.0% List of functions (15/15) 63.6% Branches (7/11)
native_udp_socket.hpp
f(x) Functions (15)
Function Calls Lines Branches Blocks
boost::corosio::native_udp_socket<boost::corosio::iocp_t{}>::get_impl() :80 4x 100.0% 100.0% boost::corosio::native_udp_socket<boost::corosio::iocp_t{}>::native_send_to_awaitable<boost::capy::const_buffer>::native_send_to_awaitable(boost::corosio::native_udp_socket<boost::corosio::iocp_t{}>&, boost::capy::const_buffer, boost::corosio::endpoint, int) :96 1x 100.0% 100.0% boost::corosio::native_udp_socket<boost::corosio::iocp_t{}>::native_send_to_awaitable<boost::capy::const_buffer>::await_ready() const :108 1x 100.0% 100.0% boost::corosio::native_udp_socket<boost::corosio::iocp_t{}>::native_send_to_awaitable<boost::capy::const_buffer>::await_resume() const :113 1x 75.0% 50.0% 66.7% boost::corosio::native_udp_socket<boost::corosio::iocp_t{}>::native_send_to_awaitable<boost::capy::const_buffer>::await_suspend(std::__n4861::coroutine_handle<void>, boost::capy::io_env const*) :120 1x 100.0% 100.0% 76.9% boost::corosio::native_udp_socket<boost::corosio::iocp_t{}>::native_recv_from_awaitable<boost::capy::mutable_buffer>::native_recv_from_awaitable(boost::corosio::native_udp_socket<boost::corosio::iocp_t{}>&, boost::capy::mutable_buffer, boost::corosio::endpoint&, int) :141 3x 100.0% 100.0% boost::corosio::native_udp_socket<boost::corosio::iocp_t{}>::native_recv_from_awaitable<boost::capy::mutable_buffer>::await_ready() const :153 3x 100.0% 100.0% boost::corosio::native_udp_socket<boost::corosio::iocp_t{}>::native_recv_from_awaitable<boost::capy::mutable_buffer>::await_resume() const :158 3x 75.0% 50.0% 66.7% boost::corosio::native_udp_socket<boost::corosio::iocp_t{}>::native_recv_from_awaitable<boost::capy::mutable_buffer>::await_suspend(std::__n4861::coroutine_handle<void>, boost::capy::io_env const*) :165 3x 100.0% 100.0% 76.9% boost::corosio::native_udp_socket<boost::corosio::iocp_t{}>::native_udp_socket(boost::capy::execution_context&) :180 9x 100.0% 100.0% 100.0% boost::corosio::native_udp_socket<boost::corosio::iocp_t{}>::native_udp_socket(boost::corosio::native_udp_socket<boost::corosio::iocp_t{}>&&) :197 1x 100.0% 100.0% auto boost::corosio::native_udp_socket<boost::corosio::iocp_t{}>::send_to<boost::capy::const_buffer>(boost::capy::const_buffer const&, boost::corosio::endpoint, boost::corosio::message_flags) :217 1x 75.0% 50.0% 80.0% auto boost::corosio::native_udp_socket<boost::corosio::iocp_t{}>::send_to<boost::capy::const_buffer>(boost::capy::const_buffer const&, boost::corosio::endpoint) :230 1x 100.0% 100.0% auto boost::corosio::native_udp_socket<boost::corosio::iocp_t{}>::recv_from<boost::capy::mutable_buffer>(boost::capy::mutable_buffer const&, boost::corosio::endpoint&, boost::corosio::message_flags) :248 3x 75.0% 50.0% 80.0% auto boost::corosio::native_udp_socket<boost::corosio::iocp_t{}>::recv_from<boost::capy::mutable_buffer>(boost::capy::mutable_buffer const&, boost::corosio::endpoint&) :261 3x 100.0% 100.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_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_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 4x impl_type& get_impl() noexcept
81 {
82 4x 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 int flags_;
92 std::stop_token token_;
93 mutable std::error_code ec_;
94 mutable std::size_t bytes_transferred_ = 0;
95
96 1x native_send_to_awaitable(
97 native_udp_socket& self,
98 ConstBufferSequence buffers,
99 endpoint dest,
100 int flags) noexcept
101 1x : self_(self)
102 1x , buffers_(std::move(buffers))
103 1x , dest_(dest)
104 1x , flags_(flags)
105 {
106 1x }
107
108 1x bool await_ready() const noexcept
109 {
110 1x return token_.stop_requested();
111 }
112
113 1x capy::io_result<std::size_t> await_resume() const noexcept
114 {
115
1/2
✗ Branch 3 → 4 not taken.
✓ Branch 3 → 6 taken 1 time.
1x if (token_.stop_requested())
116 return {make_error_code(std::errc::operation_canceled), 0};
117 1x return {ec_, bytes_transferred_};
118 }
119
120 1x auto await_suspend(std::coroutine_handle<> h, capy::io_env const* env)
121 -> std::coroutine_handle<>
122 {
123 1x token_ = env->stop_token;
124
1/1
✓ Branch 6 → 7 taken 1 time.
3x return self_.get_impl().send_to(
125 1x h, env->executor, buffers_, dest_, flags_,
126 3x token_, &ec_, &bytes_transferred_);
127 }
128 };
129
130 template<class MutableBufferSequence>
131 struct native_recv_from_awaitable
132 {
133 native_udp_socket& self_;
134 MutableBufferSequence buffers_;
135 endpoint& source_;
136 int flags_;
137 std::stop_token token_;
138 mutable std::error_code ec_;
139 mutable std::size_t bytes_transferred_ = 0;
140
141 3x native_recv_from_awaitable(
142 native_udp_socket& self,
143 MutableBufferSequence buffers,
144 endpoint& source,
145 int flags) noexcept
146 3x : self_(self)
147 3x , buffers_(std::move(buffers))
148 3x , source_(source)
149 3x , flags_(flags)
150 {
151 3x }
152
153 3x bool await_ready() const noexcept
154 {
155 3x return token_.stop_requested();
156 }
157
158 3x capy::io_result<std::size_t> await_resume() const noexcept
159 {
160
1/2
✗ Branch 3 → 4 not taken.
✓ Branch 3 → 6 taken 3 times.
3x if (token_.stop_requested())
161 return {make_error_code(std::errc::operation_canceled), 0};
162 3x return {ec_, bytes_transferred_};
163 }
164
165 3x auto await_suspend(std::coroutine_handle<> h, capy::io_env const* env)
166 -> std::coroutine_handle<>
167 {
168 3x token_ = env->stop_token;
169
1/1
✓ Branch 6 → 7 taken 3 times.
9x return self_.get_impl().recv_from(
170 3x h, env->executor, buffers_, &source_, flags_,
171 9x token_, &ec_, &bytes_transferred_);
172 }
173 };
174
175 public:
176 /** Construct a native UDP socket from an execution context.
177
178 @param ctx The execution context that will own this socket.
179 */
180 9x explicit native_udp_socket(capy::execution_context& ctx)
181
1/1
✓ Branch 2 → 3 taken 9 times.
9x : udp_socket(create_handle<service_type>(ctx))
182 {
183 9x }
184
185 /** Construct a native UDP socket from an executor.
186
187 @param ex The executor whose context will own the socket.
188 */
189 template<class Ex>
190 requires(!std::same_as<std::remove_cvref_t<Ex>, native_udp_socket>) &&
191 capy::Executor<Ex>
192 explicit native_udp_socket(Ex const& ex) : native_udp_socket(ex.context())
193 {
194 }
195
196 /// Move construct.
197 1x native_udp_socket(native_udp_socket&&) noexcept = default;
198
199 /// Move assign.
200 native_udp_socket& operator=(native_udp_socket&&) noexcept = default;
201
202 native_udp_socket(native_udp_socket const&) = delete;
203 native_udp_socket& operator=(native_udp_socket const&) = delete;
204
205 /** Send a datagram to the specified destination.
206
207 Calls the backend implementation directly, bypassing virtual
208 dispatch. Otherwise identical to @ref udp_socket::send_to.
209
210 @param buffers The buffer sequence containing data to send.
211 @param dest The destination endpoint.
212 @param flags Message flags.
213
214 @return An awaitable yielding `(error_code, std::size_t)`.
215 */
216 template<capy::ConstBufferSequence CB>
217 1x auto send_to(
218 CB const& buffers,
219 endpoint dest,
220 corosio::message_flags flags)
221 {
222
1/2
✗ Branch 3 → 4 not taken.
✓ Branch 3 → 5 taken 1 time.
1x if (!is_open())
223 detail::throw_logic_error("send_to: socket not open");
224 return native_send_to_awaitable<CB>(
225 1x *this, buffers, dest, static_cast<int>(flags));
226 }
227
228 /// @overload
229 template<capy::ConstBufferSequence CB>
230 1x auto send_to(CB const& buffers, endpoint dest)
231 {
232 1x return send_to(buffers, dest, corosio::message_flags::none);
233 }
234
235 /** Receive a datagram and capture the sender's endpoint.
236
237 Calls the backend implementation directly, bypassing virtual
238 dispatch. Otherwise identical to @ref udp_socket::recv_from.
239
240 @param buffers The buffer sequence to receive data into.
241 @param source Reference to an endpoint that will be set to
242 the sender's address on successful completion.
243 @param flags Message flags (e.g. message_flags::peek).
244
245 @return An awaitable yielding `(error_code, std::size_t)`.
246 */
247 template<capy::MutableBufferSequence MB>
248 3x auto recv_from(
249 MB const& buffers,
250 endpoint& source,
251 corosio::message_flags flags)
252 {
253
1/2
✗ Branch 3 → 4 not taken.
✓ Branch 3 → 5 taken 3 times.
3x if (!is_open())
254 detail::throw_logic_error("recv_from: socket not open");
255 return native_recv_from_awaitable<MB>(
256 3x *this, buffers, source, static_cast<int>(flags));
257 }
258
259 /// @overload
260 template<capy::MutableBufferSequence MB>
261 3x auto recv_from(MB const& buffers, endpoint& source)
262 {
263 3x return recv_from(buffers, source, corosio::message_flags::none);
264 }
265 };
266
267 } // namespace boost::corosio
268
269 #endif // BOOST_COROSIO_NATIVE_NATIVE_UDP_SOCKET_HPP
270