92.31% Lines (120/130) 100.00% Functions (37/37)
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_NATIVE_NATIVE_UDP_SOCKET_HPP 10   #ifndef BOOST_COROSIO_NATIVE_NATIVE_UDP_SOCKET_HPP
11   #define BOOST_COROSIO_NATIVE_NATIVE_UDP_SOCKET_HPP 11   #define BOOST_COROSIO_NATIVE_NATIVE_UDP_SOCKET_HPP
12   12  
13   #include <boost/corosio/udp_socket.hpp> 13   #include <boost/corosio/udp_socket.hpp>
14   #include <boost/corosio/backend.hpp> 14   #include <boost/corosio/backend.hpp>
15   15  
16   #ifndef BOOST_COROSIO_MRDOCS 16   #ifndef BOOST_COROSIO_MRDOCS
17   #if BOOST_COROSIO_HAS_EPOLL 17   #if BOOST_COROSIO_HAS_EPOLL
18   #include <boost/corosio/native/detail/epoll/epoll_types.hpp> 18   #include <boost/corosio/native/detail/epoll/epoll_types.hpp>
19   #endif 19   #endif
20   20  
21   #if BOOST_COROSIO_HAS_SELECT 21   #if BOOST_COROSIO_HAS_SELECT
22   #include <boost/corosio/native/detail/select/select_types.hpp> 22   #include <boost/corosio/native/detail/select/select_types.hpp>
23   #endif 23   #endif
24   24  
25   #if BOOST_COROSIO_HAS_KQUEUE 25   #if BOOST_COROSIO_HAS_KQUEUE
26   #include <boost/corosio/native/detail/kqueue/kqueue_types.hpp> 26   #include <boost/corosio/native/detail/kqueue/kqueue_types.hpp>
27   #endif 27   #endif
28   28  
29   #if BOOST_COROSIO_HAS_IOCP 29   #if BOOST_COROSIO_HAS_IOCP
30   #include <boost/corosio/native/detail/iocp/win_udp_service.hpp> 30   #include <boost/corosio/native/detail/iocp/win_udp_service.hpp>
31   #endif 31   #endif
32   #endif // !BOOST_COROSIO_MRDOCS 32   #endif // !BOOST_COROSIO_MRDOCS
33   33  
34   namespace boost::corosio { 34   namespace boost::corosio {
35   35  
36   /** An asynchronous UDP socket with devirtualized I/O operations. 36   /** An asynchronous UDP socket with devirtualized I/O operations.
37   37  
38   This class template inherits from @ref udp_socket and shadows 38   This class template inherits from @ref udp_socket and shadows
39   the async operations (`send_to`, `recv_from`, `connect`, `send`, 39   the async operations (`send_to`, `recv_from`, `connect`, `send`,
40   `recv`) with versions that call the backend implementation 40   `recv`) with versions that call the backend implementation
41   directly, allowing the compiler to inline through the entire 41   directly, allowing the compiler to inline through the entire
42   call chain. 42   call chain.
43   43  
44   Non-async operations (`open`, `close`, `cancel`, `bind`, 44   Non-async operations (`open`, `close`, `cancel`, `bind`,
45   socket options) remain unchanged and dispatch through the 45   socket options) remain unchanged and dispatch through the
46   compiled library. 46   compiled library.
47   47  
48   A `native_udp_socket` IS-A `udp_socket` and can be passed to 48   A `native_udp_socket` IS-A `udp_socket` and can be passed to
49   any function expecting `udp_socket&`, in which case virtual 49   any function expecting `udp_socket&`, in which case virtual
50   dispatch is used transparently. 50   dispatch is used transparently.
51   51  
52   @tparam Backend A backend tag value (e.g., `epoll`) 52   @tparam Backend A backend tag value (e.g., `epoll`)
53   whose type provides the concrete implementation types. 53   whose type provides the concrete implementation types.
54   54  
55   @par Thread Safety 55   @par Thread Safety
56   Same as @ref udp_socket. 56   Same as @ref udp_socket.
57   57  
58   @par Example 58   @par Example
59   @code 59   @code
60   #include <boost/corosio/native/native_udp_socket.hpp> 60   #include <boost/corosio/native/native_udp_socket.hpp>
61   61  
62   native_io_context<epoll> ctx; 62   native_io_context<epoll> ctx;
63   native_udp_socket<epoll> s(ctx); 63   native_udp_socket<epoll> s(ctx);
64   s.open(); 64   s.open();
65   s.bind(endpoint(ipv4_address::any(), 9000)); 65   s.bind(endpoint(ipv4_address::any(), 9000));
66   char buf[1024]; 66   char buf[1024];
67   endpoint sender; 67   endpoint sender;
68   auto [ec, n] = co_await s.recv_from( 68   auto [ec, n] = co_await s.recv_from(
69   capy::mutable_buffer(buf, sizeof(buf)), sender); 69   capy::mutable_buffer(buf, sizeof(buf)), sender);
70   @endcode 70   @endcode
71   71  
72   @see udp_socket, epoll_t 72   @see udp_socket, epoll_t
73   */ 73   */
74   template<auto Backend> 74   template<auto Backend>
75   class native_udp_socket : public udp_socket 75   class native_udp_socket : public udp_socket
76   { 76   {
77   using backend_type = decltype(Backend); 77   using backend_type = decltype(Backend);
78   using impl_type = typename backend_type::udp_socket_type; 78   using impl_type = typename backend_type::udp_socket_type;
79   using service_type = typename backend_type::udp_service_type; 79   using service_type = typename backend_type::udp_service_type;
80   80  
HITCBC 81   26 impl_type& get_impl() noexcept 81   26 impl_type& get_impl() noexcept
82   { 82   {
HITCBC 83   26 return *static_cast<impl_type*>(h_.get()); 83   26 return *static_cast<impl_type*>(h_.get());
84   } 84   }
85   85  
86   template<class ConstBufferSequence> 86   template<class ConstBufferSequence>
87   struct native_send_to_awaitable 87   struct native_send_to_awaitable
88   { 88   {
89   native_udp_socket& self_; 89   native_udp_socket& self_;
90   ConstBufferSequence buffers_; 90   ConstBufferSequence buffers_;
91   endpoint dest_; 91   endpoint dest_;
92   int flags_; 92   int flags_;
93   std::stop_token token_; 93   std::stop_token token_;
94   mutable std::error_code ec_; 94   mutable std::error_code ec_;
95   mutable std::size_t bytes_transferred_ = 0; 95   mutable std::size_t bytes_transferred_ = 0;
96   96  
HITCBC 97   4 native_send_to_awaitable( 97   4 native_send_to_awaitable(
98   native_udp_socket& self, 98   native_udp_socket& self,
99   ConstBufferSequence buffers, 99   ConstBufferSequence buffers,
100   endpoint dest, 100   endpoint dest,
101   int flags) noexcept 101   int flags) noexcept
HITCBC 102   4 : self_(self) 102   4 : self_(self)
HITCBC 103   4 , buffers_(std::move(buffers)) 103   4 , buffers_(std::move(buffers))
HITCBC 104   4 , dest_(dest) 104   4 , dest_(dest)
HITCBC 105   4 , flags_(flags) 105   4 , flags_(flags)
106   { 106   {
HITCBC 107   4 } 107   4 }
108   108  
HITCBC 109   4 bool await_ready() const noexcept 109   4 bool await_ready() const noexcept
110   { 110   {
HITCBC 111   4 return token_.stop_requested(); 111   4 return token_.stop_requested();
112   } 112   }
113   113  
HITCBC 114   4 capy::io_result<std::size_t> await_resume() const noexcept 114   4 capy::io_result<std::size_t> await_resume() const noexcept
115   { 115   {
HITCBC 116   4 if (token_.stop_requested()) 116   4 if (token_.stop_requested())
MISUBC 117   return {make_error_code(std::errc::operation_canceled), 0}; 117   return {make_error_code(std::errc::operation_canceled), 0};
HITCBC 118   4 return {ec_, bytes_transferred_}; 118   4 return {ec_, bytes_transferred_};
119   } 119   }
120   120  
HITCBC 121   4 auto await_suspend(std::coroutine_handle<> h, capy::io_env const* env) 121   4 auto await_suspend(std::coroutine_handle<> h, capy::io_env const* env)
122   -> std::coroutine_handle<> 122   -> std::coroutine_handle<>
123   { 123   {
HITCBC 124   4 token_ = env->stop_token; 124   4 token_ = env->stop_token;
HITCBC 125   12 return self_.get_impl().send_to( 125   12 return self_.get_impl().send_to(
HITCBC 126   4 h, env->executor, buffers_, dest_, flags_, 126   4 h, env->executor, buffers_, dest_, flags_,
HITCBC 127   12 token_, &ec_, &bytes_transferred_); 127   12 token_, &ec_, &bytes_transferred_);
128   } 128   }
129   }; 129   };
130   130  
131   template<class MutableBufferSequence> 131   template<class MutableBufferSequence>
132   struct native_recv_from_awaitable 132   struct native_recv_from_awaitable
133   { 133   {
134   native_udp_socket& self_; 134   native_udp_socket& self_;
135   MutableBufferSequence buffers_; 135   MutableBufferSequence buffers_;
136   endpoint& source_; 136   endpoint& source_;
137   int flags_; 137   int flags_;
138   std::stop_token token_; 138   std::stop_token token_;
139   mutable std::error_code ec_; 139   mutable std::error_code ec_;
140   mutable std::size_t bytes_transferred_ = 0; 140   mutable std::size_t bytes_transferred_ = 0;
141   141  
HITCBC 142   8 native_recv_from_awaitable( 142   8 native_recv_from_awaitable(
143   native_udp_socket& self, 143   native_udp_socket& self,
144   MutableBufferSequence buffers, 144   MutableBufferSequence buffers,
145   endpoint& source, 145   endpoint& source,
146   int flags) noexcept 146   int flags) noexcept
HITCBC 147   8 : self_(self) 147   8 : self_(self)
HITCBC 148   8 , buffers_(std::move(buffers)) 148   8 , buffers_(std::move(buffers))
HITCBC 149   8 , source_(source) 149   8 , source_(source)
HITCBC 150   8 , flags_(flags) 150   8 , flags_(flags)
151   { 151   {
HITCBC 152   8 } 152   8 }
153   153  
HITCBC 154   8 bool await_ready() const noexcept 154   8 bool await_ready() const noexcept
155   { 155   {
HITCBC 156   8 return token_.stop_requested(); 156   8 return token_.stop_requested();
157   } 157   }
158   158  
HITCBC 159   8 capy::io_result<std::size_t> await_resume() const noexcept 159   8 capy::io_result<std::size_t> await_resume() const noexcept
160   { 160   {
HITCBC 161   8 if (token_.stop_requested()) 161   8 if (token_.stop_requested())
MISUBC 162   return {make_error_code(std::errc::operation_canceled), 0}; 162   return {make_error_code(std::errc::operation_canceled), 0};
HITCBC 163   8 return {ec_, bytes_transferred_}; 163   8 return {ec_, bytes_transferred_};
164   } 164   }
165   165  
HITCBC 166   8 auto await_suspend(std::coroutine_handle<> h, capy::io_env const* env) 166   8 auto await_suspend(std::coroutine_handle<> h, capy::io_env const* env)
167   -> std::coroutine_handle<> 167   -> std::coroutine_handle<>
168   { 168   {
HITCBC 169   8 token_ = env->stop_token; 169   8 token_ = env->stop_token;
HITCBC 170   24 return self_.get_impl().recv_from( 170   24 return self_.get_impl().recv_from(
HITCBC 171   8 h, env->executor, buffers_, &source_, flags_, 171   8 h, env->executor, buffers_, &source_, flags_,
HITCBC 172   24 token_, &ec_, &bytes_transferred_); 172   24 token_, &ec_, &bytes_transferred_);
173   } 173   }
174   }; 174   };
175   175  
176   struct native_wait_awaitable 176   struct native_wait_awaitable
177   { 177   {
178   native_udp_socket& self_; 178   native_udp_socket& self_;
179   wait_type w_; 179   wait_type w_;
180   std::stop_token token_; 180   std::stop_token token_;
181   mutable std::error_code ec_; 181   mutable std::error_code ec_;
182   182  
HITCBC 183   2 native_wait_awaitable(native_udp_socket& self, wait_type w) noexcept 183   2 native_wait_awaitable(native_udp_socket& self, wait_type w) noexcept
HITCBC 184   2 : self_(self) 184   2 : self_(self)
HITCBC 185   2 , w_(w) 185   2 , w_(w)
186   { 186   {
HITCBC 187   2 } 187   2 }
188   188  
HITCBC 189   2 bool await_ready() const noexcept 189   2 bool await_ready() const noexcept
190   { 190   {
HITCBC 191   2 return token_.stop_requested(); 191   2 return token_.stop_requested();
192   } 192   }
193   193  
HITCBC 194   2 capy::io_result<> await_resume() const noexcept 194   2 capy::io_result<> await_resume() const noexcept
195   { 195   {
HITCBC 196   2 if (token_.stop_requested()) 196   2 if (token_.stop_requested())
MISUBC 197   return {make_error_code(std::errc::operation_canceled)}; 197   return {make_error_code(std::errc::operation_canceled)};
HITCBC 198   2 return {ec_}; 198   2 return {ec_};
199   } 199   }
200   200  
HITCBC 201   2 auto await_suspend(std::coroutine_handle<> h, capy::io_env const* env) 201   2 auto await_suspend(std::coroutine_handle<> h, capy::io_env const* env)
202   -> std::coroutine_handle<> 202   -> std::coroutine_handle<>
203   { 203   {
HITCBC 204   2 token_ = env->stop_token; 204   2 token_ = env->stop_token;
HITCBC 205   6 return self_.get_impl().wait( 205   6 return self_.get_impl().wait(
HITCBC 206   6 h, env->executor, w_, token_, &ec_); 206   6 h, env->executor, w_, token_, &ec_);
207   } 207   }
208   }; 208   };
209   209  
210   struct native_connect_awaitable 210   struct native_connect_awaitable
211   { 211   {
212   native_udp_socket& self_; 212   native_udp_socket& self_;
213   endpoint endpoint_; 213   endpoint endpoint_;
214   std::stop_token token_; 214   std::stop_token token_;
215   mutable std::error_code ec_; 215   mutable std::error_code ec_;
216   216  
HITCBC 217   6 native_connect_awaitable(native_udp_socket& self, endpoint ep) noexcept 217   6 native_connect_awaitable(native_udp_socket& self, endpoint ep) noexcept
HITCBC 218   6 : self_(self) 218   6 : self_(self)
HITCBC 219   6 , endpoint_(ep) 219   6 , endpoint_(ep)
220   { 220   {
HITCBC 221   6 } 221   6 }
222   222  
HITCBC 223   6 bool await_ready() const noexcept 223   6 bool await_ready() const noexcept
224   { 224   {
HITCBC 225   6 return token_.stop_requested(); 225   6 return token_.stop_requested();
226   } 226   }
227   227  
HITCBC 228   6 capy::io_result<> await_resume() const noexcept 228   6 capy::io_result<> await_resume() const noexcept
229   { 229   {
HITCBC 230   6 if (token_.stop_requested()) 230   6 if (token_.stop_requested())
MISUBC 231   return {make_error_code(std::errc::operation_canceled)}; 231   return {make_error_code(std::errc::operation_canceled)};
HITCBC 232   6 return {ec_}; 232   6 return {ec_};
233   } 233   }
234   234  
HITCBC 235   6 auto await_suspend(std::coroutine_handle<> h, capy::io_env const* env) 235   6 auto await_suspend(std::coroutine_handle<> h, capy::io_env const* env)
236   -> std::coroutine_handle<> 236   -> std::coroutine_handle<>
237   { 237   {
HITCBC 238   6 token_ = env->stop_token; 238   6 token_ = env->stop_token;
HITCBC 239   18 return self_.get_impl().connect( 239   18 return self_.get_impl().connect(
HITCBC 240   18 h, env->executor, endpoint_, token_, &ec_); 240   18 h, env->executor, endpoint_, token_, &ec_);
241   } 241   }
242   }; 242   };
243   243  
244   template<class ConstBufferSequence> 244   template<class ConstBufferSequence>
245   struct native_send_awaitable 245   struct native_send_awaitable
246   { 246   {
247   native_udp_socket& self_; 247   native_udp_socket& self_;
248   ConstBufferSequence buffers_; 248   ConstBufferSequence buffers_;
249   int flags_; 249   int flags_;
250   std::stop_token token_; 250   std::stop_token token_;
251   mutable std::error_code ec_; 251   mutable std::error_code ec_;
252   mutable std::size_t bytes_transferred_ = 0; 252   mutable std::size_t bytes_transferred_ = 0;
253   253  
HITCBC 254   4 native_send_awaitable( 254   4 native_send_awaitable(
255   native_udp_socket& self, 255   native_udp_socket& self,
256   ConstBufferSequence buffers, 256   ConstBufferSequence buffers,
257   int flags) noexcept 257   int flags) noexcept
HITCBC 258   4 : self_(self) 258   4 : self_(self)
HITCBC 259   4 , buffers_(std::move(buffers)) 259   4 , buffers_(std::move(buffers))
HITCBC 260   4 , flags_(flags) 260   4 , flags_(flags)
261   { 261   {
HITCBC 262   4 } 262   4 }
263   263  
HITCBC 264   4 bool await_ready() const noexcept 264   4 bool await_ready() const noexcept
265   { 265   {
HITCBC 266   4 return token_.stop_requested(); 266   4 return token_.stop_requested();
267   } 267   }
268   268  
HITCBC 269   4 capy::io_result<std::size_t> await_resume() const noexcept 269   4 capy::io_result<std::size_t> await_resume() const noexcept
270   { 270   {
HITCBC 271   4 if (token_.stop_requested()) 271   4 if (token_.stop_requested())
MISUBC 272   return {make_error_code(std::errc::operation_canceled), 0}; 272   return {make_error_code(std::errc::operation_canceled), 0};
HITCBC 273   4 return {ec_, bytes_transferred_}; 273   4 return {ec_, bytes_transferred_};
274   } 274   }
275   275  
HITCBC 276   4 auto await_suspend(std::coroutine_handle<> h, capy::io_env const* env) 276   4 auto await_suspend(std::coroutine_handle<> h, capy::io_env const* env)
277   -> std::coroutine_handle<> 277   -> std::coroutine_handle<>
278   { 278   {
HITCBC 279   4 token_ = env->stop_token; 279   4 token_ = env->stop_token;
HITCBC 280   12 return self_.get_impl().send( 280   12 return self_.get_impl().send(
HITCBC 281   4 h, env->executor, buffers_, flags_, 281   4 h, env->executor, buffers_, flags_,
HITCBC 282   12 token_, &ec_, &bytes_transferred_); 282   12 token_, &ec_, &bytes_transferred_);
283   } 283   }
284   }; 284   };
285   285  
286   template<class MutableBufferSequence> 286   template<class MutableBufferSequence>
287   struct native_recv_awaitable 287   struct native_recv_awaitable
288   { 288   {
289   native_udp_socket& self_; 289   native_udp_socket& self_;
290   MutableBufferSequence buffers_; 290   MutableBufferSequence buffers_;
291   int flags_; 291   int flags_;
292   std::stop_token token_; 292   std::stop_token token_;
293   mutable std::error_code ec_; 293   mutable std::error_code ec_;
294   mutable std::size_t bytes_transferred_ = 0; 294   mutable std::size_t bytes_transferred_ = 0;
295   295  
HITCBC 296   2 native_recv_awaitable( 296   2 native_recv_awaitable(
297   native_udp_socket& self, 297   native_udp_socket& self,
298   MutableBufferSequence buffers, 298   MutableBufferSequence buffers,
299   int flags) noexcept 299   int flags) noexcept
HITCBC 300   2 : self_(self) 300   2 : self_(self)
HITCBC 301   2 , buffers_(std::move(buffers)) 301   2 , buffers_(std::move(buffers))
HITCBC 302   2 , flags_(flags) 302   2 , flags_(flags)
303   { 303   {
HITCBC 304   2 } 304   2 }
305   305  
HITCBC 306   2 bool await_ready() const noexcept 306   2 bool await_ready() const noexcept
307   { 307   {
HITCBC 308   2 return token_.stop_requested(); 308   2 return token_.stop_requested();
309   } 309   }
310   310  
HITCBC 311   2 capy::io_result<std::size_t> await_resume() const noexcept 311   2 capy::io_result<std::size_t> await_resume() const noexcept
312   { 312   {
HITCBC 313   2 if (token_.stop_requested()) 313   2 if (token_.stop_requested())
MISUBC 314   return {make_error_code(std::errc::operation_canceled), 0}; 314   return {make_error_code(std::errc::operation_canceled), 0};
HITCBC 315   2 return {ec_, bytes_transferred_}; 315   2 return {ec_, bytes_transferred_};
316   } 316   }
317   317  
HITCBC 318   2 auto await_suspend(std::coroutine_handle<> h, capy::io_env const* env) 318   2 auto await_suspend(std::coroutine_handle<> h, capy::io_env const* env)
319   -> std::coroutine_handle<> 319   -> std::coroutine_handle<>
320   { 320   {
HITCBC 321   2 token_ = env->stop_token; 321   2 token_ = env->stop_token;
HITCBC 322   6 return self_.get_impl().recv( 322   6 return self_.get_impl().recv(
HITCBC 323   2 h, env->executor, buffers_, flags_, 323   2 h, env->executor, buffers_, flags_,
HITCBC 324   6 token_, &ec_, &bytes_transferred_); 324   6 token_, &ec_, &bytes_transferred_);
325   } 325   }
326   }; 326   };
327   327  
328   public: 328   public:
329   /** Construct a native UDP socket from an execution context. 329   /** Construct a native UDP socket from an execution context.
330   330  
331   @param ctx The execution context that will own this socket. 331   @param ctx The execution context that will own this socket.
332   */ 332   */
HITCBC 333   36 explicit native_udp_socket(capy::execution_context& ctx) 333   36 explicit native_udp_socket(capy::execution_context& ctx)
HITCBC 334   36 : udp_socket(create_handle<service_type>(ctx)) 334   36 : udp_socket(create_handle<service_type>(ctx))
335   { 335   {
HITCBC 336   36 } 336   36 }
337   337  
338   /** Construct a native UDP socket from an executor. 338   /** Construct a native UDP socket from an executor.
339   339  
340   @param ex The executor whose context will own the socket. 340   @param ex The executor whose context will own the socket.
341   */ 341   */
342   template<class Ex> 342   template<class Ex>
343   requires(!std::same_as<std::remove_cvref_t<Ex>, native_udp_socket>) && 343   requires(!std::same_as<std::remove_cvref_t<Ex>, native_udp_socket>) &&
344   capy::Executor<Ex> 344   capy::Executor<Ex>
345   explicit native_udp_socket(Ex const& ex) : native_udp_socket(ex.context()) 345   explicit native_udp_socket(Ex const& ex) : native_udp_socket(ex.context())
346   { 346   {
347   } 347   }
348   348  
349   /// Move construct. 349   /// Move construct.
HITCBC 350   2 native_udp_socket(native_udp_socket&&) noexcept = default; 350   2 native_udp_socket(native_udp_socket&&) noexcept = default;
351   351  
352   /// Move assign. 352   /// Move assign.
353   native_udp_socket& operator=(native_udp_socket&&) noexcept = default; 353   native_udp_socket& operator=(native_udp_socket&&) noexcept = default;
354   354  
355   native_udp_socket(native_udp_socket const&) = delete; 355   native_udp_socket(native_udp_socket const&) = delete;
356   native_udp_socket& operator=(native_udp_socket const&) = delete; 356   native_udp_socket& operator=(native_udp_socket const&) = delete;
357   357  
358   /** Send a datagram to the specified destination. 358   /** Send a datagram to the specified destination.
359   359  
360   Calls the backend implementation directly, bypassing virtual 360   Calls the backend implementation directly, bypassing virtual
361   dispatch. Otherwise identical to @ref udp_socket::send_to. 361   dispatch. Otherwise identical to @ref udp_socket::send_to.
362   362  
363   @param buffers The buffer sequence containing data to send. 363   @param buffers The buffer sequence containing data to send.
364   @param dest The destination endpoint. 364   @param dest The destination endpoint.
365   @param flags Message flags. 365   @param flags Message flags.
366   366  
367   @return An awaitable yielding `(error_code, std::size_t)`. 367   @return An awaitable yielding `(error_code, std::size_t)`.
368   */ 368   */
369   template<capy::ConstBufferSequence CB> 369   template<capy::ConstBufferSequence CB>
HITCBC 370   4 auto send_to( 370   4 auto send_to(
371   CB const& buffers, 371   CB const& buffers,
372   endpoint dest, 372   endpoint dest,
373   corosio::message_flags flags) 373   corosio::message_flags flags)
374   { 374   {
HITCBC 375   4 if (!is_open()) 375   4 if (!is_open())
MISUBC 376   detail::throw_logic_error("send_to: socket not open"); 376   detail::throw_logic_error("send_to: socket not open");
377   return native_send_to_awaitable<CB>( 377   return native_send_to_awaitable<CB>(
HITCBC 378   4 *this, buffers, dest, static_cast<int>(flags)); 378   4 *this, buffers, dest, static_cast<int>(flags));
379   } 379   }
380   380  
381   /// @overload 381   /// @overload
382   template<capy::ConstBufferSequence CB> 382   template<capy::ConstBufferSequence CB>
HITCBC 383   4 auto send_to(CB const& buffers, endpoint dest) 383   4 auto send_to(CB const& buffers, endpoint dest)
384   { 384   {
HITCBC 385   4 return send_to(buffers, dest, corosio::message_flags::none); 385   4 return send_to(buffers, dest, corosio::message_flags::none);
386   } 386   }
387   387  
388   /** Receive a datagram and capture the sender's endpoint. 388   /** Receive a datagram and capture the sender's endpoint.
389   389  
390   Calls the backend implementation directly, bypassing virtual 390   Calls the backend implementation directly, bypassing virtual
391   dispatch. Otherwise identical to @ref udp_socket::recv_from. 391   dispatch. Otherwise identical to @ref udp_socket::recv_from.
392   392  
393   @param buffers The buffer sequence to receive data into. 393   @param buffers The buffer sequence to receive data into.
394   @param source Reference to an endpoint that will be set to 394   @param source Reference to an endpoint that will be set to
395   the sender's address on successful completion. 395   the sender's address on successful completion.
396   @param flags Message flags (e.g. message_flags::peek). 396   @param flags Message flags (e.g. message_flags::peek).
397   397  
398   @return An awaitable yielding `(error_code, std::size_t)`. 398   @return An awaitable yielding `(error_code, std::size_t)`.
399   */ 399   */
400   template<capy::MutableBufferSequence MB> 400   template<capy::MutableBufferSequence MB>
HITCBC 401   8 auto recv_from( 401   8 auto recv_from(
402   MB const& buffers, 402   MB const& buffers,
403   endpoint& source, 403   endpoint& source,
404   corosio::message_flags flags) 404   corosio::message_flags flags)
405   { 405   {
HITCBC 406   8 if (!is_open()) 406   8 if (!is_open())
MISUBC 407   detail::throw_logic_error("recv_from: socket not open"); 407   detail::throw_logic_error("recv_from: socket not open");
408   return native_recv_from_awaitable<MB>( 408   return native_recv_from_awaitable<MB>(
HITCBC 409   8 *this, buffers, source, static_cast<int>(flags)); 409   8 *this, buffers, source, static_cast<int>(flags));
410   } 410   }
411   411  
412   /// @overload 412   /// @overload
413   template<capy::MutableBufferSequence MB> 413   template<capy::MutableBufferSequence MB>
HITCBC 414   8 auto recv_from(MB const& buffers, endpoint& source) 414   8 auto recv_from(MB const& buffers, endpoint& source)
415   { 415   {
HITCBC 416   8 return recv_from(buffers, source, corosio::message_flags::none); 416   8 return recv_from(buffers, source, corosio::message_flags::none);
417   } 417   }
418   418  
419   /** Asynchronously connect to set the default peer. 419   /** Asynchronously connect to set the default peer.
420   420  
421   Calls the backend implementation directly, bypassing virtual 421   Calls the backend implementation directly, bypassing virtual
422   dispatch. Otherwise identical to @ref udp_socket::connect. 422   dispatch. Otherwise identical to @ref udp_socket::connect.
423   423  
424   If the socket is not already open, it is opened automatically 424   If the socket is not already open, it is opened automatically
425   using the address family of @p ep. 425   using the address family of @p ep.
426   426  
427   @param ep The remote endpoint to connect to. 427   @param ep The remote endpoint to connect to.
428   428  
429   @return An awaitable yielding `io_result<>`. 429   @return An awaitable yielding `io_result<>`.
430   430  
431   @throws std::system_error if the socket needs to be opened 431   @throws std::system_error if the socket needs to be opened
432   and the open fails. 432   and the open fails.
433   */ 433   */
HITCBC 434   6 auto connect(endpoint ep) 434   6 auto connect(endpoint ep)
435   { 435   {
HITCBC 436   6 if (!is_open()) 436   6 if (!is_open())
HITCBC 437   4 open(ep.is_v6() ? udp::v6() : udp::v4()); 437   4 open(ep.is_v6() ? udp::v6() : udp::v4());
HITCBC 438   6 return native_connect_awaitable(*this, ep); 438   6 return native_connect_awaitable(*this, ep);
439   } 439   }
440   440  
441   /** Send a datagram to the connected peer. 441   /** Send a datagram to the connected peer.
442   442  
443   Calls the backend implementation directly, bypassing virtual 443   Calls the backend implementation directly, bypassing virtual
444   dispatch. Otherwise identical to @ref udp_socket::send. 444   dispatch. Otherwise identical to @ref udp_socket::send.
445   445  
446   @param buffers The buffer sequence containing data to send. 446   @param buffers The buffer sequence containing data to send.
447   @param flags Message flags. 447   @param flags Message flags.
448   448  
449   @return An awaitable yielding `(error_code, std::size_t)`. 449   @return An awaitable yielding `(error_code, std::size_t)`.
450   450  
451   @throws std::logic_error if the socket is not open. 451   @throws std::logic_error if the socket is not open.
452   */ 452   */
453   template<capy::ConstBufferSequence CB> 453   template<capy::ConstBufferSequence CB>
HITCBC 454   4 auto send(CB const& buffers, corosio::message_flags flags) 454   4 auto send(CB const& buffers, corosio::message_flags flags)
455   { 455   {
HITCBC 456   4 if (!is_open()) 456   4 if (!is_open())
MISUBC 457   detail::throw_logic_error("send: socket not open"); 457   detail::throw_logic_error("send: socket not open");
458   return native_send_awaitable<CB>( 458   return native_send_awaitable<CB>(
HITCBC 459   4 *this, buffers, static_cast<int>(flags)); 459   4 *this, buffers, static_cast<int>(flags));
460   } 460   }
461   461  
462   /// @overload 462   /// @overload
463   template<capy::ConstBufferSequence CB> 463   template<capy::ConstBufferSequence CB>
HITCBC 464   4 auto send(CB const& buffers) 464   4 auto send(CB const& buffers)
465   { 465   {
HITCBC 466   4 return send(buffers, corosio::message_flags::none); 466   4 return send(buffers, corosio::message_flags::none);
467   } 467   }
468   468  
469   /** Receive a datagram from the connected peer. 469   /** Receive a datagram from the connected peer.
470   470  
471   Calls the backend implementation directly, bypassing virtual 471   Calls the backend implementation directly, bypassing virtual
472   dispatch. Otherwise identical to @ref udp_socket::recv. 472   dispatch. Otherwise identical to @ref udp_socket::recv.
473   473  
474   @param buffers The buffer sequence to receive data into. 474   @param buffers The buffer sequence to receive data into.
475   @param flags Message flags (e.g. message_flags::peek). 475   @param flags Message flags (e.g. message_flags::peek).
476   476  
477   @return An awaitable yielding `(error_code, std::size_t)`. 477   @return An awaitable yielding `(error_code, std::size_t)`.
478   478  
479   @throws std::logic_error if the socket is not open. 479   @throws std::logic_error if the socket is not open.
480   */ 480   */
481   template<capy::MutableBufferSequence MB> 481   template<capy::MutableBufferSequence MB>
HITCBC 482   2 auto recv(MB const& buffers, corosio::message_flags flags) 482   2 auto recv(MB const& buffers, corosio::message_flags flags)
483   { 483   {
HITCBC 484   2 if (!is_open()) 484   2 if (!is_open())
MISUBC 485   detail::throw_logic_error("recv: socket not open"); 485   detail::throw_logic_error("recv: socket not open");
486   return native_recv_awaitable<MB>( 486   return native_recv_awaitable<MB>(
HITCBC 487   2 *this, buffers, static_cast<int>(flags)); 487   2 *this, buffers, static_cast<int>(flags));
488   } 488   }
489   489  
490   /// @overload 490   /// @overload
491   template<capy::MutableBufferSequence MB> 491   template<capy::MutableBufferSequence MB>
HITCBC 492   2 auto recv(MB const& buffers) 492   2 auto recv(MB const& buffers)
493   { 493   {
HITCBC 494   2 return recv(buffers, corosio::message_flags::none); 494   2 return recv(buffers, corosio::message_flags::none);
495   } 495   }
496   496  
497   /** Asynchronously wait for the socket to be ready. 497   /** Asynchronously wait for the socket to be ready.
498   498  
499   Calls the backend implementation directly, bypassing virtual 499   Calls the backend implementation directly, bypassing virtual
500   dispatch. Otherwise identical to @ref udp_socket::wait. 500   dispatch. Otherwise identical to @ref udp_socket::wait.
501   501  
502   @param w The wait direction (read, write, or error). 502   @param w The wait direction (read, write, or error).
503   503  
504   @return An awaitable yielding `io_result<>`. 504   @return An awaitable yielding `io_result<>`.
505   */ 505   */
HITCBC 506   2 [[nodiscard]] auto wait(wait_type w) 506   2 [[nodiscard]] auto wait(wait_type w)
507   { 507   {
HITCBC 508   2 return native_wait_awaitable(*this, w); 508   2 return native_wait_awaitable(*this, w);
509   } 509   }
510   }; 510   };
511   511  
512   } // namespace boost::corosio 512   } // namespace boost::corosio
513   513  
514   #endif // BOOST_COROSIO_NATIVE_NATIVE_UDP_SOCKET_HPP 514   #endif // BOOST_COROSIO_NATIVE_NATIVE_UDP_SOCKET_HPP