From 9d60f1ebda0cdedc67ee439997e60b74a40f2f3f Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Sun, 25 Aug 2013 18:40:13 +0200 Subject: [PATCH] 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. --- src/unix/udp.c | 34 ++++++---------------------------- 1 file changed, 6 insertions(+), 28 deletions(-) diff --git a/src/unix/udp.c b/src/unix/udp.c index 4a545d72..1413985b 100644 --- a/src/unix/udp.c +++ b/src/unix/udp.c @@ -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;