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

68.2% Lines (73/107) 81.8% List of functions (18/22)
f(x) Functions (22)
Function Calls Lines Blocks
boost::corosio::detail::select_udp_service::select_udp_service(boost::capy::execution_context&) :51 195x 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 39x 100.0% 100.0% boost::corosio::detail::select_udp_socket::~select_udp_socket() :147 39x 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, 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*, std::stop_token, std::error_code*, unsigned long*) :168 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*) :183 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, std::stop_token, std::error_code*, unsigned long*) :197 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, std::stop_token, std::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 2x 100.0% 100.0% boost::corosio::detail::select_udp_socket::close_socket() :236 152x 100.0% 100.0% boost::corosio::detail::select_udp_service::open_datagram_socket(boost::corosio::udp_socket::implementation&, int, int, int) :242 37x 64.7% 71.0% boost::corosio::detail::select_udp_service::bind_datagram(boost::corosio::udp_socket::implementation&, boost::corosio::endpoint) :306 21x 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 195x explicit select_udp_service(capy::execution_context& ctx)
52 195x : reactor_socket_service(ctx)
53 {
54 195x }
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 39x inline select_udp_socket::select_udp_socket(select_udp_service& svc) noexcept
143 39x : reactor_datagram_socket(svc)
144 {
145 39x }
146
147 39x 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 std::stop_token token,
158 std::error_code* ec,
159 std::size_t* bytes_out)
160 {
161 11x auto result = do_send_to(h, ex, buf, dest, token, ec, bytes_out);
162 11x if (result == std::noop_coroutine())
163 8x svc_.scheduler().notify_reactor();
164 11x return result;
165 }
166
167 inline std::coroutine_handle<>
168 16x 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 16x 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 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 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 2x select_udp_socket::cancel() noexcept
231 {
232 2x do_cancel();
233 2x }
234
235 inline void
236 152x select_udp_socket::close_socket() noexcept
237 {
238 152x do_close_socket();
239 152x }
240
241 inline std::error_code
242 37x select_udp_service::open_datagram_socket(
243 udp_socket::implementation& impl, int family, int type, int protocol)
244 {
245 37x auto* select_impl = static_cast<select_udp_socket*>(&impl);
246 37x select_impl->close_socket();
247
248 37x int fd = ::socket(family, type, protocol);
249 37x if (fd < 0)
250 return make_err(errno);
251
252 37x if (family == AF_INET6)
253 {
254 7x int one = 1;
255 7x ::setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &one, sizeof(one));
256 }
257
258 37x int flags = ::fcntl(fd, F_GETFL, 0);
259 37x if (flags == -1)
260 {
261 int errn = errno;
262 ::close(fd);
263 return make_err(errn);
264 }
265 37x if (::fcntl(fd, F_SETFL, flags | O_NONBLOCK) == -1)
266 {
267 int errn = errno;
268 ::close(fd);
269 return make_err(errn);
270 }
271 37x if (::fcntl(fd, F_SETFD, FD_CLOEXEC) == -1)
272 {
273 int errn = errno;
274 ::close(fd);
275 return make_err(errn);
276 }
277
278 37x if (fd >= FD_SETSIZE)
279 {
280 ::close(fd);
281 return make_err(EMFILE);
282 }
283
284 #ifdef SO_NOSIGPIPE
285 {
286 int one = 1;
287 ::setsockopt(fd, SOL_SOCKET, SO_NOSIGPIPE, &one, sizeof(one));
288 }
289 #endif
290
291 37x select_impl->fd_ = fd;
292
293 37x select_impl->desc_state_.fd = fd;
294 {
295 37x std::lock_guard lock(select_impl->desc_state_.mutex);
296 37x select_impl->desc_state_.read_op = nullptr;
297 37x select_impl->desc_state_.write_op = nullptr;
298 37x select_impl->desc_state_.connect_op = nullptr;
299 37x }
300 37x scheduler().register_descriptor(fd, &select_impl->desc_state_);
301
302 37x return {};
303 }
304
305 inline std::error_code
306 21x select_udp_service::bind_datagram(udp_socket::implementation& impl, endpoint ep)
307 {
308 21x 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