include/boost/corosio/native/native_tcp_socket.hpp

100.0% Lines (74/0/74) 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) :200 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) :200 10x 100.0% 100.0% boost::corosio::native_tcp_socket<boost::corosio::epoll_t{}>::native_connect_awaitable::await_ready() const :206 11x 100.0% 88.0% boost::corosio::native_tcp_socket<boost::corosio::select_t{}>::native_connect_awaitable::await_ready() const :206 10x 100.0% 88.0% boost::corosio::native_tcp_socket<boost::corosio::epoll_t{}>::native_connect_awaitable::await_resume() const :213 11x 100.0% 100.0% boost::corosio::native_tcp_socket<boost::corosio::select_t{}>::native_connect_awaitable::await_resume() const :213 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*) :220 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*) :220 10x 100.0% 82.0% boost::corosio::native_tcp_socket<boost::corosio::epoll_t{}>::native_tcp_socket(boost::capy::execution_context&) :234 24x 100.0% 100.0% boost::corosio::native_tcp_socket<boost::corosio::select_t{}>::native_tcp_socket(boost::capy::execution_context&) :234 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{}>&&) :260 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{}>&&) :260 11x 100.0% 100.0% boost::corosio::native_tcp_socket<boost::corosio::epoll_t{}>::operator=(boost::corosio::native_tcp_socket<boost::corosio::epoll_t{}>&&) :273 2x 100.0% 100.0% boost::corosio::native_tcp_socket<boost::corosio::select_t{}>::operator=(boost::corosio::native_tcp_socket<boost::corosio::select_t{}>&&) :273 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&) :292 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&) :292 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&) :311 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&) :311 6x 100.0% 100.0% boost::corosio::native_tcp_socket<boost::corosio::epoll_t{}>::connect(boost::corosio::endpoint) :331 6x 100.0% 90.0% boost::corosio::native_tcp_socket<boost::corosio::select_t{}>::connect(boost::corosio::endpoint) :331 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_IO_URING
35 #include <boost/corosio/native/detail/io_uring/io_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 18x return self_.get_impl().wait(
189 18x h, env->executor, w_, token_, &ec_);
190 }
191 };
192
193 struct native_connect_awaitable
194 {
195 native_tcp_socket& self_;
196 endpoint endpoint_;
197 std::stop_token token_;
198 mutable std::error_code ec_;
199
200 21x native_connect_awaitable(native_tcp_socket& self, endpoint ep) noexcept
201 21x : self_(self)
202 21x , endpoint_(ep)
203 {
204 21x }
205
206 21x bool await_ready() const noexcept
207 {
208 // A pre-set ec_ means the initiator failed before
209 // dispatch (e.g. a closed object).
210 21x return static_cast<bool>(ec_) || token_.stop_requested();
211 }
212
213 21x [[nodiscard]] capy::io_result<> await_resume() const noexcept
214 {
215 21x if (token_.stop_requested())
216 2x return {make_error_code(std::errc::operation_canceled)};
217 19x return {ec_};
218 }
219
220 21x auto await_suspend(std::coroutine_handle<> h, capy::io_env const* env)
221 -> std::coroutine_handle<>
222 {
223 21x token_ = env->stop_token;
224 63x return self_.get_impl().connect(
225 63x h, env->executor, endpoint_, token_, &ec_);
226 }
227 };
228
229 public:
230 /** Construct a native socket from an execution context.
231
232 @param ctx The execution context that will own this socket.
233 */
234 45x explicit native_tcp_socket(capy::execution_context& ctx)
235 45x : io_object(create_handle<service_type>(ctx))
236 {
237 45x }
238
239 /** Construct a native socket from an executor.
240
241 @param ex The executor whose context will own the socket.
242 */
243 template<class Ex>
244 requires(!std::same_as<std::remove_cvref_t<Ex>, native_tcp_socket>) &&
245 capy::Executor<Ex>
246 explicit native_tcp_socket(Ex const& ex) : native_tcp_socket(ex.context())
247 {
248 }
249
250 /** Move construct.
251
252 @param other The socket to move from.
253
254 @pre No awaitables returned by @p other's methods exist.
255 @pre @p other is not referenced as a peer in any outstanding
256 accept awaitable.
257 @pre The execution context associated with @p other must
258 outlive this socket.
259 */
260 24x native_tcp_socket(native_tcp_socket&&) noexcept = default;
261
262 /** Move assign.
263
264 @param other The socket to move from.
265
266 @pre No awaitables returned by either `*this` or @p other's
267 methods exist.
268 @pre Neither `*this` nor @p other is referenced as a peer in
269 any outstanding accept awaitable.
270 @pre The execution context associated with @p other must
271 outlive this socket.
272 */
273 3x native_tcp_socket& operator=(native_tcp_socket&&) noexcept = default;
274
275 native_tcp_socket(native_tcp_socket const&) = delete;
276 native_tcp_socket& operator=(native_tcp_socket const&) = delete;
277
278 /** Asynchronously read data from the socket.
279
280 Calls the backend implementation directly, bypassing virtual
281 dispatch. Otherwise identical to @ref io_stream::read_some.
282
283 @param buffers The buffer sequence to read into.
284
285 @return An awaitable yielding `(error_code, std::size_t)`.
286
287 This socket must outlive the returned awaitable. The memory
288 referenced by @p buffers must remain valid until the operation
289 completes.
290 */
291 template<capy::MutableBufferSequence MB>
292 10x [[nodiscard]] auto read_some(MB const& buffers)
293 {
294 10x return native_read_awaitable<MB>(*this, buffers);
295 }
296
297 /** Asynchronously write data to the socket.
298
299 Calls the backend implementation directly, bypassing virtual
300 dispatch. Otherwise identical to @ref io_stream::write_some.
301
302 @param buffers The buffer sequence to write from.
303
304 @return An awaitable yielding `(error_code, std::size_t)`.
305
306 This socket must outlive the returned awaitable. The memory
307 referenced by @p buffers must remain valid until the operation
308 completes.
309 */
310 template<capy::ConstBufferSequence CB>
311 12x [[nodiscard]] auto write_some(CB const& buffers)
312 {
313 12x return native_write_awaitable<CB>(*this, buffers);
314 }
315
316 /** Asynchronously connect to a remote endpoint.
317
318 Calls the backend implementation directly, bypassing virtual
319 dispatch. Otherwise identical to @ref tcp_socket::connect.
320
321 If the socket is not open, it is opened automatically using
322 the protocol matching the endpoint's address family. An open
323 failure surfaces through the connect completion.
324
325 @param ep The remote endpoint to connect to.
326
327 @return An awaitable yielding `io_result<>`.
328
329 This socket must outlive the returned awaitable.
330 */
331 21x [[nodiscard]] auto connect(endpoint ep)
332 {
333 21x native_connect_awaitable aw(*this, ep);
334 21x if (!is_open())
335 2x aw.ec_ = open(ep.is_v6() ? tcp::v6() : tcp::v4());
336 21x return aw;
337 }
338
339 /** Asynchronously wait for the socket to be ready.
340
341 Calls the backend implementation directly, bypassing virtual
342 dispatch. Otherwise identical to @ref tcp_socket::wait.
343
344 @param w The wait direction (read, write, or error).
345
346 @return An awaitable yielding `io_result<>`.
347 */
348 6x [[nodiscard]] auto wait(wait_type w)
349 {
350 6x return native_wait_awaitable(*this, w);
351 }
352 };
353
354 } // namespace boost::corosio
355
356 #endif
357