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

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