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

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