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_LOCAL_STREAM_SOCKET_HPP 11   #ifndef BOOST_COROSIO_NATIVE_NATIVE_LOCAL_STREAM_SOCKET_HPP
12   #define BOOST_COROSIO_NATIVE_NATIVE_LOCAL_STREAM_SOCKET_HPP 12   #define BOOST_COROSIO_NATIVE_NATIVE_LOCAL_STREAM_SOCKET_HPP
13   13  
14   #include <boost/corosio/local_stream_socket.hpp> 14   #include <boost/corosio/local_stream_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_URING 31   #if BOOST_COROSIO_HAS_URING
32   #include <boost/corosio/native/detail/uring/uring_types.hpp> 32   #include <boost/corosio/native/detail/uring/uring_types.hpp>
33   #endif 33   #endif
34   34  
35   #if BOOST_COROSIO_HAS_IOCP 35   #if BOOST_COROSIO_HAS_IOCP
36   #include <boost/corosio/native/detail/iocp/win_local_stream_acceptor_service.hpp> 36   #include <boost/corosio/native/detail/iocp/win_local_stream_acceptor_service.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   /** Reads and writes a Unix domain stream, calling the backend directly. 42   /** Reads and writes a Unix domain stream, calling the backend directly.
43   43  
44   This class template inherits from @ref local_stream_socket. It 44   This class template inherits from @ref local_stream_socket. It
45   shadows the async operations (`read_some`, `write_some`, `connect`) 45   shadows the async operations (`read_some`, `write_some`, `connect`)
46   with versions that call the backend implementation directly. The 46   with versions that call the backend implementation directly. The
47   compiler can then inline through the entire call chain. 47   compiler 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_local_stream_socket` IS-A `local_stream_socket` and 52   A `native_local_stream_socket` IS-A `local_stream_socket` and
53   can be passed to any function expecting `local_stream_socket&` 53   can be passed to any function expecting `local_stream_socket&`
54   or `io_stream&`, in which case virtual dispatch is used 54   or `io_stream&`, in which case virtual dispatch is used
55   transparently. 55   transparently.
56   56  
57   @tparam Backend A backend tag value (e.g., `epoll`) whose type 57   @tparam Backend A backend tag value (e.g., `epoll`) whose type
58   provides the concrete implementation types. 58   provides the concrete implementation types.
59   59  
60   @par Thread Safety 60   @par Thread Safety
61   Same as @ref local_stream_socket. 61   Same as @ref local_stream_socket.
62   62  
63   @par Example 63   @par Example
64   @par !example connect 64   @par !example connect
65   65  
66   @see @ref local_stream_socket, @ref epoll_t, @ref iocp_t 66   @see @ref local_stream_socket, @ref epoll_t, @ref iocp_t
67   */ 67   */
68   template<auto Backend> 68   template<auto Backend>
69   class native_local_stream_socket : public local_stream_socket 69   class native_local_stream_socket : public local_stream_socket
70   { 70   {
71   using backend_type = decltype(Backend); 71   using backend_type = decltype(Backend);
72   using impl_type = typename backend_type::local_stream_socket_type; 72   using impl_type = typename backend_type::local_stream_socket_type;
73   using service_type = typename backend_type::local_stream_service_type; 73   using service_type = typename backend_type::local_stream_service_type;
74   74  
HITCBC 75   26 impl_type& get_impl() noexcept 75   26 impl_type& get_impl() noexcept
76   { 76   {
HITCBC 77   26 return *static_cast<impl_type*>(h_.get()); 77   26 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_local_stream_socket& self_; 84   native_local_stream_socket& self_;
85   MutableBufferSequence buffers_; 85   MutableBufferSequence buffers_;
86   86  
HITCBC 87   8 native_read_awaitable( 87   8 native_read_awaitable(
88   native_local_stream_socket& self, 88   native_local_stream_socket& self,
89   MutableBufferSequence buffers) noexcept 89   MutableBufferSequence buffers) noexcept
HITCBC 90   8 : self_(self) 90   8 : self_(self)
HITCBC 91   8 , buffers_(std::move(buffers)) 91   8 , buffers_(std::move(buffers))
92   { 92   {
HITCBC 93   8 } 93   8 }
94   94  
95   std::coroutine_handle<> 95   std::coroutine_handle<>
HITCBC 96   6 dispatch(capy::continuation& cont, capy::executor_ref ex) const 96   6 dispatch(capy::continuation& cont, capy::executor_ref ex) const
97   { 97   {
HITCBC 98   18 return self_.get_impl().read_some( 98   18 return self_.get_impl().read_some(
HITCBC 99   18 cont, ex, buffers_, this->token_, &this->ec_, &this->bytes_); 99   18 cont, ex, buffers_, this->token_, &this->ec_, &this->bytes_);
100   } 100   }
101   }; 101   };
102   102  
103   template<class ConstBufferSequence> 103   template<class ConstBufferSequence>
104   struct native_write_awaitable 104   struct native_write_awaitable
105   : detail::bytes_op_base<native_write_awaitable<ConstBufferSequence>> 105   : detail::bytes_op_base<native_write_awaitable<ConstBufferSequence>>
106   { 106   {
107   native_local_stream_socket& self_; 107   native_local_stream_socket& self_;
108   ConstBufferSequence buffers_; 108   ConstBufferSequence buffers_;
109   109  
HITCBC 110   8 native_write_awaitable( 110   8 native_write_awaitable(
111   native_local_stream_socket& self, 111   native_local_stream_socket& self,
112   ConstBufferSequence buffers) noexcept 112   ConstBufferSequence buffers) noexcept
HITCBC 113   8 : self_(self) 113   8 : self_(self)
HITCBC 114   8 , buffers_(std::move(buffers)) 114   8 , buffers_(std::move(buffers))
115   { 115   {
HITCBC 116   8 } 116   8 }
117   117  
118   std::coroutine_handle<> 118   std::coroutine_handle<>
HITCBC 119   6 dispatch(capy::continuation& cont, capy::executor_ref ex) const 119   6 dispatch(capy::continuation& cont, capy::executor_ref ex) const
120   { 120   {
HITCBC 121   18 return self_.get_impl().write_some( 121   18 return self_.get_impl().write_some(
HITCBC 122   18 cont, ex, buffers_, this->token_, &this->ec_, &this->bytes_); 122   18 cont, ex, buffers_, this->token_, &this->ec_, &this->bytes_);
123   } 123   }
124   }; 124   };
125   125  
126   struct native_wait_awaitable : detail::void_op_base<native_wait_awaitable> 126   struct native_wait_awaitable : detail::void_op_base<native_wait_awaitable>
127   { 127   {
128   native_local_stream_socket& self_; 128   native_local_stream_socket& self_;
129   wait_type w_; 129   wait_type w_;
130   130  
HITCBC 131   6 native_wait_awaitable( 131   6 native_wait_awaitable(
132   native_local_stream_socket& self, wait_type w) noexcept 132   native_local_stream_socket& self, wait_type w) noexcept
HITCBC 133   6 : self_(self) 133   6 : self_(self)
HITCBC 134   6 , w_(w) 134   6 , w_(w)
135   { 135   {
HITCBC 136   6 } 136   6 }
137   137  
138   std::coroutine_handle<> 138   std::coroutine_handle<>
HITCBC 139   4 dispatch(capy::continuation& cont, capy::executor_ref ex) const 139   4 dispatch(capy::continuation& cont, capy::executor_ref ex) const
140   { 140   {
HITCBC 141   8 return self_.get_impl().wait( 141   8 return self_.get_impl().wait(
HITCBC 142   8 cont, ex, w_, this->token_, &this->ec_); 142   8 cont, ex, w_, this->token_, &this->ec_);
143   } 143   }
144   }; 144   };
145   145  
146   struct native_connect_awaitable 146   struct native_connect_awaitable
147   : detail::void_op_base<native_connect_awaitable> 147   : detail::void_op_base<native_connect_awaitable>
148   { 148   {
149   native_local_stream_socket& self_; 149   native_local_stream_socket& self_;
150   corosio::local_endpoint endpoint_; 150   corosio::local_endpoint endpoint_;
151   151  
HITCBC 152   12 native_connect_awaitable( 152   12 native_connect_awaitable(
153   native_local_stream_socket& self, 153   native_local_stream_socket& self,
154   corosio::local_endpoint ep) noexcept 154   corosio::local_endpoint ep) noexcept
HITCBC 155   12 : self_(self) 155   12 : self_(self)
HITCBC 156   12 , endpoint_(ep) 156   12 , endpoint_(ep)
157   { 157   {
HITCBC 158   12 } 158   12 }
159   159  
160   std::coroutine_handle<> 160   std::coroutine_handle<>
HITCBC 161   10 dispatch(capy::continuation& cont, capy::executor_ref ex) const 161   10 dispatch(capy::continuation& cont, capy::executor_ref ex) const
162   { 162   {
HITCBC 163   30 return self_.get_impl().connect( 163   30 return self_.get_impl().connect(
HITCBC 164   30 cont, ex, endpoint_, this->token_, &this->ec_); 164   30 cont, ex, endpoint_, this->token_, &this->ec_);
165   } 165   }
166   }; 166   };
167   167  
168   // The peer a failed accept returns: it must not touch the 168   // The peer a failed accept returns: it must not touch the
169   // acceptor's context, which a moved-from acceptor lacks. 169   // acceptor's context, which a moved-from acceptor lacks.
170   template<auto> 170   template<auto>
171   friend class native_local_stream_acceptor; 171   friend class native_local_stream_acceptor;
172   172  
HITCBC 173   6 native_local_stream_socket() noexcept = default; 173   6 native_local_stream_socket() noexcept = default;
174   174  
175   public: 175   public:
176   /** Construct a native socket from an execution context. 176   /** Construct a native socket from an execution context.
177   177  
178   @param ctx The execution context that owns this socket. 178   @param ctx The execution context that owns this socket.
179   */ 179   */
HITCBC 180   36 explicit native_local_stream_socket(capy::execution_context& ctx) 180   36 explicit native_local_stream_socket(capy::execution_context& ctx)
HITCBC 181   36 : io_object(handle(ctx, ctx.use_service<service_type>())) 181   36 : io_object(handle(ctx, ctx.use_service<service_type>()))
182   { 182   {
HITCBC 183   36 } 183   36 }
184   184  
185   /** Construct a native socket from an executor. 185   /** Construct a native socket from an executor.
186   186  
187   @param ex The executor whose context owns the socket. 187   @param ex The executor whose context owns the socket.
188   */ 188   */
189   template<class Ex> 189   template<class Ex>
190   requires(!std::same_as< 190   requires(!std::same_as<
191   std::remove_cvref_t<Ex>, 191   std::remove_cvref_t<Ex>,
192   native_local_stream_socket>) && 192   native_local_stream_socket>) &&
193   capy::Executor<Ex> 193   capy::Executor<Ex>
194   explicit native_local_stream_socket(Ex const& ex) 194   explicit native_local_stream_socket(Ex const& ex)
195   : native_local_stream_socket(ex.context()) 195   : native_local_stream_socket(ex.context())
196   { 196   {
197   } 197   }
198   198  
199   /// Move construct. 199   /// Move construct.
HITCBC 200   8 native_local_stream_socket(native_local_stream_socket&&) noexcept = default; 200   8 native_local_stream_socket(native_local_stream_socket&&) noexcept = default;
201   201  
202   /// Move assign. 202   /// Move assign.
203   native_local_stream_socket& 203   native_local_stream_socket&
204   operator=(native_local_stream_socket&&) noexcept = default; 204   operator=(native_local_stream_socket&&) noexcept = default;
205   205  
206   /// Copy construction is disabled; the handle is uniquely owned. 206   /// Copy construction is disabled; the handle is uniquely owned.
207   native_local_stream_socket(native_local_stream_socket const&) = delete; 207   native_local_stream_socket(native_local_stream_socket const&) = delete;
208   /// Copy assignment is disabled; the handle is uniquely owned. 208   /// Copy assignment is disabled; the handle is uniquely owned.
209   native_local_stream_socket& 209   native_local_stream_socket&
210   operator=(native_local_stream_socket const&) = delete; 210   operator=(native_local_stream_socket const&) = delete;
211   211  
212   /** Asynchronously read data from the socket. 212   /** Asynchronously read data from the socket.
213   213  
214   Calls the backend implementation directly, bypassing virtual 214   Calls the backend implementation directly, bypassing virtual
215   dispatch. Otherwise identical to @ref io_stream::read_some. 215   dispatch. Otherwise identical to @ref io_stream::read_some.
216   216  
217   @param buffers The buffer sequence to read into. 217   @param buffers The buffer sequence to read into.
218   218  
219   @return An awaitable yielding `(error_code, std::size_t)`. 219   @return An awaitable yielding `(error_code, std::size_t)`.
220   */ 220   */
221   template<capy::MutableBufferSequence MB> 221   template<capy::MutableBufferSequence MB>
HITCBC 222   8 [[nodiscard]] auto read_some(MB const& buffers) 222   8 [[nodiscard]] auto read_some(MB const& buffers)
223   { 223   {
HITCBC 224   8 return native_read_awaitable<MB>(*this, buffers); 224   8 return native_read_awaitable<MB>(*this, buffers);
225   } 225   }
226   226  
227   /** Asynchronously write data to the socket. 227   /** Asynchronously write data to the socket.
228   228  
229   Calls the backend implementation directly, bypassing virtual 229   Calls the backend implementation directly, bypassing virtual
230   dispatch. Otherwise identical to @ref io_stream::write_some. 230   dispatch. Otherwise identical to @ref io_stream::write_some.
231   231  
232   @param buffers The buffer sequence to write from. 232   @param buffers The buffer sequence to write from.
233   233  
234   @return An awaitable yielding `(error_code, std::size_t)`. 234   @return An awaitable yielding `(error_code, std::size_t)`.
235   */ 235   */
236   template<capy::ConstBufferSequence CB> 236   template<capy::ConstBufferSequence CB>
HITCBC 237   8 [[nodiscard]] auto write_some(CB const& buffers) 237   8 [[nodiscard]] auto write_some(CB const& buffers)
238   { 238   {
HITCBC 239   8 return native_write_awaitable<CB>(*this, buffers); 239   8 return native_write_awaitable<CB>(*this, buffers);
240   } 240   }
241   241  
242   /** Asynchronously connect to a remote endpoint. 242   /** Asynchronously connect to a remote endpoint.
243   243  
244   Calls the backend implementation directly, bypassing virtual 244   Calls the backend implementation directly, bypassing virtual
245   dispatch. Otherwise identical to @ref local_stream_socket::connect. 245   dispatch. Otherwise identical to @ref local_stream_socket::connect.
246   246  
247   If the socket is not already open, it is opened automatically. 247   If the socket is not already open, it is opened automatically.
248   248  
249   @param ep The local endpoint (path) to connect to. 249   @param ep The local endpoint (path) to connect to.
250   250  
251   @return An awaitable yielding `results<>`. 251   @return An awaitable yielding `results<>`.
252   252  
253   If the socket needs to be opened and the open fails, the 253   If the socket needs to be opened and the open fails, the
254   awaitable completes immediately with that error. 254   awaitable completes immediately with that error.
255   */ 255   */
HITCBC 256   12 [[nodiscard]] auto connect(corosio::local_endpoint ep) 256   12 [[nodiscard]] auto connect(corosio::local_endpoint ep)
257   { 257   {
HITCBC 258   12 native_connect_awaitable aw(*this, ep); 258   12 native_connect_awaitable aw(*this, ep);
HITCBC 259   12 if (!is_open()) 259   12 if (!is_open())
HITCBC 260   10 aw.ec_ = open(); 260   10 aw.ec_ = open();
HITCBC 261   12 return aw; 261   12 return aw;
262   } 262   }
263   263  
264   /** Asynchronously wait for the socket to be ready. 264   /** Asynchronously wait for the socket to be ready.
265   265  
266   Calls the backend implementation directly, bypassing virtual 266   Calls the backend implementation directly, bypassing virtual
267   dispatch. Otherwise identical to @ref local_stream_socket::wait. 267   dispatch. Otherwise identical to @ref local_stream_socket::wait.
268   268  
269   @param w The wait direction (read, write, or error). 269   @param w The wait direction (read, write, or error).
270   270  
271   @return An awaitable yielding `results<>`. 271   @return An awaitable yielding `results<>`.
272   */ 272   */
HITCBC 273   6 [[nodiscard]] auto wait(wait_type w) 273   6 [[nodiscard]] auto wait(wait_type w)
274   { 274   {
HITCBC 275   6 return native_wait_awaitable(*this, w); 275   6 return native_wait_awaitable(*this, w);
276   } 276   }
277   }; 277   };
278   278  
279   } // namespace boost::corosio 279   } // namespace boost::corosio
280   280  
281   #endif // BOOST_COROSIO_NATIVE_NATIVE_LOCAL_STREAM_SOCKET_HPP 281   #endif // BOOST_COROSIO_NATIVE_NATIVE_LOCAL_STREAM_SOCKET_HPP