include/boost/corosio/native/native_tcp_socket.hpp

92.7% Lines (51/55) 100.0% List of functions (50/50) 56.2% Branches (18/32)
native_tcp_socket.hpp
f(x) Functions (50)
Function Calls Lines Branches Blocks
boost::corosio::native_tcp_socket<boost::corosio::kqueue_t{}>::~native_tcp_socket() :69 100x 100.0% – 100.0% boost::corosio::native_tcp_socket<boost::corosio::select_t{}>::~native_tcp_socket() :69 90x 100.0% – 100.0% boost::corosio::native_tcp_socket<boost::corosio::kqueue_t{}>::get_impl() :75 32x 100.0% – 100.0% boost::corosio::native_tcp_socket<boost::corosio::select_t{}>::get_impl() :75 31x 100.0% – 100.0% boost::corosio::native_tcp_socket<boost::corosio::kqueue_t{}>::native_read_awaitable<boost::capy::mutable_buffer>::native_read_awaitable(boost::corosio::native_tcp_socket<boost::corosio::kqueue_t{}>::native_read_awaitable<boost::capy::mutable_buffer>&&) :81 18x 100.0% – 100.0% boost::corosio::native_tcp_socket<boost::corosio::kqueue_t{}>::native_read_awaitable<boost::capy::mutable_buffer>::~native_read_awaitable() :81 36x 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{}>::native_read_awaitable<boost::capy::mutable_buffer>&&) :81 18x 100.0% – 100.0% boost::corosio::native_tcp_socket<boost::corosio::select_t{}>::native_read_awaitable<boost::capy::mutable_buffer>::~native_read_awaitable() :81 36x 100.0% – 100.0% boost::corosio::native_tcp_socket<boost::corosio::kqueue_t{}>::native_read_awaitable<boost::capy::mutable_buffer>::native_read_awaitable(boost::corosio::native_tcp_socket<boost::corosio::kqueue_t{}>&, boost::capy::mutable_buffer) :87 18x 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) :87 18x 100.0% – 100.0% boost::corosio::native_tcp_socket<boost::corosio::kqueue_t{}>::native_read_awaitable<boost::capy::mutable_buffer>::dispatch(std::__1::coroutine_handle<void>, boost::capy::executor_ref) const :95 7x 100.0% – 50.0% boost::corosio::native_tcp_socket<boost::corosio::select_t{}>::native_read_awaitable<boost::capy::mutable_buffer>::dispatch(std::__1::coroutine_handle<void>, boost::capy::executor_ref) const :95 7x 75.0% 50.0% 50.0% boost::corosio::native_tcp_socket<boost::corosio::kqueue_t{}>::native_write_awaitable<boost::capy::const_buffer>::native_write_awaitable(boost::corosio::native_tcp_socket<boost::corosio::kqueue_t{}>::native_write_awaitable<boost::capy::const_buffer>&&) :103 18x 100.0% – 100.0% boost::corosio::native_tcp_socket<boost::corosio::kqueue_t{}>::native_write_awaitable<boost::capy::const_buffer>::~native_write_awaitable() :103 36x 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{}>::native_write_awaitable<boost::capy::const_buffer>&&) :103 18x 100.0% – 100.0% boost::corosio::native_tcp_socket<boost::corosio::select_t{}>::native_write_awaitable<boost::capy::const_buffer>::~native_write_awaitable() :103 36x 100.0% – 100.0% boost::corosio::native_tcp_socket<boost::corosio::kqueue_t{}>::native_write_awaitable<boost::capy::const_buffer>::native_write_awaitable(boost::corosio::native_tcp_socket<boost::corosio::kqueue_t{}>&, boost::capy::const_buffer) :109 18x 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) :109 18x 100.0% – 100.0% boost::corosio::native_tcp_socket<boost::corosio::kqueue_t{}>::native_write_awaitable<boost::capy::const_buffer>::dispatch(std::__1::coroutine_handle<void>, boost::capy::executor_ref) const :117 8x 100.0% – 50.0% boost::corosio::native_tcp_socket<boost::corosio::select_t{}>::native_write_awaitable<boost::capy::const_buffer>::dispatch(std::__1::coroutine_handle<void>, boost::capy::executor_ref) const :117 8x 75.0% 50.0% 50.0% boost::corosio::native_tcp_socket<boost::corosio::kqueue_t{}>::native_wait_awaitable::native_wait_awaitable(boost::corosio::native_tcp_socket<boost::corosio::kqueue_t{}>::native_wait_awaitable&&) :124 10x 100.0% – 100.0% boost::corosio::native_tcp_socket<boost::corosio::kqueue_t{}>::native_wait_awaitable::~native_wait_awaitable() :124 20x 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{}>::native_wait_awaitable&&) :124 10x 100.0% – 100.0% boost::corosio::native_tcp_socket<boost::corosio::select_t{}>::native_wait_awaitable::~native_wait_awaitable() :124 20x 100.0% – 100.0% boost::corosio::native_tcp_socket<boost::corosio::kqueue_t{}>::native_wait_awaitable::native_wait_awaitable(boost::corosio::native_tcp_socket<boost::corosio::kqueue_t{}>&, boost::corosio::wait_type) :129 10x 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) :129 10x 100.0% – 100.0% boost::corosio::native_tcp_socket<boost::corosio::kqueue_t{}>::native_wait_awaitable::dispatch(std::__1::coroutine_handle<void>, boost::capy::executor_ref) const :136 4x 100.0% – 50.0% boost::corosio::native_tcp_socket<boost::corosio::select_t{}>::native_wait_awaitable::dispatch(std::__1::coroutine_handle<void>, boost::capy::executor_ref) const :136 4x 66.7% 50.0% 50.0% boost::corosio::native_tcp_socket<boost::corosio::kqueue_t{}>::native_connect_awaitable::native_connect_awaitable(boost::corosio::native_tcp_socket<boost::corosio::kqueue_t{}>::native_connect_awaitable&&) :142 56x 100.0% – 100.0% boost::corosio::native_tcp_socket<boost::corosio::kqueue_t{}>::native_connect_awaitable::~native_connect_awaitable() :142 84x 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{}>::native_connect_awaitable&&) :142 52x 100.0% – 100.0% boost::corosio::native_tcp_socket<boost::corosio::select_t{}>::native_connect_awaitable::~native_connect_awaitable() :142 78x 100.0% – 100.0% boost::corosio::native_tcp_socket<boost::corosio::kqueue_t{}>::native_connect_awaitable::native_connect_awaitable(boost::corosio::native_tcp_socket<boost::corosio::kqueue_t{}>&, boost::corosio::endpoint) :148 28x 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) :148 26x 100.0% – 100.0% boost::corosio::native_tcp_socket<boost::corosio::kqueue_t{}>::native_connect_awaitable::dispatch(std::__1::coroutine_handle<void>, boost::capy::executor_ref) const :155 13x 75.0% 50.0% 50.0% boost::corosio::native_tcp_socket<boost::corosio::select_t{}>::native_connect_awaitable::dispatch(std::__1::coroutine_handle<void>, boost::capy::executor_ref) const :155 12x 75.0% 50.0% 50.0% boost::corosio::native_tcp_socket<boost::corosio::kqueue_t{}>::native_tcp_socket(boost::capy::execution_context&) :167 31x 100.0% – 100.0% boost::corosio::native_tcp_socket<boost::corosio::select_t{}>::native_tcp_socket(boost::capy::execution_context&) :167 28x 100.0% – 100.0% boost::corosio::native_tcp_socket<boost::corosio::kqueue_t{}>::native_tcp_socket(boost::corosio::native_tcp_socket<boost::corosio::kqueue_t{}>&&) :197 19x 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{}>&&) :197 17x 100.0% – 100.0% boost::corosio::native_tcp_socket<boost::corosio::kqueue_t{}>::operator=(boost::corosio::native_tcp_socket<boost::corosio::kqueue_t{}>&&) :210 3x 100.0% – 100.0% boost::corosio::native_tcp_socket<boost::corosio::select_t{}>::operator=(boost::corosio::native_tcp_socket<boost::corosio::select_t{}>&&) :210 2x 100.0% – 100.0% auto boost::corosio::native_tcp_socket<boost::corosio::kqueue_t{}>::read_some<boost::capy::mutable_buffer>(boost::capy::mutable_buffer const&) :231 9x 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&) :231 9x 100.0% – 100.0% auto boost::corosio::native_tcp_socket<boost::corosio::kqueue_t{}>::write_some<boost::capy::const_buffer>(boost::capy::const_buffer const&) :250 9x 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&) :250 9x 100.0% – 100.0% boost::corosio::native_tcp_socket<boost::corosio::kqueue_t{}>::connect(boost::corosio::endpoint) :270 14x 83.3% 50.0% 100.0% boost::corosio::native_tcp_socket<boost::corosio::select_t{}>::connect(boost::corosio::endpoint) :270 13x 100.0% 100.0% 100.0% boost::corosio::native_tcp_socket<boost::corosio::kqueue_t{}>::wait(boost::corosio::wait_type) :287 5x 100.0% – 100.0% boost::corosio::native_tcp_socket<boost::corosio::select_t{}>::wait(boost::corosio::wait_type) :287 5x 100.0% – 100.0%
Line Branch 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 #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 63x impl_type& get_impl() noexcept
76 {
77 63x 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 36x native_read_awaitable(
88 native_tcp_socket& self, MutableBufferSequence buffers) noexcept
89 18x : self_(self)
90 18x , buffers_(std::move(buffers))
91 18x {
92 36x }
93
94 std::coroutine_handle<>
95 14x dispatch(std::coroutine_handle<> h, capy::executor_ref ex) const
96 {
97
4/8
✓ Branch 0 taken 7 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 7 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 7 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 7 times.
✗ Branch 7 not taken.
28x return self_.get_impl().read_some(
98 14x h, 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 36x native_write_awaitable(
110 native_tcp_socket& self, ConstBufferSequence buffers) noexcept
111 18x : self_(self)
112 18x , buffers_(std::move(buffers))
113 18x {
114 36x }
115
116 std::coroutine_handle<>
117 16x dispatch(std::coroutine_handle<> h, capy::executor_ref ex) const
118 {
119
4/8
✓ Branch 0 taken 8 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 8 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 8 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 8 times.
✗ Branch 7 not taken.
32x return self_.get_impl().write_some(
120 16x h, 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 20x native_wait_awaitable(native_tcp_socket& self, wait_type w) noexcept
130 10x : self_(self)
131 10x , w_(w)
132 10x {
133 20x }
134
135 std::coroutine_handle<>
136 8x dispatch(std::coroutine_handle<> h, capy::executor_ref ex) const
137 {
138
2/4
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
✗ Branch 3 not taken.
8x return self_.get_impl().wait(h, ex, w_, this->token_, &this->ec_);
139 ✗ }
140 };
141
142 struct native_connect_awaitable
143 : detail::void_op_base<native_connect_awaitable>
144 {
145 native_tcp_socket& self_;
146 endpoint endpoint_;
147
148 54x native_connect_awaitable(native_tcp_socket& self, endpoint ep) noexcept
149 27x : self_(self)
150 27x , endpoint_(ep)
151 27x {
152 54x }
153
154 std::coroutine_handle<>
155 25x dispatch(std::coroutine_handle<> h, capy::executor_ref ex) const
156 {
157
4/8
✓ Branch 0 taken 13 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 13 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 12 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 12 times.
✗ Branch 7 not taken.
50x return self_.get_impl().connect(
158 25x h, ex, endpoint_, this->token_, &this->ec_);
159 ✗ }
160 };
161
162 public:
163 /** Construct a native socket from an execution context.
164
165 @param ctx The execution context that owns this socket.
166 */
167 118x explicit native_tcp_socket(capy::execution_context& ctx)
168 59x : io_object(handle(ctx, ctx.use_service<service_type>()))
169 118x {
170 59x }
171
172 /** Construct a native socket from an executor.
173
174 @param ex The executor whose context owns the socket.
175
176 @tparam Ex A type satisfying @ref capy::Executor. Must not
177 be `native_tcp_socket` itself (disables implicit
178 conversion from move).
179 */
180 template<class Ex>
181 requires(!std::same_as<std::remove_cvref_t<Ex>, native_tcp_socket>) &&
182 capy::Executor<Ex>
183 explicit native_tcp_socket(Ex const& ex) : native_tcp_socket(ex.context())
184 {
185 }
186
187 /** Move construct.
188
189 @param other The socket to move from.
190
191 @pre No awaitables returned by @p other's methods exist.
192 @pre @p other is not referenced as a peer in any outstanding
193 accept awaitable.
194 @pre The execution context associated with @p other must
195 outlive this socket.
196 */
197 36x native_tcp_socket(native_tcp_socket&&) noexcept = default;
198
199 /** Move assign.
200
201 @param other The socket to move from.
202
203 @pre No awaitables returned by either `*this` or @p other's
204 methods exist.
205 @pre Neither `*this` nor @p other is referenced as a peer in
206 any outstanding accept awaitable.
207 @pre The execution context associated with @p other must
208 outlive this socket.
209 */
210 5x native_tcp_socket& operator=(native_tcp_socket&&) noexcept = default;
211
212 /// Copy construction is disabled; the handle is uniquely owned.
213 native_tcp_socket(native_tcp_socket const&) = delete;
214 /// Copy assignment is disabled; the handle is uniquely owned.
215 native_tcp_socket& operator=(native_tcp_socket const&) = delete;
216
217 /** Asynchronously read data from the socket.
218
219 Calls the backend implementation directly, bypassing virtual
220 dispatch. Otherwise identical to @ref io_stream::read_some.
221
222 @param buffers The buffer sequence to read into.
223
224 @return An awaitable yielding `(error_code, std::size_t)`.
225
226 This socket must outlive the returned awaitable. The memory
227 referenced by @p buffers must remain valid until the operation
228 completes.
229 */
230 template<capy::MutableBufferSequence MB>
231 18x [[nodiscard]] auto read_some(MB const& buffers)
232 {
233 18x return native_read_awaitable<MB>(*this, buffers);
234 }
235
236 /** Asynchronously write data to the socket.
237
238 Calls the backend implementation directly, bypassing virtual
239 dispatch. Otherwise identical to @ref io_stream::write_some.
240
241 @param buffers The buffer sequence to write from.
242
243 @return An awaitable yielding `(error_code, std::size_t)`.
244
245 This socket must outlive the returned awaitable. The memory
246 referenced by @p buffers must remain valid until the operation
247 completes.
248 */
249 template<capy::ConstBufferSequence CB>
250 18x [[nodiscard]] auto write_some(CB const& buffers)
251 {
252 18x return native_write_awaitable<CB>(*this, buffers);
253 }
254
255 /** Asynchronously connect to a remote endpoint.
256
257 Calls the backend implementation directly, bypassing virtual
258 dispatch. Otherwise identical to @ref tcp_socket::connect.
259
260 If the socket is not open, it is opened automatically using
261 the protocol matching the endpoint's address family. An open
262 failure surfaces through the connect completion.
263
264 @param ep The remote endpoint to connect to.
265
266 @return An awaitable yielding `io_result<>`.
267
268 This socket must outlive the returned awaitable.
269 */
270 27x [[nodiscard]] auto connect(endpoint ep)
271 {
272 27x native_connect_awaitable aw(*this, ep);
273
4/4
✓ Branch 0 taken 13 times.
✓ Branch 1 taken 1 time.
✓ Branch 2 taken 12 times.
✓ Branch 3 taken 1 time.
27x if (!is_open())
274 2x aw.ec_ = open(ep.address().family());
275 27x return aw;
276 27x }
277
278 /** Asynchronously wait for the socket to be ready.
279
280 Calls the backend implementation directly, bypassing virtual
281 dispatch. Otherwise identical to @ref tcp_socket::wait.
282
283 @param w The wait direction (read, write, or error).
284
285 @return An awaitable yielding `io_result<>`.
286 */
287 10x [[nodiscard]] auto wait(wait_type w)
288 {
289 10x return native_wait_awaitable(*this, w);
290 }
291 };
292
293 } // namespace boost::corosio
294
295 #endif
296