TLA Line data 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 HIT 21 : impl_type& get_impl() noexcept
70 : {
71 21 : 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 6 : native_wait_awaitable(native_tcp_acceptor& acc, wait_type w) noexcept
80 6 : : acc_(acc)
81 6 : , w_(w)
82 : {
83 6 : }
84 :
85 : std::coroutine_handle<>
86 4 : dispatch(capy::continuation& cont, capy::executor_ref ex) const
87 : {
88 4 : 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 19 : native_accept_awaitable(
100 : native_tcp_acceptor& acc, tcp_socket& peer) noexcept
101 19 : : acc_(acc)
102 19 : , peer_(peer)
103 : {
104 19 : }
105 :
106 19 : [[nodiscard]] capy::results<> await_resume() const noexcept
107 : {
108 19 : if (!this->ec_)
109 15 : acc_.reset_peer_impl(peer_, peer_impl_);
110 19 : return {this->ec_};
111 : }
112 :
113 : std::coroutine_handle<>
114 15 : dispatch(capy::continuation& cont, capy::executor_ref ex) const
115 : {
116 45 : return acc_.get_impl().accept(
117 45 : cont, ex, this->token_, &this->ec_, &peer_impl_);
118 : }
119 : };
120 :
121 : struct native_accept_value_awaitable
122 : : detail::void_op_base<native_accept_value_awaitable>
123 : {
124 : native_tcp_acceptor& acc_;
125 : tcp_socket peer_;
126 : mutable io_object::implementation* peer_impl_ = nullptr;
127 :
128 6 : explicit native_accept_value_awaitable(native_tcp_acceptor& acc)
129 6 : : acc_(acc)
130 6 : , peer_(acc.context())
131 : {
132 6 : }
133 :
134 6 : [[nodiscard]] capy::results<tcp_socket> await_resume() noexcept
135 : {
136 6 : if (!this->ec_ && peer_impl_)
137 2 : acc_.reset_peer_impl(peer_, peer_impl_);
138 6 : return {this->ec_, std::move(peer_)};
139 : }
140 :
141 : std::coroutine_handle<>
142 2 : dispatch(capy::continuation& cont, capy::executor_ref ex) const
143 : {
144 6 : return acc_.get_impl().accept(
145 6 : cont, ex, this->token_, &this->ec_, &peer_impl_);
146 : }
147 : };
148 :
149 : public:
150 : /** Construct a native acceptor from an execution context.
151 :
152 : @param ctx The execution context that owns this acceptor.
153 : */
154 35 : explicit native_tcp_acceptor(capy::execution_context& ctx)
155 35 : : tcp_acceptor(handle(ctx, ctx.use_service<service_type>()))
156 : {
157 35 : }
158 :
159 : /** Construct a native acceptor from an executor.
160 :
161 : @param ex The executor whose context owns the acceptor.
162 :
163 : @tparam Ex A type satisfying @ref capy::Executor. Must not
164 : be `native_tcp_acceptor` itself (disables implicit
165 : conversion from move).
166 : */
167 : template<class Ex>
168 : requires(!std::same_as<std::remove_cvref_t<Ex>, native_tcp_acceptor>) &&
169 : capy::Executor<Ex>
170 : explicit native_tcp_acceptor(Ex const& ex)
171 : : native_tcp_acceptor(ex.context())
172 : {
173 : }
174 :
175 : /** Move construct.
176 :
177 : @param other The acceptor to move from.
178 :
179 : @pre No awaitables returned by @p other's methods exist.
180 : @pre The execution context associated with @p other must
181 : outlive this acceptor.
182 : */
183 4 : native_tcp_acceptor(native_tcp_acceptor&&) noexcept = default;
184 :
185 : /** Move assign.
186 :
187 : @param other The acceptor to move from.
188 :
189 : @pre No awaitables returned by either `*this` or @p other's
190 : methods exist.
191 : @pre The execution context associated with @p other must
192 : outlive this acceptor.
193 : */
194 : native_tcp_acceptor& operator=(native_tcp_acceptor&&) noexcept = default;
195 :
196 : /// Copy construction is disabled; the handle is uniquely owned.
197 : native_tcp_acceptor(native_tcp_acceptor const&) = delete;
198 : /// Copy assignment is disabled; the handle is uniquely owned.
199 : native_tcp_acceptor& operator=(native_tcp_acceptor const&) = delete;
200 :
201 : /** Asynchronously accept an incoming connection.
202 :
203 : Calls the backend implementation directly, bypassing virtual
204 : dispatch. Otherwise identical to @ref tcp_acceptor::accept.
205 :
206 : @param peer The socket to receive the accepted connection.
207 :
208 : @return An awaitable yielding `results<>`.
209 :
210 : A closed acceptor reports `errc::bad_file_descriptor`.
211 :
212 : Both this acceptor and @p peer must outlive the returned
213 : awaitable.
214 : */
215 19 : [[nodiscard]] auto accept(tcp_socket& peer)
216 : {
217 19 : native_accept_awaitable aw(*this, peer);
218 19 : if (!is_open())
219 2 : aw.ec_ = make_error_code(std::errc::bad_file_descriptor);
220 19 : return aw;
221 : }
222 :
223 : /** Asynchronously accept an incoming connection, returning the peer.
224 :
225 : Calls the backend implementation directly, bypassing virtual
226 : dispatch. Otherwise identical to @ref tcp_acceptor::accept().
227 :
228 : @return An awaitable yielding `results<tcp_socket>`.
229 :
230 : A closed acceptor reports `errc::bad_file_descriptor`.
231 :
232 : @throws std::logic_error If the acceptor is moved-from.
233 :
234 : This acceptor must outlive the returned awaitable.
235 : */
236 8 : [[nodiscard]] auto accept()
237 : {
238 : // The awaitable builds the peer from context(), which a
239 : // moved-from acceptor no longer has.
240 8 : if (!h_)
241 2 : detail::throw_logic_error("accept: acceptor moved-from");
242 6 : native_accept_value_awaitable aw(*this);
243 6 : if (!is_open())
244 2 : aw.ec_ = make_error_code(std::errc::bad_file_descriptor);
245 6 : return aw;
246 : }
247 :
248 : /** Asynchronously wait for the acceptor to be ready.
249 :
250 : Calls the backend implementation directly, bypassing virtual
251 : dispatch. Otherwise identical to @ref tcp_acceptor::wait.
252 :
253 : @param w The wait direction (typically `wait_type::read`).
254 :
255 : @return An awaitable yielding `results<>`.
256 : */
257 6 : [[nodiscard]] auto wait(wait_type w)
258 : {
259 6 : return native_wait_awaitable(*this, w);
260 : }
261 : };
262 :
263 : } // namespace boost::corosio
264 :
265 : #endif
|