include/boost/corosio/native/native_tcp_socket.hpp

100.0% Lines (45 / 45) 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(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::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(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::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(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::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::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::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::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::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% 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::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% 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%
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(std::coroutine_handle<> h, capy::executor_ref ex) const
96 {
97 30x return self_.get_impl().read_some(
98 30x 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 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(std::coroutine_handle<> h, capy::executor_ref ex) const
118 {
119 36x return self_.get_impl().write_some(
120 36x 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 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(std::coroutine_handle<> h, capy::executor_ref ex) const
137 {
138 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 23x native_connect_awaitable(native_tcp_socket& self, endpoint ep) noexcept
149 23x : self_(self)
150 23x , endpoint_(ep)
151 {
152 23x }
153
154 std::coroutine_handle<>
155 21x dispatch(std::coroutine_handle<> h, capy::executor_ref ex) const
156 {
157 63x return self_.get_impl().connect(
158 63x 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 49x explicit native_tcp_socket(capy::execution_context& ctx)
168 49x : io_object(handle(ctx, ctx.use_service<service_type>()))
169 {
170 49x }
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 28x 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 3x 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 14x [[nodiscard]] auto read_some(MB const& buffers)
232 {
233 14x 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 14x [[nodiscard]] auto write_some(CB const& buffers)
251 {
252 14x 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 23x [[nodiscard]] auto connect(endpoint ep)
271 {
272 23x native_connect_awaitable aw(*this, ep);
273 23x if (!is_open())
274 2x aw.ec_ = open(ep.address().family());
275 23x 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 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