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