diff --git a/Makefile b/Makefile index b42ab57cee863e58534034203d8bf5ef35361871..dece13bdd69ac1baf42f7ecec25cef31d9b48b0a 100644 --- a/Makefile +++ b/Makefile @@ -1013,7 +1013,6 @@ LIBGRPC_TEST_UTIL_SRC = \ test/core/statistics/census_log_tests.c \ test/core/transport/transport_end2end_tests.c \ test/core/util/grpc_profiler.c \ - test/core/util/ipv6_posix.c \ test/core/util/parse_hexstring.c \ test/core/util/port_posix.c \ test/core/util/slice_splitter.c \ diff --git a/build.json b/build.json index 64a1df266b2e54987e3448cb12bdbe7d786dac9f..07e2318e4b0e9b0626826abd49e4ff0962b4c257 100644 --- a/build.json +++ b/build.json @@ -289,7 +289,6 @@ "test/core/statistics/census_log_tests.c", "test/core/transport/transport_end2end_tests.c", "test/core/util/grpc_profiler.c", - "test/core/util/ipv6_posix.c", "test/core/util/parse_hexstring.c", "test/core/util/port_posix.c", "test/core/util/slice_splitter.c", diff --git a/src/core/iomgr/socket_utils_common_posix.c b/src/core/iomgr/socket_utils_common_posix.c index 0767d6f91802c0d0152b6666e5559bc9c7fdffe6..7f2b43f2cad110608db3413bb6a4d42ee0ccf78f 100644 --- a/src/core/iomgr/socket_utils_common_posix.c +++ b/src/core/iomgr/socket_utils_common_posix.c @@ -50,6 +50,7 @@ #include <grpc/support/string.h> #include <grpc/support/log.h> #include <grpc/support/port_platform.h> +#include <grpc/support/sync.h> /* set a socket to non blocking mode */ int grpc_set_socket_nonblocking(int fd, int non_blocking) { @@ -111,6 +112,34 @@ int grpc_set_socket_low_latency(int fd, int low_latency) { newval == val; } +static gpr_once g_probe_ipv6_once = GPR_ONCE_INIT; +static int g_ipv6_loopback_available; + +static void probe_ipv6_once() { + int fd = socket(AF_INET6, SOCK_STREAM, 0); + g_ipv6_loopback_available = 0; + if (fd < 0) { + gpr_log(GPR_INFO, "Disabling AF_INET6 sockets because socket() failed."); + } else { + struct sockaddr_in6 addr; + memset(&addr, 0, sizeof(addr)); + addr.sin6_family = AF_INET6; + addr.sin6_addr.s6_addr[15] = 1; /* [::1]:0 */ + if (bind(fd, (struct sockaddr *)&addr, sizeof(addr)) == 0) { + g_ipv6_loopback_available = 1; + } else { + gpr_log(GPR_INFO, + "Disabling AF_INET6 sockets because ::1 is not available."); + } + close(fd); + } +} + +int grpc_ipv6_loopback_available() { + gpr_once_init(&g_probe_ipv6_once, probe_ipv6_once); + return g_ipv6_loopback_available; +} + /* This should be 0 in production, but it may be enabled for testing or debugging purposes, to simulate an environment where IPv6 sockets can't also speak IPv4. */ @@ -132,7 +161,13 @@ int grpc_create_dualstack_socket(const struct sockaddr *addr, int type, int protocol, grpc_dualstack_mode *dsmode) { int family = addr->sa_family; if (family == AF_INET6) { - int fd = socket(family, type, protocol); + int fd; + if (grpc_ipv6_loopback_available()) { + fd = socket(family, type, protocol); + } else { + fd = -1; + errno = EAFNOSUPPORT; + } /* Check if we've got a valid dualstack socket. */ if (fd >= 0 && set_socket_dualstack(fd)) { *dsmode = GRPC_DSMODE_DUALSTACK; diff --git a/src/core/iomgr/socket_utils_posix.h b/src/core/iomgr/socket_utils_posix.h index 5c31e5e6d882156c30454f4517c7046d5ec51a58..9c5d93c2b4bce303a9c6a95c35732231f759b5ec 100644 --- a/src/core/iomgr/socket_utils_posix.h +++ b/src/core/iomgr/socket_utils_posix.h @@ -53,6 +53,16 @@ int grpc_set_socket_reuse_addr(int fd, int reuse); /* disable nagle */ int grpc_set_socket_low_latency(int fd, int low_latency); +/* Returns true if this system can create AF_INET6 sockets bound to ::1. + The value is probed once, and cached for the life of the process. + + This is more restrictive than checking for socket(AF_INET6) to succeed, + because Linux with "net.ipv6.conf.all.disable_ipv6 = 1" is able to create + and bind IPv6 sockets, but cannot connect to a getsockname() of [::]:port + without a valid loopback interface. Rather than expose this half-broken + state to library users, we turn off IPv6 sockets. */ +int grpc_ipv6_loopback_available(); + /* An enum to keep track of IPv4/IPv6 socket modes. Currently, this information is only used when a socket is first created, but diff --git a/test/core/echo/echo_test.c b/test/core/echo/echo_test.c index cc265cadbf0295d3c536eed2d1d0c4be8389dd87..748e8bc0ef09b65d80a53b266917c5e5ce4bc13e 100644 --- a/test/core/echo/echo_test.c +++ b/test/core/echo/echo_test.c @@ -40,11 +40,11 @@ #include <sys/types.h> #include <sys/wait.h> +#include "src/core/iomgr/socket_utils_posix.h" #include <grpc/support/alloc.h> #include <grpc/support/host_port.h> #include <grpc/support/log.h> #include <grpc/support/string.h> -#include "test/core/util/ipv6.h" #include "test/core/util/port.h" int test_client(const char *root, const char *host, int port) { diff --git a/test/core/end2end/dualstack_socket_test.c b/test/core/end2end/dualstack_socket_test.c index 808fcbd65d2a7059c040a93574fb0bdfbe3e0dc3..b443caa2a67249702d9c42b7c111f0333969716b 100644 --- a/test/core/end2end/dualstack_socket_test.c +++ b/test/core/end2end/dualstack_socket_test.c @@ -37,7 +37,6 @@ #include <grpc/support/host_port.h> #include <grpc/support/log.h> #include "test/core/end2end/cq_verifier.h" -#include "test/core/util/ipv6.h" #include "test/core/util/port.h" #include "test/core/util/test_config.h" diff --git a/test/core/util/ipv6.h b/test/core/util/ipv6.h deleted file mode 100644 index bb536645b8775467270fe22f1c0bffa856082a25..0000000000000000000000000000000000000000 --- a/test/core/util/ipv6.h +++ /dev/null @@ -1,41 +0,0 @@ -/* - * - * Copyright 2014, Google Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - */ - -#ifndef __GRPC_TEST_UTIL_IPV6_H__ -#define __GRPC_TEST_UTIL_IPV6_H__ - -/* Returns true if we're able to create an AF_INET6 socket bound to ::1 on an - arbitrary port. */ -int grpc_ipv6_loopback_available(); - -#endif /* __GRPC_TEST_UTIL_IPV6_H__ */ diff --git a/test/core/util/ipv6_posix.c b/test/core/util/ipv6_posix.c deleted file mode 100644 index 25758f59fea8e328b99e28277b85d8a198b62f91..0000000000000000000000000000000000000000 --- a/test/core/util/ipv6_posix.c +++ /dev/null @@ -1,60 +0,0 @@ -/* - * - * Copyright 2014, Google Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - */ - -#include <grpc/support/port_platform.h> -#ifdef GPR_POSIX_SOCKET - -#include "test/core/util/ipv6.h" - -#include <netinet/in.h> -#include <string.h> -#include <sys/socket.h> -#include <unistd.h> - -int grpc_ipv6_loopback_available() { - int ok = 0; - int fd = socket(AF_INET6, SOCK_STREAM, 0); - if (fd >= 0) { - struct sockaddr_in6 addr; - memset(&addr, 0, sizeof(addr)); - addr.sin6_family = AF_INET6; - addr.sin6_addr.s6_addr[15] = 1; /* [::1]:0 */ - if (bind(fd, (struct sockaddr *)&addr, sizeof(addr)) == 0) { - ok = 1; - } - close(fd); - } - return ok; -} - -#endif /* GPR_POSIX_SOCKET */ diff --git a/vsprojects/vs2013/grpc_test_util.vcxproj b/vsprojects/vs2013/grpc_test_util.vcxproj index 9a118cf590ccb24effa0502854780bed79928a3d..a86d415cc6ed62cbe9dab14a3fe388e334adf0cf 100644 --- a/vsprojects/vs2013/grpc_test_util.vcxproj +++ b/vsprojects/vs2013/grpc_test_util.vcxproj @@ -89,8 +89,6 @@ </ClCompile> <ClCompile Include="..\..\test\core\util\grpc_profiler.c"> </ClCompile> - <ClCompile Include="..\..\test\core\util\ipv6_posix.c"> - </ClCompile> <ClCompile Include="..\..\test\core\util\parse_hexstring.c"> </ClCompile> <ClCompile Include="..\..\test\core\util\port_posix.c">