include/boost/corosio/native/detail/select/select_udp_service.hpp

69.9% Lines (79/113) 82.6% List of functions (19/23) 46.4% Branches (13/28)
f(x) Functions (23)
Function Calls Lines Branches Blocks
boost::corosio::detail::select_udp_service::~select_udp_service() :43 693x 100.0% 100.0% boost::corosio::detail::select_udp_service::select_udp_service(boost::capy::execution_context&) :51 462x 100.0% 100.0% boost::corosio::detail::select_send_to_op::cancel() :68 0 0.0% 0.0% 0.0% boost::corosio::detail::select_recv_from_op::cancel() :77 1x 80.0% 50.0% 75.0% boost::corosio::detail::select_udp_connect_op::cancel() :88 0 0.0% 0.0% 0.0% boost::corosio::detail::select_send_op::cancel() :97 0 0.0% 0.0% 0.0% boost::corosio::detail::select_recv_op::cancel() :106 0 0.0% 0.0% 0.0% boost::corosio::detail::select_datagram_op::operator()() :117 10x 100.0% 100.0% boost::corosio::detail::select_recv_from_op::operator()() :123 16x 100.0% 100.0% boost::corosio::detail::select_udp_connect_op::operator()() :129 5x 100.0% 100.0% boost::corosio::detail::select_recv_op::operator()() :135 2x 100.0% 100.0% boost::corosio::detail::select_udp_socket::select_udp_socket(boost::corosio::detail::select_udp_service&) :142 96x 100.0% 100.0% boost::corosio::detail::select_udp_socket::~select_udp_socket() :147 96x 100.0% 100.0% boost::corosio::detail::select_udp_socket::send_to(std::__1::coroutine_handle<void>, boost::capy::executor_ref, boost::corosio::buffer_param, boost::corosio::endpoint, std::__1::stop_token, std::__1::error_code*, unsigned long*) :152 13x 100.0% 100.0% 100.0% boost::corosio::detail::select_udp_socket::recv_from(std::__1::coroutine_handle<void>, boost::capy::executor_ref, boost::corosio::buffer_param, boost::corosio::endpoint*, std::__1::stop_token, std::__1::error_code*, unsigned long*) :168 19x 100.0% 100.0% boost::corosio::detail::select_udp_socket::connect(std::__1::coroutine_handle<void>, boost::capy::executor_ref, boost::corosio::endpoint, std::__1::stop_token, std::__1::error_code*) :183 6x 100.0% 100.0% 100.0% boost::corosio::detail::select_udp_socket::send(std::__1::coroutine_handle<void>, boost::capy::executor_ref, boost::corosio::buffer_param, std::__1::stop_token, std::__1::error_code*, unsigned long*) :197 3x 80.0% 50.0% 66.0% boost::corosio::detail::select_udp_socket::recv(std::__1::coroutine_handle<void>, boost::capy::executor_ref, boost::corosio::buffer_param, std::__1::stop_token, std::__1::error_code*, unsigned long*) :212 2x 100.0% 100.0% boost::corosio::detail::select_udp_socket::remote_endpoint() const :224 2x 100.0% 100.0% boost::corosio::detail::select_udp_socket::cancel() :230 3x 100.0% 100.0% boost::corosio::detail::select_udp_socket::close_socket() :236 186x 100.0% 100.0% boost::corosio::detail::select_udp_service::open_datagram_socket(boost::corosio::udp_socket::implementation&, int, int, int) :242 45x 68.4% 58.3% 64.0% boost::corosio::detail::select_udp_service::bind_datagram(boost::corosio::udp_socket::implementation&, boost::corosio::endpoint) :306 25x 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_DETAIL_SELECT_SELECT_UDP_SERVICE_HPP
11 #define BOOST_COROSIO_NATIVE_DETAIL_SELECT_SELECT_UDP_SERVICE_HPP
12
13 #include <boost/corosio/detail/platform.hpp>
14
15 #if BOOST_COROSIO_HAS_SELECT
16
17 #include <boost/corosio/detail/config.hpp>
18 #include <boost/corosio/detail/udp_service.hpp>
19
20 #include <boost/corosio/native/detail/select/select_udp_socket.hpp>
21 #include <boost/corosio/native/detail/select/select_scheduler.hpp>
22 #include <boost/corosio/native/detail/reactor/reactor_socket_service.hpp>
23
24 #include <boost/corosio/native/detail/reactor/reactor_op_complete.hpp>
25
26 #include <coroutine>
27 #include <mutex>
28
29 #include <errno.h>
30 #include <fcntl.h>
31 #include <netinet/in.h>
32 #include <sys/select.h>
33 #include <sys/socket.h>
34 #include <unistd.h>
35
36 namespace boost::corosio::detail {
37
38 /** select UDP service implementation.
39
40 Inherits from udp_service to enable runtime polymorphism.
41 Uses key_type = udp_service for service lookup.
42 */
43 class BOOST_COROSIO_DECL select_udp_service final
44 : public reactor_socket_service<
45 select_udp_service,
46 udp_service,
47 select_scheduler,
48 select_udp_socket>
49 {
50 public:
51 462x explicit select_udp_service(capy::execution_context& ctx)
52 231x : reactor_socket_service(ctx)
53 462x {
54 462x }
55
56 std::error_code open_datagram_socket(
57 udp_socket::implementation& impl,
58 int family,
59 int type,
60 int protocol) override;
61 std::error_code
62 bind_datagram(udp_socket::implementation& impl, endpoint ep) override;
63 };
64
65 // Cancellation for connectionless ops
66
67 inline void
68 select_send_to_op::cancel() noexcept
69 {
70 if (socket_impl_)
71 socket_impl_->cancel_single_op(*this);
72 else
73 request_cancel();
74 }
75
76 inline void
77 1x select_recv_from_op::cancel() noexcept
78 {
79
1/2
✓ Branch 0 taken 1 time.
✗ Branch 1 not taken.
1x if (socket_impl_)
80 1x socket_impl_->cancel_single_op(*this);
81 else
82 request_cancel();
83 1x }
84
85 // Cancellation for connected-mode ops
86
87 inline void
88 select_udp_connect_op::cancel() noexcept
89 {
90 if (socket_impl_)
91 socket_impl_->cancel_single_op(*this);
92 else
93 request_cancel();
94 }
95
96 inline void
97 select_send_op::cancel() noexcept
98 {
99 if (socket_impl_)
100 socket_impl_->cancel_single_op(*this);
101 else
102 request_cancel();
103 }
104
105 inline void
106 select_recv_op::cancel() noexcept
107 {
108 if (socket_impl_)
109 socket_impl_->cancel_single_op(*this);
110 else
111 request_cancel();
112 }
113
114 // Completion handlers
115
116 inline void
117 10x select_datagram_op::operator()()
118 {
119 10x complete_io_op(*this);
120 10x }
121
122 inline void
123 16x select_recv_from_op::operator()()
124 {
125 16x complete_datagram_op(*this, this->source_out);
126 16x }
127
128 inline void
129 5x select_udp_connect_op::operator()()
130 {
131 5x complete_connect_op(*this);
132 5x }
133
134 inline void
135 2x select_recv_op::operator()()
136 {
137 2x complete_io_op(*this);
138 2x }
139
140 // Socket construction/destruction
141
142 96x inline select_udp_socket::select_udp_socket(select_udp_service& svc) noexcept
143 48x : reactor_datagram_socket(svc)
144 96x {
145 96x }
146
147 96x inline select_udp_socket::~select_udp_socket() = default;
148
149 // Connectionless I/O
150
151 inline std::coroutine_handle<>
152 13x select_udp_socket::send_to(
153 std::coroutine_handle<> h,
154 capy::executor_ref ex,
155 buffer_param buf,
156 endpoint dest,
157 std::stop_token token,
158 std::error_code* ec,
159 std::size_t* bytes_out)
160 {
161 13x auto result = do_send_to(h, ex, buf, dest, token, ec, bytes_out);
162
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 10 times.
13x if (result == std::noop_coroutine())
163 10x svc_.scheduler().notify_reactor();
164 13x return result;
165 }
166
167 inline std::coroutine_handle<>
168 19x select_udp_socket::recv_from(
169 std::coroutine_handle<> h,
170 capy::executor_ref ex,
171 buffer_param buf,
172 endpoint* source,
173 std::stop_token token,
174 std::error_code* ec,
175 std::size_t* bytes_out)
176 {
177 19x return do_recv_from(h, ex, buf, source, token, ec, bytes_out);
178 }
179
180 // Connected-mode I/O
181
182 inline std::coroutine_handle<>
183 6x select_udp_socket::connect(
184 std::coroutine_handle<> h,
185 capy::executor_ref ex,
186 endpoint ep,
187 std::stop_token token,
188 std::error_code* ec)
189 {
190 6x auto result = do_connect(h, ex, ep, token, ec);
191
2/2
✓ Branch 0 taken 1 time.
✓ Branch 1 taken 5 times.
6x if (result == std::noop_coroutine())
192 5x svc_.scheduler().notify_reactor();
193 6x return result;
194 }
195
196 inline std::coroutine_handle<>
197 3x select_udp_socket::send(
198 std::coroutine_handle<> h,
199 capy::executor_ref ex,
200 buffer_param buf,
201 std::stop_token token,
202 std::error_code* ec,
203 std::size_t* bytes_out)
204 {
205 3x auto result = do_send(h, ex, buf, token, ec, bytes_out);
206
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3x if (result == std::noop_coroutine())
207 svc_.scheduler().notify_reactor();
208 3x return result;
209 }
210
211 inline std::coroutine_handle<>
212 2x select_udp_socket::recv(
213 std::coroutine_handle<> h,
214 capy::executor_ref ex,
215 buffer_param buf,
216 std::stop_token token,
217 std::error_code* ec,
218 std::size_t* bytes_out)
219 {
220 2x return do_recv(h, ex, buf, token, ec, bytes_out);
221 }
222
223 inline endpoint
224 2x select_udp_socket::remote_endpoint() const noexcept
225 {
226 2x return reactor_datagram_socket::remote_endpoint();
227 }
228
229 inline void
230 3x select_udp_socket::cancel() noexcept
231 {
232 3x do_cancel();
233 3x }
234
235 inline void
236 186x select_udp_socket::close_socket() noexcept
237 {
238 186x do_close_socket();
239 186x }
240
241 inline std::error_code
242 45x select_udp_service::open_datagram_socket(
243 udp_socket::implementation& impl, int family, int type, int protocol)
244 {
245 45x auto* select_impl = static_cast<select_udp_socket*>(&impl);
246 45x select_impl->close_socket();
247
248 45x int fd = ::socket(family, type, protocol);
249
1/2
✓ Branch 0 taken 45 times.
✗ Branch 1 not taken.
45x if (fd < 0)
250 return make_err(errno);
251
252
2/2
✓ Branch 0 taken 38 times.
✓ Branch 1 taken 7 times.
45x if (family == AF_INET6)
253 {
254 7x int one = 1;
255 7x ::setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &one, sizeof(one));
256 7x }
257
258 45x int flags = ::fcntl(fd, F_GETFL, 0);
259
1/2
✓ Branch 0 taken 45 times.
✗ Branch 1 not taken.
45x if (flags == -1)
260 {
261 int errn = errno;
262 ::close(fd);
263 return make_err(errn);
264 }
265
1/2
✓ Branch 0 taken 45 times.
✗ Branch 1 not taken.
45x if (::fcntl(fd, F_SETFL, flags | O_NONBLOCK) == -1)
266 {
267 int errn = errno;
268 ::close(fd);
269 return make_err(errn);
270 }
271
1/2
✓ Branch 0 taken 45 times.
✗ Branch 1 not taken.
45x if (::fcntl(fd, F_SETFD, FD_CLOEXEC) == -1)
272 {
273 int errn = errno;
274 ::close(fd);
275 return make_err(errn);
276 }
277
278
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 45 times.
45x if (fd >= FD_SETSIZE)
279 {
280 ::close(fd);
281 return make_err(EMFILE);
282 }
283
284 #ifdef SO_NOSIGPIPE
285 {
286 45x int one = 1;
287 45x ::setsockopt(fd, SOL_SOCKET, SO_NOSIGPIPE, &one, sizeof(one));
288 }
289 #endif
290
291 45x select_impl->fd_ = fd;
292
293 45x select_impl->desc_state_.fd = fd;
294 {
295 45x std::lock_guard lock(select_impl->desc_state_.mutex);
296 45x select_impl->desc_state_.read_op = nullptr;
297 45x select_impl->desc_state_.write_op = nullptr;
298 45x select_impl->desc_state_.connect_op = nullptr;
299 45x }
300 45x scheduler().register_descriptor(fd, &select_impl->desc_state_);
301
302 45x return {};
303 45x }
304
305 inline std::error_code
306 25x select_udp_service::bind_datagram(udp_socket::implementation& impl, endpoint ep)
307 {
308 25x return static_cast<select_udp_socket*>(&impl)->do_bind(ep);
309 }
310
311 } // namespace boost::corosio::detail
312
313 #endif // BOOST_COROSIO_HAS_SELECT
314
315 #endif // BOOST_COROSIO_NATIVE_DETAIL_SELECT_SELECT_UDP_SERVICE_HPP
316