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