include/boost/corosio/native/native_tcp_socket.hpp

100.0% Lines (73/0/73) 100.0% List of functions (46/0/46)
native_tcp_socket.hpp
f(x) Functions (46)
Function Calls Lines Blocks
boost::corosio::native_tcp_socket<boost::corosio::epoll_t{}>::get_impl() :74 25x 100.0% 100.0% boost::corosio::native_tcp_socket<boost::corosio::select_t{}>::get_impl() :74 24x 100.0% 100.0% boost::corosio::native_tcp_socket<boost::corosio::epoll_t{}>::native_read_awaitable<boost::capy::mutable_buffer>::native_read_awaitable(boost::corosio::native_tcp_socket<boost::corosio::epoll_t{}>&, boost::capy::mutable_buffer) :88 5x 100.0% 100.0% boost::corosio::native_tcp_socket<boost::corosio::select_t{}>::native_read_awaitable<boost::capy::mutable_buffer>::native_read_awaitable(boost::corosio::native_tcp_socket<boost::corosio::select_t{}>&, boost::capy::mutable_buffer) :88 5x 100.0% 100.0% boost::corosio::native_tcp_socket<boost::corosio::epoll_t{}>::native_read_awaitable<boost::capy::mutable_buffer>::await_ready() const :95 5x 100.0% 88.0% boost::corosio::native_tcp_socket<boost::corosio::select_t{}>::native_read_awaitable<boost::capy::mutable_buffer>::await_ready() const :95 5x 100.0% 88.0% boost::corosio::native_tcp_socket<boost::corosio::epoll_t{}>::native_read_awaitable<boost::capy::mutable_buffer>::await_resume() const :102 5x 100.0% 86.0% boost::corosio::native_tcp_socket<boost::corosio::select_t{}>::native_read_awaitable<boost::capy::mutable_buffer>::await_resume() const :102 5x 100.0% 86.0% boost::corosio::native_tcp_socket<boost::corosio::epoll_t{}>::native_read_awaitable<boost::capy::mutable_buffer>::await_suspend(std::__n4861::coroutine_handle<void>, boost::capy::io_env const*) :109 5x 100.0% 77.0% boost::corosio::native_tcp_socket<boost::corosio::select_t{}>::native_read_awaitable<boost::capy::mutable_buffer>::await_suspend(std::__n4861::coroutine_handle<void>, boost::capy::io_env const*) :109 5x 100.0% 77.0% boost::corosio::native_tcp_socket<boost::corosio::epoll_t{}>::native_write_awaitable<boost::capy::const_buffer>::native_write_awaitable(boost::corosio::native_tcp_socket<boost::corosio::epoll_t{}>&, boost::capy::const_buffer) :127 6x 100.0% 100.0% boost::corosio::native_tcp_socket<boost::corosio::select_t{}>::native_write_awaitable<boost::capy::const_buffer>::native_write_awaitable(boost::corosio::native_tcp_socket<boost::corosio::select_t{}>&, boost::capy::const_buffer) :127 6x 100.0% 100.0% boost::corosio::native_tcp_socket<boost::corosio::epoll_t{}>::native_write_awaitable<boost::capy::const_buffer>::await_ready() const :134 6x 100.0% 88.0% boost::corosio::native_tcp_socket<boost::corosio::select_t{}>::native_write_awaitable<boost::capy::const_buffer>::await_ready() const :134 6x 100.0% 88.0% boost::corosio::native_tcp_socket<boost::corosio::epoll_t{}>::native_write_awaitable<boost::capy::const_buffer>::await_resume() const :141 6x 100.0% 100.0% boost::corosio::native_tcp_socket<boost::corosio::select_t{}>::native_write_awaitable<boost::capy::const_buffer>::await_resume() const :141 6x 100.0% 100.0% boost::corosio::native_tcp_socket<boost::corosio::epoll_t{}>::native_write_awaitable<boost::capy::const_buffer>::await_suspend(std::__n4861::coroutine_handle<void>, boost::capy::io_env const*) :148 6x 100.0% 77.0% boost::corosio::native_tcp_socket<boost::corosio::select_t{}>::native_write_awaitable<boost::capy::const_buffer>::await_suspend(std::__n4861::coroutine_handle<void>, boost::capy::io_env const*) :148 6x 100.0% 77.0% boost::corosio::native_tcp_socket<boost::corosio::epoll_t{}>::native_wait_awaitable::native_wait_awaitable(boost::corosio::native_tcp_socket<boost::corosio::epoll_t{}>&, boost::corosio::wait_type) :164 3x 100.0% 100.0% boost::corosio::native_tcp_socket<boost::corosio::select_t{}>::native_wait_awaitable::native_wait_awaitable(boost::corosio::native_tcp_socket<boost::corosio::select_t{}>&, boost::corosio::wait_type) :164 3x 100.0% 100.0% boost::corosio::native_tcp_socket<boost::corosio::epoll_t{}>::native_wait_awaitable::await_ready() const :170 3x 100.0% 88.0% boost::corosio::native_tcp_socket<boost::corosio::select_t{}>::native_wait_awaitable::await_ready() const :170 3x 100.0% 88.0% boost::corosio::native_tcp_socket<boost::corosio::epoll_t{}>::native_wait_awaitable::await_resume() const :177 3x 100.0% 86.0% boost::corosio::native_tcp_socket<boost::corosio::select_t{}>::native_wait_awaitable::await_resume() const :177 3x 100.0% 86.0% boost::corosio::native_tcp_socket<boost::corosio::epoll_t{}>::native_wait_awaitable::await_suspend(std::__n4861::coroutine_handle<void>, boost::capy::io_env const*) :184 3x 100.0% 82.0% boost::corosio::native_tcp_socket<boost::corosio::select_t{}>::native_wait_awaitable::await_suspend(std::__n4861::coroutine_handle<void>, boost::capy::io_env const*) :184 3x 100.0% 82.0% boost::corosio::native_tcp_socket<boost::corosio::epoll_t{}>::native_connect_awaitable::native_connect_awaitable(boost::corosio::native_tcp_socket<boost::corosio::epoll_t{}>&, boost::corosio::endpoint) :199 11x 100.0% 100.0% boost::corosio::native_tcp_socket<boost::corosio::select_t{}>::native_connect_awaitable::native_connect_awaitable(boost::corosio::native_tcp_socket<boost::corosio::select_t{}>&, boost::corosio::endpoint) :199 10x 100.0% 100.0% boost::corosio::native_tcp_socket<boost::corosio::epoll_t{}>::native_connect_awaitable::await_ready() const :205 11x 100.0% 88.0% boost::corosio::native_tcp_socket<boost::corosio::select_t{}>::native_connect_awaitable::await_ready() const :205 10x 100.0% 88.0% boost::corosio::native_tcp_socket<boost::corosio::epoll_t{}>::native_connect_awaitable::await_resume() const :212 11x 100.0% 100.0% boost::corosio::native_tcp_socket<boost::corosio::select_t{}>::native_connect_awaitable::await_resume() const :212 10x 100.0% 100.0% boost::corosio::native_tcp_socket<boost::corosio::epoll_t{}>::native_connect_awaitable::await_suspend(std::__n4861::coroutine_handle<void>, boost::capy::io_env const*) :219 11x 100.0% 82.0% boost::corosio::native_tcp_socket<boost::corosio::select_t{}>::native_connect_awaitable::await_suspend(std::__n4861::coroutine_handle<void>, boost::capy::io_env const*) :219 10x 100.0% 82.0% boost::corosio::native_tcp_socket<boost::corosio::epoll_t{}>::native_tcp_socket(boost::capy::execution_context&) :233 24x 100.0% 100.0% boost::corosio::native_tcp_socket<boost::corosio::select_t{}>::native_tcp_socket(boost::capy::execution_context&) :233 21x 100.0% 100.0% boost::corosio::native_tcp_socket<boost::corosio::epoll_t{}>::native_tcp_socket(boost::corosio::native_tcp_socket<boost::corosio::epoll_t{}>&&) :259 13x 100.0% 100.0% boost::corosio::native_tcp_socket<boost::corosio::select_t{}>::native_tcp_socket(boost::corosio::native_tcp_socket<boost::corosio::select_t{}>&&) :259 11x 100.0% 100.0% boost::corosio::native_tcp_socket<boost::corosio::epoll_t{}>::operator=(boost::corosio::native_tcp_socket<boost::corosio::epoll_t{}>&&) :272 2x 100.0% 100.0% boost::corosio::native_tcp_socket<boost::corosio::select_t{}>::operator=(boost::corosio::native_tcp_socket<boost::corosio::select_t{}>&&) :272 1x 100.0% 100.0% auto boost::corosio::native_tcp_socket<boost::corosio::epoll_t{}>::read_some<boost::capy::mutable_buffer>(boost::capy::mutable_buffer const&) :291 5x 100.0% 100.0% auto boost::corosio::native_tcp_socket<boost::corosio::select_t{}>::read_some<boost::capy::mutable_buffer>(boost::capy::mutable_buffer const&) :291 5x 100.0% 100.0% auto boost::corosio::native_tcp_socket<boost::corosio::epoll_t{}>::write_some<boost::capy::const_buffer>(boost::capy::const_buffer const&) :310 6x 100.0% 100.0% auto boost::corosio::native_tcp_socket<boost::corosio::select_t{}>::write_some<boost::capy::const_buffer>(boost::capy::const_buffer const&) :310 6x 100.0% 100.0% boost::corosio::native_tcp_socket<boost::corosio::epoll_t{}>::connect(boost::corosio::endpoint) :330 6x 100.0% 90.0% boost::corosio::native_tcp_socket<boost::corosio::select_t{}>::connect(boost::corosio::endpoint) :330 5x 100.0% 90.0%
Line TLA Hits 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
17 #ifndef BOOST_COROSIO_MRDOCS
18 #if BOOST_COROSIO_HAS_EPOLL
19 #include <boost/corosio/native/detail/epoll/epoll_types.hpp>
20 #endif
21
22 #if BOOST_COROSIO_HAS_SELECT
23 #include <boost/corosio/native/detail/select/select_types.hpp>
24 #endif
25
26 #if BOOST_COROSIO_HAS_KQUEUE
27 #include <boost/corosio/native/detail/kqueue/kqueue_types.hpp>
28 #endif
29
30 #if BOOST_COROSIO_HAS_IOCP
31 #include <boost/corosio/native/detail/iocp/win_tcp_acceptor_service.hpp>
32 #endif
33
34 #if BOOST_COROSIO_HAS_URING
35 #include <boost/corosio/native/detail/uring/uring_types.hpp>
36 #endif
37 #endif // !BOOST_COROSIO_MRDOCS
38
39 namespace boost::corosio {
40
41 /** An asynchronous TCP socket with devirtualized I/O operations.
42
43 This class template inherits from @ref tcp_socket and shadows
44 the async operations (`read_some`, `write_some`, `connect`) with
45 versions that call the backend implementation directly, allowing
46 the compiler to inline through the entire call chain.
47
48 Non-async operations (`open`, `close`, `cancel`, socket options)
49 remain unchanged and dispatch through the compiled library.
50
51 A `native_tcp_socket` IS-A `tcp_socket` and can be passed to
52 any function expecting `tcp_socket&` or `io_stream&`, in which
53 case virtual dispatch is used transparently.
54
55 @tparam Backend A backend tag value (e.g., `epoll`,
56 `iocp`) whose type provides the concrete implementation
57 types.
58
59 @par Thread Safety
60 Same as @ref tcp_socket.
61
62 @par Example
63 @par !example native_tcp_socket
64
65 @see tcp_socket, epoll_t, iocp_t
66 */
67 template<auto Backend>
68 class native_tcp_socket : public tcp_socket
69 {
70 using backend_type = decltype(Backend);
71 using impl_type = typename backend_type::tcp_socket_type;
72 using service_type = typename backend_type::tcp_service_type;
73
74 49x impl_type& get_impl() noexcept
75 {
76 49x return *static_cast<impl_type*>(h_.get());
77 }
78
79 template<class MutableBufferSequence>
80 struct native_read_awaitable
81 {
82 native_tcp_socket& self_;
83 MutableBufferSequence buffers_;
84 std::stop_token token_;
85 mutable std::error_code ec_;
86 mutable std::size_t bytes_transferred_ = 0;
87
88 10x native_read_awaitable(
89 native_tcp_socket& self, MutableBufferSequence buffers) noexcept
90 10x : self_(self)
91 10x , buffers_(std::move(buffers))
92 {
93 10x }
94
95 10x bool await_ready() const noexcept
96 {
97 // A pre-set ec_ means the initiator failed before
98 // dispatch (e.g. a closed object).
99 10x return static_cast<bool>(ec_) || token_.stop_requested();
100 }
101
102 10x [[nodiscard]] capy::io_result<std::size_t> await_resume() const noexcept
103 {
104 10x if (token_.stop_requested())
105 4x return {make_error_code(std::errc::operation_canceled), 0};
106 6x return {ec_, bytes_transferred_};
107 }
108
109 10x auto await_suspend(std::coroutine_handle<> h, capy::io_env const* env)
110 -> std::coroutine_handle<>
111 {
112 10x token_ = env->stop_token;
113 30x return self_.get_impl().read_some(
114 30x h, env->executor, buffers_, token_, &ec_, &bytes_transferred_);
115 }
116 };
117
118 template<class ConstBufferSequence>
119 struct native_write_awaitable
120 {
121 native_tcp_socket& self_;
122 ConstBufferSequence buffers_;
123 std::stop_token token_;
124 mutable std::error_code ec_;
125 mutable std::size_t bytes_transferred_ = 0;
126
127 12x native_write_awaitable(
128 native_tcp_socket& self, ConstBufferSequence buffers) noexcept
129 12x : self_(self)
130 12x , buffers_(std::move(buffers))
131 {
132 12x }
133
134 12x bool await_ready() const noexcept
135 {
136 // A pre-set ec_ means the initiator failed before
137 // dispatch (e.g. a closed object).
138 12x return static_cast<bool>(ec_) || token_.stop_requested();
139 }
140
141 12x [[nodiscard]] capy::io_result<std::size_t> await_resume() const noexcept
142 {
143 12x if (token_.stop_requested())
144 2x return {make_error_code(std::errc::operation_canceled), 0};
145 10x return {ec_, bytes_transferred_};
146 }
147
148 12x auto await_suspend(std::coroutine_handle<> h, capy::io_env const* env)
149 -> std::coroutine_handle<>
150 {
151 12x token_ = env->stop_token;
152 36x return self_.get_impl().write_some(
153 36x h, env->executor, buffers_, token_, &ec_, &bytes_transferred_);
154 }
155 };
156
157 struct native_wait_awaitable
158 {
159 native_tcp_socket& self_;
160 wait_type w_;
161 std::stop_token token_;
162 mutable std::error_code ec_;
163
164 6x native_wait_awaitable(native_tcp_socket& self, wait_type w) noexcept
165 6x : self_(self)
166 6x , w_(w)
167 {
168 6x }
169
170 6x bool await_ready() const noexcept
171 {
172 // A pre-set ec_ means the initiator failed before
173 // dispatch (e.g. a closed object).
174 6x return static_cast<bool>(ec_) || token_.stop_requested();
175 }
176
177 6x [[nodiscard]] capy::io_result<> await_resume() const noexcept
178 {
179 6x if (token_.stop_requested())
180 2x return {make_error_code(std::errc::operation_canceled)};
181 4x return {ec_};
182 }
183
184 6x auto await_suspend(std::coroutine_handle<> h, capy::io_env const* env)
185 -> std::coroutine_handle<>
186 {
187 6x token_ = env->stop_token;
188 6x return self_.get_impl().wait(h, env->executor, w_, token_, &ec_);
189 }
190 };
191
192 struct native_connect_awaitable
193 {
194 native_tcp_socket& self_;
195 endpoint endpoint_;
196 std::stop_token token_;
197 mutable std::error_code ec_;
198
199 21x native_connect_awaitable(native_tcp_socket& self, endpoint ep) noexcept
200 21x : self_(self)
201 21x , endpoint_(ep)
202 {
203 21x }
204
205 21x bool await_ready() const noexcept
206 {
207 // A pre-set ec_ means the initiator failed before
208 // dispatch (e.g. a closed object).
209 21x return static_cast<bool>(ec_) || token_.stop_requested();
210 }
211
212 21x [[nodiscard]] capy::io_result<> await_resume() const noexcept
213 {
214 21x if (token_.stop_requested())
215 2x return {make_error_code(std::errc::operation_canceled)};
216 19x return {ec_};
217 }
218
219 21x auto await_suspend(std::coroutine_handle<> h, capy::io_env const* env)
220 -> std::coroutine_handle<>
221 {
222 21x token_ = env->stop_token;
223 63x return self_.get_impl().connect(
224 63x h, env->executor, endpoint_, token_, &ec_);
225 }
226 };
227
228 public:
229 /** Construct a native socket from an execution context.
230
231 @param ctx The execution context that will own this socket.
232 */
233 45x explicit native_tcp_socket(capy::execution_context& ctx)
234 45x : io_object(create_handle<service_type>(ctx))
235 {
236 45x }
237
238 /** Construct a native socket from an executor.
239
240 @param ex The executor whose context will own the socket.
241 */
242 template<class Ex>
243 requires(!std::same_as<std::remove_cvref_t<Ex>, native_tcp_socket>) &&
244 capy::Executor<Ex>
245 explicit native_tcp_socket(Ex const& ex) : native_tcp_socket(ex.context())
246 {
247 }
248
249 /** Move construct.
250
251 @param other The socket to move from.
252
253 @pre No awaitables returned by @p other's methods exist.
254 @pre @p other is not referenced as a peer in any outstanding
255 accept awaitable.
256 @pre The execution context associated with @p other must
257 outlive this socket.
258 */
259 24x native_tcp_socket(native_tcp_socket&&) noexcept = default;
260
261 /** Move assign.
262
263 @param other The socket to move from.
264
265 @pre No awaitables returned by either `*this` or @p other's
266 methods exist.
267 @pre Neither `*this` nor @p other is referenced as a peer in
268 any outstanding accept awaitable.
269 @pre The execution context associated with @p other must
270 outlive this socket.
271 */
272 3x native_tcp_socket& operator=(native_tcp_socket&&) noexcept = default;
273
274 native_tcp_socket(native_tcp_socket const&) = delete;
275 native_tcp_socket& operator=(native_tcp_socket const&) = delete;
276
277 /** Asynchronously read data from the socket.
278
279 Calls the backend implementation directly, bypassing virtual
280 dispatch. Otherwise identical to @ref io_stream::read_some.
281
282 @param buffers The buffer sequence to read into.
283
284 @return An awaitable yielding `(error_code, std::size_t)`.
285
286 This socket must outlive the returned awaitable. The memory
287 referenced by @p buffers must remain valid until the operation
288 completes.
289 */
290 template<capy::MutableBufferSequence MB>
291 10x [[nodiscard]] auto read_some(MB const& buffers)
292 {
293 10x return native_read_awaitable<MB>(*this, buffers);
294 }
295
296 /** Asynchronously write data to the socket.
297
298 Calls the backend implementation directly, bypassing virtual
299 dispatch. Otherwise identical to @ref io_stream::write_some.
300
301 @param buffers The buffer sequence to write from.
302
303 @return An awaitable yielding `(error_code, std::size_t)`.
304
305 This socket must outlive the returned awaitable. The memory
306 referenced by @p buffers must remain valid until the operation
307 completes.
308 */
309 template<capy::ConstBufferSequence CB>
310 12x [[nodiscard]] auto write_some(CB const& buffers)
311 {
312 12x return native_write_awaitable<CB>(*this, buffers);
313 }
314
315 /** Asynchronously connect to a remote endpoint.
316
317 Calls the backend implementation directly, bypassing virtual
318 dispatch. Otherwise identical to @ref tcp_socket::connect.
319
320 If the socket is not open, it is opened automatically using
321 the protocol matching the endpoint's address family. An open
322 failure surfaces through the connect completion.
323
324 @param ep The remote endpoint to connect to.
325
326 @return An awaitable yielding `io_result<>`.
327
328 This socket must outlive the returned awaitable.
329 */
330 21x [[nodiscard]] auto connect(endpoint ep)
331 {
332 21x native_connect_awaitable aw(*this, ep);
333 21x if (!is_open())
334 2x aw.ec_ = open(ep.is_v6() ? tcp::v6() : tcp::v4());
335 21x return aw;
336 }
337
338 /** Asynchronously wait for the socket to be ready.
339
340 Calls the backend implementation directly, bypassing virtual
341 dispatch. Otherwise identical to @ref tcp_socket::wait.
342
343 @param w The wait direction (read, write, or error).
344
345 @return An awaitable yielding `io_result<>`.
346 */
347 6x [[nodiscard]] auto wait(wait_type w)
348 {
349 6x return native_wait_awaitable(*this, w);
350 }
351 };
352
353 } // namespace boost::corosio
354
355 #endif
356