include/boost/corosio/native/native_tcp_acceptor.hpp

95.8% Lines (69 / 72) 77.3% Branches (34 / 44) 100.0% Functions (46 / 46)
native_tcp_acceptor.hpp
f(x) Functions (46)
Function Calls Lines Branches Blocks
boost::corosio::native_tcp_acceptor<boost::corosio::kqueue_t{}>::~native_tcp_acceptor() :63 54x 100.0% – 100.0% boost::corosio::native_tcp_acceptor<boost::corosio::select_t{}>::~native_tcp_acceptor() :63 52x 100.0% – 100.0% boost::corosio::native_tcp_acceptor<boost::corosio::kqueue_t{}>::get_impl() :69 15x 100.0% – 100.0% boost::corosio::native_tcp_acceptor<boost::corosio::select_t{}>::get_impl() :69 14x 100.0% – 100.0% boost::corosio::native_tcp_acceptor<boost::corosio::kqueue_t{}>::native_wait_awaitable::native_wait_awaitable(boost::corosio::native_tcp_acceptor<boost::corosio::kqueue_t{}>::native_wait_awaitable&&) :74 6x 100.0% – 100.0% boost::corosio::native_tcp_acceptor<boost::corosio::kqueue_t{}>::native_wait_awaitable::~native_wait_awaitable() :74 12x 100.0% – 100.0% boost::corosio::native_tcp_acceptor<boost::corosio::select_t{}>::native_wait_awaitable::native_wait_awaitable(boost::corosio::native_tcp_acceptor<boost::corosio::select_t{}>::native_wait_awaitable&&) :74 6x 100.0% – 100.0% boost::corosio::native_tcp_acceptor<boost::corosio::select_t{}>::native_wait_awaitable::~native_wait_awaitable() :74 12x 100.0% – 100.0% boost::corosio::native_tcp_acceptor<boost::corosio::kqueue_t{}>::native_wait_awaitable::native_wait_awaitable(boost::corosio::native_tcp_acceptor<boost::corosio::kqueue_t{}>&, boost::corosio::wait_type) :79 6x 100.0% – 100.0% boost::corosio::native_tcp_acceptor<boost::corosio::select_t{}>::native_wait_awaitable::native_wait_awaitable(boost::corosio::native_tcp_acceptor<boost::corosio::select_t{}>&, boost::corosio::wait_type) :79 6x 100.0% – 100.0% boost::corosio::native_tcp_acceptor<boost::corosio::kqueue_t{}>::native_wait_awaitable::dispatch(boost::capy::continuation&, boost::capy::executor_ref) const :86 2x 100.0% – 50.0% boost::corosio::native_tcp_acceptor<boost::corosio::select_t{}>::native_wait_awaitable::dispatch(boost::capy::continuation&, boost::capy::executor_ref) const :86 2x 66.7% 50.0% 50.0% boost::corosio::native_tcp_acceptor<boost::corosio::kqueue_t{}>::native_accept_awaitable::native_accept_awaitable(boost::corosio::native_tcp_acceptor<boost::corosio::kqueue_t{}>::native_accept_awaitable const&) :92 52x 100.0% – 100.0% boost::corosio::native_tcp_acceptor<boost::corosio::select_t{}>::native_accept_awaitable::native_accept_awaitable(boost::corosio::native_tcp_acceptor<boost::corosio::select_t{}>::native_accept_awaitable const&) :92 48x 100.0% – 100.0% boost::corosio::native_tcp_acceptor<boost::corosio::kqueue_t{}>::native_accept_awaitable::native_accept_awaitable(boost::corosio::native_tcp_acceptor<boost::corosio::kqueue_t{}>&, boost::corosio::tcp_socket&) :99 26x 100.0% – 100.0% boost::corosio::native_tcp_acceptor<boost::corosio::select_t{}>::native_accept_awaitable::native_accept_awaitable(boost::corosio::native_tcp_acceptor<boost::corosio::select_t{}>&, boost::corosio::tcp_socket&) :99 24x 100.0% – 100.0% boost::corosio::native_tcp_acceptor<boost::corosio::kqueue_t{}>::native_accept_awaitable::~native_accept_awaitable() :108 78x 80.0% 50.0% 100.0% boost::corosio::native_tcp_acceptor<boost::corosio::select_t{}>::native_accept_awaitable::~native_accept_awaitable() :108 72x 100.0% 100.0% 100.0% boost::corosio::native_tcp_acceptor<boost::corosio::kqueue_t{}>::native_accept_awaitable::await_resume() const :114 12x 100.0% 50.0% 100.0% boost::corosio::native_tcp_acceptor<boost::corosio::select_t{}>::native_accept_awaitable::await_resume() const :114 11x 100.0% 100.0% 100.0% boost::corosio::native_tcp_acceptor<boost::corosio::kqueue_t{}>::native_accept_awaitable::dispatch(boost::capy::continuation&, boost::capy::executor_ref) const :122 11x 75.0% 50.0% 50.0% boost::corosio::native_tcp_acceptor<boost::corosio::select_t{}>::native_accept_awaitable::dispatch(boost::capy::continuation&, boost::capy::executor_ref) const :122 10x 75.0% 50.0% 50.0% boost::corosio::native_tcp_acceptor<boost::corosio::kqueue_t{}>::native_accept_value_awaitable::native_accept_value_awaitable(boost::corosio::native_tcp_acceptor<boost::corosio::kqueue_t{}>::native_accept_value_awaitable const&) :129 20x 100.0% – 100.0% boost::corosio::native_tcp_acceptor<boost::corosio::select_t{}>::native_accept_value_awaitable::native_accept_value_awaitable(boost::corosio::native_tcp_acceptor<boost::corosio::select_t{}>::native_accept_value_awaitable const&) :129 20x 100.0% – 100.0% boost::corosio::native_tcp_acceptor<boost::corosio::kqueue_t{}>::native_accept_value_awaitable::native_accept_value_awaitable(boost::corosio::native_tcp_acceptor<boost::corosio::kqueue_t{}>&) :135 10x 100.0% – 100.0% boost::corosio::native_tcp_acceptor<boost::corosio::select_t{}>::native_accept_value_awaitable::native_accept_value_awaitable(boost::corosio::native_tcp_acceptor<boost::corosio::select_t{}>&) :135 10x 100.0% – 100.0% boost::corosio::native_tcp_acceptor<boost::corosio::kqueue_t{}>::native_accept_value_awaitable::~native_accept_value_awaitable() :143 30x 100.0% – 100.0% boost::corosio::native_tcp_acceptor<boost::corosio::select_t{}>::native_accept_value_awaitable::~native_accept_value_awaitable() :143 30x 100.0% 100.0% 100.0% boost::corosio::native_tcp_acceptor<boost::corosio::kqueue_t{}>::native_accept_value_awaitable::await_resume() :149 4x 100.0% – 100.0% boost::corosio::native_tcp_acceptor<boost::corosio::select_t{}>::native_accept_value_awaitable::await_resume() :149 4x 100.0% – 100.0% boost::corosio::native_tcp_acceptor<boost::corosio::kqueue_t{}>::native_accept_value_awaitable::dispatch(boost::capy::continuation&, boost::capy::executor_ref) const :155 2x 100.0% – 50.0% boost::corosio::native_tcp_acceptor<boost::corosio::select_t{}>::native_accept_value_awaitable::dispatch(boost::capy::continuation&, boost::capy::executor_ref) const :155 2x 75.0% 50.0% 50.0% boost::corosio::native_tcp_acceptor<boost::corosio::kqueue_t{}>::native_tcp_acceptor(boost::capy::execution_context&) :167 44x 100.0% – 100.0% boost::corosio::native_tcp_acceptor<boost::corosio::select_t{}>::native_tcp_acceptor(boost::capy::execution_context&) :167 42x 100.0% – 100.0% boost::corosio::native_tcp_acceptor<boost::corosio::kqueue_t{}>::native_tcp_acceptor(boost::capy::execution_context&, boost::corosio::endpoint, int) :204 8x 100.0% – 100.0% boost::corosio::native_tcp_acceptor<boost::corosio::select_t{}>::native_tcp_acceptor(boost::capy::execution_context&, boost::corosio::endpoint, int) :204 8x 100.0% 100.0% 100.0% boost::corosio::native_tcp_acceptor<boost::corosio::kqueue_t{}>::native_tcp_acceptor<boost::corosio::io_context::executor_type>(boost::corosio::io_context::executor_type const&, boost::corosio::endpoint, int) :224 1x 100.0% – 100.0% boost::corosio::native_tcp_acceptor<boost::corosio::select_t{}>::native_tcp_acceptor<boost::corosio::io_context::executor_type>(boost::corosio::io_context::executor_type const&, boost::corosio::endpoint, int) :224 1x 100.0% – 100.0% boost::corosio::native_tcp_acceptor<boost::corosio::kqueue_t{}>::native_tcp_acceptor(boost::corosio::native_tcp_acceptor<boost::corosio::kqueue_t{}>&&) :237 4x 100.0% – 100.0% boost::corosio::native_tcp_acceptor<boost::corosio::select_t{}>::native_tcp_acceptor(boost::corosio::native_tcp_acceptor<boost::corosio::select_t{}>&&) :237 4x 100.0% – 100.0% boost::corosio::native_tcp_acceptor<boost::corosio::kqueue_t{}>::accept(boost::corosio::tcp_socket&) :270 13x 83.3% 50.0% 100.0% boost::corosio::native_tcp_acceptor<boost::corosio::select_t{}>::accept(boost::corosio::tcp_socket&) :270 12x 100.0% 100.0% 100.0% boost::corosio::native_tcp_acceptor<boost::corosio::kqueue_t{}>::accept() :293 5x 100.0% – 100.0% boost::corosio::native_tcp_acceptor<boost::corosio::select_t{}>::accept() :293 5x 100.0% 100.0% 100.0% boost::corosio::native_tcp_acceptor<boost::corosio::kqueue_t{}>::wait(boost::corosio::wait_type) :310 3x 100.0% – 100.0% boost::corosio::native_tcp_acceptor<boost::corosio::select_t{}>::wait(boost::corosio::wait_type) :310 3x 100.0% – 100.0%
Line Branch TLA Hits Source Code
1 //
2 // Copyright (c) 2026 Steve Gerbino
3 // Copyright (c) 2026 Michael Vandeberg
4 //
5 // Distributed under the Boost Software License, Version 1.0. (See accompanying
6 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
7 //
8 // Official repository: https://github.com/cppalliance/corosio
9 //
10
11 #ifndef BOOST_COROSIO_NATIVE_NATIVE_TCP_ACCEPTOR_HPP
12 #define BOOST_COROSIO_NATIVE_NATIVE_TCP_ACCEPTOR_HPP
13
14 #include <boost/corosio/tcp_acceptor.hpp>
15 #include <boost/corosio/backend.hpp>
16 #include <boost/corosio/detail/op_base.hpp>
17
18 #ifndef BOOST_COROSIO_MRDOCS
19 #if BOOST_COROSIO_HAS_EPOLL
20 #include <boost/corosio/native/detail/epoll/epoll_types.hpp>
21 #endif
22
23 #if BOOST_COROSIO_HAS_SELECT
24 #include <boost/corosio/native/detail/select/select_types.hpp>
25 #endif
26
27 #if BOOST_COROSIO_HAS_KQUEUE
28 #include <boost/corosio/native/detail/kqueue/kqueue_types.hpp>
29 #endif
30
31 #if BOOST_COROSIO_HAS_IOCP
32 #include <boost/corosio/native/detail/iocp/win_tcp_acceptor_service.hpp>
33 #endif
34
35 #if BOOST_COROSIO_HAS_URING
36 #include <boost/corosio/native/detail/uring/uring_types.hpp>
37 #endif
38 #endif // !BOOST_COROSIO_MRDOCS
39
40 namespace boost::corosio {
41
42 /** Accepts TCP connections, calling the backend directly.
43
44 This class template inherits from @ref tcp_acceptor. It shadows the
45 `accept` operation with a version that calls the backend
46 implementation directly. The compiler can then inline through the
47 entire call chain.
48
49 Non-async operations (`listen`, `close`, `cancel`) remain
50 unchanged and dispatch through the compiled library.
51
52 A `native_tcp_acceptor` IS-A `tcp_acceptor` and can be passed
53 to any function expecting `tcp_acceptor&`.
54
55 @tparam Backend A backend tag value (e.g., `epoll`).
56
57 @par Thread Safety
58 Same as @ref tcp_acceptor.
59
60 @see @ref tcp_acceptor, @ref epoll_t, @ref iocp_t
61 */
62 template<auto Backend>
63 class native_tcp_acceptor : public tcp_acceptor
64 {
65 using backend_type = decltype(Backend);
66 using impl_type = typename backend_type::tcp_acceptor_type;
67 using service_type = typename backend_type::tcp_acceptor_service_type;
68
69 29x impl_type& get_impl() noexcept
70 {
71 29x return *static_cast<impl_type*>(h_.get());
72 }
73
74 struct native_wait_awaitable : detail::void_op_base<native_wait_awaitable>
75 {
76 native_tcp_acceptor& acc_;
77 wait_type w_;
78
79 12x native_wait_awaitable(native_tcp_acceptor& acc, wait_type w) noexcept
80 6x : acc_(acc)
81 6x , w_(w)
82 6x {
83 12x }
84
85 std::coroutine_handle<>
86 4x dispatch(capy::continuation& cont, capy::executor_ref ex) const
87 {
88
2/4
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
4x return acc_.get_impl().wait(cont, ex, w_, this->token_, &this->ec_);
89 ✗ }
90 };
91
92 struct native_accept_awaitable
93 : detail::void_op_base<native_accept_awaitable>
94 {
95 native_tcp_acceptor& acc_;
96 tcp_socket& peer_;
97 25x mutable io_object::implementation* peer_impl_ = nullptr;
98
99 50x native_accept_awaitable(
100 native_tcp_acceptor& acc, tcp_socket& peer) noexcept
101 25x : acc_(acc)
102 25x , peer_(peer)
103 25x {
104 50x }
105
106 // A peer accepted for an awaiter that never resumed is closed
107 // here, or nothing would own it.
108 150x ~native_accept_awaitable()
109 75x {
110
4/4
✓ Branch 0 taken 38 times.
✓ Branch 1 taken 1 time.
✓ Branch 2 taken 35 times.
✓ Branch 3 taken 1 time.
75x if (peer_impl_)
111 2x discard_peer(acc_, peer_impl_);
112 150x }
113
114 23x [[nodiscard]] capy::results<> await_resume() const noexcept
115 {
116
4/4
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 10 times.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 9 times.
23x if (!this->ec_)
117 19x acc_.reset_peer_impl(peer_, std::exchange(peer_impl_, nullptr));
118 23x return {this->ec_};
119 }
120
121 std::coroutine_handle<>
122 21x dispatch(capy::continuation& cont, capy::executor_ref ex) const
123 {
124
4/8
✓ Branch 0 taken 11 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 11 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 10 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 10 times.
✗ Branch 7 not taken.
42x return acc_.get_impl().accept(
125 21x cont, ex, this->token_, &this->ec_, &peer_impl_);
126 ✗ }
127 };
128
129 struct native_accept_value_awaitable
130 : detail::void_op_base<native_accept_value_awaitable>
131 {
132 native_tcp_acceptor& acc_;
133 10x mutable io_object::implementation* peer_impl_ = nullptr;
134
135 20x explicit native_accept_value_awaitable(
136 native_tcp_acceptor& acc) noexcept
137 10x : acc_(acc)
138 10x {
139 20x }
140
141 // A peer accepted for an awaiter that never resumed is closed
142 // here, or nothing would own it.
143 60x ~native_accept_value_awaitable()
144 30x {
145
4/4
✓ Branch 0 taken 14 times.
✓ Branch 1 taken 1 time.
✓ Branch 2 taken 14 times.
✓ Branch 3 taken 1 time.
30x if (peer_impl_)
146 2x discard_peer(acc_, peer_impl_);
147 60x }
148
149 8x [[nodiscard]] capy::results<tcp_socket> await_resume() noexcept
150 {
151 8x return take_peer(acc_, this->ec_, peer_impl_);
152 }
153
154 std::coroutine_handle<>
155 4x dispatch(capy::continuation& cont, capy::executor_ref ex) const
156 {
157
4/8
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 2 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 2 times.
✗ Branch 7 not taken.
8x return acc_.get_impl().accept(
158 4x cont, ex, this->token_, &this->ec_, &peer_impl_);
159 ✗ }
160 };
161
162 public:
163 /** Construct a native acceptor from an execution context.
164
165 @param ctx The execution context that owns this acceptor.
166 */
167 86x explicit native_tcp_acceptor(capy::execution_context& ctx)
168 43x : tcp_acceptor(handle(ctx, ctx.use_service<service_type>()))
169 86x {
170 86x }
171
172 /** Construct a native acceptor from an executor.
173
174 @param ex The executor whose context owns the acceptor.
175
176 @tparam Ex A type satisfying @ref capy::Executor. Must not
177 be `native_tcp_acceptor` itself (disables implicit
178 conversion from move).
179 */
180 template<class Ex>
181 requires(!std::same_as<std::remove_cvref_t<Ex>, native_tcp_acceptor>) &&
182 capy::Executor<Ex>
183 explicit native_tcp_acceptor(Ex const& ex)
184 : native_tcp_acceptor(ex.context())
185 {
186 }
187
188 /** Construct a native acceptor that is open, bound, and listening.
189
190 Creates a fully bound listening acceptor in a single
191 expression, throwing the codes the piecewise `open()` +
192 `set_option()` + `bind()` + `listen()` path reports. The
193 address family is deduced from @p ep, and address reuse is
194 configured as by the @ref tcp_acceptor convenience
195 constructor.
196
197 @param ctx The execution context that owns this acceptor.
198 @param ep The local endpoint to bind to.
199 @param backlog The maximum pending connection queue length.
200
201 @throws std::system_error on open, configuration, bind, or
202 listen failure.
203 */
204 16x native_tcp_acceptor(
205 capy::execution_context& ctx, endpoint ep, int backlog = 128)
206
4/4
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 1 time.
✓ Branch 2 taken 3 times.
✓ Branch 3 taken 1 time.
8x : tcp_acceptor(
207 8x handle(ctx, ctx.use_service<service_type>()), ep, backlog)
208 14x {
209 16x }
210
211 /** Construct a native acceptor that is open, bound, and listening.
212
213 @param ex The executor whose context owns the acceptor.
214 @param ep The local endpoint to bind to.
215 @param backlog The maximum pending connection queue length.
216
217 @tparam Ex A type satisfying @ref capy::Executor.
218
219 @throws std::system_error on open, configuration, bind, or
220 listen failure.
221 */
222 template<class Ex>
223 requires capy::Executor<Ex>
224 2x native_tcp_acceptor(Ex const& ex, endpoint ep, int backlog = 128)
225 2x : native_tcp_acceptor(ex.context(), ep, backlog)
226 {
227 2x }
228
229 /** Move construct.
230
231 @param other The acceptor to move from.
232
233 @pre No awaitables returned by @p other's methods exist.
234 @pre The execution context associated with @p other must
235 outlive this acceptor.
236 */
237 8x native_tcp_acceptor(native_tcp_acceptor&&) noexcept = default;
238
239 /** Move assign.
240
241 @param other The acceptor to move from.
242
243 @pre No awaitables returned by either `*this` or @p other's
244 methods exist.
245 @pre The execution context associated with @p other must
246 outlive this acceptor.
247 */
248 native_tcp_acceptor& operator=(native_tcp_acceptor&&) noexcept = default;
249
250 /// Copy construction is disabled; the handle is uniquely owned.
251 native_tcp_acceptor(native_tcp_acceptor const&) = delete;
252 /// Copy assignment is disabled; the handle is uniquely owned.
253 native_tcp_acceptor& operator=(native_tcp_acceptor const&) = delete;
254
255 /** Asynchronously accept an incoming connection.
256
257 Calls the backend implementation directly, bypassing virtual
258 dispatch. Otherwise identical to @ref tcp_acceptor::accept.
259
260 @param peer The socket to receive the accepted connection.
261
262 @return An awaitable yielding `results<>`.
263
264 A closed or moved-from acceptor reports
265 `errc::bad_file_descriptor`.
266
267 Both this acceptor and @p peer must outlive the returned
268 awaitable.
269 */
270 25x [[nodiscard]] auto accept(tcp_socket& peer)
271 {
272 25x native_accept_awaitable aw(*this, peer);
273
4/4
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 1 time.
✓ Branch 2 taken 11 times.
✓ Branch 3 taken 1 time.
25x if (!is_open())
274 2x aw.ec_ = make_error_code(std::errc::bad_file_descriptor);
275 25x return aw;
276 25x }
277
278 /** Asynchronously accept an incoming connection, returning the peer.
279
280 Calls the backend implementation directly, bypassing virtual
281 dispatch. Otherwise identical to @ref tcp_acceptor::accept().
282
283 @return An awaitable yielding `results<tcp_socket>`.
284
285 A closed or moved-from acceptor reports
286 `errc::bad_file_descriptor`.
287 On failure the returned socket is default-constructed and not
288 open. It has no context, so it may only be destroyed, assigned,
289 or checked with `is_open()`.
290
291 This acceptor must outlive the returned awaitable.
292 */
293 10x [[nodiscard]] auto accept()
294 {
295 10x native_accept_value_awaitable aw(*this);
296
4/4
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 3 times.
✓ Branch 3 taken 2 times.
10x if (!is_open())
297 4x aw.ec_ = make_error_code(std::errc::bad_file_descriptor);
298 10x return aw;
299 10x }
300
301 /** Asynchronously wait for the acceptor to be ready.
302
303 Calls the backend implementation directly, bypassing virtual
304 dispatch. Otherwise identical to @ref tcp_acceptor::wait.
305
306 @param w The wait direction (typically `wait_type::read`).
307
308 @return An awaitable yielding `results<>`.
309 */
310 6x [[nodiscard]] auto wait(wait_type w)
311 {
312 6x return native_wait_awaitable(*this, w);
313 }
314 };
315
316 } // namespace boost::corosio
317
318 #endif
319