include/boost/corosio/native/native_tcp_socket.hpp

100.0% Lines (46 / 46) 100.0% Functions (30 / 30)
native_tcp_socket.hpp
f(x) Functions (30)
Function Calls Lines Blocks
boost::corosio::native_tcp_socket<boost::corosio::epoll_t{}>::get_impl() :75 26x 100.0% 100.0% boost::corosio::native_tcp_socket<boost::corosio::select_t{}>::get_impl() :75 25x 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) :87 7x 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 7x 100.0% 100.0% boost::corosio::native_tcp_socket<boost::corosio::epoll_t{}>::native_read_awaitable<boost::capy::mutable_buffer>::dispatch(boost::capy::continuation&, boost::capy::executor_ref) const :95 5x 100.0% 75.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 5x 100.0% 75.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) :109 7x 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 7x 100.0% 100.0% boost::corosio::native_tcp_socket<boost::corosio::epoll_t{}>::native_write_awaitable<boost::capy::const_buffer>::dispatch(boost::capy::continuation&, boost::capy::executor_ref) const :117 6x 100.0% 75.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 6x 100.0% 75.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) :129 5x 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 5x 100.0% 100.0% boost::corosio::native_tcp_socket<boost::corosio::epoll_t{}>::native_wait_awaitable::dispatch(boost::capy::continuation&, boost::capy::executor_ref) const :136 4x 100.0% 80.0% boost::corosio::native_tcp_socket<boost::corosio::select_t{}>::native_wait_awaitable::dispatch(boost::capy::continuation&, boost::capy::executor_ref) const :136 4x 100.0% 80.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) :149 12x 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 11x 100.0% 100.0% boost::corosio::native_tcp_socket<boost::corosio::epoll_t{}>::native_connect_awaitable::dispatch(boost::capy::continuation&, boost::capy::executor_ref) const :156 11x 100.0% 80.0% boost::corosio::native_tcp_socket<boost::corosio::select_t{}>::native_connect_awaitable::dispatch(boost::capy::continuation&, boost::capy::executor_ref) const :156 10x 100.0% 80.0% boost::corosio::native_tcp_socket<boost::corosio::epoll_t{}>::native_tcp_socket(boost::capy::execution_context&) :168 26x 100.0% 100.0% boost::corosio::native_tcp_socket<boost::corosio::select_t{}>::native_tcp_socket(boost::capy::execution_context&) :168 23x 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{}>&&) :198 15x 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 13x 100.0% 100.0% boost::corosio::native_tcp_socket<boost::corosio::epoll_t{}>::operator=(boost::corosio::native_tcp_socket<boost::corosio::epoll_t{}>&&) :211 2x 100.0% 100.0% boost::corosio::native_tcp_socket<boost::corosio::select_t{}>::operator=(boost::corosio::native_tcp_socket<boost::corosio::select_t{}>&&) :211 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&) :232 7x 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 7x 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&) :251 7x 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 7x 100.0% 100.0% boost::corosio::native_tcp_socket<boost::corosio::epoll_t{}>::connect(boost::corosio::endpoint) :271 7x 100.0% 100.0% boost::corosio::native_tcp_socket<boost::corosio::select_t{}>::connect(boost::corosio::endpoint) :271 6x 100.0% 100.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 #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 51x impl_type& get_impl() noexcept
76 {
77 51x 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 14x native_read_awaitable(
88 native_tcp_socket& self, MutableBufferSequence buffers) noexcept
89 14x : self_(self)
90 14x , buffers_(std::move(buffers))
91 {
92 14x }
93
94 std::coroutine_handle<>
95 10x dispatch(capy::continuation& cont, capy::executor_ref ex) const
96 {
97 30x return self_.get_impl().read_some(
98 30x 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 14x native_write_awaitable(
110 native_tcp_socket& self, ConstBufferSequence buffers) noexcept
111 14x : self_(self)
112 14x , buffers_(std::move(buffers))
113 {
114 14x }
115
116 std::coroutine_handle<>
117 12x dispatch(capy::continuation& cont, capy::executor_ref ex) const
118 {
119 36x return self_.get_impl().write_some(
120 36x 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 10x native_wait_awaitable(native_tcp_socket& self, wait_type w) noexcept
130 10x : self_(self)
131 10x , w_(w)
132 {
133 10x }
134
135 std::coroutine_handle<>
136 8x dispatch(capy::continuation& cont, capy::executor_ref ex) const
137 {
138 16x return self_.get_impl().wait(
139 16x 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 23x native_connect_awaitable(native_tcp_socket& self, endpoint ep) noexcept
150 23x : self_(self)
151 23x , endpoint_(ep)
152 {
153 23x }
154
155 std::coroutine_handle<>
156 21x dispatch(capy::continuation& cont, capy::executor_ref ex) const
157 {
158 63x return self_.get_impl().connect(
159 63x 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 49x explicit native_tcp_socket(capy::execution_context& ctx)
169 49x : io_object(handle(ctx, ctx.use_service<service_type>()))
170 {
171 49x }
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 28x 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 14x [[nodiscard]] auto read_some(MB const& buffers)
233 {
234 14x 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 14x [[nodiscard]] auto write_some(CB const& buffers)
252 {
253 14x 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 23x [[nodiscard]] auto connect(endpoint ep)
272 {
273 23x native_connect_awaitable aw(*this, ep);
274 23x if (!is_open())
275 2x aw.ec_ = open(ep.address().family());
276 23x 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 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