123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136 |
- --- ./src/unix/udp.c 2013-05-14 19:50:19.000000000 -0400
- +++ ./src/unix/udp.c 2013-08-24 10:19:11.446792000 -0400
- @@ -286,6 +286,53 @@
- }
-
-
- +/* On the BSDs, SO_REUSEPORT implies SO_REUSEADDR but it also lets you share
- + * the address and port with other processes.
- + *
- + * 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.
- + */
- +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)
- + yes = 1;
- + if (setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, &yes, sizeof(yes)))
- + return -errno;
- +#else
- + yes = 1;
- + if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes)))
- + return -errno;
- +#endif
- +
- + return 0;
- +}
- +
- +
- static int uv__bind(uv_udp_t* handle,
- int domain,
- struct sockaddr* addr,
- @@ -295,6 +342,7 @@
- int status;
- int yes;
- int fd;
- + int err;
-
- saved_errno = errno;
- status = -1;
- @@ -321,28 +369,12 @@
- }
-
- fd = handle->io_watcher.fd;
- - yes = 1;
- - if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof yes) == -1) {
- - uv__set_sys_error(handle->loop, errno);
- + err = uv__set_reuse(fd);
- + if (err) {
- + uv__set_sys_error(handle->loop, -err);
- goto out;
- }
-
- - /* On the BSDs, SO_REUSEADDR lets you reuse an address that's in the TIME_WAIT
- - * state (i.e. was until recently tied to a socket) while SO_REUSEPORT lets
- - * multiple processes bind to the same address. Yes, it's something of a
- - * misnomer but then again, SO_REUSEADDR was already taken.
- - *
- - * None of the above applies to Linux: SO_REUSEADDR implies SO_REUSEPORT on
- - * Linux and hence it does not have SO_REUSEPORT at all.
- - */
- -#ifdef SO_REUSEPORT
- - yes = 1;
- - if (setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, &yes, sizeof yes) == -1) {
- - uv__set_sys_error(handle->loop, errno);
- - goto out;
- - }
- -#endif
- -
- if (flags & UV_UDP_IPV6ONLY) {
- #ifdef IPV6_V6ONLY
- yes = 1;
- @@ -481,7 +513,7 @@
- int uv_udp_open(uv_udp_t* handle, uv_os_sock_t sock) {
- int saved_errno;
- int status;
- - int yes;
- + int err;
-
- saved_errno = errno;
- status = -1;
- @@ -492,27 +524,11 @@
- goto out;
- }
-
- - yes = 1;
- - if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof yes) == -1) {
- - uv__set_sys_error(handle->loop, errno);
- - goto out;
- - }
- -
- - /* On the BSDs, SO_REUSEADDR lets you reuse an address that's in the TIME_WAIT
- - * state (i.e. was until recently tied to a socket) while SO_REUSEPORT lets
- - * multiple processes bind to the same address. Yes, it's something of a
- - * misnomer but then again, SO_REUSEADDR was already taken.
- - *
- - * None of the above applies to Linux: SO_REUSEADDR implies SO_REUSEPORT on
- - * Linux and hence it does not have SO_REUSEPORT at all.
- - */
- -#ifdef SO_REUSEPORT
- - yes = 1;
- - if (setsockopt(sock, SOL_SOCKET, SO_REUSEPORT, &yes, sizeof yes) == -1) {
- - uv__set_sys_error(handle->loop, errno);
- + err = uv__set_reuse(sock);
- + if (err) {
- + uv__set_sys_error(handle->loop, -err);
- goto out;
- }
- -#endif
-
- handle->io_watcher.fd = sock;
- status = 0;
|