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{}>&&) :193 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{}>&&) :193 13x 100.0% 100.0% boost::corosio::native_tcp_socket<boost::corosio::epoll_t{}>::operator=(boost::corosio::native_tcp_socket<boost::corosio::epoll_t{}>&&) :206 2x 100.0% 100.0% boost::corosio::native_tcp_socket<boost::corosio::select_t{}>::operator=(boost::corosio::native_tcp_socket<boost::corosio::select_t{}>&&) :206 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&) :225 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&) :225 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&) :244 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&) :244 7x 100.0% 100.0% boost::corosio::native_tcp_socket<boost::corosio::epoll_t{}>::connect(boost::corosio::endpoint) :264 7x 100.0% 100.0% boost::corosio::native_tcp_socket<boost::corosio::select_t{}>::connect(boost::corosio::endpoint) :264 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 /** An asynchronous TCP socket with devirtualized I/O operations.
43
44 This class template inherits from @ref tcp_socket and shadows
45 the async operations (`read_some`, `write_some`, `connect`) with
46 versions that call the backend implementation directly, allowing
47 the compiler to 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 which
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 will own this socket.
166 */
167 49x explicit native_tcp_socket(capy::execution_context& ctx)
168 49x : io_object(create_handle<service_type>(ctx))
169 {
170 49x }
171
172 /** Construct a native socket from an executor.
173
174 @param ex The executor whose context will own the socket.
175 */
176 template<class Ex>
177 requires(!std::same_as<std::remove_cvref_t<Ex>, native_tcp_socket>) &&
178 capy::Executor<Ex>
179 explicit native_tcp_socket(Ex const& ex) : native_tcp_socket(ex.context())
180 {
181 }
182
183 /** Move construct.
184
185 @param other The socket to move from.
186
187 @pre No awaitables returned by @p other's methods exist.
188 @pre @p other is not referenced as a peer in any outstanding
189 accept awaitable.
190 @pre The execution context associated with @p other must
191 outlive this socket.
192 */
193 28x native_tcp_socket(native_tcp_socket&&) noexcept = default;
194
195 /** Move assign.
196
197 @param other The socket to move from.
198
199 @pre No awaitables returned by either `*this` or @p other's
200 methods exist.
201 @pre Neither `*this` nor @p other is referenced as a peer in
202 any outstanding accept awaitable.
203 @pre The execution context associated with @p other must
204 outlive this socket.
205 */
206 3x native_tcp_socket& operator=(native_tcp_socket&&) noexcept = default;
207
208 native_tcp_socket(native_tcp_socket const&) = delete;
209 native_tcp_socket& operator=(native_tcp_socket const&) = delete;
210
211 /** Asynchronously read data from the socket.
212
213 Calls the backend implementation directly, bypassing virtual
214 dispatch. Otherwise identical to @ref io_stream::read_some.
215
216 @param buffers The buffer sequence to read into.
217
218 @return An awaitable yielding `(error_code, std::size_t)`.
219
220 This socket must outlive the returned awaitable. The memory
221 referenced by @p buffers must remain valid until the operation
222 completes.
223 */
224 template<capy::MutableBufferSequence MB>
225 14x [[nodiscard]] auto read_some(MB const& buffers)
226 {
227 14x return native_read_awaitable<MB>(*this, buffers);
228 }
229
230 /** Asynchronously write data to the socket.
231
232 Calls the backend implementation directly, bypassing virtual
233 dispatch. Otherwise identical to @ref io_stream::write_some.
234
235 @param buffers The buffer sequence to write from.
236
237 @return An awaitable yielding `(error_code, std::size_t)`.
238
239 This socket must outlive the returned awaitable. The memory
240 referenced by @p buffers must remain valid until the operation
241 completes.
242 */
243 template<capy::ConstBufferSequence CB>
244 14x [[nodiscard]] auto write_some(CB const& buffers)
245 {
246 14x return native_write_awaitable<CB>(*this, buffers);
247 }
248
249 /** Asynchronously connect to a remote endpoint.
250
251 Calls the backend implementation directly, bypassing virtual
252 dispatch. Otherwise identical to @ref tcp_socket::connect.
253
254 If the socket is not open, it is opened automatically using
255 the protocol matching the endpoint's address family. An open
256 failure surfaces through the connect completion.
257
258 @param ep The remote endpoint to connect to.
259
260 @return An awaitable yielding `io_result<>`.
261
262 This socket must outlive the returned awaitable.
263 */
264 23x [[nodiscard]] auto connect(endpoint ep)
265 {
266 23x native_connect_awaitable aw(*this, ep);
267 23x if (!is_open())
268 2x aw.ec_ = open(ep.address().family());
269 23x return aw;
270 }
271
272 /** Asynchronously wait for the socket to be ready.
273
274 Calls the backend implementation directly, bypassing virtual
275 dispatch. Otherwise identical to @ref tcp_socket::wait.
276
277 @param w The wait direction (read, write, or error).
278
279 @return An awaitable yielding `io_result<>`.
280 */
281 10x [[nodiscard]] auto wait(wait_type w)
282 {
283 10x return native_wait_awaitable(*this, w);
284 }
285 };
286
287 } // namespace boost::corosio
288
289 #endif
290