100.00% Lines (45/45) 100.00% Functions (16/16)
TLA Baseline Branch
Line Hits Code Line Hits Code
1   // 1   //
2   // Copyright (c) 2026 Steve Gerbino 2   // Copyright (c) 2026 Steve Gerbino
3   // Copyright (c) 2026 Michael Vandeberg 3   // Copyright (c) 2026 Michael Vandeberg
4   // 4   //
5   // Distributed under the Boost Software License, Version 1.0. (See accompanying 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) 6   // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
7   // 7   //
8   // Official repository: https://github.com/cppalliance/corosio 8   // Official repository: https://github.com/cppalliance/corosio
9   // 9   //
10   10  
11   #ifndef BOOST_COROSIO_NATIVE_NATIVE_TCP_SOCKET_HPP 11   #ifndef BOOST_COROSIO_NATIVE_NATIVE_TCP_SOCKET_HPP
12   #define BOOST_COROSIO_NATIVE_NATIVE_TCP_SOCKET_HPP 12   #define BOOST_COROSIO_NATIVE_NATIVE_TCP_SOCKET_HPP
13   13  
14   #include <boost/corosio/tcp_socket.hpp> 14   #include <boost/corosio/tcp_socket.hpp>
15   #include <boost/corosio/backend.hpp> 15   #include <boost/corosio/backend.hpp>
16   #include <boost/corosio/detail/op_base.hpp> 16   #include <boost/corosio/detail/op_base.hpp>
17   17  
18   #ifndef BOOST_COROSIO_MRDOCS 18   #ifndef BOOST_COROSIO_MRDOCS
19   #if BOOST_COROSIO_HAS_EPOLL 19   #if BOOST_COROSIO_HAS_EPOLL
20   #include <boost/corosio/native/detail/epoll/epoll_types.hpp> 20   #include <boost/corosio/native/detail/epoll/epoll_types.hpp>
21   #endif 21   #endif
22   22  
23   #if BOOST_COROSIO_HAS_SELECT 23   #if BOOST_COROSIO_HAS_SELECT
24   #include <boost/corosio/native/detail/select/select_types.hpp> 24   #include <boost/corosio/native/detail/select/select_types.hpp>
25   #endif 25   #endif
26   26  
27   #if BOOST_COROSIO_HAS_KQUEUE 27   #if BOOST_COROSIO_HAS_KQUEUE
28   #include <boost/corosio/native/detail/kqueue/kqueue_types.hpp> 28   #include <boost/corosio/native/detail/kqueue/kqueue_types.hpp>
29   #endif 29   #endif
30   30  
31   #if BOOST_COROSIO_HAS_IOCP 31   #if BOOST_COROSIO_HAS_IOCP
32   #include <boost/corosio/native/detail/iocp/win_tcp_acceptor_service.hpp> 32   #include <boost/corosio/native/detail/iocp/win_tcp_acceptor_service.hpp>
33   #endif 33   #endif
34   34  
35   #if BOOST_COROSIO_HAS_URING 35   #if BOOST_COROSIO_HAS_URING
36   #include <boost/corosio/native/detail/uring/uring_types.hpp> 36   #include <boost/corosio/native/detail/uring/uring_types.hpp>
37   #endif 37   #endif
38   #endif // !BOOST_COROSIO_MRDOCS 38   #endif // !BOOST_COROSIO_MRDOCS
39   39  
40   namespace boost::corosio { 40   namespace boost::corosio {
41   41  
42   /** An asynchronous TCP socket with devirtualized I/O operations. 42   /** An asynchronous TCP socket with devirtualized I/O operations.
43   43  
44   This class template inherits from @ref tcp_socket and shadows 44   This class template inherits from @ref tcp_socket and shadows
45   the async operations (`read_some`, `write_some`, `connect`) with 45   the async operations (`read_some`, `write_some`, `connect`) with
46   versions that call the backend implementation directly, allowing 46   versions that call the backend implementation directly, allowing
47   the compiler to inline through the entire call chain. 47   the compiler to inline through the entire call chain.
48   48  
49   Non-async operations (`open`, `close`, `cancel`, socket options) 49   Non-async operations (`open`, `close`, `cancel`, socket options)
50   remain unchanged and dispatch through the compiled library. 50   remain unchanged and dispatch through the compiled library.
51   51  
52   A `native_tcp_socket` IS-A `tcp_socket` and can be passed to 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 53   any function expecting `tcp_socket&` or `io_stream&`, in which
54   case virtual dispatch is used transparently. 54   case virtual dispatch is used transparently.
55   55  
56   @tparam Backend A backend tag value (e.g., `epoll`, 56   @tparam Backend A backend tag value (e.g., `epoll`,
57   `iocp`) whose type provides the concrete implementation 57   `iocp`) whose type provides the concrete implementation
58   types. 58   types.
59   59  
60   @par Thread Safety 60   @par Thread Safety
61   Same as @ref tcp_socket. 61   Same as @ref tcp_socket.
62   62  
63   @par Example 63   @par Example
64   @par !example native_tcp_socket 64   @par !example native_tcp_socket
65   65  
66   @see tcp_socket, epoll_t, iocp_t 66   @see tcp_socket, epoll_t, iocp_t
67   */ 67   */
68   template<auto Backend> 68   template<auto Backend>
69   class native_tcp_socket : public tcp_socket 69   class native_tcp_socket : public tcp_socket
70   { 70   {
71   using backend_type = decltype(Backend); 71   using backend_type = decltype(Backend);
72   using impl_type = typename backend_type::tcp_socket_type; 72   using impl_type = typename backend_type::tcp_socket_type;
73   using service_type = typename backend_type::tcp_service_type; 73   using service_type = typename backend_type::tcp_service_type;
74   74  
HITCBC 75   51 impl_type& get_impl() noexcept 75   51 impl_type& get_impl() noexcept
76   { 76   {
HITCBC 77   51 return *static_cast<impl_type*>(h_.get()); 77   51 return *static_cast<impl_type*>(h_.get());
78   } 78   }
79   79  
80   template<class MutableBufferSequence> 80   template<class MutableBufferSequence>
81   struct native_read_awaitable 81   struct native_read_awaitable
82   : detail::bytes_op_base<native_read_awaitable<MutableBufferSequence>> 82   : detail::bytes_op_base<native_read_awaitable<MutableBufferSequence>>
83   { 83   {
84   native_tcp_socket& self_; 84   native_tcp_socket& self_;
85   MutableBufferSequence buffers_; 85   MutableBufferSequence buffers_;
86   86  
HITCBC 87   14 native_read_awaitable( 87   14 native_read_awaitable(
88   native_tcp_socket& self, MutableBufferSequence buffers) noexcept 88   native_tcp_socket& self, MutableBufferSequence buffers) noexcept
HITCBC 89   14 : self_(self) 89   14 : self_(self)
HITCBC 90   14 , buffers_(std::move(buffers)) 90   14 , buffers_(std::move(buffers))
91   { 91   {
HITCBC 92   14 } 92   14 }
93   93  
94   std::coroutine_handle<> 94   std::coroutine_handle<>
HITCBC 95   10 dispatch(std::coroutine_handle<> h, capy::executor_ref ex) const 95   10 dispatch(std::coroutine_handle<> h, capy::executor_ref ex) const
96   { 96   {
HITCBC 97   30 return self_.get_impl().read_some( 97   30 return self_.get_impl().read_some(
HITCBC 98   30 h, ex, buffers_, this->token_, &this->ec_, &this->bytes_); 98   30 h, ex, buffers_, this->token_, &this->ec_, &this->bytes_);
99   } 99   }
100   }; 100   };
101   101  
102   template<class ConstBufferSequence> 102   template<class ConstBufferSequence>
103   struct native_write_awaitable 103   struct native_write_awaitable
104   : detail::bytes_op_base<native_write_awaitable<ConstBufferSequence>> 104   : detail::bytes_op_base<native_write_awaitable<ConstBufferSequence>>
105   { 105   {
106   native_tcp_socket& self_; 106   native_tcp_socket& self_;
107   ConstBufferSequence buffers_; 107   ConstBufferSequence buffers_;
108   108  
HITCBC 109   14 native_write_awaitable( 109   14 native_write_awaitable(
110   native_tcp_socket& self, ConstBufferSequence buffers) noexcept 110   native_tcp_socket& self, ConstBufferSequence buffers) noexcept
HITCBC 111   14 : self_(self) 111   14 : self_(self)
HITCBC 112   14 , buffers_(std::move(buffers)) 112   14 , buffers_(std::move(buffers))
113   { 113   {
HITCBC 114   14 } 114   14 }
115   115  
116   std::coroutine_handle<> 116   std::coroutine_handle<>
HITCBC 117   12 dispatch(std::coroutine_handle<> h, capy::executor_ref ex) const 117   12 dispatch(std::coroutine_handle<> h, capy::executor_ref ex) const
118   { 118   {
HITCBC 119   36 return self_.get_impl().write_some( 119   36 return self_.get_impl().write_some(
HITCBC 120   36 h, ex, buffers_, this->token_, &this->ec_, &this->bytes_); 120   36 h, ex, buffers_, this->token_, &this->ec_, &this->bytes_);
121   } 121   }
122   }; 122   };
123   123  
124   struct native_wait_awaitable : detail::void_op_base<native_wait_awaitable> 124   struct native_wait_awaitable : detail::void_op_base<native_wait_awaitable>
125   { 125   {
126   native_tcp_socket& self_; 126   native_tcp_socket& self_;
127   wait_type w_; 127   wait_type w_;
128   128  
HITCBC 129   10 native_wait_awaitable(native_tcp_socket& self, wait_type w) noexcept 129   10 native_wait_awaitable(native_tcp_socket& self, wait_type w) noexcept
HITCBC 130   10 : self_(self) 130   10 : self_(self)
HITCBC 131   10 , w_(w) 131   10 , w_(w)
132   { 132   {
HITCBC 133   10 } 133   10 }
134   134  
135   std::coroutine_handle<> 135   std::coroutine_handle<>
HITCBC 136   8 dispatch(std::coroutine_handle<> h, capy::executor_ref ex) const 136   8 dispatch(std::coroutine_handle<> h, capy::executor_ref ex) const
137   { 137   {
HITCBC 138   8 return self_.get_impl().wait(h, ex, w_, this->token_, &this->ec_); 138   8 return self_.get_impl().wait(h, ex, w_, this->token_, &this->ec_);
139   } 139   }
140   }; 140   };
141   141  
142   struct native_connect_awaitable 142   struct native_connect_awaitable
143   : detail::void_op_base<native_connect_awaitable> 143   : detail::void_op_base<native_connect_awaitable>
144   { 144   {
145   native_tcp_socket& self_; 145   native_tcp_socket& self_;
146   endpoint endpoint_; 146   endpoint endpoint_;
147   147  
HITCBC 148   23 native_connect_awaitable(native_tcp_socket& self, endpoint ep) noexcept 148   23 native_connect_awaitable(native_tcp_socket& self, endpoint ep) noexcept
HITCBC 149   23 : self_(self) 149   23 : self_(self)
HITCBC 150   23 , endpoint_(ep) 150   23 , endpoint_(ep)
151   { 151   {
HITCBC 152   23 } 152   23 }
153   153  
154   std::coroutine_handle<> 154   std::coroutine_handle<>
HITCBC 155   21 dispatch(std::coroutine_handle<> h, capy::executor_ref ex) const 155   21 dispatch(std::coroutine_handle<> h, capy::executor_ref ex) const
156   { 156   {
HITCBC 157   63 return self_.get_impl().connect( 157   63 return self_.get_impl().connect(
HITCBC 158   63 h, ex, endpoint_, this->token_, &this->ec_); 158   63 h, ex, endpoint_, this->token_, &this->ec_);
159   } 159   }
160   }; 160   };
161   161  
162   public: 162   public:
163   /** Construct a native socket from an execution context. 163   /** Construct a native socket from an execution context.
164   164  
165   @param ctx The execution context that will own this socket. 165   @param ctx The execution context that will own this socket.
166   */ 166   */
HITCBC 167   49 explicit native_tcp_socket(capy::execution_context& ctx) 167   49 explicit native_tcp_socket(capy::execution_context& ctx)
HITCBC 168   49 : io_object(create_handle<service_type>(ctx)) 168   49 : io_object(create_handle<service_type>(ctx))
169   { 169   {
HITCBC 170   49 } 170   49 }
171   171  
172   /** Construct a native socket from an executor. 172   /** Construct a native socket from an executor.
173   173  
174   @param ex The executor whose context will own the socket. 174   @param ex The executor whose context will own the socket.
175   */ 175   */
176   template<class Ex> 176   template<class Ex>
177   requires(!std::same_as<std::remove_cvref_t<Ex>, native_tcp_socket>) && 177   requires(!std::same_as<std::remove_cvref_t<Ex>, native_tcp_socket>) &&
178   capy::Executor<Ex> 178   capy::Executor<Ex>
179   explicit native_tcp_socket(Ex const& ex) : native_tcp_socket(ex.context()) 179   explicit native_tcp_socket(Ex const& ex) : native_tcp_socket(ex.context())
180   { 180   {
181   } 181   }
182   182  
183   /** Move construct. 183   /** Move construct.
184   184  
185   @param other The socket to move from. 185   @param other The socket to move from.
186   186  
187   @pre No awaitables returned by @p other's methods exist. 187   @pre No awaitables returned by @p other's methods exist.
188   @pre @p other is not referenced as a peer in any outstanding 188   @pre @p other is not referenced as a peer in any outstanding
189   accept awaitable. 189   accept awaitable.
190   @pre The execution context associated with @p other must 190   @pre The execution context associated with @p other must
191   outlive this socket. 191   outlive this socket.
192   */ 192   */
HITCBC 193   28 native_tcp_socket(native_tcp_socket&&) noexcept = default; 193   28 native_tcp_socket(native_tcp_socket&&) noexcept = default;
194   194  
195   /** Move assign. 195   /** Move assign.
196   196  
197   @param other The socket to move from. 197   @param other The socket to move from.
198   198  
199   @pre No awaitables returned by either `*this` or @p other's 199   @pre No awaitables returned by either `*this` or @p other's
200   methods exist. 200   methods exist.
201   @pre Neither `*this` nor @p other is referenced as a peer in 201   @pre Neither `*this` nor @p other is referenced as a peer in
202   any outstanding accept awaitable. 202   any outstanding accept awaitable.
203   @pre The execution context associated with @p other must 203   @pre The execution context associated with @p other must
204   outlive this socket. 204   outlive this socket.
205   */ 205   */
HITCBC 206   3 native_tcp_socket& operator=(native_tcp_socket&&) noexcept = default; 206   3 native_tcp_socket& operator=(native_tcp_socket&&) noexcept = default;
207   207  
208   native_tcp_socket(native_tcp_socket const&) = delete; 208   native_tcp_socket(native_tcp_socket const&) = delete;
209   native_tcp_socket& operator=(native_tcp_socket const&) = delete; 209   native_tcp_socket& operator=(native_tcp_socket const&) = delete;
210   210  
211   /** Asynchronously read data from the socket. 211   /** Asynchronously read data from the socket.
212   212  
213   Calls the backend implementation directly, bypassing virtual 213   Calls the backend implementation directly, bypassing virtual
214   dispatch. Otherwise identical to @ref io_stream::read_some. 214   dispatch. Otherwise identical to @ref io_stream::read_some.
215   215  
216   @param buffers The buffer sequence to read into. 216   @param buffers The buffer sequence to read into.
217   217  
218   @return An awaitable yielding `(error_code, std::size_t)`. 218   @return An awaitable yielding `(error_code, std::size_t)`.
219   219  
220   This socket must outlive the returned awaitable. The memory 220   This socket must outlive the returned awaitable. The memory
221   referenced by @p buffers must remain valid until the operation 221   referenced by @p buffers must remain valid until the operation
222   completes. 222   completes.
223   */ 223   */
224   template<capy::MutableBufferSequence MB> 224   template<capy::MutableBufferSequence MB>
HITCBC 225   14 [[nodiscard]] auto read_some(MB const& buffers) 225   14 [[nodiscard]] auto read_some(MB const& buffers)
226   { 226   {
HITCBC 227   14 return native_read_awaitable<MB>(*this, buffers); 227   14 return native_read_awaitable<MB>(*this, buffers);
228   } 228   }
229   229  
230   /** Asynchronously write data to the socket. 230   /** Asynchronously write data to the socket.
231   231  
232   Calls the backend implementation directly, bypassing virtual 232   Calls the backend implementation directly, bypassing virtual
233   dispatch. Otherwise identical to @ref io_stream::write_some. 233   dispatch. Otherwise identical to @ref io_stream::write_some.
234   234  
235   @param buffers The buffer sequence to write from. 235   @param buffers The buffer sequence to write from.
236   236  
237   @return An awaitable yielding `(error_code, std::size_t)`. 237   @return An awaitable yielding `(error_code, std::size_t)`.
238   238  
239   This socket must outlive the returned awaitable. The memory 239   This socket must outlive the returned awaitable. The memory
240   referenced by @p buffers must remain valid until the operation 240   referenced by @p buffers must remain valid until the operation
241   completes. 241   completes.
242   */ 242   */
243   template<capy::ConstBufferSequence CB> 243   template<capy::ConstBufferSequence CB>
HITCBC 244   14 [[nodiscard]] auto write_some(CB const& buffers) 244   14 [[nodiscard]] auto write_some(CB const& buffers)
245   { 245   {
HITCBC 246   14 return native_write_awaitable<CB>(*this, buffers); 246   14 return native_write_awaitable<CB>(*this, buffers);
247   } 247   }
248   248  
249   /** Asynchronously connect to a remote endpoint. 249   /** Asynchronously connect to a remote endpoint.
250   250  
251   Calls the backend implementation directly, bypassing virtual 251   Calls the backend implementation directly, bypassing virtual
252   dispatch. Otherwise identical to @ref tcp_socket::connect. 252   dispatch. Otherwise identical to @ref tcp_socket::connect.
253   253  
254   If the socket is not open, it is opened automatically using 254   If the socket is not open, it is opened automatically using
255   the protocol matching the endpoint's address family. An open 255   the protocol matching the endpoint's address family. An open
256   failure surfaces through the connect completion. 256   failure surfaces through the connect completion.
257   257  
258   @param ep The remote endpoint to connect to. 258   @param ep The remote endpoint to connect to.
259   259  
260   @return An awaitable yielding `io_result<>`. 260   @return An awaitable yielding `io_result<>`.
261   261  
262   This socket must outlive the returned awaitable. 262   This socket must outlive the returned awaitable.
263   */ 263   */
HITCBC 264   23 [[nodiscard]] auto connect(endpoint ep) 264   23 [[nodiscard]] auto connect(endpoint ep)
265   { 265   {
HITCBC 266   23 native_connect_awaitable aw(*this, ep); 266   23 native_connect_awaitable aw(*this, ep);
HITCBC 267   23 if (!is_open()) 267   23 if (!is_open())
HITCBC 268   2 aw.ec_ = open(ep.address().family()); 268   2 aw.ec_ = open(ep.address().family());
HITCBC 269   23 return aw; 269   23 return aw;
270   } 270   }
271   271  
272   /** Asynchronously wait for the socket to be ready. 272   /** Asynchronously wait for the socket to be ready.
273   273  
274   Calls the backend implementation directly, bypassing virtual 274   Calls the backend implementation directly, bypassing virtual
275   dispatch. Otherwise identical to @ref tcp_socket::wait. 275   dispatch. Otherwise identical to @ref tcp_socket::wait.
276   276  
277   @param w The wait direction (read, write, or error). 277   @param w The wait direction (read, write, or error).
278   278  
279   @return An awaitable yielding `io_result<>`. 279   @return An awaitable yielding `io_result<>`.
280   */ 280   */
HITCBC 281   10 [[nodiscard]] auto wait(wait_type w) 281   10 [[nodiscard]] auto wait(wait_type w)
282   { 282   {
HITCBC 283   10 return native_wait_awaitable(*this, w); 283   10 return native_wait_awaitable(*this, w);
284   } 284   }
285   }; 285   };
286   286  
287   } // namespace boost::corosio 287   } // namespace boost::corosio
288   288  
289   #endif 289   #endif