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  
HITGIC 69   impl_type& get_impl() noexcept 69   8 impl_type& get_impl() noexcept
70   { 70   {
HITGIC 71   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  
HITGIC 81   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
HITGIC 83   : acc_(acc) 83   2 : acc_(acc)
HITGIC 84   , w_(w) 84   2 , w_(w)
85   { 85   {
HITGIC 86   } 86   2 }
87   87  
HITGIC 88   bool await_ready() const noexcept 88   2 bool await_ready() const noexcept
89   { 89   {
HITGIC 90   return token_.stop_requested(); 90   2 return token_.stop_requested();
91   } 91   }
92   92  
HITGIC 93   capy::io_result<> await_resume() const noexcept 93   2 capy::io_result<> await_resume() const noexcept
94   { 94   {
HITGIC 95   if (token_.stop_requested()) 95   2 if (token_.stop_requested())
MISUIC 96   return {make_error_code(std::errc::operation_canceled)}; 96   return {make_error_code(std::errc::operation_canceled)};
HITGIC 97   return {ec_}; 97   2 return {ec_};
98   } 98   }
99   99  
HITGIC 100   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   {
HITGIC 103   token_ = env->stop_token; 103   2 token_ = env->stop_token;
HITGIC 104   return acc_.get_impl().wait( 104   6 return acc_.get_impl().wait(
HITGIC 105   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  
HITGIC 117   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
HITGIC 120   : acc_(acc) 120   4 : acc_(acc)
HITGIC 121   , peer_(peer) 121   4 , peer_(peer)
122   { 122   {
HITGIC 123   } 123   4 }
124   124  
HITGIC 125   bool await_ready() const noexcept 125   4 bool await_ready() const noexcept
126   { 126   {
HITGIC 127   return token_.stop_requested(); 127   4 return token_.stop_requested();
128   } 128   }
129   129  
HITGIC 130   capy::io_result<> await_resume() const noexcept 130   4 capy::io_result<> await_resume() const noexcept
131   { 131   {
HITGIC 132   if (token_.stop_requested()) 132   4 if (token_.stop_requested())
MISUIC 133   return {make_error_code(std::errc::operation_canceled)}; 133   return {make_error_code(std::errc::operation_canceled)};
HITGIC 134   if (!ec_) 134   4 if (!ec_)
HITGIC 135   acc_.reset_peer_impl(peer_, peer_impl_); 135   4 acc_.reset_peer_impl(peer_, peer_impl_);
HITGIC 136   return {ec_}; 136   4 return {ec_};
137   } 137   }
138   138  
HITGIC 139   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   {
HITGIC 142   token_ = env->stop_token; 142   4 token_ = env->stop_token;
HITGIC 143   return acc_.get_impl().accept( 143   12 return acc_.get_impl().accept(
HITGIC 144   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  
HITGIC 155   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
HITGIC 157   : acc_(acc) 157   2 : acc_(acc)
158   { 158   {
HITGIC 159   } 159   2 }
160   160  
HITGIC 161   bool await_ready() const noexcept 161   2 bool await_ready() const noexcept
162   { 162   {
HITGIC 163   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>>
HITGIC 167   await_resume() const noexcept 167   2 await_resume() const noexcept
168   { 168   {
HITGIC 169   if (token_.stop_requested()) 169   2 if (token_.stop_requested())
170   return { 170   return {
MISUIC 171   make_error_code(std::errc::operation_canceled), 171   make_error_code(std::errc::operation_canceled),
MISUIC 172   native_local_stream_socket<Backend>(acc_.context())}; 172   native_local_stream_socket<Backend>(acc_.context())};
HITGIC 173   if (ec_ || !peer_impl_) 173   2 if (ec_ || !peer_impl_)
174   return { 174   return {
175   ec_, 175   ec_,
MISUIC 176   native_local_stream_socket<Backend>(acc_.context())}; 176   native_local_stream_socket<Backend>(acc_.context())};
177   177  
HITGIC 178   native_local_stream_socket<Backend> peer(acc_.context()); 178   2 native_local_stream_socket<Backend> peer(acc_.context());
HITGIC 179   acc_.reset_peer_impl(peer, peer_impl_); 179   2 acc_.reset_peer_impl(peer, peer_impl_);
HITGIC 180   return {ec_, std::move(peer)}; 180   2 return {ec_, std::move(peer)};
HITGIC 181   } 181   2 }
182   182  
HITGIC 183   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   {
HITGIC 186   token_ = env->stop_token; 186   2 token_ = env->stop_token;
HITGIC 187   return acc_.get_impl().accept( 187   6 return acc_.get_impl().accept(
HITGIC 188   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   */
HITGIC 197   explicit native_local_stream_acceptor(capy::execution_context& ctx) 197   12 explicit native_local_stream_acceptor(capy::execution_context& ctx)
HITGIC 198   : local_stream_acceptor(create_handle<service_type>(ctx), ctx) 198   12 : local_stream_acceptor(create_handle<service_type>(ctx), ctx)
199   { 199   {
HITGIC 200   } 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   */
HITGIC 242   auto accept(local_stream_socket& peer) 242   6 auto accept(local_stream_socket& peer)
243   { 243   {
HITGIC 244   if (!is_open()) 244   6 if (!is_open())
HITGIC 245   detail::throw_logic_error("accept: acceptor not listening"); 245   2 detail::throw_logic_error("accept: acceptor not listening");
HITGIC 246   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   */
HITGIC 263   auto accept() 263   4 auto accept()
264   { 264   {
HITGIC 265   if (!is_open()) 265   4 if (!is_open())
HITGIC 266   detail::throw_logic_error("accept: acceptor not listening"); 266   2 detail::throw_logic_error("accept: acceptor not listening");
HITGIC 267   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   */
HITGIC 279   [[nodiscard]] auto wait(wait_type w) 279   2 [[nodiscard]] auto wait(wait_type w)
280   { 280   {
HITGIC 281   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