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

20  

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

24  

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

28  

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

33  

32  
namespace boost::corosio {
34  
namespace boost::corosio {
33  

35  

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

37  

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

42  

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

45  

44  
    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
45  
    to any function expecting `tcp_acceptor&`.
47  
    to any function expecting `tcp_acceptor&`.
46  

48  

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

50  

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

53  

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

62  

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

67  

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

75  

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

82  

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

87  

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

96  

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

105  

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

108  

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

115  

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

117  

116  
        @param ex The executor whose context will own the acceptor.
118  
        @param ex The executor whose context will own the acceptor.
117  
    */
119  
    */
118  
    template<class Ex>
120  
    template<class Ex>
119  
        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>) &&
120  
        capy::Executor<Ex>
122  
        capy::Executor<Ex>
121  
    explicit native_tcp_acceptor(Ex const& ex)
123  
    explicit native_tcp_acceptor(Ex const& ex)
122  
        : native_tcp_acceptor(ex.context())
124  
        : native_tcp_acceptor(ex.context())
123  
    {
125  
    {
124  
    }
126  
    }
125  

127  

126  
    /** Move construct.
128  
    /** Move construct.
127  

129  

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

131  

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

137  

136  
    /** Move assign.
138  
    /** Move assign.
137  

139  

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

141  

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

148  

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

151  

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

153  

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

156  

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

158  

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

160  

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

162  

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

173  

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

175  

174  
#endif
176  
#endif