• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
2  *
3  * Permission is hereby granted, free of charge, to any person obtaining a copy
4  * of this software and associated documentation files (the "Software"), to
5  * deal in the Software without restriction, including without limitation the
6  * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
7  * sell copies of the Software, and to permit persons to whom the Software is
8  * furnished to do so, subject to the following conditions:
9  *
10  * The above copyright notice and this permission notice shall be included in
11  * all copies or substantial portions of the Software.
12  *
13  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
18  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
19  * IN THE SOFTWARE.
20  */
21 
22 #include "uv.h"
23 #include "internal.h"
24 
25 #include <assert.h>
26 #include <string.h>
27 #include <errno.h>
28 #include <stdlib.h>
29 #include <unistd.h>
30 #if defined(__MVS__)
31 #include <xti.h>
32 #endif
33 #include <sys/un.h>
34 
35 #if defined(IPV6_JOIN_GROUP) && !defined(IPV6_ADD_MEMBERSHIP)
36 # define IPV6_ADD_MEMBERSHIP IPV6_JOIN_GROUP
37 #endif
38 
39 #if defined(IPV6_LEAVE_GROUP) && !defined(IPV6_DROP_MEMBERSHIP)
40 # define IPV6_DROP_MEMBERSHIP IPV6_LEAVE_GROUP
41 #endif
42 
43 static void uv__udp_run_completed(uv_udp_t* handle);
44 static void uv__udp_io(uv_loop_t* loop, uv__io_t* w, unsigned int revents);
45 static void uv__udp_recvmsg(uv_udp_t* handle);
46 static void uv__udp_sendmsg(uv_udp_t* handle);
47 static int uv__udp_maybe_deferred_bind(uv_udp_t* handle,
48                                        int domain,
49                                        unsigned int flags);
50 
51 
uv__udp_close(uv_udp_t * handle)52 void uv__udp_close(uv_udp_t* handle) {
53   uv__io_close(handle->loop, &handle->io_watcher);
54   uv__handle_stop(handle);
55 
56   if (handle->io_watcher.fd != -1) {
57     uv__close(handle->io_watcher.fd);
58     handle->io_watcher.fd = -1;
59   }
60 }
61 
62 
uv__udp_finish_close(uv_udp_t * handle)63 void uv__udp_finish_close(uv_udp_t* handle) {
64   uv_udp_send_t* req;
65   struct uv__queue* q;
66 
67   assert(!uv__io_active(&handle->io_watcher, POLLIN | POLLOUT));
68   assert(handle->io_watcher.fd == -1);
69 
70   while (!uv__queue_empty(&handle->write_queue)) {
71     q = uv__queue_head(&handle->write_queue);
72     uv__queue_remove(q);
73 
74     req = uv__queue_data(q, uv_udp_send_t, queue);
75     req->status = UV_ECANCELED;
76     uv__queue_insert_tail(&handle->write_completed_queue, &req->queue);
77   }
78 
79   uv__udp_run_completed(handle);
80 
81   assert(handle->send_queue_size == 0);
82   assert(handle->send_queue_count == 0);
83 
84   /* Now tear down the handle. */
85   handle->recv_cb = NULL;
86   handle->alloc_cb = NULL;
87   /* but _do not_ touch close_cb */
88 }
89 
90 
uv__udp_run_completed(uv_udp_t * handle)91 static void uv__udp_run_completed(uv_udp_t* handle) {
92   uv_udp_send_t* req;
93   struct uv__queue* q;
94 
95   assert(!(handle->flags & UV_HANDLE_UDP_PROCESSING));
96   handle->flags |= UV_HANDLE_UDP_PROCESSING;
97 
98   while (!uv__queue_empty(&handle->write_completed_queue)) {
99     q = uv__queue_head(&handle->write_completed_queue);
100     uv__queue_remove(q);
101 
102     req = uv__queue_data(q, uv_udp_send_t, queue);
103     uv__req_unregister(handle->loop, req);
104 
105     handle->send_queue_size -= uv__count_bufs(req->bufs, req->nbufs);
106     handle->send_queue_count--;
107 
108     if (req->bufs != req->bufsml)
109       uv__free(req->bufs);
110     req->bufs = NULL;
111 
112     if (req->send_cb == NULL)
113       continue;
114 
115     /* req->status >= 0 == bytes written
116      * req->status <  0 == errno
117      */
118     if (req->status >= 0)
119       req->send_cb(req, 0);
120     else
121       req->send_cb(req, req->status);
122   }
123 
124   if (uv__queue_empty(&handle->write_queue)) {
125     /* Pending queue and completion queue empty, stop watcher. */
126     uv__io_stop(handle->loop, &handle->io_watcher, POLLOUT);
127     if (!uv__io_active(&handle->io_watcher, POLLIN))
128       uv__handle_stop(handle);
129   }
130 
131   handle->flags &= ~UV_HANDLE_UDP_PROCESSING;
132 }
133 
134 
uv__udp_io(uv_loop_t * loop,uv__io_t * w,unsigned int revents)135 static void uv__udp_io(uv_loop_t* loop, uv__io_t* w, unsigned int revents) {
136   uv_udp_t* handle;
137 
138   handle = container_of(w, uv_udp_t, io_watcher);
139   assert(handle->type == UV_UDP);
140 
141   if (revents & POLLIN)
142     uv__udp_recvmsg(handle);
143 
144   if (revents & POLLOUT) {
145     uv__udp_sendmsg(handle);
146     uv__udp_run_completed(handle);
147   }
148 }
149 
uv__udp_recvmmsg(uv_udp_t * handle,uv_buf_t * buf)150 static int uv__udp_recvmmsg(uv_udp_t* handle, uv_buf_t* buf) {
151 #if defined(__linux__) || defined(__FreeBSD__)
152   struct sockaddr_in6 peers[20];
153   struct iovec iov[ARRAY_SIZE(peers)];
154   struct mmsghdr msgs[ARRAY_SIZE(peers)];
155   ssize_t nread;
156   uv_buf_t chunk_buf;
157   size_t chunks;
158   int flags;
159   size_t k;
160 
161   /* prepare structures for recvmmsg */
162   chunks = buf->len / UV__UDP_DGRAM_MAXSIZE;
163   if (chunks > ARRAY_SIZE(iov))
164     chunks = ARRAY_SIZE(iov);
165   for (k = 0; k < chunks; ++k) {
166     iov[k].iov_base = buf->base + k * UV__UDP_DGRAM_MAXSIZE;
167     iov[k].iov_len = UV__UDP_DGRAM_MAXSIZE;
168     memset(&msgs[k].msg_hdr, 0, sizeof(msgs[k].msg_hdr));
169     msgs[k].msg_hdr.msg_iov = iov + k;
170     msgs[k].msg_hdr.msg_iovlen = 1;
171     msgs[k].msg_hdr.msg_name = peers + k;
172     msgs[k].msg_hdr.msg_namelen = sizeof(peers[0]);
173     msgs[k].msg_hdr.msg_control = NULL;
174     msgs[k].msg_hdr.msg_controllen = 0;
175     msgs[k].msg_hdr.msg_flags = 0;
176   }
177 
178   do
179     nread = recvmmsg(handle->io_watcher.fd, msgs, chunks, 0, NULL);
180   while (nread == -1 && errno == EINTR);
181 
182   if (nread < 1) {
183     if (nread == 0 || errno == EAGAIN || errno == EWOULDBLOCK)
184       handle->recv_cb(handle, 0, buf, NULL, 0);
185     else
186       handle->recv_cb(handle, UV__ERR(errno), buf, NULL, 0);
187   } else {
188     /* pass each chunk to the application */
189     for (k = 0; k < (size_t) nread && handle->recv_cb != NULL; k++) {
190       flags = UV_UDP_MMSG_CHUNK;
191       if (msgs[k].msg_hdr.msg_flags & MSG_TRUNC)
192         flags |= UV_UDP_PARTIAL;
193 
194       chunk_buf = uv_buf_init(iov[k].iov_base, iov[k].iov_len);
195       handle->recv_cb(handle,
196                       msgs[k].msg_len,
197                       &chunk_buf,
198                       msgs[k].msg_hdr.msg_name,
199                       flags);
200     }
201 
202     /* one last callback so the original buffer is freed */
203     if (handle->recv_cb != NULL)
204       handle->recv_cb(handle, 0, buf, NULL, UV_UDP_MMSG_FREE);
205   }
206   return nread;
207 #else  /* __linux__ || ____FreeBSD__ */
208   return UV_ENOSYS;
209 #endif  /* __linux__ || ____FreeBSD__ */
210 }
211 
uv__udp_recvmsg(uv_udp_t * handle)212 static void uv__udp_recvmsg(uv_udp_t* handle) {
213   struct sockaddr_storage peer;
214   struct msghdr h;
215   ssize_t nread;
216   uv_buf_t buf;
217   int flags;
218   int count;
219 
220   assert(handle->recv_cb != NULL);
221   assert(handle->alloc_cb != NULL);
222 
223   /* Prevent loop starvation when the data comes in as fast as (or faster than)
224    * we can read it. XXX Need to rearm fd if we switch to edge-triggered I/O.
225    */
226   count = 32;
227 
228   do {
229     buf = uv_buf_init(NULL, 0);
230     handle->alloc_cb((uv_handle_t*) handle, UV__UDP_DGRAM_MAXSIZE, &buf);
231     if (buf.base == NULL || buf.len == 0) {
232       handle->recv_cb(handle, UV_ENOBUFS, &buf, NULL, 0);
233       return;
234     }
235     assert(buf.base != NULL);
236 
237     if (uv_udp_using_recvmmsg(handle)) {
238       nread = uv__udp_recvmmsg(handle, &buf);
239       if (nread > 0)
240         count -= nread;
241       continue;
242     }
243 
244     memset(&h, 0, sizeof(h));
245     memset(&peer, 0, sizeof(peer));
246     h.msg_name = &peer;
247     h.msg_namelen = sizeof(peer);
248     h.msg_iov = (void*) &buf;
249     h.msg_iovlen = 1;
250 
251     do {
252       nread = recvmsg(handle->io_watcher.fd, &h, 0);
253     }
254     while (nread == -1 && errno == EINTR);
255 
256     if (nread == -1) {
257       if (errno == EAGAIN || errno == EWOULDBLOCK)
258         handle->recv_cb(handle, 0, &buf, NULL, 0);
259       else
260         handle->recv_cb(handle, UV__ERR(errno), &buf, NULL, 0);
261     }
262     else {
263       flags = 0;
264       if (h.msg_flags & MSG_TRUNC)
265         flags |= UV_UDP_PARTIAL;
266 
267       handle->recv_cb(handle, nread, &buf, (const struct sockaddr*) &peer, flags);
268     }
269     count--;
270   }
271   /* recv_cb callback may decide to pause or close the handle */
272   while (nread != -1
273       && count > 0
274       && handle->io_watcher.fd != -1
275       && handle->recv_cb != NULL);
276 }
277 
uv__udp_sendmsg(uv_udp_t * handle)278 static void uv__udp_sendmsg(uv_udp_t* handle) {
279 #if defined(__linux__) || defined(__FreeBSD__)
280   uv_udp_send_t* req;
281   struct mmsghdr h[20];
282   struct mmsghdr* p;
283   struct uv__queue* q;
284   ssize_t npkts;
285   size_t pkts;
286   size_t i;
287 
288   if (uv__queue_empty(&handle->write_queue))
289     return;
290 
291 write_queue_drain:
292   for (pkts = 0, q = uv__queue_head(&handle->write_queue);
293        pkts < ARRAY_SIZE(h) && q != &handle->write_queue;
294        ++pkts, q = uv__queue_head(q)) {
295     assert(q != NULL);
296     req = uv__queue_data(q, uv_udp_send_t, queue);
297     assert(req != NULL);
298 
299     p = &h[pkts];
300     memset(p, 0, sizeof(*p));
301     if (req->addr.ss_family == AF_UNSPEC) {
302       p->msg_hdr.msg_name = NULL;
303       p->msg_hdr.msg_namelen = 0;
304     } else {
305       p->msg_hdr.msg_name = &req->addr;
306       if (req->addr.ss_family == AF_INET6)
307         p->msg_hdr.msg_namelen = sizeof(struct sockaddr_in6);
308       else if (req->addr.ss_family == AF_INET)
309         p->msg_hdr.msg_namelen = sizeof(struct sockaddr_in);
310       else if (req->addr.ss_family == AF_UNIX)
311         p->msg_hdr.msg_namelen = sizeof(struct sockaddr_un);
312       else {
313         assert(0 && "unsupported address family");
314         abort();
315       }
316     }
317     h[pkts].msg_hdr.msg_iov = (struct iovec*) req->bufs;
318     h[pkts].msg_hdr.msg_iovlen = req->nbufs;
319   }
320 
321   do
322     npkts = sendmmsg(handle->io_watcher.fd, h, pkts, 0);
323   while (npkts == -1 && errno == EINTR);
324 
325   if (npkts < 1) {
326     if (errno == EAGAIN || errno == EWOULDBLOCK || errno == ENOBUFS)
327       return;
328     for (i = 0, q = uv__queue_head(&handle->write_queue);
329          i < pkts && q != &handle->write_queue;
330          ++i, q = uv__queue_head(&handle->write_queue)) {
331       assert(q != NULL);
332       req = uv__queue_data(q, uv_udp_send_t, queue);
333       assert(req != NULL);
334 
335       req->status = UV__ERR(errno);
336       uv__queue_remove(&req->queue);
337       uv__queue_insert_tail(&handle->write_completed_queue, &req->queue);
338     }
339     uv__io_feed(handle->loop, &handle->io_watcher);
340     return;
341   }
342 
343   /* Safety: npkts known to be >0 below. Hence cast from ssize_t
344    * to size_t safe.
345    */
346   for (i = 0, q = uv__queue_head(&handle->write_queue);
347        i < (size_t)npkts && q != &handle->write_queue;
348        ++i, q = uv__queue_head(&handle->write_queue)) {
349     assert(q != NULL);
350     req = uv__queue_data(q, uv_udp_send_t, queue);
351     assert(req != NULL);
352 
353     req->status = req->bufs[0].len;
354 
355     /* Sending a datagram is an atomic operation: either all data
356      * is written or nothing is (and EMSGSIZE is raised). That is
357      * why we don't handle partial writes. Just pop the request
358      * off the write queue and onto the completed queue, done.
359      */
360     uv__queue_remove(&req->queue);
361     uv__queue_insert_tail(&handle->write_completed_queue, &req->queue);
362   }
363 
364   /* couldn't batch everything, continue sending (jump to avoid stack growth) */
365   if (!uv__queue_empty(&handle->write_queue))
366     goto write_queue_drain;
367   uv__io_feed(handle->loop, &handle->io_watcher);
368 #else  /* __linux__ || ____FreeBSD__ */
369   uv_udp_send_t* req;
370   struct msghdr h;
371   struct uv__queue* q;
372   ssize_t size;
373 
374   while (!uv__queue_empty(&handle->write_queue)) {
375     q = uv__queue_head(&handle->write_queue);
376     assert(q != NULL);
377 
378     req = uv__queue_data(q, uv_udp_send_t, queue);
379     assert(req != NULL);
380 
381     memset(&h, 0, sizeof h);
382     if (req->addr.ss_family == AF_UNSPEC) {
383       h.msg_name = NULL;
384       h.msg_namelen = 0;
385     } else {
386       h.msg_name = &req->addr;
387       if (req->addr.ss_family == AF_INET6)
388         h.msg_namelen = sizeof(struct sockaddr_in6);
389       else if (req->addr.ss_family == AF_INET)
390         h.msg_namelen = sizeof(struct sockaddr_in);
391       else if (req->addr.ss_family == AF_UNIX)
392         h.msg_namelen = sizeof(struct sockaddr_un);
393       else {
394         assert(0 && "unsupported address family");
395         abort();
396       }
397     }
398     h.msg_iov = (struct iovec*) req->bufs;
399     h.msg_iovlen = req->nbufs;
400 
401     do {
402       size = sendmsg(handle->io_watcher.fd, &h, 0);
403     } while (size == -1 && errno == EINTR);
404 
405     if (size == -1) {
406       if (errno == EAGAIN || errno == EWOULDBLOCK || errno == ENOBUFS)
407         break;
408     }
409 
410     req->status = (size == -1 ? UV__ERR(errno) : size);
411 
412     /* Sending a datagram is an atomic operation: either all data
413      * is written or nothing is (and EMSGSIZE is raised). That is
414      * why we don't handle partial writes. Just pop the request
415      * off the write queue and onto the completed queue, done.
416      */
417     uv__queue_remove(&req->queue);
418     uv__queue_insert_tail(&handle->write_completed_queue, &req->queue);
419     uv__io_feed(handle->loop, &handle->io_watcher);
420   }
421 #endif  /* __linux__ || ____FreeBSD__ */
422 }
423 
424 /* On the BSDs, SO_REUSEPORT implies SO_REUSEADDR but with some additional
425  * refinements for programs that use multicast.
426  *
427  * Linux as of 3.9 has a SO_REUSEPORT socket option but with semantics that
428  * are different from the BSDs: it _shares_ the port rather than steal it
429  * from the current listener.  While useful, it's not something we can emulate
430  * on other platforms so we don't enable it.
431  *
432  * zOS does not support getsockname with SO_REUSEPORT option when using
433  * AF_UNIX.
434  */
uv__set_reuse(int fd)435 static int uv__set_reuse(int fd) {
436   int yes;
437   yes = 1;
438 
439 #if defined(SO_REUSEPORT) && defined(__MVS__)
440   struct sockaddr_in sockfd;
441   unsigned int sockfd_len = sizeof(sockfd);
442   if (getsockname(fd, (struct sockaddr*) &sockfd, &sockfd_len) == -1)
443       return UV__ERR(errno);
444   if (sockfd.sin_family == AF_UNIX) {
445     if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes)))
446       return UV__ERR(errno);
447   } else {
448     if (setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, &yes, sizeof(yes)))
449        return UV__ERR(errno);
450   }
451 #elif defined(SO_REUSEPORT) && !defined(__linux__) && !defined(__GNU__) && \
452 	!defined(__sun__)
453   if (setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, &yes, sizeof(yes)))
454     return UV__ERR(errno);
455 #else
456   if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes)))
457     return UV__ERR(errno);
458 #endif
459 
460   return 0;
461 }
462 
463 /*
464  * The Linux kernel suppresses some ICMP error messages by default for UDP
465  * sockets. Setting IP_RECVERR/IPV6_RECVERR on the socket enables full ICMP
466  * error reporting, hopefully resulting in faster failover to working name
467  * servers.
468  */
uv__set_recverr(int fd,sa_family_t ss_family)469 static int uv__set_recverr(int fd, sa_family_t ss_family) {
470 #if defined(__linux__)
471   int yes;
472 
473   yes = 1;
474   if (ss_family == AF_INET) {
475     if (setsockopt(fd, IPPROTO_IP, IP_RECVERR, &yes, sizeof(yes)))
476       return UV__ERR(errno);
477   } else if (ss_family == AF_INET6) {
478     if (setsockopt(fd, IPPROTO_IPV6, IPV6_RECVERR, &yes, sizeof(yes)))
479        return UV__ERR(errno);
480   }
481 #endif
482   return 0;
483 }
484 
485 
uv__udp_bind(uv_udp_t * handle,const struct sockaddr * addr,unsigned int addrlen,unsigned int flags)486 int uv__udp_bind(uv_udp_t* handle,
487                  const struct sockaddr* addr,
488                  unsigned int addrlen,
489                  unsigned int flags) {
490   int err;
491   int yes;
492   int fd;
493 
494   /* Check for bad flags. */
495   if (flags & ~(UV_UDP_IPV6ONLY | UV_UDP_REUSEADDR | UV_UDP_LINUX_RECVERR))
496     return UV_EINVAL;
497 
498   /* Cannot set IPv6-only mode on non-IPv6 socket. */
499   if ((flags & UV_UDP_IPV6ONLY) && addr->sa_family != AF_INET6)
500     return UV_EINVAL;
501 
502   fd = handle->io_watcher.fd;
503   if (fd == -1) {
504     err = uv__socket(addr->sa_family, SOCK_DGRAM, 0);
505     if (err < 0)
506       return err;
507     fd = err;
508     handle->io_watcher.fd = fd;
509   }
510 
511   if (flags & UV_UDP_LINUX_RECVERR) {
512     err = uv__set_recverr(fd, addr->sa_family);
513     if (err)
514       return err;
515   }
516 
517   if (flags & UV_UDP_REUSEADDR) {
518     err = uv__set_reuse(fd);
519     if (err)
520       return err;
521   }
522 
523   if (flags & UV_UDP_IPV6ONLY) {
524 #ifdef IPV6_V6ONLY
525     yes = 1;
526     if (setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &yes, sizeof yes) == -1) {
527       err = UV__ERR(errno);
528       return err;
529     }
530 #else
531     err = UV_ENOTSUP;
532     return err;
533 #endif
534   }
535 
536   if (bind(fd, addr, addrlen)) {
537     err = UV__ERR(errno);
538     if (errno == EAFNOSUPPORT)
539       /* OSX, other BSDs and SunoS fail with EAFNOSUPPORT when binding a
540        * socket created with AF_INET to an AF_INET6 address or vice versa. */
541       err = UV_EINVAL;
542     return err;
543   }
544 
545   if (addr->sa_family == AF_INET6)
546     handle->flags |= UV_HANDLE_IPV6;
547 
548   handle->flags |= UV_HANDLE_BOUND;
549   return 0;
550 }
551 
552 
uv__udp_maybe_deferred_bind(uv_udp_t * handle,int domain,unsigned int flags)553 static int uv__udp_maybe_deferred_bind(uv_udp_t* handle,
554                                        int domain,
555                                        unsigned int flags) {
556   union uv__sockaddr taddr;
557   socklen_t addrlen;
558 
559   if (handle->io_watcher.fd != -1)
560     return 0;
561 
562   switch (domain) {
563   case AF_INET:
564   {
565     struct sockaddr_in* addr = &taddr.in;
566     memset(addr, 0, sizeof *addr);
567     addr->sin_family = AF_INET;
568     addr->sin_addr.s_addr = INADDR_ANY;
569     addrlen = sizeof *addr;
570     break;
571   }
572   case AF_INET6:
573   {
574     struct sockaddr_in6* addr = &taddr.in6;
575     memset(addr, 0, sizeof *addr);
576     addr->sin6_family = AF_INET6;
577     addr->sin6_addr = in6addr_any;
578     addrlen = sizeof *addr;
579     break;
580   }
581   default:
582     assert(0 && "unsupported address family");
583     abort();
584   }
585 
586   return uv__udp_bind(handle, &taddr.addr, addrlen, flags);
587 }
588 
589 
uv__udp_connect(uv_udp_t * handle,const struct sockaddr * addr,unsigned int addrlen)590 int uv__udp_connect(uv_udp_t* handle,
591                     const struct sockaddr* addr,
592                     unsigned int addrlen) {
593   int err;
594 
595   err = uv__udp_maybe_deferred_bind(handle, addr->sa_family, 0);
596   if (err)
597     return err;
598 
599   do {
600     errno = 0;
601     err = connect(handle->io_watcher.fd, addr, addrlen);
602   } while (err == -1 && errno == EINTR);
603 
604   if (err)
605     return UV__ERR(errno);
606 
607   handle->flags |= UV_HANDLE_UDP_CONNECTED;
608 
609   return 0;
610 }
611 
612 /* From https://pubs.opengroup.org/onlinepubs/9699919799/functions/connect.html
613  * Any of uv supported UNIXs kernel should be standardized, but the kernel
614  * implementation logic not same, let's use pseudocode to explain the udp
615  * disconnect behaviors:
616  *
617  * Predefined stubs for pseudocode:
618  *   1. sodisconnect: The function to perform the real udp disconnect
619  *   2. pru_connect: The function to perform the real udp connect
620  *   3. so: The kernel object match with socket fd
621  *   4. addr: The sockaddr parameter from user space
622  *
623  * BSDs:
624  *   if(sodisconnect(so) == 0) { // udp disconnect succeed
625  *     if (addr->sa_len != so->addr->sa_len) return EINVAL;
626  *     if (addr->sa_family != so->addr->sa_family) return EAFNOSUPPORT;
627  *     pru_connect(so);
628  *   }
629  *   else return EISCONN;
630  *
631  * z/OS (same with Windows):
632  *   if(addr->sa_len < so->addr->sa_len) return EINVAL;
633  *   if (addr->sa_family == AF_UNSPEC) sodisconnect(so);
634  *
635  * AIX:
636  *   if(addr->sa_len != sizeof(struct sockaddr)) return EINVAL; // ignore ip proto version
637  *   if (addr->sa_family == AF_UNSPEC) sodisconnect(so);
638  *
639  * Linux,Others:
640  *   if(addr->sa_len < sizeof(struct sockaddr)) return EINVAL;
641  *   if (addr->sa_family == AF_UNSPEC) sodisconnect(so);
642  */
uv__udp_disconnect(uv_udp_t * handle)643 int uv__udp_disconnect(uv_udp_t* handle) {
644     int r;
645 #if defined(__MVS__)
646     struct sockaddr_storage addr;
647 #else
648     struct sockaddr addr;
649 #endif
650 
651     memset(&addr, 0, sizeof(addr));
652 
653 #if defined(__MVS__)
654     addr.ss_family = AF_UNSPEC;
655 #else
656     addr.sa_family = AF_UNSPEC;
657 #endif
658 
659     do {
660       errno = 0;
661 #ifdef __PASE__
662       /* On IBMi a connectionless transport socket can be disconnected by
663        * either setting the addr parameter to NULL or setting the
664        * addr_length parameter to zero, and issuing another connect().
665        * https://www.ibm.com/docs/en/i/7.4?topic=ssw_ibm_i_74/apis/connec.htm
666        */
667       r = connect(handle->io_watcher.fd, (struct sockaddr*) NULL, 0);
668 #else
669       r = connect(handle->io_watcher.fd, (struct sockaddr*) &addr, sizeof(addr));
670 #endif
671     } while (r == -1 && errno == EINTR);
672 
673     if (r == -1) {
674 #if defined(BSD)  /* The macro BSD is from sys/param.h */
675       if (errno != EAFNOSUPPORT && errno != EINVAL)
676         return UV__ERR(errno);
677 #else
678       return UV__ERR(errno);
679 #endif
680     }
681 
682     handle->flags &= ~UV_HANDLE_UDP_CONNECTED;
683     return 0;
684 }
685 
uv__udp_send(uv_udp_send_t * req,uv_udp_t * handle,const uv_buf_t bufs[],unsigned int nbufs,const struct sockaddr * addr,unsigned int addrlen,uv_udp_send_cb send_cb)686 int uv__udp_send(uv_udp_send_t* req,
687                  uv_udp_t* handle,
688                  const uv_buf_t bufs[],
689                  unsigned int nbufs,
690                  const struct sockaddr* addr,
691                  unsigned int addrlen,
692                  uv_udp_send_cb send_cb) {
693   int err;
694   int empty_queue;
695 
696   assert(nbufs > 0);
697 
698   if (addr) {
699     err = uv__udp_maybe_deferred_bind(handle, addr->sa_family, 0);
700     if (err)
701       return err;
702   }
703 
704   /* It's legal for send_queue_count > 0 even when the write_queue is empty;
705    * it means there are error-state requests in the write_completed_queue that
706    * will touch up send_queue_size/count later.
707    */
708   empty_queue = (handle->send_queue_count == 0);
709 
710   uv__req_init(handle->loop, req, UV_UDP_SEND);
711   assert(addrlen <= sizeof(req->addr));
712   if (addr == NULL)
713     req->addr.ss_family = AF_UNSPEC;
714   else
715     memcpy(&req->addr, addr, addrlen);
716   req->send_cb = send_cb;
717   req->handle = handle;
718   req->nbufs = nbufs;
719 
720   req->bufs = req->bufsml;
721   if (nbufs > ARRAY_SIZE(req->bufsml))
722     req->bufs = uv__malloc(nbufs * sizeof(bufs[0]));
723 
724   if (req->bufs == NULL) {
725     uv__req_unregister(handle->loop, req);
726     return UV_ENOMEM;
727   }
728 
729   memcpy(req->bufs, bufs, nbufs * sizeof(bufs[0]));
730   handle->send_queue_size += uv__count_bufs(req->bufs, req->nbufs);
731   handle->send_queue_count++;
732   uv__queue_insert_tail(&handle->write_queue, &req->queue);
733   uv__handle_start(handle);
734 
735   if (empty_queue && !(handle->flags & UV_HANDLE_UDP_PROCESSING)) {
736     uv__udp_sendmsg(handle);
737 
738     /* `uv__udp_sendmsg` may not be able to do non-blocking write straight
739      * away. In such cases the `io_watcher` has to be queued for asynchronous
740      * write.
741      */
742     if (!uv__queue_empty(&handle->write_queue))
743       uv__io_start(handle->loop, &handle->io_watcher, POLLOUT);
744   } else {
745     uv__io_start(handle->loop, &handle->io_watcher, POLLOUT);
746   }
747 
748   return 0;
749 }
750 
751 
uv__udp_try_send(uv_udp_t * handle,const uv_buf_t bufs[],unsigned int nbufs,const struct sockaddr * addr,unsigned int addrlen)752 int uv__udp_try_send(uv_udp_t* handle,
753                      const uv_buf_t bufs[],
754                      unsigned int nbufs,
755                      const struct sockaddr* addr,
756                      unsigned int addrlen) {
757   int err;
758   struct msghdr h;
759   ssize_t size;
760 
761   assert(nbufs > 0);
762 
763   /* already sending a message */
764   if (handle->send_queue_count != 0)
765     return UV_EAGAIN;
766 
767   if (addr) {
768     err = uv__udp_maybe_deferred_bind(handle, addr->sa_family, 0);
769     if (err)
770       return err;
771   } else {
772     assert(handle->flags & UV_HANDLE_UDP_CONNECTED);
773   }
774 
775   memset(&h, 0, sizeof h);
776   h.msg_name = (struct sockaddr*) addr;
777   h.msg_namelen = addrlen;
778   h.msg_iov = (struct iovec*) bufs;
779   h.msg_iovlen = nbufs;
780 
781   do {
782     size = sendmsg(handle->io_watcher.fd, &h, 0);
783   } while (size == -1 && errno == EINTR);
784 
785   if (size == -1) {
786     if (errno == EAGAIN || errno == EWOULDBLOCK || errno == ENOBUFS)
787       return UV_EAGAIN;
788     else
789       return UV__ERR(errno);
790   }
791 
792   return size;
793 }
794 
795 
uv__udp_set_membership4(uv_udp_t * handle,const struct sockaddr_in * multicast_addr,const char * interface_addr,uv_membership membership)796 static int uv__udp_set_membership4(uv_udp_t* handle,
797                                    const struct sockaddr_in* multicast_addr,
798                                    const char* interface_addr,
799                                    uv_membership membership) {
800   struct ip_mreq mreq;
801   int optname;
802   int err;
803 
804   memset(&mreq, 0, sizeof mreq);
805 
806   if (interface_addr) {
807     err = uv_inet_pton(AF_INET, interface_addr, &mreq.imr_interface.s_addr);
808     if (err)
809       return err;
810   } else {
811     mreq.imr_interface.s_addr = htonl(INADDR_ANY);
812   }
813 
814   mreq.imr_multiaddr.s_addr = multicast_addr->sin_addr.s_addr;
815 
816   switch (membership) {
817   case UV_JOIN_GROUP:
818     optname = IP_ADD_MEMBERSHIP;
819     break;
820   case UV_LEAVE_GROUP:
821     optname = IP_DROP_MEMBERSHIP;
822     break;
823   default:
824     return UV_EINVAL;
825   }
826 
827   if (setsockopt(handle->io_watcher.fd,
828                  IPPROTO_IP,
829                  optname,
830                  &mreq,
831                  sizeof(mreq))) {
832 #if defined(__MVS__)
833   if (errno == ENXIO)
834     return UV_ENODEV;
835 #endif
836     return UV__ERR(errno);
837   }
838 
839   return 0;
840 }
841 
842 
uv__udp_set_membership6(uv_udp_t * handle,const struct sockaddr_in6 * multicast_addr,const char * interface_addr,uv_membership membership)843 static int uv__udp_set_membership6(uv_udp_t* handle,
844                                    const struct sockaddr_in6* multicast_addr,
845                                    const char* interface_addr,
846                                    uv_membership membership) {
847   int optname;
848   struct ipv6_mreq mreq;
849   struct sockaddr_in6 addr6;
850 
851   memset(&mreq, 0, sizeof mreq);
852 
853   if (interface_addr) {
854     if (uv_ip6_addr(interface_addr, 0, &addr6))
855       return UV_EINVAL;
856     mreq.ipv6mr_interface = addr6.sin6_scope_id;
857   } else {
858     mreq.ipv6mr_interface = 0;
859   }
860 
861   mreq.ipv6mr_multiaddr = multicast_addr->sin6_addr;
862 
863   switch (membership) {
864   case UV_JOIN_GROUP:
865     optname = IPV6_ADD_MEMBERSHIP;
866     break;
867   case UV_LEAVE_GROUP:
868     optname = IPV6_DROP_MEMBERSHIP;
869     break;
870   default:
871     return UV_EINVAL;
872   }
873 
874   if (setsockopt(handle->io_watcher.fd,
875                  IPPROTO_IPV6,
876                  optname,
877                  &mreq,
878                  sizeof(mreq))) {
879 #if defined(__MVS__)
880   if (errno == ENXIO)
881     return UV_ENODEV;
882 #endif
883     return UV__ERR(errno);
884   }
885 
886   return 0;
887 }
888 
889 
890 #if !defined(__OpenBSD__) &&                                        \
891     !defined(__NetBSD__) &&                                         \
892     !defined(__ANDROID__) &&                                        \
893     !defined(__DragonFly__) &&                                      \
894     !defined(__QNX__) &&                                            \
895     !defined(__GNU__)
uv__udp_set_source_membership4(uv_udp_t * handle,const struct sockaddr_in * multicast_addr,const char * interface_addr,const struct sockaddr_in * source_addr,uv_membership membership)896 static int uv__udp_set_source_membership4(uv_udp_t* handle,
897                                           const struct sockaddr_in* multicast_addr,
898                                           const char* interface_addr,
899                                           const struct sockaddr_in* source_addr,
900                                           uv_membership membership) {
901   struct ip_mreq_source mreq;
902   int optname;
903   int err;
904 
905   err = uv__udp_maybe_deferred_bind(handle, AF_INET, UV_UDP_REUSEADDR);
906   if (err)
907     return err;
908 
909   memset(&mreq, 0, sizeof(mreq));
910 
911   if (interface_addr != NULL) {
912     err = uv_inet_pton(AF_INET, interface_addr, &mreq.imr_interface.s_addr);
913     if (err)
914       return err;
915   } else {
916     mreq.imr_interface.s_addr = htonl(INADDR_ANY);
917   }
918 
919   mreq.imr_multiaddr.s_addr = multicast_addr->sin_addr.s_addr;
920   mreq.imr_sourceaddr.s_addr = source_addr->sin_addr.s_addr;
921 
922   if (membership == UV_JOIN_GROUP)
923     optname = IP_ADD_SOURCE_MEMBERSHIP;
924   else if (membership == UV_LEAVE_GROUP)
925     optname = IP_DROP_SOURCE_MEMBERSHIP;
926   else
927     return UV_EINVAL;
928 
929   if (setsockopt(handle->io_watcher.fd,
930                  IPPROTO_IP,
931                  optname,
932                  &mreq,
933                  sizeof(mreq))) {
934     return UV__ERR(errno);
935   }
936 
937   return 0;
938 }
939 
940 
uv__udp_set_source_membership6(uv_udp_t * handle,const struct sockaddr_in6 * multicast_addr,const char * interface_addr,const struct sockaddr_in6 * source_addr,uv_membership membership)941 static int uv__udp_set_source_membership6(uv_udp_t* handle,
942                                           const struct sockaddr_in6* multicast_addr,
943                                           const char* interface_addr,
944                                           const struct sockaddr_in6* source_addr,
945                                           uv_membership membership) {
946   struct group_source_req mreq;
947   struct sockaddr_in6 addr6;
948   int optname;
949   int err;
950 
951   err = uv__udp_maybe_deferred_bind(handle, AF_INET6, UV_UDP_REUSEADDR);
952   if (err)
953     return err;
954 
955   memset(&mreq, 0, sizeof(mreq));
956 
957   if (interface_addr != NULL) {
958     err = uv_ip6_addr(interface_addr, 0, &addr6);
959     if (err)
960       return err;
961     mreq.gsr_interface = addr6.sin6_scope_id;
962   } else {
963     mreq.gsr_interface = 0;
964   }
965 
966   STATIC_ASSERT(sizeof(mreq.gsr_group) >= sizeof(*multicast_addr));
967   STATIC_ASSERT(sizeof(mreq.gsr_source) >= sizeof(*source_addr));
968   memcpy(&mreq.gsr_group, multicast_addr, sizeof(*multicast_addr));
969   memcpy(&mreq.gsr_source, source_addr, sizeof(*source_addr));
970 
971   if (membership == UV_JOIN_GROUP)
972     optname = MCAST_JOIN_SOURCE_GROUP;
973   else if (membership == UV_LEAVE_GROUP)
974     optname = MCAST_LEAVE_SOURCE_GROUP;
975   else
976     return UV_EINVAL;
977 
978   if (setsockopt(handle->io_watcher.fd,
979                  IPPROTO_IPV6,
980                  optname,
981                  &mreq,
982                  sizeof(mreq))) {
983     return UV__ERR(errno);
984   }
985 
986   return 0;
987 }
988 #endif
989 
990 
uv__udp_init_ex(uv_loop_t * loop,uv_udp_t * handle,unsigned flags,int domain)991 int uv__udp_init_ex(uv_loop_t* loop,
992                     uv_udp_t* handle,
993                     unsigned flags,
994                     int domain) {
995   int fd;
996 
997   fd = -1;
998   if (domain != AF_UNSPEC) {
999     fd = uv__socket(domain, SOCK_DGRAM, 0);
1000     if (fd < 0)
1001       return fd;
1002   }
1003 
1004   uv__handle_init(loop, (uv_handle_t*)handle, UV_UDP);
1005   handle->alloc_cb = NULL;
1006   handle->recv_cb = NULL;
1007   handle->send_queue_size = 0;
1008   handle->send_queue_count = 0;
1009   uv__io_init(&handle->io_watcher, uv__udp_io, fd);
1010   uv__queue_init(&handle->write_queue);
1011   uv__queue_init(&handle->write_completed_queue);
1012 
1013   return 0;
1014 }
1015 
1016 
uv_udp_using_recvmmsg(const uv_udp_t * handle)1017 int uv_udp_using_recvmmsg(const uv_udp_t* handle) {
1018 #if defined(__linux__) || defined(__FreeBSD__)
1019   if (handle->flags & UV_HANDLE_UDP_RECVMMSG)
1020     return 1;
1021 #endif
1022   return 0;
1023 }
1024 
1025 
uv_udp_open(uv_udp_t * handle,uv_os_sock_t sock)1026 int uv_udp_open(uv_udp_t* handle, uv_os_sock_t sock) {
1027   int err;
1028 
1029   /* Check for already active socket. */
1030   if (handle->io_watcher.fd != -1)
1031     return UV_EBUSY;
1032 
1033   if (uv__fd_exists(handle->loop, sock))
1034     return UV_EEXIST;
1035 
1036   err = uv__nonblock(sock, 1);
1037   if (err)
1038     return err;
1039 
1040   err = uv__set_reuse(sock);
1041   if (err)
1042     return err;
1043 
1044   handle->io_watcher.fd = sock;
1045   if (uv__udp_is_connected(handle))
1046     handle->flags |= UV_HANDLE_UDP_CONNECTED;
1047 
1048   return 0;
1049 }
1050 
1051 
uv_udp_set_membership(uv_udp_t * handle,const char * multicast_addr,const char * interface_addr,uv_membership membership)1052 int uv_udp_set_membership(uv_udp_t* handle,
1053                           const char* multicast_addr,
1054                           const char* interface_addr,
1055                           uv_membership membership) {
1056   int err;
1057   struct sockaddr_in addr4;
1058   struct sockaddr_in6 addr6;
1059 
1060   if (uv_ip4_addr(multicast_addr, 0, &addr4) == 0) {
1061     err = uv__udp_maybe_deferred_bind(handle, AF_INET, UV_UDP_REUSEADDR);
1062     if (err)
1063       return err;
1064     return uv__udp_set_membership4(handle, &addr4, interface_addr, membership);
1065   } else if (uv_ip6_addr(multicast_addr, 0, &addr6) == 0) {
1066     err = uv__udp_maybe_deferred_bind(handle, AF_INET6, UV_UDP_REUSEADDR);
1067     if (err)
1068       return err;
1069     return uv__udp_set_membership6(handle, &addr6, interface_addr, membership);
1070   } else {
1071     return UV_EINVAL;
1072   }
1073 }
1074 
1075 
uv_udp_set_source_membership(uv_udp_t * handle,const char * multicast_addr,const char * interface_addr,const char * source_addr,uv_membership membership)1076 int uv_udp_set_source_membership(uv_udp_t* handle,
1077                                  const char* multicast_addr,
1078                                  const char* interface_addr,
1079                                  const char* source_addr,
1080                                  uv_membership membership) {
1081 #if !defined(__OpenBSD__) &&                                        \
1082     !defined(__NetBSD__) &&                                         \
1083     !defined(__ANDROID__) &&                                        \
1084     !defined(__DragonFly__) &&                                      \
1085     !defined(__QNX__) &&                                            \
1086     !defined(__GNU__)
1087   int err;
1088   union uv__sockaddr mcast_addr;
1089   union uv__sockaddr src_addr;
1090 
1091   err = uv_ip4_addr(multicast_addr, 0, &mcast_addr.in);
1092   if (err) {
1093     err = uv_ip6_addr(multicast_addr, 0, &mcast_addr.in6);
1094     if (err)
1095       return err;
1096     err = uv_ip6_addr(source_addr, 0, &src_addr.in6);
1097     if (err)
1098       return err;
1099     return uv__udp_set_source_membership6(handle,
1100                                           &mcast_addr.in6,
1101                                           interface_addr,
1102                                           &src_addr.in6,
1103                                           membership);
1104   }
1105 
1106   err = uv_ip4_addr(source_addr, 0, &src_addr.in);
1107   if (err)
1108     return err;
1109   return uv__udp_set_source_membership4(handle,
1110                                         &mcast_addr.in,
1111                                         interface_addr,
1112                                         &src_addr.in,
1113                                         membership);
1114 #else
1115   return UV_ENOSYS;
1116 #endif
1117 }
1118 
1119 
uv__setsockopt(uv_udp_t * handle,int option4,int option6,const void * val,socklen_t size)1120 static int uv__setsockopt(uv_udp_t* handle,
1121                          int option4,
1122                          int option6,
1123                          const void* val,
1124                          socklen_t size) {
1125   int r;
1126 
1127   if (handle->flags & UV_HANDLE_IPV6)
1128     r = setsockopt(handle->io_watcher.fd,
1129                    IPPROTO_IPV6,
1130                    option6,
1131                    val,
1132                    size);
1133   else
1134     r = setsockopt(handle->io_watcher.fd,
1135                    IPPROTO_IP,
1136                    option4,
1137                    val,
1138                    size);
1139   if (r)
1140     return UV__ERR(errno);
1141 
1142   return 0;
1143 }
1144 
uv__setsockopt_maybe_char(uv_udp_t * handle,int option4,int option6,int val)1145 static int uv__setsockopt_maybe_char(uv_udp_t* handle,
1146                                      int option4,
1147                                      int option6,
1148                                      int val) {
1149 #if defined(__sun) || defined(_AIX) || defined(__MVS__)
1150   char arg = val;
1151 #elif defined(__OpenBSD__)
1152   unsigned char arg = val;
1153 #else
1154   int arg = val;
1155 #endif
1156 
1157   if (val < 0 || val > 255)
1158     return UV_EINVAL;
1159 
1160   return uv__setsockopt(handle, option4, option6, &arg, sizeof(arg));
1161 }
1162 
1163 
uv_udp_set_broadcast(uv_udp_t * handle,int on)1164 int uv_udp_set_broadcast(uv_udp_t* handle, int on) {
1165   if (setsockopt(handle->io_watcher.fd,
1166                  SOL_SOCKET,
1167                  SO_BROADCAST,
1168                  &on,
1169                  sizeof(on))) {
1170     return UV__ERR(errno);
1171   }
1172 
1173   return 0;
1174 }
1175 
1176 
uv_udp_set_ttl(uv_udp_t * handle,int ttl)1177 int uv_udp_set_ttl(uv_udp_t* handle, int ttl) {
1178   if (ttl < 1 || ttl > 255)
1179     return UV_EINVAL;
1180 
1181 #if defined(__MVS__)
1182   if (!(handle->flags & UV_HANDLE_IPV6))
1183     return UV_ENOTSUP;  /* zOS does not support setting ttl for IPv4 */
1184 #endif
1185 
1186 /*
1187  * On Solaris and derivatives such as SmartOS, the length of socket options
1188  * is sizeof(int) for IP_TTL and IPV6_UNICAST_HOPS,
1189  * so hardcode the size of these options on this platform,
1190  * and use the general uv__setsockopt_maybe_char call on other platforms.
1191  */
1192 #if defined(__sun) || defined(_AIX) || defined(__OpenBSD__) || \
1193     defined(__MVS__) || defined(__QNX__)
1194 
1195   return uv__setsockopt(handle,
1196                         IP_TTL,
1197                         IPV6_UNICAST_HOPS,
1198                         &ttl,
1199                         sizeof(ttl));
1200 
1201 #else /* !(defined(__sun) || defined(_AIX) || defined (__OpenBSD__) ||
1202            defined(__MVS__) || defined(__QNX__)) */
1203 
1204   return uv__setsockopt_maybe_char(handle,
1205                                    IP_TTL,
1206                                    IPV6_UNICAST_HOPS,
1207                                    ttl);
1208 
1209 #endif /* defined(__sun) || defined(_AIX) || defined (__OpenBSD__) ||
1210           defined(__MVS__) || defined(__QNX__) */
1211 }
1212 
1213 
uv_udp_set_multicast_ttl(uv_udp_t * handle,int ttl)1214 int uv_udp_set_multicast_ttl(uv_udp_t* handle, int ttl) {
1215 /*
1216  * On Solaris and derivatives such as SmartOS, the length of socket options
1217  * is sizeof(int) for IPV6_MULTICAST_HOPS and sizeof(char) for
1218  * IP_MULTICAST_TTL, so hardcode the size of the option in the IPv6 case,
1219  * and use the general uv__setsockopt_maybe_char call otherwise.
1220  */
1221 #if defined(__sun) || defined(_AIX) || defined(__OpenBSD__) || \
1222     defined(__MVS__) || defined(__QNX__)
1223   if (handle->flags & UV_HANDLE_IPV6)
1224     return uv__setsockopt(handle,
1225                           IP_MULTICAST_TTL,
1226                           IPV6_MULTICAST_HOPS,
1227                           &ttl,
1228                           sizeof(ttl));
1229 #endif /* defined(__sun) || defined(_AIX) || defined(__OpenBSD__) || \
1230     defined(__MVS__) || defined(__QNX__) */
1231 
1232   return uv__setsockopt_maybe_char(handle,
1233                                    IP_MULTICAST_TTL,
1234                                    IPV6_MULTICAST_HOPS,
1235                                    ttl);
1236 }
1237 
1238 
uv_udp_set_multicast_loop(uv_udp_t * handle,int on)1239 int uv_udp_set_multicast_loop(uv_udp_t* handle, int on) {
1240 /*
1241  * On Solaris and derivatives such as SmartOS, the length of socket options
1242  * is sizeof(int) for IPV6_MULTICAST_LOOP and sizeof(char) for
1243  * IP_MULTICAST_LOOP, so hardcode the size of the option in the IPv6 case,
1244  * and use the general uv__setsockopt_maybe_char call otherwise.
1245  */
1246 #if defined(__sun) || defined(_AIX) || defined(__OpenBSD__) || \
1247     defined(__MVS__) || defined(__QNX__)
1248   if (handle->flags & UV_HANDLE_IPV6)
1249     return uv__setsockopt(handle,
1250                           IP_MULTICAST_LOOP,
1251                           IPV6_MULTICAST_LOOP,
1252                           &on,
1253                           sizeof(on));
1254 #endif /* defined(__sun) || defined(_AIX) ||defined(__OpenBSD__) ||
1255     defined(__MVS__) || defined(__QNX__) */
1256 
1257   return uv__setsockopt_maybe_char(handle,
1258                                    IP_MULTICAST_LOOP,
1259                                    IPV6_MULTICAST_LOOP,
1260                                    on);
1261 }
1262 
uv_udp_set_multicast_interface(uv_udp_t * handle,const char * interface_addr)1263 int uv_udp_set_multicast_interface(uv_udp_t* handle, const char* interface_addr) {
1264   struct sockaddr_storage addr_st;
1265   struct sockaddr_in* addr4;
1266   struct sockaddr_in6* addr6;
1267 
1268   addr4 = (struct sockaddr_in*) &addr_st;
1269   addr6 = (struct sockaddr_in6*) &addr_st;
1270 
1271   if (!interface_addr) {
1272     memset(&addr_st, 0, sizeof addr_st);
1273     if (handle->flags & UV_HANDLE_IPV6) {
1274       addr_st.ss_family = AF_INET6;
1275       addr6->sin6_scope_id = 0;
1276     } else {
1277       addr_st.ss_family = AF_INET;
1278       addr4->sin_addr.s_addr = htonl(INADDR_ANY);
1279     }
1280   } else if (uv_ip4_addr(interface_addr, 0, addr4) == 0) {
1281     /* nothing, address was parsed */
1282   } else if (uv_ip6_addr(interface_addr, 0, addr6) == 0) {
1283     /* nothing, address was parsed */
1284   } else {
1285     return UV_EINVAL;
1286   }
1287 
1288   if (addr_st.ss_family == AF_INET) {
1289     if (setsockopt(handle->io_watcher.fd,
1290                    IPPROTO_IP,
1291                    IP_MULTICAST_IF,
1292                    (void*) &addr4->sin_addr,
1293                    sizeof(addr4->sin_addr)) == -1) {
1294       return UV__ERR(errno);
1295     }
1296   } else if (addr_st.ss_family == AF_INET6) {
1297     if (setsockopt(handle->io_watcher.fd,
1298                    IPPROTO_IPV6,
1299                    IPV6_MULTICAST_IF,
1300                    &addr6->sin6_scope_id,
1301                    sizeof(addr6->sin6_scope_id)) == -1) {
1302       return UV__ERR(errno);
1303     }
1304   } else {
1305     assert(0 && "unexpected address family");
1306     abort();
1307   }
1308 
1309   return 0;
1310 }
1311 
uv_udp_getpeername(const uv_udp_t * handle,struct sockaddr * name,int * namelen)1312 int uv_udp_getpeername(const uv_udp_t* handle,
1313                        struct sockaddr* name,
1314                        int* namelen) {
1315 
1316   return uv__getsockpeername((const uv_handle_t*) handle,
1317                              getpeername,
1318                              name,
1319                              namelen);
1320 }
1321 
uv_udp_getsockname(const uv_udp_t * handle,struct sockaddr * name,int * namelen)1322 int uv_udp_getsockname(const uv_udp_t* handle,
1323                        struct sockaddr* name,
1324                        int* namelen) {
1325 
1326   return uv__getsockpeername((const uv_handle_t*) handle,
1327                              getsockname,
1328                              name,
1329                              namelen);
1330 }
1331 
1332 
uv__udp_recv_start(uv_udp_t * handle,uv_alloc_cb alloc_cb,uv_udp_recv_cb recv_cb)1333 int uv__udp_recv_start(uv_udp_t* handle,
1334                        uv_alloc_cb alloc_cb,
1335                        uv_udp_recv_cb recv_cb) {
1336   int err;
1337 
1338   if (alloc_cb == NULL || recv_cb == NULL)
1339     return UV_EINVAL;
1340 
1341   if (uv__io_active(&handle->io_watcher, POLLIN))
1342     return UV_EALREADY;  /* FIXME(bnoordhuis) Should be UV_EBUSY. */
1343 
1344   err = uv__udp_maybe_deferred_bind(handle, AF_INET, 0);
1345   if (err)
1346     return err;
1347 
1348   handle->alloc_cb = alloc_cb;
1349   handle->recv_cb = recv_cb;
1350 
1351   uv__io_start(handle->loop, &handle->io_watcher, POLLIN);
1352   uv__handle_start(handle);
1353 
1354   return 0;
1355 }
1356 
1357 
uv__udp_recv_stop(uv_udp_t * handle)1358 int uv__udp_recv_stop(uv_udp_t* handle) {
1359   uv__io_stop(handle->loop, &handle->io_watcher, POLLIN);
1360 
1361   if (!uv__io_active(&handle->io_watcher, POLLOUT))
1362     uv__handle_stop(handle);
1363 
1364   handle->alloc_cb = NULL;
1365   handle->recv_cb = NULL;
1366 
1367   return 0;
1368 }
1369