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