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   /** An asynchronous UDP socket with devirtualized I/O operations. 42   /** An asynchronous UDP socket with devirtualized I/O operations.
43   43  
44   This class template inherits from @ref udp_socket and shadows 44   This class template inherits from @ref udp_socket and shadows
45   the async operations (`send_to`, `recv_from`, `connect`, `send`, 45   the async operations (`send_to`, `recv_from`, `connect`, `send`,
46   `recv`) with versions that call the backend implementation 46   `recv`) with versions that call the backend implementation
47   directly, allowing the compiler to inline through the entire 47   directly, allowing the compiler to inline through the entire
48   call chain. 48   call chain.
49   49  
50   Non-async operations (`open`, `close`, `cancel`, `bind`, 50   Non-async operations (`open`, `close`, `cancel`, `bind`,
51   socket options) remain unchanged and dispatch through the 51   socket options) remain unchanged and dispatch through the
52   compiled library. 52   compiled library.
53   53  
54   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
55   any function expecting `udp_socket&`, in which case virtual 55   any function expecting `udp_socket&`, in which case virtual
56   dispatch is used transparently. 56   dispatch is used transparently.
57   57  
58   @tparam Backend A backend tag value (e.g., `epoll`) 58   @tparam Backend A backend tag value (e.g., `epoll`)
59   whose type provides the concrete implementation types. 59   whose type provides the concrete implementation types.
60   60  
61   @par Thread Safety 61   @par Thread Safety
62   Same as @ref udp_socket. 62   Same as @ref udp_socket.
63   63  
64   @par Example 64   @par Example
65   @par !example native_udp_socket 65   @par !example native_udp_socket
66   66  
67   @see udp_socket, epoll_t 67   @see udp_socket, epoll_t
68   */ 68   */
69   template<auto Backend> 69   template<auto Backend>
70   class native_udp_socket : public udp_socket 70   class native_udp_socket : public udp_socket
71   { 71   {
72   using backend_type = decltype(Backend); 72   using backend_type = decltype(Backend);
73   using impl_type = typename backend_type::udp_socket_type; 73   using impl_type = typename backend_type::udp_socket_type;
74   using service_type = typename backend_type::udp_service_type; 74   using service_type = typename backend_type::udp_service_type;
75   75  
HITCBC 76   28 impl_type& get_impl() noexcept 76   28 impl_type& get_impl() noexcept
77   { 77   {
HITCBC 78   28 return *static_cast<impl_type*>(h_.get()); 78   28 return *static_cast<impl_type*>(h_.get());
79   } 79   }
80   80  
81   template<class ConstBufferSequence> 81   template<class ConstBufferSequence>
82   struct native_send_to_awaitable 82   struct native_send_to_awaitable
83   : detail::bytes_op_base<native_send_to_awaitable<ConstBufferSequence>> 83   : detail::bytes_op_base<native_send_to_awaitable<ConstBufferSequence>>
84   { 84   {
85   native_udp_socket& self_; 85   native_udp_socket& self_;
86   ConstBufferSequence buffers_; 86   ConstBufferSequence buffers_;
87   endpoint dest_; 87   endpoint dest_;
88   int flags_; 88   int flags_;
89   89  
HITCBC 90   8 native_send_to_awaitable( 90   8 native_send_to_awaitable(
91   native_udp_socket& self, 91   native_udp_socket& self,
92   ConstBufferSequence buffers, 92   ConstBufferSequence buffers,
93   endpoint dest, 93   endpoint dest,
94   int flags) noexcept 94   int flags) noexcept
HITCBC 95   8 : self_(self) 95   8 : self_(self)
HITCBC 96   8 , buffers_(std::move(buffers)) 96   8 , buffers_(std::move(buffers))
HITCBC 97   8 , dest_(dest) 97   8 , dest_(dest)
HITCBC 98   8 , flags_(flags) 98   8 , flags_(flags)
99   { 99   {
HITCBC 100   8 } 100   8 }
101   101  
102   std::coroutine_handle<> 102   std::coroutine_handle<>
HITCBC 103   4 dispatch(std::coroutine_handle<> h, capy::executor_ref ex) const 103   4 dispatch(std::coroutine_handle<> h, capy::executor_ref ex) const
104   { 104   {
HITCBC 105   12 return self_.get_impl().send_to( 105   12 return self_.get_impl().send_to(
HITCBC 106   4 h, ex, buffers_, dest_, flags_, this->token_, &this->ec_, 106   4 h, ex, buffers_, dest_, flags_, this->token_, &this->ec_,
HITCBC 107   8 &this->bytes_); 107   8 &this->bytes_);
108   } 108   }
109   }; 109   };
110   110  
111   template<class MutableBufferSequence> 111   template<class MutableBufferSequence>
112   struct native_recv_from_awaitable 112   struct native_recv_from_awaitable
113   : detail::bytes_op_base< 113   : detail::bytes_op_base<
114   native_recv_from_awaitable<MutableBufferSequence>> 114   native_recv_from_awaitable<MutableBufferSequence>>
115   { 115   {
116   native_udp_socket& self_; 116   native_udp_socket& self_;
117   MutableBufferSequence buffers_; 117   MutableBufferSequence buffers_;
118   endpoint& source_; 118   endpoint& source_;
119   int flags_; 119   int flags_;
120   120  
HITCBC 121   12 native_recv_from_awaitable( 121   12 native_recv_from_awaitable(
122   native_udp_socket& self, 122   native_udp_socket& self,
123   MutableBufferSequence buffers, 123   MutableBufferSequence buffers,
124   endpoint& source, 124   endpoint& source,
125   int flags) noexcept 125   int flags) noexcept
HITCBC 126   12 : self_(self) 126   12 : self_(self)
HITCBC 127   12 , buffers_(std::move(buffers)) 127   12 , buffers_(std::move(buffers))
HITCBC 128   12 , source_(source) 128   12 , source_(source)
HITCBC 129   12 , flags_(flags) 129   12 , flags_(flags)
130   { 130   {
HITCBC 131   12 } 131   12 }
132   132  
133   std::coroutine_handle<> 133   std::coroutine_handle<>
HITCBC 134   8 dispatch(std::coroutine_handle<> h, capy::executor_ref ex) const 134   8 dispatch(std::coroutine_handle<> h, capy::executor_ref ex) const
135   { 135   {
HITCBC 136   24 return self_.get_impl().recv_from( 136   24 return self_.get_impl().recv_from(
HITCBC 137   8 h, ex, buffers_, &source_, flags_, this->token_, &this->ec_, 137   8 h, ex, buffers_, &source_, flags_, this->token_, &this->ec_,
HITCBC 138   16 &this->bytes_); 138   16 &this->bytes_);
139   } 139   }
140   }; 140   };
141   141  
142   struct native_wait_awaitable : detail::void_op_base<native_wait_awaitable> 142   struct native_wait_awaitable : detail::void_op_base<native_wait_awaitable>
143   { 143   {
144   native_udp_socket& self_; 144   native_udp_socket& self_;
145   wait_type w_; 145   wait_type w_;
146   146  
HITCBC 147   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 148   4 : self_(self) 148   4 : self_(self)
HITCBC 149   4 , w_(w) 149   4 , w_(w)
150   { 150   {
HITCBC 151   4 } 151   4 }
152   152  
153   std::coroutine_handle<> 153   std::coroutine_handle<>
HITCBC 154   2 dispatch(std::coroutine_handle<> h, capy::executor_ref ex) const 154   2 dispatch(std::coroutine_handle<> h, capy::executor_ref ex) const
155   { 155   {
HITCBC 156   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_);
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(std::coroutine_handle<> h, capy::executor_ref ex) const 173   8 dispatch(std::coroutine_handle<> h, 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 h, ex, endpoint_, this->token_, &this->ec_); 176   24 h, 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(std::coroutine_handle<> h, capy::executor_ref ex) const 199   4 dispatch(std::coroutine_handle<> h, 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 h, ex, buffers_, flags_, this->token_, &this->ec_, 202   4 h, 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(std::coroutine_handle<> h, capy::executor_ref ex) const 226   2 dispatch(std::coroutine_handle<> h, 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 h, ex, buffers_, flags_, this->token_, &this->ec_, 229   2 h, 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 will own this socket. 237   @param ctx The execution context that will own 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(create_handle<service_type>(ctx)) 240   42 : udp_socket(create_handle<service_type>(ctx))
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 will own the socket. 246   @param ex The executor whose context will own the socket.
247   */ 247   */
248   template<class Ex> 248   template<class Ex>
249   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>) &&
250   capy::Executor<Ex> 250   capy::Executor<Ex>
251   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())
252   { 252   {
253   } 253   }
254   254  
255   /// Move construct. 255   /// Move construct.
HITCBC 256   2 native_udp_socket(native_udp_socket&&) noexcept = default; 256   2 native_udp_socket(native_udp_socket&&) noexcept = default;
257   257  
258   /// Move assign. 258   /// Move assign.
259   native_udp_socket& operator=(native_udp_socket&&) noexcept = default; 259   native_udp_socket& operator=(native_udp_socket&&) noexcept = default;
260   260  
261   native_udp_socket(native_udp_socket const&) = delete; 261   native_udp_socket(native_udp_socket const&) = delete;
262   native_udp_socket& operator=(native_udp_socket const&) = delete; 262   native_udp_socket& operator=(native_udp_socket const&) = delete;
263   263  
264   /** Send a datagram to the specified destination. 264   /** Send a datagram to the specified destination.
265   265  
266   Calls the backend implementation directly, bypassing virtual 266   Calls the backend implementation directly, bypassing virtual
267   dispatch. Otherwise identical to @ref udp_socket::send_to. 267   dispatch. Otherwise identical to @ref udp_socket::send_to.
268   268  
269   @param buffers The buffer sequence containing data to send. 269   @param buffers The buffer sequence containing data to send.
270   @param dest The destination endpoint. 270   @param dest The destination endpoint.
271   @param flags Message flags. 271   @param flags Message flags.
272   272  
273   @return An awaitable yielding `(error_code, std::size_t)`. 273   @return An awaitable yielding `(error_code, std::size_t)`.
274   274  
275   A closed socket reports `errc::bad_file_descriptor`. 275   A closed socket reports `errc::bad_file_descriptor`.
276   */ 276   */
277   template<capy::ConstBufferSequence CB> 277   template<capy::ConstBufferSequence CB>
278   [[nodiscard]] auto 278   [[nodiscard]] auto
HITCBC 279   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)
280   { 280   {
HITCBC 281   8 native_send_to_awaitable<CB> aw( 281   8 native_send_to_awaitable<CB> aw(
282   *this, buffers, dest, static_cast<int>(flags)); 282   *this, buffers, dest, static_cast<int>(flags));
HITCBC 283   8 if (!is_open()) 283   8 if (!is_open())
HITCBC 284   2 aw.ec_ = make_error_code(std::errc::bad_file_descriptor); 284   2 aw.ec_ = make_error_code(std::errc::bad_file_descriptor);
HITCBC 285   8 return aw; 285   8 return aw;
286   } 286   }
287   287  
288   /// @overload 288   /// @overload
289   template<capy::ConstBufferSequence CB> 289   template<capy::ConstBufferSequence CB>
HITCBC 290   8 [[nodiscard]] auto send_to(CB const& buffers, endpoint dest) 290   8 [[nodiscard]] auto send_to(CB const& buffers, endpoint dest)
291   { 291   {
HITCBC 292   8 return send_to(buffers, dest, corosio::message_flags::none); 292   8 return send_to(buffers, dest, corosio::message_flags::none);
293   } 293   }
294   294  
295   /** Receive a datagram and capture the sender's endpoint. 295   /** Receive a datagram and capture the sender's endpoint.
296   296  
297   Calls the backend implementation directly, bypassing virtual 297   Calls the backend implementation directly, bypassing virtual
298   dispatch. Otherwise identical to @ref udp_socket::recv_from. 298   dispatch. Otherwise identical to @ref udp_socket::recv_from.
299   299  
300   @param buffers The buffer sequence to receive data into. 300   @param buffers The buffer sequence to receive data into.
301   @param source Reference to an endpoint that will be set to 301   @param source Reference to an endpoint that will be set to
302   the sender's address on successful completion. 302   the sender's address on successful completion.
303   @param flags Message flags (e.g. message_flags::peek). 303   @param flags Message flags (e.g. message_flags::peek).
304   304  
305   @return An awaitable yielding `(error_code, std::size_t)`. 305   @return An awaitable yielding `(error_code, std::size_t)`.
306   306  
307   A closed socket reports `errc::bad_file_descriptor`. 307   A closed socket reports `errc::bad_file_descriptor`.
308   */ 308   */
309   template<capy::MutableBufferSequence MB> 309   template<capy::MutableBufferSequence MB>
310   [[nodiscard]] auto 310   [[nodiscard]] auto
HITCBC 311   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)
312   { 312   {
HITCBC 313   12 native_recv_from_awaitable<MB> aw( 313   12 native_recv_from_awaitable<MB> aw(
314   *this, buffers, source, static_cast<int>(flags)); 314   *this, buffers, source, static_cast<int>(flags));
HITCBC 315   12 if (!is_open()) 315   12 if (!is_open())
HITCBC 316   2 aw.ec_ = make_error_code(std::errc::bad_file_descriptor); 316   2 aw.ec_ = make_error_code(std::errc::bad_file_descriptor);
HITCBC 317   12 return aw; 317   12 return aw;
318   } 318   }
319   319  
320   /// @overload 320   /// @overload
321   template<capy::MutableBufferSequence MB> 321   template<capy::MutableBufferSequence MB>
HITCBC 322   12 [[nodiscard]] auto recv_from(MB const& buffers, endpoint& source) 322   12 [[nodiscard]] auto recv_from(MB const& buffers, endpoint& source)
323   { 323   {
HITCBC 324   12 return recv_from(buffers, source, corosio::message_flags::none); 324   12 return recv_from(buffers, source, corosio::message_flags::none);
325   } 325   }
326   326  
327   /** Asynchronously connect to set the default peer. 327   /** Asynchronously connect to set the default peer.
328   328  
329   Calls the backend implementation directly, bypassing virtual 329   Calls the backend implementation directly, bypassing virtual
330   dispatch. Otherwise identical to @ref udp_socket::connect. 330   dispatch. Otherwise identical to @ref udp_socket::connect.
331   331  
332   If the socket is not already open, it is opened automatically 332   If the socket is not already open, it is opened automatically
333   using the address family of @p ep. 333   using the address family of @p ep.
334   334  
335   @param ep The remote endpoint to connect to. 335   @param ep The remote endpoint to connect to.
336   336  
337   @return An awaitable yielding `io_result<>`. 337   @return An awaitable yielding `io_result<>`.
338   338  
339   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
340   awaitable completes immediately with that error. 340   awaitable completes immediately with that error.
341   */ 341   */
HITCBC 342   10 [[nodiscard]] auto connect(endpoint ep) 342   10 [[nodiscard]] auto connect(endpoint ep)
343   { 343   {
HITCBC 344   10 native_connect_awaitable aw(*this, ep); 344   10 native_connect_awaitable aw(*this, ep);
HITCBC 345   10 if (!is_open()) 345   10 if (!is_open())
HITCBC 346   4 aw.ec_ = open(ep.address().family()); 346   4 aw.ec_ = open(ep.address().family());
HITCBC 347   10 return aw; 347   10 return aw;
348   } 348   }
349   349  
350   /** Send a datagram to the connected peer. 350   /** Send a datagram to the connected peer.
351   351  
352   Calls the backend implementation directly, bypassing virtual 352   Calls the backend implementation directly, bypassing virtual
353   dispatch. Otherwise identical to @ref udp_socket::send. 353   dispatch. Otherwise identical to @ref udp_socket::send.
354   354  
355   @param buffers The buffer sequence containing data to send. 355   @param buffers The buffer sequence containing data to send.
356   @param flags Message flags. 356   @param flags Message flags.
357   357  
358   @return An awaitable yielding `(error_code, std::size_t)`. 358   @return An awaitable yielding `(error_code, std::size_t)`.
359   359  
360   A closed socket reports `errc::bad_file_descriptor`. 360   A closed socket reports `errc::bad_file_descriptor`.
361   */ 361   */
362   template<capy::ConstBufferSequence CB> 362   template<capy::ConstBufferSequence CB>
HITCBC 363   8 [[nodiscard]] auto send(CB const& buffers, corosio::message_flags flags) 363   8 [[nodiscard]] auto send(CB const& buffers, corosio::message_flags flags)
364   { 364   {
HITCBC 365   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 366   8 if (!is_open()) 366   8 if (!is_open())
HITCBC 367   2 aw.ec_ = make_error_code(std::errc::bad_file_descriptor); 367   2 aw.ec_ = make_error_code(std::errc::bad_file_descriptor);
HITCBC 368   8 return aw; 368   8 return aw;
369   } 369   }
370   370  
371   /// @overload 371   /// @overload
372   template<capy::ConstBufferSequence CB> 372   template<capy::ConstBufferSequence CB>
HITCBC 373   8 [[nodiscard]] auto send(CB const& buffers) 373   8 [[nodiscard]] auto send(CB const& buffers)
374   { 374   {
HITCBC 375   8 return send(buffers, corosio::message_flags::none); 375   8 return send(buffers, corosio::message_flags::none);
376   } 376   }
377   377  
378   /** Receive a datagram from the connected peer. 378   /** Receive a datagram from the connected peer.
379   379  
380   Calls the backend implementation directly, bypassing virtual 380   Calls the backend implementation directly, bypassing virtual
381   dispatch. Otherwise identical to @ref udp_socket::recv. 381   dispatch. Otherwise identical to @ref udp_socket::recv.
382   382  
383   @param buffers The buffer sequence to receive data into. 383   @param buffers The buffer sequence to receive data into.
384   @param flags Message flags (e.g. message_flags::peek). 384   @param flags Message flags (e.g. message_flags::peek).
385   385  
386   @return An awaitable yielding `(error_code, std::size_t)`. 386   @return An awaitable yielding `(error_code, std::size_t)`.
387   387  
388   A closed socket reports `errc::bad_file_descriptor`. 388   A closed socket reports `errc::bad_file_descriptor`.
389   */ 389   */
390   template<capy::MutableBufferSequence MB> 390   template<capy::MutableBufferSequence MB>
HITCBC 391   6 [[nodiscard]] auto recv(MB const& buffers, corosio::message_flags flags) 391   6 [[nodiscard]] auto recv(MB const& buffers, corosio::message_flags flags)
392   { 392   {
HITCBC 393   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 394   6 if (!is_open()) 394   6 if (!is_open())
HITCBC 395   2 aw.ec_ = make_error_code(std::errc::bad_file_descriptor); 395   2 aw.ec_ = make_error_code(std::errc::bad_file_descriptor);
HITCBC 396   6 return aw; 396   6 return aw;
397   } 397   }
398   398  
399   /// @overload 399   /// @overload
400   template<capy::MutableBufferSequence MB> 400   template<capy::MutableBufferSequence MB>
HITCBC 401   6 [[nodiscard]] auto recv(MB const& buffers) 401   6 [[nodiscard]] auto recv(MB const& buffers)
402   { 402   {
HITCBC 403   6 return recv(buffers, corosio::message_flags::none); 403   6 return recv(buffers, corosio::message_flags::none);
404   } 404   }
405   405  
406   /** Asynchronously wait for the socket to be ready. 406   /** Asynchronously wait for the socket to be ready.
407   407  
408   Calls the backend implementation directly, bypassing virtual 408   Calls the backend implementation directly, bypassing virtual
409   dispatch. Otherwise identical to @ref udp_socket::wait. 409   dispatch. Otherwise identical to @ref udp_socket::wait.
410   410  
411   @param w The wait direction (read, write, or error). 411   @param w The wait direction (read, write, or error).
412   412  
413   @return An awaitable yielding `io_result<>`. 413   @return An awaitable yielding `io_result<>`.
414   */ 414   */
HITCBC 415   4 [[nodiscard]] auto wait(wait_type w) 415   4 [[nodiscard]] auto wait(wait_type w)
416   { 416   {
HITCBC 417   4 return native_wait_awaitable(*this, w); 417   4 return native_wait_awaitable(*this, w);
418   } 418   }
419   }; 419   };
420   420  
421   } // namespace boost::corosio 421   } // namespace boost::corosio
422   422  
423   #endif // BOOST_COROSIO_NATIVE_NATIVE_UDP_SOCKET_HPP 423   #endif // BOOST_COROSIO_NATIVE_NATIVE_UDP_SOCKET_HPP