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

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