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