include/boost/corosio/native/detail/iocp/win_tcp_acceptor_service.hpp

91.7% Lines (772/842) 99.0% List of functions (100/101) 73.1% Branches (253/346)
win_tcp_acceptor_service.hpp
f(x) Functions (101)
Function Calls Lines Branches Blocks
boost::corosio::detail::connect_op::connect_op(boost::corosio::detail::win_tcp_socket_internal&) :82 7469x 100.0% 100.0% boost::corosio::detail::read_op::read_op(boost::corosio::detail::win_tcp_socket_internal&) :89 7469x 100.0% 100.0% boost::corosio::detail::write_op::write_op(boost::corosio::detail::win_tcp_socket_internal&) :96 7469x 100.0% 100.0% boost::corosio::detail::wait_op::wait_op(boost::corosio::detail::win_tcp_socket_internal&) :103 7469x 100.0% 100.0% boost::corosio::detail::accept_op::accept_op() :110 2334x 100.0% 100.0% boost::corosio::detail::acceptor_wait_op::acceptor_wait_op() :115 2334x 100.0% 100.0% boost::corosio::detail::connect_op::do_cancel_impl(boost::corosio::detail::overlapped_op*) :124 2x 100.0% 50.0% 87.5% boost::corosio::detail::read_op::do_cancel_impl(boost::corosio::detail::overlapped_op*) :135 1389x 100.0% 50.0% 88.9% boost::corosio::detail::write_op::do_cancel_impl(boost::corosio::detail::overlapped_op*) :147 4x 100.0% 50.0% 88.9% boost::corosio::detail::wait_op::do_cancel_impl(boost::corosio::detail::overlapped_op*) :159 3x 100.0% 50.0% 90.9% boost::corosio::detail::accept_op::do_cancel_impl(boost::corosio::detail::overlapped_op*) :179 13x 100.0% 75.0% 83.3% boost::corosio::detail::acceptor_wait_op::do_cancel_impl(boost::corosio::detail::overlapped_op*) :189 0 0.0% 0.0% 0.0% boost::corosio::detail::accept_op::do_complete(void*, boost::corosio::detail::scheduler_op*, unsigned int, unsigned int) :207 2351x 100.0% 78.6% 94.1% boost::corosio::detail::acceptor_wait_op::do_complete(void*, boost::corosio::detail::scheduler_op*, unsigned int, unsigned int) :306 8x 66.7% 66.7% 61.5% boost::corosio::detail::connect_op::do_complete(void*, boost::corosio::detail::scheduler_op*, unsigned int, unsigned int) :328 2344x 85.7% 76.5% 82.9% boost::corosio::detail::read_op::do_complete(void*, boost::corosio::detail::scheduler_op*, unsigned int, unsigned int) :369 312422x 100.0% 100.0% 84.6% boost::corosio::detail::write_op::do_complete(void*, boost::corosio::detail::scheduler_op*, unsigned int, unsigned int) :391 310308x 66.7% 66.7% 61.5% boost::corosio::detail::wait_op::do_complete(void*, boost::corosio::detail::scheduler_op*, unsigned int, unsigned int) :413 16x 66.7% 66.7% 61.5% boost::corosio::detail::win_tcp_socket_internal::win_tcp_socket_internal(boost::corosio::detail::win_tcp_service&) :434 7469x 100.0% 100.0% boost::corosio::detail::win_tcp_socket_internal::~win_tcp_socket_internal() :443 7469x 100.0% 100.0% boost::corosio::detail::win_tcp_socket_internal::native_handle() const :449 34303x 100.0% 100.0% boost::corosio::detail::win_tcp_socket_internal::local_endpoint() const :455 29x 100.0% 100.0% boost::corosio::detail::win_tcp_socket_internal::remote_endpoint() const :461 28x 100.0% 100.0% boost::corosio::detail::win_tcp_socket_internal::is_open() const :467 3724x 100.0% 100.0% boost::corosio::detail::win_tcp_socket_internal::set_socket(unsigned long long) :473 2332x 100.0% 100.0% boost::corosio::detail::win_tcp_socket_internal::set_endpoints(boost::corosio::endpoint, boost::corosio::endpoint) :479 4661x 100.0% 100.0% boost::corosio::detail::win_tcp_socket_internal::connect(std::__n4861::coroutine_handle<void>, boost::capy::executor_ref, boost::corosio::endpoint, std::stop_token, std::error_code*) :486 2344x 86.0% 70.6% 65.9% boost::corosio::detail::win_tcp_socket_internal::read_some(std::__n4861::coroutine_handle<void>, boost::capy::executor_ref, boost::corosio::buffer_param, std::stop_token, std::error_code*, unsigned long long*) :569 312422x 100.0% 100.0% 97.6% boost::corosio::detail::win_tcp_socket_internal::write_some(std::__n4861::coroutine_handle<void>, boost::capy::executor_ref, boost::corosio::buffer_param, std::stop_token, std::error_code*, unsigned long long*) :643 310308x 100.0% 93.8% 97.6% boost::corosio::detail::win_tcp_socket_internal::wait(std::__n4861::coroutine_handle<void>, boost::capy::executor_ref, boost::corosio::wait_type, std::stop_token, std::error_code*) :713 16x 93.1% 90.9% 88.6% boost::corosio::detail::win_tcp_socket_internal::cancel() :781 2174x 100.0% 50.0% 100.0% boost::corosio::detail::win_tcp_socket_internal::close_socket() :800 22007x 100.0% 100.0% 100.0% boost::corosio::detail::win_tcp_socket::win_tcp_socket(std::shared_ptr<boost::corosio::detail::win_tcp_socket_internal>) :834 7469x 100.0% 100.0% boost::corosio::detail::win_tcp_socket::close_internal() :841 7469x 100.0% 50.0% 100.0% boost::corosio::detail::win_tcp_socket::connect(std::__n4861::coroutine_handle<void>, boost::capy::executor_ref, boost::corosio::endpoint, std::stop_token, std::error_code*) :851 2344x 100.0% 100.0% 80.0% boost::corosio::detail::win_tcp_socket::read_some(std::__n4861::coroutine_handle<void>, boost::capy::executor_ref, boost::corosio::buffer_param, std::stop_token, std::error_code*, unsigned long long*) :862 312422x 100.0% 100.0% 80.0% boost::corosio::detail::win_tcp_socket::write_some(std::__n4861::coroutine_handle<void>, boost::capy::executor_ref, boost::corosio::buffer_param, std::stop_token, std::error_code*, unsigned long long*) :874 310308x 100.0% 100.0% 80.0% boost::corosio::detail::win_tcp_socket::wait(std::__n4861::coroutine_handle<void>, boost::capy::executor_ref, boost::corosio::wait_type, std::stop_token, std::error_code*) :886 16x 100.0% 100.0% 80.0% boost::corosio::detail::win_tcp_socket::shutdown(boost::corosio::shutdown_type) :897 13x 81.2% 66.7% 76.9% boost::corosio::detail::win_tcp_socket::native_handle() const :920 24469x 100.0% 100.0% boost::corosio::detail::win_tcp_socket::release_socket() :926 1x 100.0% 50.0% 100.0% boost::corosio::detail::win_tcp_socket::set_option(int, int, void const*, unsigned long long) :945 3730x 83.3% 50.0% 75.0% boost::corosio::detail::win_tcp_socket::get_option(int, int, void*, unsigned long long*) const :956 41x 87.5% 50.0% 77.8% boost::corosio::detail::win_tcp_socket::local_endpoint() const :969 29x 100.0% 100.0% boost::corosio::detail::win_tcp_socket::remote_endpoint() const :975 28x 100.0% 100.0% boost::corosio::detail::win_tcp_socket::cancel() :981 2173x 100.0% 100.0% boost::corosio::detail::win_tcp_socket::get_internal() const :987 19212x 100.0% 100.0% boost::corosio::detail::win_tcp_service::win_tcp_service(boost::capy::execution_context&) :994 1121x 100.0% 100.0% 65.0% boost::corosio::detail::win_tcp_service::~win_tcp_service() :1001 2242x 100.0% 100.0% boost::corosio::detail::win_tcp_service::shutdown() :1016 1121x 100.0% 100.0% 100.0% boost::corosio::detail::win_tcp_service::construct() :1039 7469x 100.0% 100.0% 89.5% boost::corosio::detail::win_tcp_service::destroy(boost::corosio::io_object::implementation*) :1059 7468x 100.0% 50.0% 100.0% boost::corosio::detail::win_tcp_service::close(boost::corosio::io_object::handle&) :1070 12158x 100.0% 100.0% boost::corosio::detail::win_tcp_service::destroy_impl(boost::corosio::detail::win_tcp_socket&) :1077 7468x 100.0% 50.0% 100.0% boost::corosio::detail::win_tcp_service::unregister_impl(boost::corosio::detail::win_tcp_socket_internal&) :1087 7469x 100.0% 100.0% boost::corosio::detail::win_tcp_service::open_socket(boost::corosio::detail::win_tcp_socket_internal&, int, int, int) :1094 2375x 76.5% 71.4% 68.8% boost::corosio::detail::win_tcp_service::assign_socket(boost::corosio::detail::win_tcp_socket_internal&, unsigned long long) :1129 8x 91.7% 70.8% 84.8% boost::corosio::detail::win_tcp_service::bind_socket(boost::corosio::detail::win_tcp_socket_internal&, boost::corosio::endpoint) :1183 7x 100.0% 85.7% 100.0% boost::corosio::detail::win_tcp_service::native_handle() const :1205 2351x 100.0% 100.0% boost::corosio::detail::win_tcp_service::on_pending(boost::corosio::detail::overlapped_op*) :1217 627265x 100.0% 100.0% boost::corosio::detail::win_tcp_service::on_completion(boost::corosio::detail::overlapped_op*, unsigned long, unsigned long) :1223 172x 100.0% 100.0% boost::corosio::detail::win_tcp_service::work_started() :1229 627449x 100.0% 100.0% boost::corosio::detail::win_tcp_service::load_extension_functions() :1241 1121x 91.7% 83.3% 88.9% boost::corosio::detail::win_tcp_service::destroy_acceptor_impl(boost::corosio::detail::win_tcp_acceptor&) :1267 2334x 100.0% 50.0% 100.0% boost::corosio::detail::win_tcp_service::unregister_acceptor_impl(boost::corosio::detail::win_tcp_acceptor_internal&) :1277 2334x 100.0% 100.0% boost::corosio::detail::win_tcp_service::open_acceptor_socket(boost::corosio::detail::win_tcp_acceptor_internal&, int, int, int) :1284 2320x 75.0% 71.4% 68.8% boost::corosio::detail::win_tcp_service::assign_acceptor_socket(boost::corosio::detail::win_tcp_acceptor_internal&, unsigned long long) :1318 8x 89.3% 71.4% 80.8% boost::corosio::detail::win_tcp_service::bind_acceptor(boost::corosio::detail::win_tcp_acceptor_internal&, boost::corosio::endpoint) :1364 2316x 100.0% 85.7% 100.0% boost::corosio::detail::win_tcp_service::listen_acceptor(boost::corosio::detail::win_tcp_acceptor_internal&, int) :1386 2298x 80.0% 50.0% 66.7% boost::corosio::detail::win_tcp_acceptor_internal::win_tcp_acceptor_internal(boost::corosio::detail::win_tcp_service&) :1398 2334x 100.0% 100.0% boost::corosio::detail::win_tcp_acceptor_internal::~win_tcp_acceptor_internal() :1403 2334x 100.0% 100.0% boost::corosio::detail::win_tcp_acceptor_internal::socket_service() :1409 17x 100.0% 100.0% boost::corosio::detail::win_tcp_acceptor_internal::native_handle() const :1415 2320x 100.0% 100.0% boost::corosio::detail::win_tcp_acceptor_internal::local_endpoint() const :1421 2298x 100.0% 100.0% boost::corosio::detail::win_tcp_acceptor_internal::is_open() const :1427 18567x 100.0% 100.0% boost::corosio::detail::win_tcp_acceptor_internal::set_local_endpoint(boost::corosio::endpoint) :1433 2316x 100.0% 100.0% boost::corosio::detail::win_tcp_acceptor_internal::accept(std::__n4861::coroutine_handle<void>, boost::capy::executor_ref, std::stop_token, std::error_code*, boost::corosio::io_object::implementation**) :1439 2351x 73.6% 65.6% 67.2% boost::corosio::detail::win_tcp_acceptor_internal::wait(std::__n4861::coroutine_handle<void>, boost::capy::executor_ref, boost::corosio::wait_type, std::stop_token, std::error_code*) :1540 8x 100.0% 100.0% 100.0% boost::corosio::detail::win_tcp_acceptor_internal::cancel() :1583 9x 100.0% 50.0% 100.0% boost::corosio::detail::win_tcp_acceptor_internal::close_socket() :1596 9314x 100.0% 100.0% 100.0% boost::corosio::detail::win_tcp_acceptor::win_tcp_acceptor(std::shared_ptr<boost::corosio::detail::win_tcp_acceptor_internal>) :1619 2334x 100.0% 100.0% boost::corosio::detail::win_tcp_acceptor::close_internal() :1626 2334x 100.0% 50.0% 100.0% boost::corosio::detail::win_tcp_acceptor::accept(std::__n4861::coroutine_handle<void>, boost::capy::executor_ref, std::stop_token, std::error_code*, boost::corosio::io_object::implementation**) :1636 2351x 100.0% 100.0% 80.0% boost::corosio::detail::win_tcp_acceptor::wait(std::__n4861::coroutine_handle<void>, boost::capy::executor_ref, boost::corosio::wait_type, std::stop_token, std::error_code*) :1647 8x 100.0% 100.0% 80.0% boost::corosio::detail::win_tcp_acceptor::local_endpoint() const :1658 2298x 100.0% 100.0% boost::corosio::detail::win_tcp_acceptor::is_open() const :1664 18567x 100.0% 75.0% 100.0% boost::corosio::detail::win_tcp_acceptor::cancel() :1670 5x 100.0% 100.0% boost::corosio::detail::win_tcp_acceptor::native_handle() const :1676 11x 75.0% 50.0% 83.3% boost::corosio::detail::win_tcp_acceptor::release_socket() :1684 4x 90.0% 50.0% 92.9% boost::corosio::detail::win_tcp_acceptor::set_option(int, int, void const*, unsigned long long) :1700 2308x 83.3% 50.0% 75.0% boost::corosio::detail::win_tcp_acceptor::get_option(int, int, void*, unsigned long long*) const :1711 1x 87.5% 50.0% 77.8% boost::corosio::detail::win_tcp_acceptor::get_internal() const :1724 11596x 100.0% 100.0% boost::corosio::detail::win_tcp_acceptor_service::win_tcp_acceptor_service(boost::capy::execution_context&, boost::corosio::detail::win_tcp_service&) :1731 1121x 100.0% 100.0% boost::corosio::detail::win_tcp_acceptor_service::construct() :1738 2334x 100.0% 100.0% 89.5% boost::corosio::detail::win_tcp_acceptor_service::destroy(boost::corosio::io_object::implementation*) :1758 2334x 100.0% 50.0% 100.0% boost::corosio::detail::win_tcp_acceptor_service::close(boost::corosio::io_object::handle&) :1769 4654x 100.0% 100.0% boost::corosio::detail::win_tcp_acceptor_service::open_acceptor_socket(boost::corosio::tcp_acceptor::implementation&, int, int, int) :1776 2320x 100.0% 100.0% boost::corosio::detail::win_tcp_acceptor_service::assign_socket(boost::corosio::tcp_acceptor::implementation&, unsigned long long) :1785 8x 100.0% 100.0% boost::corosio::detail::win_tcp_acceptor_service::bind_acceptor(boost::corosio::tcp_acceptor::implementation&, boost::corosio::endpoint) :1793 2316x 100.0% 100.0% boost::corosio::detail::win_tcp_acceptor_service::listen_acceptor(boost::corosio::tcp_acceptor::implementation&, int) :1801 2298x 100.0% 100.0% boost::corosio::detail::win_tcp_acceptor_service::shutdown() :1809 1121x 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 // Copyright (c) 2026 Michael Vandeberg
5 //
6 // Distributed under the Boost Software License, Version 1.0. (See accompanying
7 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
8 //
9 // Official repository: https://github.com/cppalliance/corosio
10 //
11
12 #ifndef BOOST_COROSIO_NATIVE_DETAIL_IOCP_WIN_TCP_ACCEPTOR_SERVICE_HPP
13 #define BOOST_COROSIO_NATIVE_DETAIL_IOCP_WIN_TCP_ACCEPTOR_SERVICE_HPP
14
15 #include <boost/corosio/detail/platform.hpp>
16
17 #if BOOST_COROSIO_HAS_IOCP
18
19 #include <boost/corosio/detail/config.hpp>
20 #include <boost/corosio/detail/except.hpp>
21 #include <boost/capy/ex/execution_context.hpp>
22
23 #include <boost/corosio/native/detail/iocp/win_dissociate.hpp>
24 #include <boost/corosio/native/detail/iocp/win_tcp_acceptor.hpp>
25 #include <boost/corosio/native/detail/iocp/win_tcp_service.hpp>
26
27 #include <boost/corosio/native/detail/iocp/win_scheduler.hpp>
28 #include <boost/corosio/native/detail/iocp/win_completion_key.hpp>
29
30 #include <boost/corosio/native/detail/endpoint_convert.hpp>
31 #include <boost/corosio/native/detail/make_err.hpp>
32 #include <boost/corosio/detail/dispatch_coro.hpp>
33
34 #include <Ws2tcpip.h>
35
36 namespace boost::corosio::detail {
37
38 /** IOCP acceptor service wrapping win_tcp_service for acceptor lifecycle.
39
40 Provides io_service + acceptor_service interface for tcp_acceptor
41 on Windows. Delegates to win_tcp_service for actual socket operations.
42 */
43 class BOOST_COROSIO_DECL win_tcp_acceptor_service final
44 : public capy::execution_context::service
45 , public io_object::io_service
46 {
47 public:
48 using key_type = win_tcp_acceptor_service;
49
50 win_tcp_acceptor_service(capy::execution_context& ctx, win_tcp_service& svc);
51
52 io_object::implementation* construct() override;
53
54 void destroy(io_object::implementation* p) override;
55
56 void close(io_object::handle& h) override;
57
58 /** Create the acceptor socket without binding or listening. */
59 std::error_code open_acceptor_socket(
60 tcp_acceptor::implementation& impl, int family, int type, int protocol);
61
62 /** Adopt an existing listening socket. */
63 std::error_code assign_socket(
64 tcp_acceptor::implementation& impl, native_handle_type fd);
65
66 /** Bind an open acceptor to a local endpoint. */
67 std::error_code
68 bind_acceptor(tcp_acceptor::implementation& impl, endpoint ep);
69
70 /** Start listening for incoming connections. */
71 std::error_code
72 listen_acceptor(tcp_acceptor::implementation& impl, int backlog);
73
74 void shutdown() override;
75
76 private:
77 win_tcp_service& svc_;
78 };
79
80 // Operation constructors
81
82 7469x inline connect_op::connect_op(win_tcp_socket_internal& internal_) noexcept
83 : overlapped_op(&do_complete)
84 7469x , internal(internal_)
85 {
86 7469x cancel_func_ = &do_cancel_impl;
87 7469x }
88
89 7469x inline read_op::read_op(win_tcp_socket_internal& internal_) noexcept
90 : overlapped_op(&do_complete)
91 7469x , internal(internal_)
92 {
93 7469x cancel_func_ = &do_cancel_impl;
94 7469x }
95
96 7469x inline write_op::write_op(win_tcp_socket_internal& internal_) noexcept
97 : overlapped_op(&do_complete)
98 7469x , internal(internal_)
99 {
100 7469x cancel_func_ = &do_cancel_impl;
101 7469x }
102
103 7469x inline wait_op::wait_op(win_tcp_socket_internal& internal_) noexcept
104 : overlapped_op(&do_complete)
105 7469x , internal(internal_)
106 {
107 7469x cancel_func_ = &do_cancel_impl;
108 7469x }
109
110 2334x inline accept_op::accept_op() noexcept : overlapped_op(&do_complete)
111 {
112 2334x cancel_func_ = &do_cancel_impl;
113 2334x }
114
115 2334x inline acceptor_wait_op::acceptor_wait_op() noexcept
116 2334x : overlapped_op(&do_complete)
117 {
118 2334x cancel_func_ = &do_cancel_impl;
119 2334x }
120
121 // Cancellation functions
122
123 inline void
124 2x connect_op::do_cancel_impl(overlapped_op* base) noexcept
125 {
126 2x auto* op = static_cast<connect_op*>(base);
127
1/2
✓ Branch 3 → 4 taken 2 times.
✗ Branch 3 → 9 not taken.
2x if (op->internal.is_open())
128 {
129
1/2
✓ Branch 4 → 5 taken 2 times.
✗ Branch 4 → 6 not taken.
4x ::CancelIoEx(
130 2x reinterpret_cast<HANDLE>(op->internal.native_handle()), op);
131 }
132 2x }
133
134 inline void
135 1389x read_op::do_cancel_impl(overlapped_op* base) noexcept
136 {
137 1389x auto* op = static_cast<read_op*>(base);
138 1389x op->cancelled.store(true, std::memory_order_release);
139
1/2
✓ Branch 4 → 5 taken 1389 times.
✗ Branch 4 → 10 not taken.
1389x if (op->internal.is_open())
140 {
141
1/2
✓ Branch 5 → 6 taken 1389 times.
✗ Branch 5 → 7 not taken.
2778x ::CancelIoEx(
142 1389x reinterpret_cast<HANDLE>(op->internal.native_handle()), op);
143 }
144 1389x }
145
146 inline void
147 4x write_op::do_cancel_impl(overlapped_op* base) noexcept
148 {
149 4x auto* op = static_cast<write_op*>(base);
150 4x op->cancelled.store(true, std::memory_order_release);
151
1/2
✓ Branch 4 → 5 taken 4 times.
✗ Branch 4 → 10 not taken.
4x if (op->internal.is_open())
152 {
153
1/2
✓ Branch 5 → 6 taken 4 times.
✗ Branch 5 → 7 not taken.
8x ::CancelIoEx(
154 4x reinterpret_cast<HANDLE>(op->internal.native_handle()), op);
155 }
156 4x }
157
158 inline void
159 3x wait_op::do_cancel_impl(overlapped_op* base) noexcept
160 {
161 3x auto* op = static_cast<wait_op*>(base);
162 3x op->cancelled.store(true, std::memory_order_release);
163 // Best-effort cancel of any pending zero-byte WSARecv issued for
164 // wait_type::read. ERROR_NOT_FOUND when nothing overlapped is
165 // pending is harmless.
166
1/2
✓ Branch 4 → 5 taken 3 times.
✗ Branch 4 → 10 not taken.
3x if (op->internal.is_open())
167 {
168
1/2
✓ Branch 5 → 6 taken 3 times.
✗ Branch 5 → 7 not taken.
6x ::CancelIoEx(
169 3x reinterpret_cast<HANDLE>(op->internal.native_handle()), op);
170 }
171 // wait_type::error parks the op in the auxiliary select reactor;
172 // wake it so the reactor can post a cancelled completion. No-op
173 // if the reactor was never constructed (e.g. zero-byte WSARecv
174 // path was the only thing this socket ever did).
175 3x op->internal.svc_.scheduler().cancel_wait_if_constructed(op);
176 3x }
177
178 inline void
179 13x accept_op::do_cancel_impl(overlapped_op* base) noexcept
180 {
181 13x auto* op = static_cast<accept_op*>(base);
182
2/2
✓ Branch 2 → 3 taken 12 times.
✓ Branch 2 → 7 taken 1 time.
13x if (op->listen_socket != INVALID_SOCKET)
183 {
184
1/2
✓ Branch 3 → 4 taken 12 times.
✗ Branch 3 → 5 not taken.
12x ::CancelIoEx(reinterpret_cast<HANDLE>(op->listen_socket), op);
185 }
186 13x }
187
188 inline void
189 acceptor_wait_op::do_cancel_impl(overlapped_op* base) noexcept
190 {
191 auto* op = static_cast<acceptor_wait_op*>(base);
192 op->cancelled.store(true, std::memory_order_release);
193 if (op->listen_socket != INVALID_SOCKET)
194 {
195 ::CancelIoEx(reinterpret_cast<HANDLE>(op->listen_socket), op);
196 }
197 if (op->acceptor_ptr)
198 {
199 op->acceptor_ptr->socket_service().scheduler()
200 .cancel_wait_if_constructed(op);
201 }
202 }
203
204 // accept_op completion handler
205
206 inline void
207 2351x accept_op::do_complete(
208 void* owner,
209 scheduler_op* base,
210 std::uint32_t /*bytes*/,
211 std::uint32_t /*error*/)
212 {
213 2351x auto* op = static_cast<accept_op*>(base);
214
215
2/2
✓ Branch 2 → 3 taken 1 time.
✓ Branch 2 → 12 taken 2350 times.
2351x if (!owner)
216 {
217
1/2
✓ Branch 3 → 4 taken 1 time.
✗ Branch 3 → 6 not taken.
1x if (op->accepted_socket != INVALID_SOCKET)
218 {
219
1/1
✓ Branch 4 → 5 taken 1 time.
1x ::closesocket(op->accepted_socket);
220 1x op->accepted_socket = INVALID_SOCKET;
221 }
222
223
1/2
✓ Branch 6 → 7 taken 1 time.
✗ Branch 6 → 9 not taken.
1x if (op->peer_wrapper)
224 {
225 1x op->peer_wrapper->close_internal();
226 1x op->peer_wrapper = nullptr;
227 }
228
229 1x op->cleanup_only();
230 1x op->acceptor_ptr.reset();
231 1x return;
232 }
233
234 2350x op->stop_cb.reset();
235
236 bool success =
237
4/4
✓ Branch 13 → 14 taken 2333 times.
✓ Branch 13 → 17 taken 17 times.
✓ Branch 15 → 16 taken 2332 times.
✓ Branch 15 → 17 taken 1 time.
2350x (op->dwError == 0 && !op->cancelled.load(std::memory_order_acquire));
238
239
1/2
✓ Branch 18 → 19 taken 2350 times.
✗ Branch 18 → 27 not taken.
2350x if (op->ec_out)
240 {
241
2/2
✓ Branch 20 → 21 taken 17 times.
✓ Branch 20 → 23 taken 2333 times.
2350x if (op->cancelled.load(std::memory_order_acquire))
242 17x *op->ec_out = capy::error::canceled;
243
2/2
✓ Branch 23 → 24 taken 1 time.
✓ Branch 23 → 25 taken 2332 times.
2333x else if (op->dwError != 0)
244 1x *op->ec_out = iocp_make_err(op->dwError, /*accept_path=*/true);
245 else
246 2332x *op->ec_out = {};
247 }
248
249
4/6
✓ Branch 27 → 28 taken 2332 times.
✓ Branch 27 → 48 taken 18 times.
✓ Branch 28 → 29 taken 2332 times.
✗ Branch 28 → 48 not taken.
✓ Branch 29 → 30 taken 2332 times.
✗ Branch 29 → 48 not taken.
2350x if (success && op->accepted_socket != INVALID_SOCKET && op->peer_wrapper)
250 {
251 2332x ::setsockopt(
252 op->accepted_socket, SOL_SOCKET, SO_UPDATE_ACCEPT_CONTEXT,
253
1/1
✓ Branch 30 → 31 taken 2332 times.
2332x reinterpret_cast<char*>(&op->listen_socket), sizeof(SOCKET));
254
255 2332x op->peer_wrapper->get_internal()->set_socket(op->accepted_socket);
256
257 2332x sockaddr_storage local_storage{};
258 2332x int local_len = sizeof(local_storage);
259 2332x sockaddr_storage remote_storage{};
260 2332x int remote_len = sizeof(remote_storage);
261
262 2332x endpoint local_ep, remote_ep;
263
1/1
✓ Branch 35 → 36 taken 2332 times.
2332x if (::getsockname(
264 op->accepted_socket,
265
1/2
✓ Branch 36 → 37 taken 2332 times.
✗ Branch 36 → 39 not taken.
2332x reinterpret_cast<sockaddr*>(&local_storage), &local_len) == 0)
266 2332x local_ep = from_sockaddr(local_storage);
267
1/1
✓ Branch 39 → 40 taken 2332 times.
2332x if (::getpeername(
268 op->accepted_socket,
269
1/2
✓ Branch 40 → 41 taken 2332 times.
✗ Branch 40 → 43 not taken.
2332x reinterpret_cast<sockaddr*>(&remote_storage), &remote_len) == 0)
270 2332x remote_ep = from_sockaddr(remote_storage);
271
272 2332x op->peer_wrapper->get_internal()->set_endpoints(local_ep, remote_ep);
273 2332x op->accepted_socket = INVALID_SOCKET;
274
275
1/2
✓ Branch 45 → 46 taken 2332 times.
✗ Branch 45 → 47 not taken.
2332x if (op->impl_out)
276 2332x *op->impl_out = op->peer_wrapper;
277 2332x }
278 else
279 {
280
2/2
✓ Branch 48 → 49 taken 17 times.
✓ Branch 48 → 51 taken 1 time.
18x if (op->accepted_socket != INVALID_SOCKET)
281 {
282
1/1
✓ Branch 49 → 50 taken 17 times.
17x ::closesocket(op->accepted_socket);
283 17x op->accepted_socket = INVALID_SOCKET;
284 }
285
286
2/2
✓ Branch 51 → 52 taken 17 times.
✓ Branch 51 → 56 taken 1 time.
18x if (op->peer_wrapper)
287 {
288
1/1
✓ Branch 54 → 55 taken 17 times.
17x op->acceptor_ptr->socket_service().destroy(op->peer_wrapper);
289 17x op->peer_wrapper = nullptr;
290 }
291
292
1/2
✓ Branch 56 → 57 taken 18 times.
✗ Branch 56 → 58 not taken.
18x if (op->impl_out)
293 18x *op->impl_out = nullptr;
294 }
295
296 2350x op->cont.h = op->h;
297 2350x auto saved_ex = op->ex;
298 2350x auto prevent_premature_destruction = std::move(op->acceptor_ptr);
299
300
2/2
✓ Branch 60 → 61 taken 2350 times.
✓ Branch 61 → 62 taken 2350 times.
2350x dispatch_coro(saved_ex, op->cont).resume();
301 2350x }
302
303 // acceptor_wait_op completion handler
304
305 inline void
306 8x acceptor_wait_op::do_complete(
307 void* owner,
308 scheduler_op* base,
309 std::uint32_t /*bytes*/,
310 std::uint32_t /*error*/)
311 {
312 8x auto* op = static_cast<acceptor_wait_op*>(base);
313
314
1/2
✗ Branch 2 → 3 not taken.
✓ Branch 2 → 6 taken 8 times.
8x if (!owner)
315 {
316 op->cleanup_only();
317 op->acceptor_ptr.reset();
318 return;
319 }
320
321 8x auto prevent_premature_destruction = std::move(op->acceptor_ptr);
322
1/1
✓ Branch 8 → 9 taken 8 times.
8x op->invoke_handler();
323 8x }
324
325 // connect_op completion handler
326
327 inline void
328 2344x connect_op::do_complete(
329 void* owner,
330 scheduler_op* base,
331 std::uint32_t /*bytes*/,
332 std::uint32_t /*error*/)
333 {
334 2344x auto* op = static_cast<connect_op*>(base);
335
336
1/2
✗ Branch 2 → 3 not taken.
✓ Branch 2 → 6 taken 2344 times.
2344x if (!owner)
337 {
338 op->cleanup_only();
339 op->internal_ptr.reset();
340 return;
341 }
342
343 bool success =
344
3/4
✓ Branch 6 → 7 taken 2326 times.
✓ Branch 6 → 10 taken 18 times.
✓ Branch 8 → 9 taken 2326 times.
✗ Branch 8 → 10 not taken.
2344x (op->dwError == 0 && !op->cancelled.load(std::memory_order_acquire));
345
5/6
✓ Branch 11 → 12 taken 2326 times.
✓ Branch 11 → 15 taken 18 times.
✓ Branch 13 → 14 taken 2326 times.
✗ Branch 13 → 15 not taken.
✓ Branch 16 → 17 taken 2326 times.
✓ Branch 16 → 27 taken 18 times.
2344x if (success && op->internal.is_open())
346 {
347 // Required after ConnectEx to enable shutdown(), getsockname(), etc.
348
1/1
✓ Branch 18 → 19 taken 2326 times.
2326x ::setsockopt(
349 2326x op->internal.native_handle(), SOL_SOCKET, SO_UPDATE_CONNECT_CONTEXT,
350 nullptr, 0);
351
352 2326x endpoint local_ep;
353 2326x sockaddr_storage local_storage{};
354 2326x int local_len = sizeof(local_storage);
355
1/1
✓ Branch 21 → 22 taken 2326 times.
2326x if (::getsockname(
356 2326x op->internal.native_handle(),
357
1/2
✓ Branch 22 → 23 taken 2326 times.
✗ Branch 22 → 25 not taken.
2326x reinterpret_cast<sockaddr*>(&local_storage), &local_len) == 0)
358 2326x local_ep = from_sockaddr(local_storage);
359 2326x op->internal.set_endpoints(local_ep, op->target_endpoint);
360 }
361
362 2344x auto prevent_premature_destruction = std::move(op->internal_ptr);
363
1/1
✓ Branch 29 → 30 taken 2344 times.
2344x op->invoke_handler();
364 2344x }
365
366 // read_op completion handler
367
368 inline void
369 312422x read_op::do_complete(
370 void* owner,
371 scheduler_op* base,
372 std::uint32_t /*bytes*/,
373 std::uint32_t /*error*/)
374 {
375 312422x auto* op = static_cast<read_op*>(base);
376
377
2/2
✓ Branch 2 → 3 taken 1 time.
✓ Branch 2 → 6 taken 312421 times.
312422x if (!owner)
378 {
379 1x op->cleanup_only();
380 1x op->internal_ptr.reset();
381 1x return;
382 }
383
384 312421x auto prevent_premature_destruction = std::move(op->internal_ptr);
385
1/1
✓ Branch 8 → 9 taken 312421 times.
312421x op->invoke_handler();
386 312421x }
387
388 // write_op completion handler
389
390 inline void
391 310308x write_op::do_complete(
392 void* owner,
393 scheduler_op* base,
394 std::uint32_t /*bytes*/,
395 std::uint32_t /*error*/)
396 {
397 310308x auto* op = static_cast<write_op*>(base);
398
399
1/2
✗ Branch 2 → 3 not taken.
✓ Branch 2 → 6 taken 310308 times.
310308x if (!owner)
400 {
401 op->cleanup_only();
402 op->internal_ptr.reset();
403 return;
404 }
405
406 310308x auto prevent_premature_destruction = std::move(op->internal_ptr);
407
1/1
✓ Branch 8 → 9 taken 310308 times.
310308x op->invoke_handler();
408 310308x }
409
410 // wait_op completion handler
411
412 inline void
413 16x wait_op::do_complete(
414 void* owner,
415 scheduler_op* base,
416 std::uint32_t /*bytes*/,
417 std::uint32_t /*error*/)
418 {
419 16x auto* op = static_cast<wait_op*>(base);
420
421
1/2
✗ Branch 2 → 3 not taken.
✓ Branch 2 → 6 taken 16 times.
16x if (!owner)
422 {
423 op->cleanup_only();
424 op->internal_ptr.reset();
425 return;
426 }
427
428 16x auto prevent_premature_destruction = std::move(op->internal_ptr);
429
1/1
✓ Branch 8 → 9 taken 16 times.
16x op->invoke_handler();
430 16x }
431
432 // win_tcp_socket_internal
433
434 7469x inline win_tcp_socket_internal::win_tcp_socket_internal(win_tcp_service& svc) noexcept
435 7469x : svc_(svc)
436 7469x , conn_(*this)
437 7469x , rd_(*this)
438 7469x , wr_(*this)
439 14938x , wt_(*this)
440 {
441 7469x }
442
443 7469x inline win_tcp_socket_internal::~win_tcp_socket_internal()
444 {
445 7469x svc_.unregister_impl(*this);
446 7469x }
447
448 inline SOCKET
449 34303x win_tcp_socket_internal::native_handle() const noexcept
450 {
451 34303x return socket_;
452 }
453
454 inline endpoint
455 29x win_tcp_socket_internal::local_endpoint() const noexcept
456 {
457 29x return local_endpoint_;
458 }
459
460 inline endpoint
461 28x win_tcp_socket_internal::remote_endpoint() const noexcept
462 {
463 28x return remote_endpoint_;
464 }
465
466 inline bool
467 3724x win_tcp_socket_internal::is_open() const noexcept
468 {
469 3724x return socket_ != INVALID_SOCKET;
470 }
471
472 inline void
473 2332x win_tcp_socket_internal::set_socket(SOCKET s) noexcept
474 {
475 2332x socket_ = s;
476 2332x }
477
478 inline void
479 4661x win_tcp_socket_internal::set_endpoints(endpoint local, endpoint remote) noexcept
480 {
481 4661x local_endpoint_ = local;
482 4661x remote_endpoint_ = remote;
483 4661x }
484
485 inline std::coroutine_handle<>
486 2344x win_tcp_socket_internal::connect(
487 std::coroutine_handle<> h,
488 capy::executor_ref d,
489 endpoint ep,
490 std::stop_token token,
491 std::error_code* ec)
492 {
493 // Keep internal alive during I/O
494
1/1
✓ Branch 2 → 3 taken 2344 times.
2344x conn_.internal_ptr = shared_from_this();
495
496 2344x auto& op = conn_;
497 2344x op.reset();
498 2344x op.h = h;
499 2344x op.ex = d;
500 2344x op.ec_out = ec;
501 2344x op.target_endpoint = ep;
502 2344x op.start(token);
503
504 2344x svc_.work_started();
505
506 // ConnectEx requires the socket to be bound. Skip if already bound
507 // (e.g. the caller used tcp_socket::bind() before connect).
508
2/2
✓ Branch 10 → 11 taken 2343 times.
✓ Branch 10 → 22 taken 1 time.
2344x if (local_endpoint_ == endpoint{})
509 {
510 2343x sockaddr_storage bind_storage{};
511 socklen_t bind_len;
512
2/2
✓ Branch 11 → 12 taken 7 times.
✓ Branch 11 → 13 taken 2336 times.
2343x if (family_ == AF_INET6)
513 {
514 7x sockaddr_in6 sa6{};
515 7x sa6.sin6_family = AF_INET6;
516 7x sa6.sin6_port = 0;
517 7x sa6.sin6_addr = in6addr_any;
518 7x std::memcpy(&bind_storage, &sa6, sizeof(sa6));
519 7x bind_len = sizeof(sa6);
520 }
521 else
522 {
523 2336x sockaddr_in sa4{};
524 2336x sa4.sin_family = AF_INET;
525 2336x sa4.sin_addr.s_addr = INADDR_ANY;
526 2336x sa4.sin_port = 0;
527 2336x std::memcpy(&bind_storage, &sa4, sizeof(sa4));
528 2336x bind_len = sizeof(sa4);
529 }
530
531
1/1
✓ Branch 14 → 15 taken 2343 times.
2343x if (::bind(
532 socket_, reinterpret_cast<sockaddr*>(&bind_storage),
533
1/2
✗ Branch 15 → 16 not taken.
✓ Branch 15 → 21 taken 2343 times.
2343x bind_len) == SOCKET_ERROR)
534 {
535 svc_.on_completion(&op, ::WSAGetLastError(), 0);
536 return std::noop_coroutine();
537 }
538 }
539
540 2344x auto connect_ex = svc_.connect_ex();
541
1/2
✗ Branch 23 → 24 not taken.
✓ Branch 23 → 28 taken 2344 times.
2344x if (!connect_ex)
542 {
543 svc_.on_completion(&op, WSAEOPNOTSUPP, 0);
544 return std::noop_coroutine();
545 }
546
547 2344x sockaddr_storage storage{};
548 2344x socklen_t addrlen = detail::to_sockaddr(ep, family_, storage);
549
550
1/1
✓ Branch 29 → 30 taken 2344 times.
2344x BOOL result = connect_ex(
551 socket_, reinterpret_cast<sockaddr*>(&storage),
552 static_cast<int>(addrlen), nullptr, 0, nullptr, &op);
553
554
1/2
✓ Branch 30 → 31 taken 2344 times.
✗ Branch 30 → 37 not taken.
2344x if (!result)
555 {
556
1/1
✓ Branch 31 → 32 taken 2344 times.
2344x DWORD err = ::WSAGetLastError();
557
1/2
✗ Branch 32 → 33 not taken.
✓ Branch 32 → 37 taken 2344 times.
2344x if (err != ERROR_IO_PENDING)
558 {
559 svc_.on_completion(&op, err, 0);
560 return std::noop_coroutine();
561 }
562 }
563
564 2344x svc_.on_pending(&op);
565 2344x return std::noop_coroutine();
566 }
567
568 inline std::coroutine_handle<>
569 312422x win_tcp_socket_internal::read_some(
570 std::coroutine_handle<> h,
571 capy::executor_ref d,
572 buffer_param param,
573 std::stop_token token,
574 std::error_code* ec,
575 std::size_t* bytes_out)
576 {
577 // Keep internal alive during I/O
578
1/1
✓ Branch 2 → 3 taken 312422 times.
312422x rd_.internal_ptr = shared_from_this();
579
580 312422x auto& op = rd_;
581 312422x op.reset();
582 312422x op.is_read = true;
583 312422x op.h = h;
584 312422x op.ex = d;
585 312422x op.ec_out = ec;
586 312422x op.bytes_out = bytes_out;
587 312422x op.start(token);
588
589 312422x svc_.work_started();
590
591 // Closed-object contract: complete with bad_file_descriptor
592 // without touching the kernel.
593
2/2
✓ Branch 8 → 9 taken 151 times.
✓ Branch 8 → 13 taken 312271 times.
312422x if (socket_ == INVALID_SOCKET)
594 {
595 151x svc_.on_completion(&op, WSAEBADF, 0);
596 151x return std::noop_coroutine();
597 }
598
599 // Prepare buffers
600 312271x capy::mutable_buffer bufs[read_op::max_buffers];
601 312271x op.wsabuf_count =
602 312271x static_cast<DWORD>(param.copy_to(bufs, read_op::max_buffers));
603
604 // Handle empty buffer: complete with 0 bytes
605
2/2
✓ Branch 14 → 15 taken 1 time.
✓ Branch 14 → 19 taken 312270 times.
312271x if (op.wsabuf_count == 0)
606 {
607 1x op.empty_buffer = true;
608 1x svc_.on_completion(&op, 0, 0);
609 1x return std::noop_coroutine();
610 }
611
612
2/2
✓ Branch 23 → 20 taken 312274 times.
✓ Branch 23 → 24 taken 312270 times.
624544x for (DWORD i = 0; i < op.wsabuf_count; ++i)
613 {
614 312274x op.wsabufs[i].buf = static_cast<char*>(bufs[i].data());
615 312274x op.wsabufs[i].len = static_cast<ULONG>(bufs[i].size());
616 }
617
618 312270x op.flags = 0;
619
620 624540x int result = ::WSARecv(
621
1/1
✓ Branch 24 → 25 taken 312270 times.
312270x socket_, op.wsabufs, op.wsabuf_count, nullptr, &op.flags, &op, nullptr);
622
623
2/2
✓ Branch 25 → 26 taken 4341 times.
✓ Branch 25 → 32 taken 307929 times.
312270x if (result == SOCKET_ERROR)
624 {
625
1/1
✓ Branch 26 → 27 taken 4341 times.
4341x DWORD err = ::WSAGetLastError();
626
2/2
✓ Branch 27 → 28 taken 5 times.
✓ Branch 27 → 32 taken 4336 times.
4341x if (err != WSA_IO_PENDING)
627 {
628 5x svc_.on_completion(&op, err, 0);
629 5x return std::noop_coroutine();
630 }
631 }
632
633 312265x svc_.on_pending(&op);
634
635 // Re-check cancellation after I/O is pending
636
2/2
✓ Branch 34 → 35 taken 2 times.
✓ Branch 34 → 36 taken 312263 times.
312265x if (op.cancelled.load(std::memory_order_acquire))
637
1/1
✓ Branch 35 → 36 taken 2 times.
2x ::CancelIoEx(reinterpret_cast<HANDLE>(socket_), &op);
638
639 312265x return std::noop_coroutine();
640 }
641
642 inline std::coroutine_handle<>
643 310308x win_tcp_socket_internal::write_some(
644 std::coroutine_handle<> h,
645 capy::executor_ref d,
646 buffer_param param,
647 std::stop_token token,
648 std::error_code* ec,
649 std::size_t* bytes_out)
650 {
651 // Keep internal alive during I/O
652
1/1
✓ Branch 2 → 3 taken 310308 times.
310308x wr_.internal_ptr = shared_from_this();
653
654 310308x auto& op = wr_;
655 310308x op.reset();
656 310308x op.h = h;
657 310308x op.ex = d;
658 310308x op.ec_out = ec;
659 310308x op.bytes_out = bytes_out;
660 310308x op.start(token);
661
662 310308x svc_.work_started();
663
664 // Closed-object contract: complete with bad_file_descriptor
665 // without touching the kernel.
666
2/2
✓ Branch 8 → 9 taken 6 times.
✓ Branch 8 → 13 taken 310302 times.
310308x if (socket_ == INVALID_SOCKET)
667 {
668 6x svc_.on_completion(&op, WSAEBADF, 0);
669 6x return std::noop_coroutine();
670 }
671
672 // Prepare buffers
673 310302x capy::mutable_buffer bufs[write_op::max_buffers];
674 310302x op.wsabuf_count =
675 310302x static_cast<DWORD>(param.copy_to(bufs, write_op::max_buffers));
676
677 // Handle empty buffer: complete immediately with 0 bytes
678
2/2
✓ Branch 14 → 15 taken 1 time.
✓ Branch 14 → 19 taken 310301 times.
310302x if (op.wsabuf_count == 0)
679 {
680 1x svc_.on_completion(&op, 0, 0);
681 1x return std::noop_coroutine();
682 }
683
684
2/2
✓ Branch 23 → 20 taken 310303 times.
✓ Branch 23 → 24 taken 310301 times.
620604x for (DWORD i = 0; i < op.wsabuf_count; ++i)
685 {
686 310303x op.wsabufs[i].buf = static_cast<char*>(bufs[i].data());
687 310303x op.wsabufs[i].len = static_cast<ULONG>(bufs[i].size());
688 }
689
690 620602x int result = ::WSASend(
691
1/1
✓ Branch 24 → 25 taken 310301 times.
310301x socket_, op.wsabufs, op.wsabuf_count, nullptr, 0, &op, nullptr);
692
693
2/2
✓ Branch 25 → 26 taken 3 times.
✓ Branch 25 → 32 taken 310298 times.
310301x if (result == SOCKET_ERROR)
694 {
695
1/1
✓ Branch 26 → 27 taken 3 times.
3x DWORD err = ::WSAGetLastError();
696
1/2
✓ Branch 27 → 28 taken 3 times.
✗ Branch 27 → 32 not taken.
3x if (err != WSA_IO_PENDING)
697 {
698 3x svc_.on_completion(&op, err, 0);
699 3x return std::noop_coroutine();
700 }
701 }
702
703 310298x svc_.on_pending(&op);
704
705 // Re-check cancellation after I/O is pending
706
2/2
✓ Branch 34 → 35 taken 1 time.
✓ Branch 34 → 36 taken 310297 times.
310298x if (op.cancelled.load(std::memory_order_acquire))
707
1/1
✓ Branch 35 → 36 taken 1 time.
1x ::CancelIoEx(reinterpret_cast<HANDLE>(socket_), &op);
708
709 310298x return std::noop_coroutine();
710 }
711
712 inline std::coroutine_handle<>
713 16x win_tcp_socket_internal::wait(
714 std::coroutine_handle<> h,
715 capy::executor_ref d,
716 wait_type w,
717 std::stop_token token,
718 std::error_code* ec)
719 {
720
1/1
✓ Branch 2 → 3 taken 16 times.
16x wt_.internal_ptr = shared_from_this();
721
722 16x auto& op = wt_;
723 16x op.reset();
724 16x op.h = h;
725 16x op.ex = d;
726 16x op.ec_out = ec;
727 16x op.bytes_out = nullptr;
728 16x op.empty_buffer = true; // skip EOF translation in invoke_handler
729 16x op.start(token);
730
731 16x svc_.work_started();
732
733 // Closed-object contract: complete with bad_file_descriptor
734 // without touching the kernel or the wait reactor.
735
2/2
✓ Branch 8 → 9 taken 2 times.
✓ Branch 8 → 13 taken 14 times.
16x if (socket_ == INVALID_SOCKET)
736 {
737 2x svc_.on_completion(&op, WSAEBADF, 0);
738 2x return std::noop_coroutine();
739 }
740
741
2/2
✓ Branch 13 → 14 taken 8 times.
✓ Branch 13 → 29 taken 6 times.
14x if (w == wait_type::read)
742 {
743 // Zero-byte WSARecv: kernel signals completion when data is
744 // available without consuming any bytes from the stream. This
745 // is the documented Winsock pattern for "is the socket
746 // readable" notifications.
747 8x op.wsabuf = WSABUF{0, nullptr};
748 8x op.flags = 0;
749
750 8x int result = ::WSARecv(
751 socket_, &op.wsabuf, 1, nullptr, &op.flags, &op, nullptr);
752
753
2/2
✓ Branch 15 → 16 taken 7 times.
✓ Branch 15 → 22 taken 1 time.
8x if (result == SOCKET_ERROR)
754 {
755 7x DWORD err = ::WSAGetLastError();
756
1/2
✗ Branch 17 → 18 not taken.
✓ Branch 17 → 22 taken 7 times.
7x if (err != WSA_IO_PENDING)
757 {
758 svc_.on_completion(&op, err, 0);
759 return std::noop_coroutine();
760 }
761 }
762
763 8x svc_.on_pending(&op);
764
765 // Re-check cancellation after I/O is pending.
766
2/2
✓ Branch 24 → 25 taken 1 time.
✓ Branch 24 → 26 taken 7 times.
8x if (op.cancelled.load(std::memory_order_acquire))
767 1x ::CancelIoEx(reinterpret_cast<HANDLE>(socket_), &op);
768
769 8x return std::noop_coroutine();
770 }
771
772 // wait_type::write and wait_type::error: route through the
773 // auxiliary poll reactor. There is no overlapped primitive for
774 // "the send buffer has room" that does not also transfer bytes,
775 // and a write wait must report real writability.
776 6x svc_.scheduler().wait_reactor().register_wait(socket_, w, &op);
777 6x return std::noop_coroutine();
778 }
779
780 inline void
781 2174x win_tcp_socket_internal::cancel() noexcept
782 {
783
1/2
✓ Branch 2 → 3 taken 2174 times.
✗ Branch 2 → 4 not taken.
2174x if (socket_ != INVALID_SOCKET)
784 {
785 2174x ::CancelIoEx(reinterpret_cast<HANDLE>(socket_), nullptr);
786 }
787
788 2174x conn_.request_cancel();
789 2174x rd_.request_cancel();
790 2174x wr_.request_cancel();
791 2174x wt_.request_cancel();
792 // CancelIoEx covers overlapped I/O on the socket but cannot reach
793 // a wait op parked in the auxiliary reactor (no overlapped is
794 // outstanding). Route through the reactor explicitly. Safe no-op
795 // if the reactor was never constructed.
796 2174x svc_.scheduler().cancel_wait_if_constructed(&wt_);
797 2174x }
798
799 inline void
800 22007x win_tcp_socket_internal::close_socket() noexcept
801 {
802 // Flag every op cancelled before tearing down the handle. closesocket()
803 // can complete a pending overlapped op with ERROR_NETNAME_DELETED (not the
804 // MSDN-documented ERROR_OPERATION_ABORTED), which iocp_make_err now maps to
805 // connection_reset -- so a locally-closed op must be short-circuited to
806 // canceled via the flag rather than relying on the raw error, exactly as
807 // cancel() does. The store happens-before the completion is decoded.
808 22007x conn_.request_cancel();
809 22007x rd_.request_cancel();
810 22007x wr_.request_cancel();
811 // wt_ is parked in the aux reactor (no overlapped outstanding), so it also
812 // needs an explicit reactor deregister before the SOCKET handle is closed;
813 // otherwise the reactor would keep polling a dangling fd (and on a Winsock
814 // SOCKET-id reuse the wrong fd could be polled briefly).
815 22007x wt_.request_cancel();
816 22007x svc_.scheduler().cancel_wait_if_constructed(&wt_);
817
818
2/2
✓ Branch 8 → 9 taken 4709 times.
✓ Branch 8 → 12 taken 17298 times.
22007x if (socket_ != INVALID_SOCKET)
819 {
820 4709x ::CancelIoEx(reinterpret_cast<HANDLE>(socket_), nullptr);
821 4709x ::closesocket(socket_);
822 4709x socket_ = INVALID_SOCKET;
823 }
824
825 22007x family_ = AF_UNSPEC;
826
827 // Clear cached endpoints
828 22007x local_endpoint_ = endpoint{};
829 22007x remote_endpoint_ = endpoint{};
830 22007x }
831
832 // win_tcp_socket
833
834 7469x inline win_tcp_socket::win_tcp_socket(
835 7469x std::shared_ptr<win_tcp_socket_internal> internal) noexcept
836 7469x : internal_(std::move(internal))
837 {
838 7469x }
839
840 inline void
841 7469x win_tcp_socket::close_internal() noexcept
842 {
843
1/2
✓ Branch 3 → 4 taken 7469 times.
✗ Branch 3 → 7 not taken.
7469x if (internal_)
844 {
845 7469x internal_->close_socket();
846 7469x internal_.reset();
847 }
848 7469x }
849
850 inline std::coroutine_handle<>
851 2344x win_tcp_socket::connect(
852 std::coroutine_handle<> h,
853 capy::executor_ref d,
854 endpoint ep,
855 std::stop_token token,
856 std::error_code* ec)
857 {
858
1/1
✓ Branch 4 → 5 taken 2344 times.
2344x return internal_->connect(h, d, ep, token, ec);
859 }
860
861 inline std::coroutine_handle<>
862 312422x win_tcp_socket::read_some(
863 std::coroutine_handle<> h,
864 capy::executor_ref d,
865 buffer_param buf,
866 std::stop_token token,
867 std::error_code* ec,
868 std::size_t* bytes)
869 {
870
1/1
✓ Branch 4 → 5 taken 312422 times.
312422x return internal_->read_some(h, d, buf, token, ec, bytes);
871 }
872
873 inline std::coroutine_handle<>
874 310308x win_tcp_socket::write_some(
875 std::coroutine_handle<> h,
876 capy::executor_ref d,
877 buffer_param buf,
878 std::stop_token token,
879 std::error_code* ec,
880 std::size_t* bytes)
881 {
882
1/1
✓ Branch 4 → 5 taken 310308 times.
310308x return internal_->write_some(h, d, buf, token, ec, bytes);
883 }
884
885 inline std::coroutine_handle<>
886 16x win_tcp_socket::wait(
887 std::coroutine_handle<> h,
888 capy::executor_ref d,
889 wait_type w,
890 std::stop_token token,
891 std::error_code* ec)
892 {
893
1/1
✓ Branch 4 → 5 taken 16 times.
16x return internal_->wait(h, d, w, token, ec);
894 }
895
896 inline std::error_code
897 13x win_tcp_socket::shutdown(tcp_socket::shutdown_type what) noexcept
898 {
899 int how;
900
3/4
✓ Branch 2 → 3 taken 1 time.
✓ Branch 2 → 4 taken 11 times.
✓ Branch 2 → 5 taken 1 time.
✗ Branch 2 → 6 not taken.
13x switch (what)
901 {
902 1x case tcp_socket::shutdown_receive:
903 1x how = SD_RECEIVE;
904 1x break;
905 11x case tcp_socket::shutdown_send:
906 11x how = SD_SEND;
907 11x break;
908 1x case tcp_socket::shutdown_both:
909 1x how = SD_BOTH;
910 1x break;
911 default:
912 return make_err(WSAEINVAL);
913 }
914
1/2
✗ Branch 10 → 11 not taken.
✓ Branch 10 → 13 taken 13 times.
13x if (::shutdown(internal_->native_handle(), how) != 0)
915 return make_err(WSAGetLastError());
916 13x return {};
917 }
918
919 inline native_handle_type
920 24469x win_tcp_socket::native_handle() const noexcept
921 {
922 24469x return static_cast<native_handle_type>(internal_->native_handle());
923 }
924
925 inline native_handle_type
926 1x win_tcp_socket::release_socket() noexcept
927 {
928 1x SOCKET s = internal_->socket_;
929
1/2
✓ Branch 3 → 4 taken 1 time.
✗ Branch 3 → 14 not taken.
1x if (s != INVALID_SOCKET)
930 {
931 1x internal_->cancel();
932 // Sever the port association so the descriptor can be
933 // adopted again; best-effort, the caller keeps a working
934 // socket either way.
935 1x dissociate_from_iocp(s);
936 1x internal_->socket_ = INVALID_SOCKET;
937 1x internal_->family_ = AF_UNSPEC;
938 1x internal_->local_endpoint_ = endpoint{};
939 1x internal_->remote_endpoint_ = endpoint{};
940 }
941 1x return static_cast<native_handle_type>(s);
942 }
943
944 inline std::error_code
945 3730x win_tcp_socket::set_option(
946 int level, int optname, void const* data, std::size_t size) noexcept
947 {
948 3730x if (::setsockopt(
949 3730x internal_->native_handle(), level, optname,
950
1/2
✗ Branch 5 → 6 not taken.
✓ Branch 5 → 8 taken 3730 times.
3730x reinterpret_cast<char const*>(data), static_cast<int>(size)) != 0)
951 return make_err(WSAGetLastError());
952 3730x return {};
953 }
954
955 inline std::error_code
956 41x win_tcp_socket::get_option(
957 int level, int optname, void* data, std::size_t* size) const noexcept
958 {
959 41x int len = static_cast<int>(*size);
960 41x if (::getsockopt(
961 41x internal_->native_handle(), level, optname,
962
1/2
✗ Branch 5 → 6 not taken.
✓ Branch 5 → 8 taken 41 times.
41x reinterpret_cast<char*>(data), &len) != 0)
963 return make_err(WSAGetLastError());
964 41x *size = static_cast<std::size_t>(len);
965 41x return {};
966 }
967
968 inline endpoint
969 29x win_tcp_socket::local_endpoint() const noexcept
970 {
971 29x return internal_->local_endpoint();
972 }
973
974 inline endpoint
975 28x win_tcp_socket::remote_endpoint() const noexcept
976 {
977 28x return internal_->remote_endpoint();
978 }
979
980 inline void
981 2173x win_tcp_socket::cancel() noexcept
982 {
983 2173x internal_->cancel();
984 2173x }
985
986 inline win_tcp_socket_internal*
987 19212x win_tcp_socket::get_internal() const noexcept
988 {
989 19212x return internal_.get();
990 }
991
992 // win_tcp_service
993
994 1121x inline win_tcp_service::win_tcp_service(capy::execution_context& ctx)
995 2242x : sched_(ctx.use_service<win_scheduler>())
996
2/2
✓ Branch 5 → 6 taken 1121 times.
✓ Branch 6 → 7 taken 1121 times.
1121x , iocp_(sched_.native_handle())
997 {
998
1/1
✓ Branch 12 → 13 taken 1121 times.
1121x load_extension_functions();
999 1121x }
1000
1001 2242x inline win_tcp_service::~win_tcp_service()
1002 {
1003 // Delete wrappers that survived shutdown. This runs after
1004 // win_scheduler is destroyed (reverse creation order), so
1005 // all coroutine frames and their tcp_socket members are gone.
1006
2/2
✓ Branch 6 → 3 taken 1 time.
✓ Branch 6 → 7 taken 1121 times.
1122x for (auto* w = socket_wrapper_list_.pop_front(); w != nullptr;
1007 1x w = socket_wrapper_list_.pop_front())
1008
1/2
✓ Branch 3 → 4 taken 1 time.
✗ Branch 3 → 5 not taken.
1x delete w;
1009
1010
1/2
✗ Branch 11 → 8 not taken.
✓ Branch 11 → 12 taken 1121 times.
1121x for (auto* w = acceptor_wrapper_list_.pop_front(); w != nullptr;
1011 w = acceptor_wrapper_list_.pop_front())
1012 delete w;
1013 2242x }
1014
1015 inline void
1016 1121x win_tcp_service::shutdown()
1017 {
1018 1121x std::lock_guard<win_mutex> lock(mutex_);
1019
1020 // Close all sockets to force pending I/O to complete via IOCP.
1021 // Wrappers are NOT deleted here - coroutine frames destroyed
1022 // during scheduler shutdown may still hold tcp_socket objects
1023 // that reference them. Wrapper deletion is deferred to ~win_tcp_service
1024 // after the scheduler has drained all outstanding operations.
1025
2/2
✓ Branch 6 → 4 taken 2 times.
✓ Branch 6 → 7 taken 1121 times.
1123x for (auto* impl = socket_list_.pop_front(); impl != nullptr;
1026 2x impl = socket_list_.pop_front())
1027 {
1028 2x impl->close_socket();
1029 }
1030
1031
2/2
✓ Branch 10 → 8 taken 1 time.
✓ Branch 10 → 11 taken 1121 times.
1122x for (auto* impl = acceptor_list_.pop_front(); impl != nullptr;
1032 1x impl = acceptor_list_.pop_front())
1033 {
1034 1x impl->close_socket();
1035 }
1036 1121x }
1037
1038 inline io_object::implementation*
1039 7469x win_tcp_service::construct()
1040 {
1041
1/1
✓ Branch 2 → 3 taken 7469 times.
7469x auto internal = std::make_shared<win_tcp_socket_internal>(*this);
1042
1043 {
1044 7469x std::lock_guard<win_mutex> lock(mutex_);
1045 7469x socket_list_.push_back(internal.get());
1046 7469x }
1047
1048
1/1
✓ Branch 7 → 8 taken 7469 times.
7469x auto* wrapper = new win_tcp_socket(std::move(internal));
1049
1050 {
1051 7469x std::lock_guard<win_mutex> lock(mutex_);
1052 7469x socket_wrapper_list_.push_back(wrapper);
1053 7469x }
1054
1055 7469x return wrapper;
1056 7469x }
1057
1058 inline void
1059 7468x win_tcp_service::destroy(io_object::implementation* p)
1060 {
1061
1/2
✓ Branch 2 → 3 taken 7468 times.
✗ Branch 2 → 5 not taken.
7468x if (p)
1062 {
1063 7468x auto& wrapper = static_cast<win_tcp_socket&>(*p);
1064 7468x wrapper.close_internal();
1065 7468x destroy_impl(wrapper);
1066 }
1067 7468x }
1068
1069 inline void
1070 12158x win_tcp_service::close(io_object::handle& h)
1071 {
1072 12158x auto& wrapper = static_cast<win_tcp_socket&>(*h.get());
1073 12158x wrapper.get_internal()->close_socket();
1074 12158x }
1075
1076 inline void
1077 7468x win_tcp_service::destroy_impl(win_tcp_socket& impl)
1078 {
1079 {
1080 7468x std::lock_guard<win_mutex> lock(mutex_);
1081 7468x socket_wrapper_list_.remove(&impl);
1082 7468x }
1083
1/2
✓ Branch 5 → 6 taken 7468 times.
✗ Branch 5 → 7 not taken.
7468x delete &impl;
1084 7468x }
1085
1086 inline void
1087 7469x win_tcp_service::unregister_impl(win_tcp_socket_internal& impl)
1088 {
1089 7469x std::lock_guard<win_mutex> lock(mutex_);
1090 7469x socket_list_.remove(&impl);
1091 7469x }
1092
1093 inline std::error_code
1094 2375x win_tcp_service::open_socket(
1095 win_tcp_socket_internal& impl, int family, int type, int protocol)
1096 {
1097 2375x impl.close_socket();
1098
1099 SOCKET sock =
1100 2375x ::WSASocketW(family, type, protocol, nullptr, 0, WSA_FLAG_OVERLAPPED);
1101
1102
1/2
✗ Branch 4 → 5 not taken.
✓ Branch 4 → 7 taken 2375 times.
2375x if (sock == INVALID_SOCKET)
1103 return make_err(::WSAGetLastError());
1104
1105
2/2
✓ Branch 7 → 8 taken 9 times.
✓ Branch 7 → 10 taken 2366 times.
2375x if (family == AF_INET6)
1106 {
1107 9x DWORD one = 1;
1108
1/1
✓ Branch 8 → 9 taken 9 times.
9x ::setsockopt(
1109 sock, IPPROTO_IPV6, IPV6_V6ONLY, reinterpret_cast<char*>(&one),
1110 sizeof(one));
1111 }
1112
1113 4750x HANDLE result = ::CreateIoCompletionPort(
1114 2375x reinterpret_cast<HANDLE>(sock), static_cast<HANDLE>(iocp_), key_io, 0);
1115
1116
1/2
✗ Branch 11 → 12 not taken.
✓ Branch 11 → 15 taken 2375 times.
2375x if (result == nullptr)
1117 {
1118 DWORD dwError = ::GetLastError();
1119 ::closesocket(sock);
1120 return make_err(dwError);
1121 }
1122
1123 2375x impl.socket_ = sock;
1124 2375x impl.family_ = family;
1125 2375x return {};
1126 }
1127
1128 inline std::error_code
1129 8x win_tcp_service::assign_socket(
1130 win_tcp_socket_internal& impl, native_handle_type fd)
1131 {
1132 8x SOCKET sock = static_cast<SOCKET>(fd);
1133
2/2
✓ Branch 2 → 3 taken 2 times.
✓ Branch 2 → 4 taken 6 times.
8x if (sock == INVALID_SOCKET)
1134 2x return make_err(WSAENOTSOCK);
1135
2/2
✓ Branch 4 → 5 taken 1 time.
✓ Branch 4 → 6 taken 5 times.
6x if (sock == impl.socket_)
1136 1x return std::make_error_code(std::errc::invalid_argument);
1137
1138 // SO_PROTOCOL_INFOW works on an unbound socket, unlike getsockname
1139 // (WSAEINVAL until bind/connect names it) -- an adopted socket may
1140 // have reached connected state without an explicit bind.
1141 5x WSAPROTOCOL_INFOW proto_info{};
1142 5x int proto_len = sizeof(proto_info);
1143
1/1
✓ Branch 6 → 7 taken 5 times.
5x if (::getsockopt(
1144 sock, SOL_SOCKET, SO_PROTOCOL_INFOW,
1145
1/2
✗ Branch 7 → 8 not taken.
✓ Branch 7 → 10 taken 5 times.
5x reinterpret_cast<char*>(&proto_info), &proto_len) != 0)
1146 return make_err(::WSAGetLastError());
1147
2/2
✓ Branch 10 → 11 taken 1 time.
✓ Branch 10 → 13 taken 4 times.
5x if (proto_info.iAddressFamily != AF_INET &&
1148
1/2
✗ Branch 11 → 12 not taken.
✓ Branch 11 → 13 taken 1 time.
1x proto_info.iAddressFamily != AF_INET6)
1149 return make_err(WSAEAFNOSUPPORT);
1150
2/2
✓ Branch 13 → 14 taken 2 times.
✓ Branch 13 → 15 taken 3 times.
5x if (proto_info.iSocketType != SOCK_STREAM)
1151 2x return make_err(WSAEPROTOTYPE);
1152
1153 // Associate before releasing the held socket: on IOCP nothing
1154 // shares descriptor state the way the reactor path does, so a
1155 // failed association must not cost the caller their old socket.
1156 6x HANDLE result = ::CreateIoCompletionPort(
1157
1/1
✓ Branch 15 → 16 taken 3 times.
3x reinterpret_cast<HANDLE>(sock), static_cast<HANDLE>(iocp_), key_io, 0);
1158
1/2
✗ Branch 16 → 17 not taken.
✓ Branch 16 → 19 taken 3 times.
3x if (result == nullptr)
1159 return make_err(::GetLastError());
1160
1161 3x impl.close_socket();
1162 3x impl.socket_ = sock;
1163 3x impl.family_ = proto_info.iAddressFamily;
1164
1165 3x endpoint local_ep, remote_ep;
1166 3x sockaddr_storage local_storage{};
1167 3x int local_len = sizeof(local_storage);
1168
1/1
✓ Branch 22 → 23 taken 3 times.
3x if (::getsockname(
1169
1/2
✓ Branch 23 → 24 taken 3 times.
✗ Branch 23 → 26 not taken.
3x sock, reinterpret_cast<sockaddr*>(&local_storage), &local_len) == 0)
1170 3x local_ep = detail::from_sockaddr(local_storage);
1171 3x sockaddr_storage remote_storage{};
1172 3x int remote_len = sizeof(remote_storage);
1173
1/1
✓ Branch 26 → 27 taken 3 times.
3x if (::getpeername(
1174 sock, reinterpret_cast<sockaddr*>(&remote_storage),
1175
1/2
✓ Branch 27 → 28 taken 3 times.
✗ Branch 27 → 30 not taken.
3x &remote_len) == 0)
1176 3x remote_ep = detail::from_sockaddr(remote_storage);
1177 3x impl.set_endpoints(local_ep, remote_ep);
1178
1179 3x return {};
1180 }
1181
1182 inline std::error_code
1183 7x win_tcp_service::bind_socket(win_tcp_socket_internal& impl, endpoint ep)
1184 {
1185 7x SOCKET sock = impl.socket_;
1186
1187 7x sockaddr_storage storage{};
1188 7x socklen_t addrlen = detail::to_sockaddr(ep, storage);
1189
1/1
✓ Branch 3 → 4 taken 7 times.
7x if (::bind(
1190 sock, reinterpret_cast<sockaddr*>(&storage),
1191
2/2
✓ Branch 4 → 5 taken 2 times.
✓ Branch 4 → 7 taken 5 times.
7x static_cast<int>(addrlen)) == SOCKET_ERROR)
1192
1/1
✓ Branch 5 → 6 taken 2 times.
2x return make_err(::WSAGetLastError());
1193
1194 // Cache local endpoint (resolves ephemeral port)
1195 5x sockaddr_storage local_storage{};
1196 5x int local_len = sizeof(local_storage);
1197
1/1
✓ Branch 7 → 8 taken 5 times.
5x if (::getsockname(
1198
1/2
✓ Branch 8 → 9 taken 5 times.
✗ Branch 8 → 11 not taken.
5x sock, reinterpret_cast<sockaddr*>(&local_storage), &local_len) == 0)
1199 5x impl.local_endpoint_ = detail::from_sockaddr(local_storage);
1200
1201 5x return {};
1202 }
1203
1204 inline void*
1205 2351x win_tcp_service::native_handle() const noexcept
1206 {
1207 2351x return iocp_;
1208 }
1209
1210 inline void
1211 win_tcp_service::post(overlapped_op* op)
1212 {
1213 sched_.post(op);
1214 }
1215
1216 inline void
1217 627265x win_tcp_service::on_pending(overlapped_op* op) noexcept
1218 {
1219 627265x sched_.on_pending(op);
1220 627265x }
1221
1222 inline void
1223 172x win_tcp_service::on_completion(overlapped_op* op, DWORD error, DWORD bytes) noexcept
1224 {
1225 172x sched_.on_completion(op, error, bytes);
1226 172x }
1227
1228 inline void
1229 627449x win_tcp_service::work_started() noexcept
1230 {
1231 627449x sched_.work_started();
1232 627449x }
1233
1234 inline void
1235 win_tcp_service::work_finished() noexcept
1236 {
1237 sched_.work_finished();
1238 }
1239
1240 inline void
1241 1121x win_tcp_service::load_extension_functions()
1242 {
1243
1/1
✓ Branch 2 → 3 taken 1121 times.
1121x SOCKET sock = ::WSASocketW(
1244 AF_INET, SOCK_STREAM, IPPROTO_TCP, nullptr, 0, WSA_FLAG_OVERLAPPED);
1245
1246
1/2
✗ Branch 3 → 4 not taken.
✓ Branch 3 → 5 taken 1121 times.
1121x if (sock == INVALID_SOCKET)
1247 return;
1248
1249 1121x DWORD bytes = 0;
1250
1251 1121x GUID connect_ex_guid = WSAID_CONNECTEX;
1252 1121x ::WSAIoctl(
1253 sock, SIO_GET_EXTENSION_FUNCTION_POINTER, &connect_ex_guid,
1254
1/1
✓ Branch 5 → 6 taken 1121 times.
1121x sizeof(connect_ex_guid), &connect_ex_, sizeof(connect_ex_), &bytes,
1255 nullptr, nullptr);
1256
1257 1121x GUID accept_ex_guid = WSAID_ACCEPTEX;
1258 1121x ::WSAIoctl(
1259 sock, SIO_GET_EXTENSION_FUNCTION_POINTER, &accept_ex_guid,
1260
1/1
✓ Branch 6 → 7 taken 1121 times.
1121x sizeof(accept_ex_guid), &accept_ex_, sizeof(accept_ex_), &bytes,
1261 nullptr, nullptr);
1262
1263
1/1
✓ Branch 7 → 8 taken 1121 times.
1121x ::closesocket(sock);
1264 }
1265
1266 inline void
1267 2334x win_tcp_service::destroy_acceptor_impl(win_tcp_acceptor& impl)
1268 {
1269 {
1270 2334x std::lock_guard<win_mutex> lock(mutex_);
1271 2334x acceptor_wrapper_list_.remove(&impl);
1272 2334x }
1273
1/2
✓ Branch 5 → 6 taken 2334 times.
✗ Branch 5 → 7 not taken.
2334x delete &impl;
1274 2334x }
1275
1276 inline void
1277 2334x win_tcp_service::unregister_acceptor_impl(win_tcp_acceptor_internal& impl)
1278 {
1279 2334x std::lock_guard<win_mutex> lock(mutex_);
1280 2334x acceptor_list_.remove(&impl);
1281 2334x }
1282
1283 inline std::error_code
1284 2320x win_tcp_service::open_acceptor_socket(
1285 win_tcp_acceptor_internal& impl, int family, int type, int protocol)
1286 {
1287 2320x impl.close_socket();
1288
1289 SOCKET sock =
1290 2320x ::WSASocketW(family, type, protocol, nullptr, 0, WSA_FLAG_OVERLAPPED);
1291
1292
1/2
✗ Branch 4 → 5 not taken.
✓ Branch 4 → 7 taken 2320 times.
2320x if (sock == INVALID_SOCKET)
1293 return make_err(::WSAGetLastError());
1294
1295
2/2
✓ Branch 7 → 8 taken 11 times.
✓ Branch 7 → 10 taken 2309 times.
2320x if (family == AF_INET6)
1296 {
1297 11x DWORD val = 0; // dual-stack default
1298
1/1
✓ Branch 8 → 9 taken 11 times.
11x ::setsockopt(
1299 sock, IPPROTO_IPV6, IPV6_V6ONLY, reinterpret_cast<char*>(&val),
1300 sizeof(val));
1301 }
1302
1303 4640x HANDLE result = ::CreateIoCompletionPort(
1304 2320x reinterpret_cast<HANDLE>(sock), static_cast<HANDLE>(iocp_), key_io, 0);
1305
1306
1/2
✗ Branch 11 → 12 not taken.
✓ Branch 11 → 15 taken 2320 times.
2320x if (result == nullptr)
1307 {
1308 DWORD dwError = ::GetLastError();
1309 ::closesocket(sock);
1310 return make_err(dwError);
1311 }
1312
1313 2320x impl.socket_ = sock;
1314 2320x return {};
1315 }
1316
1317 inline std::error_code
1318 8x win_tcp_service::assign_acceptor_socket(
1319 win_tcp_acceptor_internal& impl, native_handle_type fd)
1320 {
1321 8x SOCKET sock = static_cast<SOCKET>(fd);
1322
2/2
✓ Branch 2 → 3 taken 1 time.
✓ Branch 2 → 4 taken 7 times.
8x if (sock == INVALID_SOCKET)
1323 1x return make_err(WSAENOTSOCK);
1324
2/2
✓ Branch 4 → 5 taken 1 time.
✓ Branch 4 → 6 taken 6 times.
7x if (sock == impl.socket_)
1325 1x return std::make_error_code(std::errc::invalid_argument);
1326
1327 // SO_PROTOCOL_INFOW works on an unbound socket, unlike getsockname
1328 // (WSAEINVAL until bind names it).
1329 6x WSAPROTOCOL_INFOW proto_info{};
1330 6x int proto_len = sizeof(proto_info);
1331
1/1
✓ Branch 6 → 7 taken 6 times.
6x if (::getsockopt(
1332 sock, SOL_SOCKET, SO_PROTOCOL_INFOW,
1333
1/2
✗ Branch 7 → 8 not taken.
✓ Branch 7 → 10 taken 6 times.
6x reinterpret_cast<char*>(&proto_info), &proto_len) != 0)
1334 return make_err(::WSAGetLastError());
1335
2/2
✓ Branch 10 → 11 taken 1 time.
✓ Branch 10 → 13 taken 5 times.
6x if (proto_info.iAddressFamily != AF_INET &&
1336
1/2
✗ Branch 11 → 12 not taken.
✓ Branch 11 → 13 taken 1 time.
1x proto_info.iAddressFamily != AF_INET6)
1337 return make_err(WSAEAFNOSUPPORT);
1338
2/2
✓ Branch 13 → 14 taken 1 time.
✓ Branch 13 → 15 taken 5 times.
6x if (proto_info.iSocketType != SOCK_STREAM)
1339 1x return make_err(WSAEPROTOTYPE);
1340
1341 // Associate before releasing the held socket: on IOCP nothing
1342 // shares descriptor state the way the reactor path does, so a
1343 // failed association must not cost the caller their old socket.
1344 10x HANDLE result = ::CreateIoCompletionPort(
1345
1/1
✓ Branch 15 → 16 taken 5 times.
5x reinterpret_cast<HANDLE>(sock), static_cast<HANDLE>(iocp_), key_io, 0);
1346
1/2
✗ Branch 16 → 17 not taken.
✓ Branch 16 → 19 taken 5 times.
5x if (result == nullptr)
1347 return make_err(::GetLastError());
1348
1349 5x impl.close_socket();
1350 5x impl.socket_ = sock;
1351
1352 // AcceptEx sizes its address buffers from this cache, so an
1353 // unseeded endpoint breaks accepts on an adopted v6 listener.
1354 5x sockaddr_storage local_storage{};
1355 5x int local_len = sizeof(local_storage);
1356
1/1
✓ Branch 20 → 21 taken 5 times.
5x if (::getsockname(
1357
1/2
✓ Branch 21 → 22 taken 5 times.
✗ Branch 21 → 24 not taken.
5x sock, reinterpret_cast<sockaddr*>(&local_storage), &local_len) == 0)
1358 5x impl.set_local_endpoint(detail::from_sockaddr(local_storage));
1359
1360 5x return {};
1361 }
1362
1363 inline std::error_code
1364 2316x win_tcp_service::bind_acceptor(win_tcp_acceptor_internal& impl, endpoint ep)
1365 {
1366 2316x SOCKET sock = impl.socket_;
1367
1368 2316x sockaddr_storage storage{};
1369 2316x socklen_t addrlen = detail::to_sockaddr(ep, storage);
1370
1/1
✓ Branch 3 → 4 taken 2316 times.
2316x if (::bind(
1371 sock, reinterpret_cast<sockaddr*>(&storage),
1372
2/2
✓ Branch 4 → 5 taken 5 times.
✓ Branch 4 → 7 taken 2311 times.
2316x static_cast<int>(addrlen)) == SOCKET_ERROR)
1373
1/1
✓ Branch 5 → 6 taken 5 times.
5x return make_err(::WSAGetLastError());
1374
1375 // Cache local endpoint (resolves ephemeral port)
1376 2311x sockaddr_storage local_storage{};
1377 2311x int local_len = sizeof(local_storage);
1378
1/1
✓ Branch 7 → 8 taken 2311 times.
2311x if (::getsockname(
1379
1/2
✓ Branch 8 → 9 taken 2311 times.
✗ Branch 8 → 11 not taken.
2311x sock, reinterpret_cast<sockaddr*>(&local_storage), &local_len) == 0)
1380 2311x impl.set_local_endpoint(detail::from_sockaddr(local_storage));
1381
1382 2311x return {};
1383 }
1384
1385 inline std::error_code
1386 2298x win_tcp_service::listen_acceptor(win_tcp_acceptor_internal& impl, int backlog)
1387 {
1388 2298x SOCKET sock = impl.socket_;
1389
1390
1/2
✗ Branch 3 → 4 not taken.
✓ Branch 3 → 6 taken 2298 times.
2298x if (::listen(sock, backlog) == SOCKET_ERROR)
1391 return make_err(::WSAGetLastError());
1392
1393 2298x return {};
1394 }
1395
1396 // win_tcp_acceptor_internal
1397
1398 2334x inline win_tcp_acceptor_internal::win_tcp_acceptor_internal(win_tcp_service& svc) noexcept
1399 2334x : svc_(svc)
1400 {
1401 2334x }
1402
1403 2334x inline win_tcp_acceptor_internal::~win_tcp_acceptor_internal()
1404 {
1405 2334x svc_.unregister_acceptor_impl(*this);
1406 2334x }
1407
1408 inline win_tcp_service&
1409 17x win_tcp_acceptor_internal::socket_service() noexcept
1410 {
1411 17x return svc_;
1412 }
1413
1414 inline SOCKET
1415 2320x win_tcp_acceptor_internal::native_handle() const noexcept
1416 {
1417 2320x return socket_;
1418 }
1419
1420 inline endpoint
1421 2298x win_tcp_acceptor_internal::local_endpoint() const noexcept
1422 {
1423 2298x return local_endpoint_;
1424 }
1425
1426 inline bool
1427 18567x win_tcp_acceptor_internal::is_open() const noexcept
1428 {
1429 18567x return socket_ != INVALID_SOCKET;
1430 }
1431
1432 inline void
1433 2316x win_tcp_acceptor_internal::set_local_endpoint(endpoint ep) noexcept
1434 {
1435 2316x local_endpoint_ = ep;
1436 2316x }
1437
1438 inline std::coroutine_handle<>
1439 2351x win_tcp_acceptor_internal::accept(
1440 std::coroutine_handle<> h,
1441 capy::executor_ref d,
1442 std::stop_token token,
1443 std::error_code* ec,
1444 io_object::implementation** impl_out)
1445 {
1446 // Keep acceptor internal alive during I/O
1447
1/1
✓ Branch 2 → 3 taken 2351 times.
2351x acc_.acceptor_ptr = shared_from_this();
1448
1449 2351x auto& op = acc_;
1450 2351x op.reset();
1451 2351x op.h = h;
1452 2351x op.ex = d;
1453 2351x op.ec_out = ec;
1454 2351x op.impl_out = impl_out;
1455 2351x op.start(token);
1456
1457 2351x svc_.work_started();
1458
1459 // Create wrapper for the peer socket (service owns it)
1460
1/1
✓ Branch 8 → 9 taken 2351 times.
2351x auto& peer_wrapper = static_cast<win_tcp_socket&>(*svc_.construct());
1461
1462 // Derive AF from the listening socket's cached local endpoint
1463
2/2
✓ Branch 10 → 11 taken 9 times.
✓ Branch 10 → 12 taken 2342 times.
2351x int af = local_endpoint_.is_v6() ? AF_INET6 : AF_INET;
1464
1465 // Create the accepted socket with matching address family
1466
1/1
✓ Branch 13 → 14 taken 2351 times.
2351x SOCKET accepted = ::WSASocketW(
1467 af, SOCK_STREAM, IPPROTO_TCP, nullptr, 0, WSA_FLAG_OVERLAPPED);
1468
1469
1/2
✗ Branch 14 → 15 not taken.
✓ Branch 14 → 21 taken 2351 times.
2351x if (accepted == INVALID_SOCKET)
1470 {
1471 svc_.destroy(&peer_wrapper);
1472 svc_.on_completion(&op, ::WSAGetLastError(), 0);
1473 return std::noop_coroutine();
1474 }
1475
1476
1/1
✓ Branch 22 → 23 taken 2351 times.
2351x HANDLE result = ::CreateIoCompletionPort(
1477 2351x reinterpret_cast<HANDLE>(accepted), svc_.native_handle(), key_io, 0);
1478
1479
1/2
✗ Branch 23 → 24 not taken.
✓ Branch 23 → 31 taken 2351 times.
2351x if (result == nullptr)
1480 {
1481 DWORD err = ::GetLastError();
1482 ::closesocket(accepted);
1483 svc_.destroy(&peer_wrapper);
1484 svc_.on_completion(&op, err, 0);
1485 return std::noop_coroutine();
1486 }
1487
1488 // Set up the accept operation
1489 2351x op.accepted_socket = accepted;
1490 2351x op.peer_wrapper = &peer_wrapper;
1491 2351x op.listen_socket = socket_;
1492
1493 2351x auto accept_ex = svc_.accept_ex();
1494
1/2
✗ Branch 32 → 33 not taken.
✓ Branch 32 → 39 taken 2351 times.
2351x if (!accept_ex)
1495 {
1496 ::closesocket(accepted);
1497 svc_.destroy(&peer_wrapper);
1498 op.peer_wrapper = nullptr;
1499 op.accepted_socket = INVALID_SOCKET;
1500 svc_.on_completion(&op, WSAEOPNOTSUPP, 0);
1501 return std::noop_coroutine();
1502 }
1503
1504 // AcceptEx address buffer sizes must match the socket's address family
1505
2/2
✓ Branch 39 → 40 taken 9 times.
✓ Branch 39 → 41 taken 2342 times.
2351x DWORD addr_size = static_cast<DWORD>(
1506 (af == AF_INET6 ? sizeof(sockaddr_in6) : sizeof(sockaddr_in)) + 16);
1507 2351x DWORD bytes_received = 0;
1508
1509 4702x BOOL ok = accept_ex(
1510
1/1
✓ Branch 42 → 43 taken 2351 times.
2351x socket_, accepted, op.addr_buf, 0, addr_size, addr_size,
1511 &bytes_received, &op);
1512
1513
1/2
✓ Branch 43 → 44 taken 2351 times.
✗ Branch 43 → 52 not taken.
2351x if (!ok)
1514 {
1515
1/1
✓ Branch 44 → 45 taken 2351 times.
2351x DWORD err = ::WSAGetLastError();
1516
2/2
✓ Branch 45 → 46 taken 1 time.
✓ Branch 45 → 52 taken 2350 times.
2351x if (err != ERROR_IO_PENDING)
1517 {
1518
1/1
✓ Branch 46 → 47 taken 1 time.
1x ::closesocket(accepted);
1519
1/1
✓ Branch 47 → 48 taken 1 time.
1x svc_.destroy(&peer_wrapper);
1520 1x op.peer_wrapper = nullptr;
1521 1x op.accepted_socket = INVALID_SOCKET;
1522 1x svc_.on_completion(&op, err, 0);
1523 1x return std::noop_coroutine();
1524 }
1525 }
1526
1527 2350x svc_.on_pending(&op);
1528
1529 // If the stop_token was already cancelled when start() was called,
1530 // the CancelIoEx in the canceller fired before AcceptEx was
1531 // submitted and had no effect. Re-issue now that the I/O is
1532 // pending so the completion posts with ERROR_OPERATION_ABORTED.
1533
2/2
✓ Branch 54 → 55 taken 2 times.
✓ Branch 54 → 56 taken 2348 times.
2350x if (op.cancelled.load(std::memory_order_acquire))
1534
1/1
✓ Branch 55 → 56 taken 2 times.
2x ::CancelIoEx(reinterpret_cast<HANDLE>(socket_), &op);
1535
1536 2350x return std::noop_coroutine();
1537 }
1538
1539 inline std::coroutine_handle<>
1540 8x win_tcp_acceptor_internal::wait(
1541 std::coroutine_handle<> h,
1542 capy::executor_ref d,
1543 wait_type w,
1544 std::stop_token token,
1545 std::error_code* ec)
1546 {
1547
1/1
✓ Branch 2 → 3 taken 8 times.
8x wt_.acceptor_ptr = shared_from_this();
1548 8x wt_.listen_socket = socket_;
1549
1550 8x auto& op = wt_;
1551 8x op.reset();
1552 8x op.h = h;
1553 8x op.ex = d;
1554 8x op.ec_out = ec;
1555 8x op.bytes_out = nullptr;
1556 8x op.start(token);
1557
1558 8x svc_.work_started();
1559
1560 // Closed-object contract: complete with bad_file_descriptor
1561 // without touching the kernel or the wait reactor.
1562
2/2
✓ Branch 8 → 9 taken 1 time.
✓ Branch 8 → 13 taken 7 times.
8x if (socket_ == INVALID_SOCKET)
1563 {
1564 1x svc_.on_completion(&op, WSAEBADF, 0);
1565 1x return std::noop_coroutine();
1566 }
1567
1568 // Writability carries no meaning for a listening socket; the
1569 // wait fails the same way on every backend.
1570
2/2
✓ Branch 13 → 14 taken 1 time.
✓ Branch 13 → 18 taken 6 times.
7x if (w == wait_type::write)
1571 {
1572 1x svc_.on_completion(&op, WSAEOPNOTSUPP, 0);
1573 1x return std::noop_coroutine();
1574 }
1575
1576 // wait_type::read (incoming connection ready) and wait_type::error
1577 // on the listen socket route through the auxiliary select reactor.
1578 6x svc_.scheduler().wait_reactor().register_wait(socket_, w, &op);
1579 6x return std::noop_coroutine();
1580 }
1581
1582 inline void
1583 9x win_tcp_acceptor_internal::cancel() noexcept
1584 {
1585
1/2
✓ Branch 2 → 3 taken 9 times.
✗ Branch 2 → 4 not taken.
9x if (socket_ != INVALID_SOCKET)
1586 {
1587 9x ::CancelIoEx(reinterpret_cast<HANDLE>(socket_), nullptr);
1588 }
1589
1590 9x acc_.request_cancel();
1591 9x wt_.request_cancel();
1592 9x svc_.scheduler().cancel_wait_if_constructed(&wt_);
1593 9x }
1594
1595 inline void
1596 9314x win_tcp_acceptor_internal::close_socket() noexcept
1597 {
1598 // Flag the accept op cancelled before closing so a closesocket-delivered
1599 // ERROR_NETNAME_DELETED is short-circuited to canceled rather than mapped
1600 // to connection_aborted by iocp_make_err (see win_tcp_socket close_socket).
1601 9314x acc_.request_cancel();
1602 // Tear down any aux-reactor-parked wait op first.
1603 9314x wt_.request_cancel();
1604 9314x svc_.scheduler().cancel_wait_if_constructed(&wt_);
1605
1606
2/2
✓ Branch 6 → 7 taken 2321 times.
✓ Branch 6 → 10 taken 6993 times.
9314x if (socket_ != INVALID_SOCKET)
1607 {
1608 2321x ::CancelIoEx(reinterpret_cast<HANDLE>(socket_), nullptr);
1609 2321x ::closesocket(socket_);
1610 2321x socket_ = INVALID_SOCKET;
1611 }
1612
1613 // Clear cached endpoint
1614 9314x local_endpoint_ = endpoint{};
1615 9314x }
1616
1617 // win_tcp_acceptor
1618
1619 2334x inline win_tcp_acceptor::win_tcp_acceptor(
1620 2334x std::shared_ptr<win_tcp_acceptor_internal> internal) noexcept
1621 2334x : internal_(std::move(internal))
1622 {
1623 2334x }
1624
1625 inline void
1626 2334x win_tcp_acceptor::close_internal() noexcept
1627 {
1628
1/2
✓ Branch 3 → 4 taken 2334 times.
✗ Branch 3 → 7 not taken.
2334x if (internal_)
1629 {
1630 2334x internal_->close_socket();
1631 2334x internal_.reset();
1632 }
1633 2334x }
1634
1635 inline std::coroutine_handle<>
1636 2351x win_tcp_acceptor::accept(
1637 std::coroutine_handle<> h,
1638 capy::executor_ref d,
1639 std::stop_token token,
1640 std::error_code* ec,
1641 io_object::implementation** impl_out)
1642 {
1643
1/1
✓ Branch 4 → 5 taken 2351 times.
2351x return internal_->accept(h, d, token, ec, impl_out);
1644 }
1645
1646 inline std::coroutine_handle<>
1647 8x win_tcp_acceptor::wait(
1648 std::coroutine_handle<> h,
1649 capy::executor_ref d,
1650 wait_type w,
1651 std::stop_token token,
1652 std::error_code* ec)
1653 {
1654
1/1
✓ Branch 4 → 5 taken 8 times.
8x return internal_->wait(h, d, w, token, ec);
1655 }
1656
1657 inline endpoint
1658 2298x win_tcp_acceptor::local_endpoint() const noexcept
1659 {
1660 2298x return internal_->local_endpoint();
1661 }
1662
1663 inline bool
1664 18567x win_tcp_acceptor::is_open() const noexcept
1665 {
1666
3/4
✓ Branch 3 → 4 taken 18567 times.
✗ Branch 3 → 8 not taken.
✓ Branch 6 → 7 taken 13946 times.
✓ Branch 6 → 8 taken 4621 times.
18567x return internal_ && internal_->is_open();
1667 }
1668
1669 inline void
1670 5x win_tcp_acceptor::cancel() noexcept
1671 {
1672 5x internal_->cancel();
1673 5x }
1674
1675 inline native_handle_type
1676 11x win_tcp_acceptor::native_handle() const noexcept
1677 {
1678
1/2
✗ Branch 3 → 4 not taken.
✓ Branch 3 → 5 taken 11 times.
11x if (!internal_)
1679 return static_cast<native_handle_type>(INVALID_SOCKET);
1680 11x return static_cast<native_handle_type>(internal_->native_handle());
1681 }
1682
1683 inline native_handle_type
1684 4x win_tcp_acceptor::release_socket() noexcept
1685 {
1686
1/2
✗ Branch 3 → 4 not taken.
✓ Branch 3 → 5 taken 4 times.
4x if (!internal_)
1687 return static_cast<native_handle_type>(INVALID_SOCKET);
1688 4x SOCKET s = internal_->socket_;
1689
1/2
✓ Branch 6 → 7 taken 4 times.
✗ Branch 6 → 14 not taken.
4x if (s != INVALID_SOCKET)
1690 {
1691 4x internal_->cancel();
1692 4x dissociate_from_iocp(s);
1693 4x internal_->socket_ = INVALID_SOCKET;
1694 4x internal_->local_endpoint_ = endpoint{};
1695 }
1696 4x return static_cast<native_handle_type>(s);
1697 }
1698
1699 inline std::error_code
1700 2308x win_tcp_acceptor::set_option(
1701 int level, int optname, void const* data, std::size_t size) noexcept
1702 {
1703 2308x if (::setsockopt(
1704 2308x internal_->native_handle(), level, optname,
1705
1/2
✗ Branch 5 → 6 not taken.
✓ Branch 5 → 8 taken 2308 times.
2308x reinterpret_cast<char const*>(data), static_cast<int>(size)) != 0)
1706 return make_err(WSAGetLastError());
1707 2308x return {};
1708 }
1709
1710 inline std::error_code
1711 1x win_tcp_acceptor::get_option(
1712 int level, int optname, void* data, std::size_t* size) const noexcept
1713 {
1714 1x int len = static_cast<int>(*size);
1715 1x if (::getsockopt(
1716 1x internal_->native_handle(), level, optname,
1717
1/2
✗ Branch 5 → 6 not taken.
✓ Branch 5 → 8 taken 1 time.
1x reinterpret_cast<char*>(data), &len) != 0)
1718 return make_err(WSAGetLastError());
1719 1x *size = static_cast<std::size_t>(len);
1720 1x return {};
1721 }
1722
1723 inline win_tcp_acceptor_internal*
1724 11596x win_tcp_acceptor::get_internal() const noexcept
1725 {
1726 11596x return internal_.get();
1727 }
1728
1729 // win_tcp_acceptor_service
1730
1731 1121x inline win_tcp_acceptor_service::win_tcp_acceptor_service(
1732 1121x [[maybe_unused]] capy::execution_context& ctx, win_tcp_service& svc)
1733 1121x : svc_(svc)
1734 {
1735 1121x }
1736
1737 inline io_object::implementation*
1738 2334x win_tcp_acceptor_service::construct()
1739 {
1740
1/1
✓ Branch 2 → 3 taken 2334 times.
2334x auto internal = std::make_shared<win_tcp_acceptor_internal>(svc_);
1741
1742 {
1743 2334x std::lock_guard<win_mutex> lock(svc_.mutex_);
1744 2334x svc_.acceptor_list_.push_back(internal.get());
1745 2334x }
1746
1747
1/1
✓ Branch 7 → 8 taken 2334 times.
2334x auto* wrapper = new win_tcp_acceptor(std::move(internal));
1748
1749 {
1750 2334x std::lock_guard<win_mutex> lock(svc_.mutex_);
1751 2334x svc_.acceptor_wrapper_list_.push_back(wrapper);
1752 2334x }
1753
1754 2334x return wrapper;
1755 2334x }
1756
1757 inline void
1758 2334x win_tcp_acceptor_service::destroy(io_object::implementation* p)
1759 {
1760
1/2
✓ Branch 2 → 3 taken 2334 times.
✗ Branch 2 → 5 not taken.
2334x if (p)
1761 {
1762 2334x auto& wrapper = static_cast<win_tcp_acceptor&>(*p);
1763 2334x wrapper.close_internal();
1764 2334x svc_.destroy_acceptor_impl(wrapper);
1765 }
1766 2334x }
1767
1768 inline void
1769 4654x win_tcp_acceptor_service::close(io_object::handle& h)
1770 {
1771 4654x auto& wrapper = static_cast<win_tcp_acceptor&>(*h.get());
1772 4654x wrapper.get_internal()->close_socket();
1773 4654x }
1774
1775 inline std::error_code
1776 2320x win_tcp_acceptor_service::open_acceptor_socket(
1777 tcp_acceptor::implementation& impl, int family, int type, int protocol)
1778 {
1779 2320x auto& wrapper = static_cast<win_tcp_acceptor&>(impl);
1780 2320x return svc_.open_acceptor_socket(
1781 4640x *wrapper.get_internal(), family, type, protocol);
1782 }
1783
1784 inline std::error_code
1785 8x win_tcp_acceptor_service::assign_socket(
1786 tcp_acceptor::implementation& impl, native_handle_type fd)
1787 {
1788 8x auto& wrapper = static_cast<win_tcp_acceptor&>(impl);
1789 8x return svc_.assign_acceptor_socket(*wrapper.get_internal(), fd);
1790 }
1791
1792 inline std::error_code
1793 2316x win_tcp_acceptor_service::bind_acceptor(
1794 tcp_acceptor::implementation& impl, endpoint ep)
1795 {
1796 2316x auto& wrapper = static_cast<win_tcp_acceptor&>(impl);
1797 2316x return svc_.bind_acceptor(*wrapper.get_internal(), ep);
1798 }
1799
1800 inline std::error_code
1801 2298x win_tcp_acceptor_service::listen_acceptor(
1802 tcp_acceptor::implementation& impl, int backlog)
1803 {
1804 2298x auto& wrapper = static_cast<win_tcp_acceptor&>(impl);
1805 2298x return svc_.listen_acceptor(*wrapper.get_internal(), backlog);
1806 }
1807
1808 inline void
1809 1121x win_tcp_acceptor_service::shutdown()
1810 {
1811 1121x }
1812
1813 } // namespace boost::corosio::detail
1814
1815 #endif // BOOST_COROSIO_HAS_IOCP
1816
1817 #endif // BOOST_COROSIO_NATIVE_DETAIL_IOCP_WIN_TCP_ACCEPTOR_SERVICE_HPP
1818