100.00% Lines (46/46) 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   /** Connects, reads, and writes over TCP, calling the backend directly. 42   /** Connects, reads, and writes over TCP, calling the backend directly.
43   43  
44   This class template inherits from @ref tcp_socket. It shadows the 44   This class template inherits from @ref tcp_socket. It shadows the
45   async operations (`read_some`, `write_some`, `connect`) with 45   async operations (`read_some`, `write_some`, `connect`) with
46   versions that call the backend implementation directly. The compiler 46   versions that call the backend implementation directly. The compiler
47   can then inline through the entire call chain. 47   can then 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 that 53   any function expecting `tcp_socket&` or `io_stream&`. In that
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(capy::continuation& cont, capy::executor_ref ex) const 95   10 dispatch(capy::continuation& cont, 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 cont, ex, buffers_, this->token_, &this->ec_, &this->bytes_); 98   30 cont, 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(capy::continuation& cont, capy::executor_ref ex) const 117   12 dispatch(capy::continuation& cont, 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 cont, ex, buffers_, this->token_, &this->ec_, &this->bytes_); 120   36 cont, 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(capy::continuation& cont, capy::executor_ref ex) const 136   8 dispatch(capy::continuation& cont, capy::executor_ref ex) const
137   { 137   {
HITCBC 138   16 return self_.get_impl().wait( 138   16 return self_.get_impl().wait(
HITCBC 139   16 cont, ex, w_, this->token_, &this->ec_); 139   16 cont, ex, w_, this->token_, &this->ec_);
140   } 140   }
141   }; 141   };
142   142  
143   struct native_connect_awaitable 143   struct native_connect_awaitable
144   : detail::void_op_base<native_connect_awaitable> 144   : detail::void_op_base<native_connect_awaitable>
145   { 145   {
146   native_tcp_socket& self_; 146   native_tcp_socket& self_;
147   endpoint endpoint_; 147   endpoint endpoint_;
148   148  
HITCBC 149   23 native_connect_awaitable(native_tcp_socket& self, endpoint ep) noexcept 149   23 native_connect_awaitable(native_tcp_socket& self, endpoint ep) noexcept
HITCBC 150   23 : self_(self) 150   23 : self_(self)
HITCBC 151   23 , endpoint_(ep) 151   23 , endpoint_(ep)
152   { 152   {
HITCBC 153   23 } 153   23 }
154   154  
155   std::coroutine_handle<> 155   std::coroutine_handle<>
HITCBC 156   21 dispatch(capy::continuation& cont, capy::executor_ref ex) const 156   21 dispatch(capy::continuation& cont, capy::executor_ref ex) const
157   { 157   {
HITCBC 158   63 return self_.get_impl().connect( 158   63 return self_.get_impl().connect(
HITCBC 159   63 cont, ex, endpoint_, this->token_, &this->ec_); 159   63 cont, ex, endpoint_, this->token_, &this->ec_);
160   } 160   }
161   }; 161   };
162   162  
163   public: 163   public:
164   /** Construct a native socket from an execution context. 164   /** Construct a native socket from an execution context.
165   165  
166   @param ctx The execution context that owns this socket. 166   @param ctx The execution context that owns this socket.
167   */ 167   */
HITCBC 168   49 explicit native_tcp_socket(capy::execution_context& ctx) 168   49 explicit native_tcp_socket(capy::execution_context& ctx)
HITCBC 169   49 : io_object(handle(ctx, ctx.use_service<service_type>())) 169   49 : io_object(handle(ctx, ctx.use_service<service_type>()))
170   { 170   {
HITCBC 171   49 } 171   49 }
172   172  
173   /** Construct a native socket from an executor. 173   /** Construct a native socket from an executor.
174   174  
175   @param ex The executor whose context owns the socket. 175   @param ex The executor whose context owns the socket.
176   176  
177   @tparam Ex A type satisfying @ref capy::Executor. Must not 177   @tparam Ex A type satisfying @ref capy::Executor. Must not
178   be `native_tcp_socket` itself (disables implicit 178   be `native_tcp_socket` itself (disables implicit
179   conversion from move). 179   conversion from move).
180   */ 180   */
181   template<class Ex> 181   template<class Ex>
182   requires(!std::same_as<std::remove_cvref_t<Ex>, native_tcp_socket>) && 182   requires(!std::same_as<std::remove_cvref_t<Ex>, native_tcp_socket>) &&
183   capy::Executor<Ex> 183   capy::Executor<Ex>
184   explicit native_tcp_socket(Ex const& ex) : native_tcp_socket(ex.context()) 184   explicit native_tcp_socket(Ex const& ex) : native_tcp_socket(ex.context())
185   { 185   {
186   } 186   }
187   187  
188   /** Move construct. 188   /** Move construct.
189   189  
190   @param other The socket to move from. 190   @param other The socket to move from.
191   191  
192   @pre No awaitables returned by @p other's methods exist. 192   @pre No awaitables returned by @p other's methods exist.
193   @pre @p other is not referenced as a peer in any outstanding 193   @pre @p other is not referenced as a peer in any outstanding
194   accept awaitable. 194   accept awaitable.
195   @pre The execution context associated with @p other must 195   @pre The execution context associated with @p other must
196   outlive this socket. 196   outlive this socket.
197   */ 197   */
HITCBC 198   28 native_tcp_socket(native_tcp_socket&&) noexcept = default; 198   28 native_tcp_socket(native_tcp_socket&&) noexcept = default;
199   199  
200   /** Move assign. 200   /** Move assign.
201   201  
202   @param other The socket to move from. 202   @param other The socket to move from.
203   203  
204   @pre No awaitables returned by either `*this` or @p other's 204   @pre No awaitables returned by either `*this` or @p other's
205   methods exist. 205   methods exist.
206   @pre Neither `*this` nor @p other is referenced as a peer in 206   @pre Neither `*this` nor @p other is referenced as a peer in
207   any outstanding accept awaitable. 207   any outstanding accept awaitable.
208   @pre The execution context associated with @p other must 208   @pre The execution context associated with @p other must
209   outlive this socket. 209   outlive this socket.
210   */ 210   */
HITCBC 211   3 native_tcp_socket& operator=(native_tcp_socket&&) noexcept = default; 211   3 native_tcp_socket& operator=(native_tcp_socket&&) noexcept = default;
212   212  
213   /// Copy construction is disabled; the handle is uniquely owned. 213   /// Copy construction is disabled; the handle is uniquely owned.
214   native_tcp_socket(native_tcp_socket const&) = delete; 214   native_tcp_socket(native_tcp_socket const&) = delete;
215   /// Copy assignment is disabled; the handle is uniquely owned. 215   /// Copy assignment is disabled; the handle is uniquely owned.
216   native_tcp_socket& operator=(native_tcp_socket const&) = delete; 216   native_tcp_socket& operator=(native_tcp_socket const&) = delete;
217   217  
218   /** Asynchronously read data from the socket. 218   /** Asynchronously read data from the socket.
219   219  
220   Calls the backend implementation directly, bypassing virtual 220   Calls the backend implementation directly, bypassing virtual
221   dispatch. Otherwise identical to @ref io_stream::read_some. 221   dispatch. Otherwise identical to @ref io_stream::read_some.
222   222  
223   @param buffers The buffer sequence to read into. 223   @param buffers The buffer sequence to read into.
224   224  
225   @return An awaitable yielding `(error_code, std::size_t)`. 225   @return An awaitable yielding `(error_code, std::size_t)`.
226   226  
227   This socket must outlive the returned awaitable. The memory 227   This socket must outlive the returned awaitable. The memory
228   referenced by @p buffers must remain valid until the operation 228   referenced by @p buffers must remain valid until the operation
229   completes. 229   completes.
230   */ 230   */
231   template<capy::MutableBufferSequence MB> 231   template<capy::MutableBufferSequence MB>
HITCBC 232   14 [[nodiscard]] auto read_some(MB const& buffers) 232   14 [[nodiscard]] auto read_some(MB const& buffers)
233   { 233   {
HITCBC 234   14 return native_read_awaitable<MB>(*this, buffers); 234   14 return native_read_awaitable<MB>(*this, buffers);
235   } 235   }
236   236  
237   /** Asynchronously write data to the socket. 237   /** Asynchronously write data to the socket.
238   238  
239   Calls the backend implementation directly, bypassing virtual 239   Calls the backend implementation directly, bypassing virtual
240   dispatch. Otherwise identical to @ref io_stream::write_some. 240   dispatch. Otherwise identical to @ref io_stream::write_some.
241   241  
242   @param buffers The buffer sequence to write from. 242   @param buffers The buffer sequence to write from.
243   243  
244   @return An awaitable yielding `(error_code, std::size_t)`. 244   @return An awaitable yielding `(error_code, std::size_t)`.
245   245  
246   This socket must outlive the returned awaitable. The memory 246   This socket must outlive the returned awaitable. The memory
247   referenced by @p buffers must remain valid until the operation 247   referenced by @p buffers must remain valid until the operation
248   completes. 248   completes.
249   */ 249   */
250   template<capy::ConstBufferSequence CB> 250   template<capy::ConstBufferSequence CB>
HITCBC 251   14 [[nodiscard]] auto write_some(CB const& buffers) 251   14 [[nodiscard]] auto write_some(CB const& buffers)
252   { 252   {
HITCBC 253   14 return native_write_awaitable<CB>(*this, buffers); 253   14 return native_write_awaitable<CB>(*this, buffers);
254   } 254   }
255   255  
256   /** Asynchronously connect to a remote endpoint. 256   /** Asynchronously connect to a remote endpoint.
257   257  
258   Calls the backend implementation directly, bypassing virtual 258   Calls the backend implementation directly, bypassing virtual
259   dispatch. Otherwise identical to @ref tcp_socket::connect. 259   dispatch. Otherwise identical to @ref tcp_socket::connect.
260   260  
261   If the socket is not open, it is opened automatically using 261   If the socket is not open, it is opened automatically using
262   the protocol matching the endpoint's address family. An open 262   the protocol matching the endpoint's address family. An open
263   failure surfaces through the connect completion. 263   failure surfaces through the connect completion.
264   264  
265   @param ep The remote endpoint to connect to. 265   @param ep The remote endpoint to connect to.
266   266  
267   @return An awaitable yielding `results<>`. 267   @return An awaitable yielding `results<>`.
268   268  
269   This socket must outlive the returned awaitable. 269   This socket must outlive the returned awaitable.
270   */ 270   */
HITCBC 271   23 [[nodiscard]] auto connect(endpoint ep) 271   23 [[nodiscard]] auto connect(endpoint ep)
272   { 272   {
HITCBC 273   23 native_connect_awaitable aw(*this, ep); 273   23 native_connect_awaitable aw(*this, ep);
HITCBC 274   23 if (!is_open()) 274   23 if (!is_open())
HITCBC 275   2 aw.ec_ = open(ep.address().family()); 275   2 aw.ec_ = open(ep.address().family());
HITCBC 276   23 return aw; 276   23 return aw;
277   } 277   }
278   278  
279   /** Asynchronously wait for the socket to be ready. 279   /** Asynchronously wait for the socket to be ready.
280   280  
281   Calls the backend implementation directly, bypassing virtual 281   Calls the backend implementation directly, bypassing virtual
282   dispatch. Otherwise identical to @ref tcp_socket::wait. 282   dispatch. Otherwise identical to @ref tcp_socket::wait.
283   283  
284   @param w The wait direction (read, write, or error). 284   @param w The wait direction (read, write, or error).
285   285  
286   @return An awaitable yielding `results<>`. 286   @return An awaitable yielding `results<>`.
287   */ 287   */
HITCBC 288   10 [[nodiscard]] auto wait(wait_type w) 288   10 [[nodiscard]] auto wait(wait_type w)
289   { 289   {
HITCBC 290   10 return native_wait_awaitable(*this, w); 290   10 return native_wait_awaitable(*this, w);
291   } 291   }
292   }; 292   };
293   293  
294   } // namespace boost::corosio 294   } // namespace boost::corosio
295   295  
296   #endif 296   #endif