unix: only set SO_REUSEADDR on tcp listen sockets

Avoid the extra syscall, it's a no-op for non-listening sockets.

At least, it should be - it remains to be investigated if a FreeBSD kernel bug
affects ephemeral port allocation inside connect(). See [1] for details.

[1] http://www.freebsd.org/cgi/query-pr.cgi?pr=174087
This commit is contained in:
Ben Noordhuis 2012-12-09 13:21:20 +01:00
parent b4168cd697
commit a385ae4f59
2 changed files with 10 additions and 26 deletions

View File

@ -101,18 +101,10 @@ void uv__stream_init(uv_loop_t* loop,
int uv__stream_open(uv_stream_t* stream, int fd, int flags) {
socklen_t yes;
assert(fd >= 0);
stream->flags |= flags;
if (stream->type == UV_TCP) {
/* Reuse the port address if applicable. */
yes = 1;
if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof yes) == -1)
return uv__set_sys_error(stream->loop, errno);
if ((stream->flags & UV_TCP_NODELAY) && uv__tcp_nodelay(fd, 1))
return uv__set_sys_error(stream->loop, errno);

View File

@ -58,29 +58,21 @@ static int uv__bind(uv_tcp_t* tcp,
int domain,
struct sockaddr* addr,
int addrsize) {
int saved_errno;
int status;
saved_errno = errno;
status = -1;
int on;
if (maybe_new_socket(tcp, domain, UV_STREAM_READABLE|UV_STREAM_WRITABLE))
return -1;
tcp->delayed_error = 0;
if (bind(tcp->io_watcher.fd, addr, addrsize) == -1) {
if (errno == EADDRINUSE) {
tcp->delayed_error = errno;
} else {
uv__set_sys_error(tcp->loop, errno);
goto out;
}
}
status = 0;
on = 1;
if (setsockopt(tcp->io_watcher.fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)))
return uv__set_sys_error(tcp->loop, errno);
out:
errno = saved_errno;
return status;
errno = 0;
if (bind(tcp->io_watcher.fd, addr, addrsize) && errno != EADDRINUSE)
return uv__set_sys_error(tcp->loop, errno);
tcp->delayed_error = errno;
return 0;
}