include/boost/corosio/native/native_tcp_socket.hpp

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