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