include/boost/corosio/native/native_tcp_socket.hpp

100.0% Lines (46 / 46) 100.0% Branches (8 / 8) 100.0% Functions (16 / 16)
native_tcp_socket.hpp
f(x) Functions (16)
Function Calls Lines Branches Blocks
boost::corosio::native_tcp_socket<boost::corosio::iocp_t{}>::get_impl() :75 32x 100.0% – 100.0% boost::corosio::native_tcp_socket<boost::corosio::iocp_t{}>::native_read_awaitable<boost::capy::mutable_buffer>::native_read_awaitable(boost::corosio::native_tcp_socket<boost::corosio::iocp_t{}>&, boost::capy::mutable_buffer) :87 9x 100.0% – 100.0% boost::corosio::native_tcp_socket<boost::corosio::iocp_t{}>::native_read_awaitable<boost::capy::mutable_buffer>::dispatch(boost::capy::continuation&, boost::capy::executor_ref) const :95 7x 100.0% 100.0% 75.0% boost::corosio::native_tcp_socket<boost::corosio::iocp_t{}>::native_write_awaitable<boost::capy::const_buffer>::native_write_awaitable(boost::corosio::native_tcp_socket<boost::corosio::iocp_t{}>&, boost::capy::const_buffer) :109 9x 100.0% – 100.0% boost::corosio::native_tcp_socket<boost::corosio::iocp_t{}>::native_write_awaitable<boost::capy::const_buffer>::dispatch(boost::capy::continuation&, boost::capy::executor_ref) const :117 8x 100.0% 100.0% 75.0% boost::corosio::native_tcp_socket<boost::corosio::iocp_t{}>::native_wait_awaitable::native_wait_awaitable(boost::corosio::native_tcp_socket<boost::corosio::iocp_t{}>&, boost::corosio::wait_type) :129 5x 100.0% – 100.0% boost::corosio::native_tcp_socket<boost::corosio::iocp_t{}>::native_wait_awaitable::dispatch(boost::capy::continuation&, boost::capy::executor_ref) const :136 4x 100.0% 100.0% 80.0% boost::corosio::native_tcp_socket<boost::corosio::iocp_t{}>::native_connect_awaitable::native_connect_awaitable(boost::corosio::native_tcp_socket<boost::corosio::iocp_t{}>&, boost::corosio::endpoint) :149 14x 100.0% – 100.0% boost::corosio::native_tcp_socket<boost::corosio::iocp_t{}>::native_connect_awaitable::dispatch(boost::capy::continuation&, boost::capy::executor_ref) const :156 13x 100.0% 100.0% 80.0% boost::corosio::native_tcp_socket<boost::corosio::iocp_t{}>::native_tcp_socket(boost::capy::execution_context&) :168 31x 100.0% 100.0% 100.0% boost::corosio::native_tcp_socket<boost::corosio::iocp_t{}>::native_tcp_socket(boost::corosio::native_tcp_socket<boost::corosio::iocp_t{}>&&) :198 35x 100.0% – 100.0% boost::corosio::native_tcp_socket<boost::corosio::iocp_t{}>::operator=(boost::corosio::native_tcp_socket<boost::corosio::iocp_t{}>&&) :211 3x 100.0% – 100.0% auto boost::corosio::native_tcp_socket<boost::corosio::iocp_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::iocp_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::iocp_t{}>::connect(boost::corosio::endpoint) :271 14x 100.0% 100.0% 100.0% boost::corosio::native_tcp_socket<boost::corosio::iocp_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 32x impl_type& get_impl() noexcept
76 {
77 32x 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 9x native_read_awaitable(
88 native_tcp_socket& self, MutableBufferSequence buffers) noexcept
89 9x : self_(self)
90 9x , buffers_(std::move(buffers))
91 {
92 9x }
93
94 std::coroutine_handle<>
95 7x dispatch(capy::continuation& cont, capy::executor_ref ex) const
96 {
97
1/1
✓ Branch 5 → 6 taken 7 times.
21x return self_.get_impl().read_some(
98 21x 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 9x native_write_awaitable(
110 native_tcp_socket& self, ConstBufferSequence buffers) noexcept
111 9x : self_(self)
112 9x , buffers_(std::move(buffers))
113 {
114 9x }
115
116 std::coroutine_handle<>
117 8x dispatch(capy::continuation& cont, capy::executor_ref ex) const
118 {
119
1/1
✓ Branch 5 → 6 taken 8 times.
24x return self_.get_impl().write_some(
120 24x 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 5x native_wait_awaitable(native_tcp_socket& self, wait_type w) noexcept
130 5x : self_(self)
131 5x , w_(w)
132 {
133 5x }
134
135 std::coroutine_handle<>
136 4x dispatch(capy::continuation& cont, capy::executor_ref ex) const
137 {
138 8x return self_.get_impl().wait(
139
1/1
✓ Branch 4 → 5 taken 4 times.
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 14x native_connect_awaitable(native_tcp_socket& self, endpoint ep) noexcept
150 14x : self_(self)
151 14x , endpoint_(ep)
152 {
153 14x }
154
155 std::coroutine_handle<>
156 13x dispatch(capy::continuation& cont, capy::executor_ref ex) const
157 {
158
1/1
✓ Branch 4 → 5 taken 13 times.
39x return self_.get_impl().connect(
159 39x 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 31x explicit native_tcp_socket(capy::execution_context& ctx)
169
2/2
✓ Branch 2 → 3 taken 31 times.
✓ Branch 3 → 4 taken 31 times.
31x : io_object(handle(ctx, ctx.use_service<service_type>()))
170 {
171 31x }
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 35x 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 3x 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 9x [[nodiscard]] auto read_some(MB const& buffers)
233 {
234 9x 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 9x [[nodiscard]] auto write_some(CB const& buffers)
252 {
253 9x 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 14x [[nodiscard]] auto connect(endpoint ep)
272 {
273 14x native_connect_awaitable aw(*this, ep);
274
2/2
✓ Branch 4 → 5 taken 1 time.
✓ Branch 4 → 9 taken 13 times.
14x if (!is_open())
275 1x aw.ec_ = open(ep.address().family());
276 14x return aw;
277 }
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 5x [[nodiscard]] auto wait(wait_type w)
289 {
290 5x return native_wait_awaitable(*this, w);
291 }
292 };
293
294 } // namespace boost::corosio
295
296 #endif
297