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; }