include/boost/corosio/native/detail/reactor/reactor_acceptor.hpp

87.7% Lines (136/155) 91.7% List of functions (22/24)
f(x) Functions (24)
Function Calls Lines Branches Blocks
boost::corosio::detail::reactor_acceptor<boost::corosio::detail::epoll_acceptor, boost::corosio::detail::epoll_acceptor_service, boost::corosio::detail::epoll_op, boost::corosio::detail::epoll_accept_op, boost::corosio::detail::descriptor_state>::reactor_acceptor(boost::corosio::detail::epoll_acceptor_service&) :56 0 100.0% boost::corosio::detail::reactor_acceptor<boost::corosio::detail::select_acceptor, boost::corosio::detail::select_acceptor_service, boost::corosio::detail::select_op, boost::corosio::detail::select_accept_op, boost::corosio::detail::select_descriptor_state>::reactor_acceptor(boost::corosio::detail::select_acceptor_service&) :56 0 100.0% boost::corosio::detail::reactor_acceptor<boost::corosio::detail::epoll_acceptor, boost::corosio::detail::epoll_acceptor_service, boost::corosio::detail::epoll_op, boost::corosio::detail::epoll_accept_op, boost::corosio::detail::descriptor_state>::~reactor_acceptor() :70 0 100.0% boost::corosio::detail::reactor_acceptor<boost::corosio::detail::select_acceptor, boost::corosio::detail::select_acceptor_service, boost::corosio::detail::select_op, boost::corosio::detail::select_accept_op, boost::corosio::detail::select_descriptor_state>::~reactor_acceptor() :70 0 100.0% boost::corosio::detail::reactor_acceptor<boost::corosio::detail::epoll_acceptor, boost::corosio::detail::epoll_acceptor_service, boost::corosio::detail::epoll_op, boost::corosio::detail::epoll_accept_op, boost::corosio::detail::descriptor_state>::local_endpoint() const :79 0 100.0% boost::corosio::detail::reactor_acceptor<boost::corosio::detail::select_acceptor, boost::corosio::detail::select_acceptor_service, boost::corosio::detail::select_op, boost::corosio::detail::select_accept_op, boost::corosio::detail::select_descriptor_state>::local_endpoint() const :79 0 100.0% boost::corosio::detail::reactor_acceptor<boost::corosio::detail::epoll_acceptor, boost::corosio::detail::epoll_acceptor_service, boost::corosio::detail::epoll_op, boost::corosio::detail::epoll_accept_op, boost::corosio::detail::descriptor_state>::is_open() const :85 0 100.0% boost::corosio::detail::reactor_acceptor<boost::corosio::detail::select_acceptor, boost::corosio::detail::select_acceptor_service, boost::corosio::detail::select_op, boost::corosio::detail::select_accept_op, boost::corosio::detail::select_descriptor_state>::is_open() const :85 0 100.0% boost::corosio::detail::reactor_acceptor<boost::corosio::detail::epoll_acceptor, boost::corosio::detail::epoll_acceptor_service, boost::corosio::detail::epoll_op, boost::corosio::detail::epoll_accept_op, boost::corosio::detail::descriptor_state>::set_option(int, int, void const*, unsigned long) :91 0 80.0% boost::corosio::detail::reactor_acceptor<boost::corosio::detail::select_acceptor, boost::corosio::detail::select_acceptor_service, boost::corosio::detail::select_op, boost::corosio::detail::select_accept_op, boost::corosio::detail::select_descriptor_state>::set_option(int, int, void const*, unsigned long) :91 0 80.0% boost::corosio::detail::reactor_acceptor<boost::corosio::detail::epoll_acceptor, boost::corosio::detail::epoll_acceptor_service, boost::corosio::detail::epoll_op, boost::corosio::detail::epoll_accept_op, boost::corosio::detail::descriptor_state>::get_option(int, int, void*, unsigned long*) const :105 0 0.0% boost::corosio::detail::reactor_acceptor<boost::corosio::detail::select_acceptor, boost::corosio::detail::select_acceptor_service, boost::corosio::detail::select_op, boost::corosio::detail::select_accept_op, boost::corosio::detail::select_descriptor_state>::get_option(int, int, void*, unsigned long*) const :105 0 0.0% boost::corosio::detail::reactor_acceptor<boost::corosio::detail::epoll_acceptor, boost::corosio::detail::epoll_acceptor_service, boost::corosio::detail::epoll_op, boost::corosio::detail::epoll_accept_op, boost::corosio::detail::descriptor_state>::set_local_endpoint(boost::corosio::endpoint) :116 0 100.0% boost::corosio::detail::reactor_acceptor<boost::corosio::detail::select_acceptor, boost::corosio::detail::select_acceptor_service, boost::corosio::detail::select_op, boost::corosio::detail::select_accept_op, boost::corosio::detail::select_descriptor_state>::set_local_endpoint(boost::corosio::endpoint) :116 0 100.0% boost::corosio::detail::reactor_acceptor<boost::corosio::detail::epoll_acceptor, boost::corosio::detail::epoll_acceptor_service, boost::corosio::detail::epoll_op, boost::corosio::detail::epoll_accept_op, boost::corosio::detail::descriptor_state>::service() :122 0 100.0% boost::corosio::detail::reactor_acceptor<boost::corosio::detail::select_acceptor, boost::corosio::detail::select_acceptor_service, boost::corosio::detail::select_op, boost::corosio::detail::select_accept_op, boost::corosio::detail::select_descriptor_state>::service() :122 0 100.0% boost::corosio::detail::reactor_acceptor<boost::corosio::detail::epoll_acceptor, boost::corosio::detail::epoll_acceptor_service, boost::corosio::detail::epoll_op, boost::corosio::detail::epoll_accept_op, boost::corosio::detail::descriptor_state>::cancel_single_op(boost::corosio::detail::epoll_op&) :178 0 93.3% boost::corosio::detail::reactor_acceptor<boost::corosio::detail::select_acceptor, boost::corosio::detail::select_acceptor_service, boost::corosio::detail::select_op, boost::corosio::detail::select_accept_op, boost::corosio::detail::select_descriptor_state>::cancel_single_op(boost::corosio::detail::select_op&) :178 0 93.3% boost::corosio::detail::reactor_acceptor<boost::corosio::detail::epoll_acceptor, boost::corosio::detail::epoll_acceptor_service, boost::corosio::detail::epoll_op, boost::corosio::detail::epoll_accept_op, boost::corosio::detail::descriptor_state>::do_cancel() :208 0 100.0% boost::corosio::detail::reactor_acceptor<boost::corosio::detail::select_acceptor, boost::corosio::detail::select_acceptor_service, boost::corosio::detail::select_op, boost::corosio::detail::select_accept_op, boost::corosio::detail::select_descriptor_state>::do_cancel() :208 0 100.0% boost::corosio::detail::reactor_acceptor<boost::corosio::detail::epoll_acceptor, boost::corosio::detail::epoll_acceptor_service, boost::corosio::detail::epoll_op, boost::corosio::detail::epoll_accept_op, boost::corosio::detail::descriptor_state>::do_close_socket() :221 0 96.0% boost::corosio::detail::reactor_acceptor<boost::corosio::detail::select_acceptor, boost::corosio::detail::select_acceptor_service, boost::corosio::detail::select_op, boost::corosio::detail::select_accept_op, boost::corosio::detail::select_descriptor_state>::do_close_socket() :221 0 96.0% boost::corosio::detail::reactor_acceptor<boost::corosio::detail::epoll_acceptor, boost::corosio::detail::epoll_acceptor_service, boost::corosio::detail::epoll_op, boost::corosio::detail::epoll_accept_op, boost::corosio::detail::descriptor_state>::do_bind(boost::corosio::endpoint) :269 0 100.0% boost::corosio::detail::reactor_acceptor<boost::corosio::detail::select_acceptor, boost::corosio::detail::select_acceptor_service, boost::corosio::detail::select_op, boost::corosio::detail::select_accept_op, boost::corosio::detail::select_descriptor_state>::do_bind(boost::corosio::endpoint) :269 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_REACTOR_REACTOR_ACCEPTOR_HPP
11 #define BOOST_COROSIO_NATIVE_DETAIL_REACTOR_REACTOR_ACCEPTOR_HPP
12
13 #include <boost/corosio/tcp_acceptor.hpp>
14 #include <boost/corosio/detail/intrusive.hpp>
15 #include <boost/corosio/native/detail/reactor/reactor_op_base.hpp>
16 #include <boost/corosio/native/detail/make_err.hpp>
17 #include <boost/corosio/native/detail/endpoint_convert.hpp>
18
19 #include <memory>
20 #include <mutex>
21 #include <utility>
22
23 #include <errno.h>
24 #include <netinet/in.h>
25 #include <sys/socket.h>
26 #include <unistd.h>
27
28 namespace boost::corosio::detail {
29
30 /** CRTP base for reactor-backed acceptor implementations.
31
32 Provides shared data members, trivial virtual overrides, and
33 non-virtual helper methods for cancellation and close. Concrete
34 backends inherit and add `cancel()`, `close_socket()`, and
35 `accept()` overrides that delegate to the `do_*` helpers.
36
37 @tparam Derived The concrete acceptor type (CRTP).
38 @tparam Service The backend's acceptor service type.
39 @tparam Op The backend's base op type.
40 @tparam AcceptOp The backend's accept op type.
41 @tparam DescState The backend's descriptor_state type.
42 */
43 template<
44 class Derived,
45 class Service,
46 class Op,
47 class AcceptOp,
48 class DescState>
49 class reactor_acceptor
50 : public tcp_acceptor::implementation
51 , public std::enable_shared_from_this<Derived>
52 , public intrusive_list<Derived>::node
53 {
54 friend Derived;
55
56 141x explicit reactor_acceptor(Service& svc) noexcept : svc_(svc) {}
57
58 protected:
59 Service& svc_;
60 int fd_ = -1;
61 endpoint local_endpoint_;
62
63 public:
64 /// Pending accept operation slot.
65 AcceptOp acc_;
66
67 /// Per-descriptor state for persistent reactor registration.
68 DescState desc_state_;
69
70 141x ~reactor_acceptor() override = default;
71
72 /// Return the underlying file descriptor.
73 int native_handle() const noexcept
74 {
75 return fd_;
76 }
77
78 /// Return the cached local endpoint.
79 7607x endpoint local_endpoint() const noexcept override
80 {
81 7607x return local_endpoint_;
82 }
83
84 /// Return true if the acceptor has an open file descriptor.
85 8467x bool is_open() const noexcept override
86 {
87 8467x return fd_ >= 0;
88 }
89
90 /// Set a socket option.
91 135x std::error_code set_option(
92 int level,
93 int optname,
94 void const* data,
95 std::size_t size) noexcept override
96 {
97 135x if (::setsockopt(
98 135x fd_, level, optname, data, static_cast<socklen_t>(size)) != 0)
99 return make_err(errno);
100 135x return {};
101 }
102
103 /// Get a socket option.
104 std::error_code
105 get_option(int level, int optname, void* data, std::size_t* size)
106 const noexcept override
107 {
108 socklen_t len = static_cast<socklen_t>(*size);
109 if (::getsockopt(fd_, level, optname, data, &len) != 0)
110 return make_err(errno);
111 *size = static_cast<std::size_t>(len);
112 return {};
113 }
114
115 /// Cache the local endpoint.
116 132x void set_local_endpoint(endpoint ep) noexcept
117 {
118 132x local_endpoint_ = ep;
119 132x }
120
121 /// Return a reference to the owning service.
122 7481x Service& service() noexcept
123 {
124 7481x return svc_;
125 }
126
127 /** Cancel a single pending operation.
128
129 Claims the operation from the read_op descriptor slot
130 under the mutex and posts it to the scheduler as cancelled.
131
132 @param op The operation to cancel.
133 */
134 void cancel_single_op(Op& op) noexcept;
135
136 /** Cancel the pending accept operation.
137
138 Invoked by the derived class's cancel() override.
139 */
140 void do_cancel() noexcept;
141
142 /** Close the acceptor and cancel pending operations.
143
144 Invoked by the derived class's close_socket(). The
145 derived class may add backend-specific cleanup after
146 calling this method.
147 */
148 void do_close_socket() noexcept;
149
150 /** Bind the acceptor socket to an endpoint.
151
152 Caches the resolved local endpoint (including ephemeral
153 port) after a successful bind.
154
155 @param ep The endpoint to bind to.
156 @return The error code from bind(), or success.
157 */
158 std::error_code do_bind(endpoint ep);
159
160 /** Start listening on the acceptor socket.
161
162 Registers the file descriptor with the reactor after
163 a successful listen() call.
164
165 @param backlog The listen backlog.
166 @return The error code from listen(), or success.
167 */
168 std::error_code do_listen(int backlog);
169 };
170
171 template<
172 class Derived,
173 class Service,
174 class Op,
175 class AcceptOp,
176 class DescState>
177 void
178 10x reactor_acceptor<Derived, Service, Op, AcceptOp, DescState>::cancel_single_op(
179 Op& op) noexcept
180 {
181 10x auto self = this->weak_from_this().lock();
182 10x if (!self)
183 return;
184
185 10x op.request_cancel();
186
187 10x reactor_op_base* claimed = nullptr;
188 {
189 10x std::lock_guard lock(desc_state_.mutex);
190 10x if (desc_state_.read_op == &op)
191 8x claimed = std::exchange(desc_state_.read_op, nullptr);
192 10x }
193 10x if (claimed)
194 {
195 8x op.impl_ptr = self;
196 8x svc_.post(&op);
197 8x svc_.work_finished();
198 }
199 10x }
200
201 template<
202 class Derived,
203 class Service,
204 class Op,
205 class AcceptOp,
206 class DescState>
207 void
208 4x reactor_acceptor<Derived, Service, Op, AcceptOp, DescState>::
209 do_cancel() noexcept
210 {
211 4x cancel_single_op(acc_);
212 4x }
213
214 template<
215 class Derived,
216 class Service,
217 class Op,
218 class AcceptOp,
219 class DescState>
220 void
221 558x reactor_acceptor<Derived, Service, Op, AcceptOp, DescState>::
222 do_close_socket() noexcept
223 {
224 558x auto self = this->weak_from_this().lock();
225 558x if (self)
226 {
227 558x acc_.request_cancel();
228
229 558x reactor_op_base* claimed = nullptr;
230 {
231 558x std::lock_guard lock(desc_state_.mutex);
232 558x claimed = std::exchange(desc_state_.read_op, nullptr);
233 558x desc_state_.read_ready = false;
234 558x desc_state_.write_ready = false;
235
236 558x if (desc_state_.is_enqueued_.load(std::memory_order_acquire))
237 desc_state_.impl_ref_ = self;
238 558x }
239
240 558x if (claimed)
241 {
242 4x acc_.impl_ptr = self;
243 4x svc_.post(&acc_);
244 4x svc_.work_finished();
245 }
246 }
247
248 558x if (fd_ >= 0)
249 {
250 138x if (desc_state_.registered_events != 0)
251 132x svc_.scheduler().deregister_descriptor(fd_);
252 138x ::close(fd_);
253 138x fd_ = -1;
254 }
255
256 558x desc_state_.fd = -1;
257 558x desc_state_.registered_events = 0;
258
259 558x local_endpoint_ = endpoint{};
260 558x }
261
262 template<
263 class Derived,
264 class Service,
265 class Op,
266 class AcceptOp,
267 class DescState>
268 std::error_code
269 136x reactor_acceptor<Derived, Service, Op, AcceptOp, DescState>::do_bind(
270 endpoint ep)
271 {
272 136x sockaddr_storage storage{};
273 136x socklen_t addrlen = to_sockaddr(ep, storage);
274 136x if (::bind(fd_, reinterpret_cast<sockaddr*>(&storage), addrlen) < 0)
275 4x return make_err(errno);
276
277 // Cache local endpoint (resolves ephemeral port)
278 132x sockaddr_storage local{};
279 132x socklen_t local_len = sizeof(local);
280 132x if (::getsockname(fd_, reinterpret_cast<sockaddr*>(&local), &local_len) ==
281 0)
282 132x set_local_endpoint(from_sockaddr(local));
283
284 132x return {};
285 }
286
287 template<
288 class Derived,
289 class Service,
290 class Op,
291 class AcceptOp,
292 class DescState>
293 std::error_code
294 132x reactor_acceptor<Derived, Service, Op, AcceptOp, DescState>::do_listen(
295 int backlog)
296 {
297 132x if (::listen(fd_, backlog) < 0)
298 return make_err(errno);
299
300 132x svc_.scheduler().register_descriptor(fd_, &desc_state_);
301 132x return {};
302 }
303
304 } // namespace boost::corosio::detail
305
306 #endif // BOOST_COROSIO_NATIVE_DETAIL_REACTOR_REACTOR_ACCEPTOR_HPP
307