Fix a problem with IP protocol version confusion on MacOS when TCP FastOpen is enabled (#11588)
Motivation: This fixes a bug that would result in an `io.netty.channel.unix.Errors$NativeIoException: connectx(..) failed: Address family not supported by protocol family` error. This happens when the connecting socket is configured to use IPv6 but the address being connected to is IPv4. This can occur because, for instance, Netty and `InetAddress.getLoopbackAddress()` have different preferences for IPv6 vs. IPv4. Modification: Pass the correct ipv6 or ipv4 flags to connectx, depending on whether the socket was created for AF_INET or AF_INET6, rather than relying on the IP version of the destination address. Result: No more issue with TCP FastOpen on MacOS when using addresses of the "wrong" IP version.
This commit is contained in:
parent
0e2f4adc9d
commit
9eb4f0ee85
@ -34,11 +34,11 @@ public abstract class AbstractSocketTest extends AbstractComboTestsuiteTest<Serv
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void configure(ServerBootstrap bootstrap, Bootstrap bootstrap2, ByteBufAllocator allocator) {
|
protected void configure(ServerBootstrap sb, Bootstrap cb, ByteBufAllocator allocator) {
|
||||||
bootstrap.localAddress(newSocketAddress());
|
sb.localAddress(newSocketAddress());
|
||||||
bootstrap.option(ChannelOption.ALLOCATOR, allocator);
|
sb.option(ChannelOption.ALLOCATOR, allocator);
|
||||||
bootstrap.childOption(ChannelOption.ALLOCATOR, allocator);
|
sb.childOption(ChannelOption.ALLOCATOR, allocator);
|
||||||
bootstrap2.option(ChannelOption.ALLOCATOR, allocator);
|
cb.option(ChannelOption.ALLOCATOR, allocator);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected SocketAddress newSocketAddress() {
|
protected SocketAddress newSocketAddress() {
|
||||||
|
@ -39,7 +39,7 @@ class EpollDomainDatagramPathTest extends AbstractClientSocketTest {
|
|||||||
run(testInfo, bootstrap -> {
|
run(testInfo, bootstrap -> {
|
||||||
try {
|
try {
|
||||||
bootstrap.handler(new ChannelHandlerAdapter() { })
|
bootstrap.handler(new ChannelHandlerAdapter() { })
|
||||||
.connect(EpollSocketTestPermutation.newSocketAddress()).get();
|
.connect(EpollSocketTestPermutation.newDomainSocketAddress()).get();
|
||||||
fail("Expected FileNotFoundException");
|
fail("Expected FileNotFoundException");
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
assertTrue(e.getCause() instanceof FileNotFoundException);
|
assertTrue(e.getCause() instanceof FileNotFoundException);
|
||||||
@ -52,10 +52,10 @@ class EpollDomainDatagramPathTest extends AbstractClientSocketTest {
|
|||||||
run(testInfo, bootstrap -> {
|
run(testInfo, bootstrap -> {
|
||||||
try {
|
try {
|
||||||
Channel ch = bootstrap.handler(new ChannelHandlerAdapter() { })
|
Channel ch = bootstrap.handler(new ChannelHandlerAdapter() { })
|
||||||
.bind(EpollSocketTestPermutation.newSocketAddress()).get();
|
.bind(EpollSocketTestPermutation.newDomainSocketAddress()).get();
|
||||||
ch.writeAndFlush(new DomainDatagramPacket(
|
ch.writeAndFlush(new DomainDatagramPacket(
|
||||||
Unpooled.copiedBuffer("test", CharsetUtil.US_ASCII),
|
Unpooled.copiedBuffer("test", CharsetUtil.US_ASCII),
|
||||||
EpollSocketTestPermutation.newSocketAddress())).sync();
|
EpollSocketTestPermutation.newDomainSocketAddress())).sync();
|
||||||
fail("Expected FileNotFoundException");
|
fail("Expected FileNotFoundException");
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
assertTrue(e.getCause() instanceof FileNotFoundException);
|
assertTrue(e.getCause() instanceof FileNotFoundException);
|
||||||
|
@ -76,7 +76,7 @@ class EpollDomainDatagramUnicastTest extends DatagramUnicastTest {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected SocketAddress newSocketAddress() {
|
protected SocketAddress newSocketAddress() {
|
||||||
return EpollSocketTestPermutation.newSocketAddress();
|
return EpollSocketTestPermutation.newDomainSocketAddress();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -26,7 +26,7 @@ import java.util.List;
|
|||||||
public class EpollDomainSocketDataReadInitialStateTest extends SocketDataReadInitialStateTest {
|
public class EpollDomainSocketDataReadInitialStateTest extends SocketDataReadInitialStateTest {
|
||||||
@Override
|
@Override
|
||||||
protected SocketAddress newSocketAddress() {
|
protected SocketAddress newSocketAddress() {
|
||||||
return EpollSocketTestPermutation.newSocketAddress();
|
return EpollSocketTestPermutation.newDomainSocketAddress();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -25,7 +25,7 @@ import java.util.List;
|
|||||||
public class EpollDomainSocketEchoTest extends EpollSocketEchoTest {
|
public class EpollDomainSocketEchoTest extends EpollSocketEchoTest {
|
||||||
@Override
|
@Override
|
||||||
protected SocketAddress newSocketAddress() {
|
protected SocketAddress newSocketAddress() {
|
||||||
return EpollSocketTestPermutation.newSocketAddress();
|
return EpollSocketTestPermutation.newDomainSocketAddress();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -43,7 +43,7 @@ import static org.junit.jupiter.api.Assertions.assertTrue;
|
|||||||
public class EpollDomainSocketFdTest extends AbstractSocketTest {
|
public class EpollDomainSocketFdTest extends AbstractSocketTest {
|
||||||
@Override
|
@Override
|
||||||
protected SocketAddress newSocketAddress() {
|
protected SocketAddress newSocketAddress() {
|
||||||
return EpollSocketTestPermutation.newSocketAddress();
|
return EpollSocketTestPermutation.newDomainSocketAddress();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -25,7 +25,7 @@ import java.util.List;
|
|||||||
public class EpollDomainSocketFileRegionTest extends EpollSocketFileRegionTest {
|
public class EpollDomainSocketFileRegionTest extends EpollSocketFileRegionTest {
|
||||||
@Override
|
@Override
|
||||||
protected SocketAddress newSocketAddress() {
|
protected SocketAddress newSocketAddress() {
|
||||||
return EpollSocketTestPermutation.newSocketAddress();
|
return EpollSocketTestPermutation.newDomainSocketAddress();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -27,7 +27,7 @@ public class EpollDomainSocketFixedLengthEchoTest extends SocketFixedLengthEchoT
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected SocketAddress newSocketAddress() {
|
protected SocketAddress newSocketAddress() {
|
||||||
return EpollSocketTestPermutation.newSocketAddress();
|
return EpollSocketTestPermutation.newDomainSocketAddress();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -27,7 +27,7 @@ public class EpollDomainSocketGatheringWriteTest extends SocketGatheringWriteTes
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected SocketAddress newSocketAddress() {
|
protected SocketAddress newSocketAddress() {
|
||||||
return EpollSocketTestPermutation.newSocketAddress();
|
return EpollSocketTestPermutation.newDomainSocketAddress();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -26,7 +26,7 @@ import java.util.List;
|
|||||||
public class EpollDomainSocketObjectEchoTest extends SocketObjectEchoTest {
|
public class EpollDomainSocketObjectEchoTest extends SocketObjectEchoTest {
|
||||||
@Override
|
@Override
|
||||||
protected SocketAddress newSocketAddress() {
|
protected SocketAddress newSocketAddress() {
|
||||||
return EpollSocketTestPermutation.newSocketAddress();
|
return EpollSocketTestPermutation.newDomainSocketAddress();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -26,7 +26,7 @@ import java.util.List;
|
|||||||
public class EpollDomainSocketReuseFdTest extends AbstractSocketReuseFdTest {
|
public class EpollDomainSocketReuseFdTest extends AbstractSocketReuseFdTest {
|
||||||
@Override
|
@Override
|
||||||
protected SocketAddress newSocketAddress() {
|
protected SocketAddress newSocketAddress() {
|
||||||
return EpollSocketTestPermutation.newSocketAddress();
|
return EpollSocketTestPermutation.newDomainSocketAddress();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -35,7 +35,7 @@ public class EpollDomainSocketShutdownOutputByPeerTest extends AbstractSocketShu
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected SocketAddress newSocketAddress() {
|
protected SocketAddress newSocketAddress() {
|
||||||
return EpollSocketTestPermutation.newSocketAddress();
|
return EpollSocketTestPermutation.newDomainSocketAddress();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -31,6 +31,6 @@ public class EpollDomainSocketSslClientRenegotiateTest extends SocketSslClientRe
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected SocketAddress newSocketAddress() {
|
protected SocketAddress newSocketAddress() {
|
||||||
return EpollSocketTestPermutation.newSocketAddress();
|
return EpollSocketTestPermutation.newDomainSocketAddress();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -26,7 +26,7 @@ import java.util.List;
|
|||||||
public class EpollDomainSocketSslEchoTest extends SocketSslEchoTest {
|
public class EpollDomainSocketSslEchoTest extends SocketSslEchoTest {
|
||||||
@Override
|
@Override
|
||||||
protected SocketAddress newSocketAddress() {
|
protected SocketAddress newSocketAddress() {
|
||||||
return EpollSocketTestPermutation.newSocketAddress();
|
return EpollSocketTestPermutation.newDomainSocketAddress();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -26,7 +26,7 @@ import java.util.List;
|
|||||||
public class EpollDomainSocketSslGreetingTest extends SocketSslGreetingTest {
|
public class EpollDomainSocketSslGreetingTest extends SocketSslGreetingTest {
|
||||||
@Override
|
@Override
|
||||||
protected SocketAddress newSocketAddress() {
|
protected SocketAddress newSocketAddress() {
|
||||||
return EpollSocketTestPermutation.newSocketAddress();
|
return EpollSocketTestPermutation.newDomainSocketAddress();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -26,7 +26,7 @@ import java.util.List;
|
|||||||
public class EpollDomainSocketStartTlsTest extends SocketStartTlsTest {
|
public class EpollDomainSocketStartTlsTest extends SocketStartTlsTest {
|
||||||
@Override
|
@Override
|
||||||
protected SocketAddress newSocketAddress() {
|
protected SocketAddress newSocketAddress() {
|
||||||
return EpollSocketTestPermutation.newSocketAddress();
|
return EpollSocketTestPermutation.newDomainSocketAddress();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -26,7 +26,7 @@ import java.util.List;
|
|||||||
public class EpollDomainSocketStringEchoTest extends SocketStringEchoTest {
|
public class EpollDomainSocketStringEchoTest extends SocketStringEchoTest {
|
||||||
@Override
|
@Override
|
||||||
protected SocketAddress newSocketAddress() {
|
protected SocketAddress newSocketAddress() {
|
||||||
return EpollSocketTestPermutation.newSocketAddress();
|
return EpollSocketTestPermutation.newDomainSocketAddress();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -0,0 +1,27 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2021 The Netty Project
|
||||||
|
*
|
||||||
|
* The Netty Project licenses this file to you under the Apache License,
|
||||||
|
* version 2.0 (the "License"); you may not use this file except in compliance
|
||||||
|
* with the License. You may obtain a copy of the License at:
|
||||||
|
*
|
||||||
|
* https://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
* License for the specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*/
|
||||||
|
package io.netty.channel.epoll;
|
||||||
|
|
||||||
|
import io.netty.channel.unix.tests.UnixTestUtils;
|
||||||
|
|
||||||
|
import java.net.SocketAddress;
|
||||||
|
|
||||||
|
public class EpollJdkLoopbackSocketSslEchoTest extends EpollSocketSslEchoTest {
|
||||||
|
@Override
|
||||||
|
protected SocketAddress newSocketAddress() {
|
||||||
|
return UnixTestUtils.newInetLoopbackSocketAddress();
|
||||||
|
}
|
||||||
|
}
|
@ -47,7 +47,7 @@ public class EpollSocketTest extends SocketTest<LinuxSocket> {
|
|||||||
LinuxSocket s2 = LinuxSocket.newSocketDomain();
|
LinuxSocket s2 = LinuxSocket.newSocketDomain();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
DomainSocketAddress dsa = UnixTestUtils.newSocketAddress();
|
DomainSocketAddress dsa = UnixTestUtils.newDomainSocketAddress();
|
||||||
s1.bind(dsa);
|
s1.bind(dsa);
|
||||||
s1.listen(1);
|
s1.listen(1);
|
||||||
|
|
||||||
|
@ -184,8 +184,8 @@ class EpollSocketTestPermutation extends SocketTestPermutation {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static DomainSocketAddress newSocketAddress() {
|
public static DomainSocketAddress newDomainSocketAddress() {
|
||||||
return UnixTestUtils.newSocketAddress();
|
return UnixTestUtils.newDomainSocketAddress();
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<TestsuitePermutation.BootstrapComboFactory<Bootstrap, Bootstrap>> domainDatagram() {
|
public List<TestsuitePermutation.BootstrapComboFactory<Bootstrap, Bootstrap>> domainDatagram() {
|
||||||
|
@ -125,8 +125,8 @@ final class BsdSocket extends Socket {
|
|||||||
sourcePort = 0;
|
sourcePort = 0;
|
||||||
} else {
|
} else {
|
||||||
InetAddress sourceInetAddress = source.getAddress();
|
InetAddress sourceInetAddress = source.getAddress();
|
||||||
sourceIPv6 = sourceInetAddress instanceof Inet6Address;
|
sourceIPv6 = useIpv6(this, sourceInetAddress);
|
||||||
if (sourceIPv6) {
|
if (sourceInetAddress instanceof Inet6Address) {
|
||||||
sourceAddress = sourceInetAddress.getAddress();
|
sourceAddress = sourceInetAddress.getAddress();
|
||||||
sourceScopeId = ((Inet6Address) sourceInetAddress).getScopeId();
|
sourceScopeId = ((Inet6Address) sourceInetAddress).getScopeId();
|
||||||
} else {
|
} else {
|
||||||
@ -138,10 +138,10 @@ final class BsdSocket extends Socket {
|
|||||||
}
|
}
|
||||||
|
|
||||||
InetAddress destinationInetAddress = destination.getAddress();
|
InetAddress destinationInetAddress = destination.getAddress();
|
||||||
boolean destinationIPv6 = destinationInetAddress instanceof Inet6Address;
|
boolean destinationIPv6 = useIpv6(this, destinationInetAddress);
|
||||||
byte[] destinationAddress;
|
byte[] destinationAddress;
|
||||||
int destinationScopeId;
|
int destinationScopeId;
|
||||||
if (destinationIPv6) {
|
if (destinationInetAddress instanceof Inet6Address) {
|
||||||
destinationAddress = destinationInetAddress.getAddress();
|
destinationAddress = destinationInetAddress.getAddress();
|
||||||
destinationScopeId = ((Inet6Address) destinationInetAddress).getScopeId();
|
destinationScopeId = ((Inet6Address) destinationInetAddress).getScopeId();
|
||||||
} else {
|
} else {
|
||||||
|
@ -0,0 +1,27 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2021 The Netty Project
|
||||||
|
*
|
||||||
|
* The Netty Project licenses this file to you under the Apache License,
|
||||||
|
* version 2.0 (the "License"); you may not use this file except in compliance
|
||||||
|
* with the License. You may obtain a copy of the License at:
|
||||||
|
*
|
||||||
|
* https://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
* License for the specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*/
|
||||||
|
package io.netty.channel.kqueue;
|
||||||
|
|
||||||
|
import io.netty.channel.unix.tests.UnixTestUtils;
|
||||||
|
|
||||||
|
import java.net.SocketAddress;
|
||||||
|
|
||||||
|
public class KQueueJdkLoopbackSocketSslEchoTest extends KQueueSocketSslEchoTest {
|
||||||
|
@Override
|
||||||
|
protected SocketAddress newSocketAddress() {
|
||||||
|
return UnixTestUtils.newInetLoopbackSocketAddress();
|
||||||
|
}
|
||||||
|
}
|
@ -40,7 +40,7 @@ public class KQueueSocketTest extends SocketTest<BsdSocket> {
|
|||||||
BsdSocket s2 = BsdSocket.newSocketDomain();
|
BsdSocket s2 = BsdSocket.newSocketDomain();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
DomainSocketAddress dsa = UnixTestUtils.newSocketAddress();
|
DomainSocketAddress dsa = UnixTestUtils.newDomainSocketAddress();
|
||||||
s1.bind(dsa);
|
s1.bind(dsa);
|
||||||
s1.listen(1);
|
s1.listen(1);
|
||||||
|
|
||||||
@ -61,7 +61,7 @@ public class KQueueSocketTest extends SocketTest<BsdSocket> {
|
|||||||
BsdSocket s2 = BsdSocket.newSocketDomain();
|
BsdSocket s2 = BsdSocket.newSocketDomain();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
DomainSocketAddress dsa = UnixTestUtils.newSocketAddress();
|
DomainSocketAddress dsa = UnixTestUtils.newDomainSocketAddress();
|
||||||
s1.bind(dsa);
|
s1.bind(dsa);
|
||||||
s1.listen(1);
|
s1.listen(1);
|
||||||
|
|
||||||
|
@ -54,7 +54,7 @@ class KQueueSocketTestPermutation extends SocketTestPermutation {
|
|||||||
public List<TestsuitePermutation.BootstrapComboFactory<ServerBootstrap, Bootstrap>> socket() {
|
public List<TestsuitePermutation.BootstrapComboFactory<ServerBootstrap, Bootstrap>> socket() {
|
||||||
|
|
||||||
List<TestsuitePermutation.BootstrapComboFactory<ServerBootstrap, Bootstrap>> list =
|
List<TestsuitePermutation.BootstrapComboFactory<ServerBootstrap, Bootstrap>> list =
|
||||||
combo(serverSocket(), clientSocket());
|
combo(serverSocket(), clientSocketWithFastOpen());
|
||||||
|
|
||||||
list.remove(list.size() - 1); // Exclude NIO x NIO test
|
list.remove(list.size() - 1); // Exclude NIO x NIO test
|
||||||
|
|
||||||
@ -139,8 +139,9 @@ class KQueueSocketTestPermutation extends SocketTestPermutation {
|
|||||||
() -> new Bootstrap().group(KQUEUE_WORKER_GROUP).channel(KQueueDatagramChannel.class)
|
() -> new Bootstrap().group(KQUEUE_WORKER_GROUP).channel(KQueueDatagramChannel.class)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static DomainSocketAddress newSocketAddress() {
|
public static DomainSocketAddress newSocketAddress() {
|
||||||
return UnixTestUtils.newSocketAddress();
|
return UnixTestUtils.newDomainSocketAddress();
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<TestsuitePermutation.BootstrapComboFactory<Bootstrap, Bootstrap>> domainDatagram() {
|
public List<TestsuitePermutation.BootstrapComboFactory<Bootstrap, Bootstrap>> domainDatagram() {
|
||||||
|
@ -20,9 +20,26 @@ import io.netty.util.internal.PlatformDependent;
|
|||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.lang.reflect.Method;
|
||||||
|
import java.net.InetAddress;
|
||||||
|
import java.net.InetSocketAddress;
|
||||||
|
import java.net.SocketAddress;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assumptions.assumeTrue;
|
||||||
|
|
||||||
public final class UnixTestUtils {
|
public final class UnixTestUtils {
|
||||||
|
private static final Object INET_LOOPBACK_UNAVAILABLE = new Object();
|
||||||
|
private static volatile Object inetLoopbackCache;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @deprecated Use {@link #newDomainSocketAddress()} instead.
|
||||||
|
*/
|
||||||
|
@Deprecated
|
||||||
public static DomainSocketAddress newSocketAddress() {
|
public static DomainSocketAddress newSocketAddress() {
|
||||||
|
return newDomainSocketAddress();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static DomainSocketAddress newDomainSocketAddress() {
|
||||||
try {
|
try {
|
||||||
File file;
|
File file;
|
||||||
do {
|
do {
|
||||||
@ -37,5 +54,30 @@ public final class UnixTestUtils {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The JDK method may produce IPv4 loopback addresses where {@link io.netty.util.NetUtil#LOCALHOST} might be an
|
||||||
|
* IPv6 addresses.
|
||||||
|
* This difference can stress the system in different ways that are important to test.
|
||||||
|
*/
|
||||||
|
public static SocketAddress newInetLoopbackSocketAddress() {
|
||||||
|
Object loopback = inetLoopbackCache;
|
||||||
|
|
||||||
|
if (loopback == null) {
|
||||||
|
inetLoopbackCache = loopback = getLoopbackAddress();
|
||||||
|
}
|
||||||
|
|
||||||
|
assumeTrue(loopback != INET_LOOPBACK_UNAVAILABLE, "InetAddress.getLoopbackAddress() is not available");
|
||||||
|
return new InetSocketAddress((InetAddress) loopback, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Object getLoopbackAddress() {
|
||||||
|
try {
|
||||||
|
Method method = InetAddress.class.getMethod("getLoopbackAddress");
|
||||||
|
return method.invoke(null);
|
||||||
|
} catch (Exception ignore) {
|
||||||
|
return INET_LOOPBACK_UNAVAILABLE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private UnixTestUtils() { }
|
private UnixTestUtils() { }
|
||||||
}
|
}
|
||||||
|
@ -59,7 +59,15 @@ public class Socket extends FileDescriptor {
|
|||||||
* Returns {@code true} if we should use IPv6 internally, {@code false} otherwise.
|
* Returns {@code true} if we should use IPv6 internally, {@code false} otherwise.
|
||||||
*/
|
*/
|
||||||
private boolean useIpv6(InetAddress address) {
|
private boolean useIpv6(InetAddress address) {
|
||||||
return ipv6 || address instanceof Inet6Address;
|
return useIpv6(this, address);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns {@code true} if the given socket and address combination should use IPv6 internally,
|
||||||
|
* {@code false} otherwise.
|
||||||
|
*/
|
||||||
|
protected static boolean useIpv6(Socket socket, InetAddress address) {
|
||||||
|
return socket.ipv6 || address instanceof Inet6Address;
|
||||||
}
|
}
|
||||||
|
|
||||||
public final void shutdown() throws IOException {
|
public final void shutdown() throws IOException {
|
||||||
|
Loading…
Reference in New Issue
Block a user