TLA Line data Source code
1 : //
2 : // Copyright (c) 2026 Michael Vandeberg
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_REACTOR_REACTOR_SERVICE_FINALS_HPP
11 : #define BOOST_COROSIO_NATIVE_DETAIL_REACTOR_REACTOR_SERVICE_FINALS_HPP
12 :
13 : /* Parameterized service implementation bases for reactor backends.
14 :
15 : One template per protocol (TCP, local stream, UDP, local datagram,
16 : acceptor). Named per-backend classes (e.g. epoll_tcp_service) inherit
17 : from these as final. The Derived parameter (CRTP) flows through to
18 : reactor_socket_service so construct() creates the correct named type.
19 : */
20 :
21 : #include <boost/corosio/native/detail/reactor/reactor_socket_finals.hpp>
22 : #include <boost/corosio/native/detail/reactor/reactor_socket_service.hpp>
23 : #include <boost/corosio/native/detail/reactor/reactor_acceptor_service.hpp>
24 : #include <boost/corosio/detail/tcp_service.hpp>
25 : #include <boost/corosio/detail/tcp_acceptor_service.hpp>
26 : #include <boost/corosio/detail/udp_service.hpp>
27 : #include <boost/corosio/detail/local_stream_service.hpp>
28 : #include <boost/corosio/detail/local_stream_acceptor_service.hpp>
29 : #include <boost/corosio/detail/local_datagram_service.hpp>
30 :
31 : #include <boost/corosio/native/detail/endpoint_convert.hpp>
32 : #include <boost/corosio/native/detail/make_err.hpp>
33 :
34 : #include <system_error>
35 : #include <type_traits>
36 :
37 : #include <sys/socket.h>
38 : #include <unistd.h>
39 :
40 : namespace boost::corosio::detail {
41 :
42 : // ============================================================
43 : // Shared socket creation helpers
44 : // ============================================================
45 :
46 : template<class Traits, class SocketFinal>
47 : std::error_code
48 HIT 7504 : do_open_socket(
49 : SocketFinal* socket_impl,
50 : int family, int type, int protocol,
51 : bool is_ip) noexcept
52 : {
53 7504 : socket_impl->close_socket();
54 :
55 7504 : int fd = Traits::create_socket(family, type, protocol);
56 7504 : if (fd < 0)
57 MIS 0 : return make_err(errno);
58 :
59 : std::error_code ec = is_ip
60 HIT 7504 : ? Traits::configure_ip_socket(fd, family)
61 28 : : Traits::configure_local_socket(fd);
62 :
63 7504 : if (ec)
64 : {
65 MIS 0 : ::close(fd);
66 0 : return ec;
67 : }
68 :
69 HIT 7504 : socket_impl->init_and_register(fd);
70 7504 : return {};
71 : }
72 :
73 : template<class Traits, class SocketFinal>
74 : std::error_code
75 28 : do_assign_fd(
76 : SocketFinal* socket_impl,
77 : int fd,
78 : int expected_type) noexcept
79 : {
80 28 : if (fd < 0)
81 MIS 0 : return make_err(EBADF);
82 :
83 HIT 28 : socket_impl->close_socket();
84 :
85 : // Validate that fd is actually an AF_UNIX socket of the expected type.
86 : {
87 28 : sockaddr_storage st{};
88 28 : socklen_t st_len = sizeof(st);
89 28 : if (::getsockname(
90 28 : fd, reinterpret_cast<sockaddr*>(&st), &st_len) != 0)
91 MIS 0 : return make_err(errno);
92 HIT 28 : if (st.ss_family != AF_UNIX)
93 MIS 0 : return make_err(EAFNOSUPPORT);
94 :
95 HIT 28 : int sock_type = 0;
96 28 : socklen_t opt_len = sizeof(sock_type);
97 28 : if (::getsockopt(
98 28 : fd, SOL_SOCKET, SO_TYPE, &sock_type, &opt_len) != 0)
99 MIS 0 : return make_err(errno);
100 HIT 28 : if (sock_type != expected_type)
101 MIS 0 : return make_err(EPROTOTYPE);
102 : }
103 :
104 : // Adopt-only: do not mutate the caller's fd flags. Callers
105 : // pass fds they have already configured (e.g., from socketpair
106 : // or SCM_RIGHTS). Only non-mutating validation is performed.
107 HIT 28 : if (auto ec = Traits::validate_assigned_fd(fd))
108 MIS 0 : return ec;
109 :
110 HIT 28 : socket_impl->init_and_register(fd);
111 :
112 : // Best-effort: refresh endpoint caches.
113 : using endpoint_type = std::remove_cvref_t<
114 : decltype(socket_impl->local_endpoint())>;
115 :
116 28 : endpoint_type local_ep{};
117 28 : sockaddr_storage local_storage{};
118 28 : socklen_t local_len = sizeof(local_storage);
119 28 : if (::getsockname(
120 28 : fd, reinterpret_cast<sockaddr*>(&local_storage), &local_len) == 0)
121 28 : local_ep = from_sockaddr_as(local_storage, local_len, endpoint_type{});
122 :
123 28 : endpoint_type remote_ep{};
124 28 : sockaddr_storage peer_storage{};
125 28 : socklen_t peer_len = sizeof(peer_storage);
126 28 : if (::getpeername(
127 28 : fd, reinterpret_cast<sockaddr*>(&peer_storage), &peer_len) == 0)
128 28 : remote_ep = from_sockaddr_as(peer_storage, peer_len, endpoint_type{});
129 :
130 28 : socket_impl->set_endpoints(local_ep, remote_ep);
131 :
132 28 : return {};
133 : }
134 :
135 : template<class Traits, class AccFinal>
136 : std::error_code
137 156 : do_open_acceptor(
138 : AccFinal* acc_impl,
139 : int family, int type, int protocol,
140 : bool is_ip) noexcept
141 : {
142 156 : acc_impl->close_socket();
143 :
144 156 : int fd = Traits::create_socket(family, type, protocol);
145 156 : if (fd < 0)
146 MIS 0 : return make_err(errno);
147 :
148 : std::error_code ec = is_ip
149 HIT 156 : ? Traits::configure_ip_acceptor(fd, family)
150 12 : : Traits::configure_local_socket(fd);
151 :
152 156 : if (ec)
153 : {
154 MIS 0 : ::close(fd);
155 0 : return ec;
156 : }
157 :
158 HIT 156 : acc_impl->init_acceptor_fd(fd);
159 156 : return {};
160 : }
161 :
162 : // ============================================================
163 : // TCP service
164 : // ============================================================
165 :
166 : template<class Derived, class Traits, class SocketFinal>
167 : class reactor_tcp_service_impl
168 : : public reactor_socket_service<
169 : Derived,
170 : tcp_service,
171 : typename Traits::scheduler_type,
172 : SocketFinal>
173 : {
174 : using base_service = reactor_socket_service<
175 : Derived, tcp_service,
176 : typename Traits::scheduler_type, SocketFinal>;
177 : friend Derived;
178 : friend base_service;
179 :
180 585 : explicit reactor_tcp_service_impl(capy::execution_context& ctx)
181 585 : : base_service(ctx) {}
182 :
183 : public:
184 : static constexpr bool needs_write_notification =
185 : Traits::needs_write_notification;
186 :
187 7396 : std::error_code open_socket(
188 : tcp_socket::implementation& impl,
189 : int family, int type, int protocol) override
190 : {
191 7396 : return do_open_socket<Traits>(
192 : static_cast<SocketFinal*>(&impl),
193 7396 : family, type, protocol, true);
194 : }
195 :
196 12 : std::error_code bind_socket(
197 : tcp_socket::implementation& impl, endpoint ep) override
198 : {
199 12 : return static_cast<SocketFinal*>(&impl)->do_bind(ep);
200 : }
201 :
202 MIS 0 : void pre_shutdown(SocketFinal* impl) noexcept
203 : {
204 0 : impl->hook_.pre_shutdown(impl->native_handle());
205 0 : }
206 :
207 HIT 22155 : void pre_destroy(SocketFinal* impl) noexcept
208 : {
209 22155 : impl->hook_.pre_destroy(impl->native_handle());
210 22155 : }
211 : };
212 :
213 : // ============================================================
214 : // Local stream service
215 : // ============================================================
216 :
217 : template<class Derived, class Traits, class SocketFinal>
218 : class reactor_local_stream_service_impl
219 : : public reactor_socket_service<
220 : Derived,
221 : local_stream_service,
222 : typename Traits::scheduler_type,
223 : SocketFinal>
224 : {
225 : using base_service = reactor_socket_service<
226 : Derived, local_stream_service,
227 : typename Traits::scheduler_type, SocketFinal>;
228 : friend Derived;
229 : friend base_service;
230 :
231 585 : explicit reactor_local_stream_service_impl(capy::execution_context& ctx)
232 585 : : base_service(ctx) {}
233 :
234 : public:
235 : static constexpr bool needs_write_notification =
236 : Traits::needs_write_notification;
237 :
238 8 : std::error_code open_socket(
239 : local_stream_socket::implementation& impl,
240 : int family, int type, int protocol) override
241 : {
242 8 : return do_open_socket<Traits>(
243 : static_cast<SocketFinal*>(&impl),
244 8 : family, type, protocol, false);
245 : }
246 :
247 16 : std::error_code assign_socket(
248 : local_stream_socket::implementation& impl, int fd) override
249 : {
250 16 : return do_assign_fd<Traits>(
251 16 : static_cast<SocketFinal*>(&impl), fd, SOCK_STREAM);
252 : }
253 : };
254 :
255 : // ============================================================
256 : // UDP service
257 : // ============================================================
258 :
259 : template<class Derived, class Traits, class SocketFinal>
260 : class reactor_udp_service_impl
261 : : public reactor_socket_service<
262 : Derived,
263 : udp_service,
264 : typename Traits::scheduler_type,
265 : SocketFinal>
266 : {
267 : using base_service = reactor_socket_service<
268 : Derived, udp_service,
269 : typename Traits::scheduler_type, SocketFinal>;
270 : friend Derived;
271 : friend base_service;
272 :
273 585 : explicit reactor_udp_service_impl(capy::execution_context& ctx)
274 585 : : base_service(ctx) {}
275 :
276 : public:
277 : static constexpr bool needs_write_notification =
278 : Traits::needs_write_notification;
279 :
280 80 : std::error_code open_datagram_socket(
281 : udp_socket::implementation& impl,
282 : int family, int type, int protocol) override
283 : {
284 80 : return do_open_socket<Traits>(
285 : static_cast<SocketFinal*>(&impl),
286 80 : family, type, protocol, true);
287 : }
288 :
289 48 : std::error_code bind_datagram(
290 : udp_socket::implementation& impl, endpoint ep) override
291 : {
292 48 : return static_cast<SocketFinal*>(&impl)->do_bind(ep);
293 : }
294 : };
295 :
296 : // ============================================================
297 : // Local datagram service
298 : // ============================================================
299 :
300 : template<class Derived, class Traits, class SocketFinal>
301 : class reactor_local_dgram_service_impl
302 : : public reactor_socket_service<
303 : Derived,
304 : local_datagram_service,
305 : typename Traits::scheduler_type,
306 : SocketFinal>
307 : {
308 : using base_service = reactor_socket_service<
309 : Derived, local_datagram_service,
310 : typename Traits::scheduler_type, SocketFinal>;
311 : friend Derived;
312 : friend base_service;
313 :
314 585 : explicit reactor_local_dgram_service_impl(capy::execution_context& ctx)
315 585 : : base_service(ctx) {}
316 :
317 : public:
318 : static constexpr bool needs_write_notification =
319 : Traits::needs_write_notification;
320 :
321 20 : std::error_code open_socket(
322 : local_datagram_socket::implementation& impl,
323 : int family, int type, int protocol) override
324 : {
325 20 : return do_open_socket<Traits>(
326 : static_cast<SocketFinal*>(&impl),
327 20 : family, type, protocol, false);
328 : }
329 :
330 12 : std::error_code assign_socket(
331 : local_datagram_socket::implementation& impl, int fd) override
332 : {
333 12 : return do_assign_fd<Traits>(
334 12 : static_cast<SocketFinal*>(&impl), fd, SOCK_DGRAM);
335 : }
336 :
337 16 : std::error_code bind_socket(
338 : local_datagram_socket::implementation& impl,
339 : corosio::local_endpoint ep) override
340 : {
341 16 : return static_cast<SocketFinal*>(&impl)->do_bind(ep);
342 : }
343 : };
344 :
345 : // ============================================================
346 : // Acceptor service
347 : // ============================================================
348 :
349 : template<class Derived, class Traits, class ServiceBase, class AccFinal,
350 : class StreamServiceFinal, class Endpoint>
351 : class reactor_acceptor_service_impl
352 : : public reactor_acceptor_service<
353 : Derived,
354 : ServiceBase,
355 : typename Traits::scheduler_type,
356 : AccFinal,
357 : StreamServiceFinal>
358 : {
359 : using base_service = reactor_acceptor_service<
360 : Derived,
361 : ServiceBase,
362 : typename Traits::scheduler_type,
363 : AccFinal,
364 : StreamServiceFinal>;
365 : friend Derived;
366 : friend base_service;
367 :
368 1170 : explicit reactor_acceptor_service_impl(capy::execution_context& ctx)
369 1170 : : base_service(ctx)
370 : {
371 : // Look up the concrete stream service directly by its type.
372 1170 : this->stream_svc_ =
373 1170 : this->ctx_.template find_service<StreamServiceFinal>();
374 1170 : }
375 :
376 : public:
377 156 : std::error_code open_acceptor_socket(
378 : typename AccFinal::impl_base_type& impl,
379 : int family, int type, int protocol) override
380 : {
381 156 : return do_open_acceptor<Traits>(
382 : static_cast<AccFinal*>(&impl),
383 : family, type, protocol,
384 156 : std::is_same_v<Endpoint, endpoint>);
385 : }
386 :
387 154 : std::error_code bind_acceptor(
388 : typename AccFinal::impl_base_type& impl,
389 : Endpoint ep) override
390 : {
391 154 : return static_cast<AccFinal*>(&impl)->do_bind(ep);
392 : }
393 :
394 138 : std::error_code listen_acceptor(
395 : typename AccFinal::impl_base_type& impl,
396 : int backlog) override
397 : {
398 138 : return static_cast<AccFinal*>(&impl)->do_listen(backlog);
399 : }
400 : };
401 :
402 : } // namespace boost::corosio::detail
403 :
404 : #endif // BOOST_COROSIO_NATIVE_DETAIL_REACTOR_REACTOR_SERVICE_FINALS_HPP
|