uvw  1.3.0
udp.hpp
1 #pragma once
2 
3 
4 #include <type_traits>
5 #include <algorithm>
6 #include <iterator>
7 #include <utility>
8 #include <cstddef>
9 #include <memory>
10 #include <string>
11 #include <uv.h>
12 #include "request.hpp"
13 #include "handle.hpp"
14 #include "util.hpp"
15 
16 
17 namespace uvw {
18 
19 
25 struct SendEvent {};
26 
27 
33 struct UDPDataEvent {
34  explicit UDPDataEvent(Addr sndr, std::unique_ptr<const char[]> buf, std::size_t len, bool part) noexcept
35  : data{std::move(buf)}, length{len}, sender{std::move(sndr)}, partial{part}
36  {}
37 
38  std::unique_ptr<const char[]> data;
39  std::size_t length;
41  bool partial;
42 };
43 
44 
45 namespace details {
46 
47 
48 enum class UVUdpFlags: std::underlying_type_t<uv_udp_flags> {
49  IPV6ONLY = UV_UDP_IPV6ONLY,
50  REUSEADDR = UV_UDP_REUSEADDR
51 };
52 
53 
54 enum class UVMembership: std::underlying_type_t<uv_membership> {
55  LEAVE_GROUP = UV_LEAVE_GROUP,
56  JOIN_GROUP = UV_JOIN_GROUP
57 };
58 
59 
60 class SendReq final: public Request<SendReq, uv_udp_send_t> {
61 public:
62  using Deleter = void(*)(char *);
63 
64  SendReq(ConstructorAccess ca, std::shared_ptr<Loop> loop, std::unique_ptr<char[], Deleter> dt, unsigned int len)
65  : Request<SendReq, uv_udp_send_t>{ca, std::move(loop)},
66  data{std::move(dt)},
67  buf{uv_buf_init(data.get(), len)}
68  {}
69 
70  void send(uv_udp_t *handle, const struct sockaddr* addr) {
71  invoke(&uv_udp_send, get(), handle, &buf, 1, addr, &defaultCallback<SendEvent>);
72  }
73 
74 private:
75  std::unique_ptr<char[], Deleter> data;
76  uv_buf_t buf;
77 };
78 
79 
80 }
81 
82 
99 class UDPHandle final: public Handle<UDPHandle, uv_udp_t> {
100  template<typename I>
101  static void recvCallback(uv_udp_t *handle, ssize_t nread, const uv_buf_t *buf, const sockaddr *addr, unsigned flags) {
102  const typename details::IpTraits<I>::Type *aptr = reinterpret_cast<const typename details::IpTraits<I>::Type *>(addr);
103 
104  UDPHandle &udp = *(static_cast<UDPHandle*>(handle->data));
105  // data will be destroyed no matter of what the value of nread is
106  std::unique_ptr<const char[]> data{buf->base};
107 
108  if(nread > 0) {
109  // data available (can be truncated)
110  udp.publish(UDPDataEvent{details::address<I>(aptr), std::move(data), static_cast<std::size_t>(nread), !(0 == (flags & UV_UDP_PARTIAL))});
111  } else if(nread == 0 && addr == nullptr) {
112  // no more data to be read, doing nothing is fine
113  } else if(nread == 0 && addr != nullptr) {
114  // empty udp packet
115  udp.publish(UDPDataEvent{details::address<I>(aptr), std::move(data), static_cast<std::size_t>(nread), false});
116  } else {
117  // transmission error
118  udp.publish(ErrorEvent(nread));
119  }
120  }
121 
122 public:
123  using Membership = details::UVMembership;
124  using Bind = details::UVUdpFlags;
125  using IPv4 = uvw::IPv4;
126  using IPv6 = uvw::IPv6;
127 
128  using Handle::Handle;
129 
130  explicit UDPHandle(ConstructorAccess ca, std::shared_ptr<Loop> ref, unsigned int f)
131  : Handle{ca, std::move(ref)}, tag{FLAGS}, flags{f}
132  {}
133 
138  bool init() {
139  return (tag == FLAGS)
140  ? initialize(&uv_udp_init_ex, flags)
141  : initialize(&uv_udp_init);
142  }
143 
156  void open(OSSocketHandle socket) {
157  invoke(&uv_udp_open, get(), socket);
158  }
159 
176  template<typename I = IPv4>
177  void bind(std::string ip, unsigned int port, Flags<Bind> opts = Flags<Bind>{}) {
178  typename details::IpTraits<I>::Type addr;
179  details::IpTraits<I>::addrFunc(ip.data(), port, &addr);
180  invoke(&uv_udp_bind, get(), reinterpret_cast<const sockaddr *>(&addr), opts);
181  }
182 
198  template<typename I = IPv4>
199  void bind(Addr addr, Flags<Bind> opts = Flags<Bind>{}) {
200  bind<I>(addr.ip, addr.port, opts);
201  }
202 
207  template<typename I = IPv4>
208  Addr sock() const noexcept {
209  return details::address<I>(&uv_udp_getsockname, get());
210  }
211 
225  template<typename I = IPv4>
226  bool multicastMembership(std::string multicast, std::string iface, Membership membership) {
227  return (0 == uv_udp_set_membership(get(), multicast.data(), iface.data(), static_cast<uv_membership>(membership)));
228  }
229 
238  bool multicastLoop(bool enable = true) {
239  return (0 == uv_udp_set_multicast_loop(get(), enable));
240  }
241 
247  bool multicastTtl(int val) {
248  return (0 == uv_udp_set_multicast_ttl(get(), val > 255 ? 255 : val));
249  }
250 
256  template<typename I = IPv4>
257  bool multicastInterface(std::string iface) {
258  return (0 == uv_udp_set_multicast_interface(get(), iface.data()));
259  }
260 
266  bool broadcast(bool enable = false) {
267  return (0 == uv_udp_set_broadcast(get(), enable));
268  }
269 
275  bool ttl(int val) {
276  return (0 == uv_udp_set_ttl(get(), val > 255 ? 255 : val));
277  }
278 
297  template<typename I = IPv4>
298  void send(std::string ip, unsigned int port, std::unique_ptr<char[]> data, unsigned int len) {
299  typename details::IpTraits<I>::Type addr;
300  details::IpTraits<I>::addrFunc(ip.data(), port, &addr);
301 
302  auto req = loop().resource<details::SendReq>(
303  std::unique_ptr<char[], details::SendReq::Deleter>{
304  data.release(), [](char *ptr) { delete[] ptr; }
305  }, len);
306 
307  auto listener = [ptr = shared_from_this()](const auto &event, const auto &) {
308  ptr->publish(event);
309  };
310 
311  req->once<ErrorEvent>(listener);
312  req->once<SendEvent>(listener);
313  req->send(get(), reinterpret_cast<const sockaddr *>(&addr));
314  }
315 
333  template<typename I = IPv4>
334  void send(Addr addr, std::unique_ptr<char[]> data, unsigned int len) {
335  send<I>(addr.ip, addr.port, std::move(data), len);
336  }
337 
356  template<typename I = IPv4>
357  void send(std::string ip, unsigned int port, char *data, unsigned int len) {
358  typename details::IpTraits<I>::Type addr;
359  details::IpTraits<I>::addrFunc(ip.data(), port, &addr);
360 
361  auto req = loop().resource<details::SendReq>(
362  std::unique_ptr<char[], details::SendReq::Deleter>{
363  data, [](char *) {}
364  }, len);
365 
366  auto listener = [ptr = shared_from_this()](const auto &event, const auto &) {
367  ptr->publish(event);
368  };
369 
370  req->once<ErrorEvent>(listener);
371  req->once<SendEvent>(listener);
372  req->send(get(), reinterpret_cast<const sockaddr *>(&addr));
373  }
374 
392  template<typename I = IPv4>
393  void send(Addr addr, char *data, unsigned int len) {
394  send<I>(addr.ip, addr.port, data, len);
395  }
396 
409  template<typename I = IPv4>
410  int trySend(std::string ip, unsigned int port, std::unique_ptr<char[]> data, unsigned int len) {
411  typename details::IpTraits<I>::Type addr;
412  details::IpTraits<I>::addrFunc(ip.data(), port, &addr);
413 
414  uv_buf_t bufs[] = { uv_buf_init(data.get(), len) };
415  auto bw = uv_udp_try_send(get(), bufs, 1, reinterpret_cast<const sockaddr *>(&addr));
416 
417  if(bw < 0) {
418  publish(ErrorEvent{bw});
419  bw = 0;
420  }
421 
422  return bw;
423  }
424 
436  template<typename I = IPv4>
437  int trySend(Addr addr, std::unique_ptr<char[]> data, unsigned int len) {
438  return trySend<I>(addr.ip, addr.port, std::move(data), len);
439  }
440 
453  template<typename I = IPv4>
454  int trySend(std::string ip, unsigned int port, char *data, unsigned int len) {
455  typename details::IpTraits<I>::Type addr;
456  details::IpTraits<I>::addrFunc(ip.data(), port, &addr);
457 
458  uv_buf_t bufs[] = { uv_buf_init(data, len) };
459  auto bw = uv_udp_try_send(get(), bufs, 1, reinterpret_cast<const sockaddr *>(&addr));
460 
461  if(bw < 0) {
462  publish(ErrorEvent{bw});
463  bw = 0;
464  }
465 
466  return bw;
467  }
468 
480  template<typename I = IPv4>
481  int trySend(Addr addr, char *data, unsigned int len) {
482  return trySend<I>(addr.ip, addr.port, data, len);
483  }
484 
495  template<typename I = IPv4>
496  void recv() {
497  invoke(&uv_udp_recv_start, get(), &allocCallback, &recvCallback<I>);
498  }
499 
503  void stop() {
504  invoke(&uv_udp_recv_stop, get());
505  }
506 
507 private:
508  enum { DEFAULT, FLAGS } tag{DEFAULT};
509  unsigned int flags{};
510 };
511 
512 
513 }
Address representation.
Definition: util.hpp:286
bool init()
Initializes the handle. The actual socket is created lazily.
Definition: udp.hpp:138
unsigned int port
Definition: util.hpp:288
int trySend(Addr addr, std::unique_ptr< char[]> data, unsigned int len)
Sends data over the UDP socket.
Definition: udp.hpp:437
std::string ip
Definition: util.hpp:287
bool ttl(int val)
Sets the time to live.
Definition: udp.hpp:275
void recv()
Prepares for receiving data.
Definition: udp.hpp:496
void bind(Addr addr, Flags< Bind > opts=Flags< Bind >{})
Binds the UDP handle to an IP address and port.
Definition: udp.hpp:199
void send(std::string ip, unsigned int port, char *data, unsigned int len)
Sends data over the UDP socket.
Definition: udp.hpp:357
void send(Addr addr, char *data, unsigned int len)
Sends data over the UDP socket.
Definition: udp.hpp:393
UDPDataEvent event.
Definition: udp.hpp:33
bool multicastMembership(std::string multicast, std::string iface, Membership membership)
Sets membership for a multicast address.
Definition: udp.hpp:226
Utility class to handle flags.
Definition: util.hpp:77
Handle base class.
Definition: handle.hpp:29
std::size_t length
Definition: udp.hpp:39
void send(Addr addr, std::unique_ptr< char[]> data, unsigned int len)
Sends data over the UDP socket.
Definition: udp.hpp:334
SendEvent event.
Definition: udp.hpp:25
void stop()
Stops listening for incoming datagrams.
Definition: udp.hpp:503
The IPv6 tag.
Definition: util.hpp:280
std::unique_ptr< const char[]> data
Definition: udp.hpp:38
void open(OSSocketHandle socket)
Opens an existing file descriptor or SOCKET as a UDP handle.
Definition: udp.hpp:156
bool partial
Definition: udp.hpp:41
int trySend(std::string ip, unsigned int port, std::unique_ptr< char[]> data, unsigned int len)
Sends data over the UDP socket.
Definition: udp.hpp:410
The ErrorEvent event.
Definition: emitter.hpp:23
bool multicastInterface(std::string iface)
Sets the multicast interface to send or receive data on.
Definition: udp.hpp:257
int trySend(Addr addr, char *data, unsigned int len)
Sends data over the UDP socket.
Definition: udp.hpp:481
details::UVTypeWrapper< uv_os_sock_t > OSSocketHandle
Definition: util.hpp:187
bool broadcast(bool enable=false)
Sets broadcast on or off.
Definition: udp.hpp:266
bool multicastTtl(int val)
Sets the multicast ttl.
Definition: udp.hpp:247
The UDPHandle handle.
Definition: udp.hpp:99
void send(std::string ip, unsigned int port, std::unique_ptr< char[]> data, unsigned int len)
Sends data over the UDP socket.
Definition: udp.hpp:298
bool multicastLoop(bool enable=true)
Sets IP multicast loop flag.
Definition: udp.hpp:238
int trySend(std::string ip, unsigned int port, char *data, unsigned int len)
Sends data over the UDP socket.
Definition: udp.hpp:454
void bind(std::string ip, unsigned int port, Flags< Bind > opts=Flags< Bind >{})
Binds the UDP handle to an IP address and port.
Definition: udp.hpp:177
The IPv4 tag.
Definition: util.hpp:272
Addr sock() const noexcept
Get the local IP and port of the UDP handle.
Definition: udp.hpp:208
uvw default namespace.
Definition: async.hpp:11