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

68.2% Lines (73/107) 81.8% List of functions (18/22)
select_udp_service.hpp
f(x) Functions (22)
Function Calls Lines Blocks
boost::corosio::detail::select_udp_service::select_udp_service(boost::capy::execution_context&) :51 228x 100.0% 100.0% boost::corosio::detail::select_send_to_op::cancel() :68 0 0.0% 0.0% boost::corosio::detail::select_recv_from_op::cancel() :77 1x 80.0% 75.0% boost::corosio::detail::select_udp_connect_op::cancel() :88 0 0.0% 0.0% boost::corosio::detail::select_send_op::cancel() :97 0 0.0% 0.0% boost::corosio::detail::select_recv_op::cancel() :106 0 0.0% 0.0% boost::corosio::detail::select_datagram_op::operator()() :117 8x 100.0% 100.0% boost::corosio::detail::select_recv_from_op::operator()() :123 7x 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 43x 100.0% 100.0% boost::corosio::detail::select_udp_socket::~select_udp_socket() :147 43x 100.0% 100.0% boost::corosio::detail::select_udp_socket::send_to(std::__n4861::coroutine_handle<void>, boost::capy::executor_ref, boost::corosio::buffer_param, boost::corosio::endpoint, int, std::stop_token, std::error_code*, unsigned long*) :152 11x 100.0% 100.0% boost::corosio::detail::select_udp_socket::recv_from(std::__n4861::coroutine_handle<void>, boost::capy::executor_ref, boost::corosio::buffer_param, boost::corosio::endpoint*, int, std::stop_token, std::error_code*, unsigned long*) :169 16x 100.0% 100.0% boost::corosio::detail::select_udp_socket::connect(std::__n4861::coroutine_handle<void>, boost::capy::executor_ref, boost::corosio::endpoint, std::stop_token, std::error_code*) :185 6x 100.0% 100.0% boost::corosio::detail::select_udp_socket::send(std::__n4861::coroutine_handle<void>, boost::capy::executor_ref, boost::corosio::buffer_param, int, std::stop_token, std::error_code*, unsigned long*) :199 3x 80.0% 80.0% boost::corosio::detail::select_udp_socket::recv(std::__n4861::coroutine_handle<void>, boost::capy::executor_ref, boost::corosio::buffer_param, int, std::stop_token, std::error_code*, unsigned long*) :215 2x 100.0% 100.0% boost::corosio::detail::select_udp_socket::remote_endpoint() const :228 2x 100.0% 100.0% boost::corosio::detail::select_udp_socket::cancel() :234 2x 100.0% 100.0% boost::corosio::detail::select_udp_socket::close_socket() :240 166x 100.0% 100.0% boost::corosio::detail::select_udp_service::open_datagram_socket(boost::corosio::udp_socket::implementation&, int, int, int) :246 40x 64.7% 71.0% boost::corosio::detail::select_udp_service::bind_datagram(boost::corosio::udp_socket::implementation&, boost::corosio::endpoint) :310 24x 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_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 228x explicit select_udp_service(capy::execution_context& ctx)
52 228x : reactor_socket_service(ctx)
53 {
54 228x }
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 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 8x select_datagram_op::operator()()
118 {
119 8x complete_io_op(*this);
120 8x }
121
122 inline void
123 7x select_recv_from_op::operator()()
124 {
125 7x complete_datagram_op(*this, this->source_out);
126 7x }
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 43x inline select_udp_socket::select_udp_socket(select_udp_service& svc) noexcept
143 43x : reactor_datagram_socket(svc)
144 {
145 43x }
146
147 43x inline select_udp_socket::~select_udp_socket() = default;
148
149 // Connectionless I/O
150
151 inline std::coroutine_handle<>
152 11x select_udp_socket::send_to(
153 std::coroutine_handle<> h,
154 capy::executor_ref ex,
155 buffer_param buf,
156 endpoint dest,
157 int flags,
158 std::stop_token token,
159 std::error_code* ec,
160 std::size_t* bytes_out)
161 {
162 11x auto result = do_send_to(h, ex, buf, dest, flags, token, ec, bytes_out);
163 11x if (result == std::noop_coroutine())
164 8x svc_.scheduler().notify_reactor();
165 11x return result;
166 }
167
168 inline std::coroutine_handle<>
169 16x select_udp_socket::recv_from(
170 std::coroutine_handle<> h,
171 capy::executor_ref ex,
172 buffer_param buf,
173 endpoint* source,
174 int flags,
175 std::stop_token token,
176 std::error_code* ec,
177 std::size_t* bytes_out)
178 {
179 16x return do_recv_from(h, ex, buf, source, flags, token, ec, bytes_out);
180 }
181
182 // Connected-mode I/O
183
184 inline std::coroutine_handle<>
185 6x select_udp_socket::connect(
186 std::coroutine_handle<> h,
187 capy::executor_ref ex,
188 endpoint ep,
189 std::stop_token token,
190 std::error_code* ec)
191 {
192 6x auto result = do_connect(h, ex, ep, token, ec);
193 6x if (result == std::noop_coroutine())
194 5x svc_.scheduler().notify_reactor();
195 6x return result;
196 }
197
198 inline std::coroutine_handle<>
199 3x select_udp_socket::send(
200 std::coroutine_handle<> h,
201 capy::executor_ref ex,
202 buffer_param buf,
203 int flags,
204 std::stop_token token,
205 std::error_code* ec,
206 std::size_t* bytes_out)
207 {
208 3x auto result = do_send(h, ex, buf, flags, token, ec, bytes_out);
209 3x if (result == std::noop_coroutine())
210 svc_.scheduler().notify_reactor();
211 3x return result;
212 }
213
214 inline std::coroutine_handle<>
215 2x select_udp_socket::recv(
216 std::coroutine_handle<> h,
217 capy::executor_ref ex,
218 buffer_param buf,
219 int flags,
220 std::stop_token token,
221 std::error_code* ec,
222 std::size_t* bytes_out)
223 {
224 2x return do_recv(h, ex, buf, flags, token, ec, bytes_out);
225 }
226
227 inline endpoint
228 2x select_udp_socket::remote_endpoint() const noexcept
229 {
230 2x return reactor_datagram_socket::remote_endpoint();
231 }
232
233 inline void
234 2x select_udp_socket::cancel() noexcept
235 {
236 2x do_cancel();
237 2x }
238
239 inline void
240 166x select_udp_socket::close_socket() noexcept
241 {
242 166x do_close_socket();
243 166x }
244
245 inline std::error_code
246 40x select_udp_service::open_datagram_socket(
247 udp_socket::implementation& impl, int family, int type, int protocol)
248 {
249 40x auto* select_impl = static_cast<select_udp_socket*>(&impl);
250 40x select_impl->close_socket();
251
252 40x int fd = ::socket(family, type, protocol);
253 40x if (fd < 0)
254 return make_err(errno);
255
256 40x if (family == AF_INET6)
257 {
258 7x int one = 1;
259 7x ::setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &one, sizeof(one));
260 }
261
262 40x int flags = ::fcntl(fd, F_GETFL, 0);
263 40x if (flags == -1)
264 {
265 int errn = errno;
266 ::close(fd);
267 return make_err(errn);
268 }
269 40x if (::fcntl(fd, F_SETFL, flags | O_NONBLOCK) == -1)
270 {
271 int errn = errno;
272 ::close(fd);
273 return make_err(errn);
274 }
275 40x if (::fcntl(fd, F_SETFD, FD_CLOEXEC) == -1)
276 {
277 int errn = errno;
278 ::close(fd);
279 return make_err(errn);
280 }
281
282 40x if (fd >= FD_SETSIZE)
283 {
284 ::close(fd);
285 return make_err(EMFILE);
286 }
287
288 #ifdef SO_NOSIGPIPE
289 {
290 int one = 1;
291 ::setsockopt(fd, SOL_SOCKET, SO_NOSIGPIPE, &one, sizeof(one));
292 }
293 #endif
294
295 40x select_impl->fd_ = fd;
296
297 40x select_impl->desc_state_.fd = fd;
298 {
299 40x std::lock_guard lock(select_impl->desc_state_.mutex);
300 40x select_impl->desc_state_.read_op = nullptr;
301 40x select_impl->desc_state_.write_op = nullptr;
302 40x select_impl->desc_state_.connect_op = nullptr;
303 40x }
304 40x scheduler().register_descriptor(fd, &select_impl->desc_state_);
305
306 40x return {};
307 }
308
309 inline std::error_code
310 24x select_udp_service::bind_datagram(udp_socket::implementation& impl, endpoint ep)
311 {
312 24x return static_cast<select_udp_socket*>(&impl)->do_bind(ep);
313 }
314
315 } // namespace boost::corosio::detail
316
317 #endif // BOOST_COROSIO_HAS_SELECT
318
319 #endif // BOOST_COROSIO_NATIVE_DETAIL_SELECT_SELECT_UDP_SERVICE_HPP
320