include/boost/corosio/native/native_tcp_socket.hpp

92.9% Lines (52 / 56) 55.6% Branches (20 / 36) 100.0% Functions (50 / 50)
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 132x 100.0% – 100.0% boost::corosio::native_tcp_socket<boost::corosio::select_t{}>::~native_tcp_socket() :69 122x 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(boost::capy::continuation&, 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(boost::capy::continuation&, 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(boost::capy::continuation&, 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(boost::capy::continuation&, 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(boost::capy::continuation&, boost::capy::executor_ref) const :136 4x 100.0% – 50.0% boost::corosio::native_tcp_socket<boost::corosio::select_t{}>::native_wait_awaitable::dispatch(boost::capy::continuation&, boost::capy::executor_ref) const :136 4x 75.0% 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&&) :143 56x 100.0% – 100.0% boost::corosio::native_tcp_socket<boost::corosio::kqueue_t{}>::native_connect_awaitable::~native_connect_awaitable() :143 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&&) :143 52x 100.0% – 100.0% boost::corosio::native_tcp_socket<boost::corosio::select_t{}>::native_connect_awaitable::~native_connect_awaitable() :143 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) :149 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) :149 26x 100.0% – 100.0% boost::corosio::native_tcp_socket<boost::corosio::kqueue_t{}>::native_connect_awaitable::dispatch(boost::capy::continuation&, boost::capy::executor_ref) const :156 13x 75.0% 50.0% 50.0% boost::corosio::native_tcp_socket<boost::corosio::select_t{}>::native_connect_awaitable::dispatch(boost::capy::continuation&, boost::capy::executor_ref) const :156 12x 75.0% 50.0% 50.0% boost::corosio::native_tcp_socket<boost::corosio::kqueue_t{}>::native_tcp_socket(boost::capy::execution_context&) :168 31x 100.0% – 100.0% boost::corosio::native_tcp_socket<boost::corosio::select_t{}>::native_tcp_socket(boost::capy::execution_context&) :168 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{}>&&) :198 35x 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{}>&&) :198 33x 100.0% – 100.0% boost::corosio::native_tcp_socket<boost::corosio::kqueue_t{}>::operator=(boost::corosio::native_tcp_socket<boost::corosio::kqueue_t{}>&&) :211 3x 100.0% – 100.0% boost::corosio::native_tcp_socket<boost::corosio::select_t{}>::operator=(boost::corosio::native_tcp_socket<boost::corosio::select_t{}>&&) :211 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&) :232 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&) :232 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&) :251 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&) :251 9x 100.0% – 100.0% boost::corosio::native_tcp_socket<boost::corosio::kqueue_t{}>::connect(boost::corosio::endpoint) :271 14x 83.3% 50.0% 100.0% boost::corosio::native_tcp_socket<boost::corosio::select_t{}>::connect(boost::corosio::endpoint) :271 13x 100.0% 100.0% 100.0% boost::corosio::native_tcp_socket<boost::corosio::kqueue_t{}>::wait(boost::corosio::wait_type) :288 5x 100.0% – 100.0% boost::corosio::native_tcp_socket<boost::corosio::select_t{}>::wait(boost::corosio::wait_type) :288 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 @ref tcp_socket, @ref epoll_t, @ref 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(capy::continuation& cont, 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 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 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(capy::continuation& cont, 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 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 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(capy::continuation& cont, capy::executor_ref ex) const
137 {
138
4/8
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 4 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 4 times.
✗ Branch 7 not taken.
16x return self_.get_impl().wait(
139 8x 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 54x native_connect_awaitable(native_tcp_socket& self, endpoint ep) noexcept
150 27x : self_(self)
151 27x , endpoint_(ep)
152 27x {
153 54x }
154
155 std::coroutine_handle<>
156 25x dispatch(capy::continuation& cont, capy::executor_ref ex) const
157 {
158
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(
159 25x 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 118x explicit native_tcp_socket(capy::execution_context& ctx)
169 59x : io_object(handle(ctx, ctx.use_service<service_type>()))
170 118x {
171 59x }
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 68x 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 5x 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 18x [[nodiscard]] auto read_some(MB const& buffers)
233 {
234 18x 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 18x [[nodiscard]] auto write_some(CB const& buffers)
252 {
253 18x 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 27x [[nodiscard]] auto connect(endpoint ep)
272 {
273 27x native_connect_awaitable aw(*this, ep);
274
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())
275 2x aw.ec_ = open(ep.address().family());
276 27x return aw;
277 27x }
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 10x [[nodiscard]] auto wait(wait_type w)
289 {
290 10x return native_wait_awaitable(*this, w);
291 }
292 };
293
294 } // namespace boost::corosio
295
296 #endif
297