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

100.0% Lines (2 / 2) -% Branches (0 / 0) 100.0% Functions (1 / 1)
win_tcp_socket.hpp
f(x) Functions (1)
Line Branch TLA Hits Source Code
1 //
2 // Copyright (c) 2025 Vinnie Falco ([email protected])
3 // Copyright (c) 2026 Steve Gerbino
4 // Copyright (c) 2026 Michael Vandeberg
5 //
6 // Distributed under the Boost Software License, Version 1.0. (See accompanying
7 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
8 //
9 // Official repository: https://github.com/cppalliance/corosio
10 //
11
12 #ifndef BOOST_COROSIO_NATIVE_DETAIL_IOCP_WIN_TCP_SOCKET_HPP
13 #define BOOST_COROSIO_NATIVE_DETAIL_IOCP_WIN_TCP_SOCKET_HPP
14
15 #include <boost/corosio/native/detail/endpoint_convert.hpp>
16 #include <boost/corosio/detail/platform.hpp>
17
18 #if BOOST_COROSIO_HAS_IOCP
19
20 #include <boost/corosio/detail/config.hpp>
21 #include <boost/corosio/detail/object_ref.hpp>
22 #include <boost/corosio/tcp_socket.hpp>
23 #include <boost/corosio/wait_type.hpp>
24 #include <boost/capy/continuation.hpp>
25 #include <boost/capy/ex/executor_ref.hpp>
26 #include <boost/corosio/detail/intrusive.hpp>
27 #include <boost/corosio/native/detail/iocp/win_overlapped_op.hpp>
28 #include <boost/corosio/native/detail/iocp/win_windows.hpp>
29
30 #include <coroutine>
31
32 #include <mswsock.h>
33
34 namespace boost::corosio::detail {
35
36 class win_tcp_service;
37 class win_tcp_socket;
38
39 /** Connect operation state. */
40 struct connect_op : overlapped_op
41 {
42 win_tcp_socket& internal;
43 endpoint target_endpoint;
44
45 static void do_complete(
46 void* owner,
47 scheduler_op* base,
48 std::uint32_t bytes,
49 std::uint32_t error);
50 static void do_cancel_impl(overlapped_op* op) noexcept;
51
52 explicit connect_op(win_tcp_socket& internal_) noexcept;
53 };
54
55 /** Read operation state with buffer descriptors. */
56 struct read_op : overlapped_op
57 {
58 static constexpr std::size_t max_buffers = 16;
59 WSABUF wsabufs[max_buffers];
60 DWORD wsabuf_count = 0;
61 DWORD flags = 0;
62 win_tcp_socket& internal;
63
64 static void do_complete(
65 void* owner,
66 scheduler_op* base,
67 std::uint32_t bytes,
68 std::uint32_t error);
69 static void do_cancel_impl(overlapped_op* op) noexcept;
70
71 explicit read_op(win_tcp_socket& internal_) noexcept;
72 };
73
74 /** Write operation state with buffer descriptors. */
75 struct write_op : overlapped_op
76 {
77 static constexpr std::size_t max_buffers = 16;
78 WSABUF wsabufs[max_buffers];
79 DWORD wsabuf_count = 0;
80 win_tcp_socket& internal;
81
82 static void do_complete(
83 void* owner,
84 scheduler_op* base,
85 std::uint32_t bytes,
86 std::uint32_t error);
87 static void do_cancel_impl(overlapped_op* op) noexcept;
88
89 explicit write_op(win_tcp_socket& internal_) noexcept;
90 };
91
92 /** Readiness-wait operation state.
93
94 Completion conveys an error_code only (no bytes_transferred).
95 wait_type::read posts a zero-byte WSARecv: the kernel signals
96 completion when data arrives without consuming it.
97 wait_type::write and wait_type::error park the op in the
98 auxiliary poll reactor until the socket becomes writable or the
99 kernel reports an error condition.
100 */
101 struct wait_op : overlapped_op
102 {
103 WSABUF wsabuf{};
104 DWORD flags = 0;
105 wait_type w = wait_type::read;
106 win_tcp_socket& internal;
107
108 static void do_complete(
109 void* owner,
110 scheduler_op* base,
111 std::uint32_t bytes,
112 std::uint32_t error);
113 static void do_cancel_impl(overlapped_op* op) noexcept;
114
115 explicit wait_op(win_tcp_socket& internal_) noexcept;
116 };
117
118 /** Socket implementation for IOCP-based I/O.
119
120 Collapses the historical internal-state/wrapper split into one
121 pooled `io_object::implementation`: it both owns the native socket
122 handle and pending operations, and directly implements
123 `tcp_socket::implementation`. `win_tcp_service` recycles instances
124 through its pool instead of freeing them on every close, so the
125 keepalive each embedded op holds is the intrusive `object_ref` from
126 `coro_op`, not a `shared_ptr`.
127
128 @note Internal implementation detail. Users interact with socket class.
129 */
130 class win_tcp_socket final
131 : public tcp_socket::implementation
132 , public intrusive_list<win_tcp_socket>::node
133 {
134 friend class win_tcp_service;
135 friend struct read_op;
136 friend struct write_op;
137 friend struct connect_op;
138 friend struct wait_op;
139
140 win_tcp_service& svc_;
141 connect_op conn_;
142 read_op rd_;
143 write_op wr_;
144 wait_op wt_;
145 SOCKET socket_ = INVALID_SOCKET;
146 int family_ = AF_UNSPEC;
147 endpoint local_endpoint_;
148 endpoint remote_endpoint_;
149
150 public:
151 explicit win_tcp_socket(win_tcp_service& svc) noexcept;
152
153 /// Recycle into the owning service's pool. Defined out-of-line
154 /// after `win_tcp_service` is complete (needs `svc_.pool_`).
155 void retire() noexcept override;
156
157 /** Reset recycled state for reuse.
158
159 `close_socket()` already drives the socket handle and family
160 to their closed values, and each op's completion drops its
161 `object_ref_` before `refs_` can reach zero. The endpoints are
162 reset here: a connect completing on another thread can write
163 them after the close. Each op's `OVERLAPPED` fields are
164 re-seeded by `overlapped_op::reset()` at its next submit, so
165 they are not zeroed here.
166
167 @pre refs_ == 0, socket closed, no op in flight.
168 */
169 void reuse() noexcept;
170
171 std::coroutine_handle<> connect(
172 capy::continuation& cont,
173 capy::executor_ref d,
174 endpoint ep,
175 std::stop_token token,
176 std::error_code* ec) override;
177
178 std::coroutine_handle<> read_some(
179 capy::continuation& cont,
180 capy::executor_ref d,
181 buffer_param buf,
182 std::stop_token token,
183 std::error_code* ec,
184 std::size_t* bytes) override;
185
186 std::coroutine_handle<> write_some(
187 capy::continuation& cont,
188 capy::executor_ref d,
189 buffer_param buf,
190 std::stop_token token,
191 std::error_code* ec,
192 std::size_t* bytes) override;
193
194 std::coroutine_handle<> wait(
195 capy::continuation& cont,
196 capy::executor_ref d,
197 wait_type w,
198 std::stop_token token,
199 std::error_code* ec) override;
200
201 std::error_code shutdown(tcp_socket::shutdown_type what) noexcept override;
202
203 native_handle_type native_handle() const noexcept override;
204
205 3551x corosio::family family() const noexcept override
206 {
207 // getsockname fails with WSAEINVAL on an unbound socket, so
208 // the family recorded at socket creation is authoritative
209 3551x return to_family(family_);
210 }
211
212 native_handle_type release_socket() noexcept override;
213
214 std::error_code set_option(
215 int level,
216 int optname,
217 void const* data,
218 std::size_t size) noexcept override;
219 std::error_code
220 get_option(int level, int optname, void* data, std::size_t* size)
221 const noexcept override;
222
223 endpoint local_endpoint() const noexcept override;
224 endpoint remote_endpoint() const noexcept override;
225 void cancel() noexcept override;
226
227 /// Used by the acceptor's `accept_op` to finish setting up the peer.
228 void set_socket(SOCKET s) noexcept;
229 void set_endpoints(endpoint local, endpoint remote) noexcept;
230
231 void close_socket() noexcept;
232 };
233
234 } // namespace boost::corosio::detail
235
236 #endif // BOOST_COROSIO_HAS_IOCP
237
238 #endif // BOOST_COROSIO_NATIVE_DETAIL_IOCP_WIN_TCP_SOCKET_HPP
239