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 -
#ifndef BOOST_COROSIO_MRDOCS
 
16  

15  

17  
#if BOOST_COROSIO_HAS_EPOLL
16  
#if BOOST_COROSIO_HAS_EPOLL
18  
#include <boost/corosio/native/detail/epoll/epoll_acceptor_service.hpp>
17  
#include <boost/corosio/native/detail/epoll/epoll_acceptor_service.hpp>
19  
#endif
18  
#endif
20  

19  

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

23  

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

27  

29  
#if BOOST_COROSIO_HAS_IOCP
28  
#if BOOST_COROSIO_HAS_IOCP
30  
#include <boost/corosio/native/detail/iocp/win_acceptor_service.hpp>
29  
#include <boost/corosio/native/detail/iocp/win_acceptor_service.hpp>
31 -
#endif // !BOOST_COROSIO_MRDOCS
 
32  
#endif
30  
#endif
33  

31  

34  
namespace boost::corosio {
32  
namespace boost::corosio {
35  

33  

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

35  

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

40  

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

43  

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

46  

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

48  

51  
    @par Thread Safety
49  
    @par Thread Safety
52  
    Same as @ref tcp_acceptor.
50  
    Same as @ref tcp_acceptor.
53  

51  

54  
    @see tcp_acceptor, epoll_t, iocp_t
52  
    @see tcp_acceptor, epoll_t, iocp_t
55  
*/
53  
*/
56  
template<auto Backend>
54  
template<auto Backend>
57  
class native_tcp_acceptor : public tcp_acceptor
55  
class native_tcp_acceptor : public tcp_acceptor
58  
{
56  
{
59  
    using backend_type = decltype(Backend);
57  
    using backend_type = decltype(Backend);
60  
    using impl_type    = typename backend_type::acceptor_type;
58  
    using impl_type    = typename backend_type::acceptor_type;
61  
    using service_type = typename backend_type::acceptor_service_type;
59  
    using service_type = typename backend_type::acceptor_service_type;
62  

60  

63  
    impl_type& get_impl() noexcept
61  
    impl_type& get_impl() noexcept
64  
    {
62  
    {
65  
        return *static_cast<impl_type*>(h_.get());
63  
        return *static_cast<impl_type*>(h_.get());
66  
    }
64  
    }
67  

65  

68  
    struct native_accept_awaitable
66  
    struct native_accept_awaitable
69  
    {
67  
    {
70  
        native_tcp_acceptor& acc_;
68  
        native_tcp_acceptor& acc_;
71  
        tcp_socket& peer_;
69  
        tcp_socket& peer_;
72  
        std::stop_token token_;
70  
        std::stop_token token_;
73  
        mutable std::error_code ec_;
71  
        mutable std::error_code ec_;
74  
        mutable io_object::implementation* peer_impl_ = nullptr;
72  
        mutable io_object::implementation* peer_impl_ = nullptr;
75  

73  

76  
        native_accept_awaitable(
74  
        native_accept_awaitable(
77  
            native_tcp_acceptor& acc, tcp_socket& peer) noexcept
75  
            native_tcp_acceptor& acc, tcp_socket& peer) noexcept
78  
            : acc_(acc)
76  
            : acc_(acc)
79  
            , peer_(peer)
77  
            , peer_(peer)
80  
        {
78  
        {
81  
        }
79  
        }
82  

80  

83  
        bool await_ready() const noexcept
81  
        bool await_ready() const noexcept
84  
        {
82  
        {
85  
            return token_.stop_requested();
83  
            return token_.stop_requested();
86  
        }
84  
        }
87  

85  

88  
        capy::io_result<> await_resume() const noexcept
86  
        capy::io_result<> await_resume() const noexcept
89  
        {
87  
        {
90  
            if (token_.stop_requested())
88  
            if (token_.stop_requested())
91  
                return {make_error_code(std::errc::operation_canceled)};
89  
                return {make_error_code(std::errc::operation_canceled)};
92  
            if (!ec_)
90  
            if (!ec_)
93  
                acc_.reset_peer_impl(peer_, peer_impl_);
91  
                acc_.reset_peer_impl(peer_, peer_impl_);
94  
            return {ec_};
92  
            return {ec_};
95  
        }
93  
        }
96  

94  

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

103  

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

106  

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

113  

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

115  

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

125  

128  
    /** Move construct.
126  
    /** Move construct.
129  

127  

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

129  

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

135  

138  
    /** Move assign.
136  
    /** Move assign.
139  

137  

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

139  

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

146  

149  
    native_tcp_acceptor(native_tcp_acceptor const&)            = delete;
147  
    native_tcp_acceptor(native_tcp_acceptor const&)            = delete;
150  
    native_tcp_acceptor& operator=(native_tcp_acceptor const&) = delete;
148  
    native_tcp_acceptor& operator=(native_tcp_acceptor const&) = delete;
151  

149  

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

151  

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

154  

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

156  

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

158  

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

160  

163  
        Both this acceptor and @p peer must outlive the returned
161  
        Both this acceptor and @p peer must outlive the returned
164  
        awaitable.
162  
        awaitable.
165  
    */
163  
    */
166  
    auto accept(tcp_socket& peer)
164  
    auto accept(tcp_socket& peer)
167  
    {
165  
    {
168  
        if (!is_open())
166  
        if (!is_open())
169  
            detail::throw_logic_error("accept: acceptor not listening");
167  
            detail::throw_logic_error("accept: acceptor not listening");
170  
        return native_accept_awaitable(*this, peer);
168  
        return native_accept_awaitable(*this, peer);
171  
    }
169  
    }
172  
};
170  
};
173  

171  

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

173  

176  
#endif
174  
#endif