include/boost/corosio/native/native_tcp_acceptor.hpp

100.0% Lines (57 / 57) 100.0% Functions (34 / 34)
native_tcp_acceptor.hpp
f(x) Functions (34)
Function Calls Lines Blocks
boost::corosio::native_tcp_acceptor<boost::corosio::epoll_t{}>::get_impl() :69 13x 100.0% 100.0% boost::corosio::native_tcp_acceptor<boost::corosio::select_t{}>::get_impl() :69 12x 100.0% 100.0% boost::corosio::native_tcp_acceptor<boost::corosio::epoll_t{}>::native_wait_awaitable::native_wait_awaitable(boost::corosio::native_tcp_acceptor<boost::corosio::epoll_t{}>&, boost::corosio::wait_type) :79 3x 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 3x 100.0% 100.0% boost::corosio::native_tcp_acceptor<boost::corosio::epoll_t{}>::native_wait_awaitable::dispatch(boost::capy::continuation&, boost::capy::executor_ref) const :86 2x 100.0% 80.0% boost::corosio::native_tcp_acceptor<boost::corosio::select_t{}>::native_wait_awaitable::dispatch(boost::capy::continuation&, boost::capy::executor_ref) const :86 2x 100.0% 80.0% boost::corosio::native_tcp_acceptor<boost::corosio::epoll_t{}>::native_accept_awaitable::native_accept_awaitable(boost::corosio::native_tcp_acceptor<boost::corosio::epoll_t{}>&, boost::corosio::tcp_socket&) :99 11x 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 10x 100.0% 100.0% boost::corosio::native_tcp_acceptor<boost::corosio::epoll_t{}>::native_accept_awaitable::~native_accept_awaitable() :108 22x 100.0% 100.0% boost::corosio::native_tcp_acceptor<boost::corosio::select_t{}>::native_accept_awaitable::~native_accept_awaitable() :108 20x 100.0% 100.0% boost::corosio::native_tcp_acceptor<boost::corosio::epoll_t{}>::native_accept_awaitable::await_resume() const :114 10x 100.0% 100.0% boost::corosio::native_tcp_acceptor<boost::corosio::select_t{}>::native_accept_awaitable::await_resume() const :114 9x 100.0% 100.0% boost::corosio::native_tcp_acceptor<boost::corosio::epoll_t{}>::native_accept_awaitable::dispatch(boost::capy::continuation&, boost::capy::executor_ref) const :122 9x 100.0% 80.0% boost::corosio::native_tcp_acceptor<boost::corosio::select_t{}>::native_accept_awaitable::dispatch(boost::capy::continuation&, boost::capy::executor_ref) const :122 8x 100.0% 80.0% boost::corosio::native_tcp_acceptor<boost::corosio::epoll_t{}>::native_accept_value_awaitable::native_accept_value_awaitable(boost::corosio::native_tcp_acceptor<boost::corosio::epoll_t{}>&) :135 5x 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 5x 100.0% 100.0% boost::corosio::native_tcp_acceptor<boost::corosio::epoll_t{}>::native_accept_value_awaitable::~native_accept_value_awaitable() :143 10x 100.0% 100.0% boost::corosio::native_tcp_acceptor<boost::corosio::select_t{}>::native_accept_value_awaitable::~native_accept_value_awaitable() :143 10x 100.0% 100.0% boost::corosio::native_tcp_acceptor<boost::corosio::epoll_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::epoll_t{}>::native_accept_value_awaitable::dispatch(boost::capy::continuation&, boost::capy::executor_ref) const :155 2x 100.0% 80.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 100.0% 80.0% boost::corosio::native_tcp_acceptor<boost::corosio::epoll_t{}>::native_tcp_acceptor(boost::capy::execution_context&) :167 20x 100.0% 100.0% boost::corosio::native_tcp_acceptor<boost::corosio::select_t{}>::native_tcp_acceptor(boost::capy::execution_context&) :167 19x 100.0% 100.0% boost::corosio::native_tcp_acceptor<boost::corosio::epoll_t{}>::native_tcp_acceptor(boost::capy::execution_context&, boost::corosio::endpoint, int) :204 4x 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 4x 100.0% 100.0% boost::corosio::native_tcp_acceptor<boost::corosio::epoll_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::epoll_t{}>::native_tcp_acceptor(boost::corosio::native_tcp_acceptor<boost::corosio::epoll_t{}>&&) :237 2x 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 2x 100.0% 100.0% boost::corosio::native_tcp_acceptor<boost::corosio::epoll_t{}>::accept(boost::corosio::tcp_socket&) :270 7x 100.0% 100.0% boost::corosio::native_tcp_acceptor<boost::corosio::select_t{}>::accept(boost::corosio::tcp_socket&) :270 6x 100.0% 100.0% boost::corosio::native_tcp_acceptor<boost::corosio::epoll_t{}>::accept() :293 5x 100.0% 100.0% boost::corosio::native_tcp_acceptor<boost::corosio::select_t{}>::accept() :293 5x 100.0% 100.0%
Line 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 25x impl_type& get_impl() noexcept
70 {
71 25x 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 6x native_wait_awaitable(native_tcp_acceptor& acc, wait_type w) noexcept
80 6x : acc_(acc)
81 6x , w_(w)
82 {
83 6x }
84
85 std::coroutine_handle<>
86 4x dispatch(capy::continuation& cont, capy::executor_ref ex) const
87 {
88 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 mutable io_object::implementation* peer_impl_ = nullptr;
98
99 21x native_accept_awaitable(
100 native_tcp_acceptor& acc, tcp_socket& peer) noexcept
101 21x : acc_(acc)
102 21x , peer_(peer)
103 {
104 21x }
105
106 // A peer accepted for an awaiter that never resumed is closed
107 // here, or nothing would own it.
108 42x ~native_accept_awaitable()
109 {
110 42x if (peer_impl_)
111 2x discard_peer(acc_, peer_impl_);
112 42x }
113
114 19x [[nodiscard]] capy::results<> await_resume() const noexcept
115 {
116 19x if (!this->ec_)
117 15x acc_.reset_peer_impl(peer_, std::exchange(peer_impl_, nullptr));
118 19x return {this->ec_};
119 }
120
121 std::coroutine_handle<>
122 17x dispatch(capy::continuation& cont, capy::executor_ref ex) const
123 {
124 51x return acc_.get_impl().accept(
125 51x 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 mutable io_object::implementation* peer_impl_ = nullptr;
134
135 10x explicit native_accept_value_awaitable(
136 native_tcp_acceptor& acc) noexcept
137 10x : acc_(acc)
138 {
139 10x }
140
141 // A peer accepted for an awaiter that never resumed is closed
142 // here, or nothing would own it.
143 20x ~native_accept_value_awaitable()
144 {
145 20x if (peer_impl_)
146 2x discard_peer(acc_, peer_impl_);
147 20x }
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 12x return acc_.get_impl().accept(
158 12x 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 39x explicit native_tcp_acceptor(capy::execution_context& ctx)
168 39x : tcp_acceptor(handle(ctx, ctx.use_service<service_type>()))
169 {
170 39x }
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 8x native_tcp_acceptor(
205 capy::execution_context& ctx, endpoint ep, int backlog = 128)
206 : tcp_acceptor(
207 8x handle(ctx, ctx.use_service<service_type>()), ep, backlog)
208 {
209 6x }
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 4x 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 21x [[nodiscard]] auto accept(tcp_socket& peer)
271 {
272 21x native_accept_awaitable aw(*this, peer);
273 21x if (!is_open())
274 2x aw.ec_ = make_error_code(std::errc::bad_file_descriptor);
275 21x return aw;
276 }
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 10x if (!is_open())
297 4x aw.ec_ = make_error_code(std::errc::bad_file_descriptor);
298 10x return aw;
299 }
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