100.00% Lines (93/93) 100.00% Functions (25/25)
TLA Baseline Branch
Line Hits Code Line Hits Code
1   // 1   //
2   // Copyright (c) 2026 Steve Gerbino 2   // Copyright (c) 2026 Steve Gerbino
3   // Copyright (c) 2026 Michael Vandeberg 3   // Copyright (c) 2026 Michael Vandeberg
4   // 4   //
5   // Distributed under the Boost Software License, Version 1.0. (See accompanying 5   // Distributed under the Boost Software License, Version 1.0. (See accompanying
6   // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 6   // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
7   // 7   //
8   // Official repository: https://github.com/cppalliance/corosio 8   // Official repository: https://github.com/cppalliance/corosio
9   // 9   //
10   10  
11   #ifndef BOOST_COROSIO_NATIVE_NATIVE_UDP_SOCKET_HPP 11   #ifndef BOOST_COROSIO_NATIVE_NATIVE_UDP_SOCKET_HPP
12   #define BOOST_COROSIO_NATIVE_NATIVE_UDP_SOCKET_HPP 12   #define BOOST_COROSIO_NATIVE_NATIVE_UDP_SOCKET_HPP
13   13  
14   #include <boost/corosio/udp_socket.hpp> 14   #include <boost/corosio/udp_socket.hpp>
15   #include <boost/corosio/backend.hpp> 15   #include <boost/corosio/backend.hpp>
16   #include <boost/corosio/detail/op_base.hpp> 16   #include <boost/corosio/detail/op_base.hpp>
17   17  
18   #ifndef BOOST_COROSIO_MRDOCS 18   #ifndef BOOST_COROSIO_MRDOCS
19   #if BOOST_COROSIO_HAS_EPOLL 19   #if BOOST_COROSIO_HAS_EPOLL
20   #include <boost/corosio/native/detail/epoll/epoll_types.hpp> 20   #include <boost/corosio/native/detail/epoll/epoll_types.hpp>
21   #endif 21   #endif
22   22  
23   #if BOOST_COROSIO_HAS_SELECT 23   #if BOOST_COROSIO_HAS_SELECT
24   #include <boost/corosio/native/detail/select/select_types.hpp> 24   #include <boost/corosio/native/detail/select/select_types.hpp>
25   #endif 25   #endif
26   26  
27   #if BOOST_COROSIO_HAS_KQUEUE 27   #if BOOST_COROSIO_HAS_KQUEUE
28   #include <boost/corosio/native/detail/kqueue/kqueue_types.hpp> 28   #include <boost/corosio/native/detail/kqueue/kqueue_types.hpp>
29   #endif 29   #endif
30   30  
31   #if BOOST_COROSIO_HAS_URING 31   #if BOOST_COROSIO_HAS_URING
32   #include <boost/corosio/native/detail/uring/uring_types.hpp> 32   #include <boost/corosio/native/detail/uring/uring_types.hpp>
33   #endif 33   #endif
34   34  
35   #if BOOST_COROSIO_HAS_IOCP 35   #if BOOST_COROSIO_HAS_IOCP
36   #include <boost/corosio/native/detail/iocp/win_udp_service.hpp> 36   #include <boost/corosio/native/detail/iocp/win_udp_service.hpp>
37   #endif 37   #endif
38   #endif // !BOOST_COROSIO_MRDOCS 38   #endif // !BOOST_COROSIO_MRDOCS
39   39  
40   namespace boost::corosio { 40   namespace boost::corosio {
41   41  
42   /** Sends and receives UDP datagrams, calling the backend directly. 42   /** Sends and receives UDP datagrams, calling the backend directly.
43   43  
44   This class template inherits from @ref udp_socket. It shadows the 44   This class template inherits from @ref udp_socket. It shadows the
45   async operations (`send_to`, `recv_from`, `connect`, `send`, `recv`) 45   async operations (`send_to`, `recv_from`, `connect`, `send`, `recv`)
46   with versions that call the backend implementation directly. The 46   with versions that call the backend implementation directly. The
47   compiler can then inline through the entire call chain. 47   compiler can then inline through the entire call chain.
48   48  
49   Non-async operations (`open`, `close`, `cancel`, `bind`, 49   Non-async operations (`open`, `close`, `cancel`, `bind`,
50   socket options) remain unchanged and dispatch through the 50   socket options) remain unchanged and dispatch through the
51   compiled library. 51   compiled library.
52   52  
53   A `native_udp_socket` IS-A `udp_socket` and can be passed to 53   A `native_udp_socket` IS-A `udp_socket` and can be passed to
54   any function expecting `udp_socket&`, in which case virtual 54   any function expecting `udp_socket&`, in which case virtual
55   dispatch is used transparently. 55   dispatch is used transparently.
56   56  
57   @tparam Backend A backend tag value (e.g., `epoll`) 57   @tparam Backend A backend tag value (e.g., `epoll`)
58   whose type provides the concrete implementation types. 58   whose type provides the concrete implementation types.
59   59  
60   @par Thread Safety 60   @par Thread Safety
61   Same as @ref udp_socket. 61   Same as @ref udp_socket.
62   62  
63   @par Example 63   @par Example
64   @par !example native_udp_socket 64   @par !example native_udp_socket
65   65  
66   @see udp_socket, epoll_t 66   @see udp_socket, epoll_t
67   */ 67   */
68   template<auto Backend> 68   template<auto Backend>
69   class native_udp_socket : public udp_socket 69   class native_udp_socket : public udp_socket
70   { 70   {
71   using backend_type = decltype(Backend); 71   using backend_type = decltype(Backend);
72   using impl_type = typename backend_type::udp_socket_type; 72   using impl_type = typename backend_type::udp_socket_type;
73   using service_type = typename backend_type::udp_service_type; 73   using service_type = typename backend_type::udp_service_type;
74   74  
HITCBC 75   28 impl_type& get_impl() noexcept 75   28 impl_type& get_impl() noexcept
76   { 76   {
HITCBC 77   28 return *static_cast<impl_type*>(h_.get()); 77   28 return *static_cast<impl_type*>(h_.get());
78   } 78   }
79   79  
80   template<class ConstBufferSequence> 80   template<class ConstBufferSequence>
81   struct native_send_to_awaitable 81   struct native_send_to_awaitable
82   : detail::bytes_op_base<native_send_to_awaitable<ConstBufferSequence>> 82   : detail::bytes_op_base<native_send_to_awaitable<ConstBufferSequence>>
83   { 83   {
84   native_udp_socket& self_; 84   native_udp_socket& self_;
85   ConstBufferSequence buffers_; 85   ConstBufferSequence buffers_;
86   endpoint dest_; 86   endpoint dest_;
87   int flags_; 87   int flags_;
88   88  
HITCBC 89   8 native_send_to_awaitable( 89   8 native_send_to_awaitable(
90   native_udp_socket& self, 90   native_udp_socket& self,
91   ConstBufferSequence buffers, 91   ConstBufferSequence buffers,
92   endpoint dest, 92   endpoint dest,
93   int flags) noexcept 93   int flags) noexcept
HITCBC 94   8 : self_(self) 94   8 : self_(self)
HITCBC 95   8 , buffers_(std::move(buffers)) 95   8 , buffers_(std::move(buffers))
HITCBC 96   8 , dest_(dest) 96   8 , dest_(dest)
HITCBC 97   8 , flags_(flags) 97   8 , flags_(flags)
98   { 98   {
HITCBC 99   8 } 99   8 }
100   100  
101   std::coroutine_handle<> 101   std::coroutine_handle<>
HITCBC 102   4 dispatch(capy::continuation& cont, capy::executor_ref ex) const 102   4 dispatch(capy::continuation& cont, capy::executor_ref ex) const
103   { 103   {
HITCBC 104   12 return self_.get_impl().send_to( 104   12 return self_.get_impl().send_to(
HITCBC 105   4 cont, ex, buffers_, dest_, flags_, this->token_, &this->ec_, 105   4 cont, ex, buffers_, dest_, flags_, this->token_, &this->ec_,
HITCBC 106   8 &this->bytes_); 106   8 &this->bytes_);
107   } 107   }
108   }; 108   };
109   109  
110   template<class MutableBufferSequence> 110   template<class MutableBufferSequence>
111   struct native_recv_from_awaitable 111   struct native_recv_from_awaitable
112   : detail::bytes_op_base< 112   : detail::bytes_op_base<
113   native_recv_from_awaitable<MutableBufferSequence>> 113   native_recv_from_awaitable<MutableBufferSequence>>
114   { 114   {
115   native_udp_socket& self_; 115   native_udp_socket& self_;
116   MutableBufferSequence buffers_; 116   MutableBufferSequence buffers_;
117   endpoint& source_; 117   endpoint& source_;
118   int flags_; 118   int flags_;
119   119  
HITCBC 120   12 native_recv_from_awaitable( 120   12 native_recv_from_awaitable(
121   native_udp_socket& self, 121   native_udp_socket& self,
122   MutableBufferSequence buffers, 122   MutableBufferSequence buffers,
123   endpoint& source, 123   endpoint& source,
124   int flags) noexcept 124   int flags) noexcept
HITCBC 125   12 : self_(self) 125   12 : self_(self)
HITCBC 126   12 , buffers_(std::move(buffers)) 126   12 , buffers_(std::move(buffers))
HITCBC 127   12 , source_(source) 127   12 , source_(source)
HITCBC 128   12 , flags_(flags) 128   12 , flags_(flags)
129   { 129   {
HITCBC 130   12 } 130   12 }
131   131  
132   std::coroutine_handle<> 132   std::coroutine_handle<>
HITCBC 133   8 dispatch(capy::continuation& cont, capy::executor_ref ex) const 133   8 dispatch(capy::continuation& cont, capy::executor_ref ex) const
134   { 134   {
HITCBC 135   24 return self_.get_impl().recv_from( 135   24 return self_.get_impl().recv_from(
HITCBC 136   8 cont, ex, buffers_, &source_, flags_, this->token_, &this->ec_, 136   8 cont, ex, buffers_, &source_, flags_, this->token_, &this->ec_,
HITCBC 137   16 &this->bytes_); 137   16 &this->bytes_);
138   } 138   }
139   }; 139   };
140   140  
141   struct native_wait_awaitable : detail::void_op_base<native_wait_awaitable> 141   struct native_wait_awaitable : detail::void_op_base<native_wait_awaitable>
142   { 142   {
143   native_udp_socket& self_; 143   native_udp_socket& self_;
144   wait_type w_; 144   wait_type w_;
145   145  
HITCBC 146   4 native_wait_awaitable(native_udp_socket& self, wait_type w) noexcept 146   4 native_wait_awaitable(native_udp_socket& self, wait_type w) noexcept
HITCBC 147   4 : self_(self) 147   4 : self_(self)
HITCBC 148   4 , w_(w) 148   4 , w_(w)
149   { 149   {
HITCBC 150   4 } 150   4 }
151   151  
152   std::coroutine_handle<> 152   std::coroutine_handle<>
HITCBC 153   2 dispatch(capy::continuation& cont, capy::executor_ref ex) const 153   2 dispatch(capy::continuation& cont, capy::executor_ref ex) const
154   { 154   {
HITCBC 155   4 return self_.get_impl().wait( 155   4 return self_.get_impl().wait(
HITCBC 156   4 cont, ex, w_, this->token_, &this->ec_); 156   4 cont, ex, w_, this->token_, &this->ec_);
157   } 157   }
158   }; 158   };
159   159  
160   struct native_connect_awaitable 160   struct native_connect_awaitable
161   : detail::void_op_base<native_connect_awaitable> 161   : detail::void_op_base<native_connect_awaitable>
162   { 162   {
163   native_udp_socket& self_; 163   native_udp_socket& self_;
164   endpoint endpoint_; 164   endpoint endpoint_;
165   165  
HITCBC 166   10 native_connect_awaitable(native_udp_socket& self, endpoint ep) noexcept 166   10 native_connect_awaitable(native_udp_socket& self, endpoint ep) noexcept
HITCBC 167   10 : self_(self) 167   10 : self_(self)
HITCBC 168   10 , endpoint_(ep) 168   10 , endpoint_(ep)
169   { 169   {
HITCBC 170   10 } 170   10 }
171   171  
172   std::coroutine_handle<> 172   std::coroutine_handle<>
HITCBC 173   8 dispatch(capy::continuation& cont, capy::executor_ref ex) const 173   8 dispatch(capy::continuation& cont, capy::executor_ref ex) const
174   { 174   {
HITCBC 175   24 return self_.get_impl().connect( 175   24 return self_.get_impl().connect(
HITCBC 176   24 cont, ex, endpoint_, this->token_, &this->ec_); 176   24 cont, ex, endpoint_, this->token_, &this->ec_);
177   } 177   }
178   }; 178   };
179   179  
180   template<class ConstBufferSequence> 180   template<class ConstBufferSequence>
181   struct native_send_awaitable 181   struct native_send_awaitable
182   : detail::bytes_op_base<native_send_awaitable<ConstBufferSequence>> 182   : detail::bytes_op_base<native_send_awaitable<ConstBufferSequence>>
183   { 183   {
184   native_udp_socket& self_; 184   native_udp_socket& self_;
185   ConstBufferSequence buffers_; 185   ConstBufferSequence buffers_;
186   int flags_; 186   int flags_;
187   187  
HITCBC 188   8 native_send_awaitable( 188   8 native_send_awaitable(
189   native_udp_socket& self, 189   native_udp_socket& self,
190   ConstBufferSequence buffers, 190   ConstBufferSequence buffers,
191   int flags) noexcept 191   int flags) noexcept
HITCBC 192   8 : self_(self) 192   8 : self_(self)
HITCBC 193   8 , buffers_(std::move(buffers)) 193   8 , buffers_(std::move(buffers))
HITCBC 194   8 , flags_(flags) 194   8 , flags_(flags)
195   { 195   {
HITCBC 196   8 } 196   8 }
197   197  
198   std::coroutine_handle<> 198   std::coroutine_handle<>
HITCBC 199   4 dispatch(capy::continuation& cont, capy::executor_ref ex) const 199   4 dispatch(capy::continuation& cont, capy::executor_ref ex) const
200   { 200   {
HITCBC 201   12 return self_.get_impl().send( 201   12 return self_.get_impl().send(
HITCBC 202   4 cont, ex, buffers_, flags_, this->token_, &this->ec_, 202   4 cont, ex, buffers_, flags_, this->token_, &this->ec_,
HITCBC 203   8 &this->bytes_); 203   8 &this->bytes_);
204   } 204   }
205   }; 205   };
206   206  
207   template<class MutableBufferSequence> 207   template<class MutableBufferSequence>
208   struct native_recv_awaitable 208   struct native_recv_awaitable
209   : detail::bytes_op_base<native_recv_awaitable<MutableBufferSequence>> 209   : detail::bytes_op_base<native_recv_awaitable<MutableBufferSequence>>
210   { 210   {
211   native_udp_socket& self_; 211   native_udp_socket& self_;
212   MutableBufferSequence buffers_; 212   MutableBufferSequence buffers_;
213   int flags_; 213   int flags_;
214   214  
HITCBC 215   6 native_recv_awaitable( 215   6 native_recv_awaitable(
216   native_udp_socket& self, 216   native_udp_socket& self,
217   MutableBufferSequence buffers, 217   MutableBufferSequence buffers,
218   int flags) noexcept 218   int flags) noexcept
HITCBC 219   6 : self_(self) 219   6 : self_(self)
HITCBC 220   6 , buffers_(std::move(buffers)) 220   6 , buffers_(std::move(buffers))
HITCBC 221   6 , flags_(flags) 221   6 , flags_(flags)
222   { 222   {
HITCBC 223   6 } 223   6 }
224   224  
225   std::coroutine_handle<> 225   std::coroutine_handle<>
HITCBC 226   2 dispatch(capy::continuation& cont, capy::executor_ref ex) const 226   2 dispatch(capy::continuation& cont, capy::executor_ref ex) const
227   { 227   {
HITCBC 228   6 return self_.get_impl().recv( 228   6 return self_.get_impl().recv(
HITCBC 229   2 cont, ex, buffers_, flags_, this->token_, &this->ec_, 229   2 cont, ex, buffers_, flags_, this->token_, &this->ec_,
HITCBC 230   4 &this->bytes_); 230   4 &this->bytes_);
231   } 231   }
232   }; 232   };
233   233  
234   public: 234   public:
235   /** Construct a native UDP socket from an execution context. 235   /** Construct a native UDP socket from an execution context.
236   236  
237   @param ctx The execution context that owns this socket. 237   @param ctx The execution context that owns this socket.
238   */ 238   */
HITCBC 239   42 explicit native_udp_socket(capy::execution_context& ctx) 239   42 explicit native_udp_socket(capy::execution_context& ctx)
HITCBC 240   42 : udp_socket(handle(ctx, ctx.use_service<service_type>())) 240   42 : udp_socket(handle(ctx, ctx.use_service<service_type>()))
241   { 241   {
HITCBC 242   42 } 242   42 }
243   243  
244   /** Construct a native UDP socket from an executor. 244   /** Construct a native UDP socket from an executor.
245   245  
246   @param ex The executor whose context owns the socket. 246   @param ex The executor whose context owns the socket.
247   247  
248   @tparam Ex A type satisfying @ref capy::Executor. Must not 248   @tparam Ex A type satisfying @ref capy::Executor. Must not
249   be `native_udp_socket` itself (disables implicit 249   be `native_udp_socket` itself (disables implicit
250   conversion from move). 250   conversion from move).
251   */ 251   */
252   template<class Ex> 252   template<class Ex>
253   requires(!std::same_as<std::remove_cvref_t<Ex>, native_udp_socket>) && 253   requires(!std::same_as<std::remove_cvref_t<Ex>, native_udp_socket>) &&
254   capy::Executor<Ex> 254   capy::Executor<Ex>
255   explicit native_udp_socket(Ex const& ex) : native_udp_socket(ex.context()) 255   explicit native_udp_socket(Ex const& ex) : native_udp_socket(ex.context())
256   { 256   {
257   } 257   }
258   258  
259   /** Move construct. 259   /** Move construct.
260   260  
261   @param other The socket to move from. 261   @param other The socket to move from.
262   262  
263   @pre No awaitables returned by @p other's methods exist. 263   @pre No awaitables returned by @p other's methods exist.
264   @pre The execution context associated with @p other must 264   @pre The execution context associated with @p other must
265   outlive this socket. 265   outlive this socket.
266   */ 266   */
HITCBC 267   2 native_udp_socket(native_udp_socket&&) noexcept = default; 267   2 native_udp_socket(native_udp_socket&&) noexcept = default;
268   268  
269   /** Move assign. 269   /** Move assign.
270   270  
271   @param other The socket to move from. 271   @param other The socket to move from.
272   272  
273   @pre No awaitables returned by either `*this` or @p other's 273   @pre No awaitables returned by either `*this` or @p other's
274   methods exist. 274   methods exist.
275   @pre The execution context associated with @p other must 275   @pre The execution context associated with @p other must
276   outlive this socket. 276   outlive this socket.
277   */ 277   */
278   native_udp_socket& operator=(native_udp_socket&&) noexcept = default; 278   native_udp_socket& operator=(native_udp_socket&&) noexcept = default;
279   279  
280   /// Copy construction is disabled; the handle is uniquely owned. 280   /// Copy construction is disabled; the handle is uniquely owned.
281   native_udp_socket(native_udp_socket const&) = delete; 281   native_udp_socket(native_udp_socket const&) = delete;
282   /// Copy assignment is disabled; the handle is uniquely owned. 282   /// Copy assignment is disabled; the handle is uniquely owned.
283   native_udp_socket& operator=(native_udp_socket const&) = delete; 283   native_udp_socket& operator=(native_udp_socket const&) = delete;
284   284  
285   /** Send a datagram to the specified destination. 285   /** Send a datagram to the specified destination.
286   286  
287   Calls the backend implementation directly, bypassing virtual 287   Calls the backend implementation directly, bypassing virtual
288   dispatch. Otherwise identical to @ref udp_socket::send_to. 288   dispatch. Otherwise identical to @ref udp_socket::send_to.
289   289  
290   @param buffers The buffer sequence containing data to send. 290   @param buffers The buffer sequence containing data to send.
291   @param dest The destination endpoint. 291   @param dest The destination endpoint.
292   @param flags Message flags. 292   @param flags Message flags.
293   293  
294   @return An awaitable yielding `(error_code, std::size_t)`. 294   @return An awaitable yielding `(error_code, std::size_t)`.
295   295  
296   A closed socket reports `errc::bad_file_descriptor`. 296   A closed socket reports `errc::bad_file_descriptor`.
297   */ 297   */
298   template<capy::ConstBufferSequence CB> 298   template<capy::ConstBufferSequence CB>
299   [[nodiscard]] auto 299   [[nodiscard]] auto
HITCBC 300   8 send_to(CB const& buffers, endpoint dest, corosio::message_flags flags) 300   8 send_to(CB const& buffers, endpoint dest, corosio::message_flags flags)
301   { 301   {
HITCBC 302   8 native_send_to_awaitable<CB> aw( 302   8 native_send_to_awaitable<CB> aw(
303   *this, buffers, dest, static_cast<int>(flags)); 303   *this, buffers, dest, static_cast<int>(flags));
HITCBC 304   8 if (!is_open()) 304   8 if (!is_open())
HITCBC 305   2 aw.ec_ = make_error_code(std::errc::bad_file_descriptor); 305   2 aw.ec_ = make_error_code(std::errc::bad_file_descriptor);
HITCBC 306   8 return aw; 306   8 return aw;
307   } 307   }
308   308  
309   /// @overload 309   /// @overload
310   template<capy::ConstBufferSequence CB> 310   template<capy::ConstBufferSequence CB>
HITCBC 311   8 [[nodiscard]] auto send_to(CB const& buffers, endpoint dest) 311   8 [[nodiscard]] auto send_to(CB const& buffers, endpoint dest)
312   { 312   {
HITCBC 313   8 return send_to(buffers, dest, corosio::message_flags::none); 313   8 return send_to(buffers, dest, corosio::message_flags::none);
314   } 314   }
315   315  
316   /** Receive a datagram and capture the sender's endpoint. 316   /** Receive a datagram and capture the sender's endpoint.
317   317  
318   Calls the backend implementation directly, bypassing virtual 318   Calls the backend implementation directly, bypassing virtual
319   dispatch. Otherwise identical to @ref udp_socket::recv_from. 319   dispatch. Otherwise identical to @ref udp_socket::recv_from.
320   320  
321   @param buffers The buffer sequence to receive data into. 321   @param buffers The buffer sequence to receive data into.
322   @param source Reference to an endpoint that receives 322   @param source Reference to an endpoint that receives
323   the sender's address on successful completion. 323   the sender's address on successful completion.
324   @param flags Message flags (e.g. message_flags::peek). 324   @param flags Message flags (e.g. message_flags::peek).
325   325  
326   @return An awaitable yielding `(error_code, std::size_t)`. 326   @return An awaitable yielding `(error_code, std::size_t)`.
327   327  
328   A closed socket reports `errc::bad_file_descriptor`. 328   A closed socket reports `errc::bad_file_descriptor`.
329   */ 329   */
330   template<capy::MutableBufferSequence MB> 330   template<capy::MutableBufferSequence MB>
331   [[nodiscard]] auto 331   [[nodiscard]] auto
HITCBC 332   12 recv_from(MB const& buffers, endpoint& source, corosio::message_flags flags) 332   12 recv_from(MB const& buffers, endpoint& source, corosio::message_flags flags)
333   { 333   {
HITCBC 334   12 native_recv_from_awaitable<MB> aw( 334   12 native_recv_from_awaitable<MB> aw(
335   *this, buffers, source, static_cast<int>(flags)); 335   *this, buffers, source, static_cast<int>(flags));
HITCBC 336   12 if (!is_open()) 336   12 if (!is_open())
HITCBC 337   2 aw.ec_ = make_error_code(std::errc::bad_file_descriptor); 337   2 aw.ec_ = make_error_code(std::errc::bad_file_descriptor);
HITCBC 338   12 return aw; 338   12 return aw;
339   } 339   }
340   340  
341   /// @overload 341   /// @overload
342   template<capy::MutableBufferSequence MB> 342   template<capy::MutableBufferSequence MB>
HITCBC 343   12 [[nodiscard]] auto recv_from(MB const& buffers, endpoint& source) 343   12 [[nodiscard]] auto recv_from(MB const& buffers, endpoint& source)
344   { 344   {
HITCBC 345   12 return recv_from(buffers, source, corosio::message_flags::none); 345   12 return recv_from(buffers, source, corosio::message_flags::none);
346   } 346   }
347   347  
348   /** Asynchronously connect to set the default peer. 348   /** Asynchronously connect to set the default peer.
349   349  
350   Calls the backend implementation directly, bypassing virtual 350   Calls the backend implementation directly, bypassing virtual
351   dispatch. Otherwise identical to @ref udp_socket::connect. 351   dispatch. Otherwise identical to @ref udp_socket::connect.
352   352  
353   If the socket is not already open, it is opened automatically 353   If the socket is not already open, it is opened automatically
354   using the address family of @p ep. 354   using the address family of @p ep.
355   355  
356   @param ep The remote endpoint to connect to. 356   @param ep The remote endpoint to connect to.
357   357  
358   @return An awaitable yielding `results<>`. 358   @return An awaitable yielding `results<>`.
359   359  
360   If the socket needs to be opened and the open fails, the 360   If the socket needs to be opened and the open fails, the
361   awaitable completes immediately with that error. 361   awaitable completes immediately with that error.
362   */ 362   */
HITCBC 363   10 [[nodiscard]] auto connect(endpoint ep) 363   10 [[nodiscard]] auto connect(endpoint ep)
364   { 364   {
HITCBC 365   10 native_connect_awaitable aw(*this, ep); 365   10 native_connect_awaitable aw(*this, ep);
HITCBC 366   10 if (!is_open()) 366   10 if (!is_open())
HITCBC 367   4 aw.ec_ = open(ep.address().family()); 367   4 aw.ec_ = open(ep.address().family());
HITCBC 368   10 return aw; 368   10 return aw;
369   } 369   }
370   370  
371   /** Send a datagram to the connected peer. 371   /** Send a datagram to the connected peer.
372   372  
373   Calls the backend implementation directly, bypassing virtual 373   Calls the backend implementation directly, bypassing virtual
374   dispatch. Otherwise identical to @ref udp_socket::send. 374   dispatch. Otherwise identical to @ref udp_socket::send.
375   375  
376   @param buffers The buffer sequence containing data to send. 376   @param buffers The buffer sequence containing data to send.
377   @param flags Message flags. 377   @param flags Message flags.
378   378  
379   @return An awaitable yielding `(error_code, std::size_t)`. 379   @return An awaitable yielding `(error_code, std::size_t)`.
380   380  
381   A closed socket reports `errc::bad_file_descriptor`. 381   A closed socket reports `errc::bad_file_descriptor`.
382   */ 382   */
383   template<capy::ConstBufferSequence CB> 383   template<capy::ConstBufferSequence CB>
HITCBC 384   8 [[nodiscard]] auto send(CB const& buffers, corosio::message_flags flags) 384   8 [[nodiscard]] auto send(CB const& buffers, corosio::message_flags flags)
385   { 385   {
HITCBC 386   8 native_send_awaitable<CB> aw(*this, buffers, static_cast<int>(flags)); 386   8 native_send_awaitable<CB> aw(*this, buffers, static_cast<int>(flags));
HITCBC 387   8 if (!is_open()) 387   8 if (!is_open())
HITCBC 388   2 aw.ec_ = make_error_code(std::errc::bad_file_descriptor); 388   2 aw.ec_ = make_error_code(std::errc::bad_file_descriptor);
HITCBC 389   8 return aw; 389   8 return aw;
390   } 390   }
391   391  
392   /// @overload 392   /// @overload
393   template<capy::ConstBufferSequence CB> 393   template<capy::ConstBufferSequence CB>
HITCBC 394   8 [[nodiscard]] auto send(CB const& buffers) 394   8 [[nodiscard]] auto send(CB const& buffers)
395   { 395   {
HITCBC 396   8 return send(buffers, corosio::message_flags::none); 396   8 return send(buffers, corosio::message_flags::none);
397   } 397   }
398   398  
399   /** Receive a datagram from the connected peer. 399   /** Receive a datagram from the connected peer.
400   400  
401   Calls the backend implementation directly, bypassing virtual 401   Calls the backend implementation directly, bypassing virtual
402   dispatch. Otherwise identical to @ref udp_socket::recv. 402   dispatch. Otherwise identical to @ref udp_socket::recv.
403   403  
404   @param buffers The buffer sequence to receive data into. 404   @param buffers The buffer sequence to receive data into.
405   @param flags Message flags (e.g. message_flags::peek). 405   @param flags Message flags (e.g. message_flags::peek).
406   406  
407   @return An awaitable yielding `(error_code, std::size_t)`. 407   @return An awaitable yielding `(error_code, std::size_t)`.
408   408  
409   A closed socket reports `errc::bad_file_descriptor`. 409   A closed socket reports `errc::bad_file_descriptor`.
410   */ 410   */
411   template<capy::MutableBufferSequence MB> 411   template<capy::MutableBufferSequence MB>
HITCBC 412   6 [[nodiscard]] auto recv(MB const& buffers, corosio::message_flags flags) 412   6 [[nodiscard]] auto recv(MB const& buffers, corosio::message_flags flags)
413   { 413   {
HITCBC 414   6 native_recv_awaitable<MB> aw(*this, buffers, static_cast<int>(flags)); 414   6 native_recv_awaitable<MB> aw(*this, buffers, static_cast<int>(flags));
HITCBC 415   6 if (!is_open()) 415   6 if (!is_open())
HITCBC 416   2 aw.ec_ = make_error_code(std::errc::bad_file_descriptor); 416   2 aw.ec_ = make_error_code(std::errc::bad_file_descriptor);
HITCBC 417   6 return aw; 417   6 return aw;
418   } 418   }
419   419  
420   /// @overload 420   /// @overload
421   template<capy::MutableBufferSequence MB> 421   template<capy::MutableBufferSequence MB>
HITCBC 422   6 [[nodiscard]] auto recv(MB const& buffers) 422   6 [[nodiscard]] auto recv(MB const& buffers)
423   { 423   {
HITCBC 424   6 return recv(buffers, corosio::message_flags::none); 424   6 return recv(buffers, corosio::message_flags::none);
425   } 425   }
426   426  
427   /** Asynchronously wait for the socket to be ready. 427   /** Asynchronously wait for the socket to be ready.
428   428  
429   Calls the backend implementation directly, bypassing virtual 429   Calls the backend implementation directly, bypassing virtual
430   dispatch. Otherwise identical to @ref udp_socket::wait. 430   dispatch. Otherwise identical to @ref udp_socket::wait.
431   431  
432   @param w The wait direction (read, write, or error). 432   @param w The wait direction (read, write, or error).
433   433  
434   @return An awaitable yielding `results<>`. 434   @return An awaitable yielding `results<>`.
435   */ 435   */
HITCBC 436   4 [[nodiscard]] auto wait(wait_type w) 436   4 [[nodiscard]] auto wait(wait_type w)
437   { 437   {
HITCBC 438   4 return native_wait_awaitable(*this, w); 438   4 return native_wait_awaitable(*this, w);
439   } 439   }
440   }; 440   };
441   441  
442   } // namespace boost::corosio 442   } // namespace boost::corosio
443   443  
444   #endif // BOOST_COROSIO_NATIVE_NATIVE_UDP_SOCKET_HPP 444   #endif // BOOST_COROSIO_NATIVE_NATIVE_UDP_SOCKET_HPP