linux: don't turn on SO_REUSEPORT socket option

On the BSDs, SO_REUSEPORT is pretty much SO_REUSEADDR with some special
casing for IP multicast.  When two processes (that don't do multicast)
bind to the same address, only the last one receives traffic.  It allows
one to "steal" the bound address from another process.  (Both processes
have to enable SO_REUSEPORT though, so it only works in a cooperative
setting.)

On Linux however, it enables port sharing, not stealing - both processes
receive a share of the traffic.  This is a desirable trait but pre-3.9
kernels don't support the socket option and a libuv program therefore
behaves differently with older kernels or on another platform.

The difference in behavior (sharing vs. stealing) is, in my opinion,
big enough and confusing enough that it merits a rollback.  People
that want this kind of functionality can prepare the socket manually
and hand it off to uv_udp_open().

This commit effectively reverts commit 17452cd.
This commit is contained in:
Ben Noordhuis 2013-08-25 18:40:13 +02:00
parent d6464c87bd
commit 9d60f1ebda

View File

@ -280,40 +280,18 @@ static void uv__udp_sendmsg(uv_loop_t* loop,
}
/* On the BSDs, SO_REUSEPORT implies SO_REUSEADDR but it also lets you share
* the address and port with other processes.
/* On the BSDs, SO_REUSEPORT implies SO_REUSEADDR but with some additional
* refinements for programs that use multicast.
*
* Linux as of 3.9 has a SO_REUSEPORT socket option but with semantics that
* are different from the BSDs. The address:port sharing part is taken care
* of by SO_REUSEADDR while SO_REUSEPORT enables fair load distribution. (If
* you wonder why you need to explicitly enable that, well, it's complicated.)
*
* Because we cannot rely on SO_REUSEPORT being available on Linux, it's not
* considered an error when the setsockopt() system call fails. Worst case,
* the program has sub-optimal load distribution characteristics but should
* otherwise run fine.
* are different from the BSDs: it _shares_ the port rather than steal it
* from the current listener. While useful, it's not something we can emulate
* on other platforms so we don't enable it.
*/
static int uv__set_reuse(int fd) {
int yes;
#if defined(__linux__)
static int no_so_reuseport;
if (no_so_reuseport)
goto no_so_reuseport;
yes = 1;
if (setsockopt(fd, SOL_SOCKET, 15 /* SO_REUSEPORT */, &yes, sizeof(yes))) {
if (errno != EINVAL && errno != ENOPROTOOPT)
return -errno;
no_so_reuseport = 1;
}
no_so_reuseport:
yes = 1;
if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes)))
return -errno;
#elif defined(SO_REUSEPORT)
#if defined(SO_REUSEPORT) && !defined(__linux__)
yes = 1;
if (setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, &yes, sizeof(yes)))
return -errno;