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_acceptor_service.hpp>
18  
#include <boost/corosio/native/detail/epoll/epoll_acceptor_service.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_acceptor_service.hpp>
22  
#include <boost/corosio/native/detail/select/select_acceptor_service.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_acceptor_service.hpp>
26  
#include <boost/corosio/native/detail/kqueue/kqueue_acceptor_service.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_acceptor_service.hpp>
30  
#include <boost/corosio/native/detail/iocp/win_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::acceptor_type;
60  
    using impl_type    = typename backend_type::acceptor_type;
61  
    using service_type = typename backend_type::acceptor_service_type;
61  
    using service_type = typename backend_type::acceptor_service_type;
62  

62  

63  
    impl_type& get_impl() noexcept
63  
    impl_type& get_impl() noexcept
64  
    {
64  
    {
65  
        return *static_cast<impl_type*>(h_.get());
65  
        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  

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

82  

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

87  

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

96  

97  
        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)
98  
            -> std::coroutine_handle<>
98  
            -> std::coroutine_handle<>
99  
        {
99  
        {
100  
            token_ = env->stop_token;
100  
            token_ = env->stop_token;
101  
            return acc_.get_impl().accept(
101  
            return acc_.get_impl().accept(
102  
                h, env->executor, token_, &ec_, &peer_impl_);
102  
                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  
    */
111  
    explicit native_tcp_acceptor(capy::execution_context& ctx)
111  
    explicit native_tcp_acceptor(capy::execution_context& ctx)
112  
        : tcp_acceptor(create_handle<service_type>(ctx))
112  
        : tcp_acceptor(create_handle<service_type>(ctx))
113  
    {
113  
    {
114  
    }
114  
    }
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  
    */
166  
    auto accept(tcp_socket& peer)
166  
    auto accept(tcp_socket& peer)
167  
    {
167  
    {
168  
        if (!is_open())
168  
        if (!is_open())
169  
            detail::throw_logic_error("accept: acceptor not listening");
169  
            detail::throw_logic_error("accept: acceptor not listening");
170  
        return native_accept_awaitable(*this, peer);
170  
        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