|  | @@ -42,6 +42,11 @@
 | 
	
		
			
				|  |  |  # define IPV6_DROP_MEMBERSHIP IPV6_LEAVE_GROUP
 | 
	
		
			
				|  |  |  #endif
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +union uv__sockaddr {
 | 
	
		
			
				|  |  | +  struct sockaddr_in6 in6;
 | 
	
		
			
				|  |  | +  struct sockaddr_in in;
 | 
	
		
			
				|  |  | +  struct sockaddr addr;
 | 
	
		
			
				|  |  | +};
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  static void uv__udp_run_completed(uv_udp_t* handle);
 | 
	
		
			
				|  |  |  static void uv__udp_io(uv_loop_t* loop, uv__io_t* w, unsigned int revents);
 | 
	
	
		
			
				|  | @@ -68,12 +73,12 @@ static void uv__udp_mmsg_init(void) {
 | 
	
		
			
				|  |  |    s = uv__socket(AF_INET, SOCK_DGRAM, 0);
 | 
	
		
			
				|  |  |    if (s < 0)
 | 
	
		
			
				|  |  |      return;
 | 
	
		
			
				|  |  | -  ret = uv__sendmmsg(s, NULL, 0, 0);
 | 
	
		
			
				|  |  | +  ret = uv__sendmmsg(s, NULL, 0);
 | 
	
		
			
				|  |  |    if (ret == 0 || errno != ENOSYS) {
 | 
	
		
			
				|  |  |      uv__sendmmsg_avail = 1;
 | 
	
		
			
				|  |  |      uv__recvmmsg_avail = 1;
 | 
	
		
			
				|  |  |    } else {
 | 
	
		
			
				|  |  | -    ret = uv__recvmmsg(s, NULL, 0, 0, NULL);
 | 
	
		
			
				|  |  | +    ret = uv__recvmmsg(s, NULL, 0);
 | 
	
		
			
				|  |  |      if (ret == 0 || errno != ENOSYS)
 | 
	
		
			
				|  |  |        uv__recvmmsg_avail = 1;
 | 
	
		
			
				|  |  |    }
 | 
	
	
		
			
				|  | @@ -208,7 +213,7 @@ static int uv__udp_recvmmsg(uv_udp_t* handle, uv_buf_t* buf) {
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |    do
 | 
	
		
			
				|  |  | -    nread = uv__recvmmsg(handle->io_watcher.fd, msgs, chunks, 0, NULL);
 | 
	
		
			
				|  |  | +    nread = uv__recvmmsg(handle->io_watcher.fd, msgs, chunks);
 | 
	
		
			
				|  |  |    while (nread == -1 && errno == EINTR);
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |    if (nread < 1) {
 | 
	
	
		
			
				|  | @@ -233,7 +238,7 @@ static int uv__udp_recvmmsg(uv_udp_t* handle, uv_buf_t* buf) {
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |      /* one last callback so the original buffer is freed */
 | 
	
		
			
				|  |  |      if (handle->recv_cb != NULL)
 | 
	
		
			
				|  |  | -      handle->recv_cb(handle, 0, buf, NULL, 0);
 | 
	
		
			
				|  |  | +      handle->recv_cb(handle, 0, buf, NULL, UV_UDP_MMSG_FREE);
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |    return nread;
 | 
	
		
			
				|  |  |  }
 | 
	
	
		
			
				|  | @@ -265,14 +270,11 @@ static void uv__udp_recvmsg(uv_udp_t* handle) {
 | 
	
		
			
				|  |  |      assert(buf.base != NULL);
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  #if HAVE_MMSG
 | 
	
		
			
				|  |  | -    if (handle->flags & UV_HANDLE_UDP_RECVMMSG) {
 | 
	
		
			
				|  |  | -      uv_once(&once, uv__udp_mmsg_init);
 | 
	
		
			
				|  |  | -      if (uv__recvmmsg_avail) {
 | 
	
		
			
				|  |  | -        nread = uv__udp_recvmmsg(handle, &buf);
 | 
	
		
			
				|  |  | -        if (nread > 0)
 | 
	
		
			
				|  |  | -          count -= nread;
 | 
	
		
			
				|  |  | -        continue;
 | 
	
		
			
				|  |  | -      }
 | 
	
		
			
				|  |  | +    if (uv_udp_using_recvmmsg(handle)) {
 | 
	
		
			
				|  |  | +      nread = uv__udp_recvmmsg(handle, &buf);
 | 
	
		
			
				|  |  | +      if (nread > 0)
 | 
	
		
			
				|  |  | +        count -= nread;
 | 
	
		
			
				|  |  | +      continue;
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |  #endif
 | 
	
		
			
				|  |  |  
 | 
	
	
		
			
				|  | @@ -354,7 +356,7 @@ write_queue_drain:
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |    do
 | 
	
		
			
				|  |  | -    npkts = uv__sendmmsg(handle->io_watcher.fd, h, pkts, 0);
 | 
	
		
			
				|  |  | +    npkts = uv__sendmmsg(handle->io_watcher.fd, h, pkts);
 | 
	
		
			
				|  |  |    while (npkts == -1 && errno == EINTR);
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |    if (npkts < 1) {
 | 
	
	
		
			
				|  | @@ -362,7 +364,7 @@ write_queue_drain:
 | 
	
		
			
				|  |  |        return;
 | 
	
		
			
				|  |  |      for (i = 0, q = QUEUE_HEAD(&handle->write_queue);
 | 
	
		
			
				|  |  |           i < pkts && q != &handle->write_queue;
 | 
	
		
			
				|  |  | -         ++i, q = QUEUE_HEAD(q)) {
 | 
	
		
			
				|  |  | +         ++i, q = QUEUE_HEAD(&handle->write_queue)) {
 | 
	
		
			
				|  |  |        assert(q != NULL);
 | 
	
		
			
				|  |  |        req = QUEUE_DATA(q, uv_udp_send_t, queue);
 | 
	
		
			
				|  |  |        assert(req != NULL);
 | 
	
	
		
			
				|  | @@ -567,11 +569,7 @@ int uv__udp_bind(uv_udp_t* handle,
 | 
	
		
			
				|  |  |  static int uv__udp_maybe_deferred_bind(uv_udp_t* handle,
 | 
	
		
			
				|  |  |                                         int domain,
 | 
	
		
			
				|  |  |                                         unsigned int flags) {
 | 
	
		
			
				|  |  | -  union {
 | 
	
		
			
				|  |  | -    struct sockaddr_in6 in6;
 | 
	
		
			
				|  |  | -    struct sockaddr_in in;
 | 
	
		
			
				|  |  | -    struct sockaddr addr;
 | 
	
		
			
				|  |  | -  } taddr;
 | 
	
		
			
				|  |  | +  union uv__sockaddr taddr;
 | 
	
		
			
				|  |  |    socklen_t addrlen;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |    if (handle->io_watcher.fd != -1)
 | 
	
	
		
			
				|  | @@ -853,7 +851,11 @@ static int uv__udp_set_membership6(uv_udp_t* handle,
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -#if !defined(__OpenBSD__) && !defined(__NetBSD__) && !defined(__ANDROID__)
 | 
	
		
			
				|  |  | +#if !defined(__OpenBSD__) &&                                        \
 | 
	
		
			
				|  |  | +    !defined(__NetBSD__) &&                                         \
 | 
	
		
			
				|  |  | +    !defined(__ANDROID__) &&                                        \
 | 
	
		
			
				|  |  | +    !defined(__DragonFly__) &                                       \
 | 
	
		
			
				|  |  | +    !defined(__QNX__)
 | 
	
		
			
				|  |  |  static int uv__udp_set_source_membership4(uv_udp_t* handle,
 | 
	
		
			
				|  |  |                                            const struct sockaddr_in* multicast_addr,
 | 
	
		
			
				|  |  |                                            const char* interface_addr,
 | 
	
	
		
			
				|  | @@ -924,8 +926,10 @@ static int uv__udp_set_source_membership6(uv_udp_t* handle,
 | 
	
		
			
				|  |  |      mreq.gsr_interface = 0;
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -  memcpy(&mreq.gsr_group, multicast_addr, sizeof(mreq.gsr_group));
 | 
	
		
			
				|  |  | -  memcpy(&mreq.gsr_source, source_addr, sizeof(mreq.gsr_source));
 | 
	
		
			
				|  |  | +  STATIC_ASSERT(sizeof(mreq.gsr_group) >= sizeof(*multicast_addr));
 | 
	
		
			
				|  |  | +  STATIC_ASSERT(sizeof(mreq.gsr_source) >= sizeof(*source_addr));
 | 
	
		
			
				|  |  | +  memcpy(&mreq.gsr_group, multicast_addr, sizeof(*multicast_addr));
 | 
	
		
			
				|  |  | +  memcpy(&mreq.gsr_source, source_addr, sizeof(*source_addr));
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |    if (membership == UV_JOIN_GROUP)
 | 
	
		
			
				|  |  |      optname = MCAST_JOIN_SOURCE_GROUP;
 | 
	
	
		
			
				|  | @@ -973,6 +977,17 @@ int uv__udp_init_ex(uv_loop_t* loop,
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +int uv_udp_using_recvmmsg(const uv_udp_t* handle) {
 | 
	
		
			
				|  |  | +#if HAVE_MMSG
 | 
	
		
			
				|  |  | +  if (handle->flags & UV_HANDLE_UDP_RECVMMSG) {
 | 
	
		
			
				|  |  | +    uv_once(&once, uv__udp_mmsg_init);
 | 
	
		
			
				|  |  | +    return uv__recvmmsg_avail;
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +#endif
 | 
	
		
			
				|  |  | +  return 0;
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |  int uv_udp_open(uv_udp_t* handle, uv_os_sock_t sock) {
 | 
	
		
			
				|  |  |    int err;
 | 
	
		
			
				|  |  |  
 | 
	
	
		
			
				|  | @@ -1028,42 +1043,37 @@ int uv_udp_set_source_membership(uv_udp_t* handle,
 | 
	
		
			
				|  |  |                                   const char* interface_addr,
 | 
	
		
			
				|  |  |                                   const char* source_addr,
 | 
	
		
			
				|  |  |                                   uv_membership membership) {
 | 
	
		
			
				|  |  | -#if !defined(__OpenBSD__) && !defined(__NetBSD__) && !defined(__ANDROID__)
 | 
	
		
			
				|  |  | +#if !defined(__OpenBSD__) &&                                        \
 | 
	
		
			
				|  |  | +    !defined(__NetBSD__) &&                                         \
 | 
	
		
			
				|  |  | +    !defined(__ANDROID__) &&                                        \
 | 
	
		
			
				|  |  | +    !defined(__DragonFly__) &&                                      \
 | 
	
		
			
				|  |  | +    !defined(__QNX__)
 | 
	
		
			
				|  |  |    int err;
 | 
	
		
			
				|  |  | -  struct sockaddr_storage mcast_addr;
 | 
	
		
			
				|  |  | -  struct sockaddr_in* mcast_addr4;
 | 
	
		
			
				|  |  | -  struct sockaddr_in6* mcast_addr6;
 | 
	
		
			
				|  |  | -  struct sockaddr_storage src_addr;
 | 
	
		
			
				|  |  | -  struct sockaddr_in* src_addr4;
 | 
	
		
			
				|  |  | -  struct sockaddr_in6* src_addr6;
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  mcast_addr4 = (struct sockaddr_in*)&mcast_addr;
 | 
	
		
			
				|  |  | -  mcast_addr6 = (struct sockaddr_in6*)&mcast_addr;
 | 
	
		
			
				|  |  | -  src_addr4 = (struct sockaddr_in*)&src_addr;
 | 
	
		
			
				|  |  | -  src_addr6 = (struct sockaddr_in6*)&src_addr;
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  err = uv_ip4_addr(multicast_addr, 0, mcast_addr4);
 | 
	
		
			
				|  |  | +  union uv__sockaddr mcast_addr;
 | 
	
		
			
				|  |  | +  union uv__sockaddr src_addr;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  err = uv_ip4_addr(multicast_addr, 0, &mcast_addr.in);
 | 
	
		
			
				|  |  |    if (err) {
 | 
	
		
			
				|  |  | -    err = uv_ip6_addr(multicast_addr, 0, mcast_addr6);
 | 
	
		
			
				|  |  | +    err = uv_ip6_addr(multicast_addr, 0, &mcast_addr.in6);
 | 
	
		
			
				|  |  |      if (err)
 | 
	
		
			
				|  |  |        return err;
 | 
	
		
			
				|  |  | -    err = uv_ip6_addr(source_addr, 0, src_addr6);
 | 
	
		
			
				|  |  | +    err = uv_ip6_addr(source_addr, 0, &src_addr.in6);
 | 
	
		
			
				|  |  |      if (err)
 | 
	
		
			
				|  |  |        return err;
 | 
	
		
			
				|  |  |      return uv__udp_set_source_membership6(handle,
 | 
	
		
			
				|  |  | -                                          mcast_addr6,
 | 
	
		
			
				|  |  | +                                          &mcast_addr.in6,
 | 
	
		
			
				|  |  |                                            interface_addr,
 | 
	
		
			
				|  |  | -                                          src_addr6,
 | 
	
		
			
				|  |  | +                                          &src_addr.in6,
 | 
	
		
			
				|  |  |                                            membership);
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -  err = uv_ip4_addr(source_addr, 0, src_addr4);
 | 
	
		
			
				|  |  | +  err = uv_ip4_addr(source_addr, 0, &src_addr.in);
 | 
	
		
			
				|  |  |    if (err)
 | 
	
		
			
				|  |  |      return err;
 | 
	
		
			
				|  |  |    return uv__udp_set_source_membership4(handle,
 | 
	
		
			
				|  |  | -                                        mcast_addr4,
 | 
	
		
			
				|  |  | +                                        &mcast_addr.in,
 | 
	
		
			
				|  |  |                                          interface_addr,
 | 
	
		
			
				|  |  | -                                        src_addr4,
 | 
	
		
			
				|  |  | +                                        &src_addr.in,
 | 
	
		
			
				|  |  |                                          membership);
 | 
	
		
			
				|  |  |  #else
 | 
	
		
			
				|  |  |    return UV_ENOSYS;
 | 
	
	
		
			
				|  | @@ -1144,7 +1154,7 @@ int uv_udp_set_ttl(uv_udp_t* handle, int ttl) {
 | 
	
		
			
				|  |  |   * and use the general uv__setsockopt_maybe_char call on other platforms.
 | 
	
		
			
				|  |  |   */
 | 
	
		
			
				|  |  |  #if defined(__sun) || defined(_AIX) || defined(__OpenBSD__) || \
 | 
	
		
			
				|  |  | -    defined(__MVS__)
 | 
	
		
			
				|  |  | +    defined(__MVS__) || defined(__QNX__)
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |    return uv__setsockopt(handle,
 | 
	
		
			
				|  |  |                          IP_TTL,
 | 
	
	
		
			
				|  | @@ -1153,7 +1163,7 @@ int uv_udp_set_ttl(uv_udp_t* handle, int ttl) {
 | 
	
		
			
				|  |  |                          sizeof(ttl));
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  #else /* !(defined(__sun) || defined(_AIX) || defined (__OpenBSD__) ||
 | 
	
		
			
				|  |  | -           defined(__MVS__)) */
 | 
	
		
			
				|  |  | +           defined(__MVS__) || defined(__QNX__)) */
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |    return uv__setsockopt_maybe_char(handle,
 | 
	
		
			
				|  |  |                                     IP_TTL,
 | 
	
	
		
			
				|  | @@ -1161,7 +1171,7 @@ int uv_udp_set_ttl(uv_udp_t* handle, int ttl) {
 | 
	
		
			
				|  |  |                                     ttl);
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  #endif /* defined(__sun) || defined(_AIX) || defined (__OpenBSD__) ||
 | 
	
		
			
				|  |  | -          defined(__MVS__) */
 | 
	
		
			
				|  |  | +          defined(__MVS__) || defined(__QNX__) */
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  
 | 
	
	
		
			
				|  | @@ -1173,7 +1183,7 @@ int uv_udp_set_multicast_ttl(uv_udp_t* handle, int ttl) {
 | 
	
		
			
				|  |  |   * and use the general uv__setsockopt_maybe_char call otherwise.
 | 
	
		
			
				|  |  |   */
 | 
	
		
			
				|  |  |  #if defined(__sun) || defined(_AIX) || defined(__OpenBSD__) || \
 | 
	
		
			
				|  |  | -    defined(__MVS__)
 | 
	
		
			
				|  |  | +    defined(__MVS__) || defined(__QNX__)
 | 
	
		
			
				|  |  |    if (handle->flags & UV_HANDLE_IPV6)
 | 
	
		
			
				|  |  |      return uv__setsockopt(handle,
 | 
	
		
			
				|  |  |                            IP_MULTICAST_TTL,
 | 
	
	
		
			
				|  | @@ -1181,7 +1191,7 @@ int uv_udp_set_multicast_ttl(uv_udp_t* handle, int ttl) {
 | 
	
		
			
				|  |  |                            &ttl,
 | 
	
		
			
				|  |  |                            sizeof(ttl));
 | 
	
		
			
				|  |  |  #endif /* defined(__sun) || defined(_AIX) || defined(__OpenBSD__) || \
 | 
	
		
			
				|  |  | -    defined(__MVS__) */
 | 
	
		
			
				|  |  | +    defined(__MVS__) || defined(__QNX__) */
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |    return uv__setsockopt_maybe_char(handle,
 | 
	
		
			
				|  |  |                                     IP_MULTICAST_TTL,
 | 
	
	
		
			
				|  | @@ -1198,7 +1208,7 @@ int uv_udp_set_multicast_loop(uv_udp_t* handle, int on) {
 | 
	
		
			
				|  |  |   * and use the general uv__setsockopt_maybe_char call otherwise.
 | 
	
		
			
				|  |  |   */
 | 
	
		
			
				|  |  |  #if defined(__sun) || defined(_AIX) || defined(__OpenBSD__) || \
 | 
	
		
			
				|  |  | -    defined(__MVS__)
 | 
	
		
			
				|  |  | +    defined(__MVS__) || defined(__QNX__)
 | 
	
		
			
				|  |  |    if (handle->flags & UV_HANDLE_IPV6)
 | 
	
		
			
				|  |  |      return uv__setsockopt(handle,
 | 
	
		
			
				|  |  |                            IP_MULTICAST_LOOP,
 | 
	
	
		
			
				|  | @@ -1206,7 +1216,7 @@ int uv_udp_set_multicast_loop(uv_udp_t* handle, int on) {
 | 
	
		
			
				|  |  |                            &on,
 | 
	
		
			
				|  |  |                            sizeof(on));
 | 
	
		
			
				|  |  |  #endif /* defined(__sun) || defined(_AIX) ||defined(__OpenBSD__) ||
 | 
	
		
			
				|  |  | -    defined(__MVS__) */
 | 
	
		
			
				|  |  | +    defined(__MVS__) || defined(__QNX__) */
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |    return uv__setsockopt_maybe_char(handle,
 | 
	
		
			
				|  |  |                                     IP_MULTICAST_LOOP,
 |