100.00% Lines (92/92) 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(std::coroutine_handle<> h, capy::executor_ref ex) const 102   4 dispatch(std::coroutine_handle<> h, 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 h, ex, buffers_, dest_, flags_, this->token_, &this->ec_, 105   4 h, 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(std::coroutine_handle<> h, capy::executor_ref ex) const 133   8 dispatch(std::coroutine_handle<> h, 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 h, ex, buffers_, &source_, flags_, this->token_, &this->ec_, 136   8 h, 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(std::coroutine_handle<> h, capy::executor_ref ex) const 153   2 dispatch(std::coroutine_handle<> h, capy::executor_ref ex) const
154   { 154   {
HITCBC 155   2 return self_.get_impl().wait(h, ex, w_, this->token_, &this->ec_); 155   2 return self_.get_impl().wait(h, ex, w_, this->token_, &this->ec_);
156   } 156   }
157   }; 157   };
158   158  
159   struct native_connect_awaitable 159   struct native_connect_awaitable
160   : detail::void_op_base<native_connect_awaitable> 160   : detail::void_op_base<native_connect_awaitable>
161   { 161   {
162   native_udp_socket& self_; 162   native_udp_socket& self_;
163   endpoint endpoint_; 163   endpoint endpoint_;
164   164  
HITCBC 165   10 native_connect_awaitable(native_udp_socket& self, endpoint ep) noexcept 165   10 native_connect_awaitable(native_udp_socket& self, endpoint ep) noexcept
HITCBC 166   10 : self_(self) 166   10 : self_(self)
HITCBC 167   10 , endpoint_(ep) 167   10 , endpoint_(ep)
168   { 168   {
HITCBC 169   10 } 169   10 }
170   170  
171   std::coroutine_handle<> 171   std::coroutine_handle<>
HITCBC 172   8 dispatch(std::coroutine_handle<> h, capy::executor_ref ex) const 172   8 dispatch(std::coroutine_handle<> h, capy::executor_ref ex) const
173   { 173   {
HITCBC 174   24 return self_.get_impl().connect( 174   24 return self_.get_impl().connect(
HITCBC 175   24 h, ex, endpoint_, this->token_, &this->ec_); 175   24 h, ex, endpoint_, this->token_, &this->ec_);
176   } 176   }
177   }; 177   };
178   178  
179   template<class ConstBufferSequence> 179   template<class ConstBufferSequence>
180   struct native_send_awaitable 180   struct native_send_awaitable
181   : detail::bytes_op_base<native_send_awaitable<ConstBufferSequence>> 181   : detail::bytes_op_base<native_send_awaitable<ConstBufferSequence>>
182   { 182   {
183   native_udp_socket& self_; 183   native_udp_socket& self_;
184   ConstBufferSequence buffers_; 184   ConstBufferSequence buffers_;
185   int flags_; 185   int flags_;
186   186  
HITCBC 187   8 native_send_awaitable( 187   8 native_send_awaitable(
188   native_udp_socket& self, 188   native_udp_socket& self,
189   ConstBufferSequence buffers, 189   ConstBufferSequence buffers,
190   int flags) noexcept 190   int flags) noexcept
HITCBC 191   8 : self_(self) 191   8 : self_(self)
HITCBC 192   8 , buffers_(std::move(buffers)) 192   8 , buffers_(std::move(buffers))
HITCBC 193   8 , flags_(flags) 193   8 , flags_(flags)
194   { 194   {
HITCBC 195   8 } 195   8 }
196   196  
197   std::coroutine_handle<> 197   std::coroutine_handle<>
HITCBC 198   4 dispatch(std::coroutine_handle<> h, capy::executor_ref ex) const 198   4 dispatch(std::coroutine_handle<> h, capy::executor_ref ex) const
199   { 199   {
HITCBC 200   12 return self_.get_impl().send( 200   12 return self_.get_impl().send(
HITCBC 201   4 h, ex, buffers_, flags_, this->token_, &this->ec_, 201   4 h, ex, buffers_, flags_, this->token_, &this->ec_,
HITCBC 202   8 &this->bytes_); 202   8 &this->bytes_);
203   } 203   }
204   }; 204   };
205   205  
206   template<class MutableBufferSequence> 206   template<class MutableBufferSequence>
207   struct native_recv_awaitable 207   struct native_recv_awaitable
208   : detail::bytes_op_base<native_recv_awaitable<MutableBufferSequence>> 208   : detail::bytes_op_base<native_recv_awaitable<MutableBufferSequence>>
209   { 209   {
210   native_udp_socket& self_; 210   native_udp_socket& self_;
211   MutableBufferSequence buffers_; 211   MutableBufferSequence buffers_;
212   int flags_; 212   int flags_;
213   213  
HITCBC 214   6 native_recv_awaitable( 214   6 native_recv_awaitable(
215   native_udp_socket& self, 215   native_udp_socket& self,
216   MutableBufferSequence buffers, 216   MutableBufferSequence buffers,
217   int flags) noexcept 217   int flags) noexcept
HITCBC 218   6 : self_(self) 218   6 : self_(self)
HITCBC 219   6 , buffers_(std::move(buffers)) 219   6 , buffers_(std::move(buffers))
HITCBC 220   6 , flags_(flags) 220   6 , flags_(flags)
221   { 221   {
HITCBC 222   6 } 222   6 }
223   223  
224   std::coroutine_handle<> 224   std::coroutine_handle<>
HITCBC 225   2 dispatch(std::coroutine_handle<> h, capy::executor_ref ex) const 225   2 dispatch(std::coroutine_handle<> h, capy::executor_ref ex) const
226   { 226   {
HITCBC 227   6 return self_.get_impl().recv( 227   6 return self_.get_impl().recv(
HITCBC 228   2 h, ex, buffers_, flags_, this->token_, &this->ec_, 228   2 h, ex, buffers_, flags_, this->token_, &this->ec_,
HITCBC 229   4 &this->bytes_); 229   4 &this->bytes_);
230   } 230   }
231   }; 231   };
232   232  
233   public: 233   public:
234   /** Construct a native UDP socket from an execution context. 234   /** Construct a native UDP socket from an execution context.
235   235  
236   @param ctx The execution context that owns this socket. 236   @param ctx The execution context that owns this socket.
237   */ 237   */
HITCBC 238   42 explicit native_udp_socket(capy::execution_context& ctx) 238   42 explicit native_udp_socket(capy::execution_context& ctx)
HITCBC 239   42 : udp_socket(handle(ctx, ctx.use_service<service_type>())) 239   42 : udp_socket(handle(ctx, ctx.use_service<service_type>()))
240   { 240   {
HITCBC 241   42 } 241   42 }
242   242  
243   /** Construct a native UDP socket from an executor. 243   /** Construct a native UDP socket from an executor.
244   244  
245   @param ex The executor whose context owns the socket. 245   @param ex The executor whose context owns the socket.
246   246  
247   @tparam Ex A type satisfying @ref capy::Executor. Must not 247   @tparam Ex A type satisfying @ref capy::Executor. Must not
248   be `native_udp_socket` itself (disables implicit 248   be `native_udp_socket` itself (disables implicit
249   conversion from move). 249   conversion from move).
250   */ 250   */
251   template<class Ex> 251   template<class Ex>
252   requires(!std::same_as<std::remove_cvref_t<Ex>, native_udp_socket>) && 252   requires(!std::same_as<std::remove_cvref_t<Ex>, native_udp_socket>) &&
253   capy::Executor<Ex> 253   capy::Executor<Ex>
254   explicit native_udp_socket(Ex const& ex) : native_udp_socket(ex.context()) 254   explicit native_udp_socket(Ex const& ex) : native_udp_socket(ex.context())
255   { 255   {
256   } 256   }
257   257  
258   /** Move construct. 258   /** Move construct.
259   259  
260   @param other The socket to move from. 260   @param other The socket to move from.
261   261  
262   @pre No awaitables returned by @p other's methods exist. 262   @pre No awaitables returned by @p other's methods exist.
263   @pre The execution context associated with @p other must 263   @pre The execution context associated with @p other must
264   outlive this socket. 264   outlive this socket.
265   */ 265   */
HITCBC 266   2 native_udp_socket(native_udp_socket&&) noexcept = default; 266   2 native_udp_socket(native_udp_socket&&) noexcept = default;
267   267  
268   /** Move assign. 268   /** Move assign.
269   269  
270   @param other The socket to move from. 270   @param other The socket to move from.
271   271  
272   @pre No awaitables returned by either `*this` or @p other's 272   @pre No awaitables returned by either `*this` or @p other's
273   methods exist. 273   methods exist.
274   @pre The execution context associated with @p other must 274   @pre The execution context associated with @p other must
275   outlive this socket. 275   outlive this socket.
276   */ 276   */
277   native_udp_socket& operator=(native_udp_socket&&) noexcept = default; 277   native_udp_socket& operator=(native_udp_socket&&) noexcept = default;
278   278  
279   /// Copy construction is disabled; the handle is uniquely owned. 279   /// Copy construction is disabled; the handle is uniquely owned.
280   native_udp_socket(native_udp_socket const&) = delete; 280   native_udp_socket(native_udp_socket const&) = delete;
281   /// Copy assignment is disabled; the handle is uniquely owned. 281   /// Copy assignment is disabled; the handle is uniquely owned.
282   native_udp_socket& operator=(native_udp_socket const&) = delete; 282   native_udp_socket& operator=(native_udp_socket const&) = delete;
283   283  
284   /** Send a datagram to the specified destination. 284   /** Send a datagram to the specified destination.
285   285  
286   Calls the backend implementation directly, bypassing virtual 286   Calls the backend implementation directly, bypassing virtual
287   dispatch. Otherwise identical to @ref udp_socket::send_to. 287   dispatch. Otherwise identical to @ref udp_socket::send_to.
288   288  
289   @param buffers The buffer sequence containing data to send. 289   @param buffers The buffer sequence containing data to send.
290   @param dest The destination endpoint. 290   @param dest The destination endpoint.
291   @param flags Message flags. 291   @param flags Message flags.
292   292  
293   @return An awaitable yielding `(error_code, std::size_t)`. 293   @return An awaitable yielding `(error_code, std::size_t)`.
294   294  
295   A closed socket reports `errc::bad_file_descriptor`. 295   A closed socket reports `errc::bad_file_descriptor`.
296   */ 296   */
297   template<capy::ConstBufferSequence CB> 297   template<capy::ConstBufferSequence CB>
298   [[nodiscard]] auto 298   [[nodiscard]] auto
HITCBC 299   8 send_to(CB const& buffers, endpoint dest, corosio::message_flags flags) 299   8 send_to(CB const& buffers, endpoint dest, corosio::message_flags flags)
300   { 300   {
HITCBC 301   8 native_send_to_awaitable<CB> aw( 301   8 native_send_to_awaitable<CB> aw(
302   *this, buffers, dest, static_cast<int>(flags)); 302   *this, buffers, dest, static_cast<int>(flags));
HITCBC 303   8 if (!is_open()) 303   8 if (!is_open())
HITCBC 304   2 aw.ec_ = make_error_code(std::errc::bad_file_descriptor); 304   2 aw.ec_ = make_error_code(std::errc::bad_file_descriptor);
HITCBC 305   8 return aw; 305   8 return aw;
306   } 306   }
307   307  
308   /// @overload 308   /// @overload
309   template<capy::ConstBufferSequence CB> 309   template<capy::ConstBufferSequence CB>
HITCBC 310   8 [[nodiscard]] auto send_to(CB const& buffers, endpoint dest) 310   8 [[nodiscard]] auto send_to(CB const& buffers, endpoint dest)
311   { 311   {
HITCBC 312   8 return send_to(buffers, dest, corosio::message_flags::none); 312   8 return send_to(buffers, dest, corosio::message_flags::none);
313   } 313   }
314   314  
315   /** Receive a datagram and capture the sender's endpoint. 315   /** Receive a datagram and capture the sender's endpoint.
316   316  
317   Calls the backend implementation directly, bypassing virtual 317   Calls the backend implementation directly, bypassing virtual
318   dispatch. Otherwise identical to @ref udp_socket::recv_from. 318   dispatch. Otherwise identical to @ref udp_socket::recv_from.
319   319  
320   @param buffers The buffer sequence to receive data into. 320   @param buffers The buffer sequence to receive data into.
321   @param source Reference to an endpoint that receives 321   @param source Reference to an endpoint that receives
322   the sender's address on successful completion. 322   the sender's address on successful completion.
323   @param flags Message flags (e.g. message_flags::peek). 323   @param flags Message flags (e.g. message_flags::peek).
324   324  
325   @return An awaitable yielding `(error_code, std::size_t)`. 325   @return An awaitable yielding `(error_code, std::size_t)`.
326   326  
327   A closed socket reports `errc::bad_file_descriptor`. 327   A closed socket reports `errc::bad_file_descriptor`.
328   */ 328   */
329   template<capy::MutableBufferSequence MB> 329   template<capy::MutableBufferSequence MB>
330   [[nodiscard]] auto 330   [[nodiscard]] auto
HITCBC 331   12 recv_from(MB const& buffers, endpoint& source, corosio::message_flags flags) 331   12 recv_from(MB const& buffers, endpoint& source, corosio::message_flags flags)
332   { 332   {
HITCBC 333   12 native_recv_from_awaitable<MB> aw( 333   12 native_recv_from_awaitable<MB> aw(
334   *this, buffers, source, static_cast<int>(flags)); 334   *this, buffers, source, static_cast<int>(flags));
HITCBC 335   12 if (!is_open()) 335   12 if (!is_open())
HITCBC 336   2 aw.ec_ = make_error_code(std::errc::bad_file_descriptor); 336   2 aw.ec_ = make_error_code(std::errc::bad_file_descriptor);
HITCBC 337   12 return aw; 337   12 return aw;
338   } 338   }
339   339  
340   /// @overload 340   /// @overload
341   template<capy::MutableBufferSequence MB> 341   template<capy::MutableBufferSequence MB>
HITCBC 342   12 [[nodiscard]] auto recv_from(MB const& buffers, endpoint& source) 342   12 [[nodiscard]] auto recv_from(MB const& buffers, endpoint& source)
343   { 343   {
HITCBC 344   12 return recv_from(buffers, source, corosio::message_flags::none); 344   12 return recv_from(buffers, source, corosio::message_flags::none);
345   } 345   }
346   346  
347   /** Asynchronously connect to set the default peer. 347   /** Asynchronously connect to set the default peer.
348   348  
349   Calls the backend implementation directly, bypassing virtual 349   Calls the backend implementation directly, bypassing virtual
350   dispatch. Otherwise identical to @ref udp_socket::connect. 350   dispatch. Otherwise identical to @ref udp_socket::connect.
351   351  
352   If the socket is not already open, it is opened automatically 352   If the socket is not already open, it is opened automatically
353   using the address family of @p ep. 353   using the address family of @p ep.
354   354  
355   @param ep The remote endpoint to connect to. 355   @param ep The remote endpoint to connect to.
356   356  
357   @return An awaitable yielding `io_result<>`. 357   @return An awaitable yielding `io_result<>`.
358   358  
359   If the socket needs to be opened and the open fails, the 359   If the socket needs to be opened and the open fails, the
360   awaitable completes immediately with that error. 360   awaitable completes immediately with that error.
361   */ 361   */
HITCBC 362   10 [[nodiscard]] auto connect(endpoint ep) 362   10 [[nodiscard]] auto connect(endpoint ep)
363   { 363   {
HITCBC 364   10 native_connect_awaitable aw(*this, ep); 364   10 native_connect_awaitable aw(*this, ep);
HITCBC 365   10 if (!is_open()) 365   10 if (!is_open())
HITCBC 366   4 aw.ec_ = open(ep.address().family()); 366   4 aw.ec_ = open(ep.address().family());
HITCBC 367   10 return aw; 367   10 return aw;
368   } 368   }
369   369  
370   /** Send a datagram to the connected peer. 370   /** Send a datagram to the connected peer.
371   371  
372   Calls the backend implementation directly, bypassing virtual 372   Calls the backend implementation directly, bypassing virtual
373   dispatch. Otherwise identical to @ref udp_socket::send. 373   dispatch. Otherwise identical to @ref udp_socket::send.
374   374  
375   @param buffers The buffer sequence containing data to send. 375   @param buffers The buffer sequence containing data to send.
376   @param flags Message flags. 376   @param flags Message flags.
377   377  
378   @return An awaitable yielding `(error_code, std::size_t)`. 378   @return An awaitable yielding `(error_code, std::size_t)`.
379   379  
380   A closed socket reports `errc::bad_file_descriptor`. 380   A closed socket reports `errc::bad_file_descriptor`.
381   */ 381   */
382   template<capy::ConstBufferSequence CB> 382   template<capy::ConstBufferSequence CB>
HITCBC 383   8 [[nodiscard]] auto send(CB const& buffers, corosio::message_flags flags) 383   8 [[nodiscard]] auto send(CB const& buffers, corosio::message_flags flags)
384   { 384   {
HITCBC 385   8 native_send_awaitable<CB> aw(*this, buffers, static_cast<int>(flags)); 385   8 native_send_awaitable<CB> aw(*this, buffers, static_cast<int>(flags));
HITCBC 386   8 if (!is_open()) 386   8 if (!is_open())
HITCBC 387   2 aw.ec_ = make_error_code(std::errc::bad_file_descriptor); 387   2 aw.ec_ = make_error_code(std::errc::bad_file_descriptor);
HITCBC 388   8 return aw; 388   8 return aw;
389   } 389   }
390   390  
391   /// @overload 391   /// @overload
392   template<capy::ConstBufferSequence CB> 392   template<capy::ConstBufferSequence CB>
HITCBC 393   8 [[nodiscard]] auto send(CB const& buffers) 393   8 [[nodiscard]] auto send(CB const& buffers)
394   { 394   {
HITCBC 395   8 return send(buffers, corosio::message_flags::none); 395   8 return send(buffers, corosio::message_flags::none);
396   } 396   }
397   397  
398   /** Receive a datagram from the connected peer. 398   /** Receive a datagram from the connected peer.
399   399  
400   Calls the backend implementation directly, bypassing virtual 400   Calls the backend implementation directly, bypassing virtual
401   dispatch. Otherwise identical to @ref udp_socket::recv. 401   dispatch. Otherwise identical to @ref udp_socket::recv.
402   402  
403   @param buffers The buffer sequence to receive data into. 403   @param buffers The buffer sequence to receive data into.
404   @param flags Message flags (e.g. message_flags::peek). 404   @param flags Message flags (e.g. message_flags::peek).
405   405  
406   @return An awaitable yielding `(error_code, std::size_t)`. 406   @return An awaitable yielding `(error_code, std::size_t)`.
407   407  
408   A closed socket reports `errc::bad_file_descriptor`. 408   A closed socket reports `errc::bad_file_descriptor`.
409   */ 409   */
410   template<capy::MutableBufferSequence MB> 410   template<capy::MutableBufferSequence MB>
HITCBC 411   6 [[nodiscard]] auto recv(MB const& buffers, corosio::message_flags flags) 411   6 [[nodiscard]] auto recv(MB const& buffers, corosio::message_flags flags)
412   { 412   {
HITCBC 413   6 native_recv_awaitable<MB> aw(*this, buffers, static_cast<int>(flags)); 413   6 native_recv_awaitable<MB> aw(*this, buffers, static_cast<int>(flags));
HITCBC 414   6 if (!is_open()) 414   6 if (!is_open())
HITCBC 415   2 aw.ec_ = make_error_code(std::errc::bad_file_descriptor); 415   2 aw.ec_ = make_error_code(std::errc::bad_file_descriptor);
HITCBC 416   6 return aw; 416   6 return aw;
417   } 417   }
418   418  
419   /// @overload 419   /// @overload
420   template<capy::MutableBufferSequence MB> 420   template<capy::MutableBufferSequence MB>
HITCBC 421   6 [[nodiscard]] auto recv(MB const& buffers) 421   6 [[nodiscard]] auto recv(MB const& buffers)
422   { 422   {
HITCBC 423   6 return recv(buffers, corosio::message_flags::none); 423   6 return recv(buffers, corosio::message_flags::none);
424   } 424   }
425   425  
426   /** Asynchronously wait for the socket to be ready. 426   /** Asynchronously wait for the socket to be ready.
427   427  
428   Calls the backend implementation directly, bypassing virtual 428   Calls the backend implementation directly, bypassing virtual
429   dispatch. Otherwise identical to @ref udp_socket::wait. 429   dispatch. Otherwise identical to @ref udp_socket::wait.
430   430  
431   @param w The wait direction (read, write, or error). 431   @param w The wait direction (read, write, or error).
432   432  
433   @return An awaitable yielding `io_result<>`. 433   @return An awaitable yielding `io_result<>`.
434   */ 434   */
HITCBC 435   4 [[nodiscard]] auto wait(wait_type w) 435   4 [[nodiscard]] auto wait(wait_type w)
436   { 436   {
HITCBC 437   4 return native_wait_awaitable(*this, w); 437   4 return native_wait_awaitable(*this, w);
438   } 438   }
439   }; 439   };
440   440  
441   } // namespace boost::corosio 441   } // namespace boost::corosio
442   442  
443   #endif // BOOST_COROSIO_NATIVE_NATIVE_UDP_SOCKET_HPP 443   #endif // BOOST_COROSIO_NATIVE_NATIVE_UDP_SOCKET_HPP