include/boost/corosio/native/native_tcp_socket.hpp

100.0% Lines (45 / 45) 100.0% Functions (45 / 45)
native_tcp_socket.hpp
f(x) Functions (45)
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::uring_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::uring_t{}>::native_read_awaitable<boost::capy::mutable_buffer>::native_read_awaitable(boost::corosio::native_tcp_socket<boost::corosio::uring_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(std::__n4861::coroutine_handle<void>, 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(std::__n4861::coroutine_handle<void>, boost::capy::executor_ref) const :95 5x 100.0% 75.0% boost::corosio::native_tcp_socket<boost::corosio::uring_t{}>::native_read_awaitable<boost::capy::mutable_buffer>::dispatch(std::__n4861::coroutine_handle<void>, 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::uring_t{}>::native_write_awaitable<boost::capy::const_buffer>::native_write_awaitable(boost::corosio::native_tcp_socket<boost::corosio::uring_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(std::__n4861::coroutine_handle<void>, 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(std::__n4861::coroutine_handle<void>, boost::capy::executor_ref) const :117 6x 100.0% 75.0% boost::corosio::native_tcp_socket<boost::corosio::uring_t{}>::native_write_awaitable<boost::capy::const_buffer>::dispatch(std::__n4861::coroutine_handle<void>, 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::uring_t{}>::native_wait_awaitable::native_wait_awaitable(boost::corosio::native_tcp_socket<boost::corosio::uring_t{}>&, boost::corosio::wait_type) :129 5x 100.0% 100.0% boost::corosio::native_tcp_socket<boost::corosio::epoll_t{}>::native_wait_awaitable::dispatch(std::__n4861::coroutine_handle<void>, boost::capy::executor_ref) const :136 4x 100.0% 80.0% boost::corosio::native_tcp_socket<boost::corosio::select_t{}>::native_wait_awaitable::dispatch(std::__n4861::coroutine_handle<void>, boost::capy::executor_ref) const :136 4x 100.0% 80.0% boost::corosio::native_tcp_socket<boost::corosio::uring_t{}>::native_wait_awaitable::dispatch(std::__n4861::coroutine_handle<void>, 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) :148 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) :148 11x 100.0% 100.0% boost::corosio::native_tcp_socket<boost::corosio::uring_t{}>::native_connect_awaitable::native_connect_awaitable(boost::corosio::native_tcp_socket<boost::corosio::uring_t{}>&, boost::corosio::endpoint) :148 11x 100.0% 100.0% boost::corosio::native_tcp_socket<boost::corosio::epoll_t{}>::native_connect_awaitable::dispatch(std::__n4861::coroutine_handle<void>, boost::capy::executor_ref) const :155 11x 100.0% 80.0% boost::corosio::native_tcp_socket<boost::corosio::select_t{}>::native_connect_awaitable::dispatch(std::__n4861::coroutine_handle<void>, boost::capy::executor_ref) const :155 10x 100.0% 80.0% boost::corosio::native_tcp_socket<boost::corosio::uring_t{}>::native_connect_awaitable::dispatch(std::__n4861::coroutine_handle<void>, boost::capy::executor_ref) const :155 10x 100.0% 80.0% boost::corosio::native_tcp_socket<boost::corosio::epoll_t{}>::native_tcp_socket(boost::capy::execution_context&) :167 26x 100.0% 100.0% boost::corosio::native_tcp_socket<boost::corosio::select_t{}>::native_tcp_socket(boost::capy::execution_context&) :167 23x 100.0% 100.0% boost::corosio::native_tcp_socket<boost::corosio::uring_t{}>::native_tcp_socket(boost::capy::execution_context&) :167 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{}>&&) :197 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{}>&&) :197 13x 100.0% 100.0% boost::corosio::native_tcp_socket<boost::corosio::uring_t{}>::native_tcp_socket(boost::corosio::native_tcp_socket<boost::corosio::uring_t{}>&&) :197 13x 100.0% 100.0% boost::corosio::native_tcp_socket<boost::corosio::epoll_t{}>::operator=(boost::corosio::native_tcp_socket<boost::corosio::epoll_t{}>&&) :210 2x 100.0% 100.0% boost::corosio::native_tcp_socket<boost::corosio::select_t{}>::operator=(boost::corosio::native_tcp_socket<boost::corosio::select_t{}>&&) :210 1x 100.0% 100.0% boost::corosio::native_tcp_socket<boost::corosio::uring_t{}>::operator=(boost::corosio::native_tcp_socket<boost::corosio::uring_t{}>&&) :210 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&) :231 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&) :231 7x 100.0% 100.0% auto boost::corosio::native_tcp_socket<boost::corosio::uring_t{}>::read_some<boost::capy::mutable_buffer>(boost::capy::mutable_buffer const&) :231 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&) :250 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&) :250 7x 100.0% 100.0% auto boost::corosio::native_tcp_socket<boost::corosio::uring_t{}>::write_some<boost::capy::const_buffer>(boost::capy::const_buffer const&) :250 7x 100.0% 100.0% boost::corosio::native_tcp_socket<boost::corosio::epoll_t{}>::connect(boost::corosio::endpoint) :270 7x 100.0% 100.0% boost::corosio::native_tcp_socket<boost::corosio::select_t{}>::connect(boost::corosio::endpoint) :270 6x 100.0% 100.0% boost::corosio::native_tcp_socket<boost::corosio::uring_t{}>::connect(boost::corosio::endpoint) :270 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 76x impl_type& get_impl() noexcept
76 {
77 76x 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 21x native_read_awaitable(
88 native_tcp_socket& self, MutableBufferSequence buffers) noexcept
89 21x : self_(self)
90 21x , buffers_(std::move(buffers))
91 {
92 21x }
93
94 std::coroutine_handle<>
95 15x dispatch(std::coroutine_handle<> h, capy::executor_ref ex) const
96 {
97 45x return self_.get_impl().read_some(
98 45x 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 21x native_write_awaitable(
110 native_tcp_socket& self, ConstBufferSequence buffers) noexcept
111 21x : self_(self)
112 21x , buffers_(std::move(buffers))
113 {
114 21x }
115
116 std::coroutine_handle<>
117 18x dispatch(std::coroutine_handle<> h, capy::executor_ref ex) const
118 {
119 54x return self_.get_impl().write_some(
120 54x 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 15x native_wait_awaitable(native_tcp_socket& self, wait_type w) noexcept
130 15x : self_(self)
131 15x , w_(w)
132 {
133 15x }
134
135 std::coroutine_handle<>
136 12x dispatch(std::coroutine_handle<> h, capy::executor_ref ex) const
137 {
138 12x 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 34x native_connect_awaitable(native_tcp_socket& self, endpoint ep) noexcept
149 34x : self_(self)
150 34x , endpoint_(ep)
151 {
152 34x }
153
154 std::coroutine_handle<>
155 31x dispatch(std::coroutine_handle<> h, capy::executor_ref ex) const
156 {
157 93x return self_.get_impl().connect(
158 93x 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 72x explicit native_tcp_socket(capy::execution_context& ctx)
168 72x : io_object(handle(ctx, ctx.use_service<service_type>()))
169 {
170 72x }
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 41x 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 4x 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 21x [[nodiscard]] auto read_some(MB const& buffers)
232 {
233 21x 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 21x [[nodiscard]] auto write_some(CB const& buffers)
251 {
252 21x 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 34x [[nodiscard]] auto connect(endpoint ep)
271 {
272 34x native_connect_awaitable aw(*this, ep);
273 34x if (!is_open())
274 3x aw.ec_ = open(ep.address().family());
275 34x return aw;
276 }
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 15x [[nodiscard]] auto wait(wait_type w)
288 {
289 15x return native_wait_awaitable(*this, w);
290 }
291 };
292
293 } // namespace boost::corosio
294
295 #endif
296