11cb0ef41Sopenharmony_ci/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. 21cb0ef41Sopenharmony_ci * 31cb0ef41Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a copy 41cb0ef41Sopenharmony_ci * of this software and associated documentation files (the "Software"), to 51cb0ef41Sopenharmony_ci * deal in the Software without restriction, including without limitation the 61cb0ef41Sopenharmony_ci * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 71cb0ef41Sopenharmony_ci * sell copies of the Software, and to permit persons to whom the Software is 81cb0ef41Sopenharmony_ci * furnished to do so, subject to the following conditions: 91cb0ef41Sopenharmony_ci * 101cb0ef41Sopenharmony_ci * The above copyright notice and this permission notice shall be included in 111cb0ef41Sopenharmony_ci * all copies or substantial portions of the Software. 121cb0ef41Sopenharmony_ci * 131cb0ef41Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 141cb0ef41Sopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 151cb0ef41Sopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 161cb0ef41Sopenharmony_ci * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 171cb0ef41Sopenharmony_ci * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 181cb0ef41Sopenharmony_ci * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 191cb0ef41Sopenharmony_ci * IN THE SOFTWARE. 201cb0ef41Sopenharmony_ci */ 211cb0ef41Sopenharmony_ci 221cb0ef41Sopenharmony_ci#include "uv.h" 231cb0ef41Sopenharmony_ci#include "internal.h" 241cb0ef41Sopenharmony_ci 251cb0ef41Sopenharmony_ci#include <stdio.h> 261cb0ef41Sopenharmony_ci#include <stdlib.h> 271cb0ef41Sopenharmony_ci#include <string.h> 281cb0ef41Sopenharmony_ci#include <assert.h> 291cb0ef41Sopenharmony_ci#include <errno.h> 301cb0ef41Sopenharmony_ci 311cb0ef41Sopenharmony_ci#include <sys/types.h> 321cb0ef41Sopenharmony_ci#include <sys/socket.h> 331cb0ef41Sopenharmony_ci#include <sys/uio.h> 341cb0ef41Sopenharmony_ci#include <sys/un.h> 351cb0ef41Sopenharmony_ci#include <unistd.h> 361cb0ef41Sopenharmony_ci#include <limits.h> /* IOV_MAX */ 371cb0ef41Sopenharmony_ci 381cb0ef41Sopenharmony_ci#if defined(__APPLE__) 391cb0ef41Sopenharmony_ci# include <sys/event.h> 401cb0ef41Sopenharmony_ci# include <sys/time.h> 411cb0ef41Sopenharmony_ci# include <sys/select.h> 421cb0ef41Sopenharmony_ci 431cb0ef41Sopenharmony_ci/* Forward declaration */ 441cb0ef41Sopenharmony_citypedef struct uv__stream_select_s uv__stream_select_t; 451cb0ef41Sopenharmony_ci 461cb0ef41Sopenharmony_cistruct uv__stream_select_s { 471cb0ef41Sopenharmony_ci uv_stream_t* stream; 481cb0ef41Sopenharmony_ci uv_thread_t thread; 491cb0ef41Sopenharmony_ci uv_sem_t close_sem; 501cb0ef41Sopenharmony_ci uv_sem_t async_sem; 511cb0ef41Sopenharmony_ci uv_async_t async; 521cb0ef41Sopenharmony_ci int events; 531cb0ef41Sopenharmony_ci int fake_fd; 541cb0ef41Sopenharmony_ci int int_fd; 551cb0ef41Sopenharmony_ci int fd; 561cb0ef41Sopenharmony_ci fd_set* sread; 571cb0ef41Sopenharmony_ci size_t sread_sz; 581cb0ef41Sopenharmony_ci fd_set* swrite; 591cb0ef41Sopenharmony_ci size_t swrite_sz; 601cb0ef41Sopenharmony_ci}; 611cb0ef41Sopenharmony_ci#endif /* defined(__APPLE__) */ 621cb0ef41Sopenharmony_ci 631cb0ef41Sopenharmony_cistatic void uv__stream_connect(uv_stream_t*); 641cb0ef41Sopenharmony_cistatic void uv__write(uv_stream_t* stream); 651cb0ef41Sopenharmony_cistatic void uv__read(uv_stream_t* stream); 661cb0ef41Sopenharmony_cistatic void uv__stream_io(uv_loop_t* loop, uv__io_t* w, unsigned int events); 671cb0ef41Sopenharmony_cistatic void uv__write_callbacks(uv_stream_t* stream); 681cb0ef41Sopenharmony_cistatic size_t uv__write_req_size(uv_write_t* req); 691cb0ef41Sopenharmony_cistatic void uv__drain(uv_stream_t* stream); 701cb0ef41Sopenharmony_ci 711cb0ef41Sopenharmony_ci 721cb0ef41Sopenharmony_civoid uv__stream_init(uv_loop_t* loop, 731cb0ef41Sopenharmony_ci uv_stream_t* stream, 741cb0ef41Sopenharmony_ci uv_handle_type type) { 751cb0ef41Sopenharmony_ci int err; 761cb0ef41Sopenharmony_ci 771cb0ef41Sopenharmony_ci uv__handle_init(loop, (uv_handle_t*)stream, type); 781cb0ef41Sopenharmony_ci stream->read_cb = NULL; 791cb0ef41Sopenharmony_ci stream->alloc_cb = NULL; 801cb0ef41Sopenharmony_ci stream->close_cb = NULL; 811cb0ef41Sopenharmony_ci stream->connection_cb = NULL; 821cb0ef41Sopenharmony_ci stream->connect_req = NULL; 831cb0ef41Sopenharmony_ci stream->shutdown_req = NULL; 841cb0ef41Sopenharmony_ci stream->accepted_fd = -1; 851cb0ef41Sopenharmony_ci stream->queued_fds = NULL; 861cb0ef41Sopenharmony_ci stream->delayed_error = 0; 871cb0ef41Sopenharmony_ci QUEUE_INIT(&stream->write_queue); 881cb0ef41Sopenharmony_ci QUEUE_INIT(&stream->write_completed_queue); 891cb0ef41Sopenharmony_ci stream->write_queue_size = 0; 901cb0ef41Sopenharmony_ci 911cb0ef41Sopenharmony_ci if (loop->emfile_fd == -1) { 921cb0ef41Sopenharmony_ci err = uv__open_cloexec("/dev/null", O_RDONLY); 931cb0ef41Sopenharmony_ci if (err < 0) 941cb0ef41Sopenharmony_ci /* In the rare case that "/dev/null" isn't mounted open "/" 951cb0ef41Sopenharmony_ci * instead. 961cb0ef41Sopenharmony_ci */ 971cb0ef41Sopenharmony_ci err = uv__open_cloexec("/", O_RDONLY); 981cb0ef41Sopenharmony_ci if (err >= 0) 991cb0ef41Sopenharmony_ci loop->emfile_fd = err; 1001cb0ef41Sopenharmony_ci } 1011cb0ef41Sopenharmony_ci 1021cb0ef41Sopenharmony_ci#if defined(__APPLE__) 1031cb0ef41Sopenharmony_ci stream->select = NULL; 1041cb0ef41Sopenharmony_ci#endif /* defined(__APPLE_) */ 1051cb0ef41Sopenharmony_ci 1061cb0ef41Sopenharmony_ci uv__io_init(&stream->io_watcher, uv__stream_io, -1); 1071cb0ef41Sopenharmony_ci} 1081cb0ef41Sopenharmony_ci 1091cb0ef41Sopenharmony_ci 1101cb0ef41Sopenharmony_cistatic void uv__stream_osx_interrupt_select(uv_stream_t* stream) { 1111cb0ef41Sopenharmony_ci#if defined(__APPLE__) 1121cb0ef41Sopenharmony_ci /* Notify select() thread about state change */ 1131cb0ef41Sopenharmony_ci uv__stream_select_t* s; 1141cb0ef41Sopenharmony_ci int r; 1151cb0ef41Sopenharmony_ci 1161cb0ef41Sopenharmony_ci s = stream->select; 1171cb0ef41Sopenharmony_ci if (s == NULL) 1181cb0ef41Sopenharmony_ci return; 1191cb0ef41Sopenharmony_ci 1201cb0ef41Sopenharmony_ci /* Interrupt select() loop 1211cb0ef41Sopenharmony_ci * NOTE: fake_fd and int_fd are socketpair(), thus writing to one will 1221cb0ef41Sopenharmony_ci * emit read event on other side 1231cb0ef41Sopenharmony_ci */ 1241cb0ef41Sopenharmony_ci do 1251cb0ef41Sopenharmony_ci r = write(s->fake_fd, "x", 1); 1261cb0ef41Sopenharmony_ci while (r == -1 && errno == EINTR); 1271cb0ef41Sopenharmony_ci 1281cb0ef41Sopenharmony_ci assert(r == 1); 1291cb0ef41Sopenharmony_ci#else /* !defined(__APPLE__) */ 1301cb0ef41Sopenharmony_ci /* No-op on any other platform */ 1311cb0ef41Sopenharmony_ci#endif /* !defined(__APPLE__) */ 1321cb0ef41Sopenharmony_ci} 1331cb0ef41Sopenharmony_ci 1341cb0ef41Sopenharmony_ci 1351cb0ef41Sopenharmony_ci#if defined(__APPLE__) 1361cb0ef41Sopenharmony_cistatic void uv__stream_osx_select(void* arg) { 1371cb0ef41Sopenharmony_ci uv_stream_t* stream; 1381cb0ef41Sopenharmony_ci uv__stream_select_t* s; 1391cb0ef41Sopenharmony_ci char buf[1024]; 1401cb0ef41Sopenharmony_ci int events; 1411cb0ef41Sopenharmony_ci int fd; 1421cb0ef41Sopenharmony_ci int r; 1431cb0ef41Sopenharmony_ci int max_fd; 1441cb0ef41Sopenharmony_ci 1451cb0ef41Sopenharmony_ci stream = arg; 1461cb0ef41Sopenharmony_ci s = stream->select; 1471cb0ef41Sopenharmony_ci fd = s->fd; 1481cb0ef41Sopenharmony_ci 1491cb0ef41Sopenharmony_ci if (fd > s->int_fd) 1501cb0ef41Sopenharmony_ci max_fd = fd; 1511cb0ef41Sopenharmony_ci else 1521cb0ef41Sopenharmony_ci max_fd = s->int_fd; 1531cb0ef41Sopenharmony_ci 1541cb0ef41Sopenharmony_ci for (;;) { 1551cb0ef41Sopenharmony_ci /* Terminate on semaphore */ 1561cb0ef41Sopenharmony_ci if (uv_sem_trywait(&s->close_sem) == 0) 1571cb0ef41Sopenharmony_ci break; 1581cb0ef41Sopenharmony_ci 1591cb0ef41Sopenharmony_ci /* Watch fd using select(2) */ 1601cb0ef41Sopenharmony_ci memset(s->sread, 0, s->sread_sz); 1611cb0ef41Sopenharmony_ci memset(s->swrite, 0, s->swrite_sz); 1621cb0ef41Sopenharmony_ci 1631cb0ef41Sopenharmony_ci if (uv__io_active(&stream->io_watcher, POLLIN)) 1641cb0ef41Sopenharmony_ci FD_SET(fd, s->sread); 1651cb0ef41Sopenharmony_ci if (uv__io_active(&stream->io_watcher, POLLOUT)) 1661cb0ef41Sopenharmony_ci FD_SET(fd, s->swrite); 1671cb0ef41Sopenharmony_ci FD_SET(s->int_fd, s->sread); 1681cb0ef41Sopenharmony_ci 1691cb0ef41Sopenharmony_ci /* Wait indefinitely for fd events */ 1701cb0ef41Sopenharmony_ci r = select(max_fd + 1, s->sread, s->swrite, NULL, NULL); 1711cb0ef41Sopenharmony_ci if (r == -1) { 1721cb0ef41Sopenharmony_ci if (errno == EINTR) 1731cb0ef41Sopenharmony_ci continue; 1741cb0ef41Sopenharmony_ci 1751cb0ef41Sopenharmony_ci /* XXX: Possible?! */ 1761cb0ef41Sopenharmony_ci abort(); 1771cb0ef41Sopenharmony_ci } 1781cb0ef41Sopenharmony_ci 1791cb0ef41Sopenharmony_ci /* Ignore timeouts */ 1801cb0ef41Sopenharmony_ci if (r == 0) 1811cb0ef41Sopenharmony_ci continue; 1821cb0ef41Sopenharmony_ci 1831cb0ef41Sopenharmony_ci /* Empty socketpair's buffer in case of interruption */ 1841cb0ef41Sopenharmony_ci if (FD_ISSET(s->int_fd, s->sread)) 1851cb0ef41Sopenharmony_ci for (;;) { 1861cb0ef41Sopenharmony_ci r = read(s->int_fd, buf, sizeof(buf)); 1871cb0ef41Sopenharmony_ci 1881cb0ef41Sopenharmony_ci if (r == sizeof(buf)) 1891cb0ef41Sopenharmony_ci continue; 1901cb0ef41Sopenharmony_ci 1911cb0ef41Sopenharmony_ci if (r != -1) 1921cb0ef41Sopenharmony_ci break; 1931cb0ef41Sopenharmony_ci 1941cb0ef41Sopenharmony_ci if (errno == EAGAIN || errno == EWOULDBLOCK) 1951cb0ef41Sopenharmony_ci break; 1961cb0ef41Sopenharmony_ci 1971cb0ef41Sopenharmony_ci if (errno == EINTR) 1981cb0ef41Sopenharmony_ci continue; 1991cb0ef41Sopenharmony_ci 2001cb0ef41Sopenharmony_ci abort(); 2011cb0ef41Sopenharmony_ci } 2021cb0ef41Sopenharmony_ci 2031cb0ef41Sopenharmony_ci /* Handle events */ 2041cb0ef41Sopenharmony_ci events = 0; 2051cb0ef41Sopenharmony_ci if (FD_ISSET(fd, s->sread)) 2061cb0ef41Sopenharmony_ci events |= POLLIN; 2071cb0ef41Sopenharmony_ci if (FD_ISSET(fd, s->swrite)) 2081cb0ef41Sopenharmony_ci events |= POLLOUT; 2091cb0ef41Sopenharmony_ci 2101cb0ef41Sopenharmony_ci assert(events != 0 || FD_ISSET(s->int_fd, s->sread)); 2111cb0ef41Sopenharmony_ci if (events != 0) { 2121cb0ef41Sopenharmony_ci ACCESS_ONCE(int, s->events) = events; 2131cb0ef41Sopenharmony_ci 2141cb0ef41Sopenharmony_ci uv_async_send(&s->async); 2151cb0ef41Sopenharmony_ci uv_sem_wait(&s->async_sem); 2161cb0ef41Sopenharmony_ci 2171cb0ef41Sopenharmony_ci /* Should be processed at this stage */ 2181cb0ef41Sopenharmony_ci assert((s->events == 0) || (stream->flags & UV_HANDLE_CLOSING)); 2191cb0ef41Sopenharmony_ci } 2201cb0ef41Sopenharmony_ci } 2211cb0ef41Sopenharmony_ci} 2221cb0ef41Sopenharmony_ci 2231cb0ef41Sopenharmony_ci 2241cb0ef41Sopenharmony_cistatic void uv__stream_osx_select_cb(uv_async_t* handle) { 2251cb0ef41Sopenharmony_ci uv__stream_select_t* s; 2261cb0ef41Sopenharmony_ci uv_stream_t* stream; 2271cb0ef41Sopenharmony_ci int events; 2281cb0ef41Sopenharmony_ci 2291cb0ef41Sopenharmony_ci s = container_of(handle, uv__stream_select_t, async); 2301cb0ef41Sopenharmony_ci stream = s->stream; 2311cb0ef41Sopenharmony_ci 2321cb0ef41Sopenharmony_ci /* Get and reset stream's events */ 2331cb0ef41Sopenharmony_ci events = s->events; 2341cb0ef41Sopenharmony_ci ACCESS_ONCE(int, s->events) = 0; 2351cb0ef41Sopenharmony_ci 2361cb0ef41Sopenharmony_ci assert(events != 0); 2371cb0ef41Sopenharmony_ci assert(events == (events & (POLLIN | POLLOUT))); 2381cb0ef41Sopenharmony_ci 2391cb0ef41Sopenharmony_ci /* Invoke callback on event-loop */ 2401cb0ef41Sopenharmony_ci if ((events & POLLIN) && uv__io_active(&stream->io_watcher, POLLIN)) 2411cb0ef41Sopenharmony_ci uv__stream_io(stream->loop, &stream->io_watcher, POLLIN); 2421cb0ef41Sopenharmony_ci 2431cb0ef41Sopenharmony_ci if ((events & POLLOUT) && uv__io_active(&stream->io_watcher, POLLOUT)) 2441cb0ef41Sopenharmony_ci uv__stream_io(stream->loop, &stream->io_watcher, POLLOUT); 2451cb0ef41Sopenharmony_ci 2461cb0ef41Sopenharmony_ci if (stream->flags & UV_HANDLE_CLOSING) 2471cb0ef41Sopenharmony_ci return; 2481cb0ef41Sopenharmony_ci 2491cb0ef41Sopenharmony_ci /* NOTE: It is important to do it here, otherwise `select()` might be called 2501cb0ef41Sopenharmony_ci * before the actual `uv__read()`, leading to the blocking syscall 2511cb0ef41Sopenharmony_ci */ 2521cb0ef41Sopenharmony_ci uv_sem_post(&s->async_sem); 2531cb0ef41Sopenharmony_ci} 2541cb0ef41Sopenharmony_ci 2551cb0ef41Sopenharmony_ci 2561cb0ef41Sopenharmony_cistatic void uv__stream_osx_cb_close(uv_handle_t* async) { 2571cb0ef41Sopenharmony_ci uv__stream_select_t* s; 2581cb0ef41Sopenharmony_ci 2591cb0ef41Sopenharmony_ci s = container_of(async, uv__stream_select_t, async); 2601cb0ef41Sopenharmony_ci uv__free(s); 2611cb0ef41Sopenharmony_ci} 2621cb0ef41Sopenharmony_ci 2631cb0ef41Sopenharmony_ci 2641cb0ef41Sopenharmony_ciint uv__stream_try_select(uv_stream_t* stream, int* fd) { 2651cb0ef41Sopenharmony_ci /* 2661cb0ef41Sopenharmony_ci * kqueue doesn't work with some files from /dev mount on osx. 2671cb0ef41Sopenharmony_ci * select(2) in separate thread for those fds 2681cb0ef41Sopenharmony_ci */ 2691cb0ef41Sopenharmony_ci 2701cb0ef41Sopenharmony_ci struct kevent filter[1]; 2711cb0ef41Sopenharmony_ci struct kevent events[1]; 2721cb0ef41Sopenharmony_ci struct timespec timeout; 2731cb0ef41Sopenharmony_ci uv__stream_select_t* s; 2741cb0ef41Sopenharmony_ci int fds[2]; 2751cb0ef41Sopenharmony_ci int err; 2761cb0ef41Sopenharmony_ci int ret; 2771cb0ef41Sopenharmony_ci int kq; 2781cb0ef41Sopenharmony_ci int old_fd; 2791cb0ef41Sopenharmony_ci int max_fd; 2801cb0ef41Sopenharmony_ci size_t sread_sz; 2811cb0ef41Sopenharmony_ci size_t swrite_sz; 2821cb0ef41Sopenharmony_ci 2831cb0ef41Sopenharmony_ci kq = kqueue(); 2841cb0ef41Sopenharmony_ci if (kq == -1) { 2851cb0ef41Sopenharmony_ci perror("(libuv) kqueue()"); 2861cb0ef41Sopenharmony_ci return UV__ERR(errno); 2871cb0ef41Sopenharmony_ci } 2881cb0ef41Sopenharmony_ci 2891cb0ef41Sopenharmony_ci EV_SET(&filter[0], *fd, EVFILT_READ, EV_ADD | EV_ENABLE, 0, 0, 0); 2901cb0ef41Sopenharmony_ci 2911cb0ef41Sopenharmony_ci /* Use small timeout, because we only want to capture EINVALs */ 2921cb0ef41Sopenharmony_ci timeout.tv_sec = 0; 2931cb0ef41Sopenharmony_ci timeout.tv_nsec = 1; 2941cb0ef41Sopenharmony_ci 2951cb0ef41Sopenharmony_ci do 2961cb0ef41Sopenharmony_ci ret = kevent(kq, filter, 1, events, 1, &timeout); 2971cb0ef41Sopenharmony_ci while (ret == -1 && errno == EINTR); 2981cb0ef41Sopenharmony_ci 2991cb0ef41Sopenharmony_ci uv__close(kq); 3001cb0ef41Sopenharmony_ci 3011cb0ef41Sopenharmony_ci if (ret == -1) 3021cb0ef41Sopenharmony_ci return UV__ERR(errno); 3031cb0ef41Sopenharmony_ci 3041cb0ef41Sopenharmony_ci if (ret == 0 || (events[0].flags & EV_ERROR) == 0 || events[0].data != EINVAL) 3051cb0ef41Sopenharmony_ci return 0; 3061cb0ef41Sopenharmony_ci 3071cb0ef41Sopenharmony_ci /* At this point we definitely know that this fd won't work with kqueue */ 3081cb0ef41Sopenharmony_ci 3091cb0ef41Sopenharmony_ci /* 3101cb0ef41Sopenharmony_ci * Create fds for io watcher and to interrupt the select() loop. 3111cb0ef41Sopenharmony_ci * NOTE: do it ahead of malloc below to allocate enough space for fd_sets 3121cb0ef41Sopenharmony_ci */ 3131cb0ef41Sopenharmony_ci if (socketpair(AF_UNIX, SOCK_STREAM, 0, fds)) 3141cb0ef41Sopenharmony_ci return UV__ERR(errno); 3151cb0ef41Sopenharmony_ci 3161cb0ef41Sopenharmony_ci max_fd = *fd; 3171cb0ef41Sopenharmony_ci if (fds[1] > max_fd) 3181cb0ef41Sopenharmony_ci max_fd = fds[1]; 3191cb0ef41Sopenharmony_ci 3201cb0ef41Sopenharmony_ci sread_sz = ROUND_UP(max_fd + 1, sizeof(uint32_t) * NBBY) / NBBY; 3211cb0ef41Sopenharmony_ci swrite_sz = sread_sz; 3221cb0ef41Sopenharmony_ci 3231cb0ef41Sopenharmony_ci s = uv__malloc(sizeof(*s) + sread_sz + swrite_sz); 3241cb0ef41Sopenharmony_ci if (s == NULL) { 3251cb0ef41Sopenharmony_ci err = UV_ENOMEM; 3261cb0ef41Sopenharmony_ci goto failed_malloc; 3271cb0ef41Sopenharmony_ci } 3281cb0ef41Sopenharmony_ci 3291cb0ef41Sopenharmony_ci s->events = 0; 3301cb0ef41Sopenharmony_ci s->fd = *fd; 3311cb0ef41Sopenharmony_ci s->sread = (fd_set*) ((char*) s + sizeof(*s)); 3321cb0ef41Sopenharmony_ci s->sread_sz = sread_sz; 3331cb0ef41Sopenharmony_ci s->swrite = (fd_set*) ((char*) s->sread + sread_sz); 3341cb0ef41Sopenharmony_ci s->swrite_sz = swrite_sz; 3351cb0ef41Sopenharmony_ci 3361cb0ef41Sopenharmony_ci err = uv_async_init(stream->loop, &s->async, uv__stream_osx_select_cb); 3371cb0ef41Sopenharmony_ci if (err) 3381cb0ef41Sopenharmony_ci goto failed_async_init; 3391cb0ef41Sopenharmony_ci 3401cb0ef41Sopenharmony_ci s->async.flags |= UV_HANDLE_INTERNAL; 3411cb0ef41Sopenharmony_ci uv__handle_unref(&s->async); 3421cb0ef41Sopenharmony_ci 3431cb0ef41Sopenharmony_ci err = uv_sem_init(&s->close_sem, 0); 3441cb0ef41Sopenharmony_ci if (err != 0) 3451cb0ef41Sopenharmony_ci goto failed_close_sem_init; 3461cb0ef41Sopenharmony_ci 3471cb0ef41Sopenharmony_ci err = uv_sem_init(&s->async_sem, 0); 3481cb0ef41Sopenharmony_ci if (err != 0) 3491cb0ef41Sopenharmony_ci goto failed_async_sem_init; 3501cb0ef41Sopenharmony_ci 3511cb0ef41Sopenharmony_ci s->fake_fd = fds[0]; 3521cb0ef41Sopenharmony_ci s->int_fd = fds[1]; 3531cb0ef41Sopenharmony_ci 3541cb0ef41Sopenharmony_ci old_fd = *fd; 3551cb0ef41Sopenharmony_ci s->stream = stream; 3561cb0ef41Sopenharmony_ci stream->select = s; 3571cb0ef41Sopenharmony_ci *fd = s->fake_fd; 3581cb0ef41Sopenharmony_ci 3591cb0ef41Sopenharmony_ci err = uv_thread_create(&s->thread, uv__stream_osx_select, stream); 3601cb0ef41Sopenharmony_ci if (err != 0) 3611cb0ef41Sopenharmony_ci goto failed_thread_create; 3621cb0ef41Sopenharmony_ci 3631cb0ef41Sopenharmony_ci return 0; 3641cb0ef41Sopenharmony_ci 3651cb0ef41Sopenharmony_cifailed_thread_create: 3661cb0ef41Sopenharmony_ci s->stream = NULL; 3671cb0ef41Sopenharmony_ci stream->select = NULL; 3681cb0ef41Sopenharmony_ci *fd = old_fd; 3691cb0ef41Sopenharmony_ci 3701cb0ef41Sopenharmony_ci uv_sem_destroy(&s->async_sem); 3711cb0ef41Sopenharmony_ci 3721cb0ef41Sopenharmony_cifailed_async_sem_init: 3731cb0ef41Sopenharmony_ci uv_sem_destroy(&s->close_sem); 3741cb0ef41Sopenharmony_ci 3751cb0ef41Sopenharmony_cifailed_close_sem_init: 3761cb0ef41Sopenharmony_ci uv__close(fds[0]); 3771cb0ef41Sopenharmony_ci uv__close(fds[1]); 3781cb0ef41Sopenharmony_ci uv_close((uv_handle_t*) &s->async, uv__stream_osx_cb_close); 3791cb0ef41Sopenharmony_ci return err; 3801cb0ef41Sopenharmony_ci 3811cb0ef41Sopenharmony_cifailed_async_init: 3821cb0ef41Sopenharmony_ci uv__free(s); 3831cb0ef41Sopenharmony_ci 3841cb0ef41Sopenharmony_cifailed_malloc: 3851cb0ef41Sopenharmony_ci uv__close(fds[0]); 3861cb0ef41Sopenharmony_ci uv__close(fds[1]); 3871cb0ef41Sopenharmony_ci 3881cb0ef41Sopenharmony_ci return err; 3891cb0ef41Sopenharmony_ci} 3901cb0ef41Sopenharmony_ci#endif /* defined(__APPLE__) */ 3911cb0ef41Sopenharmony_ci 3921cb0ef41Sopenharmony_ci 3931cb0ef41Sopenharmony_ciint uv__stream_open(uv_stream_t* stream, int fd, int flags) { 3941cb0ef41Sopenharmony_ci#if defined(__APPLE__) 3951cb0ef41Sopenharmony_ci int enable; 3961cb0ef41Sopenharmony_ci#endif 3971cb0ef41Sopenharmony_ci 3981cb0ef41Sopenharmony_ci if (!(stream->io_watcher.fd == -1 || stream->io_watcher.fd == fd)) 3991cb0ef41Sopenharmony_ci return UV_EBUSY; 4001cb0ef41Sopenharmony_ci 4011cb0ef41Sopenharmony_ci assert(fd >= 0); 4021cb0ef41Sopenharmony_ci stream->flags |= flags; 4031cb0ef41Sopenharmony_ci 4041cb0ef41Sopenharmony_ci if (stream->type == UV_TCP) { 4051cb0ef41Sopenharmony_ci if ((stream->flags & UV_HANDLE_TCP_NODELAY) && uv__tcp_nodelay(fd, 1)) 4061cb0ef41Sopenharmony_ci return UV__ERR(errno); 4071cb0ef41Sopenharmony_ci 4081cb0ef41Sopenharmony_ci /* TODO Use delay the user passed in. */ 4091cb0ef41Sopenharmony_ci if ((stream->flags & UV_HANDLE_TCP_KEEPALIVE) && 4101cb0ef41Sopenharmony_ci uv__tcp_keepalive(fd, 1, 60)) { 4111cb0ef41Sopenharmony_ci return UV__ERR(errno); 4121cb0ef41Sopenharmony_ci } 4131cb0ef41Sopenharmony_ci } 4141cb0ef41Sopenharmony_ci 4151cb0ef41Sopenharmony_ci#if defined(__APPLE__) 4161cb0ef41Sopenharmony_ci enable = 1; 4171cb0ef41Sopenharmony_ci if (setsockopt(fd, SOL_SOCKET, SO_OOBINLINE, &enable, sizeof(enable)) && 4181cb0ef41Sopenharmony_ci errno != ENOTSOCK && 4191cb0ef41Sopenharmony_ci errno != EINVAL) { 4201cb0ef41Sopenharmony_ci return UV__ERR(errno); 4211cb0ef41Sopenharmony_ci } 4221cb0ef41Sopenharmony_ci#endif 4231cb0ef41Sopenharmony_ci 4241cb0ef41Sopenharmony_ci stream->io_watcher.fd = fd; 4251cb0ef41Sopenharmony_ci 4261cb0ef41Sopenharmony_ci return 0; 4271cb0ef41Sopenharmony_ci} 4281cb0ef41Sopenharmony_ci 4291cb0ef41Sopenharmony_ci 4301cb0ef41Sopenharmony_civoid uv__stream_flush_write_queue(uv_stream_t* stream, int error) { 4311cb0ef41Sopenharmony_ci uv_write_t* req; 4321cb0ef41Sopenharmony_ci QUEUE* q; 4331cb0ef41Sopenharmony_ci while (!QUEUE_EMPTY(&stream->write_queue)) { 4341cb0ef41Sopenharmony_ci q = QUEUE_HEAD(&stream->write_queue); 4351cb0ef41Sopenharmony_ci QUEUE_REMOVE(q); 4361cb0ef41Sopenharmony_ci 4371cb0ef41Sopenharmony_ci req = QUEUE_DATA(q, uv_write_t, queue); 4381cb0ef41Sopenharmony_ci req->error = error; 4391cb0ef41Sopenharmony_ci 4401cb0ef41Sopenharmony_ci QUEUE_INSERT_TAIL(&stream->write_completed_queue, &req->queue); 4411cb0ef41Sopenharmony_ci } 4421cb0ef41Sopenharmony_ci} 4431cb0ef41Sopenharmony_ci 4441cb0ef41Sopenharmony_ci 4451cb0ef41Sopenharmony_civoid uv__stream_destroy(uv_stream_t* stream) { 4461cb0ef41Sopenharmony_ci assert(!uv__io_active(&stream->io_watcher, POLLIN | POLLOUT)); 4471cb0ef41Sopenharmony_ci assert(stream->flags & UV_HANDLE_CLOSED); 4481cb0ef41Sopenharmony_ci 4491cb0ef41Sopenharmony_ci if (stream->connect_req) { 4501cb0ef41Sopenharmony_ci uv__req_unregister(stream->loop, stream->connect_req); 4511cb0ef41Sopenharmony_ci stream->connect_req->cb(stream->connect_req, UV_ECANCELED); 4521cb0ef41Sopenharmony_ci stream->connect_req = NULL; 4531cb0ef41Sopenharmony_ci } 4541cb0ef41Sopenharmony_ci 4551cb0ef41Sopenharmony_ci uv__stream_flush_write_queue(stream, UV_ECANCELED); 4561cb0ef41Sopenharmony_ci uv__write_callbacks(stream); 4571cb0ef41Sopenharmony_ci uv__drain(stream); 4581cb0ef41Sopenharmony_ci 4591cb0ef41Sopenharmony_ci assert(stream->write_queue_size == 0); 4601cb0ef41Sopenharmony_ci} 4611cb0ef41Sopenharmony_ci 4621cb0ef41Sopenharmony_ci 4631cb0ef41Sopenharmony_ci/* Implements a best effort approach to mitigating accept() EMFILE errors. 4641cb0ef41Sopenharmony_ci * We have a spare file descriptor stashed away that we close to get below 4651cb0ef41Sopenharmony_ci * the EMFILE limit. Next, we accept all pending connections and close them 4661cb0ef41Sopenharmony_ci * immediately to signal the clients that we're overloaded - and we are, but 4671cb0ef41Sopenharmony_ci * we still keep on trucking. 4681cb0ef41Sopenharmony_ci * 4691cb0ef41Sopenharmony_ci * There is one caveat: it's not reliable in a multi-threaded environment. 4701cb0ef41Sopenharmony_ci * The file descriptor limit is per process. Our party trick fails if another 4711cb0ef41Sopenharmony_ci * thread opens a file or creates a socket in the time window between us 4721cb0ef41Sopenharmony_ci * calling close() and accept(). 4731cb0ef41Sopenharmony_ci */ 4741cb0ef41Sopenharmony_cistatic int uv__emfile_trick(uv_loop_t* loop, int accept_fd) { 4751cb0ef41Sopenharmony_ci int err; 4761cb0ef41Sopenharmony_ci int emfile_fd; 4771cb0ef41Sopenharmony_ci 4781cb0ef41Sopenharmony_ci if (loop->emfile_fd == -1) 4791cb0ef41Sopenharmony_ci return UV_EMFILE; 4801cb0ef41Sopenharmony_ci 4811cb0ef41Sopenharmony_ci uv__close(loop->emfile_fd); 4821cb0ef41Sopenharmony_ci loop->emfile_fd = -1; 4831cb0ef41Sopenharmony_ci 4841cb0ef41Sopenharmony_ci do { 4851cb0ef41Sopenharmony_ci err = uv__accept(accept_fd); 4861cb0ef41Sopenharmony_ci if (err >= 0) 4871cb0ef41Sopenharmony_ci uv__close(err); 4881cb0ef41Sopenharmony_ci } while (err >= 0 || err == UV_EINTR); 4891cb0ef41Sopenharmony_ci 4901cb0ef41Sopenharmony_ci emfile_fd = uv__open_cloexec("/", O_RDONLY); 4911cb0ef41Sopenharmony_ci if (emfile_fd >= 0) 4921cb0ef41Sopenharmony_ci loop->emfile_fd = emfile_fd; 4931cb0ef41Sopenharmony_ci 4941cb0ef41Sopenharmony_ci return err; 4951cb0ef41Sopenharmony_ci} 4961cb0ef41Sopenharmony_ci 4971cb0ef41Sopenharmony_ci 4981cb0ef41Sopenharmony_ci#if defined(UV_HAVE_KQUEUE) 4991cb0ef41Sopenharmony_ci# define UV_DEC_BACKLOG(w) w->rcount--; 5001cb0ef41Sopenharmony_ci#else 5011cb0ef41Sopenharmony_ci# define UV_DEC_BACKLOG(w) /* no-op */ 5021cb0ef41Sopenharmony_ci#endif /* defined(UV_HAVE_KQUEUE) */ 5031cb0ef41Sopenharmony_ci 5041cb0ef41Sopenharmony_ci 5051cb0ef41Sopenharmony_civoid uv__server_io(uv_loop_t* loop, uv__io_t* w, unsigned int events) { 5061cb0ef41Sopenharmony_ci uv_stream_t* stream; 5071cb0ef41Sopenharmony_ci int err; 5081cb0ef41Sopenharmony_ci 5091cb0ef41Sopenharmony_ci stream = container_of(w, uv_stream_t, io_watcher); 5101cb0ef41Sopenharmony_ci assert(events & POLLIN); 5111cb0ef41Sopenharmony_ci assert(stream->accepted_fd == -1); 5121cb0ef41Sopenharmony_ci assert(!(stream->flags & UV_HANDLE_CLOSING)); 5131cb0ef41Sopenharmony_ci 5141cb0ef41Sopenharmony_ci uv__io_start(stream->loop, &stream->io_watcher, POLLIN); 5151cb0ef41Sopenharmony_ci 5161cb0ef41Sopenharmony_ci /* connection_cb can close the server socket while we're 5171cb0ef41Sopenharmony_ci * in the loop so check it on each iteration. 5181cb0ef41Sopenharmony_ci */ 5191cb0ef41Sopenharmony_ci while (uv__stream_fd(stream) != -1) { 5201cb0ef41Sopenharmony_ci assert(stream->accepted_fd == -1); 5211cb0ef41Sopenharmony_ci 5221cb0ef41Sopenharmony_ci#if defined(UV_HAVE_KQUEUE) 5231cb0ef41Sopenharmony_ci if (w->rcount <= 0) 5241cb0ef41Sopenharmony_ci return; 5251cb0ef41Sopenharmony_ci#endif /* defined(UV_HAVE_KQUEUE) */ 5261cb0ef41Sopenharmony_ci 5271cb0ef41Sopenharmony_ci err = uv__accept(uv__stream_fd(stream)); 5281cb0ef41Sopenharmony_ci if (err < 0) { 5291cb0ef41Sopenharmony_ci if (err == UV_EAGAIN || err == UV__ERR(EWOULDBLOCK)) 5301cb0ef41Sopenharmony_ci return; /* Not an error. */ 5311cb0ef41Sopenharmony_ci 5321cb0ef41Sopenharmony_ci if (err == UV_ECONNABORTED) 5331cb0ef41Sopenharmony_ci continue; /* Ignore. Nothing we can do about that. */ 5341cb0ef41Sopenharmony_ci 5351cb0ef41Sopenharmony_ci if (err == UV_EMFILE || err == UV_ENFILE) { 5361cb0ef41Sopenharmony_ci err = uv__emfile_trick(loop, uv__stream_fd(stream)); 5371cb0ef41Sopenharmony_ci if (err == UV_EAGAIN || err == UV__ERR(EWOULDBLOCK)) 5381cb0ef41Sopenharmony_ci break; 5391cb0ef41Sopenharmony_ci } 5401cb0ef41Sopenharmony_ci 5411cb0ef41Sopenharmony_ci stream->connection_cb(stream, err); 5421cb0ef41Sopenharmony_ci continue; 5431cb0ef41Sopenharmony_ci } 5441cb0ef41Sopenharmony_ci 5451cb0ef41Sopenharmony_ci UV_DEC_BACKLOG(w) 5461cb0ef41Sopenharmony_ci stream->accepted_fd = err; 5471cb0ef41Sopenharmony_ci stream->connection_cb(stream, 0); 5481cb0ef41Sopenharmony_ci 5491cb0ef41Sopenharmony_ci if (stream->accepted_fd != -1) { 5501cb0ef41Sopenharmony_ci /* The user hasn't yet accepted called uv_accept() */ 5511cb0ef41Sopenharmony_ci uv__io_stop(loop, &stream->io_watcher, POLLIN); 5521cb0ef41Sopenharmony_ci return; 5531cb0ef41Sopenharmony_ci } 5541cb0ef41Sopenharmony_ci 5551cb0ef41Sopenharmony_ci if (stream->type == UV_TCP && 5561cb0ef41Sopenharmony_ci (stream->flags & UV_HANDLE_TCP_SINGLE_ACCEPT)) { 5571cb0ef41Sopenharmony_ci /* Give other processes a chance to accept connections. */ 5581cb0ef41Sopenharmony_ci struct timespec timeout = { 0, 1 }; 5591cb0ef41Sopenharmony_ci nanosleep(&timeout, NULL); 5601cb0ef41Sopenharmony_ci } 5611cb0ef41Sopenharmony_ci } 5621cb0ef41Sopenharmony_ci} 5631cb0ef41Sopenharmony_ci 5641cb0ef41Sopenharmony_ci 5651cb0ef41Sopenharmony_ci#undef UV_DEC_BACKLOG 5661cb0ef41Sopenharmony_ci 5671cb0ef41Sopenharmony_ci 5681cb0ef41Sopenharmony_ciint uv_accept(uv_stream_t* server, uv_stream_t* client) { 5691cb0ef41Sopenharmony_ci int err; 5701cb0ef41Sopenharmony_ci 5711cb0ef41Sopenharmony_ci assert(server->loop == client->loop); 5721cb0ef41Sopenharmony_ci 5731cb0ef41Sopenharmony_ci if (server->accepted_fd == -1) 5741cb0ef41Sopenharmony_ci return UV_EAGAIN; 5751cb0ef41Sopenharmony_ci 5761cb0ef41Sopenharmony_ci switch (client->type) { 5771cb0ef41Sopenharmony_ci case UV_NAMED_PIPE: 5781cb0ef41Sopenharmony_ci case UV_TCP: 5791cb0ef41Sopenharmony_ci err = uv__stream_open(client, 5801cb0ef41Sopenharmony_ci server->accepted_fd, 5811cb0ef41Sopenharmony_ci UV_HANDLE_READABLE | UV_HANDLE_WRITABLE); 5821cb0ef41Sopenharmony_ci if (err) { 5831cb0ef41Sopenharmony_ci /* TODO handle error */ 5841cb0ef41Sopenharmony_ci uv__close(server->accepted_fd); 5851cb0ef41Sopenharmony_ci goto done; 5861cb0ef41Sopenharmony_ci } 5871cb0ef41Sopenharmony_ci break; 5881cb0ef41Sopenharmony_ci 5891cb0ef41Sopenharmony_ci case UV_UDP: 5901cb0ef41Sopenharmony_ci err = uv_udp_open((uv_udp_t*) client, server->accepted_fd); 5911cb0ef41Sopenharmony_ci if (err) { 5921cb0ef41Sopenharmony_ci uv__close(server->accepted_fd); 5931cb0ef41Sopenharmony_ci goto done; 5941cb0ef41Sopenharmony_ci } 5951cb0ef41Sopenharmony_ci break; 5961cb0ef41Sopenharmony_ci 5971cb0ef41Sopenharmony_ci default: 5981cb0ef41Sopenharmony_ci return UV_EINVAL; 5991cb0ef41Sopenharmony_ci } 6001cb0ef41Sopenharmony_ci 6011cb0ef41Sopenharmony_ci client->flags |= UV_HANDLE_BOUND; 6021cb0ef41Sopenharmony_ci 6031cb0ef41Sopenharmony_cidone: 6041cb0ef41Sopenharmony_ci /* Process queued fds */ 6051cb0ef41Sopenharmony_ci if (server->queued_fds != NULL) { 6061cb0ef41Sopenharmony_ci uv__stream_queued_fds_t* queued_fds; 6071cb0ef41Sopenharmony_ci 6081cb0ef41Sopenharmony_ci queued_fds = server->queued_fds; 6091cb0ef41Sopenharmony_ci 6101cb0ef41Sopenharmony_ci /* Read first */ 6111cb0ef41Sopenharmony_ci server->accepted_fd = queued_fds->fds[0]; 6121cb0ef41Sopenharmony_ci 6131cb0ef41Sopenharmony_ci /* All read, free */ 6141cb0ef41Sopenharmony_ci assert(queued_fds->offset > 0); 6151cb0ef41Sopenharmony_ci if (--queued_fds->offset == 0) { 6161cb0ef41Sopenharmony_ci uv__free(queued_fds); 6171cb0ef41Sopenharmony_ci server->queued_fds = NULL; 6181cb0ef41Sopenharmony_ci } else { 6191cb0ef41Sopenharmony_ci /* Shift rest */ 6201cb0ef41Sopenharmony_ci memmove(queued_fds->fds, 6211cb0ef41Sopenharmony_ci queued_fds->fds + 1, 6221cb0ef41Sopenharmony_ci queued_fds->offset * sizeof(*queued_fds->fds)); 6231cb0ef41Sopenharmony_ci } 6241cb0ef41Sopenharmony_ci } else { 6251cb0ef41Sopenharmony_ci server->accepted_fd = -1; 6261cb0ef41Sopenharmony_ci if (err == 0) 6271cb0ef41Sopenharmony_ci uv__io_start(server->loop, &server->io_watcher, POLLIN); 6281cb0ef41Sopenharmony_ci } 6291cb0ef41Sopenharmony_ci return err; 6301cb0ef41Sopenharmony_ci} 6311cb0ef41Sopenharmony_ci 6321cb0ef41Sopenharmony_ci 6331cb0ef41Sopenharmony_ciint uv_listen(uv_stream_t* stream, int backlog, uv_connection_cb cb) { 6341cb0ef41Sopenharmony_ci int err; 6351cb0ef41Sopenharmony_ci if (uv__is_closing(stream)) { 6361cb0ef41Sopenharmony_ci return UV_EINVAL; 6371cb0ef41Sopenharmony_ci } 6381cb0ef41Sopenharmony_ci switch (stream->type) { 6391cb0ef41Sopenharmony_ci case UV_TCP: 6401cb0ef41Sopenharmony_ci err = uv__tcp_listen((uv_tcp_t*)stream, backlog, cb); 6411cb0ef41Sopenharmony_ci break; 6421cb0ef41Sopenharmony_ci 6431cb0ef41Sopenharmony_ci case UV_NAMED_PIPE: 6441cb0ef41Sopenharmony_ci err = uv__pipe_listen((uv_pipe_t*)stream, backlog, cb); 6451cb0ef41Sopenharmony_ci break; 6461cb0ef41Sopenharmony_ci 6471cb0ef41Sopenharmony_ci default: 6481cb0ef41Sopenharmony_ci err = UV_EINVAL; 6491cb0ef41Sopenharmony_ci } 6501cb0ef41Sopenharmony_ci 6511cb0ef41Sopenharmony_ci if (err == 0) 6521cb0ef41Sopenharmony_ci uv__handle_start(stream); 6531cb0ef41Sopenharmony_ci 6541cb0ef41Sopenharmony_ci return err; 6551cb0ef41Sopenharmony_ci} 6561cb0ef41Sopenharmony_ci 6571cb0ef41Sopenharmony_ci 6581cb0ef41Sopenharmony_cistatic void uv__drain(uv_stream_t* stream) { 6591cb0ef41Sopenharmony_ci uv_shutdown_t* req; 6601cb0ef41Sopenharmony_ci int err; 6611cb0ef41Sopenharmony_ci 6621cb0ef41Sopenharmony_ci assert(QUEUE_EMPTY(&stream->write_queue)); 6631cb0ef41Sopenharmony_ci if (!(stream->flags & UV_HANDLE_CLOSING)) { 6641cb0ef41Sopenharmony_ci uv__io_stop(stream->loop, &stream->io_watcher, POLLOUT); 6651cb0ef41Sopenharmony_ci uv__stream_osx_interrupt_select(stream); 6661cb0ef41Sopenharmony_ci } 6671cb0ef41Sopenharmony_ci 6681cb0ef41Sopenharmony_ci if (!(stream->flags & UV_HANDLE_SHUTTING)) 6691cb0ef41Sopenharmony_ci return; 6701cb0ef41Sopenharmony_ci 6711cb0ef41Sopenharmony_ci req = stream->shutdown_req; 6721cb0ef41Sopenharmony_ci assert(req); 6731cb0ef41Sopenharmony_ci 6741cb0ef41Sopenharmony_ci if ((stream->flags & UV_HANDLE_CLOSING) || 6751cb0ef41Sopenharmony_ci !(stream->flags & UV_HANDLE_SHUT)) { 6761cb0ef41Sopenharmony_ci stream->shutdown_req = NULL; 6771cb0ef41Sopenharmony_ci stream->flags &= ~UV_HANDLE_SHUTTING; 6781cb0ef41Sopenharmony_ci uv__req_unregister(stream->loop, req); 6791cb0ef41Sopenharmony_ci 6801cb0ef41Sopenharmony_ci err = 0; 6811cb0ef41Sopenharmony_ci if (stream->flags & UV_HANDLE_CLOSING) 6821cb0ef41Sopenharmony_ci /* The user destroyed the stream before we got to do the shutdown. */ 6831cb0ef41Sopenharmony_ci err = UV_ECANCELED; 6841cb0ef41Sopenharmony_ci else if (shutdown(uv__stream_fd(stream), SHUT_WR)) 6851cb0ef41Sopenharmony_ci err = UV__ERR(errno); 6861cb0ef41Sopenharmony_ci else /* Success. */ 6871cb0ef41Sopenharmony_ci stream->flags |= UV_HANDLE_SHUT; 6881cb0ef41Sopenharmony_ci 6891cb0ef41Sopenharmony_ci if (req->cb != NULL) 6901cb0ef41Sopenharmony_ci req->cb(req, err); 6911cb0ef41Sopenharmony_ci } 6921cb0ef41Sopenharmony_ci} 6931cb0ef41Sopenharmony_ci 6941cb0ef41Sopenharmony_ci 6951cb0ef41Sopenharmony_cistatic ssize_t uv__writev(int fd, struct iovec* vec, size_t n) { 6961cb0ef41Sopenharmony_ci if (n == 1) 6971cb0ef41Sopenharmony_ci return write(fd, vec->iov_base, vec->iov_len); 6981cb0ef41Sopenharmony_ci else 6991cb0ef41Sopenharmony_ci return writev(fd, vec, n); 7001cb0ef41Sopenharmony_ci} 7011cb0ef41Sopenharmony_ci 7021cb0ef41Sopenharmony_ci 7031cb0ef41Sopenharmony_cistatic size_t uv__write_req_size(uv_write_t* req) { 7041cb0ef41Sopenharmony_ci size_t size; 7051cb0ef41Sopenharmony_ci 7061cb0ef41Sopenharmony_ci assert(req->bufs != NULL); 7071cb0ef41Sopenharmony_ci size = uv__count_bufs(req->bufs + req->write_index, 7081cb0ef41Sopenharmony_ci req->nbufs - req->write_index); 7091cb0ef41Sopenharmony_ci assert(req->handle->write_queue_size >= size); 7101cb0ef41Sopenharmony_ci 7111cb0ef41Sopenharmony_ci return size; 7121cb0ef41Sopenharmony_ci} 7131cb0ef41Sopenharmony_ci 7141cb0ef41Sopenharmony_ci 7151cb0ef41Sopenharmony_ci/* Returns 1 if all write request data has been written, or 0 if there is still 7161cb0ef41Sopenharmony_ci * more data to write. 7171cb0ef41Sopenharmony_ci * 7181cb0ef41Sopenharmony_ci * Note: the return value only says something about the *current* request. 7191cb0ef41Sopenharmony_ci * There may still be other write requests sitting in the queue. 7201cb0ef41Sopenharmony_ci */ 7211cb0ef41Sopenharmony_cistatic int uv__write_req_update(uv_stream_t* stream, 7221cb0ef41Sopenharmony_ci uv_write_t* req, 7231cb0ef41Sopenharmony_ci size_t n) { 7241cb0ef41Sopenharmony_ci uv_buf_t* buf; 7251cb0ef41Sopenharmony_ci size_t len; 7261cb0ef41Sopenharmony_ci 7271cb0ef41Sopenharmony_ci assert(n <= stream->write_queue_size); 7281cb0ef41Sopenharmony_ci stream->write_queue_size -= n; 7291cb0ef41Sopenharmony_ci 7301cb0ef41Sopenharmony_ci buf = req->bufs + req->write_index; 7311cb0ef41Sopenharmony_ci 7321cb0ef41Sopenharmony_ci do { 7331cb0ef41Sopenharmony_ci len = n < buf->len ? n : buf->len; 7341cb0ef41Sopenharmony_ci buf->base += len; 7351cb0ef41Sopenharmony_ci buf->len -= len; 7361cb0ef41Sopenharmony_ci buf += (buf->len == 0); /* Advance to next buffer if this one is empty. */ 7371cb0ef41Sopenharmony_ci n -= len; 7381cb0ef41Sopenharmony_ci } while (n > 0); 7391cb0ef41Sopenharmony_ci 7401cb0ef41Sopenharmony_ci req->write_index = buf - req->bufs; 7411cb0ef41Sopenharmony_ci 7421cb0ef41Sopenharmony_ci return req->write_index == req->nbufs; 7431cb0ef41Sopenharmony_ci} 7441cb0ef41Sopenharmony_ci 7451cb0ef41Sopenharmony_ci 7461cb0ef41Sopenharmony_cistatic void uv__write_req_finish(uv_write_t* req) { 7471cb0ef41Sopenharmony_ci uv_stream_t* stream = req->handle; 7481cb0ef41Sopenharmony_ci 7491cb0ef41Sopenharmony_ci /* Pop the req off tcp->write_queue. */ 7501cb0ef41Sopenharmony_ci QUEUE_REMOVE(&req->queue); 7511cb0ef41Sopenharmony_ci 7521cb0ef41Sopenharmony_ci /* Only free when there was no error. On error, we touch up write_queue_size 7531cb0ef41Sopenharmony_ci * right before making the callback. The reason we don't do that right away 7541cb0ef41Sopenharmony_ci * is that a write_queue_size > 0 is our only way to signal to the user that 7551cb0ef41Sopenharmony_ci * they should stop writing - which they should if we got an error. Something 7561cb0ef41Sopenharmony_ci * to revisit in future revisions of the libuv API. 7571cb0ef41Sopenharmony_ci */ 7581cb0ef41Sopenharmony_ci if (req->error == 0) { 7591cb0ef41Sopenharmony_ci if (req->bufs != req->bufsml) 7601cb0ef41Sopenharmony_ci uv__free(req->bufs); 7611cb0ef41Sopenharmony_ci req->bufs = NULL; 7621cb0ef41Sopenharmony_ci } 7631cb0ef41Sopenharmony_ci 7641cb0ef41Sopenharmony_ci /* Add it to the write_completed_queue where it will have its 7651cb0ef41Sopenharmony_ci * callback called in the near future. 7661cb0ef41Sopenharmony_ci */ 7671cb0ef41Sopenharmony_ci QUEUE_INSERT_TAIL(&stream->write_completed_queue, &req->queue); 7681cb0ef41Sopenharmony_ci uv__io_feed(stream->loop, &stream->io_watcher); 7691cb0ef41Sopenharmony_ci} 7701cb0ef41Sopenharmony_ci 7711cb0ef41Sopenharmony_ci 7721cb0ef41Sopenharmony_cistatic int uv__handle_fd(uv_handle_t* handle) { 7731cb0ef41Sopenharmony_ci switch (handle->type) { 7741cb0ef41Sopenharmony_ci case UV_NAMED_PIPE: 7751cb0ef41Sopenharmony_ci case UV_TCP: 7761cb0ef41Sopenharmony_ci return ((uv_stream_t*) handle)->io_watcher.fd; 7771cb0ef41Sopenharmony_ci 7781cb0ef41Sopenharmony_ci case UV_UDP: 7791cb0ef41Sopenharmony_ci return ((uv_udp_t*) handle)->io_watcher.fd; 7801cb0ef41Sopenharmony_ci 7811cb0ef41Sopenharmony_ci default: 7821cb0ef41Sopenharmony_ci return -1; 7831cb0ef41Sopenharmony_ci } 7841cb0ef41Sopenharmony_ci} 7851cb0ef41Sopenharmony_ci 7861cb0ef41Sopenharmony_cistatic int uv__try_write(uv_stream_t* stream, 7871cb0ef41Sopenharmony_ci const uv_buf_t bufs[], 7881cb0ef41Sopenharmony_ci unsigned int nbufs, 7891cb0ef41Sopenharmony_ci uv_stream_t* send_handle) { 7901cb0ef41Sopenharmony_ci struct iovec* iov; 7911cb0ef41Sopenharmony_ci int iovmax; 7921cb0ef41Sopenharmony_ci int iovcnt; 7931cb0ef41Sopenharmony_ci ssize_t n; 7941cb0ef41Sopenharmony_ci 7951cb0ef41Sopenharmony_ci /* 7961cb0ef41Sopenharmony_ci * Cast to iovec. We had to have our own uv_buf_t instead of iovec 7971cb0ef41Sopenharmony_ci * because Windows's WSABUF is not an iovec. 7981cb0ef41Sopenharmony_ci */ 7991cb0ef41Sopenharmony_ci iov = (struct iovec*) bufs; 8001cb0ef41Sopenharmony_ci iovcnt = nbufs; 8011cb0ef41Sopenharmony_ci 8021cb0ef41Sopenharmony_ci iovmax = uv__getiovmax(); 8031cb0ef41Sopenharmony_ci 8041cb0ef41Sopenharmony_ci /* Limit iov count to avoid EINVALs from writev() */ 8051cb0ef41Sopenharmony_ci if (iovcnt > iovmax) 8061cb0ef41Sopenharmony_ci iovcnt = iovmax; 8071cb0ef41Sopenharmony_ci 8081cb0ef41Sopenharmony_ci /* 8091cb0ef41Sopenharmony_ci * Now do the actual writev. Note that we've been updating the pointers 8101cb0ef41Sopenharmony_ci * inside the iov each time we write. So there is no need to offset it. 8111cb0ef41Sopenharmony_ci */ 8121cb0ef41Sopenharmony_ci if (send_handle != NULL) { 8131cb0ef41Sopenharmony_ci int fd_to_send; 8141cb0ef41Sopenharmony_ci struct msghdr msg; 8151cb0ef41Sopenharmony_ci struct cmsghdr *cmsg; 8161cb0ef41Sopenharmony_ci union { 8171cb0ef41Sopenharmony_ci char data[64]; 8181cb0ef41Sopenharmony_ci struct cmsghdr alias; 8191cb0ef41Sopenharmony_ci } scratch; 8201cb0ef41Sopenharmony_ci 8211cb0ef41Sopenharmony_ci if (uv__is_closing(send_handle)) 8221cb0ef41Sopenharmony_ci return UV_EBADF; 8231cb0ef41Sopenharmony_ci 8241cb0ef41Sopenharmony_ci fd_to_send = uv__handle_fd((uv_handle_t*) send_handle); 8251cb0ef41Sopenharmony_ci 8261cb0ef41Sopenharmony_ci memset(&scratch, 0, sizeof(scratch)); 8271cb0ef41Sopenharmony_ci 8281cb0ef41Sopenharmony_ci assert(fd_to_send >= 0); 8291cb0ef41Sopenharmony_ci 8301cb0ef41Sopenharmony_ci msg.msg_name = NULL; 8311cb0ef41Sopenharmony_ci msg.msg_namelen = 0; 8321cb0ef41Sopenharmony_ci msg.msg_iov = iov; 8331cb0ef41Sopenharmony_ci msg.msg_iovlen = iovcnt; 8341cb0ef41Sopenharmony_ci msg.msg_flags = 0; 8351cb0ef41Sopenharmony_ci 8361cb0ef41Sopenharmony_ci msg.msg_control = &scratch.alias; 8371cb0ef41Sopenharmony_ci msg.msg_controllen = CMSG_SPACE(sizeof(fd_to_send)); 8381cb0ef41Sopenharmony_ci 8391cb0ef41Sopenharmony_ci cmsg = CMSG_FIRSTHDR(&msg); 8401cb0ef41Sopenharmony_ci cmsg->cmsg_level = SOL_SOCKET; 8411cb0ef41Sopenharmony_ci cmsg->cmsg_type = SCM_RIGHTS; 8421cb0ef41Sopenharmony_ci cmsg->cmsg_len = CMSG_LEN(sizeof(fd_to_send)); 8431cb0ef41Sopenharmony_ci 8441cb0ef41Sopenharmony_ci /* silence aliasing warning */ 8451cb0ef41Sopenharmony_ci { 8461cb0ef41Sopenharmony_ci void* pv = CMSG_DATA(cmsg); 8471cb0ef41Sopenharmony_ci int* pi = pv; 8481cb0ef41Sopenharmony_ci *pi = fd_to_send; 8491cb0ef41Sopenharmony_ci } 8501cb0ef41Sopenharmony_ci 8511cb0ef41Sopenharmony_ci do 8521cb0ef41Sopenharmony_ci n = sendmsg(uv__stream_fd(stream), &msg, 0); 8531cb0ef41Sopenharmony_ci while (n == -1 && errno == EINTR); 8541cb0ef41Sopenharmony_ci } else { 8551cb0ef41Sopenharmony_ci do 8561cb0ef41Sopenharmony_ci n = uv__writev(uv__stream_fd(stream), iov, iovcnt); 8571cb0ef41Sopenharmony_ci while (n == -1 && errno == EINTR); 8581cb0ef41Sopenharmony_ci } 8591cb0ef41Sopenharmony_ci 8601cb0ef41Sopenharmony_ci if (n >= 0) 8611cb0ef41Sopenharmony_ci return n; 8621cb0ef41Sopenharmony_ci 8631cb0ef41Sopenharmony_ci if (errno == EAGAIN || errno == EWOULDBLOCK || errno == ENOBUFS) 8641cb0ef41Sopenharmony_ci return UV_EAGAIN; 8651cb0ef41Sopenharmony_ci 8661cb0ef41Sopenharmony_ci#ifdef __APPLE__ 8671cb0ef41Sopenharmony_ci /* macOS versions 10.10 and 10.15 - and presumbaly 10.11 to 10.14, too - 8681cb0ef41Sopenharmony_ci * have a bug where a race condition causes the kernel to return EPROTOTYPE 8691cb0ef41Sopenharmony_ci * because the socket isn't fully constructed. It's probably the result of 8701cb0ef41Sopenharmony_ci * the peer closing the connection and that is why libuv translates it to 8711cb0ef41Sopenharmony_ci * ECONNRESET. Previously, libuv retried until the EPROTOTYPE error went 8721cb0ef41Sopenharmony_ci * away but some VPN software causes the same behavior except the error is 8731cb0ef41Sopenharmony_ci * permanent, not transient, turning the retry mechanism into an infinite 8741cb0ef41Sopenharmony_ci * loop. See https://github.com/libuv/libuv/pull/482. 8751cb0ef41Sopenharmony_ci */ 8761cb0ef41Sopenharmony_ci if (errno == EPROTOTYPE) 8771cb0ef41Sopenharmony_ci return UV_ECONNRESET; 8781cb0ef41Sopenharmony_ci#endif /* __APPLE__ */ 8791cb0ef41Sopenharmony_ci 8801cb0ef41Sopenharmony_ci return UV__ERR(errno); 8811cb0ef41Sopenharmony_ci} 8821cb0ef41Sopenharmony_ci 8831cb0ef41Sopenharmony_cistatic void uv__write(uv_stream_t* stream) { 8841cb0ef41Sopenharmony_ci QUEUE* q; 8851cb0ef41Sopenharmony_ci uv_write_t* req; 8861cb0ef41Sopenharmony_ci ssize_t n; 8871cb0ef41Sopenharmony_ci 8881cb0ef41Sopenharmony_ci assert(uv__stream_fd(stream) >= 0); 8891cb0ef41Sopenharmony_ci 8901cb0ef41Sopenharmony_ci for (;;) { 8911cb0ef41Sopenharmony_ci if (QUEUE_EMPTY(&stream->write_queue)) 8921cb0ef41Sopenharmony_ci return; 8931cb0ef41Sopenharmony_ci 8941cb0ef41Sopenharmony_ci q = QUEUE_HEAD(&stream->write_queue); 8951cb0ef41Sopenharmony_ci req = QUEUE_DATA(q, uv_write_t, queue); 8961cb0ef41Sopenharmony_ci assert(req->handle == stream); 8971cb0ef41Sopenharmony_ci 8981cb0ef41Sopenharmony_ci n = uv__try_write(stream, 8991cb0ef41Sopenharmony_ci &(req->bufs[req->write_index]), 9001cb0ef41Sopenharmony_ci req->nbufs - req->write_index, 9011cb0ef41Sopenharmony_ci req->send_handle); 9021cb0ef41Sopenharmony_ci 9031cb0ef41Sopenharmony_ci /* Ensure the handle isn't sent again in case this is a partial write. */ 9041cb0ef41Sopenharmony_ci if (n >= 0) { 9051cb0ef41Sopenharmony_ci req->send_handle = NULL; 9061cb0ef41Sopenharmony_ci if (uv__write_req_update(stream, req, n)) { 9071cb0ef41Sopenharmony_ci uv__write_req_finish(req); 9081cb0ef41Sopenharmony_ci return; /* TODO(bnoordhuis) Start trying to write the next request. */ 9091cb0ef41Sopenharmony_ci } 9101cb0ef41Sopenharmony_ci } else if (n != UV_EAGAIN) 9111cb0ef41Sopenharmony_ci break; 9121cb0ef41Sopenharmony_ci 9131cb0ef41Sopenharmony_ci /* If this is a blocking stream, try again. */ 9141cb0ef41Sopenharmony_ci if (stream->flags & UV_HANDLE_BLOCKING_WRITES) 9151cb0ef41Sopenharmony_ci continue; 9161cb0ef41Sopenharmony_ci 9171cb0ef41Sopenharmony_ci /* We're not done. */ 9181cb0ef41Sopenharmony_ci uv__io_start(stream->loop, &stream->io_watcher, POLLOUT); 9191cb0ef41Sopenharmony_ci 9201cb0ef41Sopenharmony_ci /* Notify select() thread about state change */ 9211cb0ef41Sopenharmony_ci uv__stream_osx_interrupt_select(stream); 9221cb0ef41Sopenharmony_ci 9231cb0ef41Sopenharmony_ci return; 9241cb0ef41Sopenharmony_ci } 9251cb0ef41Sopenharmony_ci 9261cb0ef41Sopenharmony_ci req->error = n; 9271cb0ef41Sopenharmony_ci uv__write_req_finish(req); 9281cb0ef41Sopenharmony_ci uv__io_stop(stream->loop, &stream->io_watcher, POLLOUT); 9291cb0ef41Sopenharmony_ci uv__stream_osx_interrupt_select(stream); 9301cb0ef41Sopenharmony_ci} 9311cb0ef41Sopenharmony_ci 9321cb0ef41Sopenharmony_ci 9331cb0ef41Sopenharmony_cistatic void uv__write_callbacks(uv_stream_t* stream) { 9341cb0ef41Sopenharmony_ci uv_write_t* req; 9351cb0ef41Sopenharmony_ci QUEUE* q; 9361cb0ef41Sopenharmony_ci QUEUE pq; 9371cb0ef41Sopenharmony_ci 9381cb0ef41Sopenharmony_ci if (QUEUE_EMPTY(&stream->write_completed_queue)) 9391cb0ef41Sopenharmony_ci return; 9401cb0ef41Sopenharmony_ci 9411cb0ef41Sopenharmony_ci QUEUE_MOVE(&stream->write_completed_queue, &pq); 9421cb0ef41Sopenharmony_ci 9431cb0ef41Sopenharmony_ci while (!QUEUE_EMPTY(&pq)) { 9441cb0ef41Sopenharmony_ci /* Pop a req off write_completed_queue. */ 9451cb0ef41Sopenharmony_ci q = QUEUE_HEAD(&pq); 9461cb0ef41Sopenharmony_ci req = QUEUE_DATA(q, uv_write_t, queue); 9471cb0ef41Sopenharmony_ci QUEUE_REMOVE(q); 9481cb0ef41Sopenharmony_ci uv__req_unregister(stream->loop, req); 9491cb0ef41Sopenharmony_ci 9501cb0ef41Sopenharmony_ci if (req->bufs != NULL) { 9511cb0ef41Sopenharmony_ci stream->write_queue_size -= uv__write_req_size(req); 9521cb0ef41Sopenharmony_ci if (req->bufs != req->bufsml) 9531cb0ef41Sopenharmony_ci uv__free(req->bufs); 9541cb0ef41Sopenharmony_ci req->bufs = NULL; 9551cb0ef41Sopenharmony_ci } 9561cb0ef41Sopenharmony_ci 9571cb0ef41Sopenharmony_ci /* NOTE: call callback AFTER freeing the request data. */ 9581cb0ef41Sopenharmony_ci if (req->cb) 9591cb0ef41Sopenharmony_ci req->cb(req, req->error); 9601cb0ef41Sopenharmony_ci } 9611cb0ef41Sopenharmony_ci} 9621cb0ef41Sopenharmony_ci 9631cb0ef41Sopenharmony_ci 9641cb0ef41Sopenharmony_cistatic void uv__stream_eof(uv_stream_t* stream, const uv_buf_t* buf) { 9651cb0ef41Sopenharmony_ci stream->flags |= UV_HANDLE_READ_EOF; 9661cb0ef41Sopenharmony_ci stream->flags &= ~UV_HANDLE_READING; 9671cb0ef41Sopenharmony_ci uv__io_stop(stream->loop, &stream->io_watcher, POLLIN); 9681cb0ef41Sopenharmony_ci uv__handle_stop(stream); 9691cb0ef41Sopenharmony_ci uv__stream_osx_interrupt_select(stream); 9701cb0ef41Sopenharmony_ci stream->read_cb(stream, UV_EOF, buf); 9711cb0ef41Sopenharmony_ci} 9721cb0ef41Sopenharmony_ci 9731cb0ef41Sopenharmony_ci 9741cb0ef41Sopenharmony_cistatic int uv__stream_queue_fd(uv_stream_t* stream, int fd) { 9751cb0ef41Sopenharmony_ci uv__stream_queued_fds_t* queued_fds; 9761cb0ef41Sopenharmony_ci unsigned int queue_size; 9771cb0ef41Sopenharmony_ci 9781cb0ef41Sopenharmony_ci queued_fds = stream->queued_fds; 9791cb0ef41Sopenharmony_ci if (queued_fds == NULL) { 9801cb0ef41Sopenharmony_ci queue_size = 8; 9811cb0ef41Sopenharmony_ci queued_fds = uv__malloc((queue_size - 1) * sizeof(*queued_fds->fds) + 9821cb0ef41Sopenharmony_ci sizeof(*queued_fds)); 9831cb0ef41Sopenharmony_ci if (queued_fds == NULL) 9841cb0ef41Sopenharmony_ci return UV_ENOMEM; 9851cb0ef41Sopenharmony_ci queued_fds->size = queue_size; 9861cb0ef41Sopenharmony_ci queued_fds->offset = 0; 9871cb0ef41Sopenharmony_ci stream->queued_fds = queued_fds; 9881cb0ef41Sopenharmony_ci 9891cb0ef41Sopenharmony_ci /* Grow */ 9901cb0ef41Sopenharmony_ci } else if (queued_fds->size == queued_fds->offset) { 9911cb0ef41Sopenharmony_ci queue_size = queued_fds->size + 8; 9921cb0ef41Sopenharmony_ci queued_fds = uv__realloc(queued_fds, 9931cb0ef41Sopenharmony_ci (queue_size - 1) * sizeof(*queued_fds->fds) + 9941cb0ef41Sopenharmony_ci sizeof(*queued_fds)); 9951cb0ef41Sopenharmony_ci 9961cb0ef41Sopenharmony_ci /* 9971cb0ef41Sopenharmony_ci * Allocation failure, report back. 9981cb0ef41Sopenharmony_ci * NOTE: if it is fatal - sockets will be closed in uv__stream_close 9991cb0ef41Sopenharmony_ci */ 10001cb0ef41Sopenharmony_ci if (queued_fds == NULL) 10011cb0ef41Sopenharmony_ci return UV_ENOMEM; 10021cb0ef41Sopenharmony_ci queued_fds->size = queue_size; 10031cb0ef41Sopenharmony_ci stream->queued_fds = queued_fds; 10041cb0ef41Sopenharmony_ci } 10051cb0ef41Sopenharmony_ci 10061cb0ef41Sopenharmony_ci /* Put fd in a queue */ 10071cb0ef41Sopenharmony_ci queued_fds->fds[queued_fds->offset++] = fd; 10081cb0ef41Sopenharmony_ci 10091cb0ef41Sopenharmony_ci return 0; 10101cb0ef41Sopenharmony_ci} 10111cb0ef41Sopenharmony_ci 10121cb0ef41Sopenharmony_ci 10131cb0ef41Sopenharmony_ci#if defined(__PASE__) 10141cb0ef41Sopenharmony_ci/* on IBMi PASE the control message length can not exceed 256. */ 10151cb0ef41Sopenharmony_ci# define UV__CMSG_FD_COUNT 60 10161cb0ef41Sopenharmony_ci#else 10171cb0ef41Sopenharmony_ci# define UV__CMSG_FD_COUNT 64 10181cb0ef41Sopenharmony_ci#endif 10191cb0ef41Sopenharmony_ci#define UV__CMSG_FD_SIZE (UV__CMSG_FD_COUNT * sizeof(int)) 10201cb0ef41Sopenharmony_ci 10211cb0ef41Sopenharmony_ci 10221cb0ef41Sopenharmony_cistatic int uv__stream_recv_cmsg(uv_stream_t* stream, struct msghdr* msg) { 10231cb0ef41Sopenharmony_ci struct cmsghdr* cmsg; 10241cb0ef41Sopenharmony_ci 10251cb0ef41Sopenharmony_ci for (cmsg = CMSG_FIRSTHDR(msg); cmsg != NULL; cmsg = CMSG_NXTHDR(msg, cmsg)) { 10261cb0ef41Sopenharmony_ci char* start; 10271cb0ef41Sopenharmony_ci char* end; 10281cb0ef41Sopenharmony_ci int err; 10291cb0ef41Sopenharmony_ci void* pv; 10301cb0ef41Sopenharmony_ci int* pi; 10311cb0ef41Sopenharmony_ci unsigned int i; 10321cb0ef41Sopenharmony_ci unsigned int count; 10331cb0ef41Sopenharmony_ci 10341cb0ef41Sopenharmony_ci if (cmsg->cmsg_type != SCM_RIGHTS) { 10351cb0ef41Sopenharmony_ci fprintf(stderr, "ignoring non-SCM_RIGHTS ancillary data: %d\n", 10361cb0ef41Sopenharmony_ci cmsg->cmsg_type); 10371cb0ef41Sopenharmony_ci continue; 10381cb0ef41Sopenharmony_ci } 10391cb0ef41Sopenharmony_ci 10401cb0ef41Sopenharmony_ci /* silence aliasing warning */ 10411cb0ef41Sopenharmony_ci pv = CMSG_DATA(cmsg); 10421cb0ef41Sopenharmony_ci pi = pv; 10431cb0ef41Sopenharmony_ci 10441cb0ef41Sopenharmony_ci /* Count available fds */ 10451cb0ef41Sopenharmony_ci start = (char*) cmsg; 10461cb0ef41Sopenharmony_ci end = (char*) cmsg + cmsg->cmsg_len; 10471cb0ef41Sopenharmony_ci count = 0; 10481cb0ef41Sopenharmony_ci while (start + CMSG_LEN(count * sizeof(*pi)) < end) 10491cb0ef41Sopenharmony_ci count++; 10501cb0ef41Sopenharmony_ci assert(start + CMSG_LEN(count * sizeof(*pi)) == end); 10511cb0ef41Sopenharmony_ci 10521cb0ef41Sopenharmony_ci for (i = 0; i < count; i++) { 10531cb0ef41Sopenharmony_ci /* Already has accepted fd, queue now */ 10541cb0ef41Sopenharmony_ci if (stream->accepted_fd != -1) { 10551cb0ef41Sopenharmony_ci err = uv__stream_queue_fd(stream, pi[i]); 10561cb0ef41Sopenharmony_ci if (err != 0) { 10571cb0ef41Sopenharmony_ci /* Close rest */ 10581cb0ef41Sopenharmony_ci for (; i < count; i++) 10591cb0ef41Sopenharmony_ci uv__close(pi[i]); 10601cb0ef41Sopenharmony_ci return err; 10611cb0ef41Sopenharmony_ci } 10621cb0ef41Sopenharmony_ci } else { 10631cb0ef41Sopenharmony_ci stream->accepted_fd = pi[i]; 10641cb0ef41Sopenharmony_ci } 10651cb0ef41Sopenharmony_ci } 10661cb0ef41Sopenharmony_ci } 10671cb0ef41Sopenharmony_ci 10681cb0ef41Sopenharmony_ci return 0; 10691cb0ef41Sopenharmony_ci} 10701cb0ef41Sopenharmony_ci 10711cb0ef41Sopenharmony_ci 10721cb0ef41Sopenharmony_ci#ifdef __clang__ 10731cb0ef41Sopenharmony_ci# pragma clang diagnostic push 10741cb0ef41Sopenharmony_ci# pragma clang diagnostic ignored "-Wgnu-folding-constant" 10751cb0ef41Sopenharmony_ci# pragma clang diagnostic ignored "-Wvla-extension" 10761cb0ef41Sopenharmony_ci#endif 10771cb0ef41Sopenharmony_ci 10781cb0ef41Sopenharmony_cistatic void uv__read(uv_stream_t* stream) { 10791cb0ef41Sopenharmony_ci uv_buf_t buf; 10801cb0ef41Sopenharmony_ci ssize_t nread; 10811cb0ef41Sopenharmony_ci struct msghdr msg; 10821cb0ef41Sopenharmony_ci char cmsg_space[CMSG_SPACE(UV__CMSG_FD_SIZE)]; 10831cb0ef41Sopenharmony_ci int count; 10841cb0ef41Sopenharmony_ci int err; 10851cb0ef41Sopenharmony_ci int is_ipc; 10861cb0ef41Sopenharmony_ci 10871cb0ef41Sopenharmony_ci stream->flags &= ~UV_HANDLE_READ_PARTIAL; 10881cb0ef41Sopenharmony_ci 10891cb0ef41Sopenharmony_ci /* Prevent loop starvation when the data comes in as fast as (or faster than) 10901cb0ef41Sopenharmony_ci * we can read it. XXX Need to rearm fd if we switch to edge-triggered I/O. 10911cb0ef41Sopenharmony_ci */ 10921cb0ef41Sopenharmony_ci count = 32; 10931cb0ef41Sopenharmony_ci 10941cb0ef41Sopenharmony_ci is_ipc = stream->type == UV_NAMED_PIPE && ((uv_pipe_t*) stream)->ipc; 10951cb0ef41Sopenharmony_ci 10961cb0ef41Sopenharmony_ci /* XXX: Maybe instead of having UV_HANDLE_READING we just test if 10971cb0ef41Sopenharmony_ci * tcp->read_cb is NULL or not? 10981cb0ef41Sopenharmony_ci */ 10991cb0ef41Sopenharmony_ci while (stream->read_cb 11001cb0ef41Sopenharmony_ci && (stream->flags & UV_HANDLE_READING) 11011cb0ef41Sopenharmony_ci && (count-- > 0)) { 11021cb0ef41Sopenharmony_ci assert(stream->alloc_cb != NULL); 11031cb0ef41Sopenharmony_ci 11041cb0ef41Sopenharmony_ci buf = uv_buf_init(NULL, 0); 11051cb0ef41Sopenharmony_ci stream->alloc_cb((uv_handle_t*)stream, 64 * 1024, &buf); 11061cb0ef41Sopenharmony_ci if (buf.base == NULL || buf.len == 0) { 11071cb0ef41Sopenharmony_ci /* User indicates it can't or won't handle the read. */ 11081cb0ef41Sopenharmony_ci stream->read_cb(stream, UV_ENOBUFS, &buf); 11091cb0ef41Sopenharmony_ci return; 11101cb0ef41Sopenharmony_ci } 11111cb0ef41Sopenharmony_ci 11121cb0ef41Sopenharmony_ci assert(buf.base != NULL); 11131cb0ef41Sopenharmony_ci assert(uv__stream_fd(stream) >= 0); 11141cb0ef41Sopenharmony_ci 11151cb0ef41Sopenharmony_ci if (!is_ipc) { 11161cb0ef41Sopenharmony_ci do { 11171cb0ef41Sopenharmony_ci nread = read(uv__stream_fd(stream), buf.base, buf.len); 11181cb0ef41Sopenharmony_ci } 11191cb0ef41Sopenharmony_ci while (nread < 0 && errno == EINTR); 11201cb0ef41Sopenharmony_ci } else { 11211cb0ef41Sopenharmony_ci /* ipc uses recvmsg */ 11221cb0ef41Sopenharmony_ci msg.msg_flags = 0; 11231cb0ef41Sopenharmony_ci msg.msg_iov = (struct iovec*) &buf; 11241cb0ef41Sopenharmony_ci msg.msg_iovlen = 1; 11251cb0ef41Sopenharmony_ci msg.msg_name = NULL; 11261cb0ef41Sopenharmony_ci msg.msg_namelen = 0; 11271cb0ef41Sopenharmony_ci /* Set up to receive a descriptor even if one isn't in the message */ 11281cb0ef41Sopenharmony_ci msg.msg_controllen = sizeof(cmsg_space); 11291cb0ef41Sopenharmony_ci msg.msg_control = cmsg_space; 11301cb0ef41Sopenharmony_ci 11311cb0ef41Sopenharmony_ci do { 11321cb0ef41Sopenharmony_ci nread = uv__recvmsg(uv__stream_fd(stream), &msg, 0); 11331cb0ef41Sopenharmony_ci } 11341cb0ef41Sopenharmony_ci while (nread < 0 && errno == EINTR); 11351cb0ef41Sopenharmony_ci } 11361cb0ef41Sopenharmony_ci 11371cb0ef41Sopenharmony_ci if (nread < 0) { 11381cb0ef41Sopenharmony_ci /* Error */ 11391cb0ef41Sopenharmony_ci if (errno == EAGAIN || errno == EWOULDBLOCK) { 11401cb0ef41Sopenharmony_ci /* Wait for the next one. */ 11411cb0ef41Sopenharmony_ci if (stream->flags & UV_HANDLE_READING) { 11421cb0ef41Sopenharmony_ci uv__io_start(stream->loop, &stream->io_watcher, POLLIN); 11431cb0ef41Sopenharmony_ci uv__stream_osx_interrupt_select(stream); 11441cb0ef41Sopenharmony_ci } 11451cb0ef41Sopenharmony_ci stream->read_cb(stream, 0, &buf); 11461cb0ef41Sopenharmony_ci#if defined(__CYGWIN__) || defined(__MSYS__) 11471cb0ef41Sopenharmony_ci } else if (errno == ECONNRESET && stream->type == UV_NAMED_PIPE) { 11481cb0ef41Sopenharmony_ci uv__stream_eof(stream, &buf); 11491cb0ef41Sopenharmony_ci return; 11501cb0ef41Sopenharmony_ci#endif 11511cb0ef41Sopenharmony_ci } else { 11521cb0ef41Sopenharmony_ci /* Error. User should call uv_close(). */ 11531cb0ef41Sopenharmony_ci stream->flags &= ~(UV_HANDLE_READABLE | UV_HANDLE_WRITABLE); 11541cb0ef41Sopenharmony_ci stream->read_cb(stream, UV__ERR(errno), &buf); 11551cb0ef41Sopenharmony_ci if (stream->flags & UV_HANDLE_READING) { 11561cb0ef41Sopenharmony_ci stream->flags &= ~UV_HANDLE_READING; 11571cb0ef41Sopenharmony_ci uv__io_stop(stream->loop, &stream->io_watcher, POLLIN); 11581cb0ef41Sopenharmony_ci uv__handle_stop(stream); 11591cb0ef41Sopenharmony_ci uv__stream_osx_interrupt_select(stream); 11601cb0ef41Sopenharmony_ci } 11611cb0ef41Sopenharmony_ci } 11621cb0ef41Sopenharmony_ci return; 11631cb0ef41Sopenharmony_ci } else if (nread == 0) { 11641cb0ef41Sopenharmony_ci uv__stream_eof(stream, &buf); 11651cb0ef41Sopenharmony_ci return; 11661cb0ef41Sopenharmony_ci } else { 11671cb0ef41Sopenharmony_ci /* Successful read */ 11681cb0ef41Sopenharmony_ci ssize_t buflen = buf.len; 11691cb0ef41Sopenharmony_ci 11701cb0ef41Sopenharmony_ci if (is_ipc) { 11711cb0ef41Sopenharmony_ci err = uv__stream_recv_cmsg(stream, &msg); 11721cb0ef41Sopenharmony_ci if (err != 0) { 11731cb0ef41Sopenharmony_ci stream->read_cb(stream, err, &buf); 11741cb0ef41Sopenharmony_ci return; 11751cb0ef41Sopenharmony_ci } 11761cb0ef41Sopenharmony_ci } 11771cb0ef41Sopenharmony_ci 11781cb0ef41Sopenharmony_ci#if defined(__MVS__) 11791cb0ef41Sopenharmony_ci if (is_ipc && msg.msg_controllen > 0) { 11801cb0ef41Sopenharmony_ci uv_buf_t blankbuf; 11811cb0ef41Sopenharmony_ci int nread; 11821cb0ef41Sopenharmony_ci struct iovec *old; 11831cb0ef41Sopenharmony_ci 11841cb0ef41Sopenharmony_ci blankbuf.base = 0; 11851cb0ef41Sopenharmony_ci blankbuf.len = 0; 11861cb0ef41Sopenharmony_ci old = msg.msg_iov; 11871cb0ef41Sopenharmony_ci msg.msg_iov = (struct iovec*) &blankbuf; 11881cb0ef41Sopenharmony_ci nread = 0; 11891cb0ef41Sopenharmony_ci do { 11901cb0ef41Sopenharmony_ci nread = uv__recvmsg(uv__stream_fd(stream), &msg, 0); 11911cb0ef41Sopenharmony_ci err = uv__stream_recv_cmsg(stream, &msg); 11921cb0ef41Sopenharmony_ci if (err != 0) { 11931cb0ef41Sopenharmony_ci stream->read_cb(stream, err, &buf); 11941cb0ef41Sopenharmony_ci msg.msg_iov = old; 11951cb0ef41Sopenharmony_ci return; 11961cb0ef41Sopenharmony_ci } 11971cb0ef41Sopenharmony_ci } while (nread == 0 && msg.msg_controllen > 0); 11981cb0ef41Sopenharmony_ci msg.msg_iov = old; 11991cb0ef41Sopenharmony_ci } 12001cb0ef41Sopenharmony_ci#endif 12011cb0ef41Sopenharmony_ci stream->read_cb(stream, nread, &buf); 12021cb0ef41Sopenharmony_ci 12031cb0ef41Sopenharmony_ci /* Return if we didn't fill the buffer, there is no more data to read. */ 12041cb0ef41Sopenharmony_ci if (nread < buflen) { 12051cb0ef41Sopenharmony_ci stream->flags |= UV_HANDLE_READ_PARTIAL; 12061cb0ef41Sopenharmony_ci return; 12071cb0ef41Sopenharmony_ci } 12081cb0ef41Sopenharmony_ci } 12091cb0ef41Sopenharmony_ci } 12101cb0ef41Sopenharmony_ci} 12111cb0ef41Sopenharmony_ci 12121cb0ef41Sopenharmony_ci 12131cb0ef41Sopenharmony_ci#ifdef __clang__ 12141cb0ef41Sopenharmony_ci# pragma clang diagnostic pop 12151cb0ef41Sopenharmony_ci#endif 12161cb0ef41Sopenharmony_ci 12171cb0ef41Sopenharmony_ci#undef UV__CMSG_FD_COUNT 12181cb0ef41Sopenharmony_ci#undef UV__CMSG_FD_SIZE 12191cb0ef41Sopenharmony_ci 12201cb0ef41Sopenharmony_ci 12211cb0ef41Sopenharmony_ciint uv_shutdown(uv_shutdown_t* req, uv_stream_t* stream, uv_shutdown_cb cb) { 12221cb0ef41Sopenharmony_ci assert(stream->type == UV_TCP || 12231cb0ef41Sopenharmony_ci stream->type == UV_TTY || 12241cb0ef41Sopenharmony_ci stream->type == UV_NAMED_PIPE); 12251cb0ef41Sopenharmony_ci 12261cb0ef41Sopenharmony_ci if (!(stream->flags & UV_HANDLE_WRITABLE) || 12271cb0ef41Sopenharmony_ci stream->flags & UV_HANDLE_SHUT || 12281cb0ef41Sopenharmony_ci stream->flags & UV_HANDLE_SHUTTING || 12291cb0ef41Sopenharmony_ci uv__is_closing(stream)) { 12301cb0ef41Sopenharmony_ci return UV_ENOTCONN; 12311cb0ef41Sopenharmony_ci } 12321cb0ef41Sopenharmony_ci 12331cb0ef41Sopenharmony_ci assert(uv__stream_fd(stream) >= 0); 12341cb0ef41Sopenharmony_ci 12351cb0ef41Sopenharmony_ci /* Initialize request. The `shutdown(2)` call will always be deferred until 12361cb0ef41Sopenharmony_ci * `uv__drain`, just before the callback is run. */ 12371cb0ef41Sopenharmony_ci uv__req_init(stream->loop, req, UV_SHUTDOWN); 12381cb0ef41Sopenharmony_ci req->handle = stream; 12391cb0ef41Sopenharmony_ci req->cb = cb; 12401cb0ef41Sopenharmony_ci stream->shutdown_req = req; 12411cb0ef41Sopenharmony_ci stream->flags |= UV_HANDLE_SHUTTING; 12421cb0ef41Sopenharmony_ci stream->flags &= ~UV_HANDLE_WRITABLE; 12431cb0ef41Sopenharmony_ci 12441cb0ef41Sopenharmony_ci if (QUEUE_EMPTY(&stream->write_queue)) 12451cb0ef41Sopenharmony_ci uv__io_feed(stream->loop, &stream->io_watcher); 12461cb0ef41Sopenharmony_ci 12471cb0ef41Sopenharmony_ci return 0; 12481cb0ef41Sopenharmony_ci} 12491cb0ef41Sopenharmony_ci 12501cb0ef41Sopenharmony_ci 12511cb0ef41Sopenharmony_cistatic void uv__stream_io(uv_loop_t* loop, uv__io_t* w, unsigned int events) { 12521cb0ef41Sopenharmony_ci uv_stream_t* stream; 12531cb0ef41Sopenharmony_ci 12541cb0ef41Sopenharmony_ci stream = container_of(w, uv_stream_t, io_watcher); 12551cb0ef41Sopenharmony_ci 12561cb0ef41Sopenharmony_ci assert(stream->type == UV_TCP || 12571cb0ef41Sopenharmony_ci stream->type == UV_NAMED_PIPE || 12581cb0ef41Sopenharmony_ci stream->type == UV_TTY); 12591cb0ef41Sopenharmony_ci assert(!(stream->flags & UV_HANDLE_CLOSING)); 12601cb0ef41Sopenharmony_ci 12611cb0ef41Sopenharmony_ci if (stream->connect_req) { 12621cb0ef41Sopenharmony_ci uv__stream_connect(stream); 12631cb0ef41Sopenharmony_ci return; 12641cb0ef41Sopenharmony_ci } 12651cb0ef41Sopenharmony_ci 12661cb0ef41Sopenharmony_ci assert(uv__stream_fd(stream) >= 0); 12671cb0ef41Sopenharmony_ci 12681cb0ef41Sopenharmony_ci /* Ignore POLLHUP here. Even if it's set, there may still be data to read. */ 12691cb0ef41Sopenharmony_ci if (events & (POLLIN | POLLERR | POLLHUP)) 12701cb0ef41Sopenharmony_ci uv__read(stream); 12711cb0ef41Sopenharmony_ci 12721cb0ef41Sopenharmony_ci if (uv__stream_fd(stream) == -1) 12731cb0ef41Sopenharmony_ci return; /* read_cb closed stream. */ 12741cb0ef41Sopenharmony_ci 12751cb0ef41Sopenharmony_ci /* Short-circuit iff POLLHUP is set, the user is still interested in read 12761cb0ef41Sopenharmony_ci * events and uv__read() reported a partial read but not EOF. If the EOF 12771cb0ef41Sopenharmony_ci * flag is set, uv__read() called read_cb with err=UV_EOF and we don't 12781cb0ef41Sopenharmony_ci * have to do anything. If the partial read flag is not set, we can't 12791cb0ef41Sopenharmony_ci * report the EOF yet because there is still data to read. 12801cb0ef41Sopenharmony_ci */ 12811cb0ef41Sopenharmony_ci if ((events & POLLHUP) && 12821cb0ef41Sopenharmony_ci (stream->flags & UV_HANDLE_READING) && 12831cb0ef41Sopenharmony_ci (stream->flags & UV_HANDLE_READ_PARTIAL) && 12841cb0ef41Sopenharmony_ci !(stream->flags & UV_HANDLE_READ_EOF)) { 12851cb0ef41Sopenharmony_ci uv_buf_t buf = { NULL, 0 }; 12861cb0ef41Sopenharmony_ci uv__stream_eof(stream, &buf); 12871cb0ef41Sopenharmony_ci } 12881cb0ef41Sopenharmony_ci 12891cb0ef41Sopenharmony_ci if (uv__stream_fd(stream) == -1) 12901cb0ef41Sopenharmony_ci return; /* read_cb closed stream. */ 12911cb0ef41Sopenharmony_ci 12921cb0ef41Sopenharmony_ci if (events & (POLLOUT | POLLERR | POLLHUP)) { 12931cb0ef41Sopenharmony_ci uv__write(stream); 12941cb0ef41Sopenharmony_ci uv__write_callbacks(stream); 12951cb0ef41Sopenharmony_ci 12961cb0ef41Sopenharmony_ci /* Write queue drained. */ 12971cb0ef41Sopenharmony_ci if (QUEUE_EMPTY(&stream->write_queue)) 12981cb0ef41Sopenharmony_ci uv__drain(stream); 12991cb0ef41Sopenharmony_ci } 13001cb0ef41Sopenharmony_ci} 13011cb0ef41Sopenharmony_ci 13021cb0ef41Sopenharmony_ci 13031cb0ef41Sopenharmony_ci/** 13041cb0ef41Sopenharmony_ci * We get called here from directly following a call to connect(2). 13051cb0ef41Sopenharmony_ci * In order to determine if we've errored out or succeeded must call 13061cb0ef41Sopenharmony_ci * getsockopt. 13071cb0ef41Sopenharmony_ci */ 13081cb0ef41Sopenharmony_cistatic void uv__stream_connect(uv_stream_t* stream) { 13091cb0ef41Sopenharmony_ci int error; 13101cb0ef41Sopenharmony_ci uv_connect_t* req = stream->connect_req; 13111cb0ef41Sopenharmony_ci socklen_t errorsize = sizeof(int); 13121cb0ef41Sopenharmony_ci 13131cb0ef41Sopenharmony_ci assert(stream->type == UV_TCP || stream->type == UV_NAMED_PIPE); 13141cb0ef41Sopenharmony_ci assert(req); 13151cb0ef41Sopenharmony_ci 13161cb0ef41Sopenharmony_ci if (stream->delayed_error) { 13171cb0ef41Sopenharmony_ci /* To smooth over the differences between unixes errors that 13181cb0ef41Sopenharmony_ci * were reported synchronously on the first connect can be delayed 13191cb0ef41Sopenharmony_ci * until the next tick--which is now. 13201cb0ef41Sopenharmony_ci */ 13211cb0ef41Sopenharmony_ci error = stream->delayed_error; 13221cb0ef41Sopenharmony_ci stream->delayed_error = 0; 13231cb0ef41Sopenharmony_ci } else { 13241cb0ef41Sopenharmony_ci /* Normal situation: we need to get the socket error from the kernel. */ 13251cb0ef41Sopenharmony_ci assert(uv__stream_fd(stream) >= 0); 13261cb0ef41Sopenharmony_ci getsockopt(uv__stream_fd(stream), 13271cb0ef41Sopenharmony_ci SOL_SOCKET, 13281cb0ef41Sopenharmony_ci SO_ERROR, 13291cb0ef41Sopenharmony_ci &error, 13301cb0ef41Sopenharmony_ci &errorsize); 13311cb0ef41Sopenharmony_ci error = UV__ERR(error); 13321cb0ef41Sopenharmony_ci } 13331cb0ef41Sopenharmony_ci 13341cb0ef41Sopenharmony_ci if (error == UV__ERR(EINPROGRESS)) 13351cb0ef41Sopenharmony_ci return; 13361cb0ef41Sopenharmony_ci 13371cb0ef41Sopenharmony_ci stream->connect_req = NULL; 13381cb0ef41Sopenharmony_ci uv__req_unregister(stream->loop, req); 13391cb0ef41Sopenharmony_ci 13401cb0ef41Sopenharmony_ci if (error < 0 || QUEUE_EMPTY(&stream->write_queue)) { 13411cb0ef41Sopenharmony_ci uv__io_stop(stream->loop, &stream->io_watcher, POLLOUT); 13421cb0ef41Sopenharmony_ci } 13431cb0ef41Sopenharmony_ci 13441cb0ef41Sopenharmony_ci if (req->cb) 13451cb0ef41Sopenharmony_ci req->cb(req, error); 13461cb0ef41Sopenharmony_ci 13471cb0ef41Sopenharmony_ci if (uv__stream_fd(stream) == -1) 13481cb0ef41Sopenharmony_ci return; 13491cb0ef41Sopenharmony_ci 13501cb0ef41Sopenharmony_ci if (error < 0) { 13511cb0ef41Sopenharmony_ci uv__stream_flush_write_queue(stream, UV_ECANCELED); 13521cb0ef41Sopenharmony_ci uv__write_callbacks(stream); 13531cb0ef41Sopenharmony_ci } 13541cb0ef41Sopenharmony_ci} 13551cb0ef41Sopenharmony_ci 13561cb0ef41Sopenharmony_ci 13571cb0ef41Sopenharmony_cistatic int uv__check_before_write(uv_stream_t* stream, 13581cb0ef41Sopenharmony_ci unsigned int nbufs, 13591cb0ef41Sopenharmony_ci uv_stream_t* send_handle) { 13601cb0ef41Sopenharmony_ci assert(nbufs > 0); 13611cb0ef41Sopenharmony_ci assert((stream->type == UV_TCP || 13621cb0ef41Sopenharmony_ci stream->type == UV_NAMED_PIPE || 13631cb0ef41Sopenharmony_ci stream->type == UV_TTY) && 13641cb0ef41Sopenharmony_ci "uv_write (unix) does not yet support other types of streams"); 13651cb0ef41Sopenharmony_ci 13661cb0ef41Sopenharmony_ci if (uv__stream_fd(stream) < 0) 13671cb0ef41Sopenharmony_ci return UV_EBADF; 13681cb0ef41Sopenharmony_ci 13691cb0ef41Sopenharmony_ci if (!(stream->flags & UV_HANDLE_WRITABLE)) 13701cb0ef41Sopenharmony_ci return UV_EPIPE; 13711cb0ef41Sopenharmony_ci 13721cb0ef41Sopenharmony_ci if (send_handle != NULL) { 13731cb0ef41Sopenharmony_ci if (stream->type != UV_NAMED_PIPE || !((uv_pipe_t*)stream)->ipc) 13741cb0ef41Sopenharmony_ci return UV_EINVAL; 13751cb0ef41Sopenharmony_ci 13761cb0ef41Sopenharmony_ci /* XXX We abuse uv_write2() to send over UDP handles to child processes. 13771cb0ef41Sopenharmony_ci * Don't call uv__stream_fd() on those handles, it's a macro that on OS X 13781cb0ef41Sopenharmony_ci * evaluates to a function that operates on a uv_stream_t with a couple of 13791cb0ef41Sopenharmony_ci * OS X specific fields. On other Unices it does (handle)->io_watcher.fd, 13801cb0ef41Sopenharmony_ci * which works but only by accident. 13811cb0ef41Sopenharmony_ci */ 13821cb0ef41Sopenharmony_ci if (uv__handle_fd((uv_handle_t*) send_handle) < 0) 13831cb0ef41Sopenharmony_ci return UV_EBADF; 13841cb0ef41Sopenharmony_ci 13851cb0ef41Sopenharmony_ci#if defined(__CYGWIN__) || defined(__MSYS__) 13861cb0ef41Sopenharmony_ci /* Cygwin recvmsg always sets msg_controllen to zero, so we cannot send it. 13871cb0ef41Sopenharmony_ci See https://github.com/mirror/newlib-cygwin/blob/86fc4bf0/winsup/cygwin/fhandler_socket.cc#L1736-L1743 */ 13881cb0ef41Sopenharmony_ci return UV_ENOSYS; 13891cb0ef41Sopenharmony_ci#endif 13901cb0ef41Sopenharmony_ci } 13911cb0ef41Sopenharmony_ci 13921cb0ef41Sopenharmony_ci return 0; 13931cb0ef41Sopenharmony_ci} 13941cb0ef41Sopenharmony_ci 13951cb0ef41Sopenharmony_ciint uv_write2(uv_write_t* req, 13961cb0ef41Sopenharmony_ci uv_stream_t* stream, 13971cb0ef41Sopenharmony_ci const uv_buf_t bufs[], 13981cb0ef41Sopenharmony_ci unsigned int nbufs, 13991cb0ef41Sopenharmony_ci uv_stream_t* send_handle, 14001cb0ef41Sopenharmony_ci uv_write_cb cb) { 14011cb0ef41Sopenharmony_ci int empty_queue; 14021cb0ef41Sopenharmony_ci int err; 14031cb0ef41Sopenharmony_ci 14041cb0ef41Sopenharmony_ci err = uv__check_before_write(stream, nbufs, send_handle); 14051cb0ef41Sopenharmony_ci if (err < 0) 14061cb0ef41Sopenharmony_ci return err; 14071cb0ef41Sopenharmony_ci 14081cb0ef41Sopenharmony_ci /* It's legal for write_queue_size > 0 even when the write_queue is empty; 14091cb0ef41Sopenharmony_ci * it means there are error-state requests in the write_completed_queue that 14101cb0ef41Sopenharmony_ci * will touch up write_queue_size later, see also uv__write_req_finish(). 14111cb0ef41Sopenharmony_ci * We could check that write_queue is empty instead but that implies making 14121cb0ef41Sopenharmony_ci * a write() syscall when we know that the handle is in error mode. 14131cb0ef41Sopenharmony_ci */ 14141cb0ef41Sopenharmony_ci empty_queue = (stream->write_queue_size == 0); 14151cb0ef41Sopenharmony_ci 14161cb0ef41Sopenharmony_ci /* Initialize the req */ 14171cb0ef41Sopenharmony_ci uv__req_init(stream->loop, req, UV_WRITE); 14181cb0ef41Sopenharmony_ci req->cb = cb; 14191cb0ef41Sopenharmony_ci req->handle = stream; 14201cb0ef41Sopenharmony_ci req->error = 0; 14211cb0ef41Sopenharmony_ci req->send_handle = send_handle; 14221cb0ef41Sopenharmony_ci QUEUE_INIT(&req->queue); 14231cb0ef41Sopenharmony_ci 14241cb0ef41Sopenharmony_ci req->bufs = req->bufsml; 14251cb0ef41Sopenharmony_ci if (nbufs > ARRAY_SIZE(req->bufsml)) 14261cb0ef41Sopenharmony_ci req->bufs = uv__malloc(nbufs * sizeof(bufs[0])); 14271cb0ef41Sopenharmony_ci 14281cb0ef41Sopenharmony_ci if (req->bufs == NULL) 14291cb0ef41Sopenharmony_ci return UV_ENOMEM; 14301cb0ef41Sopenharmony_ci 14311cb0ef41Sopenharmony_ci memcpy(req->bufs, bufs, nbufs * sizeof(bufs[0])); 14321cb0ef41Sopenharmony_ci req->nbufs = nbufs; 14331cb0ef41Sopenharmony_ci req->write_index = 0; 14341cb0ef41Sopenharmony_ci stream->write_queue_size += uv__count_bufs(bufs, nbufs); 14351cb0ef41Sopenharmony_ci 14361cb0ef41Sopenharmony_ci /* Append the request to write_queue. */ 14371cb0ef41Sopenharmony_ci QUEUE_INSERT_TAIL(&stream->write_queue, &req->queue); 14381cb0ef41Sopenharmony_ci 14391cb0ef41Sopenharmony_ci /* If the queue was empty when this function began, we should attempt to 14401cb0ef41Sopenharmony_ci * do the write immediately. Otherwise start the write_watcher and wait 14411cb0ef41Sopenharmony_ci * for the fd to become writable. 14421cb0ef41Sopenharmony_ci */ 14431cb0ef41Sopenharmony_ci if (stream->connect_req) { 14441cb0ef41Sopenharmony_ci /* Still connecting, do nothing. */ 14451cb0ef41Sopenharmony_ci } 14461cb0ef41Sopenharmony_ci else if (empty_queue) { 14471cb0ef41Sopenharmony_ci uv__write(stream); 14481cb0ef41Sopenharmony_ci } 14491cb0ef41Sopenharmony_ci else { 14501cb0ef41Sopenharmony_ci /* 14511cb0ef41Sopenharmony_ci * blocking streams should never have anything in the queue. 14521cb0ef41Sopenharmony_ci * if this assert fires then somehow the blocking stream isn't being 14531cb0ef41Sopenharmony_ci * sufficiently flushed in uv__write. 14541cb0ef41Sopenharmony_ci */ 14551cb0ef41Sopenharmony_ci assert(!(stream->flags & UV_HANDLE_BLOCKING_WRITES)); 14561cb0ef41Sopenharmony_ci uv__io_start(stream->loop, &stream->io_watcher, POLLOUT); 14571cb0ef41Sopenharmony_ci uv__stream_osx_interrupt_select(stream); 14581cb0ef41Sopenharmony_ci } 14591cb0ef41Sopenharmony_ci 14601cb0ef41Sopenharmony_ci return 0; 14611cb0ef41Sopenharmony_ci} 14621cb0ef41Sopenharmony_ci 14631cb0ef41Sopenharmony_ci 14641cb0ef41Sopenharmony_ci/* The buffers to be written must remain valid until the callback is called. 14651cb0ef41Sopenharmony_ci * This is not required for the uv_buf_t array. 14661cb0ef41Sopenharmony_ci */ 14671cb0ef41Sopenharmony_ciint uv_write(uv_write_t* req, 14681cb0ef41Sopenharmony_ci uv_stream_t* handle, 14691cb0ef41Sopenharmony_ci const uv_buf_t bufs[], 14701cb0ef41Sopenharmony_ci unsigned int nbufs, 14711cb0ef41Sopenharmony_ci uv_write_cb cb) { 14721cb0ef41Sopenharmony_ci return uv_write2(req, handle, bufs, nbufs, NULL, cb); 14731cb0ef41Sopenharmony_ci} 14741cb0ef41Sopenharmony_ci 14751cb0ef41Sopenharmony_ci 14761cb0ef41Sopenharmony_ciint uv_try_write(uv_stream_t* stream, 14771cb0ef41Sopenharmony_ci const uv_buf_t bufs[], 14781cb0ef41Sopenharmony_ci unsigned int nbufs) { 14791cb0ef41Sopenharmony_ci return uv_try_write2(stream, bufs, nbufs, NULL); 14801cb0ef41Sopenharmony_ci} 14811cb0ef41Sopenharmony_ci 14821cb0ef41Sopenharmony_ci 14831cb0ef41Sopenharmony_ciint uv_try_write2(uv_stream_t* stream, 14841cb0ef41Sopenharmony_ci const uv_buf_t bufs[], 14851cb0ef41Sopenharmony_ci unsigned int nbufs, 14861cb0ef41Sopenharmony_ci uv_stream_t* send_handle) { 14871cb0ef41Sopenharmony_ci int err; 14881cb0ef41Sopenharmony_ci 14891cb0ef41Sopenharmony_ci /* Connecting or already writing some data */ 14901cb0ef41Sopenharmony_ci if (stream->connect_req != NULL || stream->write_queue_size != 0) 14911cb0ef41Sopenharmony_ci return UV_EAGAIN; 14921cb0ef41Sopenharmony_ci 14931cb0ef41Sopenharmony_ci err = uv__check_before_write(stream, nbufs, NULL); 14941cb0ef41Sopenharmony_ci if (err < 0) 14951cb0ef41Sopenharmony_ci return err; 14961cb0ef41Sopenharmony_ci 14971cb0ef41Sopenharmony_ci return uv__try_write(stream, bufs, nbufs, send_handle); 14981cb0ef41Sopenharmony_ci} 14991cb0ef41Sopenharmony_ci 15001cb0ef41Sopenharmony_ci 15011cb0ef41Sopenharmony_ciint uv__read_start(uv_stream_t* stream, 15021cb0ef41Sopenharmony_ci uv_alloc_cb alloc_cb, 15031cb0ef41Sopenharmony_ci uv_read_cb read_cb) { 15041cb0ef41Sopenharmony_ci assert(stream->type == UV_TCP || stream->type == UV_NAMED_PIPE || 15051cb0ef41Sopenharmony_ci stream->type == UV_TTY); 15061cb0ef41Sopenharmony_ci 15071cb0ef41Sopenharmony_ci /* The UV_HANDLE_READING flag is irrelevant of the state of the stream - it 15081cb0ef41Sopenharmony_ci * just expresses the desired state of the user. */ 15091cb0ef41Sopenharmony_ci stream->flags |= UV_HANDLE_READING; 15101cb0ef41Sopenharmony_ci stream->flags &= ~UV_HANDLE_READ_EOF; 15111cb0ef41Sopenharmony_ci 15121cb0ef41Sopenharmony_ci /* TODO: try to do the read inline? */ 15131cb0ef41Sopenharmony_ci assert(uv__stream_fd(stream) >= 0); 15141cb0ef41Sopenharmony_ci assert(alloc_cb); 15151cb0ef41Sopenharmony_ci 15161cb0ef41Sopenharmony_ci stream->read_cb = read_cb; 15171cb0ef41Sopenharmony_ci stream->alloc_cb = alloc_cb; 15181cb0ef41Sopenharmony_ci 15191cb0ef41Sopenharmony_ci uv__io_start(stream->loop, &stream->io_watcher, POLLIN); 15201cb0ef41Sopenharmony_ci uv__handle_start(stream); 15211cb0ef41Sopenharmony_ci uv__stream_osx_interrupt_select(stream); 15221cb0ef41Sopenharmony_ci 15231cb0ef41Sopenharmony_ci return 0; 15241cb0ef41Sopenharmony_ci} 15251cb0ef41Sopenharmony_ci 15261cb0ef41Sopenharmony_ci 15271cb0ef41Sopenharmony_ciint uv_read_stop(uv_stream_t* stream) { 15281cb0ef41Sopenharmony_ci if (!(stream->flags & UV_HANDLE_READING)) 15291cb0ef41Sopenharmony_ci return 0; 15301cb0ef41Sopenharmony_ci 15311cb0ef41Sopenharmony_ci stream->flags &= ~UV_HANDLE_READING; 15321cb0ef41Sopenharmony_ci uv__io_stop(stream->loop, &stream->io_watcher, POLLIN); 15331cb0ef41Sopenharmony_ci uv__handle_stop(stream); 15341cb0ef41Sopenharmony_ci uv__stream_osx_interrupt_select(stream); 15351cb0ef41Sopenharmony_ci 15361cb0ef41Sopenharmony_ci stream->read_cb = NULL; 15371cb0ef41Sopenharmony_ci stream->alloc_cb = NULL; 15381cb0ef41Sopenharmony_ci return 0; 15391cb0ef41Sopenharmony_ci} 15401cb0ef41Sopenharmony_ci 15411cb0ef41Sopenharmony_ci 15421cb0ef41Sopenharmony_ciint uv_is_readable(const uv_stream_t* stream) { 15431cb0ef41Sopenharmony_ci return !!(stream->flags & UV_HANDLE_READABLE); 15441cb0ef41Sopenharmony_ci} 15451cb0ef41Sopenharmony_ci 15461cb0ef41Sopenharmony_ci 15471cb0ef41Sopenharmony_ciint uv_is_writable(const uv_stream_t* stream) { 15481cb0ef41Sopenharmony_ci return !!(stream->flags & UV_HANDLE_WRITABLE); 15491cb0ef41Sopenharmony_ci} 15501cb0ef41Sopenharmony_ci 15511cb0ef41Sopenharmony_ci 15521cb0ef41Sopenharmony_ci#if defined(__APPLE__) 15531cb0ef41Sopenharmony_ciint uv___stream_fd(const uv_stream_t* handle) { 15541cb0ef41Sopenharmony_ci const uv__stream_select_t* s; 15551cb0ef41Sopenharmony_ci 15561cb0ef41Sopenharmony_ci assert(handle->type == UV_TCP || 15571cb0ef41Sopenharmony_ci handle->type == UV_TTY || 15581cb0ef41Sopenharmony_ci handle->type == UV_NAMED_PIPE); 15591cb0ef41Sopenharmony_ci 15601cb0ef41Sopenharmony_ci s = handle->select; 15611cb0ef41Sopenharmony_ci if (s != NULL) 15621cb0ef41Sopenharmony_ci return s->fd; 15631cb0ef41Sopenharmony_ci 15641cb0ef41Sopenharmony_ci return handle->io_watcher.fd; 15651cb0ef41Sopenharmony_ci} 15661cb0ef41Sopenharmony_ci#endif /* defined(__APPLE__) */ 15671cb0ef41Sopenharmony_ci 15681cb0ef41Sopenharmony_ci 15691cb0ef41Sopenharmony_civoid uv__stream_close(uv_stream_t* handle) { 15701cb0ef41Sopenharmony_ci unsigned int i; 15711cb0ef41Sopenharmony_ci uv__stream_queued_fds_t* queued_fds; 15721cb0ef41Sopenharmony_ci 15731cb0ef41Sopenharmony_ci#if defined(__APPLE__) 15741cb0ef41Sopenharmony_ci /* Terminate select loop first */ 15751cb0ef41Sopenharmony_ci if (handle->select != NULL) { 15761cb0ef41Sopenharmony_ci uv__stream_select_t* s; 15771cb0ef41Sopenharmony_ci 15781cb0ef41Sopenharmony_ci s = handle->select; 15791cb0ef41Sopenharmony_ci 15801cb0ef41Sopenharmony_ci uv_sem_post(&s->close_sem); 15811cb0ef41Sopenharmony_ci uv_sem_post(&s->async_sem); 15821cb0ef41Sopenharmony_ci uv__stream_osx_interrupt_select(handle); 15831cb0ef41Sopenharmony_ci uv_thread_join(&s->thread); 15841cb0ef41Sopenharmony_ci uv_sem_destroy(&s->close_sem); 15851cb0ef41Sopenharmony_ci uv_sem_destroy(&s->async_sem); 15861cb0ef41Sopenharmony_ci uv__close(s->fake_fd); 15871cb0ef41Sopenharmony_ci uv__close(s->int_fd); 15881cb0ef41Sopenharmony_ci uv_close((uv_handle_t*) &s->async, uv__stream_osx_cb_close); 15891cb0ef41Sopenharmony_ci 15901cb0ef41Sopenharmony_ci handle->select = NULL; 15911cb0ef41Sopenharmony_ci } 15921cb0ef41Sopenharmony_ci#endif /* defined(__APPLE__) */ 15931cb0ef41Sopenharmony_ci 15941cb0ef41Sopenharmony_ci uv__io_close(handle->loop, &handle->io_watcher); 15951cb0ef41Sopenharmony_ci uv_read_stop(handle); 15961cb0ef41Sopenharmony_ci uv__handle_stop(handle); 15971cb0ef41Sopenharmony_ci handle->flags &= ~(UV_HANDLE_READABLE | UV_HANDLE_WRITABLE); 15981cb0ef41Sopenharmony_ci 15991cb0ef41Sopenharmony_ci if (handle->io_watcher.fd != -1) { 16001cb0ef41Sopenharmony_ci /* Don't close stdio file descriptors. Nothing good comes from it. */ 16011cb0ef41Sopenharmony_ci if (handle->io_watcher.fd > STDERR_FILENO) 16021cb0ef41Sopenharmony_ci uv__close(handle->io_watcher.fd); 16031cb0ef41Sopenharmony_ci handle->io_watcher.fd = -1; 16041cb0ef41Sopenharmony_ci } 16051cb0ef41Sopenharmony_ci 16061cb0ef41Sopenharmony_ci if (handle->accepted_fd != -1) { 16071cb0ef41Sopenharmony_ci uv__close(handle->accepted_fd); 16081cb0ef41Sopenharmony_ci handle->accepted_fd = -1; 16091cb0ef41Sopenharmony_ci } 16101cb0ef41Sopenharmony_ci 16111cb0ef41Sopenharmony_ci /* Close all queued fds */ 16121cb0ef41Sopenharmony_ci if (handle->queued_fds != NULL) { 16131cb0ef41Sopenharmony_ci queued_fds = handle->queued_fds; 16141cb0ef41Sopenharmony_ci for (i = 0; i < queued_fds->offset; i++) 16151cb0ef41Sopenharmony_ci uv__close(queued_fds->fds[i]); 16161cb0ef41Sopenharmony_ci uv__free(handle->queued_fds); 16171cb0ef41Sopenharmony_ci handle->queued_fds = NULL; 16181cb0ef41Sopenharmony_ci } 16191cb0ef41Sopenharmony_ci 16201cb0ef41Sopenharmony_ci assert(!uv__io_active(&handle->io_watcher, POLLIN | POLLOUT)); 16211cb0ef41Sopenharmony_ci} 16221cb0ef41Sopenharmony_ci 16231cb0ef41Sopenharmony_ci 16241cb0ef41Sopenharmony_ciint uv_stream_set_blocking(uv_stream_t* handle, int blocking) { 16251cb0ef41Sopenharmony_ci /* Don't need to check the file descriptor, uv__nonblock() 16261cb0ef41Sopenharmony_ci * will fail with EBADF if it's not valid. 16271cb0ef41Sopenharmony_ci */ 16281cb0ef41Sopenharmony_ci return uv__nonblock(uv__stream_fd(handle), !blocking); 16291cb0ef41Sopenharmony_ci} 1630