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

97.6% Lines (279/286) 100.0% List of functions (38/38) 74.6% Branches (97/130)
win_local_stream_acceptor_service.hpp
f(x) Functions (38)
Function Calls Lines Branches Blocks
boost::corosio::detail::local_stream_accept_op::local_stream_accept_op() :82 90x 100.0% 100.0% boost::corosio::detail::local_stream_accept_op::do_cancel_impl(boost::corosio::detail::overlapped_op*) :89 2x 100.0% 50.0% 83.3% boost::corosio::detail::local_stream_acceptor_wait_op::local_stream_acceptor_wait_op() :98 90x 100.0% 100.0% boost::corosio::detail::local_stream_acceptor_wait_op::do_cancel_impl(boost::corosio::detail::overlapped_op*) :105 1x 100.0% 50.0% 92.3% boost::corosio::detail::local_stream_accept_op::do_complete(void*, boost::corosio::detail::scheduler_op*, unsigned int, unsigned int) :122 25x 100.0% 76.2% 93.8% boost::corosio::detail::local_stream_acceptor_wait_op::do_complete(void*, boost::corosio::detail::scheduler_op*, unsigned int, unsigned int) :221 7x 100.0% 100.0% 84.6% boost::corosio::detail::win_local_stream_acceptor_internal::win_local_stream_acceptor_internal(boost::corosio::detail::win_local_stream_service&) :244 90x 100.0% 100.0% boost::corosio::detail::win_local_stream_acceptor_internal::~win_local_stream_acceptor_internal() :250 90x 100.0% 100.0% boost::corosio::detail::win_local_stream_acceptor_internal::socket_service() :256 5x 100.0% 100.0% boost::corosio::detail::win_local_stream_acceptor_internal::native_handle() const :262 9x 100.0% 100.0% boost::corosio::detail::win_local_stream_acceptor_internal::local_endpoint() const :268 5x 100.0% 100.0% boost::corosio::detail::win_local_stream_acceptor_internal::is_open() const :274 358x 100.0% 100.0% boost::corosio::detail::win_local_stream_acceptor_internal::set_local_endpoint(boost::corosio::local_endpoint) :280 44x 100.0% 100.0% boost::corosio::detail::win_local_stream_acceptor_internal::cancel() :287 9x 100.0% 50.0% 100.0% boost::corosio::detail::win_local_stream_acceptor_internal::wait(std::__n4861::coroutine_handle<void>, boost::capy::executor_ref, boost::corosio::wait_type, std::stop_token, std::error_code*) :297 7x 100.0% 100.0% 100.0% boost::corosio::detail::win_local_stream_acceptor_internal::close_socket() :340 292x 100.0% 100.0% 100.0% boost::corosio::detail::win_local_stream_acceptor_internal::accept(std::__n4861::coroutine_handle<void>, boost::capy::executor_ref, std::stop_token, std::error_code*, boost::corosio::io_object::implementation**) :359 25x 94.6% 86.7% 89.8% boost::corosio::detail::win_local_stream_acceptor::win_local_stream_acceptor(std::shared_ptr<boost::corosio::detail::win_local_stream_acceptor_internal>) :460 90x 100.0% 100.0% boost::corosio::detail::win_local_stream_acceptor::close_internal() :467 90x 100.0% 50.0% 100.0% boost::corosio::detail::win_local_stream_acceptor::accept(std::__n4861::coroutine_handle<void>, boost::capy::executor_ref, std::stop_token, std::error_code*, boost::corosio::io_object::implementation**) :477 25x 100.0% 100.0% 80.0% boost::corosio::detail::win_local_stream_acceptor::wait(std::__n4861::coroutine_handle<void>, boost::capy::executor_ref, boost::corosio::wait_type, std::stop_token, std::error_code*) :488 7x 100.0% 100.0% 80.0% boost::corosio::detail::win_local_stream_acceptor::local_endpoint() const :499 5x 100.0% 100.0% boost::corosio::detail::win_local_stream_acceptor::is_open() const :505 354x 100.0% 75.0% 100.0% boost::corosio::detail::win_local_stream_acceptor::cancel() :511 3x 100.0% 50.0% 100.0% boost::corosio::detail::win_local_stream_acceptor::native_handle() const :518 5x 75.0% 50.0% 83.3% boost::corosio::detail::win_local_stream_acceptor::release_socket() :526 6x 90.0% 50.0% 92.9% boost::corosio::detail::win_local_stream_acceptor::set_option(int, int, void const*, unsigned long long) :542 2x 87.5% 62.5% 88.2% boost::corosio::detail::win_local_stream_acceptor::get_option(int, int, void*, unsigned long long*) const :555 2x 90.0% 62.5% 88.9% boost::corosio::detail::win_local_stream_acceptor::get_internal() const :570 302x 100.0% 100.0% boost::corosio::detail::win_local_stream_acceptor_service::win_local_stream_acceptor_service(boost::capy::execution_context&, boost::corosio::detail::win_local_stream_service&) :579 1247x 100.0% 100.0% boost::corosio::detail::win_local_stream_acceptor_service::construct() :586 90x 100.0% 100.0% 88.2% boost::corosio::detail::win_local_stream_acceptor_service::destroy(boost::corosio::io_object::implementation*) :605 90x 100.0% 50.0% 100.0% boost::corosio::detail::win_local_stream_acceptor_service::close(boost::corosio::io_object::handle&) :616 136x 100.0% 100.0% boost::corosio::detail::win_local_stream_acceptor_service::open_acceptor_socket(boost::corosio::local_stream_acceptor::implementation&, int, int, int) :623 61x 100.0% 100.0% boost::corosio::detail::win_local_stream_acceptor_service::assign_socket(boost::corosio::local_stream_acceptor::implementation&, unsigned long long) :635 24x 100.0% 100.0% boost::corosio::detail::win_local_stream_acceptor_service::bind_acceptor(boost::corosio::local_stream_acceptor::implementation&, boost::corosio::local_endpoint) :644 45x 100.0% 100.0% boost::corosio::detail::win_local_stream_acceptor_service::listen_acceptor(boost::corosio::local_stream_acceptor::implementation&, int) :653 36x 100.0% 100.0% boost::corosio::detail::win_local_stream_acceptor_service::shutdown() :662 1247x 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_ACCEPTOR_SERVICE_HPP
11 #define BOOST_COROSIO_NATIVE_DETAIL_IOCP_WIN_LOCAL_STREAM_ACCEPTOR_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/except.hpp>
19 #include <boost/corosio/detail/local_stream_acceptor_service.hpp>
20 #include <boost/capy/ex/execution_context.hpp>
21
22 #include <boost/corosio/native/detail/iocp/win_dissociate.hpp>
23 #include <boost/corosio/native/detail/iocp/win_local_stream_acceptor.hpp>
24 #include <boost/corosio/native/detail/iocp/win_local_stream_service.hpp>
25
26 #include <boost/corosio/native/detail/iocp/win_scheduler.hpp>
27 #include <boost/corosio/native/detail/iocp/win_completion_key.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 /* IOCP local stream acceptor service.
38
39 Delegates acceptor lifecycle management to win_local_stream_service
40 and provides the local_stream_acceptor_service virtual interface.
41 */
42 class BOOST_COROSIO_DECL win_local_stream_acceptor_service final
43 : public local_stream_acceptor_service
44 {
45 public:
46 win_local_stream_acceptor_service(
47 capy::execution_context& ctx, win_local_stream_service& svc);
48
49 io_object::implementation* construct() override;
50
51 void destroy(io_object::implementation* p) override;
52
53 void close(io_object::handle& h) override;
54
55 std::error_code open_acceptor_socket(
56 local_stream_acceptor::implementation& impl,
57 int family,
58 int type,
59 int protocol) override;
60
61 std::error_code assign_socket(
62 local_stream_acceptor::implementation& impl,
63 native_handle_type fd) override;
64
65 std::error_code bind_acceptor(
66 local_stream_acceptor::implementation& impl,
67 corosio::local_endpoint ep) override;
68
69 std::error_code listen_acceptor(
70 local_stream_acceptor::implementation& impl, int backlog) override;
71
72 void shutdown() override;
73
74 private:
75 win_local_stream_service& svc_;
76 };
77
78 // ============================================================
79 // local_stream_accept_op
80 // ============================================================
81
82 90x inline local_stream_accept_op::local_stream_accept_op() noexcept
83 90x : overlapped_op(&do_complete)
84 {
85 90x cancel_func_ = &do_cancel_impl;
86 90x }
87
88 inline void
89 2x local_stream_accept_op::do_cancel_impl(overlapped_op* base) noexcept
90 {
91 2x auto* op = static_cast<local_stream_accept_op*>(base);
92
1/2
✓ Branch 2 → 3 taken 2 times.
✗ Branch 2 → 7 not taken.
2x if (op->listen_socket != INVALID_SOCKET)
93 {
94
1/2
✓ Branch 3 → 4 taken 2 times.
✗ Branch 3 → 5 not taken.
2x ::CancelIoEx(reinterpret_cast<HANDLE>(op->listen_socket), op);
95 }
96 2x }
97
98 90x inline local_stream_acceptor_wait_op::local_stream_acceptor_wait_op() noexcept
99 90x : overlapped_op(&do_complete)
100 {
101 90x cancel_func_ = &do_cancel_impl;
102 90x }
103
104 inline void
105 1x local_stream_acceptor_wait_op::do_cancel_impl(overlapped_op* base) noexcept
106 {
107 1x auto* op = static_cast<local_stream_acceptor_wait_op*>(base);
108 1x op->cancelled.store(true, std::memory_order_release);
109
1/2
✓ Branch 3 → 4 taken 1 time.
✗ Branch 3 → 8 not taken.
1x if (op->listen_socket != INVALID_SOCKET)
110 {
111
1/2
✓ Branch 4 → 5 taken 1 time.
✗ Branch 4 → 6 not taken.
1x ::CancelIoEx(reinterpret_cast<HANDLE>(op->listen_socket), op);
112 }
113
1/2
✓ Branch 9 → 10 taken 1 time.
✗ Branch 9 → 14 not taken.
1x if (op->acceptor_ptr)
114 {
115 1x op->acceptor_ptr->socket_service().scheduler().cancel_wait(op);
116 }
117 1x }
118
119 // accept_op completion handler
120
121 inline void
122 25x local_stream_accept_op::do_complete(
123 void* owner,
124 scheduler_op* base,
125 std::uint32_t /*bytes*/,
126 std::uint32_t /*error*/)
127 {
128 25x auto* op = static_cast<local_stream_accept_op*>(base);
129
130
2/2
✓ Branch 2 → 3 taken 1 time.
✓ Branch 2 → 12 taken 24 times.
25x if (!owner)
131 {
132
1/2
✓ Branch 3 → 4 taken 1 time.
✗ Branch 3 → 6 not taken.
1x if (op->accepted_socket != INVALID_SOCKET)
133 {
134
1/1
✓ Branch 4 → 5 taken 1 time.
1x ::closesocket(op->accepted_socket);
135 1x op->accepted_socket = INVALID_SOCKET;
136 }
137
138
1/2
✓ Branch 6 → 7 taken 1 time.
✗ Branch 6 → 9 not taken.
1x if (op->peer_wrapper)
139 {
140 1x op->peer_wrapper->close_internal();
141 1x op->peer_wrapper = nullptr;
142 }
143
144 1x op->cleanup_only();
145 1x op->acceptor_ptr.reset();
146 1x return;
147 }
148
149 24x op->stop_cb.reset();
150
151 bool success =
152
3/4
✓ Branch 13 → 14 taken 15 times.
✓ Branch 13 → 17 taken 9 times.
✓ Branch 15 → 16 taken 15 times.
✗ Branch 15 → 17 not taken.
24x (op->dwError == 0 && !op->cancelled.load(std::memory_order_acquire));
153
154
1/2
✓ Branch 18 → 19 taken 24 times.
✗ Branch 18 → 27 not taken.
24x if (op->ec_out)
155 {
156
2/2
✓ Branch 20 → 21 taken 3 times.
✓ Branch 20 → 23 taken 21 times.
24x if (op->cancelled.load(std::memory_order_acquire))
157 3x *op->ec_out = capy::error::canceled;
158
2/2
✓ Branch 23 → 24 taken 6 times.
✓ Branch 23 → 25 taken 15 times.
21x else if (op->dwError != 0)
159 6x *op->ec_out = iocp_make_err(op->dwError, /*accept_path=*/true);
160 else
161 15x *op->ec_out = {};
162 }
163
164
4/6
✓ Branch 27 → 28 taken 15 times.
✓ Branch 27 → 44 taken 9 times.
✓ Branch 28 → 29 taken 15 times.
✗ Branch 28 → 44 not taken.
✓ Branch 29 → 30 taken 15 times.
✗ Branch 29 → 44 not taken.
24x if (success && op->accepted_socket != INVALID_SOCKET && op->peer_wrapper)
165 {
166 15x ::setsockopt(
167 op->accepted_socket, SOL_SOCKET, SO_UPDATE_ACCEPT_CONTEXT,
168
1/1
✓ Branch 30 → 31 taken 15 times.
15x reinterpret_cast<char*>(&op->listen_socket), sizeof(SOCKET));
169
170 15x op->peer_wrapper->get_internal()->set_socket(op->accepted_socket);
171
172 15x sockaddr_storage local_storage{};
173 15x int local_len = sizeof(local_storage);
174 15x sockaddr_storage remote_storage{};
175 15x int remote_len = sizeof(remote_storage);
176
177 15x corosio::local_endpoint local_ep, remote_ep;
178
1/1
✓ Branch 33 → 34 taken 15 times.
15x if (::getsockname(
179 op->accepted_socket,
180
1/2
✓ Branch 34 → 35 taken 15 times.
✗ Branch 34 → 36 not taken.
15x reinterpret_cast<sockaddr*>(&local_storage), &local_len) == 0)
181 15x local_ep = from_sockaddr_local(
182 local_storage, static_cast<socklen_t>(local_len));
183
1/1
✓ Branch 36 → 37 taken 15 times.
15x if (::getpeername(
184 op->accepted_socket,
185
1/2
✓ Branch 37 → 38 taken 15 times.
✗ Branch 37 → 39 not taken.
15x reinterpret_cast<sockaddr*>(&remote_storage), &remote_len) == 0)
186 15x remote_ep = from_sockaddr_local(
187 remote_storage, static_cast<socklen_t>(remote_len));
188
189 15x op->peer_wrapper->get_internal()->set_endpoints(local_ep, remote_ep);
190 15x op->accepted_socket = INVALID_SOCKET;
191
192
1/2
✓ Branch 41 → 42 taken 15 times.
✗ Branch 41 → 43 not taken.
15x if (op->impl_out)
193 15x *op->impl_out = op->peer_wrapper;
194 15x }
195 else
196 {
197
2/2
✓ Branch 44 → 45 taken 4 times.
✓ Branch 44 → 47 taken 5 times.
9x if (op->accepted_socket != INVALID_SOCKET)
198 {
199
1/1
✓ Branch 45 → 46 taken 4 times.
4x ::closesocket(op->accepted_socket);
200 4x op->accepted_socket = INVALID_SOCKET;
201 }
202
203
2/2
✓ Branch 47 → 48 taken 4 times.
✓ Branch 47 → 52 taken 5 times.
9x if (op->peer_wrapper)
204 {
205
1/1
✓ Branch 50 → 51 taken 4 times.
4x op->acceptor_ptr->socket_service().destroy(op->peer_wrapper);
206 4x op->peer_wrapper = nullptr;
207 }
208
209
1/2
✓ Branch 52 → 53 taken 9 times.
✗ Branch 52 → 54 not taken.
9x if (op->impl_out)
210 9x *op->impl_out = nullptr;
211 }
212
213 24x op->cont.h = op->h;
214 24x auto saved_ex = op->ex;
215 24x auto prevent_premature_destruction = std::move(op->acceptor_ptr);
216
217
2/2
✓ Branch 56 → 57 taken 24 times.
✓ Branch 57 → 58 taken 24 times.
24x dispatch_coro(saved_ex, op->cont).resume();
218 24x }
219
220 inline void
221 7x local_stream_acceptor_wait_op::do_complete(
222 void* owner,
223 scheduler_op* base,
224 std::uint32_t /*bytes*/,
225 std::uint32_t /*error*/)
226 {
227 7x auto* op = static_cast<local_stream_acceptor_wait_op*>(base);
228
229
2/2
✓ Branch 2 → 3 taken 1 time.
✓ Branch 2 → 6 taken 6 times.
7x if (!owner)
230 {
231 1x op->cleanup_only();
232 1x op->acceptor_ptr.reset();
233 1x return;
234 }
235
236 6x auto prevent_premature_destruction = std::move(op->acceptor_ptr);
237
1/1
✓ Branch 8 → 9 taken 6 times.
6x op->invoke_handler();
238 6x }
239
240 // ============================================================
241 // win_local_stream_acceptor_internal
242 // ============================================================
243
244 90x inline win_local_stream_acceptor_internal::win_local_stream_acceptor_internal(
245 90x win_local_stream_service& svc) noexcept
246 90x : svc_(svc)
247 {
248 90x }
249
250 90x inline win_local_stream_acceptor_internal::~win_local_stream_acceptor_internal()
251 {
252 90x svc_.unregister_acceptor_impl(*this);
253 90x }
254
255 inline win_local_stream_service&
256 5x win_local_stream_acceptor_internal::socket_service() noexcept
257 {
258 5x return svc_;
259 }
260
261 inline SOCKET
262 9x win_local_stream_acceptor_internal::native_handle() const noexcept
263 {
264 9x return socket_;
265 }
266
267 inline corosio::local_endpoint
268 5x win_local_stream_acceptor_internal::local_endpoint() const noexcept
269 {
270 5x return local_endpoint_;
271 }
272
273 inline bool
274 358x win_local_stream_acceptor_internal::is_open() const noexcept
275 {
276 358x return socket_ != INVALID_SOCKET;
277 }
278
279 inline void
280 44x win_local_stream_acceptor_internal::set_local_endpoint(
281 corosio::local_endpoint ep) noexcept
282 {
283 44x local_endpoint_ = ep;
284 44x }
285
286 inline void
287 9x win_local_stream_acceptor_internal::cancel() noexcept
288 {
289
1/2
✓ Branch 2 → 3 taken 9 times.
✗ Branch 2 → 4 not taken.
9x if (socket_ != INVALID_SOCKET)
290 9x ::CancelIoEx(reinterpret_cast<HANDLE>(socket_), nullptr);
291 9x acc_.request_cancel();
292 9x wt_.request_cancel();
293 9x svc_.scheduler().cancel_wait(&wt_);
294 9x }
295
296 inline std::coroutine_handle<>
297 7x win_local_stream_acceptor_internal::wait(
298 std::coroutine_handle<> h,
299 capy::executor_ref d,
300 wait_type w,
301 std::stop_token token,
302 std::error_code* ec)
303 {
304
1/1
✓ Branch 2 → 3 taken 7 times.
7x wt_.acceptor_ptr = shared_from_this();
305 7x wt_.listen_socket = socket_;
306
307 7x auto& op = wt_;
308 7x op.reset();
309 7x op.h = h;
310 7x op.ex = d;
311 7x op.ec_out = ec;
312 7x op.bytes_out = nullptr;
313 7x op.start(token);
314
315 7x svc_.work_started();
316
317 // Closed-object contract: complete with bad_file_descriptor
318 // without touching the kernel or the wait reactor.
319
2/2
✓ Branch 8 → 9 taken 1 time.
✓ Branch 8 → 13 taken 6 times.
7x if (socket_ == INVALID_SOCKET)
320 {
321 1x svc_.on_completion(&op, WSAEBADF, 0);
322 1x return std::noop_coroutine();
323 }
324
325 // Writability carries no meaning for a listening socket; the
326 // wait fails the same way on every backend.
327
2/2
✓ Branch 13 → 14 taken 1 time.
✓ Branch 13 → 18 taken 5 times.
6x if (w == wait_type::write)
328 {
329 1x svc_.on_completion(&op, WSAEOPNOTSUPP, 0);
330 1x return std::noop_coroutine();
331 }
332
333 // wait_type::read and wait_type::error route through the auxiliary
334 // select reactor.
335 5x svc_.scheduler().wait_reactor().register_wait(socket_, w, &op);
336 5x return std::noop_coroutine();
337 }
338
339 inline void
340 292x win_local_stream_acceptor_internal::close_socket() noexcept
341 {
342 // Flag the accept op cancelled before closing so a closesocket-delivered
343 // ERROR_NETNAME_DELETED is short-circuited to canceled rather than mapped
344 // to connection_aborted by iocp_make_err (see win_tcp_socket close_socket).
345 292x acc_.request_cancel();
346 292x wt_.request_cancel();
347 292x svc_.scheduler().cancel_wait(&wt_);
348
349
2/2
✓ Branch 6 → 7 taken 47 times.
✓ Branch 6 → 10 taken 245 times.
292x if (socket_ != INVALID_SOCKET)
350 {
351 47x ::CancelIoEx(reinterpret_cast<HANDLE>(socket_), nullptr);
352 47x ::closesocket(socket_);
353 47x socket_ = INVALID_SOCKET;
354 }
355 292x local_endpoint_ = corosio::local_endpoint{};
356 292x }
357
358 inline std::coroutine_handle<>
359 25x win_local_stream_acceptor_internal::accept(
360 std::coroutine_handle<> h,
361 capy::executor_ref d,
362 std::stop_token token,
363 std::error_code* ec,
364 io_object::implementation** impl_out)
365 {
366
1/1
✓ Branch 2 → 3 taken 25 times.
25x acc_.acceptor_ptr = shared_from_this();
367
368 25x auto& op = acc_;
369 25x op.reset();
370 25x op.h = h;
371 25x op.ex = d;
372 25x op.ec_out = ec;
373 25x op.impl_out = impl_out;
374 25x op.start(token);
375
376 25x svc_.work_started();
377
378 // Create wrapper for the peer socket
379
1/1
✓ Branch 8 → 9 taken 25 times.
25x auto* peer_ptr = svc_.construct();
380
1/2
✗ Branch 9 → 10 not taken.
✓ Branch 9 → 14 taken 25 times.
25x if (!peer_ptr)
381 {
382 svc_.on_completion(&op, ERROR_OUTOFMEMORY, 0);
383 return std::noop_coroutine();
384 }
385 25x auto& peer_wrapper = static_cast<win_local_stream_socket&>(*peer_ptr);
386
387 // Always AF_UNIX for local sockets
388 SOCKET accepted =
389
1/1
✓ Branch 14 → 15 taken 25 times.
25x ::WSASocketW(AF_UNIX, SOCK_STREAM, 0, nullptr, 0, WSA_FLAG_OVERLAPPED);
390
391
2/2
✓ Branch 15 → 16 taken 1 time.
✓ Branch 15 → 22 taken 24 times.
25x if (accepted == INVALID_SOCKET)
392 {
393
1/1
✓ Branch 16 → 17 taken 1 time.
1x svc_.destroy(&peer_wrapper);
394
1/1
✓ Branch 17 → 18 taken 1 time.
1x svc_.on_completion(&op, ::WSAGetLastError(), 0);
395 1x return std::noop_coroutine();
396 }
397
398
1/1
✓ Branch 23 → 24 taken 24 times.
24x HANDLE result = ::CreateIoCompletionPort(
399 24x reinterpret_cast<HANDLE>(accepted), svc_.native_handle(), key_io, 0);
400
401
2/2
✓ Branch 24 → 25 taken 1 time.
✓ Branch 24 → 32 taken 23 times.
24x if (result == nullptr)
402 {
403
1/1
✓ Branch 25 → 26 taken 1 time.
1x DWORD err = ::GetLastError();
404
1/1
✓ Branch 26 → 27 taken 1 time.
1x ::closesocket(accepted);
405
1/1
✓ Branch 27 → 28 taken 1 time.
1x svc_.destroy(&peer_wrapper);
406 1x svc_.on_completion(&op, err, 0);
407 1x return std::noop_coroutine();
408 }
409
410 23x op.accepted_socket = accepted;
411 23x op.peer_wrapper = &peer_wrapper;
412 23x op.listen_socket = socket_;
413
414 23x auto accept_ex = svc_.accept_ex();
415
2/2
✓ Branch 33 → 34 taken 1 time.
✓ Branch 33 → 40 taken 22 times.
23x if (!accept_ex)
416 {
417
1/1
✓ Branch 34 → 35 taken 1 time.
1x ::closesocket(accepted);
418
1/1
✓ Branch 35 → 36 taken 1 time.
1x svc_.destroy(&peer_wrapper);
419 1x op.peer_wrapper = nullptr;
420 1x op.accepted_socket = INVALID_SOCKET;
421 1x svc_.on_completion(&op, WSAEOPNOTSUPP, 0);
422 1x return std::noop_coroutine();
423 }
424
425 // AcceptEx address buffer sized for sockaddr_un
426 22x DWORD addr_size = static_cast<DWORD>(sizeof(un_sa_t) + 16);
427 22x DWORD bytes_received = 0;
428
429 44x BOOL ok = accept_ex(
430
1/1
✓ Branch 40 → 41 taken 22 times.
22x socket_, accepted, op.addr_buf, 0, addr_size, addr_size,
431 &bytes_received, &op);
432
433
1/2
✓ Branch 41 → 42 taken 22 times.
✗ Branch 41 → 50 not taken.
22x if (!ok)
434 {
435
1/1
✓ Branch 42 → 43 taken 22 times.
22x DWORD err = ::WSAGetLastError();
436
2/2
✓ Branch 43 → 44 taken 2 times.
✓ Branch 43 → 50 taken 20 times.
22x if (err != ERROR_IO_PENDING)
437 {
438
1/1
✓ Branch 44 → 45 taken 2 times.
2x ::closesocket(accepted);
439
1/1
✓ Branch 45 → 46 taken 2 times.
2x svc_.destroy(&peer_wrapper);
440 2x op.peer_wrapper = nullptr;
441 2x op.accepted_socket = INVALID_SOCKET;
442 2x svc_.on_completion(&op, err, 0);
443 2x return std::noop_coroutine();
444 }
445 }
446
447 20x svc_.on_pending(&op);
448
449 // Re-check cancellation after I/O is pending
450
1/2
✗ Branch 52 → 53 not taken.
✓ Branch 52 → 54 taken 20 times.
20x if (op.cancelled.load(std::memory_order_acquire))
451 ::CancelIoEx(reinterpret_cast<HANDLE>(socket_), &op);
452
453 20x return std::noop_coroutine();
454 }
455
456 // ============================================================
457 // win_local_stream_acceptor (wrapper)
458 // ============================================================
459
460 90x inline win_local_stream_acceptor::win_local_stream_acceptor(
461 90x std::shared_ptr<win_local_stream_acceptor_internal> internal) noexcept
462 90x : internal_(std::move(internal))
463 {
464 90x }
465
466 inline void
467 90x win_local_stream_acceptor::close_internal() noexcept
468 {
469
1/2
✓ Branch 3 → 4 taken 90 times.
✗ Branch 3 → 7 not taken.
90x if (internal_)
470 {
471 90x internal_->close_socket();
472 90x internal_.reset();
473 }
474 90x }
475
476 inline std::coroutine_handle<>
477 25x win_local_stream_acceptor::accept(
478 std::coroutine_handle<> h,
479 capy::executor_ref d,
480 std::stop_token token,
481 std::error_code* ec,
482 io_object::implementation** impl_out)
483 {
484
1/1
✓ Branch 4 → 5 taken 25 times.
25x return internal_->accept(h, d, token, ec, impl_out);
485 }
486
487 inline std::coroutine_handle<>
488 7x win_local_stream_acceptor::wait(
489 std::coroutine_handle<> h,
490 capy::executor_ref d,
491 wait_type w,
492 std::stop_token token,
493 std::error_code* ec)
494 {
495
1/1
✓ Branch 4 → 5 taken 7 times.
7x return internal_->wait(h, d, w, token, ec);
496 }
497
498 inline corosio::local_endpoint
499 5x win_local_stream_acceptor::local_endpoint() const noexcept
500 {
501 5x return internal_->local_endpoint();
502 }
503
504 inline bool
505 354x win_local_stream_acceptor::is_open() const noexcept
506 {
507
3/4
✓ Branch 3 → 4 taken 354 times.
✗ Branch 3 → 8 not taken.
✓ Branch 6 → 7 taken 191 times.
✓ Branch 6 → 8 taken 163 times.
354x return internal_ && internal_->is_open();
508 }
509
510 inline void
511 3x win_local_stream_acceptor::cancel() noexcept
512 {
513
1/2
✓ Branch 3 → 4 taken 3 times.
✗ Branch 3 → 6 not taken.
3x if (internal_)
514 3x internal_->cancel();
515 3x }
516
517 inline native_handle_type
518 5x win_local_stream_acceptor::native_handle() const noexcept
519 {
520
1/2
✗ Branch 3 → 4 not taken.
✓ Branch 3 → 5 taken 5 times.
5x if (!internal_)
521 return static_cast<native_handle_type>(INVALID_SOCKET);
522 5x return static_cast<native_handle_type>(internal_->native_handle());
523 }
524
525 inline native_handle_type
526 6x win_local_stream_acceptor::release_socket() noexcept
527 {
528
1/2
✗ Branch 3 → 4 not taken.
✓ Branch 3 → 5 taken 6 times.
6x if (!internal_)
529 return static_cast<native_handle_type>(INVALID_SOCKET);
530 6x SOCKET s = internal_->socket_;
531
1/2
✓ Branch 6 → 7 taken 6 times.
✗ Branch 6 → 14 not taken.
6x if (s != INVALID_SOCKET)
532 {
533 6x internal_->cancel();
534 6x dissociate_from_iocp(s);
535 6x internal_->socket_ = INVALID_SOCKET;
536 6x internal_->local_endpoint_ = corosio::local_endpoint{};
537 }
538 6x return static_cast<native_handle_type>(s);
539 }
540
541 inline std::error_code
542 2x win_local_stream_acceptor::set_option(
543 int level, int optname, void const* data, std::size_t size) noexcept
544 {
545
3/6
✓ Branch 3 → 4 taken 2 times.
✗ Branch 3 → 7 not taken.
✗ Branch 6 → 7 not taken.
✓ Branch 6 → 8 taken 2 times.
✗ Branch 9 → 10 not taken.
✓ Branch 9 → 11 taken 2 times.
2x if (!internal_ || !internal_->is_open())
546 return make_err(WSAENOTSOCK);
547 2x if (::setsockopt(
548 2x internal_->native_handle(), level, optname,
549
2/2
✓ Branch 14 → 15 taken 1 time.
✓ Branch 14 → 17 taken 1 time.
2x reinterpret_cast<char const*>(data), static_cast<int>(size)) != 0)
550 1x return make_err(WSAGetLastError());
551 1x return {};
552 }
553
554 inline std::error_code
555 2x win_local_stream_acceptor::get_option(
556 int level, int optname, void* data, std::size_t* size) const noexcept
557 {
558
3/6
✓ Branch 3 → 4 taken 2 times.
✗ Branch 3 → 7 not taken.
✗ Branch 6 → 7 not taken.
✓ Branch 6 → 8 taken 2 times.
✗ Branch 9 → 10 not taken.
✓ Branch 9 → 11 taken 2 times.
2x if (!internal_ || !internal_->is_open())
559 return make_err(WSAENOTSOCK);
560 2x int len = static_cast<int>(*size);
561 2x if (::getsockopt(
562 2x internal_->native_handle(), level, optname,
563
2/2
✓ Branch 14 → 15 taken 1 time.
✓ Branch 14 → 17 taken 1 time.
2x reinterpret_cast<char*>(data), &len) != 0)
564 1x return make_err(WSAGetLastError());
565 1x *size = static_cast<std::size_t>(len);
566 1x return {};
567 }
568
569 inline win_local_stream_acceptor_internal*
570 302x win_local_stream_acceptor::get_internal() const noexcept
571 {
572 302x return internal_.get();
573 }
574
575 // ============================================================
576 // win_local_stream_acceptor_service
577 // ============================================================
578
579 1247x inline win_local_stream_acceptor_service::win_local_stream_acceptor_service(
580 1247x capy::execution_context& /*ctx*/, win_local_stream_service& svc)
581 1247x : svc_(svc)
582 {
583 1247x }
584
585 inline io_object::implementation*
586 90x win_local_stream_acceptor_service::construct()
587 {
588
1/1
✓ Branch 2 → 3 taken 90 times.
90x auto internal = std::make_shared<win_local_stream_acceptor_internal>(svc_);
589
590 // Allocate wrapper before mutating lists so a throw from
591 // new doesn't leave a dangling pointer in acceptor_list_.
592 90x auto* raw = internal.get();
593
1/1
✓ Branch 4 → 5 taken 90 times.
90x auto* wrapper = new win_local_stream_acceptor(std::move(internal));
594
595 {
596 90x std::lock_guard<win_mutex> lock(svc_.mutex_);
597 90x svc_.acceptor_list_.push_back(raw);
598 90x svc_.acceptor_wrapper_list_.push_back(wrapper);
599 90x }
600
601 90x return wrapper;
602 90x }
603
604 inline void
605 90x win_local_stream_acceptor_service::destroy(io_object::implementation* p)
606 {
607
1/2
✓ Branch 2 → 3 taken 90 times.
✗ Branch 2 → 5 not taken.
90x if (p)
608 {
609 90x auto& wrapper = static_cast<win_local_stream_acceptor&>(*p);
610 90x wrapper.close_internal();
611 90x svc_.destroy_acceptor_impl(wrapper);
612 }
613 90x }
614
615 inline void
616 136x win_local_stream_acceptor_service::close(io_object::handle& h)
617 {
618 136x auto& wrapper = static_cast<win_local_stream_acceptor&>(*h.get());
619 136x wrapper.get_internal()->close_socket();
620 136x }
621
622 inline std::error_code
623 61x win_local_stream_acceptor_service::open_acceptor_socket(
624 local_stream_acceptor::implementation& impl,
625 int family,
626 int type,
627 int protocol)
628 {
629 auto* internal =
630 61x static_cast<win_local_stream_acceptor&>(impl).get_internal();
631 61x return svc_.open_acceptor_socket(*internal, family, type, protocol);
632 }
633
634 inline std::error_code
635 24x win_local_stream_acceptor_service::assign_socket(
636 local_stream_acceptor::implementation& impl, native_handle_type fd)
637 {
638 auto* internal =
639 24x static_cast<win_local_stream_acceptor&>(impl).get_internal();
640 24x return svc_.assign_acceptor_socket(*internal, fd);
641 }
642
643 inline std::error_code
644 45x win_local_stream_acceptor_service::bind_acceptor(
645 local_stream_acceptor::implementation& impl, corosio::local_endpoint ep)
646 {
647 auto* internal =
648 45x static_cast<win_local_stream_acceptor&>(impl).get_internal();
649 45x return svc_.bind_acceptor(*internal, ep);
650 }
651
652 inline std::error_code
653 36x win_local_stream_acceptor_service::listen_acceptor(
654 local_stream_acceptor::implementation& impl, int backlog)
655 {
656 auto* internal =
657 36x static_cast<win_local_stream_acceptor&>(impl).get_internal();
658 36x return svc_.listen_acceptor(*internal, backlog);
659 }
660
661 inline void
662 1247x win_local_stream_acceptor_service::shutdown()
663 {
664 // Socket shutdown is handled by win_local_stream_service::shutdown()
665 1247x }
666
667 } // namespace boost::corosio::detail
668
669 #endif // BOOST_COROSIO_HAS_IOCP
670
671 #endif // BOOST_COROSIO_NATIVE_DETAIL_IOCP_WIN_LOCAL_STREAM_ACCEPTOR_SERVICE_HPP
672