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

100.0% Lines (2/2) 100.0% List of functions (1/1) 50.0% Branches (1/2)
win_udp_socket.hpp
f(x) Functions (1)
Line Branch TLA Hits Source Code
1 //
2 // Copyright (c) 2026 Steve Gerbino
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_UDP_SOCKET_HPP
11 #define BOOST_COROSIO_NATIVE_DETAIL_IOCP_WIN_UDP_SOCKET_HPP
12
13 #include <boost/corosio/native/detail/endpoint_convert.hpp>
14 #include <boost/corosio/detail/platform.hpp>
15
16 #if BOOST_COROSIO_HAS_IOCP
17
18 #include <boost/corosio/detail/config.hpp>
19 #include <boost/corosio/udp_socket.hpp>
20 #include <boost/corosio/wait_type.hpp>
21 #include <boost/capy/ex/executor_ref.hpp>
22 #include <boost/corosio/detail/intrusive.hpp>
23 #include <boost/corosio/native/detail/iocp/win_overlapped_op.hpp>
24 #include <boost/corosio/native/detail/iocp/win_windows.hpp>
25
26 #include <coroutine>
27 #include <memory>
28
29 namespace boost::corosio::detail {
30
31 class win_udp_service;
32 class win_udp_socket_internal;
33
34 /** Send-to operation state with buffer and destination address. */
35 struct send_to_op : overlapped_op
36 {
37 static constexpr std::size_t max_buffers = 16;
38 WSABUF wsabufs[max_buffers];
39 DWORD wsabuf_count = 0;
40 sockaddr_storage dest_storage{};
41 int dest_len = 0;
42 win_udp_socket_internal& internal;
43 std::shared_ptr<win_udp_socket_internal> internal_ptr;
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 send_to_op(win_udp_socket_internal& internal_) noexcept;
53 };
54
55 /** Recv-from operation state with buffer and source address capture. */
56 struct recv_from_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 sockaddr_storage source_storage{};
63 INT source_len = sizeof(sockaddr_storage);
64 endpoint* source_out = nullptr;
65 win_udp_socket_internal& internal;
66 std::shared_ptr<win_udp_socket_internal> internal_ptr;
67
68 static void do_complete(
69 void* owner,
70 scheduler_op* base,
71 std::uint32_t bytes,
72 std::uint32_t error);
73 static void do_cancel_impl(overlapped_op* op) noexcept;
74
75 explicit recv_from_op(win_udp_socket_internal& internal_) noexcept;
76 };
77
78 /** Connect operation for connected-mode UDP on IOCP. */
79 struct udp_connect_op : overlapped_op
80 {
81 endpoint target_endpoint;
82 win_udp_socket_internal& internal;
83 std::shared_ptr<win_udp_socket_internal> internal_ptr;
84
85 static void do_complete(
86 void* owner,
87 scheduler_op* base,
88 std::uint32_t bytes,
89 std::uint32_t error);
90 static void do_cancel_impl(overlapped_op* op) noexcept;
91
92 explicit udp_connect_op(win_udp_socket_internal& internal_) noexcept;
93 };
94
95 /** Connected send operation (no destination address). */
96 struct udp_send_op : overlapped_op
97 {
98 static constexpr std::size_t max_buffers = 16;
99 WSABUF wsabufs[max_buffers];
100 DWORD wsabuf_count = 0;
101 win_udp_socket_internal& internal;
102 std::shared_ptr<win_udp_socket_internal> internal_ptr;
103
104 static void do_complete(
105 void* owner,
106 scheduler_op* base,
107 std::uint32_t bytes,
108 std::uint32_t error);
109 static void do_cancel_impl(overlapped_op* op) noexcept;
110
111 explicit udp_send_op(win_udp_socket_internal& internal_) noexcept;
112 };
113
114 /** Connected recv operation (no source address). */
115 struct udp_recv_op : overlapped_op
116 {
117 static constexpr std::size_t max_buffers = 16;
118 WSABUF wsabufs[max_buffers];
119 DWORD wsabuf_count = 0;
120 DWORD flags = 0;
121 win_udp_socket_internal& internal;
122 std::shared_ptr<win_udp_socket_internal> internal_ptr;
123
124 static void do_complete(
125 void* owner,
126 scheduler_op* base,
127 std::uint32_t bytes,
128 std::uint32_t error);
129 static void do_cancel_impl(overlapped_op* op) noexcept;
130
131 explicit udp_recv_op(win_udp_socket_internal& internal_) noexcept;
132 };
133
134 /** Readiness-wait operation (datagram socket). */
135 struct udp_wait_op : overlapped_op
136 {
137 win_udp_socket_internal& internal;
138 std::shared_ptr<win_udp_socket_internal> internal_ptr;
139
140 static void do_complete(
141 void* owner,
142 scheduler_op* base,
143 std::uint32_t bytes,
144 std::uint32_t error);
145 static void do_cancel_impl(overlapped_op* op) noexcept;
146
147 explicit udp_wait_op(win_udp_socket_internal& internal_) noexcept;
148 };
149
150 /** Internal datagram socket state for IOCP-based I/O.
151
152 This class contains the actual state for a single UDP socket,
153 including the native socket handle and pending operations. It
154 derives from enable_shared_from_this so operations can extend
155 its lifetime.
156
157 @note Internal implementation detail.
158 */
159 class win_udp_socket_internal
160 : public intrusive_list<win_udp_socket_internal>::node
161 , public std::enable_shared_from_this<win_udp_socket_internal>
162 {
163 friend class win_udp_service;
164 friend class win_udp_socket;
165 friend struct send_to_op;
166 friend struct recv_from_op;
167 friend struct udp_connect_op;
168 friend struct udp_send_op;
169 friend struct udp_recv_op;
170 friend struct udp_wait_op;
171
172 win_udp_service& svc_;
173 send_to_op wr_;
174 recv_from_op rd_;
175 udp_connect_op conn_;
176 udp_send_op send_wr_;
177 udp_recv_op recv_rd_;
178 udp_wait_op wt_;
179 SOCKET socket_ = INVALID_SOCKET;
180 int family_ = AF_UNSPEC;
181
182 public:
183 explicit win_udp_socket_internal(win_udp_service& svc) noexcept;
184 ~win_udp_socket_internal();
185
186 std::coroutine_handle<> send_to(
187 std::coroutine_handle<>,
188 capy::executor_ref,
189 buffer_param,
190 endpoint,
191 int flags,
192 std::stop_token,
193 std::error_code*,
194 std::size_t*);
195
196 std::coroutine_handle<> recv_from(
197 std::coroutine_handle<>,
198 capy::executor_ref,
199 buffer_param,
200 endpoint*,
201 int flags,
202 std::stop_token,
203 std::error_code*,
204 std::size_t*);
205
206 std::coroutine_handle<> connect(
207 std::coroutine_handle<>,
208 capy::executor_ref,
209 endpoint,
210 std::stop_token,
211 std::error_code*);
212
213 std::coroutine_handle<> send(
214 std::coroutine_handle<>,
215 capy::executor_ref,
216 buffer_param,
217 int flags,
218 std::stop_token,
219 std::error_code*,
220 std::size_t*);
221
222 std::coroutine_handle<> recv(
223 std::coroutine_handle<>,
224 capy::executor_ref,
225 buffer_param,
226 int flags,
227 std::stop_token,
228 std::error_code*,
229 std::size_t*);
230
231 std::coroutine_handle<> wait(
232 std::coroutine_handle<>,
233 capy::executor_ref,
234 wait_type,
235 std::stop_token,
236 std::error_code*);
237
238 SOCKET native_handle() const noexcept;
239 endpoint local_endpoint() const noexcept;
240 endpoint remote_endpoint() const noexcept;
241 bool is_open() const noexcept;
242 void cancel() noexcept;
243 void close_socket() noexcept;
244
245 private:
246 endpoint local_endpoint_;
247 endpoint remote_endpoint_;
248 };
249
250 /** Datagram socket implementation wrapper for IOCP-based I/O.
251
252 This class is the public-facing implementation that holds a
253 shared_ptr to the internal state. The shared_ptr is hidden
254 from the public interface.
255
256 @note Internal implementation detail.
257 */
258 class win_udp_socket final
259 : public udp_socket::implementation
260 , public intrusive_list<win_udp_socket>::node
261 {
262 std::shared_ptr<win_udp_socket_internal> internal_;
263
264 public:
265 explicit win_udp_socket(
266 std::shared_ptr<win_udp_socket_internal> internal) noexcept;
267
268 void close_internal() noexcept;
269
270 std::coroutine_handle<> send_to(
271 std::coroutine_handle<> h,
272 capy::executor_ref d,
273 buffer_param buf,
274 endpoint dest,
275 int flags,
276 std::stop_token token,
277 std::error_code* ec,
278 std::size_t* bytes) override;
279
280 std::coroutine_handle<> recv_from(
281 std::coroutine_handle<> h,
282 capy::executor_ref d,
283 buffer_param buf,
284 endpoint* source,
285 int flags,
286 std::stop_token token,
287 std::error_code* ec,
288 std::size_t* bytes) override;
289
290 std::coroutine_handle<> connect(
291 std::coroutine_handle<> h,
292 capy::executor_ref d,
293 endpoint ep,
294 std::stop_token token,
295 std::error_code* ec) override;
296
297 std::coroutine_handle<> send(
298 std::coroutine_handle<> h,
299 capy::executor_ref d,
300 buffer_param buf,
301 int flags,
302 std::stop_token token,
303 std::error_code* ec,
304 std::size_t* bytes) override;
305
306 std::coroutine_handle<> recv(
307 std::coroutine_handle<> h,
308 capy::executor_ref d,
309 buffer_param buf,
310 int flags,
311 std::stop_token token,
312 std::error_code* ec,
313 std::size_t* bytes) override;
314
315 std::coroutine_handle<> wait(
316 std::coroutine_handle<> h,
317 capy::executor_ref d,
318 wait_type w,
319 std::stop_token token,
320 std::error_code* ec) override;
321
322 native_handle_type native_handle() const noexcept override;
323
324 80x corosio::family family() const noexcept override
325 {
326 // getsockname fails with WSAEINVAL on an unbound socket, so
327 // the family recorded at socket creation is authoritative
328
1/2
✓ Branch 3 → 4 taken 80 times.
✗ Branch 3 → 6 not taken.
80x return to_family(internal_ ? internal_->family_ : AF_UNSPEC);
329 }
330
331 std::error_code shutdown(udp_socket::shutdown_type what) noexcept override;
332
333 native_handle_type release_socket() noexcept override;
334
335 std::error_code set_option(
336 int level,
337 int optname,
338 void const* data,
339 std::size_t size) noexcept override;
340 std::error_code
341 get_option(int level, int optname, void* data, std::size_t* size)
342 const noexcept override;
343
344 endpoint local_endpoint() const noexcept override;
345 endpoint remote_endpoint() const noexcept override;
346 void cancel() noexcept override;
347
348 win_udp_socket_internal* get_internal() const noexcept;
349 };
350
351 } // namespace boost::corosio::detail
352
353 #endif // BOOST_COROSIO_HAS_IOCP
354
355 #endif // BOOST_COROSIO_NATIVE_DETAIL_IOCP_WIN_UDP_SOCKET_HPP
356