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