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_SOCKET_HPP
12 : #define BOOST_COROSIO_NATIVE_NATIVE_LOCAL_STREAM_SOCKET_HPP
13 :
14 : #include <boost/corosio/local_stream_socket.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_URING
32 : #include <boost/corosio/native/detail/uring/uring_types.hpp>
33 : #endif
34 :
35 : #if BOOST_COROSIO_HAS_IOCP
36 : #include <boost/corosio/native/detail/iocp/win_local_stream_acceptor_service.hpp>
37 : #endif
38 : #endif // !BOOST_COROSIO_MRDOCS
39 :
40 : namespace boost::corosio {
41 :
42 : /** Reads and writes a Unix domain stream, calling the backend directly.
43 :
44 : This class template inherits from @ref local_stream_socket. It
45 : shadows the async operations (`read_some`, `write_some`, `connect`)
46 : with versions that call the backend implementation directly. The
47 : compiler can then inline through the entire call chain.
48 :
49 : Non-async operations (`open`, `close`, `cancel`, socket options)
50 : remain unchanged and dispatch through the compiled library.
51 :
52 : A `native_local_stream_socket` IS-A `local_stream_socket` and
53 : can be passed to any function expecting `local_stream_socket&`
54 : or `io_stream&`, in which case virtual dispatch is used
55 : transparently.
56 :
57 : @tparam Backend A backend tag value (e.g., `epoll`) whose type
58 : provides the concrete implementation types.
59 :
60 : @par Thread Safety
61 : Same as @ref local_stream_socket.
62 :
63 : @par Example
64 : @par !example connect
65 :
66 : @see @ref local_stream_socket, @ref epoll_t, @ref iocp_t
67 : */
68 : template<auto Backend>
69 : class native_local_stream_socket : public local_stream_socket
70 : {
71 : using backend_type = decltype(Backend);
72 : using impl_type = typename backend_type::local_stream_socket_type;
73 : using service_type = typename backend_type::local_stream_service_type;
74 :
75 HIT 26 : impl_type& get_impl() noexcept
76 : {
77 26 : return *static_cast<impl_type*>(h_.get());
78 : }
79 :
80 : template<class MutableBufferSequence>
81 : struct native_read_awaitable
82 : : detail::bytes_op_base<native_read_awaitable<MutableBufferSequence>>
83 : {
84 : native_local_stream_socket& self_;
85 : MutableBufferSequence buffers_;
86 :
87 8 : native_read_awaitable(
88 : native_local_stream_socket& self,
89 : MutableBufferSequence buffers) noexcept
90 8 : : self_(self)
91 8 : , buffers_(std::move(buffers))
92 : {
93 8 : }
94 :
95 : std::coroutine_handle<>
96 6 : dispatch(capy::continuation& cont, capy::executor_ref ex) const
97 : {
98 18 : return self_.get_impl().read_some(
99 18 : cont, ex, buffers_, this->token_, &this->ec_, &this->bytes_);
100 : }
101 : };
102 :
103 : template<class ConstBufferSequence>
104 : struct native_write_awaitable
105 : : detail::bytes_op_base<native_write_awaitable<ConstBufferSequence>>
106 : {
107 : native_local_stream_socket& self_;
108 : ConstBufferSequence buffers_;
109 :
110 8 : native_write_awaitable(
111 : native_local_stream_socket& self,
112 : ConstBufferSequence buffers) noexcept
113 8 : : self_(self)
114 8 : , buffers_(std::move(buffers))
115 : {
116 8 : }
117 :
118 : std::coroutine_handle<>
119 6 : dispatch(capy::continuation& cont, capy::executor_ref ex) const
120 : {
121 18 : return self_.get_impl().write_some(
122 18 : cont, ex, buffers_, this->token_, &this->ec_, &this->bytes_);
123 : }
124 : };
125 :
126 : struct native_wait_awaitable : detail::void_op_base<native_wait_awaitable>
127 : {
128 : native_local_stream_socket& self_;
129 : wait_type w_;
130 :
131 6 : native_wait_awaitable(
132 : native_local_stream_socket& self, wait_type w) noexcept
133 6 : : self_(self)
134 6 : , w_(w)
135 : {
136 6 : }
137 :
138 : std::coroutine_handle<>
139 4 : dispatch(capy::continuation& cont, capy::executor_ref ex) const
140 : {
141 8 : return self_.get_impl().wait(
142 8 : cont, ex, w_, this->token_, &this->ec_);
143 : }
144 : };
145 :
146 : struct native_connect_awaitable
147 : : detail::void_op_base<native_connect_awaitable>
148 : {
149 : native_local_stream_socket& self_;
150 : corosio::local_endpoint endpoint_;
151 :
152 12 : native_connect_awaitable(
153 : native_local_stream_socket& self,
154 : corosio::local_endpoint ep) noexcept
155 12 : : self_(self)
156 12 : , endpoint_(ep)
157 : {
158 12 : }
159 :
160 : std::coroutine_handle<>
161 10 : dispatch(capy::continuation& cont, capy::executor_ref ex) const
162 : {
163 30 : return self_.get_impl().connect(
164 30 : cont, ex, endpoint_, this->token_, &this->ec_);
165 : }
166 : };
167 :
168 : // The peer a failed accept returns: it must not touch the
169 : // acceptor's context, which a moved-from acceptor lacks.
170 : template<auto>
171 : friend class native_local_stream_acceptor;
172 :
173 6 : native_local_stream_socket() noexcept = default;
174 :
175 : public:
176 : /** Construct a native socket from an execution context.
177 :
178 : @param ctx The execution context that owns this socket.
179 : */
180 36 : explicit native_local_stream_socket(capy::execution_context& ctx)
181 36 : : io_object(handle(ctx, ctx.use_service<service_type>()))
182 : {
183 36 : }
184 :
185 : /** Construct a native socket from an executor.
186 :
187 : @param ex The executor whose context owns the socket.
188 : */
189 : template<class Ex>
190 : requires(!std::same_as<
191 : std::remove_cvref_t<Ex>,
192 : native_local_stream_socket>) &&
193 : capy::Executor<Ex>
194 : explicit native_local_stream_socket(Ex const& ex)
195 : : native_local_stream_socket(ex.context())
196 : {
197 : }
198 :
199 : /// Move construct.
200 8 : native_local_stream_socket(native_local_stream_socket&&) noexcept = default;
201 :
202 : /// Move assign.
203 : native_local_stream_socket&
204 : operator=(native_local_stream_socket&&) noexcept = default;
205 :
206 : /// Copy construction is disabled; the handle is uniquely owned.
207 : native_local_stream_socket(native_local_stream_socket const&) = delete;
208 : /// Copy assignment is disabled; the handle is uniquely owned.
209 : native_local_stream_socket&
210 : operator=(native_local_stream_socket const&) = delete;
211 :
212 : /** Asynchronously read data from the socket.
213 :
214 : Calls the backend implementation directly, bypassing virtual
215 : dispatch. Otherwise identical to @ref io_stream::read_some.
216 :
217 : @param buffers The buffer sequence to read into.
218 :
219 : @return An awaitable yielding `(error_code, std::size_t)`.
220 : */
221 : template<capy::MutableBufferSequence MB>
222 8 : [[nodiscard]] auto read_some(MB const& buffers)
223 : {
224 8 : return native_read_awaitable<MB>(*this, buffers);
225 : }
226 :
227 : /** Asynchronously write data to the socket.
228 :
229 : Calls the backend implementation directly, bypassing virtual
230 : dispatch. Otherwise identical to @ref io_stream::write_some.
231 :
232 : @param buffers The buffer sequence to write from.
233 :
234 : @return An awaitable yielding `(error_code, std::size_t)`.
235 : */
236 : template<capy::ConstBufferSequence CB>
237 8 : [[nodiscard]] auto write_some(CB const& buffers)
238 : {
239 8 : return native_write_awaitable<CB>(*this, buffers);
240 : }
241 :
242 : /** Asynchronously connect to a remote endpoint.
243 :
244 : Calls the backend implementation directly, bypassing virtual
245 : dispatch. Otherwise identical to @ref local_stream_socket::connect.
246 :
247 : If the socket is not already open, it is opened automatically.
248 :
249 : @param ep The local endpoint (path) to connect to.
250 :
251 : @return An awaitable yielding `results<>`.
252 :
253 : If the socket needs to be opened and the open fails, the
254 : awaitable completes immediately with that error.
255 : */
256 12 : [[nodiscard]] auto connect(corosio::local_endpoint ep)
257 : {
258 12 : native_connect_awaitable aw(*this, ep);
259 12 : if (!is_open())
260 10 : aw.ec_ = open();
261 12 : return aw;
262 : }
263 :
264 : /** Asynchronously wait for the socket to be ready.
265 :
266 : Calls the backend implementation directly, bypassing virtual
267 : dispatch. Otherwise identical to @ref local_stream_socket::wait.
268 :
269 : @param w The wait direction (read, write, or error).
270 :
271 : @return An awaitable yielding `results<>`.
272 : */
273 6 : [[nodiscard]] auto wait(wait_type w)
274 : {
275 6 : return native_wait_awaitable(*this, w);
276 : }
277 : };
278 :
279 : } // namespace boost::corosio
280 :
281 : #endif // BOOST_COROSIO_NATIVE_NATIVE_LOCAL_STREAM_SOCKET_HPP
|