ext/libuv/src/unix/tcp.c in libuv-4.0.0 vs ext/libuv/src/unix/tcp.c in libuv-4.0.1
- old
+ new
@@ -26,19 +26,16 @@
#include <unistd.h>
#include <assert.h>
#include <errno.h>
-static int maybe_new_socket(uv_tcp_t* handle, int domain, int flags) {
+static int new_socket(uv_tcp_t* handle, int domain, unsigned long flags) {
+ struct sockaddr_storage saddr;
+ socklen_t slen;
int sockfd;
int err;
- if (domain == AF_UNSPEC || uv__stream_fd(handle) != -1) {
- handle->flags |= flags;
- return 0;
- }
-
err = uv__socket(domain, SOCK_STREAM, 0);
if (err < 0)
return err;
sockfd = err;
@@ -46,24 +43,86 @@
if (err) {
uv__close(sockfd);
return err;
}
+ if (flags & UV_HANDLE_BOUND) {
+ /* Bind this new socket to an arbitrary port */
+ slen = sizeof(saddr);
+ memset(&saddr, 0, sizeof(saddr));
+ if (getsockname(uv__stream_fd(handle), (struct sockaddr*) &saddr, &slen)) {
+ uv__close(sockfd);
+ return UV__ERR(errno);
+ }
+
+ if (bind(uv__stream_fd(handle), (struct sockaddr*) &saddr, slen)) {
+ uv__close(sockfd);
+ return UV__ERR(errno);
+ }
+ }
+
return 0;
}
+static int maybe_new_socket(uv_tcp_t* handle, int domain, unsigned long flags) {
+ struct sockaddr_storage saddr;
+ socklen_t slen;
+
+ if (domain == AF_UNSPEC) {
+ handle->flags |= flags;
+ return 0;
+ }
+
+ if (uv__stream_fd(handle) != -1) {
+
+ if (flags & UV_HANDLE_BOUND) {
+
+ if (handle->flags & UV_HANDLE_BOUND) {
+ /* It is already bound to a port. */
+ handle->flags |= flags;
+ return 0;
+ }
+
+ /* Query to see if tcp socket is bound. */
+ slen = sizeof(saddr);
+ memset(&saddr, 0, sizeof(saddr));
+ if (getsockname(uv__stream_fd(handle), (struct sockaddr*) &saddr, &slen))
+ return UV__ERR(errno);
+
+ if ((saddr.ss_family == AF_INET6 &&
+ ((struct sockaddr_in6*) &saddr)->sin6_port != 0) ||
+ (saddr.ss_family == AF_INET &&
+ ((struct sockaddr_in*) &saddr)->sin_port != 0)) {
+ /* Handle is already bound to a port. */
+ handle->flags |= flags;
+ return 0;
+ }
+
+ /* Bind to arbitrary port */
+ if (bind(uv__stream_fd(handle), (struct sockaddr*) &saddr, slen))
+ return UV__ERR(errno);
+ }
+
+ handle->flags |= flags;
+ return 0;
+ }
+
+ return new_socket(handle, domain, flags);
+}
+
+
int uv_tcp_init_ex(uv_loop_t* loop, uv_tcp_t* tcp, unsigned int flags) {
int domain;
/* Use the lower 8 bits for the domain */
domain = flags & 0xFF;
if (domain != AF_INET && domain != AF_INET6 && domain != AF_UNSPEC)
- return -EINVAL;
+ return UV_EINVAL;
if (flags & ~0xFF)
- return -EINVAL;
+ return UV_EINVAL;
uv__stream_init(loop, (uv_stream_t*)tcp, UV_TCP);
/* If anything fails beyond this point we need to remove the handle from
* the handle queue, since it was added by uv__handle_init in uv_stream_init.
@@ -93,48 +152,48 @@
int err;
int on;
/* Cannot set IPv6-only mode on non-IPv6 socket. */
if ((flags & UV_TCP_IPV6ONLY) && addr->sa_family != AF_INET6)
- return -EINVAL;
+ return UV_EINVAL;
- err = maybe_new_socket(tcp,
- addr->sa_family,
- UV_STREAM_READABLE | UV_STREAM_WRITABLE);
+ err = maybe_new_socket(tcp, addr->sa_family, 0);
if (err)
return err;
on = 1;
if (setsockopt(tcp->io_watcher.fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)))
- return -errno;
+ return UV__ERR(errno);
+#ifndef __OpenBSD__
#ifdef IPV6_V6ONLY
if (addr->sa_family == AF_INET6) {
on = (flags & UV_TCP_IPV6ONLY) != 0;
if (setsockopt(tcp->io_watcher.fd,
IPPROTO_IPV6,
IPV6_V6ONLY,
&on,
sizeof on) == -1) {
#if defined(__MVS__)
if (errno == EOPNOTSUPP)
- return -EINVAL;
+ return UV_EINVAL;
#endif
- return -errno;
+ return UV__ERR(errno);
}
}
#endif
+#endif
errno = 0;
if (bind(tcp->io_watcher.fd, addr, addrlen) && errno != EADDRINUSE) {
if (errno == EAFNOSUPPORT)
/* OSX, other BSDs and SunoS fail with EAFNOSUPPORT when binding a
* socket created with AF_INET to an AF_INET6 address or vice versa. */
- return -EINVAL;
- return -errno;
+ return UV_EINVAL;
+ return UV__ERR(errno);
}
- tcp->delayed_error = -errno;
+ tcp->delayed_error = UV__ERR(errno);
tcp->flags |= UV_HANDLE_BOUND;
if (addr->sa_family == AF_INET6)
tcp->flags |= UV_HANDLE_IPV6;
@@ -151,11 +210,11 @@
int r;
assert(handle->type == UV_TCP);
if (handle->connect_req != NULL)
- return -EALREADY; /* FIXME(bnoordhuis) -EINVAL or maybe -EBUSY. */
+ return UV_EALREADY; /* FIXME(bnoordhuis) UV_EINVAL or maybe UV_EBUSY. */
err = maybe_new_socket(handle,
addr->sa_family,
UV_STREAM_READABLE | UV_STREAM_WRITABLE);
if (err)
@@ -179,13 +238,13 @@
else if (errno == ECONNREFUSED)
/* If we get a ECONNREFUSED wait until the next tick to report the
* error. Solaris wants to report immediately--other unixes want to
* wait.
*/
- handle->delayed_error = -errno;
+ handle->delayed_error = UV__ERR(errno);
else
- return -errno;
+ return UV__ERR(errno);
}
uv__req_init(handle->loop, req, UV_CONNECT);
req->cb = cb;
req->handle = (uv_stream_t*) handle;
@@ -221,17 +280,17 @@
if (handle->delayed_error)
return handle->delayed_error;
if (uv__stream_fd(handle) < 0)
- return -EINVAL; /* FIXME(bnoordhuis) -EBADF */
+ return UV_EINVAL; /* FIXME(bnoordhuis) UV_EBADF */
/* sizeof(socklen_t) != sizeof(int) on some systems. */
socklen = (socklen_t) *namelen;
if (getsockname(uv__stream_fd(handle), name, &socklen))
- return -errno;
+ return UV__ERR(errno);
*namelen = (int) socklen;
return 0;
}
@@ -243,25 +302,26 @@
if (handle->delayed_error)
return handle->delayed_error;
if (uv__stream_fd(handle) < 0)
- return -EINVAL; /* FIXME(bnoordhuis) -EBADF */
+ return UV_EINVAL; /* FIXME(bnoordhuis) UV_EBADF */
/* sizeof(socklen_t) != sizeof(int) on some systems. */
socklen = (socklen_t) *namelen;
if (getpeername(uv__stream_fd(handle), name, &socklen))
- return -errno;
+ return UV__ERR(errno);
*namelen = (int) socklen;
return 0;
}
int uv_tcp_listen(uv_tcp_t* tcp, int backlog, uv_connection_cb cb) {
static int single_accept = -1;
+ unsigned long flags;
int err;
if (tcp->delayed_error)
return tcp->delayed_error;
@@ -271,37 +331,24 @@
}
if (single_accept)
tcp->flags |= UV_TCP_SINGLE_ACCEPT;
- err = maybe_new_socket(tcp, AF_INET, UV_STREAM_READABLE);
- if (err)
- return err;
-
-#ifdef __MVS__
+ flags = 0;
+#if defined(__MVS__)
/* on zOS the listen call does not bind automatically
if the socket is unbound. Hence the manual binding to
an arbitrary port is required to be done manually
*/
-
- if (!(tcp->flags & UV_HANDLE_BOUND)) {
- struct sockaddr_storage saddr;
- socklen_t slen = sizeof(saddr);
- memset(&saddr, 0, sizeof(saddr));
-
- if (getsockname(tcp->io_watcher.fd, (struct sockaddr*) &saddr, &slen))
- return -errno;
-
- if (bind(tcp->io_watcher.fd, (struct sockaddr*) &saddr, slen))
- return -errno;
-
- tcp->flags |= UV_HANDLE_BOUND;
- }
+ flags |= UV_HANDLE_BOUND;
#endif
+ err = maybe_new_socket(tcp, AF_INET, flags);
+ if (err)
+ return err;
if (listen(tcp->io_watcher.fd, backlog))
- return -errno;
+ return UV__ERR(errno);
tcp->connection_cb = cb;
tcp->flags |= UV_HANDLE_BOUND;
/* Start listening for connections. */
@@ -312,30 +359,30 @@
}
int uv__tcp_nodelay(int fd, int on) {
if (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &on, sizeof(on)))
- return -errno;
+ return UV__ERR(errno);
return 0;
}
int uv__tcp_keepalive(int fd, int on, unsigned int delay) {
if (setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, &on, sizeof(on)))
- return -errno;
+ return UV__ERR(errno);
#ifdef TCP_KEEPIDLE
if (on && setsockopt(fd, IPPROTO_TCP, TCP_KEEPIDLE, &delay, sizeof(delay)))
- return -errno;
+ return UV__ERR(errno);
#endif
/* Solaris/SmartOS, if you don't support keep-alive,
* then don't advertise it in your system headers...
*/
/* FIXME(bnoordhuis) That's possibly because sizeof(delay) should be 1. */
#if defined(TCP_KEEPALIVE) && !defined(__sun)
if (on && setsockopt(fd, IPPROTO_TCP, TCP_KEEPALIVE, &delay, sizeof(delay)))
- return -errno;
+ return UV__ERR(errno);
#endif
return 0;
}