8241336: Some java.net tests failed with NoRouteToHostException on MacOS with special network configuration

NetworkConfiguration updated to skip interfaces that have only IPv6 link local addresses.

Reviewed-by: alanb, chegar
This commit is contained in:
Daniel Fuchs 2020-03-27 12:42:03 +00:00
parent bb7a8f643f
commit 5ddbcb7a51
5 changed files with 114 additions and 52 deletions

View file

@ -620,11 +620,6 @@ javax/management/remote/mandatory/notif/NotifReconnectDeadlockTest.java 8042215
# jdk_net # jdk_net
java/net/InetAddress/CheckJNI.java 8241336 macosx-all
java/net/Socket/LinkLocal.java 8241336 macosx-all
java/net/MulticastSocket/SetOutgoingIf.java 8241336 macosx-all
java/net/MulticastSocket/Promiscuous.java 8241336 macosx-all
java/net/MulticastSocket/NoLoopbackPackets.java 7122846 macosx-all java/net/MulticastSocket/NoLoopbackPackets.java 7122846 macosx-all
java/net/MulticastSocket/SetLoopbackMode.java 7122846 macosx-all java/net/MulticastSocket/SetLoopbackMode.java 7122846 macosx-all
@ -643,9 +638,6 @@ java/net/ServerSocket/AcceptInheritHandle.java 8211854 aix-ppc6
java/nio/Buffer/EqualsCompareTest.java 8193917 solaris-all java/nio/Buffer/EqualsCompareTest.java 8193917 solaris-all
java/nio/channels/DatagramChannel/MulticastSendReceiveTests.java 8241336 macosx-all
java/nio/channels/DatagramChannel/AdaptorMulticasting.java 8241336 macosx-all
java/nio/channels/DatagramChannel/ChangingAddress.java 7141822 macosx-all java/nio/channels/DatagramChannel/ChangingAddress.java 7141822 macosx-all
java/nio/channels/DatagramChannel/Unref.java 8233519 generic-all java/nio/channels/DatagramChannel/Unref.java 8233519 generic-all

View file

@ -32,7 +32,11 @@
import java.io.IOException; import java.io.IOException;
import static java.lang.System.out; import static java.lang.System.out;
import java.io.UncheckedIOException;
import java.net.*; import java.net.*;
import jdk.test.lib.NetworkConfiguration;
import jdk.test.lib.net.IPSupport; import jdk.test.lib.net.IPSupport;
public class Promiscuous { public class Promiscuous {
@ -69,8 +73,9 @@ public class Promiscuous {
} }
} catch (SocketTimeoutException e) { } catch (SocketTimeoutException e) {
if (datagramExpected) if (datagramExpected)
throw new RuntimeException("Expected message not received, " throw new RuntimeException(mc.getLocalSocketAddress()
+ e.getMessage()); + ": Expected message not received, "
+ e.getMessage());
else else
out.printf("Message not received, as expected\n"); out.printf("Message not received, as expected\n");
} }
@ -90,6 +95,10 @@ public class Promiscuous {
UUID = "<" + s1 + s2 + ">"; UUID = "<" + s1 + s2 + ">";
} }
static SocketAddress toSocketAddress(InetAddress group) {
return new InetSocketAddress(group, 0);
}
static void test(InetAddress group1, InetAddress group2) static void test(InetAddress group1, InetAddress group2)
throws IOException throws IOException
{ {
@ -107,10 +116,21 @@ public class Promiscuous {
p.setAddress(group1); p.setAddress(group1);
p.setPort(port); p.setPort(port);
mc1.joinGroup(group1); // join groups on all network interfaces
out.printf("mc1 joined the MC group: %s\n", group1); NetworkConfiguration.probe()
mc2.joinGroup(group2); .multicastInterfaces(false)
out.printf("mc2 joined the MC group: %s\n", group2); .forEach((nic) -> {
try {
mc1.joinGroup(toSocketAddress(group1), nic);
out.printf("mc1 joined the MC group on %s: %s\n",
nic.getDisplayName(), group1);
mc2.joinGroup(toSocketAddress(group2), nic);
out.printf("mc2 joined the MC group on %s: %s\n",
nic.getDisplayName(), group2);
} catch (IOException io) {
throw new UncheckedIOException(io);
}
});
out.printf("Sending datagram to: %s/%d\n", group1, port); out.printf("Sending datagram to: %s/%d\n", group1, port);
ds.send(p); ds.send(p);
@ -132,8 +152,21 @@ public class Promiscuous {
receive(mc2, true, nextId); receive(mc2, true, nextId);
receive(mc1, false, 0); receive(mc1, false, 0);
mc1.leaveGroup(group1); // leave groups on all network interfaces
mc2.leaveGroup(group2); NetworkConfiguration.probe()
.multicastInterfaces(false)
.forEach((nic) -> {
try {
mc1.leaveGroup(toSocketAddress(group1), nic);
out.printf("mc1 left the MC group on %s: %s\n",
nic.getDisplayName(), group1);
mc2.leaveGroup(toSocketAddress(group2), nic);
out.printf("mc2 left the MC group on %s: %s\n",
nic.getDisplayName(), group2);
} catch (IOException io) {
throw new UncheckedIOException(io);
}
});
} }
} }
@ -155,8 +188,8 @@ public class Promiscuous {
} }
// multicast groups used for the test // multicast groups used for the test
InetAddress ip4Group1 = InetAddress.getByName("224.0.0.120"); InetAddress ip4Group1 = InetAddress.getByName("224.1.1.120");
InetAddress ip4Group2 = InetAddress.getByName("224.0.0.121"); InetAddress ip4Group2 = InetAddress.getByName("224.1.1.121");
test(ip4Group1, ip4Group2); test(ip4Group1, ip4Group2);
} }

View file

@ -24,15 +24,27 @@
/* /*
* @test * @test
* @bug 4742177 * @bug 4742177
* @library /test/lib
* @summary Re-test IPv6 (and specifically MulticastSocket) with latest Linux & USAGI code * @summary Re-test IPv6 (and specifically MulticastSocket) with latest Linux & USAGI code
*/ */
import java.io.IOException;
import java.net.*; import java.net.*;
import java.util.*; import java.util.*;
import jdk.test.lib.NetworkConfiguration;
public class SetOutgoingIf { public class SetOutgoingIf implements AutoCloseable {
private static int PORT = 9001;
private static String osname; private static String osname;
private final MulticastSocket SOCKET;
private final int PORT;
private SetOutgoingIf() {
try {
SOCKET = new MulticastSocket();
PORT = SOCKET.getLocalPort();
} catch (IOException io) {
throw new ExceptionInInitializerError(io);
}
}
static boolean isWindows() { static boolean isWindows() {
if (osname == null) if (osname == null)
@ -45,20 +57,24 @@ public class SetOutgoingIf {
} }
private static boolean hasIPv6() throws Exception { private static boolean hasIPv6() throws Exception {
List<NetworkInterface> nics = Collections.list( return NetworkConfiguration.probe()
NetworkInterface.getNetworkInterfaces()); .ip6Addresses()
for (NetworkInterface nic : nics) { .findAny()
List<InetAddress> addrs = Collections.list(nic.getInetAddresses()); .isPresent();
for (InetAddress addr : addrs) {
if (addr instanceof Inet6Address)
return true;
}
}
return false;
} }
public static void main(String[] args) throws Exception { public static void main(String[] args) throws Exception {
try (var test = new SetOutgoingIf()) {
test.run();
}
}
@Override
public void close() {
SOCKET.close();
}
public void run() throws Exception {
if (isWindows()) { if (isWindows()) {
System.out.println("The test only run on non-Windows OS. Bye."); System.out.println("The test only run on non-Windows OS. Bye.");
return; return;
@ -99,11 +115,14 @@ public class SetOutgoingIf {
System.out.println("Ignore NetworkInterface nic == " + nic); System.out.println("Ignore NetworkInterface nic == " + nic);
} }
} }
Collections.reverse(netIfs);
if (netIfs.size() <= 1) { if (netIfs.size() <= 1) {
System.out.println("Need 2 or more network interfaces to run. Bye."); System.out.println("Need 2 or more network interfaces to run. Bye.");
return; return;
} }
System.out.println("Using PORT: " + PORT);
// We will send packets to one ipv4, and one ipv6 // We will send packets to one ipv4, and one ipv6
// multicast group using each network interface :- // multicast group using each network interface :-
// 224.1.1.1 --| // 224.1.1.1 --|
@ -177,12 +196,8 @@ public class SetOutgoingIf {
} }
private static boolean isTestExcludedInterface(NetworkInterface nif) { private static boolean isTestExcludedInterface(NetworkInterface nif) {
if (isMacOS() && nif.getName().contains("awdl")) return !NetworkConfiguration.isTestable(nif)
return true; || isMacOS() && nif.getName().startsWith("utun");
String dName = nif.getDisplayName();
if (isWindows() && dName != null && dName.contains("Teredo"))
return true;
return false;
} }
private static boolean debug = true; private static boolean debug = true;
@ -281,4 +296,3 @@ class NetIf {
this.groups = groups; this.groups = groups;
} }
} }

View file

@ -43,6 +43,7 @@ import java.net.SocketException;
import java.net.SocketTimeoutException; import java.net.SocketTimeoutException;
import java.net.SocketOption; import java.net.SocketOption;
import java.nio.channels.DatagramChannel; import java.nio.channels.DatagramChannel;
import java.util.Arrays;
import java.util.List; import java.util.List;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import static java.net.StandardSocketOptions.*; import static java.net.StandardSocketOptions.*;
@ -427,7 +428,9 @@ public class AdaptorMulticasting {
assertTrue(s.getOption(IP_MULTICAST_IF) != null); assertTrue(s.getOption(IP_MULTICAST_IF) != null);
SocketAddress target = new InetSocketAddress(group, s.getLocalPort()); SocketAddress target = new InetSocketAddress(group, s.getLocalPort());
byte[] message = "hello".getBytes("UTF-8"); long nano = System.nanoTime();
String text = nano + ": hello";
byte[] message = text.getBytes("UTF-8");
// send datagram to multicast group // send datagram to multicast group
DatagramPacket p = new DatagramPacket(message, message.length); DatagramPacket p = new DatagramPacket(message, message.length);
@ -437,10 +440,18 @@ public class AdaptorMulticasting {
// datagram should not be received // datagram should not be received
s.setSoTimeout(500); s.setSoTimeout(500);
p = new DatagramPacket(new byte[1024], 100); p = new DatagramPacket(new byte[1024], 100);
try { while (true) {
s.receive(p); try {
assertTrue(false); s.receive(p);
} catch (SocketTimeoutException expected) { } if (Arrays.equals(p.getData(), p.getOffset(), p.getLength(), message, 0, message.length)) {
throw new RuntimeException("message shouldn't have been received");
} else {
System.out.println("Received unexpected message from " + p.getSocketAddress());
}
} catch (SocketTimeoutException expected) {
break;
}
}
} }

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2017, 2019, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2017, 2020, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -31,10 +31,11 @@ import java.net.Inet6Address;
import java.net.InetAddress; import java.net.InetAddress;
import java.net.NetworkInterface; import java.net.NetworkInterface;
import java.util.Arrays; import java.util.Arrays;
import java.util.HashMap; import java.util.LinkedHashMap;
import java.util.LinkedList; import java.util.LinkedList;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.function.Predicate;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import java.util.stream.Stream; import java.util.stream.Stream;
import java.security.AccessController; import java.security.AccessController;
@ -87,9 +88,20 @@ public class NetworkConfiguration {
}); });
} }
private static boolean isNotExcludedInterface(NetworkInterface nif) { private static boolean isIPv6LinkLocal(InetAddress a) {
if (Platform.isOSX() && nif.getName().contains("awdl")) { return Inet6Address.class.isInstance(a) && a.isLinkLocalAddress();
return false; }
public static boolean isTestable(NetworkInterface nif) {
if (Platform.isOSX()) {
if (nif.getName().contains("awdl")) {
return false; // exclude awdl
}
// filter out interfaces that only have link-local addresses
return nif.inetAddresses()
.filter(Predicate.not(NetworkConfiguration::isIPv6LinkLocal))
.findAny()
.isPresent();
} }
if (Platform.isWindows()) { if (Platform.isWindows()) {
String dName = nif.getDisplayName(); String dName = nif.getDisplayName();
@ -201,7 +213,7 @@ public class NetworkConfiguration {
public Stream<NetworkInterface> ip4Interfaces() { public Stream<NetworkInterface> ip4Interfaces() {
return ip4Interfaces.keySet() return ip4Interfaces.keySet()
.stream() .stream()
.filter(NetworkConfiguration::isNotExcludedInterface) .filter(NetworkConfiguration::isTestable)
.filter(this::hasIp4Addresses); .filter(this::hasIp4Addresses);
} }
@ -211,7 +223,7 @@ public class NetworkConfiguration {
public Stream<NetworkInterface> ip6Interfaces() { public Stream<NetworkInterface> ip6Interfaces() {
return ip6Interfaces.keySet() return ip6Interfaces.keySet()
.stream() .stream()
.filter(NetworkConfiguration::isNotExcludedInterface) .filter(NetworkConfiguration::isTestable)
.filter(this::hasIp6Addresses); .filter(this::hasIp6Addresses);
} }
@ -309,8 +321,8 @@ public class NetworkConfiguration {
* Return a NetworkConfiguration instance. * Return a NetworkConfiguration instance.
*/ */
public static NetworkConfiguration probe() throws IOException { public static NetworkConfiguration probe() throws IOException {
Map<NetworkInterface, List<Inet4Address>> ip4Interfaces = new HashMap<>(); Map<NetworkInterface, List<Inet4Address>> ip4Interfaces = new LinkedHashMap<>();
Map<NetworkInterface, List<Inet6Address>> ip6Interfaces = new HashMap<>(); Map<NetworkInterface, List<Inet6Address>> ip6Interfaces = new LinkedHashMap<>();
List<NetworkInterface> nifs = list(getNetworkInterfaces()); List<NetworkInterface> nifs = list(getNetworkInterfaces());
for (NetworkInterface nif : nifs) { for (NetworkInterface nif : nifs) {