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