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_TCP_SOCKET_HPP
12 : #define BOOST_COROSIO_NATIVE_NATIVE_TCP_SOCKET_HPP
13 :
14 : #include <boost/corosio/tcp_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_IOCP
32 : #include <boost/corosio/native/detail/iocp/win_tcp_acceptor_service.hpp>
33 : #endif
34 :
35 : #if BOOST_COROSIO_HAS_URING
36 : #include <boost/corosio/native/detail/uring/uring_types.hpp>
37 : #endif
38 : #endif // !BOOST_COROSIO_MRDOCS
39 :
40 : namespace boost::corosio {
41 :
42 : /** Connects, reads, and writes over TCP, calling the backend directly.
43 :
44 : This class template inherits from @ref tcp_socket. It shadows the
45 : async operations (`read_some`, `write_some`, `connect`) with
46 : versions that call the backend implementation directly. The compiler
47 : 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_tcp_socket` IS-A `tcp_socket` and can be passed to
53 : any function expecting `tcp_socket&` or `io_stream&`. In that
54 : case, virtual dispatch is used transparently.
55 :
56 : @tparam Backend A backend tag value (e.g., `epoll`,
57 : `iocp`) whose type provides the concrete implementation
58 : types.
59 :
60 : @par Thread Safety
61 : Same as @ref tcp_socket.
62 :
63 : @par Example
64 : @par !example native_tcp_socket
65 :
66 : @see tcp_socket, epoll_t, iocp_t
67 : */
68 : template<auto Backend>
69 : class native_tcp_socket : public tcp_socket
70 : {
71 : using backend_type = decltype(Backend);
72 : using impl_type = typename backend_type::tcp_socket_type;
73 : using service_type = typename backend_type::tcp_service_type;
74 :
75 HIT 51 : impl_type& get_impl() noexcept
76 : {
77 51 : 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_tcp_socket& self_;
85 : MutableBufferSequence buffers_;
86 :
87 14 : native_read_awaitable(
88 : native_tcp_socket& self, MutableBufferSequence buffers) noexcept
89 14 : : self_(self)
90 14 : , buffers_(std::move(buffers))
91 : {
92 14 : }
93 :
94 : std::coroutine_handle<>
95 10 : dispatch(capy::continuation& cont, capy::executor_ref ex) const
96 : {
97 30 : return self_.get_impl().read_some(
98 30 : cont, ex, buffers_, this->token_, &this->ec_, &this->bytes_);
99 : }
100 : };
101 :
102 : template<class ConstBufferSequence>
103 : struct native_write_awaitable
104 : : detail::bytes_op_base<native_write_awaitable<ConstBufferSequence>>
105 : {
106 : native_tcp_socket& self_;
107 : ConstBufferSequence buffers_;
108 :
109 14 : native_write_awaitable(
110 : native_tcp_socket& self, ConstBufferSequence buffers) noexcept
111 14 : : self_(self)
112 14 : , buffers_(std::move(buffers))
113 : {
114 14 : }
115 :
116 : std::coroutine_handle<>
117 12 : dispatch(capy::continuation& cont, capy::executor_ref ex) const
118 : {
119 36 : return self_.get_impl().write_some(
120 36 : cont, ex, buffers_, this->token_, &this->ec_, &this->bytes_);
121 : }
122 : };
123 :
124 : struct native_wait_awaitable : detail::void_op_base<native_wait_awaitable>
125 : {
126 : native_tcp_socket& self_;
127 : wait_type w_;
128 :
129 10 : native_wait_awaitable(native_tcp_socket& self, wait_type w) noexcept
130 10 : : self_(self)
131 10 : , w_(w)
132 : {
133 10 : }
134 :
135 : std::coroutine_handle<>
136 8 : dispatch(capy::continuation& cont, capy::executor_ref ex) const
137 : {
138 16 : return self_.get_impl().wait(
139 16 : cont, ex, w_, this->token_, &this->ec_);
140 : }
141 : };
142 :
143 : struct native_connect_awaitable
144 : : detail::void_op_base<native_connect_awaitable>
145 : {
146 : native_tcp_socket& self_;
147 : endpoint endpoint_;
148 :
149 23 : native_connect_awaitable(native_tcp_socket& self, endpoint ep) noexcept
150 23 : : self_(self)
151 23 : , endpoint_(ep)
152 : {
153 23 : }
154 :
155 : std::coroutine_handle<>
156 21 : dispatch(capy::continuation& cont, capy::executor_ref ex) const
157 : {
158 63 : return self_.get_impl().connect(
159 63 : cont, ex, endpoint_, this->token_, &this->ec_);
160 : }
161 : };
162 :
163 : public:
164 : /** Construct a native socket from an execution context.
165 :
166 : @param ctx The execution context that owns this socket.
167 : */
168 49 : explicit native_tcp_socket(capy::execution_context& ctx)
169 49 : : io_object(handle(ctx, ctx.use_service<service_type>()))
170 : {
171 49 : }
172 :
173 : /** Construct a native socket from an executor.
174 :
175 : @param ex The executor whose context owns the socket.
176 :
177 : @tparam Ex A type satisfying @ref capy::Executor. Must not
178 : be `native_tcp_socket` itself (disables implicit
179 : conversion from move).
180 : */
181 : template<class Ex>
182 : requires(!std::same_as<std::remove_cvref_t<Ex>, native_tcp_socket>) &&
183 : capy::Executor<Ex>
184 : explicit native_tcp_socket(Ex const& ex) : native_tcp_socket(ex.context())
185 : {
186 : }
187 :
188 : /** Move construct.
189 :
190 : @param other The socket to move from.
191 :
192 : @pre No awaitables returned by @p other's methods exist.
193 : @pre @p other is not referenced as a peer in any outstanding
194 : accept awaitable.
195 : @pre The execution context associated with @p other must
196 : outlive this socket.
197 : */
198 28 : native_tcp_socket(native_tcp_socket&&) noexcept = default;
199 :
200 : /** Move assign.
201 :
202 : @param other The socket to move from.
203 :
204 : @pre No awaitables returned by either `*this` or @p other's
205 : methods exist.
206 : @pre Neither `*this` nor @p other is referenced as a peer in
207 : any outstanding accept awaitable.
208 : @pre The execution context associated with @p other must
209 : outlive this socket.
210 : */
211 3 : native_tcp_socket& operator=(native_tcp_socket&&) noexcept = default;
212 :
213 : /// Copy construction is disabled; the handle is uniquely owned.
214 : native_tcp_socket(native_tcp_socket const&) = delete;
215 : /// Copy assignment is disabled; the handle is uniquely owned.
216 : native_tcp_socket& operator=(native_tcp_socket const&) = delete;
217 :
218 : /** Asynchronously read data from the socket.
219 :
220 : Calls the backend implementation directly, bypassing virtual
221 : dispatch. Otherwise identical to @ref io_stream::read_some.
222 :
223 : @param buffers The buffer sequence to read into.
224 :
225 : @return An awaitable yielding `(error_code, std::size_t)`.
226 :
227 : This socket must outlive the returned awaitable. The memory
228 : referenced by @p buffers must remain valid until the operation
229 : completes.
230 : */
231 : template<capy::MutableBufferSequence MB>
232 14 : [[nodiscard]] auto read_some(MB const& buffers)
233 : {
234 14 : return native_read_awaitable<MB>(*this, buffers);
235 : }
236 :
237 : /** Asynchronously write data to the socket.
238 :
239 : Calls the backend implementation directly, bypassing virtual
240 : dispatch. Otherwise identical to @ref io_stream::write_some.
241 :
242 : @param buffers The buffer sequence to write from.
243 :
244 : @return An awaitable yielding `(error_code, std::size_t)`.
245 :
246 : This socket must outlive the returned awaitable. The memory
247 : referenced by @p buffers must remain valid until the operation
248 : completes.
249 : */
250 : template<capy::ConstBufferSequence CB>
251 14 : [[nodiscard]] auto write_some(CB const& buffers)
252 : {
253 14 : return native_write_awaitable<CB>(*this, buffers);
254 : }
255 :
256 : /** Asynchronously connect to a remote endpoint.
257 :
258 : Calls the backend implementation directly, bypassing virtual
259 : dispatch. Otherwise identical to @ref tcp_socket::connect.
260 :
261 : If the socket is not open, it is opened automatically using
262 : the protocol matching the endpoint's address family. An open
263 : failure surfaces through the connect completion.
264 :
265 : @param ep The remote endpoint to connect to.
266 :
267 : @return An awaitable yielding `results<>`.
268 :
269 : This socket must outlive the returned awaitable.
270 : */
271 23 : [[nodiscard]] auto connect(endpoint ep)
272 : {
273 23 : native_connect_awaitable aw(*this, ep);
274 23 : if (!is_open())
275 2 : aw.ec_ = open(ep.address().family());
276 23 : return aw;
277 : }
278 :
279 : /** Asynchronously wait for the socket to be ready.
280 :
281 : Calls the backend implementation directly, bypassing virtual
282 : dispatch. Otherwise identical to @ref tcp_socket::wait.
283 :
284 : @param w The wait direction (read, write, or error).
285 :
286 : @return An awaitable yielding `results<>`.
287 : */
288 10 : [[nodiscard]] auto wait(wait_type w)
289 : {
290 10 : return native_wait_awaitable(*this, w);
291 : }
292 : };
293 :
294 : } // namespace boost::corosio
295 :
296 : #endif
|