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