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