uvcc
libuv C++ bindings
handle-udp.hpp
1 
2 #ifndef UVCC_HANDLE_UDP__HPP
3 #define UVCC_HANDLE_UDP__HPP
4 
5 #include "uvcc/utility.hpp"
6 #include "uvcc/handle-base.hpp"
7 #include "uvcc/handle-io.hpp"
8 #include "uvcc/loop.hpp"
9 
10 #include <cstddef> // size_t
11 #include <uv.h>
12 
13 #include <type_traits> // enable_if_t
14 
15 
16 namespace uv
17 {
18 
19 
20 /*! \ingroup doxy_group__handle
21  \brief UDP handle.
22  \sa libuv API documentation: [`uv_udp_t` — UDP handle](http://docs.libuv.org/en/v1.x/udp.html#uv-udp-t-udp-handle). */
23 class udp : public io
24 {
25  //! \cond
26  friend class handle::uv_interface;
27  friend class handle::instance< udp >;
28  friend class udp_send;
29  //! \endcond
30 
31 public: /*types*/
32  using uv_t = ::uv_udp_t;
33 
34  /*! \brief Supplemental data passed as the last argument to `io::on_read_t` callback function
35  called by `recv_start()`.
36  \sa libuv API documentation: [`uv_udp_recv_cb`](http://docs.libuv.org/en/v1.x/udp.html#c.uv_udp_recv_cb). */
37  struct io_info
38  {
39  /*! \brief The address of the remote peer. Can be `nullptr`. The pointer is valid for the duration of the callback only.
40  \note If the receive callback is called with zero number of bytes that have been received, then `(peer == nullptr)`
41  indicates that there is nothing to read, and `(peer != nullptr)` indicates an empty UDP packet is received. */
42  const ::sockaddr *peer;
43  /*! \brief One or more or’ed [`uv_udp_flags`](http://docs.libuv.org/en/v1.x/udp.html#c.uv_udp_flags) constants.
44  \sa libuv API documentation: [`uv_udp_recv_cb`](http://docs.libuv.org/en/v1.x/udp.html#c.uv_udp_recv_cb),
45  [`uv_udp_flags`](http://docs.libuv.org/en/v1.x/udp.html#c.uv_udp_flags). */
46  unsigned int flags;
47  };
48 
49 protected: /*types*/
50  //! \cond internals
51  //! \addtogroup doxy_group__internals
52  //! \{
53 
54  struct properties : io::properties {};
55 
56  struct uv_interface : handle::uv_handle_interface, io::uv_interface
57  {
58  std::size_t write_queue_size(void *_uv_handle) const noexcept override
59  { return static_cast< ::uv_udp_t* >(_uv_handle)->send_queue_size; }
60 
61  int read_start(void *_uv_handle, int64_t _offset) const noexcept override
62  {
63  if (_offset >= 0) instance::from(_uv_handle)->properties().rdoffset = _offset;
64  return ::uv_udp_recv_start(static_cast< ::uv_udp_t* >(_uv_handle), alloc_cb, recv_cb);
65  }
66 
67  int read_stop(void *_uv_handle) const noexcept override
68  { return ::uv_udp_recv_stop(static_cast< ::uv_udp_t* >(_uv_handle)); }
69  };
70 
71  //! \}
72  //! \endcond
73 
74 private: /*types*/
75  using instance = handle::instance< udp >;
76 
77 protected: /*constructors*/
78  //! \cond
79  explicit udp(uv_t *_uv_handle) : io(static_cast< io::uv_t* >(_uv_handle)) {}
80  //! \endcond
81 
82 public: /*constructors*/
83  ~udp() = default;
84 
85  udp(const udp&) = default;
86  udp& operator =(const udp&) = default;
87 
88  udp(udp&&) noexcept = default;
89  udp& operator =(udp&&) noexcept = default;
90 
91  /*! \details Create a UDP socket with the specified flags.
92  \note With `AF_UNSPEC` flag no socket is actually created on the system.
93  \sa libuv API documentation: [`uv_udp_init_ex()`](http://docs.libuv.org/en/v1.x/udp.html#c.uv_udp_init_ex).\n
94  libuv enhancement proposals: <https://github.com/libuv/leps/blob/master/003-create-sockets-early.md>. */
95  udp(uv::loop &_loop, unsigned int _flags = AF_UNSPEC)
96  {
97  uv_handle = instance::create();
98 
99  auto uv_ret = ::uv_udp_init_ex(static_cast< uv::loop::uv_t* >(_loop), static_cast< uv_t* >(uv_handle), _flags);
100  if (uv_status(uv_ret) < 0) return;
101 
102  instance::from(uv_handle)->book_loop();
103  }
104  /*! \details Create a handle object from an existing native platform depended datagram socket descriptor.
105  \sa libuv API documentation: [`uv_udp_open()`](http://docs.libuv.org/en/v1.x/udp.html#c.uv_udp_open),
106  [`uv_udp_init()`](http://docs.libuv.org/en/v1.x/udp.html#c.uv_udp_init). */
107  udp(uv::loop &_loop, ::uv_os_sock_t _socket)
108  {
109  uv_handle = instance::create();
110 
111  auto uv_ret = ::uv_udp_init(static_cast< uv::loop::uv_t* >(_loop), static_cast< uv_t* >(uv_handle));
112  if (uv_status(uv_ret) < 0) return;
113 
114  instance::from(uv_handle)->book_loop();
115 
116  uv_status(::uv_udp_open(static_cast< uv_t* >(uv_handle), _socket));
117  }
118 
119 private: /*functions*/
120  template< typename = void > static void alloc_cb(::uv_handle_t*, std::size_t, ::uv_buf_t*);
121  template< typename = void > static void recv_cb(::uv_udp_t*, ssize_t, const ::uv_buf_t*, const ::sockaddr*, unsigned int);
122 
123 public: /*interface*/
124  /*! \brief Get the platform dependent socket descriptor. The alias for `handle::fileno()`. */
125  ::uv_os_sock_t socket() const noexcept { return (::uv_os_sock_t)fileno(); }
126 
127  /*! \brief Number of bytes queued for sending. This field strictly shows how much information is currently queued. */
128  std::size_t send_queue_size() const noexcept { return static_cast< uv_t* >(uv_handle)->send_queue_size; }
129  /*! \brief Number of send requests currently in the queue awaiting to be processed. */
130  std::size_t send_queue_count() const noexcept { return static_cast< uv_t* >(uv_handle)->send_queue_count; }
131 
132  /*! \name UDP multicast/broadcast features: */
133  //! \{
134  /*! \brief Set membership for a multicast address.
135  \sa libuv API documentation: [`uv_udp_set_membership()`](http://docs.libuv.org/en/v1.x/udp.html#c.uv_udp_set_membership),
136  [`uv_membership`](http://docs.libuv.org/en/v1.x/udp.html#c.uv_membership). */
137  int set_multicast_membership(const char *_multicast_addr, const char *_interface_addr, ::uv_membership _membership) noexcept
138  {
139  return uv_status(::uv_udp_set_membership(
140  static_cast< uv_t* >(uv_handle),
141  _multicast_addr, _interface_addr, _membership
142  ));
143  }
144  /*! \brief Set IP multicast loop flag. Makes multicast packets loop back to local sockets.
145  \sa libuv API documentation: [`uv_udp_set_multicast_loop()`](http://docs.libuv.org/en/v1.x/udp.html#c.uv_udp_set_multicast_loop). */
146  int set_multicast_loop(bool _enable) noexcept
147  { return uv_status(::uv_udp_set_multicast_loop(static_cast< uv_t* >(uv_handle), _enable)); }
148  /*! \brief Set the multicast TTL value.
149  \sa libuv API documentation: [`uv_udp_set_multicast_ttl()`](http://docs.libuv.org/en/v1.x/udp.html#c.uv_udp_set_multicast_ttl). */
150  int set_multicast_ttl(int _value) noexcept
151  { return uv_status(::uv_udp_set_multicast_ttl(static_cast< uv_t* >(uv_handle), _value)); }
152  /*! \brief Set the multicast interface to send or receive data on.
153  \sa libuv API documentation: [`uv_udp_set_multicast_interface()`](http://docs.libuv.org/en/v1.x/udp.html#c.uv_udp_set_multicast_interface). */
154  int set_multicast_interface(const char *_interface_addr) noexcept
155  { return uv_status(::uv_udp_set_multicast_interface(static_cast< uv_t* >(uv_handle), _interface_addr)); }
156  /*! \brief Set broadcast on or off.
157  \sa libuv API documentation: [`uv_udp_set_broadcast()`](http://docs.libuv.org/en/v1.x/udp.html#c.uv_udp_set_broadcast). */
158  int set_broadcast(bool _enable) noexcept
159  { return uv_status(::uv_udp_set_broadcast(static_cast< uv_t* >(uv_handle), _enable)); }
160  //! \}
161 
162  /*! \details Bind the handle to an address and port.
163  \sa libuv API documentation: [`uv_udp_bind()`](http://docs.libuv.org/en/v1.x/udp.html#c.uv_udp_bind),
164  [`uv_udp_flags`](http://docs.libuv.org/en/v1.x/udp.html#c.uv_udp_flags). */
165  template<
166  typename _T_,
168  >
169  int bind(const _T_ &_sockaddr, unsigned int _flags = 0) noexcept
170  {
171  return uv_status(::uv_udp_bind(static_cast< uv_t* >(uv_handle), reinterpret_cast< const ::sockaddr* >(&_sockaddr), _flags));
172  }
173 
174  /*! \brief Get the local address and port which this handle is bound to.
175  \returns `true` if the operation has completed successfully (can be checked with `uv_status()`) and
176  the size of the passed argument (i.e. `sizeof(_T_)`) is enough to hold the returned socket address structure.
177  \sa libuv API documentation: [`uv_udp_getsockname()`](http://docs.libuv.org/en/v1.x/udp.html#c.uv_udp_getsockname). */
178  template< typename _T_, typename = std::enable_if_t< is_one_of< _T_, ::sockaddr_in, ::sockaddr_in6, ::sockaddr_storage >::value > >
179  bool getsockname(_T_ &_sockaddr) const noexcept
180  {
181  int z = sizeof(_T_);
182  return
183  uv_status(::uv_udp_getsockname(static_cast< uv_t* >(uv_handle), reinterpret_cast< ::sockaddr* >(&_sockaddr), &z)) >= 0
184  and
185  sizeof(_T_) >= z;
186  }
187 
188  /*! \brief Set the time to live value.
189  \sa libuv API documentation: [`uv_udp_set_ttl()`](http://docs.libuv.org/en/v1.x/udp.html#c.uv_udp_set_ttl). */
190  int set_ttl(int _value) noexcept { return uv_status(::uv_udp_set_ttl(static_cast< uv_t* >(uv_handle), _value)); }
191 
192  /*! \brief Alias for `io::read_start()`. */
193  int recv_start(const on_buffer_alloc_t &_alloc_cb, const on_read_t &_recv_cb, std::size_t _size = 0) const
194  { return read_start(_alloc_cb, _recv_cb, _size); }
195  /*! \brief Idem. */
196  int recv_start(std::size_t _size = 0) const { return read_start(_size); }
197  /*! \brief Alias for `io::read_stop()`. */
198  int recv_stop() const { return read_stop(); }
199 
200 #if 1
201  /*! \brief _Get_ the size of the send buffer that the operating system uses for the socket.
202  \sa libuv API documentation: [`uv_send_buffer_size()`](http://docs.libuv.org/en/v1.x/handle.html#c.uv_send_buffer_size). */
203  unsigned int send_buffer_size() const noexcept
204  {
205  unsigned int v = 0;
206  uv_status(::uv_send_buffer_size(static_cast< handle::uv_t* >(uv_handle), (int*)&v));
207  return v;
208  }
209  /*! \brief _Set_ the size of the send buffer that the operating system uses for the socket.
210  \sa libuv API documentation: [`uv_send_buffer_size()`](http://docs.libuv.org/en/v1.x/handle.html#c.uv_send_buffer_size). */
211  void send_buffer_size(unsigned int _value) noexcept { uv_status(::uv_send_buffer_size(static_cast< handle::uv_t* >(uv_handle), (int*)&_value)); }
212 
213  /*! \brief _Get_ the size of the receive buffer that the operating system uses for the socket.
214  \sa libuv API documentation: [`uv_recv_buffer_size()`](http://docs.libuv.org/en/v1.x/handle.html#c.uv_recv_buffer_size). */
215  unsigned int recv_buffer_size() const noexcept
216  {
217  unsigned int v = 0;
218  uv_status(::uv_recv_buffer_size(static_cast< handle::uv_t* >(uv_handle), (int*)&v));
219  return v;
220  }
221  /*! \brief _Set_ the size of the receive buffer that the operating system uses for the socket.
222  \sa libuv API documentation: [`uv_recv_buffer_size()`](http://docs.libuv.org/en/v1.x/handle.html#c.uv_recv_buffer_size). */
223  void recv_buffer_size(unsigned int _value) noexcept { uv_status(::uv_recv_buffer_size(static_cast< handle::uv_t* >(uv_handle), (int*)&_value)); }
224 #endif
225 
226 public: /*conversion operators*/
227  explicit operator const uv_t*() const noexcept { return static_cast< const uv_t* >(uv_handle); }
228  explicit operator uv_t*() noexcept { return static_cast< uv_t* >(uv_handle); }
229 };
230 
231 template< typename >
232 void udp::alloc_cb(::uv_handle_t *_uv_handle, std::size_t _suggested_size, ::uv_buf_t *_uv_buf)
233 { io_alloc_cb(_uv_handle, _suggested_size, _uv_buf); }
234 
235 template< typename >
236 void udp::recv_cb(::uv_udp_t *_uv_handle, ssize_t _nread, const ::uv_buf_t *_uv_buf, const ::sockaddr *_sockaddr, unsigned int _flags)
237 {
238  io_info supplemental_data = { _sockaddr, _flags };
239  io_read_cb(_uv_handle, _nread, _uv_buf, &supplemental_data);
240 }
241 
242 
243 }
244 
245 
246 #endif
Namespace for all uvcc definitions.
Definition: buffer.hpp:17
int set_broadcast(bool _enable) noexcept
Set broadcast on or off.
Definition: handle-udp.hpp:158
int recv_start(std::size_t _size=0) const
Idem.
Definition: handle-udp.hpp:196
int set_multicast_membership(const char *_multicast_addr, const char *_interface_addr, ::uv_membership _membership) noexcept
Set membership for a multicast address.
Definition: handle-udp.hpp:137
UDP handle.
Definition: handle-udp.hpp:23
int read_start(const on_buffer_alloc_t &_alloc_cb, const on_read_t &_read_cb, std::size_t _size=0, int64_t _offset=-1) const
Start reading incoming data from the I/O endpoint with provided input buffer allocation callback (_al...
Definition: handle-io.hpp:241
const ::sockaddr * peer
The address of the remote peer. Can be nullptr. The pointer is valid for the duration of the callback...
Definition: handle-udp.hpp:42
::uv_os_sock_t socket() const noexcept
Get the platform dependent socket descriptor. The alias for handle::fileno().
Definition: handle-udp.hpp:125
std::size_t send_queue_count() const noexcept
Number of send requests currently in the queue awaiting to be processed.
Definition: handle-udp.hpp:130
int read_stop() const
Stop reading data from the I/O endpoint.
Definition: handle-io.hpp:254
The base class for the libuv handles.
Definition: handle-base.hpp:33
unsigned int flags
One or more or’ed uv_udp_flags constants.
Definition: handle-udp.hpp:46
void recv_buffer_size(unsigned int _value) noexcept
Set the size of the receive buffer that the operating system uses for the socket. ...
Definition: handle-udp.hpp:223
int set_multicast_loop(bool _enable) noexcept
Set IP multicast loop flag. Makes multicast packets loop back to local sockets.
Definition: handle-udp.hpp:146
int recv_start(const on_buffer_alloc_t &_alloc_cb, const on_read_t &_recv_cb, std::size_t _size=0) const
Alias for io::read_start().
Definition: handle-udp.hpp:193
std::size_t send_queue_size() const noexcept
Number of bytes queued for sending. This field strictly shows how much information is currently queue...
Definition: handle-udp.hpp:128
int set_multicast_interface(const char *_interface_addr) noexcept
Set the multicast interface to send or receive data on.
Definition: handle-udp.hpp:154
unsigned int send_buffer_size() const noexcept
Get the size of the send buffer that the operating system uses for the socket.
Definition: handle-udp.hpp:203
int recv_stop() const
Alias for io::read_stop().
Definition: handle-udp.hpp:198
The I/O event loop class.
Definition: loop.hpp:33
The base class for handles representing I/O endpoints: a file, TCP/UDP socket, pipe, TTY.
Definition: handle-io.hpp:25
udp(uv::loop &_loop, unsigned int _flags=AF_UNSPEC)
Definition: handle-udp.hpp:95
unsigned int recv_buffer_size() const noexcept
Get the size of the receive buffer that the operating system uses for the socket. ...
Definition: handle-udp.hpp:215
void send_buffer_size(unsigned int _value) noexcept
Set the size of the send buffer that the operating system uses for the socket.
Definition: handle-udp.hpp:211
Supplemental data passed as the last argument to io::on_read_t callback function called by recv_start...
Definition: handle-udp.hpp:37
int set_ttl(int _value) noexcept
Set the time to live value.
Definition: handle-udp.hpp:190
int bind(const _T_ &_sockaddr, unsigned int _flags=0) noexcept
Definition: handle-udp.hpp:169
udp(uv::loop &_loop, ::uv_os_sock_t _socket)
Definition: handle-udp.hpp:107
bool getsockname(_T_ &_sockaddr) const noexcept
Get the local address and port which this handle is bound to.
Definition: handle-udp.hpp:179
int read_start(std::size_t _size=0, int64_t _offset=-1) const
Start reading incoming data from the I/O endpoint.
Definition: handle-io.hpp:191
int set_multicast_ttl(int _value) noexcept
Set the multicast TTL value.
Definition: handle-udp.hpp:150