100.00% Lines (45/45) 100.00% Functions (15/15)
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 local_stream_socket, epoll_t, iocp_t 66   @see local_stream_socket, epoll_t, 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   public: 168   public:
169   /** Construct a native socket from an execution context. 169   /** Construct a native socket from an execution context.
170   170  
171   @param ctx The execution context that owns this socket. 171   @param ctx The execution context that owns this socket.
172   */ 172   */
HITCBC 173   40 explicit native_local_stream_socket(capy::execution_context& ctx) 173   40 explicit native_local_stream_socket(capy::execution_context& ctx)
HITCBC 174   40 : io_object(handle(ctx, ctx.use_service<service_type>())) 174   40 : io_object(handle(ctx, ctx.use_service<service_type>()))
175   { 175   {
HITCBC 176   40 } 176   40 }
177   177  
178   /** Construct a native socket from an executor. 178   /** Construct a native socket from an executor.
179   179  
180   @param ex The executor whose context owns the socket. 180   @param ex The executor whose context owns the socket.
181   */ 181   */
182   template<class Ex> 182   template<class Ex>
183   requires(!std::same_as< 183   requires(!std::same_as<
184   std::remove_cvref_t<Ex>, 184   std::remove_cvref_t<Ex>,
185   native_local_stream_socket>) && 185   native_local_stream_socket>) &&
186   capy::Executor<Ex> 186   capy::Executor<Ex>
187   explicit native_local_stream_socket(Ex const& ex) 187   explicit native_local_stream_socket(Ex const& ex)
188   : native_local_stream_socket(ex.context()) 188   : native_local_stream_socket(ex.context())
189   { 189   {
190   } 190   }
191   191  
192   /// Move construct. 192   /// Move construct.
HITCBC 193   6 native_local_stream_socket(native_local_stream_socket&&) noexcept = default; 193   6 native_local_stream_socket(native_local_stream_socket&&) noexcept = default;
194   194  
195   /// Move assign. 195   /// Move assign.
196   native_local_stream_socket& 196   native_local_stream_socket&
197   operator=(native_local_stream_socket&&) noexcept = default; 197   operator=(native_local_stream_socket&&) noexcept = default;
198   198  
199   /// Copy construction is disabled; the handle is uniquely owned. 199   /// Copy construction is disabled; the handle is uniquely owned.
200   native_local_stream_socket(native_local_stream_socket const&) = delete; 200   native_local_stream_socket(native_local_stream_socket const&) = delete;
201   /// Copy assignment is disabled; the handle is uniquely owned. 201   /// Copy assignment is disabled; the handle is uniquely owned.
202   native_local_stream_socket& 202   native_local_stream_socket&
203   operator=(native_local_stream_socket const&) = delete; 203   operator=(native_local_stream_socket const&) = delete;
204   204  
205   /** Asynchronously read data from the socket. 205   /** Asynchronously read data from the socket.
206   206  
207   Calls the backend implementation directly, bypassing virtual 207   Calls the backend implementation directly, bypassing virtual
208   dispatch. Otherwise identical to @ref io_stream::read_some. 208   dispatch. Otherwise identical to @ref io_stream::read_some.
209   209  
210   @param buffers The buffer sequence to read into. 210   @param buffers The buffer sequence to read into.
211   211  
212   @return An awaitable yielding `(error_code, std::size_t)`. 212   @return An awaitable yielding `(error_code, std::size_t)`.
213   */ 213   */
214   template<capy::MutableBufferSequence MB> 214   template<capy::MutableBufferSequence MB>
HITCBC 215   8 [[nodiscard]] auto read_some(MB const& buffers) 215   8 [[nodiscard]] auto read_some(MB const& buffers)
216   { 216   {
HITCBC 217   8 return native_read_awaitable<MB>(*this, buffers); 217   8 return native_read_awaitable<MB>(*this, buffers);
218   } 218   }
219   219  
220   /** Asynchronously write data to the socket. 220   /** Asynchronously write data to the socket.
221   221  
222   Calls the backend implementation directly, bypassing virtual 222   Calls the backend implementation directly, bypassing virtual
223   dispatch. Otherwise identical to @ref io_stream::write_some. 223   dispatch. Otherwise identical to @ref io_stream::write_some.
224   224  
225   @param buffers The buffer sequence to write from. 225   @param buffers The buffer sequence to write from.
226   226  
227   @return An awaitable yielding `(error_code, std::size_t)`. 227   @return An awaitable yielding `(error_code, std::size_t)`.
228   */ 228   */
229   template<capy::ConstBufferSequence CB> 229   template<capy::ConstBufferSequence CB>
HITCBC 230   8 [[nodiscard]] auto write_some(CB const& buffers) 230   8 [[nodiscard]] auto write_some(CB const& buffers)
231   { 231   {
HITCBC 232   8 return native_write_awaitable<CB>(*this, buffers); 232   8 return native_write_awaitable<CB>(*this, buffers);
233   } 233   }
234   234  
235   /** Asynchronously connect to a remote endpoint. 235   /** Asynchronously connect to a remote endpoint.
236   236  
237   Calls the backend implementation directly, bypassing virtual 237   Calls the backend implementation directly, bypassing virtual
238   dispatch. Otherwise identical to @ref local_stream_socket::connect. 238   dispatch. Otherwise identical to @ref local_stream_socket::connect.
239   239  
240   If the socket is not already open, it is opened automatically. 240   If the socket is not already open, it is opened automatically.
241   241  
242   @param ep The local endpoint (path) to connect to. 242   @param ep The local endpoint (path) to connect to.
243   243  
244   @return An awaitable yielding `results<>`. 244   @return An awaitable yielding `results<>`.
245   245  
246   If the socket needs to be opened and the open fails, the 246   If the socket needs to be opened and the open fails, the
247   awaitable completes immediately with that error. 247   awaitable completes immediately with that error.
248   */ 248   */
HITCBC 249   12 [[nodiscard]] auto connect(corosio::local_endpoint ep) 249   12 [[nodiscard]] auto connect(corosio::local_endpoint ep)
250   { 250   {
HITCBC 251   12 native_connect_awaitable aw(*this, ep); 251   12 native_connect_awaitable aw(*this, ep);
HITCBC 252   12 if (!is_open()) 252   12 if (!is_open())
HITCBC 253   10 aw.ec_ = open(); 253   10 aw.ec_ = open();
HITCBC 254   12 return aw; 254   12 return aw;
255   } 255   }
256   256  
257   /** Asynchronously wait for the socket to be ready. 257   /** Asynchronously wait for the socket to be ready.
258   258  
259   Calls the backend implementation directly, bypassing virtual 259   Calls the backend implementation directly, bypassing virtual
260   dispatch. Otherwise identical to @ref local_stream_socket::wait. 260   dispatch. Otherwise identical to @ref local_stream_socket::wait.
261   261  
262   @param w The wait direction (read, write, or error). 262   @param w The wait direction (read, write, or error).
263   263  
264   @return An awaitable yielding `results<>`. 264   @return An awaitable yielding `results<>`.
265   */ 265   */
HITCBC 266   6 [[nodiscard]] auto wait(wait_type w) 266   6 [[nodiscard]] auto wait(wait_type w)
267   { 267   {
HITCBC 268   6 return native_wait_awaitable(*this, w); 268   6 return native_wait_awaitable(*this, w);
269   } 269   }
270   }; 270   };
271   271  
272   } // namespace boost::corosio 272   } // namespace boost::corosio
273   273  
274   #endif // BOOST_COROSIO_NATIVE_NATIVE_LOCAL_STREAM_SOCKET_HPP 274   #endif // BOOST_COROSIO_NATIVE_NATIVE_LOCAL_STREAM_SOCKET_HPP