92.19% Lines (59/64) 100.00% Functions (17/17)
TLA Baseline Branch
Line Hits Code Line Hits Code
1   // 1   //
2   // Copyright (c) 2026 Steve Gerbino 2   // Copyright (c) 2026 Steve Gerbino
3   // 3   //
4   // Distributed under the Boost Software License, Version 1.0. (See accompanying 4   // Distributed under the Boost Software License, Version 1.0. (See accompanying
5   // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 5   // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
6   // 6   //
7   // Official repository: https://github.com/cppalliance/corosio 7   // Official repository: https://github.com/cppalliance/corosio
8   // 8   //
9   9  
10   #ifndef BOOST_COROSIO_NATIVE_NATIVE_LOCAL_STREAM_ACCEPTOR_HPP 10   #ifndef BOOST_COROSIO_NATIVE_NATIVE_LOCAL_STREAM_ACCEPTOR_HPP
11   #define BOOST_COROSIO_NATIVE_NATIVE_LOCAL_STREAM_ACCEPTOR_HPP 11   #define BOOST_COROSIO_NATIVE_NATIVE_LOCAL_STREAM_ACCEPTOR_HPP
12   12  
13   #include <boost/corosio/local_stream_acceptor.hpp> 13   #include <boost/corosio/local_stream_acceptor.hpp>
14   #include <boost/corosio/native/native_local_stream_socket.hpp> 14   #include <boost/corosio/native/native_local_stream_socket.hpp>
15   #include <boost/corosio/backend.hpp> 15   #include <boost/corosio/backend.hpp>
16   16  
17   #ifndef BOOST_COROSIO_MRDOCS 17   #ifndef BOOST_COROSIO_MRDOCS
18   #if BOOST_COROSIO_HAS_EPOLL 18   #if BOOST_COROSIO_HAS_EPOLL
19   #include <boost/corosio/native/detail/epoll/epoll_types.hpp> 19   #include <boost/corosio/native/detail/epoll/epoll_types.hpp>
20   #endif 20   #endif
21   21  
22   #if BOOST_COROSIO_HAS_SELECT 22   #if BOOST_COROSIO_HAS_SELECT
23   #include <boost/corosio/native/detail/select/select_types.hpp> 23   #include <boost/corosio/native/detail/select/select_types.hpp>
24   #endif 24   #endif
25   25  
26   #if BOOST_COROSIO_HAS_KQUEUE 26   #if BOOST_COROSIO_HAS_KQUEUE
27   #include <boost/corosio/native/detail/kqueue/kqueue_types.hpp> 27   #include <boost/corosio/native/detail/kqueue/kqueue_types.hpp>
28   #endif 28   #endif
29   29  
30   #if BOOST_COROSIO_HAS_IO_URING 30   #if BOOST_COROSIO_HAS_IO_URING
31   #include <boost/corosio/native/detail/io_uring/io_uring_types.hpp> 31   #include <boost/corosio/native/detail/io_uring/io_uring_types.hpp>
32   #endif 32   #endif
33   33  
34   #if BOOST_COROSIO_HAS_IOCP 34   #if BOOST_COROSIO_HAS_IOCP
35   #include <boost/corosio/native/detail/iocp/win_local_stream_acceptor_service.hpp> 35   #include <boost/corosio/native/detail/iocp/win_local_stream_acceptor_service.hpp>
36   #endif 36   #endif
37   #endif // !BOOST_COROSIO_MRDOCS 37   #endif // !BOOST_COROSIO_MRDOCS
38   38  
39   namespace boost::corosio { 39   namespace boost::corosio {
40   40  
41   /** An asynchronous Unix stream acceptor with devirtualized accept. 41   /** An asynchronous Unix stream acceptor with devirtualized accept.
42   42  
43   This class template inherits from @ref local_stream_acceptor 43   This class template inherits from @ref local_stream_acceptor
44   and shadows both `accept` overloads (the peer-reference form 44   and shadows both `accept` overloads (the peer-reference form
45   and the move-return form) with versions that call the backend 45   and the move-return form) with versions that call the backend
46   implementation directly, allowing the compiler to inline 46   implementation directly, allowing the compiler to inline
47   through the entire call chain. The move-return form yields a 47   through the entire call chain. The move-return form yields a
48   @ref native_local_stream_socket so subsequent I/O on the peer 48   @ref native_local_stream_socket so subsequent I/O on the peer
49   is also devirtualized. 49   is also devirtualized.
50   50  
51   Non-async operations (`listen`, `close`, `cancel`) remain 51   Non-async operations (`listen`, `close`, `cancel`) remain
52   unchanged and dispatch through the compiled library. 52   unchanged and dispatch through the compiled library.
53   53  
54   A `native_local_stream_acceptor` IS-A `local_stream_acceptor` 54   A `native_local_stream_acceptor` IS-A `local_stream_acceptor`
55   and can be passed to any function expecting 55   and can be passed to any function expecting
56   `local_stream_acceptor&`. 56   `local_stream_acceptor&`.
57   57  
58   @tparam Backend A backend tag value (e.g., `epoll`). 58   @tparam Backend A backend tag value (e.g., `epoll`).
59   59  
60   @par Thread Safety 60   @par Thread Safety
61   Same as @ref local_stream_acceptor. 61   Same as @ref local_stream_acceptor.
62   62  
63   @see local_stream_acceptor, epoll_t, iocp_t 63   @see local_stream_acceptor, epoll_t, iocp_t
64   */ 64   */
65   template<auto Backend> 65   template<auto Backend>
66   class native_local_stream_acceptor : public local_stream_acceptor 66   class native_local_stream_acceptor : public local_stream_acceptor
67   { 67   {
68   using backend_type = decltype(Backend); 68   using backend_type = decltype(Backend);
69   using impl_type = typename backend_type::local_stream_acceptor_type; 69   using impl_type = typename backend_type::local_stream_acceptor_type;
70   using service_type = 70   using service_type =
71   typename backend_type::local_stream_acceptor_service_type; 71   typename backend_type::local_stream_acceptor_service_type;
72   72  
HITCBC 73   8 impl_type& get_impl() noexcept 73   8 impl_type& get_impl() noexcept
74   { 74   {
HITCBC 75   8 return *static_cast<impl_type*>(h_.get()); 75   8 return *static_cast<impl_type*>(h_.get());
76   } 76   }
77   77  
78   struct native_wait_awaitable 78   struct native_wait_awaitable
79   { 79   {
80   native_local_stream_acceptor& acc_; 80   native_local_stream_acceptor& acc_;
81   wait_type w_; 81   wait_type w_;
82   std::stop_token token_; 82   std::stop_token token_;
83   mutable std::error_code ec_; 83   mutable std::error_code ec_;
84   84  
HITCBC 85   2 native_wait_awaitable( 85   2 native_wait_awaitable(
86   native_local_stream_acceptor& acc, wait_type w) noexcept 86   native_local_stream_acceptor& acc, wait_type w) noexcept
HITCBC 87   2 : acc_(acc) 87   2 : acc_(acc)
HITCBC 88   2 , w_(w) 88   2 , w_(w)
89   { 89   {
HITCBC 90   2 } 90   2 }
91   91  
HITCBC 92   2 bool await_ready() const noexcept 92   2 bool await_ready() const noexcept
93   { 93   {
HITCBC 94   2 return token_.stop_requested(); 94   2 return token_.stop_requested();
95   } 95   }
96   96  
HITCBC 97   2 capy::io_result<> await_resume() const noexcept 97   2 capy::io_result<> await_resume() const noexcept
98   { 98   {
HITCBC 99   2 if (token_.stop_requested()) 99   2 if (token_.stop_requested())
MISUBC 100   return {make_error_code(std::errc::operation_canceled)}; 100   return {make_error_code(std::errc::operation_canceled)};
HITCBC 101   2 return {ec_}; 101   2 return {ec_};
102   } 102   }
103   103  
HITCBC 104   2 auto await_suspend(std::coroutine_handle<> h, capy::io_env const* env) 104   2 auto await_suspend(std::coroutine_handle<> h, capy::io_env const* env)
105   -> std::coroutine_handle<> 105   -> std::coroutine_handle<>
106   { 106   {
HITCBC 107   2 token_ = env->stop_token; 107   2 token_ = env->stop_token;
HITCBC 108   6 return acc_.get_impl().wait( 108   6 return acc_.get_impl().wait(
HITCBC 109   6 h, env->executor, w_, token_, &ec_); 109   6 h, env->executor, w_, token_, &ec_);
110   } 110   }
111   }; 111   };
112   112  
113   struct native_accept_awaitable 113   struct native_accept_awaitable
114   { 114   {
115   native_local_stream_acceptor& acc_; 115   native_local_stream_acceptor& acc_;
116   local_stream_socket& peer_; 116   local_stream_socket& peer_;
117   std::stop_token token_; 117   std::stop_token token_;
118   mutable std::error_code ec_; 118   mutable std::error_code ec_;
119   mutable io_object::implementation* peer_impl_ = nullptr; 119   mutable io_object::implementation* peer_impl_ = nullptr;
120   120  
HITCBC 121   4 native_accept_awaitable( 121   4 native_accept_awaitable(
122   native_local_stream_acceptor& acc, 122   native_local_stream_acceptor& acc,
123   local_stream_socket& peer) noexcept 123   local_stream_socket& peer) noexcept
HITCBC 124   4 : acc_(acc) 124   4 : acc_(acc)
HITCBC 125   4 , peer_(peer) 125   4 , peer_(peer)
126   { 126   {
HITCBC 127   4 } 127   4 }
128   128  
HITCBC 129   4 bool await_ready() const noexcept 129   4 bool await_ready() const noexcept
130   { 130   {
HITCBC 131   4 return token_.stop_requested(); 131   4 return token_.stop_requested();
132   } 132   }
133   133  
HITCBC 134   4 capy::io_result<> await_resume() const noexcept 134   4 capy::io_result<> await_resume() const noexcept
135   { 135   {
HITCBC 136   4 if (token_.stop_requested()) 136   4 if (token_.stop_requested())
MISUBC 137   return {make_error_code(std::errc::operation_canceled)}; 137   return {make_error_code(std::errc::operation_canceled)};
HITCBC 138   4 if (!ec_) 138   4 if (!ec_)
HITCBC 139   4 acc_.reset_peer_impl(peer_, peer_impl_); 139   4 acc_.reset_peer_impl(peer_, peer_impl_);
HITCBC 140   4 return {ec_}; 140   4 return {ec_};
141   } 141   }
142   142  
HITCBC 143   4 auto await_suspend(std::coroutine_handle<> h, capy::io_env const* env) 143   4 auto await_suspend(std::coroutine_handle<> h, capy::io_env const* env)
144   -> std::coroutine_handle<> 144   -> std::coroutine_handle<>
145   { 145   {
HITCBC 146   4 token_ = env->stop_token; 146   4 token_ = env->stop_token;
HITCBC 147   12 return acc_.get_impl().accept( 147   12 return acc_.get_impl().accept(
HITCBC 148   12 h, env->executor, token_, &ec_, &peer_impl_); 148   12 h, env->executor, token_, &ec_, &peer_impl_);
149   } 149   }
150   }; 150   };
151   151  
152   struct native_move_accept_awaitable 152   struct native_move_accept_awaitable
153   { 153   {
154   native_local_stream_acceptor& acc_; 154   native_local_stream_acceptor& acc_;
155   std::stop_token token_; 155   std::stop_token token_;
156   mutable std::error_code ec_; 156   mutable std::error_code ec_;
157   mutable io_object::implementation* peer_impl_ = nullptr; 157   mutable io_object::implementation* peer_impl_ = nullptr;
158   158  
HITCBC 159   2 explicit native_move_accept_awaitable( 159   2 explicit native_move_accept_awaitable(
160   native_local_stream_acceptor& acc) noexcept 160   native_local_stream_acceptor& acc) noexcept
HITCBC 161   2 : acc_(acc) 161   2 : acc_(acc)
162   { 162   {
HITCBC 163   2 } 163   2 }
164   164  
HITCBC 165   2 bool await_ready() const noexcept 165   2 bool await_ready() const noexcept
166   { 166   {
HITCBC 167   2 return token_.stop_requested(); 167   2 return token_.stop_requested();
168   } 168   }
169   169  
170   capy::io_result<native_local_stream_socket<Backend>> 170   capy::io_result<native_local_stream_socket<Backend>>
HITCBC 171   2 await_resume() const noexcept 171   2 await_resume() const noexcept
172   { 172   {
HITCBC 173   2 if (token_.stop_requested()) 173   2 if (token_.stop_requested())
174   return { 174   return {
MISUBC 175   make_error_code(std::errc::operation_canceled), 175   make_error_code(std::errc::operation_canceled),
MISUBC 176   native_local_stream_socket<Backend>(acc_.context())}; 176   native_local_stream_socket<Backend>(acc_.context())};
HITCBC 177   2 if (ec_ || !peer_impl_) 177   2 if (ec_ || !peer_impl_)
178   return { 178   return {
179   ec_, 179   ec_,
MISUBC 180   native_local_stream_socket<Backend>(acc_.context())}; 180   native_local_stream_socket<Backend>(acc_.context())};
181   181  
HITCBC 182   2 native_local_stream_socket<Backend> peer(acc_.context()); 182   2 native_local_stream_socket<Backend> peer(acc_.context());
HITCBC 183   2 acc_.reset_peer_impl(peer, peer_impl_); 183   2 acc_.reset_peer_impl(peer, peer_impl_);
HITCBC 184   2 return {ec_, std::move(peer)}; 184   2 return {ec_, std::move(peer)};
HITCBC 185   2 } 185   2 }
186   186  
HITCBC 187   2 auto await_suspend(std::coroutine_handle<> h, capy::io_env const* env) 187   2 auto await_suspend(std::coroutine_handle<> h, capy::io_env const* env)
188   -> std::coroutine_handle<> 188   -> std::coroutine_handle<>
189   { 189   {
HITCBC 190   2 token_ = env->stop_token; 190   2 token_ = env->stop_token;
HITCBC 191   6 return acc_.get_impl().accept( 191   6 return acc_.get_impl().accept(
HITCBC 192   6 h, env->executor, token_, &ec_, &peer_impl_); 192   6 h, env->executor, token_, &ec_, &peer_impl_);
193   } 193   }
194   }; 194   };
195   195  
196   public: 196   public:
197   /** Construct a native acceptor from an execution context. 197   /** Construct a native acceptor from an execution context.
198   198  
199   @param ctx The execution context that will own this acceptor. 199   @param ctx The execution context that will own this acceptor.
200   */ 200   */
HITCBC 201   12 explicit native_local_stream_acceptor(capy::execution_context& ctx) 201   12 explicit native_local_stream_acceptor(capy::execution_context& ctx)
HITCBC 202   12 : local_stream_acceptor(create_handle<service_type>(ctx), ctx) 202   12 : local_stream_acceptor(create_handle<service_type>(ctx), ctx)
203   { 203   {
HITCBC 204   12 } 204   12 }
205   205  
206   /** Construct a native acceptor from an executor. 206   /** Construct a native acceptor from an executor.
207   207  
208   @param ex The executor whose context will own the acceptor. 208   @param ex The executor whose context will own the acceptor.
209   */ 209   */
210   template<class Ex> 210   template<class Ex>
211   requires(!std::same_as< 211   requires(!std::same_as<
212   std::remove_cvref_t<Ex>, 212   std::remove_cvref_t<Ex>,
213   native_local_stream_acceptor>) && 213   native_local_stream_acceptor>) &&
214   capy::Executor<Ex> 214   capy::Executor<Ex>
215   explicit native_local_stream_acceptor(Ex const& ex) 215   explicit native_local_stream_acceptor(Ex const& ex)
216   : native_local_stream_acceptor(ex.context()) 216   : native_local_stream_acceptor(ex.context())
217   { 217   {
218   } 218   }
219   219  
220   /// Move construct. 220   /// Move construct.
221   native_local_stream_acceptor(native_local_stream_acceptor&&) noexcept = 221   native_local_stream_acceptor(native_local_stream_acceptor&&) noexcept =
222   default; 222   default;
223   223  
224   /// Move assign. 224   /// Move assign.
225   native_local_stream_acceptor& 225   native_local_stream_acceptor&
226   operator=(native_local_stream_acceptor&&) noexcept = default; 226   operator=(native_local_stream_acceptor&&) noexcept = default;
227   227  
228   native_local_stream_acceptor(native_local_stream_acceptor const&) = delete; 228   native_local_stream_acceptor(native_local_stream_acceptor const&) = delete;
229   native_local_stream_acceptor& 229   native_local_stream_acceptor&
230   operator=(native_local_stream_acceptor const&) = delete; 230   operator=(native_local_stream_acceptor const&) = delete;
231   231  
232   /** Asynchronously accept an incoming connection. 232   /** Asynchronously accept an incoming connection.
233   233  
234   Calls the backend implementation directly, bypassing virtual 234   Calls the backend implementation directly, bypassing virtual
235   dispatch. Otherwise identical to @ref local_stream_acceptor::accept. 235   dispatch. Otherwise identical to @ref local_stream_acceptor::accept.
236   236  
237   @param peer The socket to receive the accepted connection. 237   @param peer The socket to receive the accepted connection.
238   238  
239   @return An awaitable yielding `io_result<>`. 239   @return An awaitable yielding `io_result<>`.
240   240  
241   @throws std::logic_error if the acceptor is not listening. 241   @throws std::logic_error if the acceptor is not listening.
242   242  
243   Both this acceptor and @p peer must outlive the returned 243   Both this acceptor and @p peer must outlive the returned
244   awaitable. 244   awaitable.
245   */ 245   */
HITCBC 246   6 auto accept(local_stream_socket& peer) 246   6 auto accept(local_stream_socket& peer)
247   { 247   {
HITCBC 248   6 if (!is_open()) 248   6 if (!is_open())
HITCBC 249   2 detail::throw_logic_error("accept: acceptor not listening"); 249   2 detail::throw_logic_error("accept: acceptor not listening");
HITCBC 250   4 return native_accept_awaitable(*this, peer); 250   4 return native_accept_awaitable(*this, peer);
251   } 251   }
252   252  
253   /** Asynchronously accept an incoming connection, returning the peer. 253   /** Asynchronously accept an incoming connection, returning the peer.
254   254  
255   Calls the backend implementation directly, bypassing virtual 255   Calls the backend implementation directly, bypassing virtual
256   dispatch. The accepted peer is returned as a 256   dispatch. The accepted peer is returned as a
257   @ref native_local_stream_socket so that subsequent I/O on it 257   @ref native_local_stream_socket so that subsequent I/O on it
258   is also devirtualized. 258   is also devirtualized.
259   259  
260   @return An awaitable yielding 260   @return An awaitable yielding
261   `io_result<native_local_stream_socket<Backend>>`. 261   `io_result<native_local_stream_socket<Backend>>`.
262   262  
263   @throws std::logic_error if the acceptor is not listening. 263   @throws std::logic_error if the acceptor is not listening.
264   264  
265   This acceptor must outlive the returned awaitable. 265   This acceptor must outlive the returned awaitable.
266   */ 266   */
HITCBC 267   4 auto accept() 267   4 auto accept()
268   { 268   {
HITCBC 269   4 if (!is_open()) 269   4 if (!is_open())
HITCBC 270   2 detail::throw_logic_error("accept: acceptor not listening"); 270   2 detail::throw_logic_error("accept: acceptor not listening");
HITCBC 271   2 return native_move_accept_awaitable(*this); 271   2 return native_move_accept_awaitable(*this);
272   } 272   }
273   273  
274   /** Asynchronously wait for the acceptor to be ready. 274   /** Asynchronously wait for the acceptor to be ready.
275   275  
276   Calls the backend implementation directly, bypassing virtual 276   Calls the backend implementation directly, bypassing virtual
277   dispatch. Otherwise identical to @ref local_stream_acceptor::wait. 277   dispatch. Otherwise identical to @ref local_stream_acceptor::wait.
278   278  
279   @param w The wait direction (typically `wait_type::read`). 279   @param w The wait direction (typically `wait_type::read`).
280   280  
281   @return An awaitable yielding `io_result<>`. 281   @return An awaitable yielding `io_result<>`.
282   */ 282   */
HITCBC 283   2 [[nodiscard]] auto wait(wait_type w) 283   2 [[nodiscard]] auto wait(wait_type w)
284   { 284   {
HITCBC 285   2 return native_wait_awaitable(*this, w); 285   2 return native_wait_awaitable(*this, w);
286   } 286   }
287   }; 287   };
288   288  
289   } // namespace boost::corosio 289   } // namespace boost::corosio
290   290  
291   #endif // BOOST_COROSIO_NATIVE_NATIVE_LOCAL_STREAM_ACCEPTOR_HPP 291   #endif // BOOST_COROSIO_NATIVE_NATIVE_LOCAL_STREAM_ACCEPTOR_HPP