98.85% Lines (86/87) 100.00% Functions (29/29)
TLA Baseline Branch
Line Hits Code Line Hits Code
1   // 1   //
2   // Copyright (c) 2026 Steve Gerbino 2   // Copyright (c) 2026 Steve Gerbino
3   // 3   //
4   // Distributed under the Boost Software License, Version 1.0. (See accompanying 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) 5   // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
6   // 6   //
7   // Official repository: https://github.com/cppalliance/corosio 7   // Official repository: https://github.com/cppalliance/corosio
8   // 8   //
9   9  
10   #ifndef BOOST_COROSIO_UDP_SOCKET_HPP 10   #ifndef BOOST_COROSIO_UDP_SOCKET_HPP
11   #define BOOST_COROSIO_UDP_SOCKET_HPP 11   #define BOOST_COROSIO_UDP_SOCKET_HPP
12   12  
13   #include <boost/corosio/detail/config.hpp> 13   #include <boost/corosio/detail/config.hpp>
14   #include <boost/corosio/detail/platform.hpp> 14   #include <boost/corosio/detail/platform.hpp>
15   #include <boost/corosio/detail/except.hpp> 15   #include <boost/corosio/detail/except.hpp>
16   #include <boost/corosio/detail/native_handle.hpp> 16   #include <boost/corosio/detail/native_handle.hpp>
17   #include <boost/corosio/detail/op_base.hpp> 17   #include <boost/corosio/detail/op_base.hpp>
18   #include <boost/corosio/io/io_object.hpp> 18   #include <boost/corosio/io/io_object.hpp>
19   #include <boost/capy/io_result.hpp> 19   #include <boost/capy/io_result.hpp>
20   #include <boost/corosio/detail/buffer_param.hpp> 20   #include <boost/corosio/detail/buffer_param.hpp>
21   #include <boost/corosio/endpoint.hpp> 21   #include <boost/corosio/endpoint.hpp>
22   #include <boost/corosio/message_flags.hpp> 22   #include <boost/corosio/message_flags.hpp>
23   #include <boost/corosio/udp.hpp> 23   #include <boost/corosio/udp.hpp>
24   #include <boost/corosio/wait_type.hpp> 24   #include <boost/corosio/wait_type.hpp>
25   #include <boost/capy/ex/executor_ref.hpp> 25   #include <boost/capy/ex/executor_ref.hpp>
26   #include <boost/capy/ex/execution_context.hpp> 26   #include <boost/capy/ex/execution_context.hpp>
27   #include <boost/capy/ex/io_env.hpp> 27   #include <boost/capy/ex/io_env.hpp>
28   #include <boost/capy/concept/executor.hpp> 28   #include <boost/capy/concept/executor.hpp>
29   29  
30   #include <system_error> 30   #include <system_error>
31   31  
32   #include <concepts> 32   #include <concepts>
33   #include <coroutine> 33   #include <coroutine>
34   #include <cstddef> 34   #include <cstddef>
35   #include <stop_token> 35   #include <stop_token>
36   #include <type_traits> 36   #include <type_traits>
37   37  
38   namespace boost::corosio { 38   namespace boost::corosio {
39   39  
40   /** An asynchronous UDP socket for coroutine I/O. 40   /** An asynchronous UDP socket for coroutine I/O.
41   41  
42   This class provides asynchronous UDP datagram operations that 42   This class provides asynchronous UDP datagram operations that
43   return awaitable types. Each operation participates in the affine 43   return awaitable types. Each operation participates in the affine
44   awaitable protocol, ensuring coroutines resume on the correct 44   awaitable protocol, ensuring coroutines resume on the correct
45   executor. 45   executor.
46   46  
47   Supports two modes of operation: 47   Supports two modes of operation:
48   48  
49   **Connectionless mode**: each `send_to` specifies a destination 49   **Connectionless mode**: each `send_to` specifies a destination
50   endpoint, and each `recv_from` captures the source endpoint. 50   endpoint, and each `recv_from` captures the source endpoint.
51   The socket must be opened (and optionally bound) before I/O. 51   The socket must be opened (and optionally bound) before I/O.
52   52  
53   **Connected mode**: call `connect()` to set a default peer, 53   **Connected mode**: call `connect()` to set a default peer,
54   then use `send()`/`recv()` without endpoint arguments. 54   then use `send()`/`recv()` without endpoint arguments.
55   The kernel filters incoming datagrams to those from the 55   The kernel filters incoming datagrams to those from the
56   connected peer. 56   connected peer.
57   57  
58   @par Thread Safety 58   @par Thread Safety
59   Distinct objects: Safe.@n 59   Distinct objects: Safe.@n
60   Shared objects: Unsafe. A socket must not have concurrent 60   Shared objects: Unsafe. A socket must not have concurrent
61   operations of the same type (e.g., two simultaneous recv_from). 61   operations of the same type (e.g., two simultaneous recv_from).
62   One send_to and one recv_from may be in flight simultaneously. 62   One send_to and one recv_from may be in flight simultaneously.
63   63  
64   @par Example 64   @par Example
65   @code 65   @code
66   // Connectionless mode 66   // Connectionless mode
67   io_context ioc; 67   io_context ioc;
68   udp_socket sock( ioc ); 68   udp_socket sock( ioc );
69   sock.open( udp::v4() ); 69   sock.open( udp::v4() );
70   sock.bind( endpoint( ipv4_address::any(), 9000 ) ); 70   sock.bind( endpoint( ipv4_address::any(), 9000 ) );
71   71  
72   char buf[1024]; 72   char buf[1024];
73   endpoint sender; 73   endpoint sender;
74   auto [ec, n] = co_await sock.recv_from( 74   auto [ec, n] = co_await sock.recv_from(
75   capy::mutable_buffer( buf, sizeof( buf ) ), sender ); 75   capy::mutable_buffer( buf, sizeof( buf ) ), sender );
76   if ( !ec ) 76   if ( !ec )
77   co_await sock.send_to( 77   co_await sock.send_to(
78   capy::const_buffer( buf, n ), sender ); 78   capy::const_buffer( buf, n ), sender );
79   79  
80   // Connected mode 80   // Connected mode
81   udp_socket csock( ioc ); 81   udp_socket csock( ioc );
82   auto [cec] = co_await csock.connect( 82   auto [cec] = co_await csock.connect(
83   endpoint( ipv4_address::loopback(), 9000 ) ); 83   endpoint( ipv4_address::loopback(), 9000 ) );
84   if ( !cec ) 84   if ( !cec )
85   co_await csock.send( 85   co_await csock.send(
86   capy::const_buffer( buf, n ) ); 86   capy::const_buffer( buf, n ) );
87   @endcode 87   @endcode
88   */ 88   */
89   class BOOST_COROSIO_DECL udp_socket : public io_object 89   class BOOST_COROSIO_DECL udp_socket : public io_object
90   { 90   {
91   public: 91   public:
92   /** Define backend hooks for UDP socket operations. 92   /** Define backend hooks for UDP socket operations.
93   93  
94   Platform backends (epoll, kqueue, select) derive from 94   Platform backends (epoll, kqueue, select) derive from
95   this to implement datagram I/O and option management. 95   this to implement datagram I/O and option management.
96   */ 96   */
97   struct implementation : io_object::implementation 97   struct implementation : io_object::implementation
98   { 98   {
99   /** Initiate an asynchronous send_to operation. 99   /** Initiate an asynchronous send_to operation.
100   100  
101   @param h Coroutine handle to resume on completion. 101   @param h Coroutine handle to resume on completion.
102   @param ex Executor for dispatching the completion. 102   @param ex Executor for dispatching the completion.
103   @param buf The buffer data to send. 103   @param buf The buffer data to send.
104   @param dest The destination endpoint. 104   @param dest The destination endpoint.
105   @param flags Platform message flags (e.g. `MSG_DONTWAIT`). 105   @param flags Platform message flags (e.g. `MSG_DONTWAIT`).
106   @param token Stop token for cancellation. 106   @param token Stop token for cancellation.
107   @param ec Output error code. 107   @param ec Output error code.
108   @param bytes_out Output bytes transferred. 108   @param bytes_out Output bytes transferred.
109   109  
110   @return Coroutine handle to resume immediately. 110   @return Coroutine handle to resume immediately.
111   */ 111   */
112   virtual std::coroutine_handle<> send_to( 112   virtual std::coroutine_handle<> send_to(
113   std::coroutine_handle<> h, 113   std::coroutine_handle<> h,
114   capy::executor_ref ex, 114   capy::executor_ref ex,
115   buffer_param buf, 115   buffer_param buf,
116   endpoint dest, 116   endpoint dest,
117   int flags, 117   int flags,
118   std::stop_token token, 118   std::stop_token token,
119   std::error_code* ec, 119   std::error_code* ec,
120   std::size_t* bytes_out) = 0; 120   std::size_t* bytes_out) = 0;
121   121  
122   /** Initiate an asynchronous recv_from operation. 122   /** Initiate an asynchronous recv_from operation.
123   123  
124   @param h Coroutine handle to resume on completion. 124   @param h Coroutine handle to resume on completion.
125   @param ex Executor for dispatching the completion. 125   @param ex Executor for dispatching the completion.
126   @param buf The buffer to receive into. 126   @param buf The buffer to receive into.
127   @param source Output endpoint for the sender's address. 127   @param source Output endpoint for the sender's address.
128   @param flags Platform message flags (e.g. `MSG_PEEK`). 128   @param flags Platform message flags (e.g. `MSG_PEEK`).
129   @param token Stop token for cancellation. 129   @param token Stop token for cancellation.
130   @param ec Output error code. 130   @param ec Output error code.
131   @param bytes_out Output bytes transferred. 131   @param bytes_out Output bytes transferred.
132   132  
133   @return Coroutine handle to resume immediately. 133   @return Coroutine handle to resume immediately.
134   */ 134   */
135   virtual std::coroutine_handle<> recv_from( 135   virtual std::coroutine_handle<> recv_from(
136   std::coroutine_handle<> h, 136   std::coroutine_handle<> h,
137   capy::executor_ref ex, 137   capy::executor_ref ex,
138   buffer_param buf, 138   buffer_param buf,
139   endpoint* source, 139   endpoint* source,
140   int flags, 140   int flags,
141   std::stop_token token, 141   std::stop_token token,
142   std::error_code* ec, 142   std::error_code* ec,
143   std::size_t* bytes_out) = 0; 143   std::size_t* bytes_out) = 0;
144   144  
145   /// Return the platform socket descriptor. 145   /// Return the platform socket descriptor.
146   virtual native_handle_type native_handle() const noexcept = 0; 146   virtual native_handle_type native_handle() const noexcept = 0;
147   147  
  148 + /** Release ownership of the native socket handle.
  149 +
  150 + Deregisters the socket from the backend and cancels
  151 + pending operations without closing the descriptor. The
  152 + caller takes ownership.
  153 +
  154 + @return The native handle.
  155 + */
  156 + virtual native_handle_type release_socket() noexcept = 0;
  157 +
148   /** Request cancellation of pending asynchronous operations. 158   /** Request cancellation of pending asynchronous operations.
149   159  
150   All outstanding operations complete with operation_canceled 160   All outstanding operations complete with operation_canceled
151   error. Check `ec == cond::canceled` for portable comparison. 161   error. Check `ec == cond::canceled` for portable comparison.
152   */ 162   */
153   virtual void cancel() noexcept = 0; 163   virtual void cancel() noexcept = 0;
154   164  
155   /** Set a socket option. 165   /** Set a socket option.
156   166  
157   @param level The protocol level (e.g. `SOL_SOCKET`). 167   @param level The protocol level (e.g. `SOL_SOCKET`).
158   @param optname The option name. 168   @param optname The option name.
159   @param data Pointer to the option value. 169   @param data Pointer to the option value.
160   @param size Size of the option value in bytes. 170   @param size Size of the option value in bytes.
161   @return Error code on failure, empty on success. 171   @return Error code on failure, empty on success.
162   */ 172   */
163   virtual std::error_code set_option( 173   virtual std::error_code set_option(
164   int level, 174   int level,
165   int optname, 175   int optname,
166   void const* data, 176   void const* data,
167   std::size_t size) noexcept = 0; 177   std::size_t size) noexcept = 0;
168   178  
169   /** Get a socket option. 179   /** Get a socket option.
170   180  
171   @param level The protocol level (e.g. `SOL_SOCKET`). 181   @param level The protocol level (e.g. `SOL_SOCKET`).
172   @param optname The option name. 182   @param optname The option name.
173   @param data Pointer to receive the option value. 183   @param data Pointer to receive the option value.
174   @param size On entry, the size of the buffer. On exit, 184   @param size On entry, the size of the buffer. On exit,
175   the size of the option value. 185   the size of the option value.
176   @return Error code on failure, empty on success. 186   @return Error code on failure, empty on success.
177   */ 187   */
178   virtual std::error_code 188   virtual std::error_code
179   get_option(int level, int optname, void* data, std::size_t* size) 189   get_option(int level, int optname, void* data, std::size_t* size)
180   const noexcept = 0; 190   const noexcept = 0;
181   191  
182   /// Return the cached local endpoint. 192   /// Return the cached local endpoint.
183   virtual endpoint local_endpoint() const noexcept = 0; 193   virtual endpoint local_endpoint() const noexcept = 0;
184   194  
185   /// Return the cached remote endpoint (connected mode). 195   /// Return the cached remote endpoint (connected mode).
186   virtual endpoint remote_endpoint() const noexcept = 0; 196   virtual endpoint remote_endpoint() const noexcept = 0;
187   197  
188   /** Initiate an asynchronous connect to set the default peer. 198   /** Initiate an asynchronous connect to set the default peer.
189   199  
190   @param h Coroutine handle to resume on completion. 200   @param h Coroutine handle to resume on completion.
191   @param ex Executor for dispatching the completion. 201   @param ex Executor for dispatching the completion.
192   @param ep The remote endpoint to connect to. 202   @param ep The remote endpoint to connect to.
193   @param token Stop token for cancellation. 203   @param token Stop token for cancellation.
194   @param ec Output error code. 204   @param ec Output error code.
195   205  
196   @return Coroutine handle to resume immediately. 206   @return Coroutine handle to resume immediately.
197   */ 207   */
198   virtual std::coroutine_handle<> connect( 208   virtual std::coroutine_handle<> connect(
199   std::coroutine_handle<> h, 209   std::coroutine_handle<> h,
200   capy::executor_ref ex, 210   capy::executor_ref ex,
201   endpoint ep, 211   endpoint ep,
202   std::stop_token token, 212   std::stop_token token,
203   std::error_code* ec) = 0; 213   std::error_code* ec) = 0;
204   214  
205   /** Initiate an asynchronous connected send operation. 215   /** Initiate an asynchronous connected send operation.
206   216  
207   @param h Coroutine handle to resume on completion. 217   @param h Coroutine handle to resume on completion.
208   @param ex Executor for dispatching the completion. 218   @param ex Executor for dispatching the completion.
209   @param buf The buffer data to send. 219   @param buf The buffer data to send.
210   @param flags Platform message flags (e.g. `MSG_DONTWAIT`). 220   @param flags Platform message flags (e.g. `MSG_DONTWAIT`).
211   @param token Stop token for cancellation. 221   @param token Stop token for cancellation.
212   @param ec Output error code. 222   @param ec Output error code.
213   @param bytes_out Output bytes transferred. 223   @param bytes_out Output bytes transferred.
214   224  
215   @return Coroutine handle to resume immediately. 225   @return Coroutine handle to resume immediately.
216   */ 226   */
217   virtual std::coroutine_handle<> send( 227   virtual std::coroutine_handle<> send(
218   std::coroutine_handle<> h, 228   std::coroutine_handle<> h,
219   capy::executor_ref ex, 229   capy::executor_ref ex,
220   buffer_param buf, 230   buffer_param buf,
221   int flags, 231   int flags,
222   std::stop_token token, 232   std::stop_token token,
223   std::error_code* ec, 233   std::error_code* ec,
224   std::size_t* bytes_out) = 0; 234   std::size_t* bytes_out) = 0;
225   235  
226   /** Initiate an asynchronous connected recv operation. 236   /** Initiate an asynchronous connected recv operation.
227   237  
228   @param h Coroutine handle to resume on completion. 238   @param h Coroutine handle to resume on completion.
229   @param ex Executor for dispatching the completion. 239   @param ex Executor for dispatching the completion.
230   @param buf The buffer to receive into. 240   @param buf The buffer to receive into.
231   @param flags Platform message flags (e.g. `MSG_PEEK`). 241   @param flags Platform message flags (e.g. `MSG_PEEK`).
232   @param token Stop token for cancellation. 242   @param token Stop token for cancellation.
233   @param ec Output error code. 243   @param ec Output error code.
234   @param bytes_out Output bytes transferred. 244   @param bytes_out Output bytes transferred.
235   245  
236   @return Coroutine handle to resume immediately. 246   @return Coroutine handle to resume immediately.
237   */ 247   */
238   virtual std::coroutine_handle<> recv( 248   virtual std::coroutine_handle<> recv(
239   std::coroutine_handle<> h, 249   std::coroutine_handle<> h,
240   capy::executor_ref ex, 250   capy::executor_ref ex,
241   buffer_param buf, 251   buffer_param buf,
242   int flags, 252   int flags,
243   std::stop_token token, 253   std::stop_token token,
244   std::error_code* ec, 254   std::error_code* ec,
245   std::size_t* bytes_out) = 0; 255   std::size_t* bytes_out) = 0;
246   256  
247   /** Initiate an asynchronous wait for socket readiness. 257   /** Initiate an asynchronous wait for socket readiness.
248   258  
249   Completes when the socket becomes ready for the 259   Completes when the socket becomes ready for the
250   specified direction, or an error condition is 260   specified direction, or an error condition is
251   reported. No bytes are transferred. 261   reported. No bytes are transferred.
252   262  
253   @param h Coroutine handle to resume on completion. 263   @param h Coroutine handle to resume on completion.
254   @param ex Executor for dispatching the completion. 264   @param ex Executor for dispatching the completion.
255   @param w The direction to wait on. 265   @param w The direction to wait on.
256   @param token Stop token for cancellation. 266   @param token Stop token for cancellation.
257   @param ec Output error code. 267   @param ec Output error code.
258   268  
259   @return Coroutine handle to resume immediately. 269   @return Coroutine handle to resume immediately.
260   */ 270   */
261   virtual std::coroutine_handle<> wait( 271   virtual std::coroutine_handle<> wait(
262   std::coroutine_handle<> h, 272   std::coroutine_handle<> h,
263   capy::executor_ref ex, 273   capy::executor_ref ex,
264   wait_type w, 274   wait_type w,
265   std::stop_token token, 275   std::stop_token token,
266   std::error_code* ec) = 0; 276   std::error_code* ec) = 0;
267   }; 277   };
268   278  
269   /** Represent the awaitable returned by @ref send_to. 279   /** Represent the awaitable returned by @ref send_to.
270   280  
271   Captures the destination endpoint and buffer, then dispatches 281   Captures the destination endpoint and buffer, then dispatches
272   to the backend implementation on suspension. 282   to the backend implementation on suspension.
273   */ 283   */
274   struct send_to_awaitable 284   struct send_to_awaitable
275   : detail::bytes_op_base<send_to_awaitable> 285   : detail::bytes_op_base<send_to_awaitable>
276   { 286   {
277   udp_socket& s_; 287   udp_socket& s_;
278   buffer_param buf_; 288   buffer_param buf_;
279   endpoint dest_; 289   endpoint dest_;
280   int flags_; 290   int flags_;
281   291  
HITCBC 282   43 send_to_awaitable( 292   53 send_to_awaitable(
283   udp_socket& s, buffer_param buf, 293   udp_socket& s, buffer_param buf,
284   endpoint dest, int flags = 0) noexcept 294   endpoint dest, int flags = 0) noexcept
HITCBC 285   43 : s_(s), buf_(buf), dest_(dest), flags_(flags) {} 295   53 : s_(s), buf_(buf), dest_(dest), flags_(flags) {}
286   296  
HITCBC 287   43 std::coroutine_handle<> dispatch( 297   53 std::coroutine_handle<> dispatch(
288   std::coroutine_handle<> h, capy::executor_ref ex) const 298   std::coroutine_handle<> h, capy::executor_ref ex) const
289   { 299   {
HITCBC 290   86 return s_.get().send_to( 300   106 return s_.get().send_to(
HITCBC 291   86 h, ex, buf_, dest_, flags_, token_, &ec_, &bytes_); 301   106 h, ex, buf_, dest_, flags_, token_, &ec_, &bytes_);
292   } 302   }
293   }; 303   };
294   304  
295   /** Represent the awaitable returned by @ref recv_from. 305   /** Represent the awaitable returned by @ref recv_from.
296   306  
297   Captures the source endpoint reference and buffer, then 307   Captures the source endpoint reference and buffer, then
298   dispatches to the backend implementation on suspension. 308   dispatches to the backend implementation on suspension.
299   */ 309   */
300   struct recv_from_awaitable 310   struct recv_from_awaitable
301   : detail::bytes_op_base<recv_from_awaitable> 311   : detail::bytes_op_base<recv_from_awaitable>
302   { 312   {
303   udp_socket& s_; 313   udp_socket& s_;
304   buffer_param buf_; 314   buffer_param buf_;
305   endpoint& source_; 315   endpoint& source_;
306   int flags_; 316   int flags_;
307   317  
HITCBC 308   55 recv_from_awaitable( 318   71 recv_from_awaitable(
309   udp_socket& s, buffer_param buf, 319   udp_socket& s, buffer_param buf,
310   endpoint& source, int flags = 0) noexcept 320   endpoint& source, int flags = 0) noexcept
HITCBC 311   55 : s_(s), buf_(buf), source_(source), flags_(flags) {} 321   71 : s_(s), buf_(buf), source_(source), flags_(flags) {}
312   322  
HITCBC 313   55 std::coroutine_handle<> dispatch( 323   71 std::coroutine_handle<> dispatch(
314   std::coroutine_handle<> h, capy::executor_ref ex) const 324   std::coroutine_handle<> h, capy::executor_ref ex) const
315   { 325   {
HITCBC 316   110 return s_.get().recv_from( 326   142 return s_.get().recv_from(
HITCBC 317   110 h, ex, buf_, &source_, flags_, token_, &ec_, &bytes_); 327   142 h, ex, buf_, &source_, flags_, token_, &ec_, &bytes_);
318   } 328   }
319   }; 329   };
320   330  
321   /// Represent the awaitable returned by @ref connect. 331   /// Represent the awaitable returned by @ref connect.
322   struct connect_awaitable 332   struct connect_awaitable
323   : detail::void_op_base<connect_awaitable> 333   : detail::void_op_base<connect_awaitable>
324   { 334   {
325   udp_socket& s_; 335   udp_socket& s_;
326   endpoint endpoint_; 336   endpoint endpoint_;
327   337  
HITCBC 328   26 connect_awaitable(udp_socket& s, endpoint ep) noexcept 338   26 connect_awaitable(udp_socket& s, endpoint ep) noexcept
HITCBC 329   26 : s_(s), endpoint_(ep) {} 339   26 : s_(s), endpoint_(ep) {}
330   340  
HITCBC 331   26 std::coroutine_handle<> dispatch( 341   26 std::coroutine_handle<> dispatch(
332   std::coroutine_handle<> h, capy::executor_ref ex) const 342   std::coroutine_handle<> h, capy::executor_ref ex) const
333   { 343   {
HITCBC 334   26 return s_.get().connect(h, ex, endpoint_, token_, &ec_); 344   26 return s_.get().connect(h, ex, endpoint_, token_, &ec_);
335   } 345   }
336   }; 346   };
337   347  
338   /// Represent the awaitable returned by @ref wait. 348   /// Represent the awaitable returned by @ref wait.
339   struct wait_awaitable 349   struct wait_awaitable
340   : detail::void_op_base<wait_awaitable> 350   : detail::void_op_base<wait_awaitable>
341   { 351   {
342   udp_socket& s_; 352   udp_socket& s_;
343   wait_type w_; 353   wait_type w_;
344   354  
HITCBC 345   22 wait_awaitable(udp_socket& s, wait_type w) noexcept 355   22 wait_awaitable(udp_socket& s, wait_type w) noexcept
HITCBC 346   22 : s_(s), w_(w) {} 356   22 : s_(s), w_(w) {}
347   357  
HITCBC 348   22 std::coroutine_handle<> dispatch( 358   22 std::coroutine_handle<> dispatch(
349   std::coroutine_handle<> h, capy::executor_ref ex) const 359   std::coroutine_handle<> h, capy::executor_ref ex) const
350   { 360   {
HITCBC 351   22 return s_.get().wait(h, ex, w_, token_, &ec_); 361   22 return s_.get().wait(h, ex, w_, token_, &ec_);
352   } 362   }
353   }; 363   };
354   364  
355   /// Represent the awaitable returned by @ref send. 365   /// Represent the awaitable returned by @ref send.
356   struct send_awaitable 366   struct send_awaitable
357   : detail::bytes_op_base<send_awaitable> 367   : detail::bytes_op_base<send_awaitable>
358   { 368   {
359   udp_socket& s_; 369   udp_socket& s_;
360   buffer_param buf_; 370   buffer_param buf_;
361   int flags_; 371   int flags_;
362   372  
HITCBC 363   12 send_awaitable( 373   12 send_awaitable(
364   udp_socket& s, buffer_param buf, 374   udp_socket& s, buffer_param buf,
365   int flags = 0) noexcept 375   int flags = 0) noexcept
HITCBC 366   12 : s_(s), buf_(buf), flags_(flags) {} 376   12 : s_(s), buf_(buf), flags_(flags) {}
367   377  
HITCBC 368   12 std::coroutine_handle<> dispatch( 378   12 std::coroutine_handle<> dispatch(
369   std::coroutine_handle<> h, capy::executor_ref ex) const 379   std::coroutine_handle<> h, capy::executor_ref ex) const
370   { 380   {
HITCBC 371   24 return s_.get().send( 381   24 return s_.get().send(
HITCBC 372   24 h, ex, buf_, flags_, token_, &ec_, &bytes_); 382   24 h, ex, buf_, flags_, token_, &ec_, &bytes_);
373   } 383   }
374   }; 384   };
375   385  
376   /// Represent the awaitable returned by @ref recv. 386   /// Represent the awaitable returned by @ref recv.
377   struct recv_awaitable 387   struct recv_awaitable
378   : detail::bytes_op_base<recv_awaitable> 388   : detail::bytes_op_base<recv_awaitable>
379   { 389   {
380   udp_socket& s_; 390   udp_socket& s_;
381   buffer_param buf_; 391   buffer_param buf_;
382   int flags_; 392   int flags_;
383   393  
HITCBC 384   12 recv_awaitable( 394   12 recv_awaitable(
385   udp_socket& s, buffer_param buf, 395   udp_socket& s, buffer_param buf,
386   int flags = 0) noexcept 396   int flags = 0) noexcept
HITCBC 387   12 : s_(s), buf_(buf), flags_(flags) {} 397   12 : s_(s), buf_(buf), flags_(flags) {}
388   398  
HITCBC 389   12 std::coroutine_handle<> dispatch( 399   12 std::coroutine_handle<> dispatch(
390   std::coroutine_handle<> h, capy::executor_ref ex) const 400   std::coroutine_handle<> h, capy::executor_ref ex) const
391   { 401   {
HITCBC 392   24 return s_.get().recv( 402   24 return s_.get().recv(
HITCBC 393   24 h, ex, buf_, flags_, token_, &ec_, &bytes_); 403   24 h, ex, buf_, flags_, token_, &ec_, &bytes_);
394   } 404   }
395   }; 405   };
396   406  
397   public: 407   public:
398   /** Destructor. 408   /** Destructor.
399   409  
400   Closes the socket if open, cancelling any pending operations. 410   Closes the socket if open, cancelling any pending operations.
401   */ 411   */
402   ~udp_socket() override; 412   ~udp_socket() override;
403   413  
404   /** Construct a socket from an execution context. 414   /** Construct a socket from an execution context.
405   415  
406   @param ctx The execution context that will own this socket. 416   @param ctx The execution context that will own this socket.
407   */ 417   */
408   explicit udp_socket(capy::execution_context& ctx); 418   explicit udp_socket(capy::execution_context& ctx);
409   419  
410   /** Construct a socket from an executor. 420   /** Construct a socket from an executor.
411   421  
412   The socket is associated with the executor's context. 422   The socket is associated with the executor's context.
413   423  
414   @param ex The executor whose context will own the socket. 424   @param ex The executor whose context will own the socket.
415   */ 425   */
416   template<class Ex> 426   template<class Ex>
417   requires(!std::same_as<std::remove_cvref_t<Ex>, udp_socket>) && 427   requires(!std::same_as<std::remove_cvref_t<Ex>, udp_socket>) &&
418   capy::Executor<Ex> 428   capy::Executor<Ex>
419   explicit udp_socket(Ex const& ex) : udp_socket(ex.context()) 429   explicit udp_socket(Ex const& ex) : udp_socket(ex.context())
420   { 430   {
421   } 431   }
422   432  
423   /** Move constructor. 433   /** Move constructor.
424   434  
425   Transfers ownership of the socket resources. 435   Transfers ownership of the socket resources.
426   436  
427   @param other The socket to move from. 437   @param other The socket to move from.
428   */ 438   */
HITCBC 429   4 udp_socket(udp_socket&& other) noexcept : io_object(std::move(other)) {} 439   4 udp_socket(udp_socket&& other) noexcept : io_object(std::move(other)) {}
430   440  
431   /** Move assignment operator. 441   /** Move assignment operator.
432   442  
433   Closes any existing socket and transfers ownership. 443   Closes any existing socket and transfers ownership.
434   444  
435   @param other The socket to move from. 445   @param other The socket to move from.
436   @return Reference to this socket. 446   @return Reference to this socket.
437   */ 447   */
HITCBC 438   2 udp_socket& operator=(udp_socket&& other) noexcept 448   2 udp_socket& operator=(udp_socket&& other) noexcept
439   { 449   {
HITCBC 440   2 if (this != &other) 450   2 if (this != &other)
441   { 451   {
HITCBC 442   2 close(); 452   2 close();
HITCBC 443   2 h_ = std::move(other.h_); 453   2 h_ = std::move(other.h_);
444   } 454   }
HITCBC 445   2 return *this; 455   2 return *this;
446   } 456   }
447   457  
448   udp_socket(udp_socket const&) = delete; 458   udp_socket(udp_socket const&) = delete;
449   udp_socket& operator=(udp_socket const&) = delete; 459   udp_socket& operator=(udp_socket const&) = delete;
450   460  
451   /** Open the socket. 461   /** Open the socket.
452   462  
453   Creates a UDP socket and associates it with the platform 463   Creates a UDP socket and associates it with the platform
454   reactor. 464   reactor.
455   465  
456   @param proto The protocol (IPv4 or IPv6). Defaults to 466   @param proto The protocol (IPv4 or IPv6). Defaults to
457   `udp::v4()`. 467   `udp::v4()`.
458   468  
459   @throws std::system_error on failure. 469   @throws std::system_error on failure.
460   */ 470   */
461   void open(udp proto = udp::v4()); 471   void open(udp proto = udp::v4());
462   472  
463   /** Close the socket. 473   /** Close the socket.
464   474  
465   Releases socket resources. Any pending operations complete 475   Releases socket resources. Any pending operations complete
466   with `errc::operation_canceled`. 476   with `errc::operation_canceled`.
467   */ 477   */
468   void close(); 478   void close();
469   479  
470   /** Check if the socket is open. 480   /** Check if the socket is open.
471   481  
472   @return `true` if the socket is open and ready for operations. 482   @return `true` if the socket is open and ready for operations.
473   */ 483   */
HITCBC 474   1125 bool is_open() const noexcept 484   1257 bool is_open() const noexcept
475   { 485   {
476   #if BOOST_COROSIO_HAS_IOCP && !defined(BOOST_COROSIO_MRDOCS) 486   #if BOOST_COROSIO_HAS_IOCP && !defined(BOOST_COROSIO_MRDOCS)
477   return h_ && get().native_handle() != ~native_handle_type(0); 487   return h_ && get().native_handle() != ~native_handle_type(0);
478   #else 488   #else
HITCBC 479   1125 return h_ && get().native_handle() >= 0; 489   1257 return h_ && get().native_handle() >= 0;
480   #endif 490   #endif
481   } 491   }
482   492  
483   /** Bind the socket to a local endpoint. 493   /** Bind the socket to a local endpoint.
484   494  
485   Associates the socket with a local address and port. 495   Associates the socket with a local address and port.
486   Required before calling `recv_from`. 496   Required before calling `recv_from`.
487   497  
488   @param ep The local endpoint to bind to. 498   @param ep The local endpoint to bind to.
489   499  
490   @return Error code on failure, empty on success. 500   @return Error code on failure, empty on success.
491   501  
492   @throws std::logic_error if the socket is not open. 502   @throws std::logic_error if the socket is not open.
493   */ 503   */
494   [[nodiscard]] std::error_code bind(endpoint ep); 504   [[nodiscard]] std::error_code bind(endpoint ep);
495   505  
496   /** Cancel any pending asynchronous operations. 506   /** Cancel any pending asynchronous operations.
497   507  
498   All outstanding operations complete with 508   All outstanding operations complete with
499   `errc::operation_canceled`. Check `ec == cond::canceled` 509   `errc::operation_canceled`. Check `ec == cond::canceled`
500   for portable comparison. 510   for portable comparison.
501   */ 511   */
502   void cancel(); 512   void cancel();
503   513  
504   /** Get the native socket handle. 514   /** Get the native socket handle.
505   515  
506   @return The native socket handle, or -1 if not open. 516   @return The native socket handle, or -1 if not open.
507   */ 517   */
508   native_handle_type native_handle() const noexcept; 518   native_handle_type native_handle() const noexcept;
  519 +
  520 + /** Assign an existing native socket to this object.
  521 +
  522 + Adopts a UDP socket created outside the library — received
  523 + from another process, inherited, or made natively — and
  524 + registers it with the backend. The socket must be a datagram
  525 + socket in the `AF_INET` or `AF_INET6` family. Adoption never
  526 + alters the descriptor's flags or options: on POSIX the fd
  527 + must already be non-blocking, and on Windows the socket must
  528 + be overlapped-capable.
  529 +
  530 + If this object is already open, pending operations complete
  531 + with `errc::operation_canceled` and the held socket is
  532 + closed before the new one is adopted.
  533 +
  534 + @par Exception Safety
  535 + Strong guarantee on validation failure: the object is
  536 + unchanged. If backend registration fails, the object either
  537 + retains its previous socket or is left closed, depending on
  538 + the backend. In all failure cases the caller retains
  539 + ownership of `fd`.
  540 +
  541 + @param fd The native socket to adopt. On success the object
  542 + owns it and will close it.
  543 +
  544 + @throws std::system_error On validation or registration
  545 + failure.
  546 + */
  547 + void assign(native_handle_type fd);
  548 +
  549 + /** Release ownership of the native socket handle.
  550 +
  551 + Deregisters the socket from the backend and cancels pending
  552 + operations without closing the descriptor. The caller takes
  553 + ownership of the returned handle.
  554 +
  555 + @return The native handle.
  556 +
  557 + @throws std::logic_error if the socket is not open.
  558 +
  559 + @post is_open() == false
  560 + */
  561 + native_handle_type release();
509   562  
510   /** Set a socket option. 563   /** Set a socket option.
511   564  
512   @param opt The option to set. 565   @param opt The option to set.
513   566  
514   @throws std::logic_error if the socket is not open. 567   @throws std::logic_error if the socket is not open.
515   @throws std::system_error on failure. 568   @throws std::system_error on failure.
516   */ 569   */
517   template<class Option> 570   template<class Option>
HITCBC 518   89 void set_option(Option const& opt) 571   89 void set_option(Option const& opt)
519   { 572   {
HITCBC 520   89 if (!is_open()) 573   89 if (!is_open())
HITCBC 521   2 detail::throw_logic_error("set_option: socket not open"); 574   2 detail::throw_logic_error("set_option: socket not open");
HITCBC 522   87 std::error_code ec = get().set_option( 575   87 std::error_code ec = get().set_option(
523   Option::level(), Option::name(), opt.data(), opt.size()); 576   Option::level(), Option::name(), opt.data(), opt.size());
HITCBC 524   87 if (ec) 577   87 if (ec)
HITCBC 525   4 detail::throw_system_error(ec, "udp_socket::set_option"); 578   4 detail::throw_system_error(ec, "udp_socket::set_option");
HITCBC 526   83 } 579   83 }
527   580  
528   /** Get a socket option. 581   /** Get a socket option.
529   582  
530   @return The current option value. 583   @return The current option value.
531   584  
532   @throws std::logic_error if the socket is not open. 585   @throws std::logic_error if the socket is not open.
533   @throws std::system_error on failure. 586   @throws std::system_error on failure.
534   */ 587   */
535   template<class Option> 588   template<class Option>
HITCBC 536   55 Option get_option() const 589   55 Option get_option() const
537   { 590   {
HITCBC 538   55 if (!is_open()) 591   55 if (!is_open())
HITCBC 539   2 detail::throw_logic_error("get_option: socket not open"); 592   2 detail::throw_logic_error("get_option: socket not open");
HITCBC 540   53 Option opt{}; 593   53 Option opt{};
HITCBC 541   53 std::size_t sz = opt.size(); 594   53 std::size_t sz = opt.size();
542   std::error_code ec = 595   std::error_code ec =
HITCBC 543   53 get().get_option(Option::level(), Option::name(), opt.data(), &sz); 596   53 get().get_option(Option::level(), Option::name(), opt.data(), &sz);
HITCBC 544   53 if (ec) 597   53 if (ec)
MISUBC 545   detail::throw_system_error(ec, "udp_socket::get_option"); 598   detail::throw_system_error(ec, "udp_socket::get_option");
HITCBC 546   53 opt.resize(sz); 599   53 opt.resize(sz);
HITCBC 547   53 return opt; 600   53 return opt;
548   } 601   }
549   602  
550   /** Get the local endpoint of the socket. 603   /** Get the local endpoint of the socket.
551   604  
552   @return The local endpoint, or a default endpoint if not bound. 605   @return The local endpoint, or a default endpoint if not bound.
553   */ 606   */
554   endpoint local_endpoint() const noexcept; 607   endpoint local_endpoint() const noexcept;
555   608  
556   /** Send a datagram to the specified destination. 609   /** Send a datagram to the specified destination.
557   610  
558   @param buf The buffer containing data to send. 611   @param buf The buffer containing data to send.
559   @param dest The destination endpoint. 612   @param dest The destination endpoint.
560   @param flags Message flags (e.g. message_flags::dont_route). 613   @param flags Message flags (e.g. message_flags::dont_route).
561   614  
562   @return An awaitable that completes with 615   @return An awaitable that completes with
563   `io_result<std::size_t>`. 616   `io_result<std::size_t>`.
564   617  
565   @throws std::logic_error if the socket is not open. 618   @throws std::logic_error if the socket is not open.
566   */ 619   */
567   template<capy::ConstBufferSequence Buffers> 620   template<capy::ConstBufferSequence Buffers>
HITCBC 568   45 auto send_to( 621   55 auto send_to(
569   Buffers const& buf, 622   Buffers const& buf,
570   endpoint dest, 623   endpoint dest,
571   corosio::message_flags flags) 624   corosio::message_flags flags)
572   { 625   {
HITCBC 573   45 if (!is_open()) 626   55 if (!is_open())
HITCBC 574   2 detail::throw_logic_error("send_to: socket not open"); 627   2 detail::throw_logic_error("send_to: socket not open");
575   return send_to_awaitable( 628   return send_to_awaitable(
HITCBC 576   43 *this, buf, dest, static_cast<int>(flags)); 629   53 *this, buf, dest, static_cast<int>(flags));
577   } 630   }
578   631  
579   /// @overload 632   /// @overload
580   template<capy::ConstBufferSequence Buffers> 633   template<capy::ConstBufferSequence Buffers>
HITCBC 581   45 auto send_to(Buffers const& buf, endpoint dest) 634   55 auto send_to(Buffers const& buf, endpoint dest)
582   { 635   {
HITCBC 583   45 return send_to(buf, dest, corosio::message_flags::none); 636   55 return send_to(buf, dest, corosio::message_flags::none);
584   } 637   }
585   638  
586   /** Receive a datagram and capture the sender's endpoint. 639   /** Receive a datagram and capture the sender's endpoint.
587   640  
588   @param buf The buffer to receive data into. 641   @param buf The buffer to receive data into.
589   @param source Reference to an endpoint that will be set to 642   @param source Reference to an endpoint that will be set to
590   the sender's address on successful completion. 643   the sender's address on successful completion.
591   @param flags Message flags (e.g. message_flags::peek). 644   @param flags Message flags (e.g. message_flags::peek).
592   645  
593   @return An awaitable that completes with 646   @return An awaitable that completes with
594   `io_result<std::size_t>`. 647   `io_result<std::size_t>`.
595   648  
596   @throws std::logic_error if the socket is not open. 649   @throws std::logic_error if the socket is not open.
597   */ 650   */
598   template<capy::MutableBufferSequence Buffers> 651   template<capy::MutableBufferSequence Buffers>
HITCBC 599   57 auto recv_from( 652   73 auto recv_from(
600   Buffers const& buf, 653   Buffers const& buf,
601   endpoint& source, 654   endpoint& source,
602   corosio::message_flags flags) 655   corosio::message_flags flags)
603   { 656   {
HITCBC 604   57 if (!is_open()) 657   73 if (!is_open())
HITCBC 605   2 detail::throw_logic_error("recv_from: socket not open"); 658   2 detail::throw_logic_error("recv_from: socket not open");
606   return recv_from_awaitable( 659   return recv_from_awaitable(
HITCBC 607   55 *this, buf, source, static_cast<int>(flags)); 660   71 *this, buf, source, static_cast<int>(flags));
608   } 661   }
609   662  
610   /// @overload 663   /// @overload
611   template<capy::MutableBufferSequence Buffers> 664   template<capy::MutableBufferSequence Buffers>
HITCBC 612   56 auto recv_from(Buffers const& buf, endpoint& source) 665   72 auto recv_from(Buffers const& buf, endpoint& source)
613   { 666   {
HITCBC 614   56 return recv_from(buf, source, corosio::message_flags::none); 667   72 return recv_from(buf, source, corosio::message_flags::none);
615   } 668   }
616   669  
617   /** Initiate an asynchronous connect to set the default peer. 670   /** Initiate an asynchronous connect to set the default peer.
618   671  
619   If the socket is not already open, it is opened automatically 672   If the socket is not already open, it is opened automatically
620   using the address family of @p ep. 673   using the address family of @p ep.
621   674  
622   @param ep The remote endpoint to connect to. 675   @param ep The remote endpoint to connect to.
623   676  
624   @return An awaitable that completes with `io_result<>`. 677   @return An awaitable that completes with `io_result<>`.
625   678  
626   @throws std::system_error if the socket needs to be opened 679   @throws std::system_error if the socket needs to be opened
627   and the open fails. 680   and the open fails.
628   */ 681   */
HITCBC 629   26 auto connect(endpoint ep) 682   26 auto connect(endpoint ep)
630   { 683   {
HITCBC 631   26 if (!is_open()) 684   26 if (!is_open())
HITCBC 632   8 open(ep.is_v6() ? udp::v6() : udp::v4()); 685   8 open(ep.is_v6() ? udp::v6() : udp::v4());
HITCBC 633   26 return connect_awaitable(*this, ep); 686   26 return connect_awaitable(*this, ep);
634   } 687   }
635   688  
636   /** Wait for the socket to become ready in a given direction. 689   /** Wait for the socket to become ready in a given direction.
637   690  
638   Suspends until the socket is ready for the requested 691   Suspends until the socket is ready for the requested
639   direction, or an error condition is reported. No bytes 692   direction, or an error condition is reported. No bytes
640   are transferred. 693   are transferred.
641   694  
642   The operation supports cancellation via `std::stop_token`. 695   The operation supports cancellation via `std::stop_token`.
643   696  
644   @param w The wait direction (read, write, or error). 697   @param w The wait direction (read, write, or error).
645   698  
646   @return An awaitable that completes with `io_result<>`. 699   @return An awaitable that completes with `io_result<>`.
647   700  
648   @par Preconditions 701   @par Preconditions
649   The socket must be open. This socket must outlive the 702   The socket must be open. This socket must outlive the
650   returned awaitable. 703   returned awaitable.
651   */ 704   */
HITCBC 652   22 [[nodiscard]] auto wait(wait_type w) 705   22 [[nodiscard]] auto wait(wait_type w)
653   { 706   {
HITCBC 654   22 return wait_awaitable(*this, w); 707   22 return wait_awaitable(*this, w);
655   } 708   }
656   709  
657   /** Send a datagram to the connected peer. 710   /** Send a datagram to the connected peer.
658   711  
659   @param buf The buffer containing data to send. 712   @param buf The buffer containing data to send.
660   @param flags Message flags. 713   @param flags Message flags.
661   714  
662   @return An awaitable that completes with 715   @return An awaitable that completes with
663   `io_result<std::size_t>`. 716   `io_result<std::size_t>`.
664   717  
665   @throws std::logic_error if the socket is not open. 718   @throws std::logic_error if the socket is not open.
666   */ 719   */
667   template<capy::ConstBufferSequence Buffers> 720   template<capy::ConstBufferSequence Buffers>
HITCBC 668   14 auto send(Buffers const& buf, corosio::message_flags flags) 721   14 auto send(Buffers const& buf, corosio::message_flags flags)
669   { 722   {
HITCBC 670   14 if (!is_open()) 723   14 if (!is_open())
HITCBC 671   2 detail::throw_logic_error("send: socket not open"); 724   2 detail::throw_logic_error("send: socket not open");
672   return send_awaitable( 725   return send_awaitable(
HITCBC 673   12 *this, buf, static_cast<int>(flags)); 726   12 *this, buf, static_cast<int>(flags));
674   } 727   }
675   728  
676   /// @overload 729   /// @overload
677   template<capy::ConstBufferSequence Buffers> 730   template<capy::ConstBufferSequence Buffers>
HITCBC 678   14 auto send(Buffers const& buf) 731   14 auto send(Buffers const& buf)
679   { 732   {
HITCBC 680   14 return send(buf, corosio::message_flags::none); 733   14 return send(buf, corosio::message_flags::none);
681   } 734   }
682   735  
683   /** Receive a datagram from the connected peer. 736   /** Receive a datagram from the connected peer.
684   737  
685   @param buf The buffer to receive data into. 738   @param buf The buffer to receive data into.
686   @param flags Message flags (e.g. message_flags::peek). 739   @param flags Message flags (e.g. message_flags::peek).
687   740  
688   @return An awaitable that completes with 741   @return An awaitable that completes with
689   `io_result<std::size_t>`. 742   `io_result<std::size_t>`.
690   743  
691   @throws std::logic_error if the socket is not open. 744   @throws std::logic_error if the socket is not open.
692   */ 745   */
693   template<capy::MutableBufferSequence Buffers> 746   template<capy::MutableBufferSequence Buffers>
HITCBC 694   14 auto recv(Buffers const& buf, corosio::message_flags flags) 747   14 auto recv(Buffers const& buf, corosio::message_flags flags)
695   { 748   {
HITCBC 696   14 if (!is_open()) 749   14 if (!is_open())
HITCBC 697   2 detail::throw_logic_error("recv: socket not open"); 750   2 detail::throw_logic_error("recv: socket not open");
698   return recv_awaitable( 751   return recv_awaitable(
HITCBC 699   12 *this, buf, static_cast<int>(flags)); 752   12 *this, buf, static_cast<int>(flags));
700   } 753   }
701   754  
702   /// @overload 755   /// @overload
703   template<capy::MutableBufferSequence Buffers> 756   template<capy::MutableBufferSequence Buffers>
HITCBC 704   14 auto recv(Buffers const& buf) 757   14 auto recv(Buffers const& buf)
705   { 758   {
HITCBC 706   14 return recv(buf, corosio::message_flags::none); 759   14 return recv(buf, corosio::message_flags::none);
707   } 760   }
708   761  
709   /** Get the remote endpoint of the socket. 762   /** Get the remote endpoint of the socket.
710   763  
711   Returns the address and port of the connected peer. 764   Returns the address and port of the connected peer.
712   765  
713   @return The remote endpoint, or a default endpoint if 766   @return The remote endpoint, or a default endpoint if
714   not connected. 767   not connected.
715   */ 768   */
716   endpoint remote_endpoint() const noexcept; 769   endpoint remote_endpoint() const noexcept;
717   770  
718   protected: 771   protected:
719   /// Construct from a pre-built handle (for native_udp_socket). 772   /// Construct from a pre-built handle (for native_udp_socket).
HITCBC 720   36 explicit udp_socket(io_object::handle h) noexcept : io_object(std::move(h)) 773   36 explicit udp_socket(io_object::handle h) noexcept : io_object(std::move(h))
721   { 774   {
HITCBC 722   36 } 775   36 }
723   776  
724   private: 777   private:
725   /// Open the socket for the given protocol triple. 778   /// Open the socket for the given protocol triple.
726   void open_for_family(int family, int type, int protocol); 779   void open_for_family(int family, int type, int protocol);
727   780  
HITCBC 728   1516 inline implementation& get() const noexcept 781   1704 inline implementation& get() const noexcept
729   { 782   {
HITCBC 730   1516 return *static_cast<implementation*>(h_.get()); 783   1704 return *static_cast<implementation*>(h_.get());
731   } 784   }
732   }; 785   };
733   786  
734   } // namespace boost::corosio 787   } // namespace boost::corosio
735   788  
736   #endif // BOOST_COROSIO_UDP_SOCKET_HPP 789   #endif // BOOST_COROSIO_UDP_SOCKET_HPP