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