uvcc
libuv C++ bindings
request-udp.hpp
1 
2 #ifndef UVCC_REQUEST_UDP__HPP
3 #define UVCC_REQUEST_UDP__HPP
4 
5 #include "uvcc/utility.hpp"
6 #include "uvcc/request-base.hpp"
7 #include "uvcc/handle-udp.hpp"
8 #include "uvcc/buffer.hpp"
9 #include "uvcc/netstruct.hpp"
10 
11 #include <uv.h>
12 
13 #include <functional> // function
14 #include <type_traits> // enable_if_t
15 
16 
17 namespace uv
18 {
19 
20 
21 /*! \ingroup doxy_group__request
22  \brief UDP send request type.
23  \sa libuv API documentation: [`uv_udp_t` — UDP handle](http://docs.libuv.org/en/v1.x/udp.html#uv-udp-t-udp-handle). */
24 class udp_send : public request
25 {
26  //! \cond
27  friend class request::instance< udp_send >;
28  friend class output;
29  //! \endcond
30 
31 public: /*types*/
32  using uv_t = ::uv_udp_send_t;
33  using on_request_t = std::function< void(udp_send _request, buffer _buffer) >;
34  /*!< \brief The function type of the callback called after data was sent.
35  \sa libuv API documentation: [`uv_udp_send_cb`](http://docs.libuv.org/en/v1.x/udp.html#c.uv_udp_send_cb). */
36 
37 protected: /*types*/
38  //! \cond internals
39  //! \addtogroup doxy_group__internals
40  //! \{
41  struct properties : request::properties
42  {
43  buffer::uv_t *uv_buf = nullptr;
44  ::sockaddr_storage peer = { 0,};
45  };
46  //! \}
47  //! \endcond
48 
49 private: /*types*/
50  using instance = request::instance< udp_send >;
51 
52 protected: /*constructors*/
53  //! \cond
54  explicit udp_send(uv_t *_uv_req) : request(reinterpret_cast< request::uv_t* >(_uv_req)) {}
55  //! \endcond
56 
57 public: /*constructors*/
58  ~udp_send() = default;
59  udp_send()
60  {
61  uv_req = instance::create();
62  static_cast< uv_t* >(uv_req)->type = UV_UDP_SEND;
63  }
64 
65  udp_send(const udp_send&) = default;
66  udp_send& operator =(const udp_send&) = default;
67 
68  udp_send(udp_send&&) noexcept = default;
69  udp_send& operator =(udp_send&&) noexcept = default;
70 
71 private: /*functions*/
72  template< typename = void > static void udp_send_cb(::uv_udp_send_t*, int);
73 
74 public: /*interface*/
75  on_request_t& on_request() const noexcept { return instance::from(uv_req)->request_cb_storage.value(); }
76 
77  /*! \brief The UDP handle where this send request has been taking place. */
78  udp handle() const noexcept { return udp(static_cast< uv_t* >(uv_req)->handle); }
79 
80  /*! \brief Get the address of the remote peer which this request has sent data to.
81  \returns `true` if `sizeof(_T_)` is enough to hold the returned socket address structure. */
82  template< typename _T_, typename = std::enable_if_t< is_one_of< _T_, ::sockaddr_in, ::sockaddr_in6, ::sockaddr_storage >::value > >
83  bool getpeername(_T_ &_sockaddr) const noexcept
84  {
85  _sockaddr = reinterpret_cast< _T_& >(instance::from(uv_req)->properties().peer);
86  switch (reinterpret_cast< ::sockaddr >(_sockaddr).sa_family)
87  {
88  case AF_INET: return sizeof(_T_) >= sizeof(::sockaddr_in);
89  case AF_INET6: return sizeof(_T_) >= sizeof(::sockaddr_in6);
90  default: return sizeof(_T_) == sizeof(::sockaddr_storage);
91  }
92  }
93 
94  /*! \brief Run the request.
95  \details Send data over the UDP socket. If the socket has not previously been bound with `udp::bind()`
96  it will be bound to 0.0.0.0 (the “all interfaces” IPv4 address) and a random port number.
97  \sa libuv API documentation: [`uv_udp_send()`](http://docs.libuv.org/en/v1.x/udp.html#c.uv_udp_send). */
98  template<
99  typename _T_,
101  >
102  int run(udp &_udp, const buffer &_buf, const _T_ &_sockaddr)
103  {
104  auto instance_ptr = instance::from(uv_req);
105 
106  udp::instance::from(_udp.uv_handle)->ref();
107  buffer::instance::from(_buf.uv_buf)->ref();
108  instance_ptr->ref();
109 
110  auto &properties = instance_ptr->properties();
111  {
112  properties.uv_buf = _buf.uv_buf;
113  init(properties.peer, reinterpret_cast< const ::sockaddr& >(_sockaddr));
114  }
115 
116  uv_status(0);
117  auto uv_ret = ::uv_udp_send(
118  static_cast< uv_t* >(uv_req), static_cast< udp::uv_t* >(_udp),
119  static_cast< const buffer::uv_t* >(_buf), _buf.count(),
120  reinterpret_cast< const ::sockaddr* >(&_sockaddr),
121  udp_send_cb
122  );
123  if (uv_ret < 0)
124  {
125  uv_status(uv_ret);
126  udp::instance::from(_udp.uv_handle)->unref();
127  buffer::instance::from(_buf.uv_buf)->unref();
128  instance_ptr->unref();
129  }
130 
131  return uv_ret;
132  }
133 
134  /*! \details The wrapper for a corresponding libuv function.
135  \note It tries to execute and complete immediately and does not call the request callback.
136  \sa libuv API documentation: [`uv_udp_try_send()`](http://docs.libuv.org/en/v1.x/udp.html#c.uv_udp_try_send). */
137  template<
138  typename _T_,
140  >
141  int try_send(udp &_udp, const buffer &_buf, const _T_ &_sockaddr)
142  {
143  return uv_status(::uv_udp_try_send(
144  static_cast< udp::uv_t* >(_udp),
145  static_cast< const buffer::uv_t* >(_buf), _buf.count(),
146  reinterpret_cast< const ::sockaddr* >(&_sockaddr)
147  ));
148  }
149 
150 public: /*conversion operators*/
151  explicit operator const uv_t*() const noexcept { return static_cast< const uv_t* >(uv_req); }
152  explicit operator uv_t*() noexcept { return static_cast< uv_t* >(uv_req); }
153 };
154 
155 template< typename >
156 void udp_send::udp_send_cb(::uv_udp_send_t *_uv_req, int _status)
157 {
158  auto instance_ptr = instance::from(_uv_req);
159  instance_ptr->uv_error = _status;
160 
161  ref_guard< udp::instance > unref_handle(*udp::instance::from(_uv_req->handle), adopt_ref);
162  ref_guard< instance > unref_req(*instance_ptr, adopt_ref);
163 
164  auto &udp_send_cb = instance_ptr->request_cb_storage.value();
165  if (udp_send_cb)
166  udp_send_cb(udp_send(_uv_req), buffer(instance_ptr->properties().uv_buf, adopt_ref));
167  else
168  buffer::instance::from(instance_ptr->properties().uv_buf)->unref();
169 }
170 
171 
172 }
173 
174 
175 #endif
Namespace for all uvcc definitions.
Definition: buffer.hpp:17
operator bool() const noexcept
Equivalent to (base() != nullptr).
Definition: buffer.hpp:248
UDP send request type.
Definition: request-udp.hpp:24
The base class for the libuv requests.
udp handle() const noexcept
The UDP handle where this send request has been taking place.
Definition: request-udp.hpp:78
int try_send(udp &_udp, const buffer &_buf, const _T_ &_sockaddr)
UDP handle.
Definition: handle-udp.hpp:23
int run(udp &_udp, const buffer &_buf, const _T_ &_sockaddr)
Run the request.
A scoped reference counting guard.
Definition: utility.hpp:280
bool getpeername(_T_ &_sockaddr) const noexcept
Get the address of the remote peer which this request has sent data to.
Definition: request-udp.hpp:83