include/boost/corosio/native/detail/iocp/win_tcp_acceptor.hpp
100.0% Lines (2 / 2)
-% Branches (0 / 0)
100.0% Functions (1 / 1)
Functions (1)
Function
Calls
Lines
Branches
Blocks
boost::corosio::detail::win_tcp_acceptor::family() const
:145
2269x
100.0%
–
100.0%
| Line | Branch | TLA | Hits | Source Code |
|---|---|---|---|---|
| 1 | // | |||
| 2 | // Copyright (c) 2025 Vinnie Falco ([email protected]) | |||
| 3 | // Copyright (c) 2026 Steve Gerbino | |||
| 4 | // | |||
| 5 | // Distributed under the Boost Software License, Version 1.0. (See accompanying | |||
| 6 | // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) | |||
| 7 | // | |||
| 8 | // Official repository: https://github.com/cppalliance/corosio | |||
| 9 | // | |||
| 10 | ||||
| 11 | #ifndef BOOST_COROSIO_NATIVE_DETAIL_IOCP_WIN_TCP_ACCEPTOR_HPP | |||
| 12 | #define BOOST_COROSIO_NATIVE_DETAIL_IOCP_WIN_TCP_ACCEPTOR_HPP | |||
| 13 | ||||
| 14 | #include <boost/corosio/native/detail/endpoint_convert.hpp> | |||
| 15 | #include <boost/corosio/detail/platform.hpp> | |||
| 16 | ||||
| 17 | #if BOOST_COROSIO_HAS_IOCP | |||
| 18 | ||||
| 19 | #include <boost/corosio/tcp_acceptor.hpp> | |||
| 20 | #include <boost/corosio/wait_type.hpp> | |||
| 21 | #include <boost/capy/continuation.hpp> | |||
| 22 | #include <boost/capy/ex/executor_ref.hpp> | |||
| 23 | #include <boost/corosio/detail/object_ref.hpp> | |||
| 24 | #include <boost/corosio/detail/intrusive.hpp> | |||
| 25 | #include <boost/corosio/native/detail/iocp/win_overlapped_op.hpp> | |||
| 26 | #include <boost/corosio/native/detail/iocp/win_windows.hpp> | |||
| 27 | ||||
| 28 | #include <coroutine> | |||
| 29 | ||||
| 30 | #include <ws2tcpip.h> | |||
| 31 | #include <mswsock.h> | |||
| 32 | ||||
| 33 | namespace boost::corosio::detail { | |||
| 34 | ||||
| 35 | class win_tcp_acceptor_service; | |||
| 36 | class win_tcp_service; | |||
| 37 | class win_tcp_socket; | |||
| 38 | class win_tcp_acceptor; | |||
| 39 | ||||
| 40 | /** Accept operation state. */ | |||
| 41 | struct accept_op : overlapped_op | |||
| 42 | { | |||
| 43 | SOCKET accepted_socket = INVALID_SOCKET; | |||
| 44 | win_tcp_socket* peer_wrapper = nullptr; | |||
| 45 | win_tcp_acceptor& acceptor; | |||
| 46 | SOCKET listen_socket = INVALID_SOCKET; | |||
| 47 | io_object::implementation** impl_out = nullptr; | |||
| 48 | char addr_buf[2 * (sizeof(sockaddr_in6) + 16)]; | |||
| 49 | ||||
| 50 | static void do_complete( | |||
| 51 | void* owner, | |||
| 52 | scheduler_op* base, | |||
| 53 | std::uint32_t bytes, | |||
| 54 | std::uint32_t error); | |||
| 55 | static void do_cancel_impl(overlapped_op* op) noexcept; | |||
| 56 | ||||
| 57 | explicit accept_op(win_tcp_acceptor& acceptor_) noexcept; | |||
| 58 | }; | |||
| 59 | ||||
| 60 | /** Readiness-wait operation state for an acceptor. */ | |||
| 61 | struct acceptor_wait_op : overlapped_op | |||
| 62 | { | |||
| 63 | win_tcp_acceptor& acceptor; | |||
| 64 | SOCKET listen_socket = INVALID_SOCKET; | |||
| 65 | ||||
| 66 | static void do_complete( | |||
| 67 | void* owner, | |||
| 68 | scheduler_op* base, | |||
| 69 | std::uint32_t bytes, | |||
| 70 | std::uint32_t error); | |||
| 71 | static void do_cancel_impl(overlapped_op* op) noexcept; | |||
| 72 | ||||
| 73 | explicit acceptor_wait_op(win_tcp_acceptor& acceptor_) noexcept; | |||
| 74 | }; | |||
| 75 | ||||
| 76 | /** Acceptor implementation for IOCP-based I/O. | |||
| 77 | ||||
| 78 | Collapses the historical internal-state/wrapper split into one | |||
| 79 | pooled `io_object::implementation`: it both owns the listening | |||
| 80 | socket and pending operations, and directly implements | |||
| 81 | `tcp_acceptor::implementation`. `win_tcp_service` recycles | |||
| 82 | instances through its acceptor pool instead of freeing them on | |||
| 83 | every close. | |||
| 84 | ||||
| 85 | @note Internal implementation detail. Users interact with acceptor class. | |||
| 86 | */ | |||
| 87 | class win_tcp_acceptor final | |||
| 88 | : public tcp_acceptor::implementation | |||
| 89 | , public intrusive_list<win_tcp_acceptor>::node | |||
| 90 | { | |||
| 91 | friend class win_tcp_service; | |||
| 92 | friend struct accept_op; | |||
| 93 | friend struct acceptor_wait_op; | |||
| 94 | ||||
| 95 | win_tcp_service& svc_; | |||
| 96 | accept_op acc_; | |||
| 97 | acceptor_wait_op wt_; | |||
| 98 | SOCKET socket_ = INVALID_SOCKET; | |||
| 99 | int family_ = AF_UNSPEC; | |||
| 100 | endpoint local_endpoint_; | |||
| 101 | ||||
| 102 | public: | |||
| 103 | explicit win_tcp_acceptor(win_tcp_service& svc) noexcept; | |||
| 104 | ||||
| 105 | /// Recycle into the owning service's pool. Defined out-of-line | |||
| 106 | /// after `win_tcp_service` is complete (needs `svc_.acceptor_pool_`). | |||
| 107 | void retire() noexcept override; | |||
| 108 | ||||
| 109 | /** Reset recycled state for reuse. | |||
| 110 | ||||
| 111 | `close_socket()` already drives the socket handle, family, | |||
| 112 | and cached endpoint to their closed values, and each op's | |||
| 113 | completion drops its `object_ref_` before `refs_` can reach | |||
| 114 | zero, so this only asserts. Each op's `OVERLAPPED` fields are | |||
| 115 | re-seeded by `overlapped_op::reset()` at its next submit, so | |||
| 116 | they are not zeroed here. | |||
| 117 | ||||
| 118 | @pre refs_ == 0, socket closed, no op in flight. | |||
| 119 | */ | |||
| 120 | void reuse() noexcept; | |||
| 121 | ||||
| 122 | /// Return the owning socket service. | |||
| 123 | win_tcp_service& socket_service() noexcept; | |||
| 124 | ||||
| 125 | std::coroutine_handle<> accept( | |||
| 126 | capy::continuation& cont, | |||
| 127 | capy::executor_ref d, | |||
| 128 | std::stop_token token, | |||
| 129 | std::error_code* ec, | |||
| 130 | io_object::implementation** impl_out) override; | |||
| 131 | ||||
| 132 | std::coroutine_handle<> wait( | |||
| 133 | capy::continuation& cont, | |||
| 134 | capy::executor_ref d, | |||
| 135 | wait_type w, | |||
| 136 | std::stop_token token, | |||
| 137 | std::error_code* ec) override; | |||
| 138 | ||||
| 139 | endpoint local_endpoint() const noexcept override; | |||
| 140 | bool is_open() const noexcept override; | |||
| 141 | void cancel() noexcept override; | |||
| 142 | ||||
| 143 | native_handle_type native_handle() const noexcept override; | |||
| 144 | ||||
| 145 | 2269x | corosio::family family() const noexcept override | ||
| 146 | { | |||
| 147 | // getsockname fails with WSAEINVAL on an unbound socket, so | |||
| 148 | // the family recorded at socket creation is authoritative | |||
| 149 | 2269x | return to_family(family_); | ||
| 150 | } | |||
| 151 | native_handle_type release_socket() noexcept override; | |||
| 152 | ||||
| 153 | std::error_code set_option( | |||
| 154 | int level, | |||
| 155 | int optname, | |||
| 156 | void const* data, | |||
| 157 | std::size_t size) noexcept override; | |||
| 158 | std::error_code | |||
| 159 | get_option(int level, int optname, void* data, std::size_t* size) | |||
| 160 | const noexcept override; | |||
| 161 | ||||
| 162 | void set_local_endpoint(endpoint ep) noexcept; | |||
| 163 | void close_socket() noexcept; | |||
| 164 | }; | |||
| 165 | ||||
| 166 | } // namespace boost::corosio::detail | |||
| 167 | ||||
| 168 | #endif // BOOST_COROSIO_HAS_IOCP | |||
| 169 | ||||
| 170 | #endif // BOOST_COROSIO_NATIVE_DETAIL_IOCP_WIN_TCP_ACCEPTOR_HPP | |||
| 171 |