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