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