92.00% Lines (23/25) 100.00% Functions (7/7)
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   15  
16   #ifndef BOOST_COROSIO_MRDOCS 16   #ifndef BOOST_COROSIO_MRDOCS
17   #if BOOST_COROSIO_HAS_EPOLL 17   #if BOOST_COROSIO_HAS_EPOLL
18   #include <boost/corosio/native/detail/epoll/epoll_types.hpp> 18   #include <boost/corosio/native/detail/epoll/epoll_types.hpp>
19   #endif 19   #endif
20   20  
21   #if BOOST_COROSIO_HAS_SELECT 21   #if BOOST_COROSIO_HAS_SELECT
22   #include <boost/corosio/native/detail/select/select_types.hpp> 22   #include <boost/corosio/native/detail/select/select_types.hpp>
23   #endif 23   #endif
24   24  
25   #if BOOST_COROSIO_HAS_KQUEUE 25   #if BOOST_COROSIO_HAS_KQUEUE
26   #include <boost/corosio/native/detail/kqueue/kqueue_types.hpp> 26   #include <boost/corosio/native/detail/kqueue/kqueue_types.hpp>
27   #endif 27   #endif
28   28  
29   #if BOOST_COROSIO_HAS_IOCP 29   #if BOOST_COROSIO_HAS_IOCP
30   #include <boost/corosio/native/detail/iocp/win_tcp_acceptor_service.hpp> 30   #include <boost/corosio/native/detail/iocp/win_tcp_acceptor_service.hpp>
31   #endif 31   #endif
32   #endif // !BOOST_COROSIO_MRDOCS 32   #endif // !BOOST_COROSIO_MRDOCS
33   33  
34   namespace boost::corosio { 34   namespace boost::corosio {
35   35  
36   /** An asynchronous TCP acceptor with devirtualized accept operations. 36   /** An asynchronous TCP acceptor with devirtualized accept operations.
37   37  
38   This class template inherits from @ref tcp_acceptor and shadows 38   This class template inherits from @ref tcp_acceptor and shadows
39   the `accept` operation with a version that calls the backend 39   the `accept` operation with a version that calls the backend
40   implementation directly, allowing the compiler to inline through 40   implementation directly, allowing the compiler to inline through
41   the entire call chain. 41   the entire call chain.
42   42  
43   Non-async operations (`listen`, `close`, `cancel`) remain 43   Non-async operations (`listen`, `close`, `cancel`) remain
44   unchanged and dispatch through the compiled library. 44   unchanged and dispatch through the compiled library.
45   45  
46   A `native_tcp_acceptor` IS-A `tcp_acceptor` and can be passed 46   A `native_tcp_acceptor` IS-A `tcp_acceptor` and can be passed
47   to any function expecting `tcp_acceptor&`. 47   to any function expecting `tcp_acceptor&`.
48   48  
49   @tparam Backend A backend tag value (e.g., `epoll`). 49   @tparam Backend A backend tag value (e.g., `epoll`).
50   50  
51   @par Thread Safety 51   @par Thread Safety
52   Same as @ref tcp_acceptor. 52   Same as @ref tcp_acceptor.
53   53  
54   @see tcp_acceptor, epoll_t, iocp_t 54   @see tcp_acceptor, epoll_t, iocp_t
55   */ 55   */
56   template<auto Backend> 56   template<auto Backend>
57   class native_tcp_acceptor : public tcp_acceptor 57   class native_tcp_acceptor : public tcp_acceptor
58   { 58   {
59   using backend_type = decltype(Backend); 59   using backend_type = decltype(Backend);
60   using impl_type = typename backend_type::tcp_acceptor_type; 60   using impl_type = typename backend_type::tcp_acceptor_type;
61   using service_type = typename backend_type::tcp_acceptor_service_type; 61   using service_type = typename backend_type::tcp_acceptor_service_type;
62   62  
HITCBC 63   4 impl_type& get_impl() noexcept 63   4 impl_type& get_impl() noexcept
64   { 64   {
HITCBC 65   4 return *static_cast<impl_type*>(h_.get()); 65   4 return *static_cast<impl_type*>(h_.get());
66   } 66   }
67   67  
68   struct native_accept_awaitable 68   struct native_accept_awaitable
69   { 69   {
70   native_tcp_acceptor& acc_; 70   native_tcp_acceptor& acc_;
71   tcp_socket& peer_; 71   tcp_socket& peer_;
72   std::stop_token token_; 72   std::stop_token token_;
73   mutable std::error_code ec_; 73   mutable std::error_code ec_;
74   mutable io_object::implementation* peer_impl_ = nullptr; 74   mutable io_object::implementation* peer_impl_ = nullptr;
75   75  
HITCBC 76   4 native_accept_awaitable( 76   4 native_accept_awaitable(
77   native_tcp_acceptor& acc, tcp_socket& peer) noexcept 77   native_tcp_acceptor& acc, tcp_socket& peer) noexcept
HITCBC 78   4 : acc_(acc) 78   4 : acc_(acc)
HITCBC 79   4 , peer_(peer) 79   4 , peer_(peer)
80   { 80   {
HITCBC 81   4 } 81   4 }
82   82  
HITCBC 83   4 bool await_ready() const noexcept 83   4 bool await_ready() const noexcept
84   { 84   {
HITCBC 85   4 return token_.stop_requested(); 85   4 return token_.stop_requested();
86   } 86   }
87   87  
HITCBC 88   4 capy::io_result<> await_resume() const noexcept 88   4 capy::io_result<> await_resume() const noexcept
89   { 89   {
HITCBC 90   4 if (token_.stop_requested()) 90   4 if (token_.stop_requested())
MISUBC 91   return {make_error_code(std::errc::operation_canceled)}; 91   return {make_error_code(std::errc::operation_canceled)};
HITCBC 92   4 if (!ec_) 92   4 if (!ec_)
HITCBC 93   4 acc_.reset_peer_impl(peer_, peer_impl_); 93   4 acc_.reset_peer_impl(peer_, peer_impl_);
HITCBC 94   4 return {ec_}; 94   4 return {ec_};
95   } 95   }
96   96  
HITCBC 97   4 auto await_suspend(std::coroutine_handle<> h, capy::io_env const* env) 97   4 auto await_suspend(std::coroutine_handle<> h, capy::io_env const* env)
98   -> std::coroutine_handle<> 98   -> std::coroutine_handle<>
99   { 99   {
HITCBC 100   4 token_ = env->stop_token; 100   4 token_ = env->stop_token;
HITCBC 101   12 return acc_.get_impl().accept( 101   12 return acc_.get_impl().accept(
HITCBC 102   12 h, env->executor, token_, &ec_, &peer_impl_); 102   12 h, env->executor, token_, &ec_, &peer_impl_);
103   } 103   }
104   }; 104   };
105   105  
106   public: 106   public:
107   /** Construct a native acceptor from an execution context. 107   /** Construct a native acceptor from an execution context.
108   108  
109   @param ctx The execution context that will own this acceptor. 109   @param ctx The execution context that will own this acceptor.
110   */ 110   */
HITCBC 111   4 explicit native_tcp_acceptor(capy::execution_context& ctx) 111   4 explicit native_tcp_acceptor(capy::execution_context& ctx)
HITCBC 112   4 : tcp_acceptor(create_handle<service_type>(ctx)) 112   4 : tcp_acceptor(create_handle<service_type>(ctx))
113   { 113   {
HITCBC 114   4 } 114   4 }
115   115  
116   /** Construct a native acceptor from an executor. 116   /** Construct a native acceptor from an executor.
117   117  
118   @param ex The executor whose context will own the acceptor. 118   @param ex The executor whose context will own the acceptor.
119   */ 119   */
120   template<class Ex> 120   template<class Ex>
121   requires(!std::same_as<std::remove_cvref_t<Ex>, native_tcp_acceptor>) && 121   requires(!std::same_as<std::remove_cvref_t<Ex>, native_tcp_acceptor>) &&
122   capy::Executor<Ex> 122   capy::Executor<Ex>
123   explicit native_tcp_acceptor(Ex const& ex) 123   explicit native_tcp_acceptor(Ex const& ex)
124   : native_tcp_acceptor(ex.context()) 124   : native_tcp_acceptor(ex.context())
125   { 125   {
126   } 126   }
127   127  
128   /** Move construct. 128   /** Move construct.
129   129  
130   @param other The acceptor to move from. 130   @param other The acceptor to move from.
131   131  
132   @pre No awaitables returned by @p other's methods exist. 132   @pre No awaitables returned by @p other's methods exist.
133   @pre The execution context associated with @p other must 133   @pre The execution context associated with @p other must
134   outlive this acceptor. 134   outlive this acceptor.
135   */ 135   */
136   native_tcp_acceptor(native_tcp_acceptor&&) noexcept = default; 136   native_tcp_acceptor(native_tcp_acceptor&&) noexcept = default;
137   137  
138   /** Move assign. 138   /** Move assign.
139   139  
140   @param other The acceptor to move from. 140   @param other The acceptor to move from.
141   141  
142   @pre No awaitables returned by either `*this` or @p other's 142   @pre No awaitables returned by either `*this` or @p other's
143   methods exist. 143   methods exist.
144   @pre The execution context associated with @p other must 144   @pre The execution context associated with @p other must
145   outlive this acceptor. 145   outlive this acceptor.
146   */ 146   */
147   native_tcp_acceptor& operator=(native_tcp_acceptor&&) noexcept = default; 147   native_tcp_acceptor& operator=(native_tcp_acceptor&&) noexcept = default;
148   148  
149   native_tcp_acceptor(native_tcp_acceptor const&) = delete; 149   native_tcp_acceptor(native_tcp_acceptor const&) = delete;
150   native_tcp_acceptor& operator=(native_tcp_acceptor const&) = delete; 150   native_tcp_acceptor& operator=(native_tcp_acceptor const&) = delete;
151   151  
152   /** Asynchronously accept an incoming connection. 152   /** Asynchronously accept an incoming connection.
153   153  
154   Calls the backend implementation directly, bypassing virtual 154   Calls the backend implementation directly, bypassing virtual
155   dispatch. Otherwise identical to @ref tcp_acceptor::accept. 155   dispatch. Otherwise identical to @ref tcp_acceptor::accept.
156   156  
157   @param peer The socket to receive the accepted connection. 157   @param peer The socket to receive the accepted connection.
158   158  
159   @return An awaitable yielding `io_result<>`. 159   @return An awaitable yielding `io_result<>`.
160   160  
161   @throws std::logic_error if the acceptor is not listening. 161   @throws std::logic_error if the acceptor is not listening.
162   162  
163   Both this acceptor and @p peer must outlive the returned 163   Both this acceptor and @p peer must outlive the returned
164   awaitable. 164   awaitable.
165   */ 165   */
HITCBC 166   4 auto accept(tcp_socket& peer) 166   4 auto accept(tcp_socket& peer)
167   { 167   {
HITCBC 168   4 if (!is_open()) 168   4 if (!is_open())
MISUBC 169   detail::throw_logic_error("accept: acceptor not listening"); 169   detail::throw_logic_error("accept: acceptor not listening");
HITCBC 170   4 return native_accept_awaitable(*this, peer); 170   4 return native_accept_awaitable(*this, peer);
171   } 171   }
172   }; 172   };
173   173  
174   } // namespace boost::corosio 174   } // namespace boost::corosio
175   175  
176   #endif 176   #endif