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

96.2% Lines (513/533) 98.5% List of functions (64/65) 79.3% Branches (161/203)
win_local_stream_service.hpp
f(x) Functions (65)
Function Calls Lines Branches Blocks
boost::corosio::detail::win_local_stream_service::scheduler() :118 1047x 100.0% – 100.0% boost::corosio::detail::local_stream_connect_op::local_stream_connect_op(boost::corosio::detail::win_local_stream_socket_internal&) :143 291x 100.0% – 100.0% boost::corosio::detail::local_stream_read_op::local_stream_read_op(boost::corosio::detail::win_local_stream_socket_internal&) :151 291x 100.0% – 100.0% boost::corosio::detail::local_stream_write_op::local_stream_write_op(boost::corosio::detail::win_local_stream_socket_internal&) :159 291x 100.0% – 100.0% boost::corosio::detail::local_stream_wait_op::local_stream_wait_op(boost::corosio::detail::win_local_stream_socket_internal&) :167 291x 100.0% – 100.0% boost::corosio::detail::local_stream_connect_op::do_cancel_impl(boost::corosio::detail::overlapped_op*) :180 0 0.0% 0.0% 0.0% boost::corosio::detail::local_stream_read_op::do_cancel_impl(boost::corosio::detail::overlapped_op*) :192 2x 100.0% 50.0% 88.9% boost::corosio::detail::local_stream_write_op::do_cancel_impl(boost::corosio::detail::overlapped_op*) :204 1x 100.0% 50.0% 88.9% boost::corosio::detail::local_stream_wait_op::do_cancel_impl(boost::corosio::detail::overlapped_op*) :216 1x 100.0% 50.0% 90.9% boost::corosio::detail::local_stream_connect_op::do_complete(void*, boost::corosio::detail::scheduler_op*, unsigned int, unsigned int) :233 26x 100.0% 82.4% 90.9% boost::corosio::detail::local_stream_read_op::do_complete(void*, boost::corosio::detail::scheduler_op*, unsigned int, unsigned int) :277 21x 100.0% 100.0% 84.6% boost::corosio::detail::local_stream_write_op::do_complete(void*, boost::corosio::detail::scheduler_op*, unsigned int, unsigned int) :301 18x 100.0% 100.0% 84.6% boost::corosio::detail::local_stream_wait_op::do_complete(void*, boost::corosio::detail::scheduler_op*, unsigned int, unsigned int) :325 9x 100.0% 100.0% 87.5% boost::corosio::detail::win_local_stream_socket_internal::win_local_stream_socket_internal(boost::corosio::detail::win_local_stream_service&) :353 291x 100.0% – 100.0% boost::corosio::detail::win_local_stream_socket_internal::~win_local_stream_socket_internal() :363 291x 100.0% – 100.0% boost::corosio::detail::win_local_stream_socket_internal::native_handle() const :369 910x 100.0% – 100.0% boost::corosio::detail::win_local_stream_socket_internal::local_endpoint() const :375 2x 100.0% – 100.0% boost::corosio::detail::win_local_stream_socket_internal::remote_endpoint() const :381 2x 100.0% – 100.0% boost::corosio::detail::win_local_stream_socket_internal::is_open() const :387 25x 100.0% – 100.0% boost::corosio::detail::win_local_stream_socket_internal::set_socket(unsigned long long) :393 15x 100.0% – 100.0% boost::corosio::detail::win_local_stream_socket_internal::set_endpoints(boost::corosio::local_endpoint, boost::corosio::local_endpoint) :399 36x 100.0% – 100.0% boost::corosio::detail::win_local_stream_socket_internal::connect(std::__n4861::coroutine_handle<void>, boost::capy::executor_ref, boost::corosio::local_endpoint, std::stop_token, std::error_code*) :407 26x 97.0% 77.8% 83.7% boost::corosio::detail::win_local_stream_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*) :477 21x 97.3% 87.5% 85.7% boost::corosio::detail::win_local_stream_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*) :548 18x 97.1% 87.5% 85.7% boost::corosio::detail::win_local_stream_socket_internal::wait(std::__n4861::coroutine_handle<void>, boost::capy::executor_ref, boost::corosio::wait_type, std::stop_token, std::error_code*) :615 9x 96.7% 81.8% 85.7% boost::corosio::detail::win_local_stream_socket_internal::cancel() :681 10x 100.0% 50.0% 100.0% boost::corosio::detail::win_local_stream_socket_internal::close_socket() :696 724x 100.0% 100.0% 100.0% boost::corosio::detail::win_local_stream_socket::win_local_stream_socket(std::shared_ptr<boost::corosio::detail::win_local_stream_socket_internal>) :722 291x 100.0% – 100.0% boost::corosio::detail::win_local_stream_socket::close_internal() :729 290x 100.0% 50.0% 100.0% boost::corosio::detail::win_local_stream_socket::connect(std::__n4861::coroutine_handle<void>, boost::capy::executor_ref, boost::corosio::local_endpoint, std::stop_token, std::error_code*) :739 26x 100.0% 100.0% 80.0% boost::corosio::detail::win_local_stream_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*) :750 21x 100.0% 100.0% 80.0% boost::corosio::detail::win_local_stream_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*) :762 18x 100.0% 100.0% 80.0% boost::corosio::detail::win_local_stream_socket::wait(std::__n4861::coroutine_handle<void>, boost::capy::executor_ref, boost::corosio::wait_type, std::stop_token, std::error_code*) :774 9x 100.0% 100.0% 80.0% boost::corosio::detail::win_local_stream_socket::shutdown(boost::corosio::shutdown_type) :785 4x 87.5% 83.3% 69.2% boost::corosio::detail::win_local_stream_socket::native_handle() const :809 855x 100.0% – 100.0% boost::corosio::detail::win_local_stream_socket::release_socket() :815 2x 100.0% 50.0% 100.0% boost::corosio::detail::win_local_stream_socket::set_option(int, int, void const*, unsigned long long) :833 3x 100.0% 100.0% 100.0% boost::corosio::detail::win_local_stream_socket::get_option(int, int, void*, unsigned long long*) const :844 2x 100.0% 100.0% 100.0% boost::corosio::detail::win_local_stream_socket::local_endpoint() const :857 2x 100.0% – 100.0% boost::corosio::detail::win_local_stream_socket::remote_endpoint() const :863 2x 100.0% – 100.0% boost::corosio::detail::win_local_stream_socket::cancel() :869 8x 100.0% – 100.0% boost::corosio::detail::win_local_stream_socket::get_internal() const :875 550x 100.0% – 100.0% boost::corosio::detail::win_local_stream_service::win_local_stream_service(boost::capy::execution_context&) :884 91x 100.0% 100.0% 80.0% boost::corosio::detail::win_local_stream_service::~win_local_stream_service() :892 182x 100.0% – 100.0% boost::corosio::detail::win_local_stream_service::shutdown() :904 91x 100.0% 100.0% 100.0% boost::corosio::detail::win_local_stream_service::construct() :922 291x 100.0% 100.0% 89.5% boost::corosio::detail::win_local_stream_service::destroy(boost::corosio::io_object::implementation*) :942 289x 100.0% 50.0% 100.0% boost::corosio::detail::win_local_stream_service::close(boost::corosio::io_object::handle&) :953 383x 100.0% – 100.0% boost::corosio::detail::win_local_stream_service::destroy_impl(boost::corosio::detail::win_local_stream_socket&) :960 289x 100.0% 50.0% 100.0% boost::corosio::detail::win_local_stream_service::unregister_impl(boost::corosio::detail::win_local_stream_socket_internal&) :970 291x 100.0% – 100.0% boost::corosio::detail::win_local_stream_service::open_socket(boost::corosio::local_stream_socket::implementation&, int, int, int) :978 44x 100.0% – 100.0% boost::corosio::detail::win_local_stream_service::assign_socket(boost::corosio::local_stream_socket::implementation&, unsigned long long) :990 93x 90.9% 75.0% 88.0% boost::corosio::detail::win_local_stream_service::open_socket_internal(boost::corosio::detail::win_local_stream_socket_internal&, int, int, int) :1038 44x 100.0% 100.0% 100.0% boost::corosio::detail::win_local_stream_service::native_handle() const :1066 24x 100.0% – 100.0% boost::corosio::detail::win_local_stream_service::connect_ex() const :1072 25x 100.0% – 100.0% boost::corosio::detail::win_local_stream_service::accept_ex() const :1078 23x 100.0% – 100.0% boost::corosio::detail::win_local_stream_service::on_pending(boost::corosio::detail::overlapped_op*) :1090 77x 100.0% – 100.0% boost::corosio::detail::win_local_stream_service::on_completion(boost::corosio::detail::overlapped_op*, unsigned long, unsigned long) :1096 22x 100.0% – 100.0% boost::corosio::detail::win_local_stream_service::work_started() :1103 106x 100.0% – 100.0% boost::corosio::detail::win_local_stream_service::destroy_acceptor_impl(boost::corosio::detail::win_local_stream_acceptor&) :1115 92x 100.0% 50.0% 100.0% boost::corosio::detail::win_local_stream_service::unregister_acceptor_impl(boost::corosio::detail::win_local_stream_acceptor_internal&) :1125 92x 100.0% – 100.0% boost::corosio::detail::win_local_stream_service::open_acceptor_socket(boost::corosio::detail::win_local_stream_acceptor_internal&, int, int, int) :1133 62x 100.0% 100.0% 100.0% boost::corosio::detail::win_local_stream_service::assign_acceptor_socket(boost::corosio::detail::win_local_stream_acceptor_internal&, unsigned long long) :1162 21x 92.0% 82.4% 72.7% boost::corosio::detail::win_local_stream_service::bind_acceptor(boost::corosio::detail::win_local_stream_acceptor_internal&, boost::corosio::local_endpoint) :1201 45x 100.0% 100.0% 100.0% boost::corosio::detail::win_local_stream_service::listen_acceptor(boost::corosio::detail::win_local_stream_acceptor_internal&, int) :1222 36x 100.0% 100.0% 100.0%
Line Branch TLA Hits Source Code
1 //
2 // Copyright (c) 2026 Michael Vandeberg
3 //
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)
6 //
7 // Official repository: https://github.com/cppalliance/corosio
8 //
9
10 #ifndef BOOST_COROSIO_NATIVE_DETAIL_IOCP_WIN_LOCAL_STREAM_SERVICE_HPP
11 #define BOOST_COROSIO_NATIVE_DETAIL_IOCP_WIN_LOCAL_STREAM_SERVICE_HPP
12
13 #include <boost/corosio/detail/platform.hpp>
14
15 #if BOOST_COROSIO_HAS_IOCP
16
17 #include <boost/corosio/detail/config.hpp>
18 #include <boost/corosio/detail/local_stream_service.hpp>
19
20 #include <boost/corosio/native/detail/iocp/win_dissociate.hpp>
21 #include <boost/corosio/native/detail/iocp/win_local_stream_acceptor.hpp>
22 #include <boost/corosio/native/detail/iocp/win_local_stream_socket.hpp>
23 #include <boost/corosio/native/detail/iocp/win_tcp_acceptor_service.hpp>
24 #include <boost/corosio/native/detail/iocp/win_scheduler.hpp>
25 #include <boost/corosio/native/detail/iocp/win_completion_key.hpp>
26 #include <boost/corosio/native/detail/iocp/win_mutex.hpp>
27 #include <boost/corosio/native/detail/iocp/win_wsa_init.hpp>
28
29 #include <boost/corosio/native/detail/endpoint_convert.hpp>
30 #include <boost/corosio/native/detail/make_err.hpp>
31 #include <boost/corosio/detail/dispatch_coro.hpp>
32
33 #include <ws2tcpip.h>
34
35 namespace boost::corosio::detail {
36
37 class win_local_stream_acceptor;
38 class win_local_stream_acceptor_internal;
39 class win_local_stream_acceptor_service;
40
41 /* IOCP local stream socket service.
42
43 Inherits from local_stream_service to enable runtime polymorphism
44 via use_service<local_stream_service>(). Reuses the ConnectEx /
45 AcceptEx function pointers already loaded by win_tcp_service.
46 */
47 class BOOST_COROSIO_DECL win_local_stream_service final
48 : private win_wsa_init
49 , public local_stream_service
50 {
51 public:
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 explicit win_local_stream_service(capy::execution_context& ctx);
59
60 ~win_local_stream_service();
61
62 win_local_stream_service(win_local_stream_service const&) = delete;
63 win_local_stream_service&
64 operator=(win_local_stream_service const&) = delete;
65
66 void shutdown() override;
67
68 std::error_code open_socket(
69 local_stream_socket::implementation& impl,
70 int family,
71 int type,
72 int protocol) override;
73
74 std::error_code assign_socket(
75 local_stream_socket::implementation& impl,
76 native_handle_type fd) override;
77
78 void destroy_impl(win_local_stream_socket& impl);
79
80 void unregister_impl(win_local_stream_socket_internal& impl);
81
82 std::error_code open_socket_internal(
83 win_local_stream_socket_internal& impl,
84 int family,
85 int type,
86 int protocol);
87
88 void destroy_acceptor_impl(win_local_stream_acceptor& impl);
89
90 void unregister_acceptor_impl(win_local_stream_acceptor_internal& impl);
91
92 std::error_code open_acceptor_socket(
93 win_local_stream_acceptor_internal& impl,
94 int family,
95 int type,
96 int protocol);
97
98 std::error_code assign_acceptor_socket(
99 win_local_stream_acceptor_internal& impl, native_handle_type fd);
100
101 std::error_code bind_acceptor(
102 win_local_stream_acceptor_internal& impl, corosio::local_endpoint ep);
103
104 std::error_code
105 listen_acceptor(win_local_stream_acceptor_internal& impl, int backlog);
106
107 void* native_handle() const noexcept;
108 LPFN_CONNECTEX connect_ex() const noexcept;
109 LPFN_ACCEPTEX accept_ex() const noexcept;
110
111 void post(overlapped_op* op);
112 void on_pending(overlapped_op* op) noexcept;
113 void on_completion(overlapped_op* op, DWORD error, DWORD bytes) noexcept;
114 void work_started() noexcept;
115 void work_finished() noexcept;
116
117 /** Return the owning IOCP scheduler. */
118 1047x win_scheduler& scheduler() noexcept
119 {
120 1047x return sched_;
121 }
122
123 private:
124 friend class win_local_stream_acceptor_service;
125
126 win_tcp_service& tcp_svc_;
127 win_scheduler& sched_;
128 BOOST_COROSIO_MSVC_WARNING_PUSH
129 BOOST_COROSIO_MSVC_WARNING_DISABLE(4251) // detail:: members, dll-interface
130 win_mutex mutex_;
131 intrusive_list<win_local_stream_socket_internal> socket_list_;
132 intrusive_list<win_local_stream_acceptor_internal> acceptor_list_;
133 intrusive_list<win_local_stream_socket> socket_wrapper_list_;
134 intrusive_list<win_local_stream_acceptor> acceptor_wrapper_list_;
135 BOOST_COROSIO_MSVC_WARNING_POP
136 void* iocp_;
137 };
138
139 // ============================================================
140 // Operation constructors
141 // ============================================================
142
143 291x inline local_stream_connect_op::local_stream_connect_op(
144 291x win_local_stream_socket_internal& internal_) noexcept
145 : overlapped_op(&do_complete)
146 291x , internal(internal_)
147 {
148 291x cancel_func_ = &do_cancel_impl;
149 291x }
150
151 291x inline local_stream_read_op::local_stream_read_op(
152 291x win_local_stream_socket_internal& internal_) noexcept
153 : overlapped_op(&do_complete)
154 291x , internal(internal_)
155 {
156 291x cancel_func_ = &do_cancel_impl;
157 291x }
158
159 291x inline local_stream_write_op::local_stream_write_op(
160 291x win_local_stream_socket_internal& internal_) noexcept
161 : overlapped_op(&do_complete)
162 291x , internal(internal_)
163 {
164 291x cancel_func_ = &do_cancel_impl;
165 291x }
166
167 291x inline local_stream_wait_op::local_stream_wait_op(
168 291x win_local_stream_socket_internal& internal_) noexcept
169 : overlapped_op(&do_complete)
170 291x , internal(internal_)
171 {
172 291x cancel_func_ = &do_cancel_impl;
173 291x }
174
175 // ============================================================
176 // Cancellation functions
177 // ============================================================
178
179 inline void
180 ✗ local_stream_connect_op::do_cancel_impl(overlapped_op* base) noexcept
181 {
182 ✗ auto* op = static_cast<local_stream_connect_op*>(base);
183 ✗ op->cancelled.store(true, std::memory_order_release);
184 ✗ if (op->internal.is_open())
185 {
186 ✗ ::CancelIoEx(
187 ✗ reinterpret_cast<HANDLE>(op->internal.native_handle()), op);
188 }
189 ✗ }
190
191 inline void
192 2x local_stream_read_op::do_cancel_impl(overlapped_op* base) noexcept
193 {
194 2x auto* op = static_cast<local_stream_read_op*>(base);
195 2x op->cancelled.store(true, std::memory_order_release);
196
1/2
✓ Branch 4 → 5 taken 2 times.
✗ Branch 4 → 10 not taken.
2x if (op->internal.is_open())
197 {
198
1/2
✓ Branch 5 → 6 taken 2 times.
✗ Branch 5 → 7 not taken.
4x ::CancelIoEx(
199 2x reinterpret_cast<HANDLE>(op->internal.native_handle()), op);
200 }
201 2x }
202
203 inline void
204 1x local_stream_write_op::do_cancel_impl(overlapped_op* base) noexcept
205 {
206 1x auto* op = static_cast<local_stream_write_op*>(base);
207 1x op->cancelled.store(true, std::memory_order_release);
208
1/2
✓ Branch 4 → 5 taken 1 time.
✗ Branch 4 → 10 not taken.
1x if (op->internal.is_open())
209 {
210
1/2
✓ Branch 5 → 6 taken 1 time.
✗ Branch 5 → 7 not taken.
2x ::CancelIoEx(
211 1x reinterpret_cast<HANDLE>(op->internal.native_handle()), op);
212 }
213 1x }
214
215 inline void
216 1x local_stream_wait_op::do_cancel_impl(overlapped_op* base) noexcept
217 {
218 1x auto* op = static_cast<local_stream_wait_op*>(base);
219 1x op->cancelled.store(true, std::memory_order_release);
220
1/2
✓ Branch 4 → 5 taken 1 time.
✗ Branch 4 → 10 not taken.
1x if (op->internal.is_open())
221 {
222
1/2
✓ Branch 5 → 6 taken 1 time.
✗ Branch 5 → 7 not taken.
2x ::CancelIoEx(
223 1x reinterpret_cast<HANDLE>(op->internal.native_handle()), op);
224 }
225 1x op->internal.svc_.scheduler().cancel_wait(op);
226 1x }
227
228 // ============================================================
229 // connect_op completion handler
230 // ============================================================
231
232 inline void
233 26x local_stream_connect_op::do_complete(
234 void* owner,
235 scheduler_op* base,
236 std::uint32_t /*bytes*/,
237 std::uint32_t /*error*/)
238 {
239 26x auto* op = static_cast<local_stream_connect_op*>(base);
240
241
2/2
✓ Branch 2 → 3 taken 1 time.
✓ Branch 2 → 6 taken 25 times.
26x if (!owner)
242 {
243 1x op->cleanup_only();
244 1x op->internal_ptr.reset();
245 1x return;
246 }
247
248 bool success =
249
3/4
✓ Branch 6 → 7 taken 21 times.
✓ Branch 6 → 10 taken 4 times.
✓ Branch 8 → 9 taken 21 times.
✗ Branch 8 → 10 not taken.
25x (op->dwError == 0 && !op->cancelled.load(std::memory_order_acquire));
250
5/6
✓ Branch 11 → 12 taken 21 times.
✓ Branch 11 → 15 taken 4 times.
✓ Branch 13 → 14 taken 21 times.
✗ Branch 13 → 15 not taken.
✓ Branch 16 → 17 taken 21 times.
✓ Branch 16 → 25 taken 4 times.
25x if (success && op->internal.is_open())
251 {
252 // Required after ConnectEx
253
1/1
✓ Branch 18 → 19 taken 21 times.
21x ::setsockopt(
254 21x op->internal.native_handle(), SOL_SOCKET, SO_UPDATE_CONNECT_CONTEXT,
255 nullptr, 0);
256
257 21x corosio::local_endpoint local_ep;
258 21x sockaddr_storage local_storage{};
259 21x int local_len = sizeof(local_storage);
260
1/1
✓ Branch 20 → 21 taken 21 times.
21x if (::getsockname(
261 21x op->internal.native_handle(),
262
1/2
✓ Branch 21 → 22 taken 21 times.
✗ Branch 21 → 23 not taken.
21x reinterpret_cast<sockaddr*>(&local_storage), &local_len) == 0)
263 21x local_ep = from_sockaddr_local(
264 local_storage, static_cast<socklen_t>(local_len));
265 21x op->internal.set_endpoints(local_ep, op->target_endpoint);
266 }
267
268 25x auto prevent_premature_destruction = std::move(op->internal_ptr);
269
1/1
✓ Branch 27 → 28 taken 25 times.
25x op->invoke_handler();
270 25x }
271
272 // ============================================================
273 // read_op completion handler
274 // ============================================================
275
276 inline void
277 21x local_stream_read_op::do_complete(
278 void* owner,
279 scheduler_op* base,
280 std::uint32_t /*bytes*/,
281 std::uint32_t /*error*/)
282 {
283 21x auto* op = static_cast<local_stream_read_op*>(base);
284
285
2/2
✓ Branch 2 → 3 taken 3 times.
✓ Branch 2 → 6 taken 18 times.
21x if (!owner)
286 {
287 3x op->cleanup_only();
288 3x op->internal_ptr.reset();
289 3x return;
290 }
291
292 18x auto prevent_premature_destruction = std::move(op->internal_ptr);
293
1/1
✓ Branch 8 → 9 taken 18 times.
18x op->invoke_handler();
294 18x }
295
296 // ============================================================
297 // write_op completion handler
298 // ============================================================
299
300 inline void
301 18x local_stream_write_op::do_complete(
302 void* owner,
303 scheduler_op* base,
304 std::uint32_t /*bytes*/,
305 std::uint32_t /*error*/)
306 {
307 18x auto* op = static_cast<local_stream_write_op*>(base);
308
309
2/2
✓ Branch 2 → 3 taken 1 time.
✓ Branch 2 → 6 taken 17 times.
18x if (!owner)
310 {
311 1x op->cleanup_only();
312 1x op->internal_ptr.reset();
313 1x return;
314 }
315
316 17x auto prevent_premature_destruction = std::move(op->internal_ptr);
317
1/1
✓ Branch 8 → 9 taken 17 times.
17x op->invoke_handler();
318 17x }
319
320 // ============================================================
321 // wait_op completion handler
322 // ============================================================
323
324 inline void
325 9x local_stream_wait_op::do_complete(
326 void* owner,
327 scheduler_op* base,
328 std::uint32_t /*bytes*/,
329 std::uint32_t /*error*/)
330 {
331 9x auto* op = static_cast<local_stream_wait_op*>(base);
332
333
2/2
✓ Branch 2 → 3 taken 1 time.
✓ Branch 2 → 6 taken 8 times.
9x if (!owner)
334 {
335 1x op->cleanup_only();
336 1x op->internal_ptr.reset();
337 1x return;
338 }
339
340 // Only the zero-byte WSARecv read wait; write and error waits come
341 // from the poll reactor through this op too.
342
2/2
✓ Branch 6 → 7 taken 6 times.
✓ Branch 6 → 9 taken 2 times.
8x if (op->w == wait_type::read)
343 6x op->dwError = normalize_read_wait_error(op->dwError);
344
345 8x auto prevent_premature_destruction = std::move(op->internal_ptr);
346
1/1
✓ Branch 11 → 12 taken 8 times.
8x op->invoke_handler();
347 8x }
348
349 // ============================================================
350 // win_local_stream_socket_internal
351 // ============================================================
352
353 291x inline win_local_stream_socket_internal::win_local_stream_socket_internal(
354 291x win_local_stream_service& svc) noexcept
355 291x : svc_(svc)
356 291x , conn_(*this)
357 291x , rd_(*this)
358 291x , wr_(*this)
359 582x , wt_(*this)
360 {
361 291x }
362
363 291x inline win_local_stream_socket_internal::~win_local_stream_socket_internal()
364 {
365 291x svc_.unregister_impl(*this);
366 291x }
367
368 inline SOCKET
369 910x win_local_stream_socket_internal::native_handle() const noexcept
370 {
371 910x return socket_;
372 }
373
374 inline corosio::local_endpoint
375 2x win_local_stream_socket_internal::local_endpoint() const noexcept
376 {
377 2x return local_endpoint_;
378 }
379
380 inline corosio::local_endpoint
381 2x win_local_stream_socket_internal::remote_endpoint() const noexcept
382 {
383 2x return remote_endpoint_;
384 }
385
386 inline bool
387 25x win_local_stream_socket_internal::is_open() const noexcept
388 {
389 25x return socket_ != INVALID_SOCKET;
390 }
391
392 inline void
393 15x win_local_stream_socket_internal::set_socket(SOCKET s) noexcept
394 {
395 15x socket_ = s;
396 15x }
397
398 inline void
399 36x win_local_stream_socket_internal::set_endpoints(
400 corosio::local_endpoint local, corosio::local_endpoint remote) noexcept
401 {
402 36x local_endpoint_ = local;
403 36x remote_endpoint_ = remote;
404 36x }
405
406 inline std::coroutine_handle<>
407 26x win_local_stream_socket_internal::connect(
408 std::coroutine_handle<> h,
409 capy::executor_ref d,
410 corosio::local_endpoint ep,
411 std::stop_token token,
412 std::error_code* ec)
413 {
414
1/1
✓ Branch 2 → 3 taken 26 times.
26x conn_.internal_ptr = shared_from_this();
415
416 26x auto& op = conn_;
417 26x op.reset();
418 26x op.h = h;
419 26x op.ex = d;
420 26x op.ec_out = ec;
421 26x op.target_endpoint = ep;
422 26x op.start(token);
423
424 26x svc_.work_started();
425
426 // ConnectEx requires the socket to be bound. For AF_UNIX,
427 // bind to a family-only sockaddr_un (empty path).
428
1/2
✓ Branch 9 → 10 taken 26 times.
✗ Branch 9 → 18 not taken.
26x if (local_endpoint_.empty())
429 {
430 26x un_sa_t bind_sa{};
431 26x bind_sa.sun_family = AF_UNIX;
432 26x socklen_t bind_len =
433 static_cast<socklen_t>(offsetof(un_sa_t, sun_path));
434
435
3/3
✓ Branch 10 → 11 taken 26 times.
✓ Branch 11 → 12 taken 1 time.
✓ Branch 11 → 17 taken 25 times.
26x if (::bind(socket_, reinterpret_cast<sockaddr*>(&bind_sa), bind_len) ==
436 SOCKET_ERROR)
437 {
438
1/1
✓ Branch 12 → 13 taken 1 time.
1x svc_.on_completion(&op, ::WSAGetLastError(), 0);
439 1x return std::noop_coroutine();
440 }
441 }
442
443 25x auto connect_ex = svc_.connect_ex();
444
2/2
✓ Branch 19 → 20 taken 1 time.
✓ Branch 19 → 24 taken 24 times.
25x if (!connect_ex)
445 {
446 1x svc_.on_completion(&op, WSAEOPNOTSUPP, 0);
447 1x return std::noop_coroutine();
448 }
449
450 24x sockaddr_storage storage{};
451 24x socklen_t addrlen = detail::to_sockaddr(ep, storage);
452
453
1/1
✓ Branch 25 → 26 taken 24 times.
24x BOOL result = connect_ex(
454 socket_, reinterpret_cast<sockaddr*>(&storage),
455 static_cast<int>(addrlen), nullptr, 0, nullptr, &op);
456
457
1/2
✓ Branch 26 → 27 taken 24 times.
✗ Branch 26 → 33 not taken.
24x if (!result)
458 {
459
1/1
✓ Branch 27 → 28 taken 24 times.
24x DWORD err = ::WSAGetLastError();
460
2/2
✓ Branch 28 → 29 taken 2 times.
✓ Branch 28 → 33 taken 22 times.
24x if (err != ERROR_IO_PENDING)
461 {
462 2x svc_.on_completion(&op, err, 0);
463 2x return std::noop_coroutine();
464 }
465 }
466
467 22x svc_.on_pending(&op);
468
469 // Re-check cancellation after I/O is pending
470
1/2
✗ Branch 35 → 36 not taken.
✓ Branch 35 → 37 taken 22 times.
22x if (op.cancelled.load(std::memory_order_acquire))
471 ✗ ::CancelIoEx(reinterpret_cast<HANDLE>(socket_), &op);
472
473 22x return std::noop_coroutine();
474 }
475
476 inline std::coroutine_handle<>
477 21x win_local_stream_socket_internal::read_some(
478 std::coroutine_handle<> h,
479 capy::executor_ref d,
480 buffer_param param,
481 std::stop_token token,
482 std::error_code* ec,
483 std::size_t* bytes_out)
484 {
485
1/1
✓ Branch 2 → 3 taken 21 times.
21x rd_.internal_ptr = shared_from_this();
486
487 21x auto& op = rd_;
488 21x op.reset();
489 21x op.is_read = true;
490 21x op.h = h;
491 21x op.ex = d;
492 21x op.ec_out = ec;
493 21x op.bytes_out = bytes_out;
494 21x op.start(token);
495
496 21x svc_.work_started();
497
498 // Closed-object contract: complete with bad_file_descriptor
499 // without touching the kernel.
500
2/2
✓ Branch 8 → 9 taken 2 times.
✓ Branch 8 → 13 taken 19 times.
21x if (socket_ == INVALID_SOCKET)
501 {
502 2x svc_.on_completion(&op, WSAEBADF, 0);
503 2x return std::noop_coroutine();
504 }
505
506 19x capy::mutable_buffer bufs[local_stream_read_op::max_buffers];
507 19x op.wsabuf_count = static_cast<DWORD>(
508 19x param.copy_to(bufs, local_stream_read_op::max_buffers));
509
510
2/2
✓ Branch 14 → 15 taken 1 time.
✓ Branch 14 → 19 taken 18 times.
19x if (op.wsabuf_count == 0)
511 {
512 1x op.empty_buffer = true;
513 1x svc_.on_completion(&op, 0, 0);
514 1x return std::noop_coroutine();
515 }
516
517
2/2
✓ Branch 24 → 20 taken 18 times.
✓ Branch 24 → 25 taken 18 times.
36x for (DWORD i = 0; i < op.wsabuf_count; ++i)
518 {
519 18x op.wsabufs[i].buf = static_cast<char*>(bufs[i].data());
520 18x op.wsabufs[i].len = static_cast<ULONG>(
521 18x (std::min)(bufs[i].size(), std::size_t(0x7fffffff)));
522 }
523
524 18x op.flags = 0;
525
526 36x int result = ::WSARecv(
527
1/1
✓ Branch 25 → 26 taken 18 times.
18x socket_, op.wsabufs, op.wsabuf_count, nullptr, &op.flags, &op, nullptr);
528
529
2/2
✓ Branch 26 → 27 taken 15 times.
✓ Branch 26 → 33 taken 3 times.
18x if (result == SOCKET_ERROR)
530 {
531
1/1
✓ Branch 27 → 28 taken 15 times.
15x DWORD err = ::WSAGetLastError();
532
2/2
✓ Branch 28 → 29 taken 1 time.
✓ Branch 28 → 33 taken 14 times.
15x if (err != WSA_IO_PENDING)
533 {
534 1x svc_.on_completion(&op, err, 0);
535 1x return std::noop_coroutine();
536 }
537 }
538
539 17x svc_.on_pending(&op);
540
541
1/2
✗ Branch 35 → 36 not taken.
✓ Branch 35 → 37 taken 17 times.
17x if (op.cancelled.load(std::memory_order_acquire))
542 ✗ ::CancelIoEx(reinterpret_cast<HANDLE>(socket_), &op);
543
544 17x return std::noop_coroutine();
545 }
546
547 inline std::coroutine_handle<>
548 18x win_local_stream_socket_internal::write_some(
549 std::coroutine_handle<> h,
550 capy::executor_ref d,
551 buffer_param param,
552 std::stop_token token,
553 std::error_code* ec,
554 std::size_t* bytes_out)
555 {
556
1/1
✓ Branch 2 → 3 taken 18 times.
18x wr_.internal_ptr = shared_from_this();
557
558 18x auto& op = wr_;
559 18x op.reset();
560 18x op.h = h;
561 18x op.ex = d;
562 18x op.ec_out = ec;
563 18x op.bytes_out = bytes_out;
564 18x op.start(token);
565
566 18x svc_.work_started();
567
568 // Closed-object contract: complete with bad_file_descriptor
569 // without touching the kernel.
570
2/2
✓ Branch 8 → 9 taken 2 times.
✓ Branch 8 → 13 taken 16 times.
18x if (socket_ == INVALID_SOCKET)
571 {
572 2x svc_.on_completion(&op, WSAEBADF, 0);
573 2x return std::noop_coroutine();
574 }
575
576 16x capy::mutable_buffer bufs[local_stream_write_op::max_buffers];
577 16x op.wsabuf_count = static_cast<DWORD>(
578 16x param.copy_to(bufs, local_stream_write_op::max_buffers));
579
580
2/2
✓ Branch 14 → 15 taken 1 time.
✓ Branch 14 → 19 taken 15 times.
16x if (op.wsabuf_count == 0)
581 {
582 1x svc_.on_completion(&op, 0, 0);
583 1x return std::noop_coroutine();
584 }
585
586
2/2
✓ Branch 24 → 20 taken 15 times.
✓ Branch 24 → 25 taken 15 times.
30x for (DWORD i = 0; i < op.wsabuf_count; ++i)
587 {
588 15x op.wsabufs[i].buf = static_cast<char*>(bufs[i].data());
589 15x op.wsabufs[i].len = static_cast<ULONG>(
590 15x (std::min)(bufs[i].size(), std::size_t(0x7fffffff)));
591 }
592
593 30x int result = ::WSASend(
594
1/1
✓ Branch 25 → 26 taken 15 times.
15x socket_, op.wsabufs, op.wsabuf_count, nullptr, 0, &op, nullptr);
595
596
2/2
✓ Branch 26 → 27 taken 2 times.
✓ Branch 26 → 33 taken 13 times.
15x if (result == SOCKET_ERROR)
597 {
598
1/1
✓ Branch 27 → 28 taken 2 times.
2x DWORD err = ::WSAGetLastError();
599
2/2
✓ Branch 28 → 29 taken 1 time.
✓ Branch 28 → 33 taken 1 time.
2x if (err != WSA_IO_PENDING)
600 {
601 1x svc_.on_completion(&op, err, 0);
602 1x return std::noop_coroutine();
603 }
604 }
605
606 14x svc_.on_pending(&op);
607
608
1/2
✗ Branch 35 → 36 not taken.
✓ Branch 35 → 37 taken 14 times.
14x if (op.cancelled.load(std::memory_order_acquire))
609 ✗ ::CancelIoEx(reinterpret_cast<HANDLE>(socket_), &op);
610
611 14x return std::noop_coroutine();
612 }
613
614 inline std::coroutine_handle<>
615 9x win_local_stream_socket_internal::wait(
616 std::coroutine_handle<> h,
617 capy::executor_ref d,
618 wait_type w,
619 std::stop_token token,
620 std::error_code* ec)
621 {
622
1/1
✓ Branch 2 → 3 taken 9 times.
9x wt_.internal_ptr = shared_from_this();
623
624 9x auto& op = wt_;
625 9x op.reset();
626 9x op.h = h;
627 9x op.ex = d;
628 9x op.ec_out = ec;
629 9x op.bytes_out = nullptr;
630 9x op.empty_buffer = true;
631 9x op.w = w;
632 9x op.start(token);
633
634 9x svc_.work_started();
635
636 // Closed-object contract: complete with bad_file_descriptor
637 // without touching the kernel or the wait reactor.
638
2/2
✓ Branch 8 → 9 taken 2 times.
✓ Branch 8 → 13 taken 7 times.
9x if (socket_ == INVALID_SOCKET)
639 {
640 2x svc_.on_completion(&op, WSAEBADF, 0);
641 2x return std::noop_coroutine();
642 }
643
644
2/2
✓ Branch 13 → 14 taken 5 times.
✓ Branch 13 → 29 taken 2 times.
7x if (w == wait_type::read)
645 {
646 // Zero-byte WSARecv — completes when data is available
647 // without consuming any bytes.
648 5x op.wsabuf = WSABUF{0, nullptr};
649 5x op.flags = 0;
650
651 int result =
652 5x ::WSARecv(socket_, &op.wsabuf, 1, nullptr, &op.flags, &op, nullptr);
653
654
1/2
✓ Branch 15 → 16 taken 5 times.
✗ Branch 15 → 22 not taken.
5x if (result == SOCKET_ERROR)
655 {
656 5x DWORD err = ::WSAGetLastError();
657
2/2
✓ Branch 17 → 18 taken 1 time.
✓ Branch 17 → 22 taken 4 times.
5x if (err != WSA_IO_PENDING)
658 {
659 1x svc_.on_completion(&op, err, 0);
660 1x return std::noop_coroutine();
661 }
662 }
663
664 4x svc_.on_pending(&op);
665
666
1/2
✗ Branch 24 → 25 not taken.
✓ Branch 24 → 26 taken 4 times.
4x if (op.cancelled.load(std::memory_order_acquire))
667 ✗ ::CancelIoEx(reinterpret_cast<HANDLE>(socket_), &op);
668
669 4x return std::noop_coroutine();
670 }
671
672 // wait_type::write and wait_type::error: route through the
673 // auxiliary poll reactor. There is no overlapped primitive for
674 // "the send buffer has room" that does not also transfer bytes,
675 // and a write wait must report real writability.
676 2x svc_.scheduler().wait_reactor().register_wait(socket_, w, &op);
677 2x return std::noop_coroutine();
678 }
679
680 inline void
681 10x win_local_stream_socket_internal::cancel() noexcept
682 {
683
1/2
✓ Branch 2 → 3 taken 10 times.
✗ Branch 2 → 4 not taken.
10x if (socket_ != INVALID_SOCKET)
684 {
685 10x ::CancelIoEx(reinterpret_cast<HANDLE>(socket_), nullptr);
686 }
687
688 10x conn_.request_cancel();
689 10x rd_.request_cancel();
690 10x wr_.request_cancel();
691 10x wt_.request_cancel();
692 10x svc_.scheduler().cancel_wait(&wt_);
693 10x }
694
695 inline void
696 724x win_local_stream_socket_internal::close_socket() noexcept
697 {
698 // Flag every op cancelled before closing so a closesocket-delivered
699 // ERROR_NETNAME_DELETED is short-circuited to canceled rather than mapped
700 // to connection_reset by iocp_make_err (see win_tcp_socket close_socket).
701 724x conn_.request_cancel();
702 724x rd_.request_cancel();
703 724x wr_.request_cancel();
704 724x wt_.request_cancel();
705 724x svc_.scheduler().cancel_wait(&wt_);
706
707
2/2
✓ Branch 8 → 9 taken 104 times.
✓ Branch 8 → 12 taken 620 times.
724x if (socket_ != INVALID_SOCKET)
708 {
709 104x ::CancelIoEx(reinterpret_cast<HANDLE>(socket_), nullptr);
710 104x ::closesocket(socket_);
711 104x socket_ = INVALID_SOCKET;
712 }
713
714 724x local_endpoint_ = corosio::local_endpoint{};
715 724x remote_endpoint_ = corosio::local_endpoint{};
716 724x }
717
718 // ============================================================
719 // win_local_stream_socket (wrapper)
720 // ============================================================
721
722 291x inline win_local_stream_socket::win_local_stream_socket(
723 291x std::shared_ptr<win_local_stream_socket_internal> internal) noexcept
724 291x : internal_(std::move(internal))
725 {
726 291x }
727
728 inline void
729 290x win_local_stream_socket::close_internal() noexcept
730 {
731
1/2
✓ Branch 3 → 4 taken 290 times.
✗ Branch 3 → 7 not taken.
290x if (internal_)
732 {
733 290x internal_->close_socket();
734 290x internal_.reset();
735 }
736 290x }
737
738 inline std::coroutine_handle<>
739 26x win_local_stream_socket::connect(
740 std::coroutine_handle<> h,
741 capy::executor_ref d,
742 corosio::local_endpoint ep,
743 std::stop_token token,
744 std::error_code* ec)
745 {
746
1/1
✓ Branch 4 → 5 taken 26 times.
26x return internal_->connect(h, d, ep, token, ec);
747 }
748
749 inline std::coroutine_handle<>
750 21x win_local_stream_socket::read_some(
751 std::coroutine_handle<> h,
752 capy::executor_ref d,
753 buffer_param buf,
754 std::stop_token token,
755 std::error_code* ec,
756 std::size_t* bytes)
757 {
758
1/1
✓ Branch 4 → 5 taken 21 times.
21x return internal_->read_some(h, d, buf, token, ec, bytes);
759 }
760
761 inline std::coroutine_handle<>
762 18x win_local_stream_socket::write_some(
763 std::coroutine_handle<> h,
764 capy::executor_ref d,
765 buffer_param buf,
766 std::stop_token token,
767 std::error_code* ec,
768 std::size_t* bytes)
769 {
770
1/1
✓ Branch 4 → 5 taken 18 times.
18x return internal_->write_some(h, d, buf, token, ec, bytes);
771 }
772
773 inline std::coroutine_handle<>
774 9x win_local_stream_socket::wait(
775 std::coroutine_handle<> h,
776 capy::executor_ref d,
777 wait_type w,
778 std::stop_token token,
779 std::error_code* ec)
780 {
781
1/1
✓ Branch 4 → 5 taken 9 times.
9x return internal_->wait(h, d, w, token, ec);
782 }
783
784 inline std::error_code
785 4x win_local_stream_socket::shutdown(
786 local_stream_socket::shutdown_type what) noexcept
787 {
788 int how;
789
3/4
✓ Branch 2 → 3 taken 1 time.
✓ Branch 2 → 4 taken 2 times.
✓ Branch 2 → 5 taken 1 time.
✗ Branch 2 → 6 not taken.
4x switch (what)
790 {
791 1x case local_stream_socket::shutdown_receive:
792 1x how = SD_RECEIVE;
793 1x break;
794 2x case local_stream_socket::shutdown_send:
795 2x how = SD_SEND;
796 2x break;
797 1x case local_stream_socket::shutdown_both:
798 1x how = SD_BOTH;
799 1x break;
800 ✗ default:
801 ✗ return make_err(WSAEINVAL);
802 }
803
2/2
✓ Branch 10 → 11 taken 1 time.
✓ Branch 10 → 13 taken 3 times.
4x if (::shutdown(internal_->native_handle(), how) != 0)
804 1x return make_err(WSAGetLastError());
805 3x return {};
806 }
807
808 inline native_handle_type
809 855x win_local_stream_socket::native_handle() const noexcept
810 {
811 855x return static_cast<native_handle_type>(internal_->native_handle());
812 }
813
814 inline native_handle_type
815 2x win_local_stream_socket::release_socket() noexcept
816 {
817 2x SOCKET s = internal_->socket_;
818
1/2
✓ Branch 3 → 4 taken 2 times.
✗ Branch 3 → 13 not taken.
2x if (s != INVALID_SOCKET)
819 {
820 2x internal_->cancel();
821 // Sever the port association so the descriptor can be
822 // adopted again; best-effort, the caller keeps a working
823 // socket either way.
824 2x dissociate_from_iocp(s);
825 2x internal_->socket_ = INVALID_SOCKET;
826 2x internal_->local_endpoint_ = corosio::local_endpoint{};
827 2x internal_->remote_endpoint_ = corosio::local_endpoint{};
828 }
829 2x return static_cast<native_handle_type>(s);
830 }
831
832 inline std::error_code
833 3x win_local_stream_socket::set_option(
834 int level, int optname, void const* data, std::size_t size) noexcept
835 {
836 3x if (::setsockopt(
837 3x internal_->native_handle(), level, optname,
838
2/2
✓ Branch 5 → 6 taken 1 time.
✓ Branch 5 → 8 taken 2 times.
3x reinterpret_cast<char const*>(data), static_cast<int>(size)) != 0)
839 1x return make_err(WSAGetLastError());
840 2x return {};
841 }
842
843 inline std::error_code
844 2x win_local_stream_socket::get_option(
845 int level, int optname, void* data, std::size_t* size) const noexcept
846 {
847 2x int len = static_cast<int>(*size);
848 2x if (::getsockopt(
849 2x internal_->native_handle(), level, optname,
850
2/2
✓ Branch 5 → 6 taken 1 time.
✓ Branch 5 → 8 taken 1 time.
2x reinterpret_cast<char*>(data), &len) != 0)
851 1x return make_err(WSAGetLastError());
852 1x *size = static_cast<std::size_t>(len);
853 1x return {};
854 }
855
856 inline corosio::local_endpoint
857 2x win_local_stream_socket::local_endpoint() const noexcept
858 {
859 2x return internal_->local_endpoint();
860 }
861
862 inline corosio::local_endpoint
863 2x win_local_stream_socket::remote_endpoint() const noexcept
864 {
865 2x return internal_->remote_endpoint();
866 }
867
868 inline void
869 8x win_local_stream_socket::cancel() noexcept
870 {
871 8x internal_->cancel();
872 8x }
873
874 inline win_local_stream_socket_internal*
875 550x win_local_stream_socket::get_internal() const noexcept
876 {
877 550x return internal_.get();
878 }
879
880 // ============================================================
881 // win_local_stream_service
882 // ============================================================
883
884 91x inline win_local_stream_service::win_local_stream_service(
885 91x capy::execution_context& ctx)
886 182x : tcp_svc_(ctx.use_service<win_tcp_service>())
887
1/1
✓ Branch 5 → 6 taken 91 times.
91x , sched_(ctx.use_service<win_scheduler>())
888
2/2
✓ Branch 4 → 5 taken 91 times.
✓ Branch 6 → 7 taken 91 times.
182x , iocp_(sched_.native_handle())
889 {
890 91x }
891
892 182x inline win_local_stream_service::~win_local_stream_service()
893 {
894
2/2
✓ Branch 6 → 3 taken 2 times.
✓ Branch 6 → 7 taken 91 times.
93x for (auto* w = socket_wrapper_list_.pop_front(); w != nullptr;
895 2x w = socket_wrapper_list_.pop_front())
896
1/2
✓ Branch 3 → 4 taken 2 times.
✗ Branch 3 → 5 not taken.
2x delete w;
897
898
1/2
✗ Branch 11 → 8 not taken.
✓ Branch 11 → 12 taken 91 times.
91x for (auto* w = acceptor_wrapper_list_.pop_front(); w != nullptr;
899 ✗ w = acceptor_wrapper_list_.pop_front())
900 ✗ delete w;
901 182x }
902
903 inline void
904 91x win_local_stream_service::shutdown()
905 {
906 91x std::lock_guard<win_mutex> lock(mutex_);
907
908
2/2
✓ Branch 6 → 4 taken 7 times.
✓ Branch 6 → 7 taken 91 times.
98x for (auto* impl = socket_list_.pop_front(); impl != nullptr;
909 7x impl = socket_list_.pop_front())
910 {
911 7x impl->close_socket();
912 }
913
914
2/2
✓ Branch 10 → 8 taken 2 times.
✓ Branch 10 → 11 taken 91 times.
93x for (auto* impl = acceptor_list_.pop_front(); impl != nullptr;
915 2x impl = acceptor_list_.pop_front())
916 {
917 2x impl->close_socket();
918 }
919 91x }
920
921 inline io_object::implementation*
922 291x win_local_stream_service::construct()
923 {
924
1/1
✓ Branch 2 → 3 taken 291 times.
291x auto internal = std::make_shared<win_local_stream_socket_internal>(*this);
925
926 {
927 291x std::lock_guard<win_mutex> lock(mutex_);
928 291x socket_list_.push_back(internal.get());
929 291x }
930
931
1/1
✓ Branch 7 → 8 taken 291 times.
291x auto* wrapper = new win_local_stream_socket(std::move(internal));
932
933 {
934 291x std::lock_guard<win_mutex> lock(mutex_);
935 291x socket_wrapper_list_.push_back(wrapper);
936 291x }
937
938 291x return wrapper;
939 291x }
940
941 inline void
942 289x win_local_stream_service::destroy(io_object::implementation* p)
943 {
944
1/2
✓ Branch 2 → 3 taken 289 times.
✗ Branch 2 → 5 not taken.
289x if (p)
945 {
946 289x auto& wrapper = static_cast<win_local_stream_socket&>(*p);
947 289x wrapper.close_internal();
948 289x destroy_impl(wrapper);
949 }
950 289x }
951
952 inline void
953 383x win_local_stream_service::close(io_object::handle& h)
954 {
955 383x auto& wrapper = static_cast<win_local_stream_socket&>(*h.get());
956 383x wrapper.get_internal()->close_socket();
957 383x }
958
959 inline void
960 289x win_local_stream_service::destroy_impl(win_local_stream_socket& impl)
961 {
962 {
963 289x std::lock_guard<win_mutex> lock(mutex_);
964 289x socket_wrapper_list_.remove(&impl);
965 289x }
966
1/2
✓ Branch 5 → 6 taken 289 times.
✗ Branch 5 → 7 not taken.
289x delete &impl;
967 289x }
968
969 inline void
970 291x win_local_stream_service::unregister_impl(
971 win_local_stream_socket_internal& impl)
972 {
973 291x std::lock_guard<win_mutex> lock(mutex_);
974 291x socket_list_.remove(&impl);
975 291x }
976
977 inline std::error_code
978 44x win_local_stream_service::open_socket(
979 local_stream_socket::implementation& impl,
980 int family,
981 int type,
982 int protocol)
983 {
984 44x auto& wrapper = static_cast<win_local_stream_socket&>(impl);
985 44x return open_socket_internal(
986 88x *wrapper.get_internal(), family, type, protocol);
987 }
988
989 inline std::error_code
990 93x win_local_stream_service::assign_socket(
991 local_stream_socket::implementation& impl, native_handle_type fd)
992 {
993 93x auto& wrapper = static_cast<win_local_stream_socket&>(impl);
994 93x auto& internal = *wrapper.get_internal();
995
996 93x SOCKET sock = static_cast<SOCKET>(fd);
997
1/2
✗ Branch 3 → 4 not taken.
✓ Branch 3 → 5 taken 93 times.
93x if (sock == INVALID_SOCKET)
998 ✗ return make_err(WSAENOTSOCK);
999
1000 // SO_PROTOCOL_INFOW works on an unbound socket, unlike getsockname
1001 // (WSAEINVAL until bind/connect names it) -- connect_pair hands in
1002 // a socket that reached connected state without an explicit bind.
1003 93x WSAPROTOCOL_INFOW proto_info{};
1004 93x int proto_len = sizeof(proto_info);
1005
1/1
✓ Branch 5 → 6 taken 93 times.
93x if (::getsockopt(
1006 sock, SOL_SOCKET, SO_PROTOCOL_INFOW,
1007
2/2
✓ Branch 6 → 7 taken 27 times.
✓ Branch 6 → 9 taken 66 times.
93x reinterpret_cast<char*>(&proto_info), &proto_len) != 0)
1008
1/1
✓ Branch 7 → 8 taken 27 times.
27x return make_err(::WSAGetLastError());
1009
1/2
✗ Branch 9 → 10 not taken.
✓ Branch 9 → 11 taken 66 times.
66x if (proto_info.iAddressFamily != AF_UNIX)
1010 ✗ return make_err(WSAEAFNOSUPPORT);
1011
1/2
✗ Branch 11 → 12 not taken.
✓ Branch 11 → 13 taken 66 times.
66x if (proto_info.iSocketType != SOCK_STREAM)
1012 ✗ return make_err(WSAEPROTOTYPE);
1013
1014 132x HANDLE result = ::CreateIoCompletionPort(
1015
1/1
✓ Branch 13 → 14 taken 66 times.
66x reinterpret_cast<HANDLE>(sock), static_cast<HANDLE>(iocp_), key_io, 0);
1016
2/2
✓ Branch 14 → 15 taken 9 times.
✓ Branch 14 → 17 taken 57 times.
66x if (result == nullptr)
1017
1/1
✓ Branch 15 → 16 taken 9 times.
9x return make_err(::GetLastError());
1018
1019 57x internal.socket_ = sock;
1020
1021 57x sockaddr_storage local{};
1022 57x int local_len = sizeof(local);
1023 57x corosio::local_endpoint lep{}, rep{};
1024
2/3
✓ Branch 17 → 18 taken 57 times.
✓ Branch 18 → 19 taken 57 times.
✗ Branch 18 → 20 not taken.
57x if (::getsockname(sock, reinterpret_cast<sockaddr*>(&local), &local_len) ==
1025 0)
1026 57x lep = from_sockaddr_local(local, static_cast<socklen_t>(local_len));
1027 57x sockaddr_storage remote{};
1028 57x int remote_len = sizeof(remote);
1029
1/1
✓ Branch 20 → 21 taken 57 times.
57x if (::getpeername(
1030
1/2
✓ Branch 21 → 22 taken 57 times.
✗ Branch 21 → 23 not taken.
57x sock, reinterpret_cast<sockaddr*>(&remote), &remote_len) == 0)
1031 57x rep = from_sockaddr_local(remote, static_cast<socklen_t>(remote_len));
1032 57x internal.local_endpoint_ = lep;
1033 57x internal.remote_endpoint_ = rep;
1034 57x return {};
1035 }
1036
1037 inline std::error_code
1038 44x win_local_stream_service::open_socket_internal(
1039 win_local_stream_socket_internal& impl, int family, int type, int protocol)
1040 {
1041 44x impl.close_socket();
1042
1043 SOCKET sock =
1044 44x ::WSASocketW(family, type, protocol, nullptr, 0, WSA_FLAG_OVERLAPPED);
1045
1046
2/2
✓ Branch 4 → 5 taken 1 time.
✓ Branch 4 → 7 taken 43 times.
44x if (sock == INVALID_SOCKET)
1047 1x return make_err(::WSAGetLastError());
1048
1049 // No IPV6_V6ONLY for AF_UNIX
1050
1051 86x HANDLE result = ::CreateIoCompletionPort(
1052 43x reinterpret_cast<HANDLE>(sock), static_cast<HANDLE>(iocp_), key_io, 0);
1053
1054
2/2
✓ Branch 8 → 9 taken 9 times.
✓ Branch 8 → 12 taken 34 times.
43x if (result == nullptr)
1055 {
1056 9x DWORD dwError = ::GetLastError();
1057 9x ::closesocket(sock);
1058 9x return make_err(dwError);
1059 }
1060
1061 34x impl.socket_ = sock;
1062 34x return {};
1063 }
1064
1065 inline void*
1066 24x win_local_stream_service::native_handle() const noexcept
1067 {
1068 24x return iocp_;
1069 }
1070
1071 inline LPFN_CONNECTEX
1072 25x win_local_stream_service::connect_ex() const noexcept
1073 {
1074 25x return tcp_svc_.connect_ex();
1075 }
1076
1077 inline LPFN_ACCEPTEX
1078 23x win_local_stream_service::accept_ex() const noexcept
1079 {
1080 23x return tcp_svc_.accept_ex();
1081 }
1082
1083 inline void
1084 win_local_stream_service::post(overlapped_op* op)
1085 {
1086 sched_.post(op);
1087 }
1088
1089 inline void
1090 77x win_local_stream_service::on_pending(overlapped_op* op) noexcept
1091 {
1092 77x sched_.on_pending(op);
1093 77x }
1094
1095 inline void
1096 22x win_local_stream_service::on_completion(
1097 overlapped_op* op, DWORD error, DWORD bytes) noexcept
1098 {
1099 22x sched_.on_completion(op, error, bytes);
1100 22x }
1101
1102 inline void
1103 106x win_local_stream_service::work_started() noexcept
1104 {
1105 106x sched_.work_started();
1106 106x }
1107
1108 inline void
1109 win_local_stream_service::work_finished() noexcept
1110 {
1111 sched_.work_finished();
1112 }
1113
1114 inline void
1115 92x win_local_stream_service::destroy_acceptor_impl(win_local_stream_acceptor& impl)
1116 {
1117 {
1118 92x std::lock_guard<win_mutex> lock(mutex_);
1119 92x acceptor_wrapper_list_.remove(&impl);
1120 92x }
1121
1/2
✓ Branch 5 → 6 taken 92 times.
✗ Branch 5 → 7 not taken.
92x delete &impl;
1122 92x }
1123
1124 inline void
1125 92x win_local_stream_service::unregister_acceptor_impl(
1126 win_local_stream_acceptor_internal& impl)
1127 {
1128 92x std::lock_guard<win_mutex> lock(mutex_);
1129 92x acceptor_list_.remove(&impl);
1130 92x }
1131
1132 inline std::error_code
1133 62x win_local_stream_service::open_acceptor_socket(
1134 win_local_stream_acceptor_internal& impl,
1135 int family,
1136 int type,
1137 int protocol)
1138 {
1139 62x impl.close_socket();
1140
1141 SOCKET sock =
1142 62x ::WSASocketW(family, type, protocol, nullptr, 0, WSA_FLAG_OVERLAPPED);
1143
1144
2/2
✓ Branch 4 → 5 taken 2 times.
✓ Branch 4 → 7 taken 60 times.
62x if (sock == INVALID_SOCKET)
1145 2x return make_err(::WSAGetLastError());
1146
1147 120x HANDLE result = ::CreateIoCompletionPort(
1148 60x reinterpret_cast<HANDLE>(sock), static_cast<HANDLE>(iocp_), key_io, 0);
1149
1150
2/2
✓ Branch 8 → 9 taken 9 times.
✓ Branch 8 → 12 taken 51 times.
60x if (result == nullptr)
1151 {
1152 9x DWORD dwError = ::GetLastError();
1153 9x ::closesocket(sock);
1154 9x return make_err(dwError);
1155 }
1156
1157 51x impl.socket_ = sock;
1158 51x return {};
1159 }
1160
1161 inline std::error_code
1162 21x win_local_stream_service::assign_acceptor_socket(
1163 win_local_stream_acceptor_internal& impl, native_handle_type fd)
1164 {
1165 21x SOCKET sock = static_cast<SOCKET>(fd);
1166
1/2
✗ Branch 2 → 3 not taken.
✓ Branch 2 → 4 taken 21 times.
21x if (sock == INVALID_SOCKET)
1167 ✗ return make_err(WSAENOTSOCK);
1168
1169 // SO_PROTOCOL_INFOW works on an unbound socket, unlike getsockname
1170 // (WSAEINVAL until bind names it).
1171 21x WSAPROTOCOL_INFOW proto_info{};
1172 21x int proto_len = sizeof(proto_info);
1173
1/1
✓ Branch 4 → 5 taken 21 times.
21x if (::getsockopt(
1174 sock, SOL_SOCKET, SO_PROTOCOL_INFOW,
1175
2/2
✓ Branch 5 → 6 taken 9 times.
✓ Branch 5 → 8 taken 12 times.
21x reinterpret_cast<char*>(&proto_info), &proto_len) != 0)
1176
1/1
✓ Branch 6 → 7 taken 9 times.
9x return make_err(::WSAGetLastError());
1177
2/2
✓ Branch 8 → 9 taken 1 time.
✓ Branch 8 → 10 taken 11 times.
12x if (proto_info.iAddressFamily != AF_UNIX)
1178 1x return make_err(WSAEAFNOSUPPORT);
1179
1/2
✗ Branch 10 → 11 not taken.
✓ Branch 10 → 12 taken 11 times.
11x if (proto_info.iSocketType != SOCK_STREAM)
1180 ✗ return make_err(WSAEPROTOTYPE);
1181
1182 22x HANDLE result = ::CreateIoCompletionPort(
1183
1/1
✓ Branch 12 → 13 taken 11 times.
11x reinterpret_cast<HANDLE>(sock), static_cast<HANDLE>(iocp_), key_io, 0);
1184
2/2
✓ Branch 13 → 14 taken 9 times.
✓ Branch 13 → 16 taken 2 times.
11x if (result == nullptr)
1185
1/1
✓ Branch 14 → 15 taken 9 times.
9x return make_err(::GetLastError());
1186
1187 2x impl.socket_ = sock;
1188
1189 2x sockaddr_storage local{};
1190 2x int local_len = sizeof(local);
1191 2x corosio::local_endpoint lep{};
1192
2/3
✓ Branch 16 → 17 taken 2 times.
✓ Branch 17 → 18 taken 2 times.
✗ Branch 17 → 19 not taken.
2x if (::getsockname(sock, reinterpret_cast<sockaddr*>(&local), &local_len) ==
1193 0)
1194 2x lep = from_sockaddr_local(local, static_cast<socklen_t>(local_len));
1195 2x impl.set_local_endpoint(lep);
1196
1197 2x return {};
1198 }
1199
1200 inline std::error_code
1201 45x win_local_stream_service::bind_acceptor(
1202 win_local_stream_acceptor_internal& impl, corosio::local_endpoint ep)
1203 {
1204 // Reject abstract sockets on Windows
1205
2/2
✓ Branch 3 → 4 taken 1 time.
✓ Branch 3 → 5 taken 44 times.
45x if (ep.is_abstract())
1206 1x return std::make_error_code(std::errc::operation_not_supported);
1207
1208 44x SOCKET sock = impl.socket_;
1209
1210 44x sockaddr_storage storage{};
1211 44x socklen_t addrlen = detail::to_sockaddr(ep, storage);
1212
1/1
✓ Branch 6 → 7 taken 44 times.
44x if (::bind(
1213 sock, reinterpret_cast<sockaddr*>(&storage),
1214
2/2
✓ Branch 7 → 8 taken 3 times.
✓ Branch 7 → 10 taken 41 times.
44x static_cast<int>(addrlen)) == SOCKET_ERROR)
1215
1/1
✓ Branch 8 → 9 taken 3 times.
3x return make_err(::WSAGetLastError());
1216
1217 41x impl.set_local_endpoint(ep);
1218 41x return {};
1219 }
1220
1221 inline std::error_code
1222 36x win_local_stream_service::listen_acceptor(
1223 win_local_stream_acceptor_internal& impl, int backlog)
1224 {
1225 36x SOCKET sock = impl.socket_;
1226
1227
2/2
✓ Branch 3 → 4 taken 2 times.
✓ Branch 3 → 6 taken 34 times.
36x if (::listen(sock, backlog) == SOCKET_ERROR)
1228 2x return make_err(::WSAGetLastError());
1229
1230 34x return {};
1231 }
1232
1233 } // namespace boost::corosio::detail
1234
1235 #endif // BOOST_COROSIO_HAS_IOCP
1236
1237 #endif // BOOST_COROSIO_NATIVE_DETAIL_IOCP_WIN_LOCAL_STREAM_SERVICE_HPP
1238