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 10 : impl_type& get_impl() noexcept
76 : {
77 10 : 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 8 : native_accept_awaitable(
107 : native_local_stream_acceptor& acc,
108 : local_stream_socket& peer) noexcept
109 8 : : acc_(acc)
110 8 : , peer_(peer)
111 : {
112 8 : }
113 :
114 8 : [[nodiscard]] capy::results<> await_resume() const noexcept
115 : {
116 8 : if (!this->ec_)
117 4 : acc_.reset_peer_impl(peer_, peer_impl_);
118 8 : return {this->ec_};
119 : }
120 :
121 : std::coroutine_handle<>
122 4 : dispatch(capy::continuation& cont, capy::executor_ref ex) const
123 : {
124 12 : return acc_.get_impl().accept(
125 12 : cont, ex, this->token_, &this->ec_, &peer_impl_);
126 : }
127 : };
128 :
129 : struct native_move_accept_awaitable
130 : : detail::void_op_base<native_move_accept_awaitable>
131 : {
132 : native_local_stream_acceptor& acc_;
133 : mutable io_object::implementation* peer_impl_ = nullptr;
134 :
135 6 : explicit native_move_accept_awaitable(
136 : native_local_stream_acceptor& acc) noexcept
137 6 : : acc_(acc)
138 : {
139 6 : }
140 :
141 : [[nodiscard]] capy::results<native_local_stream_socket<Backend>>
142 6 : await_resume() const noexcept
143 : {
144 6 : if (this->ec_ || !peer_impl_)
145 : return {
146 4 : this->ec_,
147 4 : native_local_stream_socket<Backend>(acc_.context())};
148 :
149 2 : native_local_stream_socket<Backend> peer(acc_.context());
150 2 : acc_.reset_peer_impl(peer, peer_impl_);
151 2 : return {this->ec_, std::move(peer)};
152 2 : }
153 :
154 : std::coroutine_handle<>
155 2 : dispatch(capy::continuation& cont, capy::executor_ref ex) const
156 : {
157 6 : return acc_.get_impl().accept(
158 6 : 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 18 : explicit native_local_stream_acceptor(capy::execution_context& ctx)
168 18 : : local_stream_acceptor(handle(ctx, ctx.use_service<service_type>()), ctx)
169 : {
170 18 : }
171 :
172 : /** Construct a native acceptor from an executor.
173 :
174 : @param ex The executor whose context owns the acceptor.
175 : */
176 : template<class Ex>
177 : requires(!std::same_as<
178 : std::remove_cvref_t<Ex>,
179 : native_local_stream_acceptor>) &&
180 : capy::Executor<Ex>
181 : explicit native_local_stream_acceptor(Ex const& ex)
182 : : native_local_stream_acceptor(ex.context())
183 : {
184 : }
185 :
186 : /// Move construct.
187 2 : native_local_stream_acceptor(native_local_stream_acceptor&&) noexcept =
188 : default;
189 :
190 : /// Move assign.
191 : native_local_stream_acceptor&
192 : operator=(native_local_stream_acceptor&&) noexcept = default;
193 :
194 : /// Copy construction is disabled; the handle is uniquely owned.
195 : native_local_stream_acceptor(native_local_stream_acceptor const&) = delete;
196 : /// Copy assignment is disabled; the handle is uniquely owned.
197 : native_local_stream_acceptor&
198 : operator=(native_local_stream_acceptor const&) = delete;
199 :
200 : /** Asynchronously accept an incoming connection.
201 :
202 : Calls the backend implementation directly, bypassing virtual
203 : dispatch. Otherwise identical to @ref local_stream_acceptor::accept.
204 :
205 : @param peer The socket to receive the accepted connection.
206 :
207 : @return An awaitable yielding `results<>`.
208 :
209 : A closed acceptor reports `errc::bad_file_descriptor`.
210 :
211 : Both this acceptor and @p peer must outlive the returned
212 : awaitable.
213 : */
214 8 : [[nodiscard]] auto accept(local_stream_socket& peer)
215 : {
216 8 : native_accept_awaitable aw(*this, peer);
217 8 : if (!is_open())
218 2 : aw.ec_ = make_error_code(std::errc::bad_file_descriptor);
219 8 : return aw;
220 : }
221 :
222 : /** Asynchronously accept an incoming connection, returning the peer.
223 :
224 : Calls the backend implementation directly, bypassing virtual
225 : dispatch. The accepted peer is returned as a
226 : @ref native_local_stream_socket so that subsequent I/O on it
227 : is also devirtualized.
228 :
229 : @return An awaitable yielding
230 : `results<native_local_stream_socket<Backend>>`.
231 :
232 : A closed acceptor reports `errc::bad_file_descriptor`.
233 :
234 : @throws std::logic_error If the acceptor is moved-from.
235 :
236 : This acceptor must outlive the returned awaitable.
237 : */
238 8 : [[nodiscard]] auto accept()
239 : {
240 : // The awaitable builds the peer from context(), which a
241 : // moved-from acceptor no longer has.
242 8 : if (!h_)
243 2 : detail::throw_logic_error("accept: acceptor moved-from");
244 6 : native_move_accept_awaitable aw(*this);
245 6 : if (!is_open())
246 2 : aw.ec_ = make_error_code(std::errc::bad_file_descriptor);
247 6 : return aw;
248 : }
249 :
250 : /** Asynchronously wait for the acceptor to be ready.
251 :
252 : Calls the backend implementation directly, bypassing virtual
253 : dispatch. Otherwise identical to @ref local_stream_acceptor::wait.
254 :
255 : @param w The wait direction (typically `wait_type::read`).
256 :
257 : @return An awaitable yielding `results<>`.
258 : */
259 6 : [[nodiscard]] auto wait(wait_type w)
260 : {
261 6 : return native_wait_awaitable(*this, w);
262 : }
263 : };
264 :
265 : } // namespace boost::corosio
266 :
267 : #endif // BOOST_COROSIO_NATIVE_NATIVE_LOCAL_STREAM_ACCEPTOR_HPP
|