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