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

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