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 local_stream_socket, epoll_t, 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 : public:
169 : /** Construct a native socket from an execution context.
170 :
171 : @param ctx The execution context that owns this socket.
172 : */
173 40 : explicit native_local_stream_socket(capy::execution_context& ctx)
174 40 : : io_object(handle(ctx, ctx.use_service<service_type>()))
175 : {
176 40 : }
177 :
178 : /** Construct a native socket from an executor.
179 :
180 : @param ex The executor whose context owns the socket.
181 : */
182 : template<class Ex>
183 : requires(!std::same_as<
184 : std::remove_cvref_t<Ex>,
185 : native_local_stream_socket>) &&
186 : capy::Executor<Ex>
187 : explicit native_local_stream_socket(Ex const& ex)
188 : : native_local_stream_socket(ex.context())
189 : {
190 : }
191 :
192 : /// Move construct.
193 6 : native_local_stream_socket(native_local_stream_socket&&) noexcept = default;
194 :
195 : /// Move assign.
196 : native_local_stream_socket&
197 : operator=(native_local_stream_socket&&) noexcept = default;
198 :
199 : /// Copy construction is disabled; the handle is uniquely owned.
200 : native_local_stream_socket(native_local_stream_socket const&) = delete;
201 : /// Copy assignment is disabled; the handle is uniquely owned.
202 : native_local_stream_socket&
203 : operator=(native_local_stream_socket const&) = delete;
204 :
205 : /** Asynchronously read data from the socket.
206 :
207 : Calls the backend implementation directly, bypassing virtual
208 : dispatch. Otherwise identical to @ref io_stream::read_some.
209 :
210 : @param buffers The buffer sequence to read into.
211 :
212 : @return An awaitable yielding `(error_code, std::size_t)`.
213 : */
214 : template<capy::MutableBufferSequence MB>
215 8 : [[nodiscard]] auto read_some(MB const& buffers)
216 : {
217 8 : return native_read_awaitable<MB>(*this, buffers);
218 : }
219 :
220 : /** Asynchronously write data to the socket.
221 :
222 : Calls the backend implementation directly, bypassing virtual
223 : dispatch. Otherwise identical to @ref io_stream::write_some.
224 :
225 : @param buffers The buffer sequence to write from.
226 :
227 : @return An awaitable yielding `(error_code, std::size_t)`.
228 : */
229 : template<capy::ConstBufferSequence CB>
230 8 : [[nodiscard]] auto write_some(CB const& buffers)
231 : {
232 8 : return native_write_awaitable<CB>(*this, buffers);
233 : }
234 :
235 : /** Asynchronously connect to a remote endpoint.
236 :
237 : Calls the backend implementation directly, bypassing virtual
238 : dispatch. Otherwise identical to @ref local_stream_socket::connect.
239 :
240 : If the socket is not already open, it is opened automatically.
241 :
242 : @param ep The local endpoint (path) to connect to.
243 :
244 : @return An awaitable yielding `results<>`.
245 :
246 : If the socket needs to be opened and the open fails, the
247 : awaitable completes immediately with that error.
248 : */
249 12 : [[nodiscard]] auto connect(corosio::local_endpoint ep)
250 : {
251 12 : native_connect_awaitable aw(*this, ep);
252 12 : if (!is_open())
253 10 : aw.ec_ = open();
254 12 : return aw;
255 : }
256 :
257 : /** Asynchronously wait for the socket to be ready.
258 :
259 : Calls the backend implementation directly, bypassing virtual
260 : dispatch. Otherwise identical to @ref local_stream_socket::wait.
261 :
262 : @param w The wait direction (read, write, or error).
263 :
264 : @return An awaitable yielding `results<>`.
265 : */
266 6 : [[nodiscard]] auto wait(wait_type w)
267 : {
268 6 : return native_wait_awaitable(*this, w);
269 : }
270 : };
271 :
272 : } // namespace boost::corosio
273 :
274 : #endif // BOOST_COROSIO_NATIVE_NATIVE_LOCAL_STREAM_SOCKET_HPP
|