11cb0ef41Sopenharmony_ci/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
21cb0ef41Sopenharmony_ci *
31cb0ef41Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a copy
41cb0ef41Sopenharmony_ci * of this software and associated documentation files (the "Software"), to
51cb0ef41Sopenharmony_ci * deal in the Software without restriction, including without limitation the
61cb0ef41Sopenharmony_ci * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
71cb0ef41Sopenharmony_ci * sell copies of the Software, and to permit persons to whom the Software is
81cb0ef41Sopenharmony_ci * furnished to do so, subject to the following conditions:
91cb0ef41Sopenharmony_ci *
101cb0ef41Sopenharmony_ci * The above copyright notice and this permission notice shall be included in
111cb0ef41Sopenharmony_ci * all copies or substantial portions of the Software.
121cb0ef41Sopenharmony_ci *
131cb0ef41Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
141cb0ef41Sopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
151cb0ef41Sopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
161cb0ef41Sopenharmony_ci * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
171cb0ef41Sopenharmony_ci * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
181cb0ef41Sopenharmony_ci * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
191cb0ef41Sopenharmony_ci * IN THE SOFTWARE.
201cb0ef41Sopenharmony_ci */
211cb0ef41Sopenharmony_ci
221cb0ef41Sopenharmony_ci#include "uv.h"
231cb0ef41Sopenharmony_ci#include "internal.h"
241cb0ef41Sopenharmony_ci
251cb0ef41Sopenharmony_ci#include <assert.h>
261cb0ef41Sopenharmony_ci#include <string.h>
271cb0ef41Sopenharmony_ci#include <errno.h>
281cb0ef41Sopenharmony_ci#include <stdlib.h>
291cb0ef41Sopenharmony_ci#include <unistd.h>
301cb0ef41Sopenharmony_ci#if defined(__MVS__)
311cb0ef41Sopenharmony_ci#include <xti.h>
321cb0ef41Sopenharmony_ci#endif
331cb0ef41Sopenharmony_ci#include <sys/un.h>
341cb0ef41Sopenharmony_ci
351cb0ef41Sopenharmony_ci#if defined(IPV6_JOIN_GROUP) && !defined(IPV6_ADD_MEMBERSHIP)
361cb0ef41Sopenharmony_ci# define IPV6_ADD_MEMBERSHIP IPV6_JOIN_GROUP
371cb0ef41Sopenharmony_ci#endif
381cb0ef41Sopenharmony_ci
391cb0ef41Sopenharmony_ci#if defined(IPV6_LEAVE_GROUP) && !defined(IPV6_DROP_MEMBERSHIP)
401cb0ef41Sopenharmony_ci# define IPV6_DROP_MEMBERSHIP IPV6_LEAVE_GROUP
411cb0ef41Sopenharmony_ci#endif
421cb0ef41Sopenharmony_ci
431cb0ef41Sopenharmony_ciunion uv__sockaddr {
441cb0ef41Sopenharmony_ci  struct sockaddr_in6 in6;
451cb0ef41Sopenharmony_ci  struct sockaddr_in in;
461cb0ef41Sopenharmony_ci  struct sockaddr addr;
471cb0ef41Sopenharmony_ci};
481cb0ef41Sopenharmony_ci
491cb0ef41Sopenharmony_cistatic void uv__udp_run_completed(uv_udp_t* handle);
501cb0ef41Sopenharmony_cistatic void uv__udp_io(uv_loop_t* loop, uv__io_t* w, unsigned int revents);
511cb0ef41Sopenharmony_cistatic void uv__udp_recvmsg(uv_udp_t* handle);
521cb0ef41Sopenharmony_cistatic void uv__udp_sendmsg(uv_udp_t* handle);
531cb0ef41Sopenharmony_cistatic int uv__udp_maybe_deferred_bind(uv_udp_t* handle,
541cb0ef41Sopenharmony_ci                                       int domain,
551cb0ef41Sopenharmony_ci                                       unsigned int flags);
561cb0ef41Sopenharmony_ci
571cb0ef41Sopenharmony_ci#if HAVE_MMSG
581cb0ef41Sopenharmony_ci
591cb0ef41Sopenharmony_ci#define UV__MMSG_MAXWIDTH 20
601cb0ef41Sopenharmony_ci
611cb0ef41Sopenharmony_cistatic int uv__udp_recvmmsg(uv_udp_t* handle, uv_buf_t* buf);
621cb0ef41Sopenharmony_cistatic void uv__udp_sendmmsg(uv_udp_t* handle);
631cb0ef41Sopenharmony_ci
641cb0ef41Sopenharmony_cistatic int uv__recvmmsg_avail;
651cb0ef41Sopenharmony_cistatic int uv__sendmmsg_avail;
661cb0ef41Sopenharmony_cistatic uv_once_t once = UV_ONCE_INIT;
671cb0ef41Sopenharmony_ci
681cb0ef41Sopenharmony_cistatic void uv__udp_mmsg_init(void) {
691cb0ef41Sopenharmony_ci  int ret;
701cb0ef41Sopenharmony_ci  int s;
711cb0ef41Sopenharmony_ci  s = uv__socket(AF_INET, SOCK_DGRAM, 0);
721cb0ef41Sopenharmony_ci  if (s < 0)
731cb0ef41Sopenharmony_ci    return;
741cb0ef41Sopenharmony_ci  ret = uv__sendmmsg(s, NULL, 0);
751cb0ef41Sopenharmony_ci  if (ret == 0 || errno != ENOSYS) {
761cb0ef41Sopenharmony_ci    uv__sendmmsg_avail = 1;
771cb0ef41Sopenharmony_ci    uv__recvmmsg_avail = 1;
781cb0ef41Sopenharmony_ci  } else {
791cb0ef41Sopenharmony_ci    ret = uv__recvmmsg(s, NULL, 0);
801cb0ef41Sopenharmony_ci    if (ret == 0 || errno != ENOSYS)
811cb0ef41Sopenharmony_ci      uv__recvmmsg_avail = 1;
821cb0ef41Sopenharmony_ci  }
831cb0ef41Sopenharmony_ci  uv__close(s);
841cb0ef41Sopenharmony_ci}
851cb0ef41Sopenharmony_ci
861cb0ef41Sopenharmony_ci#endif
871cb0ef41Sopenharmony_ci
881cb0ef41Sopenharmony_civoid uv__udp_close(uv_udp_t* handle) {
891cb0ef41Sopenharmony_ci  uv__io_close(handle->loop, &handle->io_watcher);
901cb0ef41Sopenharmony_ci  uv__handle_stop(handle);
911cb0ef41Sopenharmony_ci
921cb0ef41Sopenharmony_ci  if (handle->io_watcher.fd != -1) {
931cb0ef41Sopenharmony_ci    uv__close(handle->io_watcher.fd);
941cb0ef41Sopenharmony_ci    handle->io_watcher.fd = -1;
951cb0ef41Sopenharmony_ci  }
961cb0ef41Sopenharmony_ci}
971cb0ef41Sopenharmony_ci
981cb0ef41Sopenharmony_ci
991cb0ef41Sopenharmony_civoid uv__udp_finish_close(uv_udp_t* handle) {
1001cb0ef41Sopenharmony_ci  uv_udp_send_t* req;
1011cb0ef41Sopenharmony_ci  QUEUE* q;
1021cb0ef41Sopenharmony_ci
1031cb0ef41Sopenharmony_ci  assert(!uv__io_active(&handle->io_watcher, POLLIN | POLLOUT));
1041cb0ef41Sopenharmony_ci  assert(handle->io_watcher.fd == -1);
1051cb0ef41Sopenharmony_ci
1061cb0ef41Sopenharmony_ci  while (!QUEUE_EMPTY(&handle->write_queue)) {
1071cb0ef41Sopenharmony_ci    q = QUEUE_HEAD(&handle->write_queue);
1081cb0ef41Sopenharmony_ci    QUEUE_REMOVE(q);
1091cb0ef41Sopenharmony_ci
1101cb0ef41Sopenharmony_ci    req = QUEUE_DATA(q, uv_udp_send_t, queue);
1111cb0ef41Sopenharmony_ci    req->status = UV_ECANCELED;
1121cb0ef41Sopenharmony_ci    QUEUE_INSERT_TAIL(&handle->write_completed_queue, &req->queue);
1131cb0ef41Sopenharmony_ci  }
1141cb0ef41Sopenharmony_ci
1151cb0ef41Sopenharmony_ci  uv__udp_run_completed(handle);
1161cb0ef41Sopenharmony_ci
1171cb0ef41Sopenharmony_ci  assert(handle->send_queue_size == 0);
1181cb0ef41Sopenharmony_ci  assert(handle->send_queue_count == 0);
1191cb0ef41Sopenharmony_ci
1201cb0ef41Sopenharmony_ci  /* Now tear down the handle. */
1211cb0ef41Sopenharmony_ci  handle->recv_cb = NULL;
1221cb0ef41Sopenharmony_ci  handle->alloc_cb = NULL;
1231cb0ef41Sopenharmony_ci  /* but _do not_ touch close_cb */
1241cb0ef41Sopenharmony_ci}
1251cb0ef41Sopenharmony_ci
1261cb0ef41Sopenharmony_ci
1271cb0ef41Sopenharmony_cistatic void uv__udp_run_completed(uv_udp_t* handle) {
1281cb0ef41Sopenharmony_ci  uv_udp_send_t* req;
1291cb0ef41Sopenharmony_ci  QUEUE* q;
1301cb0ef41Sopenharmony_ci
1311cb0ef41Sopenharmony_ci  assert(!(handle->flags & UV_HANDLE_UDP_PROCESSING));
1321cb0ef41Sopenharmony_ci  handle->flags |= UV_HANDLE_UDP_PROCESSING;
1331cb0ef41Sopenharmony_ci
1341cb0ef41Sopenharmony_ci  while (!QUEUE_EMPTY(&handle->write_completed_queue)) {
1351cb0ef41Sopenharmony_ci    q = QUEUE_HEAD(&handle->write_completed_queue);
1361cb0ef41Sopenharmony_ci    QUEUE_REMOVE(q);
1371cb0ef41Sopenharmony_ci
1381cb0ef41Sopenharmony_ci    req = QUEUE_DATA(q, uv_udp_send_t, queue);
1391cb0ef41Sopenharmony_ci    uv__req_unregister(handle->loop, req);
1401cb0ef41Sopenharmony_ci
1411cb0ef41Sopenharmony_ci    handle->send_queue_size -= uv__count_bufs(req->bufs, req->nbufs);
1421cb0ef41Sopenharmony_ci    handle->send_queue_count--;
1431cb0ef41Sopenharmony_ci
1441cb0ef41Sopenharmony_ci    if (req->bufs != req->bufsml)
1451cb0ef41Sopenharmony_ci      uv__free(req->bufs);
1461cb0ef41Sopenharmony_ci    req->bufs = NULL;
1471cb0ef41Sopenharmony_ci
1481cb0ef41Sopenharmony_ci    if (req->send_cb == NULL)
1491cb0ef41Sopenharmony_ci      continue;
1501cb0ef41Sopenharmony_ci
1511cb0ef41Sopenharmony_ci    /* req->status >= 0 == bytes written
1521cb0ef41Sopenharmony_ci     * req->status <  0 == errno
1531cb0ef41Sopenharmony_ci     */
1541cb0ef41Sopenharmony_ci    if (req->status >= 0)
1551cb0ef41Sopenharmony_ci      req->send_cb(req, 0);
1561cb0ef41Sopenharmony_ci    else
1571cb0ef41Sopenharmony_ci      req->send_cb(req, req->status);
1581cb0ef41Sopenharmony_ci  }
1591cb0ef41Sopenharmony_ci
1601cb0ef41Sopenharmony_ci  if (QUEUE_EMPTY(&handle->write_queue)) {
1611cb0ef41Sopenharmony_ci    /* Pending queue and completion queue empty, stop watcher. */
1621cb0ef41Sopenharmony_ci    uv__io_stop(handle->loop, &handle->io_watcher, POLLOUT);
1631cb0ef41Sopenharmony_ci    if (!uv__io_active(&handle->io_watcher, POLLIN))
1641cb0ef41Sopenharmony_ci      uv__handle_stop(handle);
1651cb0ef41Sopenharmony_ci  }
1661cb0ef41Sopenharmony_ci
1671cb0ef41Sopenharmony_ci  handle->flags &= ~UV_HANDLE_UDP_PROCESSING;
1681cb0ef41Sopenharmony_ci}
1691cb0ef41Sopenharmony_ci
1701cb0ef41Sopenharmony_ci
1711cb0ef41Sopenharmony_cistatic void uv__udp_io(uv_loop_t* loop, uv__io_t* w, unsigned int revents) {
1721cb0ef41Sopenharmony_ci  uv_udp_t* handle;
1731cb0ef41Sopenharmony_ci
1741cb0ef41Sopenharmony_ci  handle = container_of(w, uv_udp_t, io_watcher);
1751cb0ef41Sopenharmony_ci  assert(handle->type == UV_UDP);
1761cb0ef41Sopenharmony_ci
1771cb0ef41Sopenharmony_ci  if (revents & POLLIN)
1781cb0ef41Sopenharmony_ci    uv__udp_recvmsg(handle);
1791cb0ef41Sopenharmony_ci
1801cb0ef41Sopenharmony_ci  if (revents & POLLOUT) {
1811cb0ef41Sopenharmony_ci    uv__udp_sendmsg(handle);
1821cb0ef41Sopenharmony_ci    uv__udp_run_completed(handle);
1831cb0ef41Sopenharmony_ci  }
1841cb0ef41Sopenharmony_ci}
1851cb0ef41Sopenharmony_ci
1861cb0ef41Sopenharmony_ci#if HAVE_MMSG
1871cb0ef41Sopenharmony_cistatic int uv__udp_recvmmsg(uv_udp_t* handle, uv_buf_t* buf) {
1881cb0ef41Sopenharmony_ci  struct sockaddr_in6 peers[UV__MMSG_MAXWIDTH];
1891cb0ef41Sopenharmony_ci  struct iovec iov[UV__MMSG_MAXWIDTH];
1901cb0ef41Sopenharmony_ci  struct uv__mmsghdr msgs[UV__MMSG_MAXWIDTH];
1911cb0ef41Sopenharmony_ci  ssize_t nread;
1921cb0ef41Sopenharmony_ci  uv_buf_t chunk_buf;
1931cb0ef41Sopenharmony_ci  size_t chunks;
1941cb0ef41Sopenharmony_ci  int flags;
1951cb0ef41Sopenharmony_ci  size_t k;
1961cb0ef41Sopenharmony_ci
1971cb0ef41Sopenharmony_ci  /* prepare structures for recvmmsg */
1981cb0ef41Sopenharmony_ci  chunks = buf->len / UV__UDP_DGRAM_MAXSIZE;
1991cb0ef41Sopenharmony_ci  if (chunks > ARRAY_SIZE(iov))
2001cb0ef41Sopenharmony_ci    chunks = ARRAY_SIZE(iov);
2011cb0ef41Sopenharmony_ci  for (k = 0; k < chunks; ++k) {
2021cb0ef41Sopenharmony_ci    iov[k].iov_base = buf->base + k * UV__UDP_DGRAM_MAXSIZE;
2031cb0ef41Sopenharmony_ci    iov[k].iov_len = UV__UDP_DGRAM_MAXSIZE;
2041cb0ef41Sopenharmony_ci    memset(&msgs[k].msg_hdr, 0, sizeof(msgs[k].msg_hdr));
2051cb0ef41Sopenharmony_ci    msgs[k].msg_hdr.msg_iov = iov + k;
2061cb0ef41Sopenharmony_ci    msgs[k].msg_hdr.msg_iovlen = 1;
2071cb0ef41Sopenharmony_ci    msgs[k].msg_hdr.msg_name = peers + k;
2081cb0ef41Sopenharmony_ci    msgs[k].msg_hdr.msg_namelen = sizeof(peers[0]);
2091cb0ef41Sopenharmony_ci    msgs[k].msg_hdr.msg_control = NULL;
2101cb0ef41Sopenharmony_ci    msgs[k].msg_hdr.msg_controllen = 0;
2111cb0ef41Sopenharmony_ci    msgs[k].msg_hdr.msg_flags = 0;
2121cb0ef41Sopenharmony_ci  }
2131cb0ef41Sopenharmony_ci
2141cb0ef41Sopenharmony_ci  do
2151cb0ef41Sopenharmony_ci    nread = uv__recvmmsg(handle->io_watcher.fd, msgs, chunks);
2161cb0ef41Sopenharmony_ci  while (nread == -1 && errno == EINTR);
2171cb0ef41Sopenharmony_ci
2181cb0ef41Sopenharmony_ci  if (nread < 1) {
2191cb0ef41Sopenharmony_ci    if (nread == 0 || errno == EAGAIN || errno == EWOULDBLOCK)
2201cb0ef41Sopenharmony_ci      handle->recv_cb(handle, 0, buf, NULL, 0);
2211cb0ef41Sopenharmony_ci    else
2221cb0ef41Sopenharmony_ci      handle->recv_cb(handle, UV__ERR(errno), buf, NULL, 0);
2231cb0ef41Sopenharmony_ci  } else {
2241cb0ef41Sopenharmony_ci    /* pass each chunk to the application */
2251cb0ef41Sopenharmony_ci    for (k = 0; k < (size_t) nread && handle->recv_cb != NULL; k++) {
2261cb0ef41Sopenharmony_ci      flags = UV_UDP_MMSG_CHUNK;
2271cb0ef41Sopenharmony_ci      if (msgs[k].msg_hdr.msg_flags & MSG_TRUNC)
2281cb0ef41Sopenharmony_ci        flags |= UV_UDP_PARTIAL;
2291cb0ef41Sopenharmony_ci
2301cb0ef41Sopenharmony_ci      chunk_buf = uv_buf_init(iov[k].iov_base, iov[k].iov_len);
2311cb0ef41Sopenharmony_ci      handle->recv_cb(handle,
2321cb0ef41Sopenharmony_ci                      msgs[k].msg_len,
2331cb0ef41Sopenharmony_ci                      &chunk_buf,
2341cb0ef41Sopenharmony_ci                      msgs[k].msg_hdr.msg_name,
2351cb0ef41Sopenharmony_ci                      flags);
2361cb0ef41Sopenharmony_ci    }
2371cb0ef41Sopenharmony_ci
2381cb0ef41Sopenharmony_ci    /* one last callback so the original buffer is freed */
2391cb0ef41Sopenharmony_ci    if (handle->recv_cb != NULL)
2401cb0ef41Sopenharmony_ci      handle->recv_cb(handle, 0, buf, NULL, UV_UDP_MMSG_FREE);
2411cb0ef41Sopenharmony_ci  }
2421cb0ef41Sopenharmony_ci  return nread;
2431cb0ef41Sopenharmony_ci}
2441cb0ef41Sopenharmony_ci#endif
2451cb0ef41Sopenharmony_ci
2461cb0ef41Sopenharmony_cistatic void uv__udp_recvmsg(uv_udp_t* handle) {
2471cb0ef41Sopenharmony_ci  struct sockaddr_storage peer;
2481cb0ef41Sopenharmony_ci  struct msghdr h;
2491cb0ef41Sopenharmony_ci  ssize_t nread;
2501cb0ef41Sopenharmony_ci  uv_buf_t buf;
2511cb0ef41Sopenharmony_ci  int flags;
2521cb0ef41Sopenharmony_ci  int count;
2531cb0ef41Sopenharmony_ci
2541cb0ef41Sopenharmony_ci  assert(handle->recv_cb != NULL);
2551cb0ef41Sopenharmony_ci  assert(handle->alloc_cb != NULL);
2561cb0ef41Sopenharmony_ci
2571cb0ef41Sopenharmony_ci  /* Prevent loop starvation when the data comes in as fast as (or faster than)
2581cb0ef41Sopenharmony_ci   * we can read it. XXX Need to rearm fd if we switch to edge-triggered I/O.
2591cb0ef41Sopenharmony_ci   */
2601cb0ef41Sopenharmony_ci  count = 32;
2611cb0ef41Sopenharmony_ci
2621cb0ef41Sopenharmony_ci  do {
2631cb0ef41Sopenharmony_ci    buf = uv_buf_init(NULL, 0);
2641cb0ef41Sopenharmony_ci    handle->alloc_cb((uv_handle_t*) handle, UV__UDP_DGRAM_MAXSIZE, &buf);
2651cb0ef41Sopenharmony_ci    if (buf.base == NULL || buf.len == 0) {
2661cb0ef41Sopenharmony_ci      handle->recv_cb(handle, UV_ENOBUFS, &buf, NULL, 0);
2671cb0ef41Sopenharmony_ci      return;
2681cb0ef41Sopenharmony_ci    }
2691cb0ef41Sopenharmony_ci    assert(buf.base != NULL);
2701cb0ef41Sopenharmony_ci
2711cb0ef41Sopenharmony_ci#if HAVE_MMSG
2721cb0ef41Sopenharmony_ci    if (uv_udp_using_recvmmsg(handle)) {
2731cb0ef41Sopenharmony_ci      nread = uv__udp_recvmmsg(handle, &buf);
2741cb0ef41Sopenharmony_ci      if (nread > 0)
2751cb0ef41Sopenharmony_ci        count -= nread;
2761cb0ef41Sopenharmony_ci      continue;
2771cb0ef41Sopenharmony_ci    }
2781cb0ef41Sopenharmony_ci#endif
2791cb0ef41Sopenharmony_ci
2801cb0ef41Sopenharmony_ci    memset(&h, 0, sizeof(h));
2811cb0ef41Sopenharmony_ci    memset(&peer, 0, sizeof(peer));
2821cb0ef41Sopenharmony_ci    h.msg_name = &peer;
2831cb0ef41Sopenharmony_ci    h.msg_namelen = sizeof(peer);
2841cb0ef41Sopenharmony_ci    h.msg_iov = (void*) &buf;
2851cb0ef41Sopenharmony_ci    h.msg_iovlen = 1;
2861cb0ef41Sopenharmony_ci
2871cb0ef41Sopenharmony_ci    do {
2881cb0ef41Sopenharmony_ci      nread = recvmsg(handle->io_watcher.fd, &h, 0);
2891cb0ef41Sopenharmony_ci    }
2901cb0ef41Sopenharmony_ci    while (nread == -1 && errno == EINTR);
2911cb0ef41Sopenharmony_ci
2921cb0ef41Sopenharmony_ci    if (nread == -1) {
2931cb0ef41Sopenharmony_ci      if (errno == EAGAIN || errno == EWOULDBLOCK)
2941cb0ef41Sopenharmony_ci        handle->recv_cb(handle, 0, &buf, NULL, 0);
2951cb0ef41Sopenharmony_ci      else
2961cb0ef41Sopenharmony_ci        handle->recv_cb(handle, UV__ERR(errno), &buf, NULL, 0);
2971cb0ef41Sopenharmony_ci    }
2981cb0ef41Sopenharmony_ci    else {
2991cb0ef41Sopenharmony_ci      flags = 0;
3001cb0ef41Sopenharmony_ci      if (h.msg_flags & MSG_TRUNC)
3011cb0ef41Sopenharmony_ci        flags |= UV_UDP_PARTIAL;
3021cb0ef41Sopenharmony_ci
3031cb0ef41Sopenharmony_ci      handle->recv_cb(handle, nread, &buf, (const struct sockaddr*) &peer, flags);
3041cb0ef41Sopenharmony_ci    }
3051cb0ef41Sopenharmony_ci    count--;
3061cb0ef41Sopenharmony_ci  }
3071cb0ef41Sopenharmony_ci  /* recv_cb callback may decide to pause or close the handle */
3081cb0ef41Sopenharmony_ci  while (nread != -1
3091cb0ef41Sopenharmony_ci      && count > 0
3101cb0ef41Sopenharmony_ci      && handle->io_watcher.fd != -1
3111cb0ef41Sopenharmony_ci      && handle->recv_cb != NULL);
3121cb0ef41Sopenharmony_ci}
3131cb0ef41Sopenharmony_ci
3141cb0ef41Sopenharmony_ci#if HAVE_MMSG
3151cb0ef41Sopenharmony_cistatic void uv__udp_sendmmsg(uv_udp_t* handle) {
3161cb0ef41Sopenharmony_ci  uv_udp_send_t* req;
3171cb0ef41Sopenharmony_ci  struct uv__mmsghdr h[UV__MMSG_MAXWIDTH];
3181cb0ef41Sopenharmony_ci  struct uv__mmsghdr *p;
3191cb0ef41Sopenharmony_ci  QUEUE* q;
3201cb0ef41Sopenharmony_ci  ssize_t npkts;
3211cb0ef41Sopenharmony_ci  size_t pkts;
3221cb0ef41Sopenharmony_ci  size_t i;
3231cb0ef41Sopenharmony_ci
3241cb0ef41Sopenharmony_ci  if (QUEUE_EMPTY(&handle->write_queue))
3251cb0ef41Sopenharmony_ci    return;
3261cb0ef41Sopenharmony_ci
3271cb0ef41Sopenharmony_ciwrite_queue_drain:
3281cb0ef41Sopenharmony_ci  for (pkts = 0, q = QUEUE_HEAD(&handle->write_queue);
3291cb0ef41Sopenharmony_ci       pkts < UV__MMSG_MAXWIDTH && q != &handle->write_queue;
3301cb0ef41Sopenharmony_ci       ++pkts, q = QUEUE_HEAD(q)) {
3311cb0ef41Sopenharmony_ci    assert(q != NULL);
3321cb0ef41Sopenharmony_ci    req = QUEUE_DATA(q, uv_udp_send_t, queue);
3331cb0ef41Sopenharmony_ci    assert(req != NULL);
3341cb0ef41Sopenharmony_ci
3351cb0ef41Sopenharmony_ci    p = &h[pkts];
3361cb0ef41Sopenharmony_ci    memset(p, 0, sizeof(*p));
3371cb0ef41Sopenharmony_ci    if (req->addr.ss_family == AF_UNSPEC) {
3381cb0ef41Sopenharmony_ci      p->msg_hdr.msg_name = NULL;
3391cb0ef41Sopenharmony_ci      p->msg_hdr.msg_namelen = 0;
3401cb0ef41Sopenharmony_ci    } else {
3411cb0ef41Sopenharmony_ci      p->msg_hdr.msg_name = &req->addr;
3421cb0ef41Sopenharmony_ci      if (req->addr.ss_family == AF_INET6)
3431cb0ef41Sopenharmony_ci        p->msg_hdr.msg_namelen = sizeof(struct sockaddr_in6);
3441cb0ef41Sopenharmony_ci      else if (req->addr.ss_family == AF_INET)
3451cb0ef41Sopenharmony_ci        p->msg_hdr.msg_namelen = sizeof(struct sockaddr_in);
3461cb0ef41Sopenharmony_ci      else if (req->addr.ss_family == AF_UNIX)
3471cb0ef41Sopenharmony_ci        p->msg_hdr.msg_namelen = sizeof(struct sockaddr_un);
3481cb0ef41Sopenharmony_ci      else {
3491cb0ef41Sopenharmony_ci        assert(0 && "unsupported address family");
3501cb0ef41Sopenharmony_ci        abort();
3511cb0ef41Sopenharmony_ci      }
3521cb0ef41Sopenharmony_ci    }
3531cb0ef41Sopenharmony_ci    h[pkts].msg_hdr.msg_iov = (struct iovec*) req->bufs;
3541cb0ef41Sopenharmony_ci    h[pkts].msg_hdr.msg_iovlen = req->nbufs;
3551cb0ef41Sopenharmony_ci  }
3561cb0ef41Sopenharmony_ci
3571cb0ef41Sopenharmony_ci  do
3581cb0ef41Sopenharmony_ci    npkts = uv__sendmmsg(handle->io_watcher.fd, h, pkts);
3591cb0ef41Sopenharmony_ci  while (npkts == -1 && errno == EINTR);
3601cb0ef41Sopenharmony_ci
3611cb0ef41Sopenharmony_ci  if (npkts < 1) {
3621cb0ef41Sopenharmony_ci    if (errno == EAGAIN || errno == EWOULDBLOCK || errno == ENOBUFS)
3631cb0ef41Sopenharmony_ci      return;
3641cb0ef41Sopenharmony_ci    for (i = 0, q = QUEUE_HEAD(&handle->write_queue);
3651cb0ef41Sopenharmony_ci         i < pkts && q != &handle->write_queue;
3661cb0ef41Sopenharmony_ci         ++i, q = QUEUE_HEAD(&handle->write_queue)) {
3671cb0ef41Sopenharmony_ci      assert(q != NULL);
3681cb0ef41Sopenharmony_ci      req = QUEUE_DATA(q, uv_udp_send_t, queue);
3691cb0ef41Sopenharmony_ci      assert(req != NULL);
3701cb0ef41Sopenharmony_ci
3711cb0ef41Sopenharmony_ci      req->status = UV__ERR(errno);
3721cb0ef41Sopenharmony_ci      QUEUE_REMOVE(&req->queue);
3731cb0ef41Sopenharmony_ci      QUEUE_INSERT_TAIL(&handle->write_completed_queue, &req->queue);
3741cb0ef41Sopenharmony_ci    }
3751cb0ef41Sopenharmony_ci    uv__io_feed(handle->loop, &handle->io_watcher);
3761cb0ef41Sopenharmony_ci    return;
3771cb0ef41Sopenharmony_ci  }
3781cb0ef41Sopenharmony_ci
3791cb0ef41Sopenharmony_ci  /* Safety: npkts known to be >0 below. Hence cast from ssize_t
3801cb0ef41Sopenharmony_ci   * to size_t safe.
3811cb0ef41Sopenharmony_ci   */
3821cb0ef41Sopenharmony_ci  for (i = 0, q = QUEUE_HEAD(&handle->write_queue);
3831cb0ef41Sopenharmony_ci       i < (size_t)npkts && q != &handle->write_queue;
3841cb0ef41Sopenharmony_ci       ++i, q = QUEUE_HEAD(&handle->write_queue)) {
3851cb0ef41Sopenharmony_ci    assert(q != NULL);
3861cb0ef41Sopenharmony_ci    req = QUEUE_DATA(q, uv_udp_send_t, queue);
3871cb0ef41Sopenharmony_ci    assert(req != NULL);
3881cb0ef41Sopenharmony_ci
3891cb0ef41Sopenharmony_ci    req->status = req->bufs[0].len;
3901cb0ef41Sopenharmony_ci
3911cb0ef41Sopenharmony_ci    /* Sending a datagram is an atomic operation: either all data
3921cb0ef41Sopenharmony_ci     * is written or nothing is (and EMSGSIZE is raised). That is
3931cb0ef41Sopenharmony_ci     * why we don't handle partial writes. Just pop the request
3941cb0ef41Sopenharmony_ci     * off the write queue and onto the completed queue, done.
3951cb0ef41Sopenharmony_ci     */
3961cb0ef41Sopenharmony_ci    QUEUE_REMOVE(&req->queue);
3971cb0ef41Sopenharmony_ci    QUEUE_INSERT_TAIL(&handle->write_completed_queue, &req->queue);
3981cb0ef41Sopenharmony_ci  }
3991cb0ef41Sopenharmony_ci
4001cb0ef41Sopenharmony_ci  /* couldn't batch everything, continue sending (jump to avoid stack growth) */
4011cb0ef41Sopenharmony_ci  if (!QUEUE_EMPTY(&handle->write_queue))
4021cb0ef41Sopenharmony_ci    goto write_queue_drain;
4031cb0ef41Sopenharmony_ci  uv__io_feed(handle->loop, &handle->io_watcher);
4041cb0ef41Sopenharmony_ci  return;
4051cb0ef41Sopenharmony_ci}
4061cb0ef41Sopenharmony_ci#endif
4071cb0ef41Sopenharmony_ci
4081cb0ef41Sopenharmony_cistatic void uv__udp_sendmsg(uv_udp_t* handle) {
4091cb0ef41Sopenharmony_ci  uv_udp_send_t* req;
4101cb0ef41Sopenharmony_ci  struct msghdr h;
4111cb0ef41Sopenharmony_ci  QUEUE* q;
4121cb0ef41Sopenharmony_ci  ssize_t size;
4131cb0ef41Sopenharmony_ci
4141cb0ef41Sopenharmony_ci#if HAVE_MMSG
4151cb0ef41Sopenharmony_ci  uv_once(&once, uv__udp_mmsg_init);
4161cb0ef41Sopenharmony_ci  if (uv__sendmmsg_avail) {
4171cb0ef41Sopenharmony_ci    uv__udp_sendmmsg(handle);
4181cb0ef41Sopenharmony_ci    return;
4191cb0ef41Sopenharmony_ci  }
4201cb0ef41Sopenharmony_ci#endif
4211cb0ef41Sopenharmony_ci
4221cb0ef41Sopenharmony_ci  while (!QUEUE_EMPTY(&handle->write_queue)) {
4231cb0ef41Sopenharmony_ci    q = QUEUE_HEAD(&handle->write_queue);
4241cb0ef41Sopenharmony_ci    assert(q != NULL);
4251cb0ef41Sopenharmony_ci
4261cb0ef41Sopenharmony_ci    req = QUEUE_DATA(q, uv_udp_send_t, queue);
4271cb0ef41Sopenharmony_ci    assert(req != NULL);
4281cb0ef41Sopenharmony_ci
4291cb0ef41Sopenharmony_ci    memset(&h, 0, sizeof h);
4301cb0ef41Sopenharmony_ci    if (req->addr.ss_family == AF_UNSPEC) {
4311cb0ef41Sopenharmony_ci      h.msg_name = NULL;
4321cb0ef41Sopenharmony_ci      h.msg_namelen = 0;
4331cb0ef41Sopenharmony_ci    } else {
4341cb0ef41Sopenharmony_ci      h.msg_name = &req->addr;
4351cb0ef41Sopenharmony_ci      if (req->addr.ss_family == AF_INET6)
4361cb0ef41Sopenharmony_ci        h.msg_namelen = sizeof(struct sockaddr_in6);
4371cb0ef41Sopenharmony_ci      else if (req->addr.ss_family == AF_INET)
4381cb0ef41Sopenharmony_ci        h.msg_namelen = sizeof(struct sockaddr_in);
4391cb0ef41Sopenharmony_ci      else if (req->addr.ss_family == AF_UNIX)
4401cb0ef41Sopenharmony_ci        h.msg_namelen = sizeof(struct sockaddr_un);
4411cb0ef41Sopenharmony_ci      else {
4421cb0ef41Sopenharmony_ci        assert(0 && "unsupported address family");
4431cb0ef41Sopenharmony_ci        abort();
4441cb0ef41Sopenharmony_ci      }
4451cb0ef41Sopenharmony_ci    }
4461cb0ef41Sopenharmony_ci    h.msg_iov = (struct iovec*) req->bufs;
4471cb0ef41Sopenharmony_ci    h.msg_iovlen = req->nbufs;
4481cb0ef41Sopenharmony_ci
4491cb0ef41Sopenharmony_ci    do {
4501cb0ef41Sopenharmony_ci      size = sendmsg(handle->io_watcher.fd, &h, 0);
4511cb0ef41Sopenharmony_ci    } while (size == -1 && errno == EINTR);
4521cb0ef41Sopenharmony_ci
4531cb0ef41Sopenharmony_ci    if (size == -1) {
4541cb0ef41Sopenharmony_ci      if (errno == EAGAIN || errno == EWOULDBLOCK || errno == ENOBUFS)
4551cb0ef41Sopenharmony_ci        break;
4561cb0ef41Sopenharmony_ci    }
4571cb0ef41Sopenharmony_ci
4581cb0ef41Sopenharmony_ci    req->status = (size == -1 ? UV__ERR(errno) : size);
4591cb0ef41Sopenharmony_ci
4601cb0ef41Sopenharmony_ci    /* Sending a datagram is an atomic operation: either all data
4611cb0ef41Sopenharmony_ci     * is written or nothing is (and EMSGSIZE is raised). That is
4621cb0ef41Sopenharmony_ci     * why we don't handle partial writes. Just pop the request
4631cb0ef41Sopenharmony_ci     * off the write queue and onto the completed queue, done.
4641cb0ef41Sopenharmony_ci     */
4651cb0ef41Sopenharmony_ci    QUEUE_REMOVE(&req->queue);
4661cb0ef41Sopenharmony_ci    QUEUE_INSERT_TAIL(&handle->write_completed_queue, &req->queue);
4671cb0ef41Sopenharmony_ci    uv__io_feed(handle->loop, &handle->io_watcher);
4681cb0ef41Sopenharmony_ci  }
4691cb0ef41Sopenharmony_ci}
4701cb0ef41Sopenharmony_ci
4711cb0ef41Sopenharmony_ci/* On the BSDs, SO_REUSEPORT implies SO_REUSEADDR but with some additional
4721cb0ef41Sopenharmony_ci * refinements for programs that use multicast.
4731cb0ef41Sopenharmony_ci *
4741cb0ef41Sopenharmony_ci * Linux as of 3.9 has a SO_REUSEPORT socket option but with semantics that
4751cb0ef41Sopenharmony_ci * are different from the BSDs: it _shares_ the port rather than steal it
4761cb0ef41Sopenharmony_ci * from the current listener.  While useful, it's not something we can emulate
4771cb0ef41Sopenharmony_ci * on other platforms so we don't enable it.
4781cb0ef41Sopenharmony_ci *
4791cb0ef41Sopenharmony_ci * zOS does not support getsockname with SO_REUSEPORT option when using
4801cb0ef41Sopenharmony_ci * AF_UNIX.
4811cb0ef41Sopenharmony_ci */
4821cb0ef41Sopenharmony_cistatic int uv__set_reuse(int fd) {
4831cb0ef41Sopenharmony_ci  int yes;
4841cb0ef41Sopenharmony_ci  yes = 1;
4851cb0ef41Sopenharmony_ci
4861cb0ef41Sopenharmony_ci#if defined(SO_REUSEPORT) && defined(__MVS__)
4871cb0ef41Sopenharmony_ci  struct sockaddr_in sockfd;
4881cb0ef41Sopenharmony_ci  unsigned int sockfd_len = sizeof(sockfd);
4891cb0ef41Sopenharmony_ci  if (getsockname(fd, (struct sockaddr*) &sockfd, &sockfd_len) == -1)
4901cb0ef41Sopenharmony_ci      return UV__ERR(errno);
4911cb0ef41Sopenharmony_ci  if (sockfd.sin_family == AF_UNIX) {
4921cb0ef41Sopenharmony_ci    if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes)))
4931cb0ef41Sopenharmony_ci      return UV__ERR(errno);
4941cb0ef41Sopenharmony_ci  } else {
4951cb0ef41Sopenharmony_ci    if (setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, &yes, sizeof(yes)))
4961cb0ef41Sopenharmony_ci       return UV__ERR(errno);
4971cb0ef41Sopenharmony_ci  }
4981cb0ef41Sopenharmony_ci#elif defined(SO_REUSEPORT) && !defined(__linux__) && !defined(__GNU__)
4991cb0ef41Sopenharmony_ci  if (setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, &yes, sizeof(yes)))
5001cb0ef41Sopenharmony_ci    return UV__ERR(errno);
5011cb0ef41Sopenharmony_ci#else
5021cb0ef41Sopenharmony_ci  if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes)))
5031cb0ef41Sopenharmony_ci    return UV__ERR(errno);
5041cb0ef41Sopenharmony_ci#endif
5051cb0ef41Sopenharmony_ci
5061cb0ef41Sopenharmony_ci  return 0;
5071cb0ef41Sopenharmony_ci}
5081cb0ef41Sopenharmony_ci
5091cb0ef41Sopenharmony_ci/*
5101cb0ef41Sopenharmony_ci * The Linux kernel suppresses some ICMP error messages by default for UDP
5111cb0ef41Sopenharmony_ci * sockets. Setting IP_RECVERR/IPV6_RECVERR on the socket enables full ICMP
5121cb0ef41Sopenharmony_ci * error reporting, hopefully resulting in faster failover to working name
5131cb0ef41Sopenharmony_ci * servers.
5141cb0ef41Sopenharmony_ci */
5151cb0ef41Sopenharmony_cistatic int uv__set_recverr(int fd, sa_family_t ss_family) {
5161cb0ef41Sopenharmony_ci#if defined(__linux__)
5171cb0ef41Sopenharmony_ci  int yes;
5181cb0ef41Sopenharmony_ci
5191cb0ef41Sopenharmony_ci  yes = 1;
5201cb0ef41Sopenharmony_ci  if (ss_family == AF_INET) {
5211cb0ef41Sopenharmony_ci    if (setsockopt(fd, IPPROTO_IP, IP_RECVERR, &yes, sizeof(yes)))
5221cb0ef41Sopenharmony_ci      return UV__ERR(errno);
5231cb0ef41Sopenharmony_ci  } else if (ss_family == AF_INET6) {
5241cb0ef41Sopenharmony_ci    if (setsockopt(fd, IPPROTO_IPV6, IPV6_RECVERR, &yes, sizeof(yes)))
5251cb0ef41Sopenharmony_ci       return UV__ERR(errno);
5261cb0ef41Sopenharmony_ci  }
5271cb0ef41Sopenharmony_ci#endif
5281cb0ef41Sopenharmony_ci  return 0;
5291cb0ef41Sopenharmony_ci}
5301cb0ef41Sopenharmony_ci
5311cb0ef41Sopenharmony_ci
5321cb0ef41Sopenharmony_ciint uv__udp_bind(uv_udp_t* handle,
5331cb0ef41Sopenharmony_ci                 const struct sockaddr* addr,
5341cb0ef41Sopenharmony_ci                 unsigned int addrlen,
5351cb0ef41Sopenharmony_ci                 unsigned int flags) {
5361cb0ef41Sopenharmony_ci  int err;
5371cb0ef41Sopenharmony_ci  int yes;
5381cb0ef41Sopenharmony_ci  int fd;
5391cb0ef41Sopenharmony_ci
5401cb0ef41Sopenharmony_ci  /* Check for bad flags. */
5411cb0ef41Sopenharmony_ci  if (flags & ~(UV_UDP_IPV6ONLY | UV_UDP_REUSEADDR | UV_UDP_LINUX_RECVERR))
5421cb0ef41Sopenharmony_ci    return UV_EINVAL;
5431cb0ef41Sopenharmony_ci
5441cb0ef41Sopenharmony_ci  /* Cannot set IPv6-only mode on non-IPv6 socket. */
5451cb0ef41Sopenharmony_ci  if ((flags & UV_UDP_IPV6ONLY) && addr->sa_family != AF_INET6)
5461cb0ef41Sopenharmony_ci    return UV_EINVAL;
5471cb0ef41Sopenharmony_ci
5481cb0ef41Sopenharmony_ci  fd = handle->io_watcher.fd;
5491cb0ef41Sopenharmony_ci  if (fd == -1) {
5501cb0ef41Sopenharmony_ci    err = uv__socket(addr->sa_family, SOCK_DGRAM, 0);
5511cb0ef41Sopenharmony_ci    if (err < 0)
5521cb0ef41Sopenharmony_ci      return err;
5531cb0ef41Sopenharmony_ci    fd = err;
5541cb0ef41Sopenharmony_ci    handle->io_watcher.fd = fd;
5551cb0ef41Sopenharmony_ci  }
5561cb0ef41Sopenharmony_ci
5571cb0ef41Sopenharmony_ci  if (flags & UV_UDP_LINUX_RECVERR) {
5581cb0ef41Sopenharmony_ci    err = uv__set_recverr(fd, addr->sa_family);
5591cb0ef41Sopenharmony_ci    if (err)
5601cb0ef41Sopenharmony_ci      return err;
5611cb0ef41Sopenharmony_ci  }
5621cb0ef41Sopenharmony_ci
5631cb0ef41Sopenharmony_ci  if (flags & UV_UDP_REUSEADDR) {
5641cb0ef41Sopenharmony_ci    err = uv__set_reuse(fd);
5651cb0ef41Sopenharmony_ci    if (err)
5661cb0ef41Sopenharmony_ci      return err;
5671cb0ef41Sopenharmony_ci  }
5681cb0ef41Sopenharmony_ci
5691cb0ef41Sopenharmony_ci  if (flags & UV_UDP_IPV6ONLY) {
5701cb0ef41Sopenharmony_ci#ifdef IPV6_V6ONLY
5711cb0ef41Sopenharmony_ci    yes = 1;
5721cb0ef41Sopenharmony_ci    if (setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &yes, sizeof yes) == -1) {
5731cb0ef41Sopenharmony_ci      err = UV__ERR(errno);
5741cb0ef41Sopenharmony_ci      return err;
5751cb0ef41Sopenharmony_ci    }
5761cb0ef41Sopenharmony_ci#else
5771cb0ef41Sopenharmony_ci    err = UV_ENOTSUP;
5781cb0ef41Sopenharmony_ci    return err;
5791cb0ef41Sopenharmony_ci#endif
5801cb0ef41Sopenharmony_ci  }
5811cb0ef41Sopenharmony_ci
5821cb0ef41Sopenharmony_ci  if (bind(fd, addr, addrlen)) {
5831cb0ef41Sopenharmony_ci    err = UV__ERR(errno);
5841cb0ef41Sopenharmony_ci    if (errno == EAFNOSUPPORT)
5851cb0ef41Sopenharmony_ci      /* OSX, other BSDs and SunoS fail with EAFNOSUPPORT when binding a
5861cb0ef41Sopenharmony_ci       * socket created with AF_INET to an AF_INET6 address or vice versa. */
5871cb0ef41Sopenharmony_ci      err = UV_EINVAL;
5881cb0ef41Sopenharmony_ci    return err;
5891cb0ef41Sopenharmony_ci  }
5901cb0ef41Sopenharmony_ci
5911cb0ef41Sopenharmony_ci  if (addr->sa_family == AF_INET6)
5921cb0ef41Sopenharmony_ci    handle->flags |= UV_HANDLE_IPV6;
5931cb0ef41Sopenharmony_ci
5941cb0ef41Sopenharmony_ci  handle->flags |= UV_HANDLE_BOUND;
5951cb0ef41Sopenharmony_ci  return 0;
5961cb0ef41Sopenharmony_ci}
5971cb0ef41Sopenharmony_ci
5981cb0ef41Sopenharmony_ci
5991cb0ef41Sopenharmony_cistatic int uv__udp_maybe_deferred_bind(uv_udp_t* handle,
6001cb0ef41Sopenharmony_ci                                       int domain,
6011cb0ef41Sopenharmony_ci                                       unsigned int flags) {
6021cb0ef41Sopenharmony_ci  union uv__sockaddr taddr;
6031cb0ef41Sopenharmony_ci  socklen_t addrlen;
6041cb0ef41Sopenharmony_ci
6051cb0ef41Sopenharmony_ci  if (handle->io_watcher.fd != -1)
6061cb0ef41Sopenharmony_ci    return 0;
6071cb0ef41Sopenharmony_ci
6081cb0ef41Sopenharmony_ci  switch (domain) {
6091cb0ef41Sopenharmony_ci  case AF_INET:
6101cb0ef41Sopenharmony_ci  {
6111cb0ef41Sopenharmony_ci    struct sockaddr_in* addr = &taddr.in;
6121cb0ef41Sopenharmony_ci    memset(addr, 0, sizeof *addr);
6131cb0ef41Sopenharmony_ci    addr->sin_family = AF_INET;
6141cb0ef41Sopenharmony_ci    addr->sin_addr.s_addr = INADDR_ANY;
6151cb0ef41Sopenharmony_ci    addrlen = sizeof *addr;
6161cb0ef41Sopenharmony_ci    break;
6171cb0ef41Sopenharmony_ci  }
6181cb0ef41Sopenharmony_ci  case AF_INET6:
6191cb0ef41Sopenharmony_ci  {
6201cb0ef41Sopenharmony_ci    struct sockaddr_in6* addr = &taddr.in6;
6211cb0ef41Sopenharmony_ci    memset(addr, 0, sizeof *addr);
6221cb0ef41Sopenharmony_ci    addr->sin6_family = AF_INET6;
6231cb0ef41Sopenharmony_ci    addr->sin6_addr = in6addr_any;
6241cb0ef41Sopenharmony_ci    addrlen = sizeof *addr;
6251cb0ef41Sopenharmony_ci    break;
6261cb0ef41Sopenharmony_ci  }
6271cb0ef41Sopenharmony_ci  default:
6281cb0ef41Sopenharmony_ci    assert(0 && "unsupported address family");
6291cb0ef41Sopenharmony_ci    abort();
6301cb0ef41Sopenharmony_ci  }
6311cb0ef41Sopenharmony_ci
6321cb0ef41Sopenharmony_ci  return uv__udp_bind(handle, &taddr.addr, addrlen, flags);
6331cb0ef41Sopenharmony_ci}
6341cb0ef41Sopenharmony_ci
6351cb0ef41Sopenharmony_ci
6361cb0ef41Sopenharmony_ciint uv__udp_connect(uv_udp_t* handle,
6371cb0ef41Sopenharmony_ci                    const struct sockaddr* addr,
6381cb0ef41Sopenharmony_ci                    unsigned int addrlen) {
6391cb0ef41Sopenharmony_ci  int err;
6401cb0ef41Sopenharmony_ci
6411cb0ef41Sopenharmony_ci  err = uv__udp_maybe_deferred_bind(handle, addr->sa_family, 0);
6421cb0ef41Sopenharmony_ci  if (err)
6431cb0ef41Sopenharmony_ci    return err;
6441cb0ef41Sopenharmony_ci
6451cb0ef41Sopenharmony_ci  do {
6461cb0ef41Sopenharmony_ci    errno = 0;
6471cb0ef41Sopenharmony_ci    err = connect(handle->io_watcher.fd, addr, addrlen);
6481cb0ef41Sopenharmony_ci  } while (err == -1 && errno == EINTR);
6491cb0ef41Sopenharmony_ci
6501cb0ef41Sopenharmony_ci  if (err)
6511cb0ef41Sopenharmony_ci    return UV__ERR(errno);
6521cb0ef41Sopenharmony_ci
6531cb0ef41Sopenharmony_ci  handle->flags |= UV_HANDLE_UDP_CONNECTED;
6541cb0ef41Sopenharmony_ci
6551cb0ef41Sopenharmony_ci  return 0;
6561cb0ef41Sopenharmony_ci}
6571cb0ef41Sopenharmony_ci
6581cb0ef41Sopenharmony_ci/* From https://pubs.opengroup.org/onlinepubs/9699919799/functions/connect.html
6591cb0ef41Sopenharmony_ci * Any of uv supported UNIXs kernel should be standardized, but the kernel
6601cb0ef41Sopenharmony_ci * implementation logic not same, let's use pseudocode to explain the udp
6611cb0ef41Sopenharmony_ci * disconnect behaviors:
6621cb0ef41Sopenharmony_ci *
6631cb0ef41Sopenharmony_ci * Predefined stubs for pseudocode:
6641cb0ef41Sopenharmony_ci *   1. sodisconnect: The function to perform the real udp disconnect
6651cb0ef41Sopenharmony_ci *   2. pru_connect: The function to perform the real udp connect
6661cb0ef41Sopenharmony_ci *   3. so: The kernel object match with socket fd
6671cb0ef41Sopenharmony_ci *   4. addr: The sockaddr parameter from user space
6681cb0ef41Sopenharmony_ci *
6691cb0ef41Sopenharmony_ci * BSDs:
6701cb0ef41Sopenharmony_ci *   if(sodisconnect(so) == 0) { // udp disconnect succeed
6711cb0ef41Sopenharmony_ci *     if (addr->sa_len != so->addr->sa_len) return EINVAL;
6721cb0ef41Sopenharmony_ci *     if (addr->sa_family != so->addr->sa_family) return EAFNOSUPPORT;
6731cb0ef41Sopenharmony_ci *     pru_connect(so);
6741cb0ef41Sopenharmony_ci *   }
6751cb0ef41Sopenharmony_ci *   else return EISCONN;
6761cb0ef41Sopenharmony_ci *
6771cb0ef41Sopenharmony_ci * z/OS (same with Windows):
6781cb0ef41Sopenharmony_ci *   if(addr->sa_len < so->addr->sa_len) return EINVAL;
6791cb0ef41Sopenharmony_ci *   if (addr->sa_family == AF_UNSPEC) sodisconnect(so);
6801cb0ef41Sopenharmony_ci *
6811cb0ef41Sopenharmony_ci * AIX:
6821cb0ef41Sopenharmony_ci *   if(addr->sa_len != sizeof(struct sockaddr)) return EINVAL; // ignore ip proto version
6831cb0ef41Sopenharmony_ci *   if (addr->sa_family == AF_UNSPEC) sodisconnect(so);
6841cb0ef41Sopenharmony_ci *
6851cb0ef41Sopenharmony_ci * Linux,Others:
6861cb0ef41Sopenharmony_ci *   if(addr->sa_len < sizeof(struct sockaddr)) return EINVAL;
6871cb0ef41Sopenharmony_ci *   if (addr->sa_family == AF_UNSPEC) sodisconnect(so);
6881cb0ef41Sopenharmony_ci */
6891cb0ef41Sopenharmony_ciint uv__udp_disconnect(uv_udp_t* handle) {
6901cb0ef41Sopenharmony_ci    int r;
6911cb0ef41Sopenharmony_ci#if defined(__MVS__)
6921cb0ef41Sopenharmony_ci    struct sockaddr_storage addr;
6931cb0ef41Sopenharmony_ci#else
6941cb0ef41Sopenharmony_ci    struct sockaddr addr;
6951cb0ef41Sopenharmony_ci#endif
6961cb0ef41Sopenharmony_ci
6971cb0ef41Sopenharmony_ci    memset(&addr, 0, sizeof(addr));
6981cb0ef41Sopenharmony_ci
6991cb0ef41Sopenharmony_ci#if defined(__MVS__)
7001cb0ef41Sopenharmony_ci    addr.ss_family = AF_UNSPEC;
7011cb0ef41Sopenharmony_ci#else
7021cb0ef41Sopenharmony_ci    addr.sa_family = AF_UNSPEC;
7031cb0ef41Sopenharmony_ci#endif
7041cb0ef41Sopenharmony_ci
7051cb0ef41Sopenharmony_ci    do {
7061cb0ef41Sopenharmony_ci      errno = 0;
7071cb0ef41Sopenharmony_ci#ifdef __PASE__
7081cb0ef41Sopenharmony_ci      /* On IBMi a connectionless transport socket can be disconnected by
7091cb0ef41Sopenharmony_ci       * either setting the addr parameter to NULL or setting the
7101cb0ef41Sopenharmony_ci       * addr_length parameter to zero, and issuing another connect().
7111cb0ef41Sopenharmony_ci       * https://www.ibm.com/docs/en/i/7.4?topic=ssw_ibm_i_74/apis/connec.htm
7121cb0ef41Sopenharmony_ci       */
7131cb0ef41Sopenharmony_ci      r = connect(handle->io_watcher.fd, (struct sockaddr*) NULL, 0);
7141cb0ef41Sopenharmony_ci#else
7151cb0ef41Sopenharmony_ci      r = connect(handle->io_watcher.fd, (struct sockaddr*) &addr, sizeof(addr));
7161cb0ef41Sopenharmony_ci#endif
7171cb0ef41Sopenharmony_ci    } while (r == -1 && errno == EINTR);
7181cb0ef41Sopenharmony_ci
7191cb0ef41Sopenharmony_ci    if (r == -1) {
7201cb0ef41Sopenharmony_ci#if defined(BSD)  /* The macro BSD is from sys/param.h */
7211cb0ef41Sopenharmony_ci      if (errno != EAFNOSUPPORT && errno != EINVAL)
7221cb0ef41Sopenharmony_ci        return UV__ERR(errno);
7231cb0ef41Sopenharmony_ci#else
7241cb0ef41Sopenharmony_ci      return UV__ERR(errno);
7251cb0ef41Sopenharmony_ci#endif
7261cb0ef41Sopenharmony_ci    }
7271cb0ef41Sopenharmony_ci
7281cb0ef41Sopenharmony_ci    handle->flags &= ~UV_HANDLE_UDP_CONNECTED;
7291cb0ef41Sopenharmony_ci    return 0;
7301cb0ef41Sopenharmony_ci}
7311cb0ef41Sopenharmony_ci
7321cb0ef41Sopenharmony_ciint uv__udp_send(uv_udp_send_t* req,
7331cb0ef41Sopenharmony_ci                 uv_udp_t* handle,
7341cb0ef41Sopenharmony_ci                 const uv_buf_t bufs[],
7351cb0ef41Sopenharmony_ci                 unsigned int nbufs,
7361cb0ef41Sopenharmony_ci                 const struct sockaddr* addr,
7371cb0ef41Sopenharmony_ci                 unsigned int addrlen,
7381cb0ef41Sopenharmony_ci                 uv_udp_send_cb send_cb) {
7391cb0ef41Sopenharmony_ci  int err;
7401cb0ef41Sopenharmony_ci  int empty_queue;
7411cb0ef41Sopenharmony_ci
7421cb0ef41Sopenharmony_ci  assert(nbufs > 0);
7431cb0ef41Sopenharmony_ci
7441cb0ef41Sopenharmony_ci  if (addr) {
7451cb0ef41Sopenharmony_ci    err = uv__udp_maybe_deferred_bind(handle, addr->sa_family, 0);
7461cb0ef41Sopenharmony_ci    if (err)
7471cb0ef41Sopenharmony_ci      return err;
7481cb0ef41Sopenharmony_ci  }
7491cb0ef41Sopenharmony_ci
7501cb0ef41Sopenharmony_ci  /* It's legal for send_queue_count > 0 even when the write_queue is empty;
7511cb0ef41Sopenharmony_ci   * it means there are error-state requests in the write_completed_queue that
7521cb0ef41Sopenharmony_ci   * will touch up send_queue_size/count later.
7531cb0ef41Sopenharmony_ci   */
7541cb0ef41Sopenharmony_ci  empty_queue = (handle->send_queue_count == 0);
7551cb0ef41Sopenharmony_ci
7561cb0ef41Sopenharmony_ci  uv__req_init(handle->loop, req, UV_UDP_SEND);
7571cb0ef41Sopenharmony_ci  assert(addrlen <= sizeof(req->addr));
7581cb0ef41Sopenharmony_ci  if (addr == NULL)
7591cb0ef41Sopenharmony_ci    req->addr.ss_family = AF_UNSPEC;
7601cb0ef41Sopenharmony_ci  else
7611cb0ef41Sopenharmony_ci    memcpy(&req->addr, addr, addrlen);
7621cb0ef41Sopenharmony_ci  req->send_cb = send_cb;
7631cb0ef41Sopenharmony_ci  req->handle = handle;
7641cb0ef41Sopenharmony_ci  req->nbufs = nbufs;
7651cb0ef41Sopenharmony_ci
7661cb0ef41Sopenharmony_ci  req->bufs = req->bufsml;
7671cb0ef41Sopenharmony_ci  if (nbufs > ARRAY_SIZE(req->bufsml))
7681cb0ef41Sopenharmony_ci    req->bufs = uv__malloc(nbufs * sizeof(bufs[0]));
7691cb0ef41Sopenharmony_ci
7701cb0ef41Sopenharmony_ci  if (req->bufs == NULL) {
7711cb0ef41Sopenharmony_ci    uv__req_unregister(handle->loop, req);
7721cb0ef41Sopenharmony_ci    return UV_ENOMEM;
7731cb0ef41Sopenharmony_ci  }
7741cb0ef41Sopenharmony_ci
7751cb0ef41Sopenharmony_ci  memcpy(req->bufs, bufs, nbufs * sizeof(bufs[0]));
7761cb0ef41Sopenharmony_ci  handle->send_queue_size += uv__count_bufs(req->bufs, req->nbufs);
7771cb0ef41Sopenharmony_ci  handle->send_queue_count++;
7781cb0ef41Sopenharmony_ci  QUEUE_INSERT_TAIL(&handle->write_queue, &req->queue);
7791cb0ef41Sopenharmony_ci  uv__handle_start(handle);
7801cb0ef41Sopenharmony_ci
7811cb0ef41Sopenharmony_ci  if (empty_queue && !(handle->flags & UV_HANDLE_UDP_PROCESSING)) {
7821cb0ef41Sopenharmony_ci    uv__udp_sendmsg(handle);
7831cb0ef41Sopenharmony_ci
7841cb0ef41Sopenharmony_ci    /* `uv__udp_sendmsg` may not be able to do non-blocking write straight
7851cb0ef41Sopenharmony_ci     * away. In such cases the `io_watcher` has to be queued for asynchronous
7861cb0ef41Sopenharmony_ci     * write.
7871cb0ef41Sopenharmony_ci     */
7881cb0ef41Sopenharmony_ci    if (!QUEUE_EMPTY(&handle->write_queue))
7891cb0ef41Sopenharmony_ci      uv__io_start(handle->loop, &handle->io_watcher, POLLOUT);
7901cb0ef41Sopenharmony_ci  } else {
7911cb0ef41Sopenharmony_ci    uv__io_start(handle->loop, &handle->io_watcher, POLLOUT);
7921cb0ef41Sopenharmony_ci  }
7931cb0ef41Sopenharmony_ci
7941cb0ef41Sopenharmony_ci  return 0;
7951cb0ef41Sopenharmony_ci}
7961cb0ef41Sopenharmony_ci
7971cb0ef41Sopenharmony_ci
7981cb0ef41Sopenharmony_ciint uv__udp_try_send(uv_udp_t* handle,
7991cb0ef41Sopenharmony_ci                     const uv_buf_t bufs[],
8001cb0ef41Sopenharmony_ci                     unsigned int nbufs,
8011cb0ef41Sopenharmony_ci                     const struct sockaddr* addr,
8021cb0ef41Sopenharmony_ci                     unsigned int addrlen) {
8031cb0ef41Sopenharmony_ci  int err;
8041cb0ef41Sopenharmony_ci  struct msghdr h;
8051cb0ef41Sopenharmony_ci  ssize_t size;
8061cb0ef41Sopenharmony_ci
8071cb0ef41Sopenharmony_ci  assert(nbufs > 0);
8081cb0ef41Sopenharmony_ci
8091cb0ef41Sopenharmony_ci  /* already sending a message */
8101cb0ef41Sopenharmony_ci  if (handle->send_queue_count != 0)
8111cb0ef41Sopenharmony_ci    return UV_EAGAIN;
8121cb0ef41Sopenharmony_ci
8131cb0ef41Sopenharmony_ci  if (addr) {
8141cb0ef41Sopenharmony_ci    err = uv__udp_maybe_deferred_bind(handle, addr->sa_family, 0);
8151cb0ef41Sopenharmony_ci    if (err)
8161cb0ef41Sopenharmony_ci      return err;
8171cb0ef41Sopenharmony_ci  } else {
8181cb0ef41Sopenharmony_ci    assert(handle->flags & UV_HANDLE_UDP_CONNECTED);
8191cb0ef41Sopenharmony_ci  }
8201cb0ef41Sopenharmony_ci
8211cb0ef41Sopenharmony_ci  memset(&h, 0, sizeof h);
8221cb0ef41Sopenharmony_ci  h.msg_name = (struct sockaddr*) addr;
8231cb0ef41Sopenharmony_ci  h.msg_namelen = addrlen;
8241cb0ef41Sopenharmony_ci  h.msg_iov = (struct iovec*) bufs;
8251cb0ef41Sopenharmony_ci  h.msg_iovlen = nbufs;
8261cb0ef41Sopenharmony_ci
8271cb0ef41Sopenharmony_ci  do {
8281cb0ef41Sopenharmony_ci    size = sendmsg(handle->io_watcher.fd, &h, 0);
8291cb0ef41Sopenharmony_ci  } while (size == -1 && errno == EINTR);
8301cb0ef41Sopenharmony_ci
8311cb0ef41Sopenharmony_ci  if (size == -1) {
8321cb0ef41Sopenharmony_ci    if (errno == EAGAIN || errno == EWOULDBLOCK || errno == ENOBUFS)
8331cb0ef41Sopenharmony_ci      return UV_EAGAIN;
8341cb0ef41Sopenharmony_ci    else
8351cb0ef41Sopenharmony_ci      return UV__ERR(errno);
8361cb0ef41Sopenharmony_ci  }
8371cb0ef41Sopenharmony_ci
8381cb0ef41Sopenharmony_ci  return size;
8391cb0ef41Sopenharmony_ci}
8401cb0ef41Sopenharmony_ci
8411cb0ef41Sopenharmony_ci
8421cb0ef41Sopenharmony_cistatic int uv__udp_set_membership4(uv_udp_t* handle,
8431cb0ef41Sopenharmony_ci                                   const struct sockaddr_in* multicast_addr,
8441cb0ef41Sopenharmony_ci                                   const char* interface_addr,
8451cb0ef41Sopenharmony_ci                                   uv_membership membership) {
8461cb0ef41Sopenharmony_ci  struct ip_mreq mreq;
8471cb0ef41Sopenharmony_ci  int optname;
8481cb0ef41Sopenharmony_ci  int err;
8491cb0ef41Sopenharmony_ci
8501cb0ef41Sopenharmony_ci  memset(&mreq, 0, sizeof mreq);
8511cb0ef41Sopenharmony_ci
8521cb0ef41Sopenharmony_ci  if (interface_addr) {
8531cb0ef41Sopenharmony_ci    err = uv_inet_pton(AF_INET, interface_addr, &mreq.imr_interface.s_addr);
8541cb0ef41Sopenharmony_ci    if (err)
8551cb0ef41Sopenharmony_ci      return err;
8561cb0ef41Sopenharmony_ci  } else {
8571cb0ef41Sopenharmony_ci    mreq.imr_interface.s_addr = htonl(INADDR_ANY);
8581cb0ef41Sopenharmony_ci  }
8591cb0ef41Sopenharmony_ci
8601cb0ef41Sopenharmony_ci  mreq.imr_multiaddr.s_addr = multicast_addr->sin_addr.s_addr;
8611cb0ef41Sopenharmony_ci
8621cb0ef41Sopenharmony_ci  switch (membership) {
8631cb0ef41Sopenharmony_ci  case UV_JOIN_GROUP:
8641cb0ef41Sopenharmony_ci    optname = IP_ADD_MEMBERSHIP;
8651cb0ef41Sopenharmony_ci    break;
8661cb0ef41Sopenharmony_ci  case UV_LEAVE_GROUP:
8671cb0ef41Sopenharmony_ci    optname = IP_DROP_MEMBERSHIP;
8681cb0ef41Sopenharmony_ci    break;
8691cb0ef41Sopenharmony_ci  default:
8701cb0ef41Sopenharmony_ci    return UV_EINVAL;
8711cb0ef41Sopenharmony_ci  }
8721cb0ef41Sopenharmony_ci
8731cb0ef41Sopenharmony_ci  if (setsockopt(handle->io_watcher.fd,
8741cb0ef41Sopenharmony_ci                 IPPROTO_IP,
8751cb0ef41Sopenharmony_ci                 optname,
8761cb0ef41Sopenharmony_ci                 &mreq,
8771cb0ef41Sopenharmony_ci                 sizeof(mreq))) {
8781cb0ef41Sopenharmony_ci#if defined(__MVS__)
8791cb0ef41Sopenharmony_ci  if (errno == ENXIO)
8801cb0ef41Sopenharmony_ci    return UV_ENODEV;
8811cb0ef41Sopenharmony_ci#endif
8821cb0ef41Sopenharmony_ci    return UV__ERR(errno);
8831cb0ef41Sopenharmony_ci  }
8841cb0ef41Sopenharmony_ci
8851cb0ef41Sopenharmony_ci  return 0;
8861cb0ef41Sopenharmony_ci}
8871cb0ef41Sopenharmony_ci
8881cb0ef41Sopenharmony_ci
8891cb0ef41Sopenharmony_cistatic int uv__udp_set_membership6(uv_udp_t* handle,
8901cb0ef41Sopenharmony_ci                                   const struct sockaddr_in6* multicast_addr,
8911cb0ef41Sopenharmony_ci                                   const char* interface_addr,
8921cb0ef41Sopenharmony_ci                                   uv_membership membership) {
8931cb0ef41Sopenharmony_ci  int optname;
8941cb0ef41Sopenharmony_ci  struct ipv6_mreq mreq;
8951cb0ef41Sopenharmony_ci  struct sockaddr_in6 addr6;
8961cb0ef41Sopenharmony_ci
8971cb0ef41Sopenharmony_ci  memset(&mreq, 0, sizeof mreq);
8981cb0ef41Sopenharmony_ci
8991cb0ef41Sopenharmony_ci  if (interface_addr) {
9001cb0ef41Sopenharmony_ci    if (uv_ip6_addr(interface_addr, 0, &addr6))
9011cb0ef41Sopenharmony_ci      return UV_EINVAL;
9021cb0ef41Sopenharmony_ci    mreq.ipv6mr_interface = addr6.sin6_scope_id;
9031cb0ef41Sopenharmony_ci  } else {
9041cb0ef41Sopenharmony_ci    mreq.ipv6mr_interface = 0;
9051cb0ef41Sopenharmony_ci  }
9061cb0ef41Sopenharmony_ci
9071cb0ef41Sopenharmony_ci  mreq.ipv6mr_multiaddr = multicast_addr->sin6_addr;
9081cb0ef41Sopenharmony_ci
9091cb0ef41Sopenharmony_ci  switch (membership) {
9101cb0ef41Sopenharmony_ci  case UV_JOIN_GROUP:
9111cb0ef41Sopenharmony_ci    optname = IPV6_ADD_MEMBERSHIP;
9121cb0ef41Sopenharmony_ci    break;
9131cb0ef41Sopenharmony_ci  case UV_LEAVE_GROUP:
9141cb0ef41Sopenharmony_ci    optname = IPV6_DROP_MEMBERSHIP;
9151cb0ef41Sopenharmony_ci    break;
9161cb0ef41Sopenharmony_ci  default:
9171cb0ef41Sopenharmony_ci    return UV_EINVAL;
9181cb0ef41Sopenharmony_ci  }
9191cb0ef41Sopenharmony_ci
9201cb0ef41Sopenharmony_ci  if (setsockopt(handle->io_watcher.fd,
9211cb0ef41Sopenharmony_ci                 IPPROTO_IPV6,
9221cb0ef41Sopenharmony_ci                 optname,
9231cb0ef41Sopenharmony_ci                 &mreq,
9241cb0ef41Sopenharmony_ci                 sizeof(mreq))) {
9251cb0ef41Sopenharmony_ci#if defined(__MVS__)
9261cb0ef41Sopenharmony_ci  if (errno == ENXIO)
9271cb0ef41Sopenharmony_ci    return UV_ENODEV;
9281cb0ef41Sopenharmony_ci#endif
9291cb0ef41Sopenharmony_ci    return UV__ERR(errno);
9301cb0ef41Sopenharmony_ci  }
9311cb0ef41Sopenharmony_ci
9321cb0ef41Sopenharmony_ci  return 0;
9331cb0ef41Sopenharmony_ci}
9341cb0ef41Sopenharmony_ci
9351cb0ef41Sopenharmony_ci
9361cb0ef41Sopenharmony_ci#if !defined(__OpenBSD__) &&                                        \
9371cb0ef41Sopenharmony_ci    !defined(__NetBSD__) &&                                         \
9381cb0ef41Sopenharmony_ci    !defined(__ANDROID__) &&                                        \
9391cb0ef41Sopenharmony_ci    !defined(__DragonFly__) &&                                      \
9401cb0ef41Sopenharmony_ci    !defined(__QNX__) &&                                            \
9411cb0ef41Sopenharmony_ci    !defined(__GNU__)
9421cb0ef41Sopenharmony_cistatic int uv__udp_set_source_membership4(uv_udp_t* handle,
9431cb0ef41Sopenharmony_ci                                          const struct sockaddr_in* multicast_addr,
9441cb0ef41Sopenharmony_ci                                          const char* interface_addr,
9451cb0ef41Sopenharmony_ci                                          const struct sockaddr_in* source_addr,
9461cb0ef41Sopenharmony_ci                                          uv_membership membership) {
9471cb0ef41Sopenharmony_ci  struct ip_mreq_source mreq;
9481cb0ef41Sopenharmony_ci  int optname;
9491cb0ef41Sopenharmony_ci  int err;
9501cb0ef41Sopenharmony_ci
9511cb0ef41Sopenharmony_ci  err = uv__udp_maybe_deferred_bind(handle, AF_INET, UV_UDP_REUSEADDR);
9521cb0ef41Sopenharmony_ci  if (err)
9531cb0ef41Sopenharmony_ci    return err;
9541cb0ef41Sopenharmony_ci
9551cb0ef41Sopenharmony_ci  memset(&mreq, 0, sizeof(mreq));
9561cb0ef41Sopenharmony_ci
9571cb0ef41Sopenharmony_ci  if (interface_addr != NULL) {
9581cb0ef41Sopenharmony_ci    err = uv_inet_pton(AF_INET, interface_addr, &mreq.imr_interface.s_addr);
9591cb0ef41Sopenharmony_ci    if (err)
9601cb0ef41Sopenharmony_ci      return err;
9611cb0ef41Sopenharmony_ci  } else {
9621cb0ef41Sopenharmony_ci    mreq.imr_interface.s_addr = htonl(INADDR_ANY);
9631cb0ef41Sopenharmony_ci  }
9641cb0ef41Sopenharmony_ci
9651cb0ef41Sopenharmony_ci  mreq.imr_multiaddr.s_addr = multicast_addr->sin_addr.s_addr;
9661cb0ef41Sopenharmony_ci  mreq.imr_sourceaddr.s_addr = source_addr->sin_addr.s_addr;
9671cb0ef41Sopenharmony_ci
9681cb0ef41Sopenharmony_ci  if (membership == UV_JOIN_GROUP)
9691cb0ef41Sopenharmony_ci    optname = IP_ADD_SOURCE_MEMBERSHIP;
9701cb0ef41Sopenharmony_ci  else if (membership == UV_LEAVE_GROUP)
9711cb0ef41Sopenharmony_ci    optname = IP_DROP_SOURCE_MEMBERSHIP;
9721cb0ef41Sopenharmony_ci  else
9731cb0ef41Sopenharmony_ci    return UV_EINVAL;
9741cb0ef41Sopenharmony_ci
9751cb0ef41Sopenharmony_ci  if (setsockopt(handle->io_watcher.fd,
9761cb0ef41Sopenharmony_ci                 IPPROTO_IP,
9771cb0ef41Sopenharmony_ci                 optname,
9781cb0ef41Sopenharmony_ci                 &mreq,
9791cb0ef41Sopenharmony_ci                 sizeof(mreq))) {
9801cb0ef41Sopenharmony_ci    return UV__ERR(errno);
9811cb0ef41Sopenharmony_ci  }
9821cb0ef41Sopenharmony_ci
9831cb0ef41Sopenharmony_ci  return 0;
9841cb0ef41Sopenharmony_ci}
9851cb0ef41Sopenharmony_ci
9861cb0ef41Sopenharmony_ci
9871cb0ef41Sopenharmony_cistatic int uv__udp_set_source_membership6(uv_udp_t* handle,
9881cb0ef41Sopenharmony_ci                                          const struct sockaddr_in6* multicast_addr,
9891cb0ef41Sopenharmony_ci                                          const char* interface_addr,
9901cb0ef41Sopenharmony_ci                                          const struct sockaddr_in6* source_addr,
9911cb0ef41Sopenharmony_ci                                          uv_membership membership) {
9921cb0ef41Sopenharmony_ci  struct group_source_req mreq;
9931cb0ef41Sopenharmony_ci  struct sockaddr_in6 addr6;
9941cb0ef41Sopenharmony_ci  int optname;
9951cb0ef41Sopenharmony_ci  int err;
9961cb0ef41Sopenharmony_ci
9971cb0ef41Sopenharmony_ci  err = uv__udp_maybe_deferred_bind(handle, AF_INET6, UV_UDP_REUSEADDR);
9981cb0ef41Sopenharmony_ci  if (err)
9991cb0ef41Sopenharmony_ci    return err;
10001cb0ef41Sopenharmony_ci
10011cb0ef41Sopenharmony_ci  memset(&mreq, 0, sizeof(mreq));
10021cb0ef41Sopenharmony_ci
10031cb0ef41Sopenharmony_ci  if (interface_addr != NULL) {
10041cb0ef41Sopenharmony_ci    err = uv_ip6_addr(interface_addr, 0, &addr6);
10051cb0ef41Sopenharmony_ci    if (err)
10061cb0ef41Sopenharmony_ci      return err;
10071cb0ef41Sopenharmony_ci    mreq.gsr_interface = addr6.sin6_scope_id;
10081cb0ef41Sopenharmony_ci  } else {
10091cb0ef41Sopenharmony_ci    mreq.gsr_interface = 0;
10101cb0ef41Sopenharmony_ci  }
10111cb0ef41Sopenharmony_ci
10121cb0ef41Sopenharmony_ci  STATIC_ASSERT(sizeof(mreq.gsr_group) >= sizeof(*multicast_addr));
10131cb0ef41Sopenharmony_ci  STATIC_ASSERT(sizeof(mreq.gsr_source) >= sizeof(*source_addr));
10141cb0ef41Sopenharmony_ci  memcpy(&mreq.gsr_group, multicast_addr, sizeof(*multicast_addr));
10151cb0ef41Sopenharmony_ci  memcpy(&mreq.gsr_source, source_addr, sizeof(*source_addr));
10161cb0ef41Sopenharmony_ci
10171cb0ef41Sopenharmony_ci  if (membership == UV_JOIN_GROUP)
10181cb0ef41Sopenharmony_ci    optname = MCAST_JOIN_SOURCE_GROUP;
10191cb0ef41Sopenharmony_ci  else if (membership == UV_LEAVE_GROUP)
10201cb0ef41Sopenharmony_ci    optname = MCAST_LEAVE_SOURCE_GROUP;
10211cb0ef41Sopenharmony_ci  else
10221cb0ef41Sopenharmony_ci    return UV_EINVAL;
10231cb0ef41Sopenharmony_ci
10241cb0ef41Sopenharmony_ci  if (setsockopt(handle->io_watcher.fd,
10251cb0ef41Sopenharmony_ci                 IPPROTO_IPV6,
10261cb0ef41Sopenharmony_ci                 optname,
10271cb0ef41Sopenharmony_ci                 &mreq,
10281cb0ef41Sopenharmony_ci                 sizeof(mreq))) {
10291cb0ef41Sopenharmony_ci    return UV__ERR(errno);
10301cb0ef41Sopenharmony_ci  }
10311cb0ef41Sopenharmony_ci
10321cb0ef41Sopenharmony_ci  return 0;
10331cb0ef41Sopenharmony_ci}
10341cb0ef41Sopenharmony_ci#endif
10351cb0ef41Sopenharmony_ci
10361cb0ef41Sopenharmony_ci
10371cb0ef41Sopenharmony_ciint uv__udp_init_ex(uv_loop_t* loop,
10381cb0ef41Sopenharmony_ci                    uv_udp_t* handle,
10391cb0ef41Sopenharmony_ci                    unsigned flags,
10401cb0ef41Sopenharmony_ci                    int domain) {
10411cb0ef41Sopenharmony_ci  int fd;
10421cb0ef41Sopenharmony_ci
10431cb0ef41Sopenharmony_ci  fd = -1;
10441cb0ef41Sopenharmony_ci  if (domain != AF_UNSPEC) {
10451cb0ef41Sopenharmony_ci    fd = uv__socket(domain, SOCK_DGRAM, 0);
10461cb0ef41Sopenharmony_ci    if (fd < 0)
10471cb0ef41Sopenharmony_ci      return fd;
10481cb0ef41Sopenharmony_ci  }
10491cb0ef41Sopenharmony_ci
10501cb0ef41Sopenharmony_ci  uv__handle_init(loop, (uv_handle_t*)handle, UV_UDP);
10511cb0ef41Sopenharmony_ci  handle->alloc_cb = NULL;
10521cb0ef41Sopenharmony_ci  handle->recv_cb = NULL;
10531cb0ef41Sopenharmony_ci  handle->send_queue_size = 0;
10541cb0ef41Sopenharmony_ci  handle->send_queue_count = 0;
10551cb0ef41Sopenharmony_ci  uv__io_init(&handle->io_watcher, uv__udp_io, fd);
10561cb0ef41Sopenharmony_ci  QUEUE_INIT(&handle->write_queue);
10571cb0ef41Sopenharmony_ci  QUEUE_INIT(&handle->write_completed_queue);
10581cb0ef41Sopenharmony_ci
10591cb0ef41Sopenharmony_ci  return 0;
10601cb0ef41Sopenharmony_ci}
10611cb0ef41Sopenharmony_ci
10621cb0ef41Sopenharmony_ci
10631cb0ef41Sopenharmony_ciint uv_udp_using_recvmmsg(const uv_udp_t* handle) {
10641cb0ef41Sopenharmony_ci#if HAVE_MMSG
10651cb0ef41Sopenharmony_ci  if (handle->flags & UV_HANDLE_UDP_RECVMMSG) {
10661cb0ef41Sopenharmony_ci    uv_once(&once, uv__udp_mmsg_init);
10671cb0ef41Sopenharmony_ci    return uv__recvmmsg_avail;
10681cb0ef41Sopenharmony_ci  }
10691cb0ef41Sopenharmony_ci#endif
10701cb0ef41Sopenharmony_ci  return 0;
10711cb0ef41Sopenharmony_ci}
10721cb0ef41Sopenharmony_ci
10731cb0ef41Sopenharmony_ci
10741cb0ef41Sopenharmony_ciint uv_udp_open(uv_udp_t* handle, uv_os_sock_t sock) {
10751cb0ef41Sopenharmony_ci  int err;
10761cb0ef41Sopenharmony_ci
10771cb0ef41Sopenharmony_ci  /* Check for already active socket. */
10781cb0ef41Sopenharmony_ci  if (handle->io_watcher.fd != -1)
10791cb0ef41Sopenharmony_ci    return UV_EBUSY;
10801cb0ef41Sopenharmony_ci
10811cb0ef41Sopenharmony_ci  if (uv__fd_exists(handle->loop, sock))
10821cb0ef41Sopenharmony_ci    return UV_EEXIST;
10831cb0ef41Sopenharmony_ci
10841cb0ef41Sopenharmony_ci  err = uv__nonblock(sock, 1);
10851cb0ef41Sopenharmony_ci  if (err)
10861cb0ef41Sopenharmony_ci    return err;
10871cb0ef41Sopenharmony_ci
10881cb0ef41Sopenharmony_ci  err = uv__set_reuse(sock);
10891cb0ef41Sopenharmony_ci  if (err)
10901cb0ef41Sopenharmony_ci    return err;
10911cb0ef41Sopenharmony_ci
10921cb0ef41Sopenharmony_ci  handle->io_watcher.fd = sock;
10931cb0ef41Sopenharmony_ci  if (uv__udp_is_connected(handle))
10941cb0ef41Sopenharmony_ci    handle->flags |= UV_HANDLE_UDP_CONNECTED;
10951cb0ef41Sopenharmony_ci
10961cb0ef41Sopenharmony_ci  return 0;
10971cb0ef41Sopenharmony_ci}
10981cb0ef41Sopenharmony_ci
10991cb0ef41Sopenharmony_ci
11001cb0ef41Sopenharmony_ciint uv_udp_set_membership(uv_udp_t* handle,
11011cb0ef41Sopenharmony_ci                          const char* multicast_addr,
11021cb0ef41Sopenharmony_ci                          const char* interface_addr,
11031cb0ef41Sopenharmony_ci                          uv_membership membership) {
11041cb0ef41Sopenharmony_ci  int err;
11051cb0ef41Sopenharmony_ci  struct sockaddr_in addr4;
11061cb0ef41Sopenharmony_ci  struct sockaddr_in6 addr6;
11071cb0ef41Sopenharmony_ci
11081cb0ef41Sopenharmony_ci  if (uv_ip4_addr(multicast_addr, 0, &addr4) == 0) {
11091cb0ef41Sopenharmony_ci    err = uv__udp_maybe_deferred_bind(handle, AF_INET, UV_UDP_REUSEADDR);
11101cb0ef41Sopenharmony_ci    if (err)
11111cb0ef41Sopenharmony_ci      return err;
11121cb0ef41Sopenharmony_ci    return uv__udp_set_membership4(handle, &addr4, interface_addr, membership);
11131cb0ef41Sopenharmony_ci  } else if (uv_ip6_addr(multicast_addr, 0, &addr6) == 0) {
11141cb0ef41Sopenharmony_ci    err = uv__udp_maybe_deferred_bind(handle, AF_INET6, UV_UDP_REUSEADDR);
11151cb0ef41Sopenharmony_ci    if (err)
11161cb0ef41Sopenharmony_ci      return err;
11171cb0ef41Sopenharmony_ci    return uv__udp_set_membership6(handle, &addr6, interface_addr, membership);
11181cb0ef41Sopenharmony_ci  } else {
11191cb0ef41Sopenharmony_ci    return UV_EINVAL;
11201cb0ef41Sopenharmony_ci  }
11211cb0ef41Sopenharmony_ci}
11221cb0ef41Sopenharmony_ci
11231cb0ef41Sopenharmony_ci
11241cb0ef41Sopenharmony_ciint uv_udp_set_source_membership(uv_udp_t* handle,
11251cb0ef41Sopenharmony_ci                                 const char* multicast_addr,
11261cb0ef41Sopenharmony_ci                                 const char* interface_addr,
11271cb0ef41Sopenharmony_ci                                 const char* source_addr,
11281cb0ef41Sopenharmony_ci                                 uv_membership membership) {
11291cb0ef41Sopenharmony_ci#if !defined(__OpenBSD__) &&                                        \
11301cb0ef41Sopenharmony_ci    !defined(__NetBSD__) &&                                         \
11311cb0ef41Sopenharmony_ci    !defined(__ANDROID__) &&                                        \
11321cb0ef41Sopenharmony_ci    !defined(__DragonFly__) &&                                      \
11331cb0ef41Sopenharmony_ci    !defined(__QNX__) &&                                            \
11341cb0ef41Sopenharmony_ci    !defined(__GNU__)
11351cb0ef41Sopenharmony_ci  int err;
11361cb0ef41Sopenharmony_ci  union uv__sockaddr mcast_addr;
11371cb0ef41Sopenharmony_ci  union uv__sockaddr src_addr;
11381cb0ef41Sopenharmony_ci
11391cb0ef41Sopenharmony_ci  err = uv_ip4_addr(multicast_addr, 0, &mcast_addr.in);
11401cb0ef41Sopenharmony_ci  if (err) {
11411cb0ef41Sopenharmony_ci    err = uv_ip6_addr(multicast_addr, 0, &mcast_addr.in6);
11421cb0ef41Sopenharmony_ci    if (err)
11431cb0ef41Sopenharmony_ci      return err;
11441cb0ef41Sopenharmony_ci    err = uv_ip6_addr(source_addr, 0, &src_addr.in6);
11451cb0ef41Sopenharmony_ci    if (err)
11461cb0ef41Sopenharmony_ci      return err;
11471cb0ef41Sopenharmony_ci    return uv__udp_set_source_membership6(handle,
11481cb0ef41Sopenharmony_ci                                          &mcast_addr.in6,
11491cb0ef41Sopenharmony_ci                                          interface_addr,
11501cb0ef41Sopenharmony_ci                                          &src_addr.in6,
11511cb0ef41Sopenharmony_ci                                          membership);
11521cb0ef41Sopenharmony_ci  }
11531cb0ef41Sopenharmony_ci
11541cb0ef41Sopenharmony_ci  err = uv_ip4_addr(source_addr, 0, &src_addr.in);
11551cb0ef41Sopenharmony_ci  if (err)
11561cb0ef41Sopenharmony_ci    return err;
11571cb0ef41Sopenharmony_ci  return uv__udp_set_source_membership4(handle,
11581cb0ef41Sopenharmony_ci                                        &mcast_addr.in,
11591cb0ef41Sopenharmony_ci                                        interface_addr,
11601cb0ef41Sopenharmony_ci                                        &src_addr.in,
11611cb0ef41Sopenharmony_ci                                        membership);
11621cb0ef41Sopenharmony_ci#else
11631cb0ef41Sopenharmony_ci  return UV_ENOSYS;
11641cb0ef41Sopenharmony_ci#endif
11651cb0ef41Sopenharmony_ci}
11661cb0ef41Sopenharmony_ci
11671cb0ef41Sopenharmony_ci
11681cb0ef41Sopenharmony_cistatic int uv__setsockopt(uv_udp_t* handle,
11691cb0ef41Sopenharmony_ci                         int option4,
11701cb0ef41Sopenharmony_ci                         int option6,
11711cb0ef41Sopenharmony_ci                         const void* val,
11721cb0ef41Sopenharmony_ci                         socklen_t size) {
11731cb0ef41Sopenharmony_ci  int r;
11741cb0ef41Sopenharmony_ci
11751cb0ef41Sopenharmony_ci  if (handle->flags & UV_HANDLE_IPV6)
11761cb0ef41Sopenharmony_ci    r = setsockopt(handle->io_watcher.fd,
11771cb0ef41Sopenharmony_ci                   IPPROTO_IPV6,
11781cb0ef41Sopenharmony_ci                   option6,
11791cb0ef41Sopenharmony_ci                   val,
11801cb0ef41Sopenharmony_ci                   size);
11811cb0ef41Sopenharmony_ci  else
11821cb0ef41Sopenharmony_ci    r = setsockopt(handle->io_watcher.fd,
11831cb0ef41Sopenharmony_ci                   IPPROTO_IP,
11841cb0ef41Sopenharmony_ci                   option4,
11851cb0ef41Sopenharmony_ci                   val,
11861cb0ef41Sopenharmony_ci                   size);
11871cb0ef41Sopenharmony_ci  if (r)
11881cb0ef41Sopenharmony_ci    return UV__ERR(errno);
11891cb0ef41Sopenharmony_ci
11901cb0ef41Sopenharmony_ci  return 0;
11911cb0ef41Sopenharmony_ci}
11921cb0ef41Sopenharmony_ci
11931cb0ef41Sopenharmony_cistatic int uv__setsockopt_maybe_char(uv_udp_t* handle,
11941cb0ef41Sopenharmony_ci                                     int option4,
11951cb0ef41Sopenharmony_ci                                     int option6,
11961cb0ef41Sopenharmony_ci                                     int val) {
11971cb0ef41Sopenharmony_ci#if defined(__sun) || defined(_AIX) || defined(__MVS__)
11981cb0ef41Sopenharmony_ci  char arg = val;
11991cb0ef41Sopenharmony_ci#elif defined(__OpenBSD__)
12001cb0ef41Sopenharmony_ci  unsigned char arg = val;
12011cb0ef41Sopenharmony_ci#else
12021cb0ef41Sopenharmony_ci  int arg = val;
12031cb0ef41Sopenharmony_ci#endif
12041cb0ef41Sopenharmony_ci
12051cb0ef41Sopenharmony_ci  if (val < 0 || val > 255)
12061cb0ef41Sopenharmony_ci    return UV_EINVAL;
12071cb0ef41Sopenharmony_ci
12081cb0ef41Sopenharmony_ci  return uv__setsockopt(handle, option4, option6, &arg, sizeof(arg));
12091cb0ef41Sopenharmony_ci}
12101cb0ef41Sopenharmony_ci
12111cb0ef41Sopenharmony_ci
12121cb0ef41Sopenharmony_ciint uv_udp_set_broadcast(uv_udp_t* handle, int on) {
12131cb0ef41Sopenharmony_ci  if (setsockopt(handle->io_watcher.fd,
12141cb0ef41Sopenharmony_ci                 SOL_SOCKET,
12151cb0ef41Sopenharmony_ci                 SO_BROADCAST,
12161cb0ef41Sopenharmony_ci                 &on,
12171cb0ef41Sopenharmony_ci                 sizeof(on))) {
12181cb0ef41Sopenharmony_ci    return UV__ERR(errno);
12191cb0ef41Sopenharmony_ci  }
12201cb0ef41Sopenharmony_ci
12211cb0ef41Sopenharmony_ci  return 0;
12221cb0ef41Sopenharmony_ci}
12231cb0ef41Sopenharmony_ci
12241cb0ef41Sopenharmony_ci
12251cb0ef41Sopenharmony_ciint uv_udp_set_ttl(uv_udp_t* handle, int ttl) {
12261cb0ef41Sopenharmony_ci  if (ttl < 1 || ttl > 255)
12271cb0ef41Sopenharmony_ci    return UV_EINVAL;
12281cb0ef41Sopenharmony_ci
12291cb0ef41Sopenharmony_ci#if defined(__MVS__)
12301cb0ef41Sopenharmony_ci  if (!(handle->flags & UV_HANDLE_IPV6))
12311cb0ef41Sopenharmony_ci    return UV_ENOTSUP;  /* zOS does not support setting ttl for IPv4 */
12321cb0ef41Sopenharmony_ci#endif
12331cb0ef41Sopenharmony_ci
12341cb0ef41Sopenharmony_ci/*
12351cb0ef41Sopenharmony_ci * On Solaris and derivatives such as SmartOS, the length of socket options
12361cb0ef41Sopenharmony_ci * is sizeof(int) for IP_TTL and IPV6_UNICAST_HOPS,
12371cb0ef41Sopenharmony_ci * so hardcode the size of these options on this platform,
12381cb0ef41Sopenharmony_ci * and use the general uv__setsockopt_maybe_char call on other platforms.
12391cb0ef41Sopenharmony_ci */
12401cb0ef41Sopenharmony_ci#if defined(__sun) || defined(_AIX) || defined(__OpenBSD__) || \
12411cb0ef41Sopenharmony_ci    defined(__MVS__) || defined(__QNX__)
12421cb0ef41Sopenharmony_ci
12431cb0ef41Sopenharmony_ci  return uv__setsockopt(handle,
12441cb0ef41Sopenharmony_ci                        IP_TTL,
12451cb0ef41Sopenharmony_ci                        IPV6_UNICAST_HOPS,
12461cb0ef41Sopenharmony_ci                        &ttl,
12471cb0ef41Sopenharmony_ci                        sizeof(ttl));
12481cb0ef41Sopenharmony_ci
12491cb0ef41Sopenharmony_ci#else /* !(defined(__sun) || defined(_AIX) || defined (__OpenBSD__) ||
12501cb0ef41Sopenharmony_ci           defined(__MVS__) || defined(__QNX__)) */
12511cb0ef41Sopenharmony_ci
12521cb0ef41Sopenharmony_ci  return uv__setsockopt_maybe_char(handle,
12531cb0ef41Sopenharmony_ci                                   IP_TTL,
12541cb0ef41Sopenharmony_ci                                   IPV6_UNICAST_HOPS,
12551cb0ef41Sopenharmony_ci                                   ttl);
12561cb0ef41Sopenharmony_ci
12571cb0ef41Sopenharmony_ci#endif /* defined(__sun) || defined(_AIX) || defined (__OpenBSD__) ||
12581cb0ef41Sopenharmony_ci          defined(__MVS__) || defined(__QNX__) */
12591cb0ef41Sopenharmony_ci}
12601cb0ef41Sopenharmony_ci
12611cb0ef41Sopenharmony_ci
12621cb0ef41Sopenharmony_ciint uv_udp_set_multicast_ttl(uv_udp_t* handle, int ttl) {
12631cb0ef41Sopenharmony_ci/*
12641cb0ef41Sopenharmony_ci * On Solaris and derivatives such as SmartOS, the length of socket options
12651cb0ef41Sopenharmony_ci * is sizeof(int) for IPV6_MULTICAST_HOPS and sizeof(char) for
12661cb0ef41Sopenharmony_ci * IP_MULTICAST_TTL, so hardcode the size of the option in the IPv6 case,
12671cb0ef41Sopenharmony_ci * and use the general uv__setsockopt_maybe_char call otherwise.
12681cb0ef41Sopenharmony_ci */
12691cb0ef41Sopenharmony_ci#if defined(__sun) || defined(_AIX) || defined(__OpenBSD__) || \
12701cb0ef41Sopenharmony_ci    defined(__MVS__) || defined(__QNX__)
12711cb0ef41Sopenharmony_ci  if (handle->flags & UV_HANDLE_IPV6)
12721cb0ef41Sopenharmony_ci    return uv__setsockopt(handle,
12731cb0ef41Sopenharmony_ci                          IP_MULTICAST_TTL,
12741cb0ef41Sopenharmony_ci                          IPV6_MULTICAST_HOPS,
12751cb0ef41Sopenharmony_ci                          &ttl,
12761cb0ef41Sopenharmony_ci                          sizeof(ttl));
12771cb0ef41Sopenharmony_ci#endif /* defined(__sun) || defined(_AIX) || defined(__OpenBSD__) || \
12781cb0ef41Sopenharmony_ci    defined(__MVS__) || defined(__QNX__) */
12791cb0ef41Sopenharmony_ci
12801cb0ef41Sopenharmony_ci  return uv__setsockopt_maybe_char(handle,
12811cb0ef41Sopenharmony_ci                                   IP_MULTICAST_TTL,
12821cb0ef41Sopenharmony_ci                                   IPV6_MULTICAST_HOPS,
12831cb0ef41Sopenharmony_ci                                   ttl);
12841cb0ef41Sopenharmony_ci}
12851cb0ef41Sopenharmony_ci
12861cb0ef41Sopenharmony_ci
12871cb0ef41Sopenharmony_ciint uv_udp_set_multicast_loop(uv_udp_t* handle, int on) {
12881cb0ef41Sopenharmony_ci/*
12891cb0ef41Sopenharmony_ci * On Solaris and derivatives such as SmartOS, the length of socket options
12901cb0ef41Sopenharmony_ci * is sizeof(int) for IPV6_MULTICAST_LOOP and sizeof(char) for
12911cb0ef41Sopenharmony_ci * IP_MULTICAST_LOOP, so hardcode the size of the option in the IPv6 case,
12921cb0ef41Sopenharmony_ci * and use the general uv__setsockopt_maybe_char call otherwise.
12931cb0ef41Sopenharmony_ci */
12941cb0ef41Sopenharmony_ci#if defined(__sun) || defined(_AIX) || defined(__OpenBSD__) || \
12951cb0ef41Sopenharmony_ci    defined(__MVS__) || defined(__QNX__)
12961cb0ef41Sopenharmony_ci  if (handle->flags & UV_HANDLE_IPV6)
12971cb0ef41Sopenharmony_ci    return uv__setsockopt(handle,
12981cb0ef41Sopenharmony_ci                          IP_MULTICAST_LOOP,
12991cb0ef41Sopenharmony_ci                          IPV6_MULTICAST_LOOP,
13001cb0ef41Sopenharmony_ci                          &on,
13011cb0ef41Sopenharmony_ci                          sizeof(on));
13021cb0ef41Sopenharmony_ci#endif /* defined(__sun) || defined(_AIX) ||defined(__OpenBSD__) ||
13031cb0ef41Sopenharmony_ci    defined(__MVS__) || defined(__QNX__) */
13041cb0ef41Sopenharmony_ci
13051cb0ef41Sopenharmony_ci  return uv__setsockopt_maybe_char(handle,
13061cb0ef41Sopenharmony_ci                                   IP_MULTICAST_LOOP,
13071cb0ef41Sopenharmony_ci                                   IPV6_MULTICAST_LOOP,
13081cb0ef41Sopenharmony_ci                                   on);
13091cb0ef41Sopenharmony_ci}
13101cb0ef41Sopenharmony_ci
13111cb0ef41Sopenharmony_ciint uv_udp_set_multicast_interface(uv_udp_t* handle, const char* interface_addr) {
13121cb0ef41Sopenharmony_ci  struct sockaddr_storage addr_st;
13131cb0ef41Sopenharmony_ci  struct sockaddr_in* addr4;
13141cb0ef41Sopenharmony_ci  struct sockaddr_in6* addr6;
13151cb0ef41Sopenharmony_ci
13161cb0ef41Sopenharmony_ci  addr4 = (struct sockaddr_in*) &addr_st;
13171cb0ef41Sopenharmony_ci  addr6 = (struct sockaddr_in6*) &addr_st;
13181cb0ef41Sopenharmony_ci
13191cb0ef41Sopenharmony_ci  if (!interface_addr) {
13201cb0ef41Sopenharmony_ci    memset(&addr_st, 0, sizeof addr_st);
13211cb0ef41Sopenharmony_ci    if (handle->flags & UV_HANDLE_IPV6) {
13221cb0ef41Sopenharmony_ci      addr_st.ss_family = AF_INET6;
13231cb0ef41Sopenharmony_ci      addr6->sin6_scope_id = 0;
13241cb0ef41Sopenharmony_ci    } else {
13251cb0ef41Sopenharmony_ci      addr_st.ss_family = AF_INET;
13261cb0ef41Sopenharmony_ci      addr4->sin_addr.s_addr = htonl(INADDR_ANY);
13271cb0ef41Sopenharmony_ci    }
13281cb0ef41Sopenharmony_ci  } else if (uv_ip4_addr(interface_addr, 0, addr4) == 0) {
13291cb0ef41Sopenharmony_ci    /* nothing, address was parsed */
13301cb0ef41Sopenharmony_ci  } else if (uv_ip6_addr(interface_addr, 0, addr6) == 0) {
13311cb0ef41Sopenharmony_ci    /* nothing, address was parsed */
13321cb0ef41Sopenharmony_ci  } else {
13331cb0ef41Sopenharmony_ci    return UV_EINVAL;
13341cb0ef41Sopenharmony_ci  }
13351cb0ef41Sopenharmony_ci
13361cb0ef41Sopenharmony_ci  if (addr_st.ss_family == AF_INET) {
13371cb0ef41Sopenharmony_ci    if (setsockopt(handle->io_watcher.fd,
13381cb0ef41Sopenharmony_ci                   IPPROTO_IP,
13391cb0ef41Sopenharmony_ci                   IP_MULTICAST_IF,
13401cb0ef41Sopenharmony_ci                   (void*) &addr4->sin_addr,
13411cb0ef41Sopenharmony_ci                   sizeof(addr4->sin_addr)) == -1) {
13421cb0ef41Sopenharmony_ci      return UV__ERR(errno);
13431cb0ef41Sopenharmony_ci    }
13441cb0ef41Sopenharmony_ci  } else if (addr_st.ss_family == AF_INET6) {
13451cb0ef41Sopenharmony_ci    if (setsockopt(handle->io_watcher.fd,
13461cb0ef41Sopenharmony_ci                   IPPROTO_IPV6,
13471cb0ef41Sopenharmony_ci                   IPV6_MULTICAST_IF,
13481cb0ef41Sopenharmony_ci                   &addr6->sin6_scope_id,
13491cb0ef41Sopenharmony_ci                   sizeof(addr6->sin6_scope_id)) == -1) {
13501cb0ef41Sopenharmony_ci      return UV__ERR(errno);
13511cb0ef41Sopenharmony_ci    }
13521cb0ef41Sopenharmony_ci  } else {
13531cb0ef41Sopenharmony_ci    assert(0 && "unexpected address family");
13541cb0ef41Sopenharmony_ci    abort();
13551cb0ef41Sopenharmony_ci  }
13561cb0ef41Sopenharmony_ci
13571cb0ef41Sopenharmony_ci  return 0;
13581cb0ef41Sopenharmony_ci}
13591cb0ef41Sopenharmony_ci
13601cb0ef41Sopenharmony_ciint uv_udp_getpeername(const uv_udp_t* handle,
13611cb0ef41Sopenharmony_ci                       struct sockaddr* name,
13621cb0ef41Sopenharmony_ci                       int* namelen) {
13631cb0ef41Sopenharmony_ci
13641cb0ef41Sopenharmony_ci  return uv__getsockpeername((const uv_handle_t*) handle,
13651cb0ef41Sopenharmony_ci                             getpeername,
13661cb0ef41Sopenharmony_ci                             name,
13671cb0ef41Sopenharmony_ci                             namelen);
13681cb0ef41Sopenharmony_ci}
13691cb0ef41Sopenharmony_ci
13701cb0ef41Sopenharmony_ciint uv_udp_getsockname(const uv_udp_t* handle,
13711cb0ef41Sopenharmony_ci                       struct sockaddr* name,
13721cb0ef41Sopenharmony_ci                       int* namelen) {
13731cb0ef41Sopenharmony_ci
13741cb0ef41Sopenharmony_ci  return uv__getsockpeername((const uv_handle_t*) handle,
13751cb0ef41Sopenharmony_ci                             getsockname,
13761cb0ef41Sopenharmony_ci                             name,
13771cb0ef41Sopenharmony_ci                             namelen);
13781cb0ef41Sopenharmony_ci}
13791cb0ef41Sopenharmony_ci
13801cb0ef41Sopenharmony_ci
13811cb0ef41Sopenharmony_ciint uv__udp_recv_start(uv_udp_t* handle,
13821cb0ef41Sopenharmony_ci                       uv_alloc_cb alloc_cb,
13831cb0ef41Sopenharmony_ci                       uv_udp_recv_cb recv_cb) {
13841cb0ef41Sopenharmony_ci  int err;
13851cb0ef41Sopenharmony_ci
13861cb0ef41Sopenharmony_ci  if (alloc_cb == NULL || recv_cb == NULL)
13871cb0ef41Sopenharmony_ci    return UV_EINVAL;
13881cb0ef41Sopenharmony_ci
13891cb0ef41Sopenharmony_ci  if (uv__io_active(&handle->io_watcher, POLLIN))
13901cb0ef41Sopenharmony_ci    return UV_EALREADY;  /* FIXME(bnoordhuis) Should be UV_EBUSY. */
13911cb0ef41Sopenharmony_ci
13921cb0ef41Sopenharmony_ci  err = uv__udp_maybe_deferred_bind(handle, AF_INET, 0);
13931cb0ef41Sopenharmony_ci  if (err)
13941cb0ef41Sopenharmony_ci    return err;
13951cb0ef41Sopenharmony_ci
13961cb0ef41Sopenharmony_ci  handle->alloc_cb = alloc_cb;
13971cb0ef41Sopenharmony_ci  handle->recv_cb = recv_cb;
13981cb0ef41Sopenharmony_ci
13991cb0ef41Sopenharmony_ci  uv__io_start(handle->loop, &handle->io_watcher, POLLIN);
14001cb0ef41Sopenharmony_ci  uv__handle_start(handle);
14011cb0ef41Sopenharmony_ci
14021cb0ef41Sopenharmony_ci  return 0;
14031cb0ef41Sopenharmony_ci}
14041cb0ef41Sopenharmony_ci
14051cb0ef41Sopenharmony_ci
14061cb0ef41Sopenharmony_ciint uv__udp_recv_stop(uv_udp_t* handle) {
14071cb0ef41Sopenharmony_ci  uv__io_stop(handle->loop, &handle->io_watcher, POLLIN);
14081cb0ef41Sopenharmony_ci
14091cb0ef41Sopenharmony_ci  if (!uv__io_active(&handle->io_watcher, POLLOUT))
14101cb0ef41Sopenharmony_ci    uv__handle_stop(handle);
14111cb0ef41Sopenharmony_ci
14121cb0ef41Sopenharmony_ci  handle->alloc_cb = NULL;
14131cb0ef41Sopenharmony_ci  handle->recv_cb = NULL;
14141cb0ef41Sopenharmony_ci
14151cb0ef41Sopenharmony_ci  return 0;
14161cb0ef41Sopenharmony_ci}
1417