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