Blame src/unix/tcp.c

Packit Service 7c31a4
/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
Packit Service 7c31a4
 *
Packit Service 7c31a4
 * Permission is hereby granted, free of charge, to any person obtaining a copy
Packit Service 7c31a4
 * of this software and associated documentation files (the "Software"), to
Packit Service 7c31a4
 * deal in the Software without restriction, including without limitation the
Packit Service 7c31a4
 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
Packit Service 7c31a4
 * sell copies of the Software, and to permit persons to whom the Software is
Packit Service 7c31a4
 * furnished to do so, subject to the following conditions:
Packit Service 7c31a4
 *
Packit Service 7c31a4
 * The above copyright notice and this permission notice shall be included in
Packit Service 7c31a4
 * all copies or substantial portions of the Software.
Packit Service 7c31a4
 *
Packit Service 7c31a4
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
Packit Service 7c31a4
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
Packit Service 7c31a4
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
Packit Service 7c31a4
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
Packit Service 7c31a4
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
Packit Service 7c31a4
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
Packit Service 7c31a4
 * IN THE SOFTWARE.
Packit Service 7c31a4
 */
Packit Service 7c31a4
Packit Service 7c31a4
#include "uv.h"
Packit Service 7c31a4
#include "internal.h"
Packit Service 7c31a4
Packit Service 7c31a4
#include <stdlib.h>
Packit Service 7c31a4
#include <unistd.h>
Packit Service 7c31a4
#include <assert.h>
Packit Service 7c31a4
#include <errno.h>
Packit Service 7c31a4
Packit Service 7c31a4
Packit Service 7c31a4
static int new_socket(uv_tcp_t* handle, int domain, unsigned long flags) {
Packit Service 7c31a4
  struct sockaddr_storage saddr;
Packit Service 7c31a4
  socklen_t slen;
Packit Service 7c31a4
  int sockfd;
Packit Service 7c31a4
  int err;
Packit Service 7c31a4
Packit Service 7c31a4
  err = uv__socket(domain, SOCK_STREAM, 0);
Packit Service 7c31a4
  if (err < 0)
Packit Service 7c31a4
    return err;
Packit Service 7c31a4
  sockfd = err;
Packit Service 7c31a4
Packit Service 7c31a4
  err = uv__stream_open((uv_stream_t*) handle, sockfd, flags);
Packit Service 7c31a4
  if (err) {
Packit Service 7c31a4
    uv__close(sockfd);
Packit Service 7c31a4
    return err;
Packit Service 7c31a4
  }
Packit Service 7c31a4
Packit Service 7c31a4
  if (flags & UV_HANDLE_BOUND) {
Packit Service 7c31a4
    /* Bind this new socket to an arbitrary port */
Packit Service 7c31a4
    slen = sizeof(saddr);
Packit Service 7c31a4
    memset(&saddr, 0, sizeof(saddr));
Packit Service 7c31a4
    if (getsockname(uv__stream_fd(handle), (struct sockaddr*) &saddr, &slen)) {
Packit Service 7c31a4
      uv__close(sockfd);
Packit Service 7c31a4
      return UV__ERR(errno);
Packit Service 7c31a4
    }
Packit Service 7c31a4
Packit Service 7c31a4
    if (bind(uv__stream_fd(handle), (struct sockaddr*) &saddr, slen)) {
Packit Service 7c31a4
      uv__close(sockfd);
Packit Service 7c31a4
      return UV__ERR(errno);
Packit Service 7c31a4
    }
Packit Service 7c31a4
  }
Packit Service 7c31a4
Packit Service 7c31a4
  return 0;
Packit Service 7c31a4
}
Packit Service 7c31a4
Packit Service 7c31a4
Packit Service 7c31a4
static int maybe_new_socket(uv_tcp_t* handle, int domain, unsigned long flags) {
Packit Service 7c31a4
  struct sockaddr_storage saddr;
Packit Service 7c31a4
  socklen_t slen;
Packit Service 7c31a4
Packit Service 7c31a4
  if (domain == AF_UNSPEC) {
Packit Service 7c31a4
    handle->flags |= flags;
Packit Service 7c31a4
    return 0;
Packit Service 7c31a4
  }
Packit Service 7c31a4
Packit Service 7c31a4
  if (uv__stream_fd(handle) != -1) {
Packit Service 7c31a4
Packit Service 7c31a4
    if (flags & UV_HANDLE_BOUND) {
Packit Service 7c31a4
Packit Service 7c31a4
      if (handle->flags & UV_HANDLE_BOUND) {
Packit Service 7c31a4
        /* It is already bound to a port. */
Packit Service 7c31a4
        handle->flags |= flags;
Packit Service 7c31a4
        return 0;
Packit Service 7c31a4
      }
Packit Service 7c31a4
Packit Service 7c31a4
      /* Query to see if tcp socket is bound. */
Packit Service 7c31a4
      slen = sizeof(saddr);
Packit Service 7c31a4
      memset(&saddr, 0, sizeof(saddr));
Packit Service 7c31a4
      if (getsockname(uv__stream_fd(handle), (struct sockaddr*) &saddr, &slen))
Packit Service 7c31a4
        return UV__ERR(errno);
Packit Service 7c31a4
Packit Service 7c31a4
      if ((saddr.ss_family == AF_INET6 &&
Packit Service 7c31a4
          ((struct sockaddr_in6*) &saddr)->sin6_port != 0) ||
Packit Service 7c31a4
          (saddr.ss_family == AF_INET &&
Packit Service 7c31a4
          ((struct sockaddr_in*) &saddr)->sin_port != 0)) {
Packit Service 7c31a4
        /* Handle is already bound to a port. */
Packit Service 7c31a4
        handle->flags |= flags;
Packit Service 7c31a4
        return 0;
Packit Service 7c31a4
      }
Packit Service 7c31a4
Packit Service 7c31a4
      /* Bind to arbitrary port */
Packit Service 7c31a4
      if (bind(uv__stream_fd(handle), (struct sockaddr*) &saddr, slen))
Packit Service 7c31a4
        return UV__ERR(errno);
Packit Service 7c31a4
    }
Packit Service 7c31a4
Packit Service 7c31a4
    handle->flags |= flags;
Packit Service 7c31a4
    return 0;
Packit Service 7c31a4
  }
Packit Service 7c31a4
Packit Service 7c31a4
  return new_socket(handle, domain, flags);
Packit Service 7c31a4
}
Packit Service 7c31a4
Packit Service 7c31a4
Packit Service 7c31a4
int uv_tcp_init_ex(uv_loop_t* loop, uv_tcp_t* tcp, unsigned int flags) {
Packit Service 7c31a4
  int domain;
Packit Service 7c31a4
Packit Service 7c31a4
  /* Use the lower 8 bits for the domain */
Packit Service 7c31a4
  domain = flags & 0xFF;
Packit Service 7c31a4
  if (domain != AF_INET && domain != AF_INET6 && domain != AF_UNSPEC)
Packit Service 7c31a4
    return UV_EINVAL;
Packit Service 7c31a4
Packit Service 7c31a4
  if (flags & ~0xFF)
Packit Service 7c31a4
    return UV_EINVAL;
Packit Service 7c31a4
Packit Service 7c31a4
  uv__stream_init(loop, (uv_stream_t*)tcp, UV_TCP);
Packit Service 7c31a4
Packit Service 7c31a4
  /* If anything fails beyond this point we need to remove the handle from
Packit Service 7c31a4
   * the handle queue, since it was added by uv__handle_init in uv_stream_init.
Packit Service 7c31a4
   */
Packit Service 7c31a4
Packit Service 7c31a4
  if (domain != AF_UNSPEC) {
Packit Service 7c31a4
    int err = maybe_new_socket(tcp, domain, 0);
Packit Service 7c31a4
    if (err) {
Packit Service 7c31a4
      QUEUE_REMOVE(&tcp->handle_queue);
Packit Service 7c31a4
      return err;
Packit Service 7c31a4
    }
Packit Service 7c31a4
  }
Packit Service 7c31a4
Packit Service 7c31a4
  return 0;
Packit Service 7c31a4
}
Packit Service 7c31a4
Packit Service 7c31a4
Packit Service 7c31a4
int uv_tcp_init(uv_loop_t* loop, uv_tcp_t* tcp) {
Packit Service 7c31a4
  return uv_tcp_init_ex(loop, tcp, AF_UNSPEC);
Packit Service 7c31a4
}
Packit Service 7c31a4
Packit Service 7c31a4
Packit Service 7c31a4
int uv__tcp_bind(uv_tcp_t* tcp,
Packit Service 7c31a4
                 const struct sockaddr* addr,
Packit Service 7c31a4
                 unsigned int addrlen,
Packit Service 7c31a4
                 unsigned int flags) {
Packit Service 7c31a4
  int err;
Packit Service 7c31a4
  int on;
Packit Service 7c31a4
Packit Service 7c31a4
  /* Cannot set IPv6-only mode on non-IPv6 socket. */
Packit Service 7c31a4
  if ((flags & UV_TCP_IPV6ONLY) && addr->sa_family != AF_INET6)
Packit Service 7c31a4
    return UV_EINVAL;
Packit Service 7c31a4
Packit Service 7c31a4
  err = maybe_new_socket(tcp, addr->sa_family, 0);
Packit Service 7c31a4
  if (err)
Packit Service 7c31a4
    return err;
Packit Service 7c31a4
Packit Service 7c31a4
  on = 1;
Packit Service 7c31a4
  if (setsockopt(tcp->io_watcher.fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)))
Packit Service 7c31a4
    return UV__ERR(errno);
Packit Service 7c31a4
Packit Service 7c31a4
#ifndef __OpenBSD__
Packit Service 7c31a4
#ifdef IPV6_V6ONLY
Packit Service 7c31a4
  if (addr->sa_family == AF_INET6) {
Packit Service 7c31a4
    on = (flags & UV_TCP_IPV6ONLY) != 0;
Packit Service 7c31a4
    if (setsockopt(tcp->io_watcher.fd,
Packit Service 7c31a4
                   IPPROTO_IPV6,
Packit Service 7c31a4
                   IPV6_V6ONLY,
Packit Service 7c31a4
                   &on,
Packit Service 7c31a4
                   sizeof on) == -1) {
Packit Service 7c31a4
#if defined(__MVS__)
Packit Service 7c31a4
      if (errno == EOPNOTSUPP)
Packit Service 7c31a4
        return UV_EINVAL;
Packit Service 7c31a4
#endif
Packit Service 7c31a4
      return UV__ERR(errno);
Packit Service 7c31a4
    }
Packit Service 7c31a4
  }
Packit Service 7c31a4
#endif
Packit Service 7c31a4
#endif
Packit Service 7c31a4
Packit Service 7c31a4
  errno = 0;
Packit Service 7c31a4
  if (bind(tcp->io_watcher.fd, addr, addrlen) && errno != EADDRINUSE) {
Packit Service 7c31a4
    if (errno == EAFNOSUPPORT)
Packit Service 7c31a4
      /* OSX, other BSDs and SunoS fail with EAFNOSUPPORT when binding a
Packit Service 7c31a4
       * socket created with AF_INET to an AF_INET6 address or vice versa. */
Packit Service 7c31a4
      return UV_EINVAL;
Packit Service 7c31a4
    return UV__ERR(errno);
Packit Service 7c31a4
  }
Packit Service 7c31a4
  tcp->delayed_error = UV__ERR(errno);
Packit Service 7c31a4
Packit Service 7c31a4
  tcp->flags |= UV_HANDLE_BOUND;
Packit Service 7c31a4
  if (addr->sa_family == AF_INET6)
Packit Service 7c31a4
    tcp->flags |= UV_HANDLE_IPV6;
Packit Service 7c31a4
Packit Service 7c31a4
  return 0;
Packit Service 7c31a4
}
Packit Service 7c31a4
Packit Service 7c31a4
Packit Service 7c31a4
int uv__tcp_connect(uv_connect_t* req,
Packit Service 7c31a4
                    uv_tcp_t* handle,
Packit Service 7c31a4
                    const struct sockaddr* addr,
Packit Service 7c31a4
                    unsigned int addrlen,
Packit Service 7c31a4
                    uv_connect_cb cb) {
Packit Service 7c31a4
  int err;
Packit Service 7c31a4
  int r;
Packit Service 7c31a4
Packit Service 7c31a4
  assert(handle->type == UV_TCP);
Packit Service 7c31a4
Packit Service 7c31a4
  if (handle->connect_req != NULL)
Packit Service 7c31a4
    return UV_EALREADY;  /* FIXME(bnoordhuis) UV_EINVAL or maybe UV_EBUSY. */
Packit Service 7c31a4
Packit Service 7c31a4
  err = maybe_new_socket(handle,
Packit Service 7c31a4
                         addr->sa_family,
Packit Service 7c31a4
                         UV_HANDLE_READABLE | UV_HANDLE_WRITABLE);
Packit Service 7c31a4
  if (err)
Packit Service 7c31a4
    return err;
Packit Service 7c31a4
Packit Service 7c31a4
  handle->delayed_error = 0;
Packit Service 7c31a4
Packit Service 7c31a4
  do {
Packit Service 7c31a4
    errno = 0;
Packit Service 7c31a4
    r = connect(uv__stream_fd(handle), addr, addrlen);
Packit Service 7c31a4
  } while (r == -1 && errno == EINTR);
Packit Service 7c31a4
Packit Service 7c31a4
  /* We not only check the return value, but also check the errno != 0.
Packit Service 7c31a4
   * Because in rare cases connect() will return -1 but the errno
Packit Service 7c31a4
   * is 0 (for example, on Android 4.3, OnePlus phone A0001_12_150227)
Packit Service 7c31a4
   * and actually the tcp three-way handshake is completed.
Packit Service 7c31a4
   */
Packit Service 7c31a4
  if (r == -1 && errno != 0) {
Packit Service 7c31a4
    if (errno == EINPROGRESS)
Packit Service 7c31a4
      ; /* not an error */
Packit Service 7c31a4
    else if (errno == ECONNREFUSED
Packit Service 7c31a4
#if defined(__OpenBSD__)
Packit Service 7c31a4
      || errno == EINVAL
Packit Service 7c31a4
#endif
Packit Service 7c31a4
      )
Packit Service 7c31a4
    /* If we get ECONNREFUSED (Solaris) or EINVAL (OpenBSD) wait until the
Packit Service 7c31a4
     * next tick to report the error. Solaris and OpenBSD wants to report
Packit Service 7c31a4
     * immediately -- other unixes want to wait.
Packit Service 7c31a4
     */
Packit Service 7c31a4
      handle->delayed_error = UV__ERR(ECONNREFUSED);
Packit Service 7c31a4
    else
Packit Service 7c31a4
      return UV__ERR(errno);
Packit Service 7c31a4
  }
Packit Service 7c31a4
Packit Service 7c31a4
  uv__req_init(handle->loop, req, UV_CONNECT);
Packit Service 7c31a4
  req->cb = cb;
Packit Service 7c31a4
  req->handle = (uv_stream_t*) handle;
Packit Service 7c31a4
  QUEUE_INIT(&req->queue);
Packit Service 7c31a4
  handle->connect_req = req;
Packit Service 7c31a4
Packit Service 7c31a4
  uv__io_start(handle->loop, &handle->io_watcher, POLLOUT);
Packit Service 7c31a4
Packit Service 7c31a4
  if (handle->delayed_error)
Packit Service 7c31a4
    uv__io_feed(handle->loop, &handle->io_watcher);
Packit Service 7c31a4
Packit Service 7c31a4
  return 0;
Packit Service 7c31a4
}
Packit Service 7c31a4
Packit Service 7c31a4
Packit Service 7c31a4
int uv_tcp_open(uv_tcp_t* handle, uv_os_sock_t sock) {
Packit Service 7c31a4
  int err;
Packit Service 7c31a4
Packit Service 7c31a4
  if (uv__fd_exists(handle->loop, sock))
Packit Service 7c31a4
    return UV_EEXIST;
Packit Service 7c31a4
Packit Service 7c31a4
  err = uv__nonblock(sock, 1);
Packit Service 7c31a4
  if (err)
Packit Service 7c31a4
    return err;
Packit Service 7c31a4
Packit Service 7c31a4
  return uv__stream_open((uv_stream_t*)handle,
Packit Service 7c31a4
                         sock,
Packit Service 7c31a4
                         UV_HANDLE_READABLE | UV_HANDLE_WRITABLE);
Packit Service 7c31a4
}
Packit Service 7c31a4
Packit Service 7c31a4
Packit Service 7c31a4
int uv_tcp_getsockname(const uv_tcp_t* handle,
Packit Service 7c31a4
                       struct sockaddr* name,
Packit Service 7c31a4
                       int* namelen) {
Packit Service 7c31a4
Packit Service 7c31a4
  if (handle->delayed_error)
Packit Service 7c31a4
    return handle->delayed_error;
Packit Service 7c31a4
Packit Service 7c31a4
  return uv__getsockpeername((const uv_handle_t*) handle,
Packit Service 7c31a4
                             getsockname,
Packit Service 7c31a4
                             name,
Packit Service 7c31a4
                             namelen);
Packit Service 7c31a4
}
Packit Service 7c31a4
Packit Service 7c31a4
Packit Service 7c31a4
int uv_tcp_getpeername(const uv_tcp_t* handle,
Packit Service 7c31a4
                       struct sockaddr* name,
Packit Service 7c31a4
                       int* namelen) {
Packit Service 7c31a4
Packit Service 7c31a4
  if (handle->delayed_error)
Packit Service 7c31a4
    return handle->delayed_error;
Packit Service 7c31a4
Packit Service 7c31a4
  return uv__getsockpeername((const uv_handle_t*) handle,
Packit Service 7c31a4
                             getpeername,
Packit Service 7c31a4
                             name,
Packit Service 7c31a4
                             namelen);
Packit Service 7c31a4
}
Packit Service 7c31a4
Packit Service 7c31a4
Packit Service 7c31a4
int uv_tcp_close_reset(uv_tcp_t* handle, uv_close_cb close_cb) {
Packit Service 7c31a4
  int fd;
Packit Service 7c31a4
  struct linger l = { 1, 0 };
Packit Service 7c31a4
Packit Service 7c31a4
  /* Disallow setting SO_LINGER to zero due to some platform inconsistencies */
Packit Service 7c31a4
  if (handle->flags & UV_HANDLE_SHUTTING)
Packit Service 7c31a4
    return UV_EINVAL;
Packit Service 7c31a4
Packit Service 7c31a4
  fd = uv__stream_fd(handle);
Packit Service 7c31a4
  if (0 != setsockopt(fd, SOL_SOCKET, SO_LINGER, &l, sizeof(l)))
Packit Service 7c31a4
    return UV__ERR(errno);
Packit Service 7c31a4
Packit Service 7c31a4
  uv_close((uv_handle_t*) handle, close_cb);
Packit Service 7c31a4
  return 0;
Packit Service 7c31a4
}
Packit Service 7c31a4
Packit Service 7c31a4
Packit Service 7c31a4
int uv_tcp_listen(uv_tcp_t* tcp, int backlog, uv_connection_cb cb) {
Packit Service e2ebee
  static int single_accept_cached = -1;
Packit Service 7c31a4
  unsigned long flags;
Packit Service e2ebee
  int single_accept;
Packit Service 7c31a4
  int err;
Packit Service 7c31a4
Packit Service 7c31a4
  if (tcp->delayed_error)
Packit Service 7c31a4
    return tcp->delayed_error;
Packit Service 7c31a4
Packit Service e2ebee
  single_accept = uv__load_relaxed(&single_accept_cached);
Packit Service 7c31a4
  if (single_accept == -1) {
Packit Service 7c31a4
    const char* val = getenv("UV_TCP_SINGLE_ACCEPT");
Packit Service 7c31a4
    single_accept = (val != NULL && atoi(val) != 0);  /* Off by default. */
Packit Service e2ebee
    uv__store_relaxed(&single_accept_cached, single_accept);
Packit Service 7c31a4
  }
Packit Service 7c31a4
Packit Service 7c31a4
  if (single_accept)
Packit Service 7c31a4
    tcp->flags |= UV_HANDLE_TCP_SINGLE_ACCEPT;
Packit Service 7c31a4
Packit Service 7c31a4
  flags = 0;
Packit Service 7c31a4
#if defined(__MVS__)
Packit Service 7c31a4
  /* on zOS the listen call does not bind automatically
Packit Service 7c31a4
     if the socket is unbound. Hence the manual binding to
Packit Service 7c31a4
     an arbitrary port is required to be done manually
Packit Service 7c31a4
  */
Packit Service 7c31a4
  flags |= UV_HANDLE_BOUND;
Packit Service 7c31a4
#endif
Packit Service 7c31a4
  err = maybe_new_socket(tcp, AF_INET, flags);
Packit Service 7c31a4
  if (err)
Packit Service 7c31a4
    return err;
Packit Service 7c31a4
Packit Service 7c31a4
  if (listen(tcp->io_watcher.fd, backlog))
Packit Service 7c31a4
    return UV__ERR(errno);
Packit Service 7c31a4
Packit Service 7c31a4
  tcp->connection_cb = cb;
Packit Service 7c31a4
  tcp->flags |= UV_HANDLE_BOUND;
Packit Service 7c31a4
Packit Service 7c31a4
  /* Start listening for connections. */
Packit Service 7c31a4
  tcp->io_watcher.cb = uv__server_io;
Packit Service 7c31a4
  uv__io_start(tcp->loop, &tcp->io_watcher, POLLIN);
Packit Service 7c31a4
Packit Service 7c31a4
  return 0;
Packit Service 7c31a4
}
Packit Service 7c31a4
Packit Service 7c31a4
Packit Service 7c31a4
int uv__tcp_nodelay(int fd, int on) {
Packit Service 7c31a4
  if (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &on, sizeof(on)))
Packit Service 7c31a4
    return UV__ERR(errno);
Packit Service 7c31a4
  return 0;
Packit Service 7c31a4
}
Packit Service 7c31a4
Packit Service 7c31a4
Packit Service 7c31a4
int uv__tcp_keepalive(int fd, int on, unsigned int delay) {
Packit Service 7c31a4
  if (setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, &on, sizeof(on)))
Packit Service 7c31a4
    return UV__ERR(errno);
Packit Service 7c31a4
Packit Service 7c31a4
#ifdef TCP_KEEPIDLE
Packit Service 7c31a4
  if (on) {
Packit Service 7c31a4
    int intvl = 1;  /*  1 second; same as default on Win32 */
Packit Service 7c31a4
    int cnt = 10;  /* 10 retries; same as hardcoded on Win32 */
Packit Service 7c31a4
    if (setsockopt(fd, IPPROTO_TCP, TCP_KEEPIDLE, &delay, sizeof(delay)))
Packit Service 7c31a4
      return UV__ERR(errno);
Packit Service 7c31a4
    if (setsockopt(fd, IPPROTO_TCP, TCP_KEEPINTVL, &intvl, sizeof(intvl)))
Packit Service 7c31a4
      return UV__ERR(errno);
Packit Service 7c31a4
    if (setsockopt(fd, IPPROTO_TCP, TCP_KEEPCNT, &cnt, sizeof(cnt)))
Packit Service 7c31a4
      return UV__ERR(errno);
Packit Service 7c31a4
  }
Packit Service 7c31a4
#endif
Packit Service 7c31a4
Packit Service 7c31a4
  /* Solaris/SmartOS, if you don't support keep-alive,
Packit Service 7c31a4
   * then don't advertise it in your system headers...
Packit Service 7c31a4
   */
Packit Service 7c31a4
  /* FIXME(bnoordhuis) That's possibly because sizeof(delay) should be 1. */
Packit Service 7c31a4
#if defined(TCP_KEEPALIVE) && !defined(__sun)
Packit Service 7c31a4
  if (on && setsockopt(fd, IPPROTO_TCP, TCP_KEEPALIVE, &delay, sizeof(delay)))
Packit Service 7c31a4
    return UV__ERR(errno);
Packit Service 7c31a4
#endif
Packit Service 7c31a4
Packit Service 7c31a4
  return 0;
Packit Service 7c31a4
}
Packit Service 7c31a4
Packit Service 7c31a4
Packit Service 7c31a4
int uv_tcp_nodelay(uv_tcp_t* handle, int on) {
Packit Service 7c31a4
  int err;
Packit Service 7c31a4
Packit Service 7c31a4
  if (uv__stream_fd(handle) != -1) {
Packit Service 7c31a4
    err = uv__tcp_nodelay(uv__stream_fd(handle), on);
Packit Service 7c31a4
    if (err)
Packit Service 7c31a4
      return err;
Packit Service 7c31a4
  }
Packit Service 7c31a4
Packit Service 7c31a4
  if (on)
Packit Service 7c31a4
    handle->flags |= UV_HANDLE_TCP_NODELAY;
Packit Service 7c31a4
  else
Packit Service 7c31a4
    handle->flags &= ~UV_HANDLE_TCP_NODELAY;
Packit Service 7c31a4
Packit Service 7c31a4
  return 0;
Packit Service 7c31a4
}
Packit Service 7c31a4
Packit Service 7c31a4
Packit Service 7c31a4
int uv_tcp_keepalive(uv_tcp_t* handle, int on, unsigned int delay) {
Packit Service 7c31a4
  int err;
Packit Service 7c31a4
Packit Service 7c31a4
  if (uv__stream_fd(handle) != -1) {
Packit Service 7c31a4
    err =uv__tcp_keepalive(uv__stream_fd(handle), on, delay);
Packit Service 7c31a4
    if (err)
Packit Service 7c31a4
      return err;
Packit Service 7c31a4
  }
Packit Service 7c31a4
Packit Service 7c31a4
  if (on)
Packit Service 7c31a4
    handle->flags |= UV_HANDLE_TCP_KEEPALIVE;
Packit Service 7c31a4
  else
Packit Service 7c31a4
    handle->flags &= ~UV_HANDLE_TCP_KEEPALIVE;
Packit Service 7c31a4
Packit Service 7c31a4
  /* TODO Store delay if uv__stream_fd(handle) == -1 but don't want to enlarge
Packit Service 7c31a4
   *      uv_tcp_t with an int that's almost never used...
Packit Service 7c31a4
   */
Packit Service 7c31a4
Packit Service 7c31a4
  return 0;
Packit Service 7c31a4
}
Packit Service 7c31a4
Packit Service 7c31a4
Packit Service 7c31a4
int uv_tcp_simultaneous_accepts(uv_tcp_t* handle, int enable) {
Packit Service 7c31a4
  if (enable)
Packit Service 7c31a4
    handle->flags &= ~UV_HANDLE_TCP_SINGLE_ACCEPT;
Packit Service 7c31a4
  else
Packit Service 7c31a4
    handle->flags |= UV_HANDLE_TCP_SINGLE_ACCEPT;
Packit Service 7c31a4
  return 0;
Packit Service 7c31a4
}
Packit Service 7c31a4
Packit Service 7c31a4
Packit Service 7c31a4
void uv__tcp_close(uv_tcp_t* handle) {
Packit Service 7c31a4
  uv__stream_close((uv_stream_t*)handle);
Packit Service 7c31a4
}