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 -
#if BOOST_COROSIO_HAS_EPOLL
 
17 -
#include <boost/corosio/native/detail/epoll/epoll_tcp_acceptor_service.hpp>
 
18 -
#endif
 
19 -

 
20 -
#if BOOST_COROSIO_HAS_SELECT
 
21 -
#include <boost/corosio/native/detail/select/select_tcp_acceptor_service.hpp>
 
22 -
#endif
 
23 -

 
24 -
#if BOOST_COROSIO_HAS_KQUEUE
 
25 -
#include <boost/corosio/native/detail/kqueue/kqueue_tcp_acceptor_service.hpp>
 
26 -
#endif
 
27 -

 
28  
#ifndef BOOST_COROSIO_MRDOCS
16  
#ifndef BOOST_COROSIO_MRDOCS
29  
#if BOOST_COROSIO_HAS_IOCP
17  
#if BOOST_COROSIO_HAS_IOCP
30  
#include <boost/corosio/native/detail/iocp/win_tcp_acceptor_service.hpp>
18  
#include <boost/corosio/native/detail/iocp/win_tcp_acceptor_service.hpp>
31  
#endif
19  
#endif
32  
#endif // !BOOST_COROSIO_MRDOCS
20  
#endif // !BOOST_COROSIO_MRDOCS
33  

21  

34  
namespace boost::corosio {
22  
namespace boost::corosio {
35  

23  

36  
/** An asynchronous TCP acceptor with devirtualized accept operations.
24  
/** An asynchronous TCP acceptor with devirtualized accept operations.
37  

25  

38  
    This class template inherits from @ref tcp_acceptor and shadows
26  
    This class template inherits from @ref tcp_acceptor and shadows
39  
    the `accept` operation with a version that calls the backend
27  
    the `accept` operation with a version that calls the backend
40  
    implementation directly, allowing the compiler to inline through
28  
    implementation directly, allowing the compiler to inline through
41  
    the entire call chain.
29  
    the entire call chain.
42  

30  

43  
    Non-async operations (`listen`, `close`, `cancel`) remain
31  
    Non-async operations (`listen`, `close`, `cancel`) remain
44  
    unchanged and dispatch through the compiled library.
32  
    unchanged and dispatch through the compiled library.
45  

33  

46  
    A `native_tcp_acceptor` IS-A `tcp_acceptor` and can be passed
34  
    A `native_tcp_acceptor` IS-A `tcp_acceptor` and can be passed
47  
    to any function expecting `tcp_acceptor&`.
35  
    to any function expecting `tcp_acceptor&`.
48  

36  

49  
    @tparam Backend A backend tag value (e.g., `epoll`).
37  
    @tparam Backend A backend tag value (e.g., `epoll`).
50  

38  

51  
    @par Thread Safety
39  
    @par Thread Safety
52  
    Same as @ref tcp_acceptor.
40  
    Same as @ref tcp_acceptor.
53  

41  

54  
    @see tcp_acceptor, epoll_t, iocp_t
42  
    @see tcp_acceptor, epoll_t, iocp_t
55  
*/
43  
*/
56  
template<auto Backend>
44  
template<auto Backend>
57  
class native_tcp_acceptor : public tcp_acceptor
45  
class native_tcp_acceptor : public tcp_acceptor
58  
{
46  
{
59  
    using backend_type = decltype(Backend);
47  
    using backend_type = decltype(Backend);
60  
    using impl_type    = typename backend_type::tcp_acceptor_type;
48  
    using impl_type    = typename backend_type::tcp_acceptor_type;
61  
    using service_type = typename backend_type::tcp_acceptor_service_type;
49  
    using service_type = typename backend_type::tcp_acceptor_service_type;
62  

50  

63  
    impl_type& get_impl() noexcept
51  
    impl_type& get_impl() noexcept
64  
    {
52  
    {
65  
        return *static_cast<impl_type*>(h_.get());
53  
        return *static_cast<impl_type*>(h_.get());
66  
    }
54  
    }
67  

55  

68  
    struct native_accept_awaitable
56  
    struct native_accept_awaitable
69  
    {
57  
    {
70  
        native_tcp_acceptor& acc_;
58  
        native_tcp_acceptor& acc_;
71  
        tcp_socket& peer_;
59  
        tcp_socket& peer_;
72  
        std::stop_token token_;
60  
        std::stop_token token_;
73  
        mutable std::error_code ec_;
61  
        mutable std::error_code ec_;
74  
        mutable io_object::implementation* peer_impl_ = nullptr;
62  
        mutable io_object::implementation* peer_impl_ = nullptr;
75  

63  

76  
        native_accept_awaitable(
64  
        native_accept_awaitable(
77  
            native_tcp_acceptor& acc, tcp_socket& peer) noexcept
65  
            native_tcp_acceptor& acc, tcp_socket& peer) noexcept
78  
            : acc_(acc)
66  
            : acc_(acc)
79  
            , peer_(peer)
67  
            , peer_(peer)
80  
        {
68  
        {
81  
        }
69  
        }
82  

70  

83  
        bool await_ready() const noexcept
71  
        bool await_ready() const noexcept
84  
        {
72  
        {
85  
            return token_.stop_requested();
73  
            return token_.stop_requested();
86  
        }
74  
        }
87  

75  

88  
        capy::io_result<> await_resume() const noexcept
76  
        capy::io_result<> await_resume() const noexcept
89  
        {
77  
        {
90  
            if (token_.stop_requested())
78  
            if (token_.stop_requested())
91  
                return {make_error_code(std::errc::operation_canceled)};
79  
                return {make_error_code(std::errc::operation_canceled)};
92  
            if (!ec_)
80  
            if (!ec_)
93  
                acc_.reset_peer_impl(peer_, peer_impl_);
81  
                acc_.reset_peer_impl(peer_, peer_impl_);
94  
            return {ec_};
82  
            return {ec_};
95  
        }
83  
        }
96  

84  

97  
        auto await_suspend(std::coroutine_handle<> h, capy::io_env const* env)
85  
        auto await_suspend(std::coroutine_handle<> h, capy::io_env const* env)
98  
            -> std::coroutine_handle<>
86  
            -> std::coroutine_handle<>
99  
        {
87  
        {
100  
            token_ = env->stop_token;
88  
            token_ = env->stop_token;
101  
            return acc_.get_impl().accept(
89  
            return acc_.get_impl().accept(
102  
                h, env->executor, token_, &ec_, &peer_impl_);
90  
                h, env->executor, token_, &ec_, &peer_impl_);
103  
        }
91  
        }
104  
    };
92  
    };
105  

93  

106  
public:
94  
public:
107  
    /** Construct a native acceptor from an execution context.
95  
    /** Construct a native acceptor from an execution context.
108  

96  

109  
        @param ctx The execution context that will own this acceptor.
97  
        @param ctx The execution context that will own this acceptor.
110  
    */
98  
    */
111  
    explicit native_tcp_acceptor(capy::execution_context& ctx)
99  
    explicit native_tcp_acceptor(capy::execution_context& ctx)
112  
        : tcp_acceptor(create_handle<service_type>(ctx))
100  
        : tcp_acceptor(create_handle<service_type>(ctx))
113  
    {
101  
    {
114  
    }
102  
    }
115  

103  

116  
    /** Construct a native acceptor from an executor.
104  
    /** Construct a native acceptor from an executor.
117  

105  

118  
        @param ex The executor whose context will own the acceptor.
106  
        @param ex The executor whose context will own the acceptor.
119  
    */
107  
    */
120  
    template<class Ex>
108  
    template<class Ex>
121  
        requires(!std::same_as<std::remove_cvref_t<Ex>, native_tcp_acceptor>) &&
109  
        requires(!std::same_as<std::remove_cvref_t<Ex>, native_tcp_acceptor>) &&
122  
        capy::Executor<Ex>
110  
        capy::Executor<Ex>
123  
    explicit native_tcp_acceptor(Ex const& ex)
111  
    explicit native_tcp_acceptor(Ex const& ex)
124  
        : native_tcp_acceptor(ex.context())
112  
        : native_tcp_acceptor(ex.context())
125  
    {
113  
    {
126  
    }
114  
    }
127  

115  

128  
    /** Move construct.
116  
    /** Move construct.
129  

117  

130  
        @param other The acceptor to move from.
118  
        @param other The acceptor to move from.
131  

119  

132  
        @pre No awaitables returned by @p other's methods exist.
120  
        @pre No awaitables returned by @p other's methods exist.
133  
        @pre The execution context associated with @p other must
121  
        @pre The execution context associated with @p other must
134  
            outlive this acceptor.
122  
            outlive this acceptor.
135  
    */
123  
    */
136  
    native_tcp_acceptor(native_tcp_acceptor&&) noexcept = default;
124  
    native_tcp_acceptor(native_tcp_acceptor&&) noexcept = default;
137  

125  

138  
    /** Move assign.
126  
    /** Move assign.
139  

127  

140  
        @param other The acceptor to move from.
128  
        @param other The acceptor to move from.
141  

129  

142  
        @pre No awaitables returned by either `*this` or @p other's
130  
        @pre No awaitables returned by either `*this` or @p other's
143  
            methods exist.
131  
            methods exist.
144  
        @pre The execution context associated with @p other must
132  
        @pre The execution context associated with @p other must
145  
            outlive this acceptor.
133  
            outlive this acceptor.
146  
    */
134  
    */
147  
    native_tcp_acceptor& operator=(native_tcp_acceptor&&) noexcept = default;
135  
    native_tcp_acceptor& operator=(native_tcp_acceptor&&) noexcept = default;
148  

136  

149  
    native_tcp_acceptor(native_tcp_acceptor const&)            = delete;
137  
    native_tcp_acceptor(native_tcp_acceptor const&)            = delete;
150  
    native_tcp_acceptor& operator=(native_tcp_acceptor const&) = delete;
138  
    native_tcp_acceptor& operator=(native_tcp_acceptor const&) = delete;
151  

139  

152  
    /** Asynchronously accept an incoming connection.
140  
    /** Asynchronously accept an incoming connection.
153  

141  

154  
        Calls the backend implementation directly, bypassing virtual
142  
        Calls the backend implementation directly, bypassing virtual
155  
        dispatch. Otherwise identical to @ref tcp_acceptor::accept.
143  
        dispatch. Otherwise identical to @ref tcp_acceptor::accept.
156  

144  

157  
        @param peer The socket to receive the accepted connection.
145  
        @param peer The socket to receive the accepted connection.
158  

146  

159  
        @return An awaitable yielding `io_result<>`.
147  
        @return An awaitable yielding `io_result<>`.
160  

148  

161  
        @throws std::logic_error if the acceptor is not listening.
149  
        @throws std::logic_error if the acceptor is not listening.
162  

150  

163  
        Both this acceptor and @p peer must outlive the returned
151  
        Both this acceptor and @p peer must outlive the returned
164  
        awaitable.
152  
        awaitable.
165  
    */
153  
    */
166  
    auto accept(tcp_socket& peer)
154  
    auto accept(tcp_socket& peer)
167  
    {
155  
    {
168  
        if (!is_open())
156  
        if (!is_open())
169  
            detail::throw_logic_error("accept: acceptor not listening");
157  
            detail::throw_logic_error("accept: acceptor not listening");
170  
        return native_accept_awaitable(*this, peer);
158  
        return native_accept_awaitable(*this, peer);
171  
    }
159  
    }
172  
};
160  
};
173  

161  

174  
} // namespace boost::corosio
162  
} // namespace boost::corosio
175  

163  

176  
#endif
164  
#endif