1 /* 2 * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 */ 23 24 package jdk.test.lib; 25 26 import java.io.PrintStream; 27 import java.io.UncheckedIOException; 28 import java.io.IOException; 29 import java.net.Inet4Address; 30 import java.net.Inet6Address; 31 import java.net.InetAddress; 32 import java.net.NetworkInterface; 33 import java.util.Arrays; 34 import java.util.HashMap; 35 import java.util.LinkedList; 36 import java.util.List; 37 import java.util.Map; 38 import java.util.function.Predicate; 39 import java.util.stream.Collectors; 40 import java.util.stream.Stream; 41 import static java.net.NetworkInterface.getNetworkInterfaces; 42 import static java.util.Collections.list; 43 44 /** 45 * Helper class for retrieving network interfaces and local addresses 46 * suitable for testing. 47 */ 48 public class NetworkConfiguration { 49 50 private Map<NetworkInterface,List<Inet4Address>> ip4Interfaces; 51 private Map<NetworkInterface,List<Inet6Address>> ip6Interfaces; 52 53 private NetworkConfiguration( 54 Map<NetworkInterface,List<Inet4Address>> ip4Interfaces, 55 Map<NetworkInterface,List<Inet6Address>> ip6Interfaces) { 56 this.ip4Interfaces = ip4Interfaces; 57 this.ip6Interfaces = ip6Interfaces; 58 } 59 60 /** 61 * Returns a stream of interfaces suitable for functional tests. 62 */ 63 public Stream<NetworkInterface> interfaces() { 64 return Stream.concat(ip4Interfaces(), ip6Interfaces()) 65 .distinct(); 66 } 67 68 /** 69 * Returns a stream of interfaces suitable for IPv4 functional tests. 70 */ 71 public Stream<NetworkInterface> ip4Interfaces() { 72 return ip4Interfaces.keySet() 73 .stream() 74 .filter(NetworkConfiguration::isNotExcludedInterface) 75 .filter(hasIp4Addresses); 76 } 77 78 /** 79 * Returns a stream of interfaces suitable for IPv6 functional tests. 80 */ 81 public Stream<NetworkInterface> ip6Interfaces() { 82 return ip6Interfaces.keySet() 83 .stream() 84 .filter(NetworkConfiguration::isNotExcludedInterface) 85 .filter(hasIp6Addresses); 86 } 87 88 private static boolean isNotExcludedInterface(NetworkInterface nif) { 89 if (Platform.isOSX() && nif.getName().contains("awdl")) { 90 return false; 91 } 92 String dName = nif.getDisplayName(); 93 if (Platform.isWindows() && dName != null && dName.contains("Teredo")) { 94 return false; 95 } 96 return true; 97 } 98 99 private final Predicate<NetworkInterface> hasIp4Addresses = nif -> 100 ip4Interfaces.get(nif).stream().anyMatch(a -> !a.isAnyLocalAddress()); 101 102 private final Predicate<NetworkInterface> hasIp6Addresses = nif -> 103 ip6Interfaces.get(nif).stream().anyMatch(a -> !a.isAnyLocalAddress()); 104 105 106 /** 107 * Returns a stream of interfaces suitable for IPv4 multicast tests. 108 */ 109 public Stream<NetworkInterface> ip4MulticastInterfaces() { 110 return ip4Interfaces().filter(supportsIp4Multicast); 111 } 112 113 /** 114 * Returns a stream of interfaces suitable for IPv6 multicast tests. 115 */ 116 public Stream<NetworkInterface> ip6MulticastInterfaces() { 117 return ip6Interfaces().filter(supportsIp6Multicast); 118 } 119 120 private final Predicate<NetworkInterface> supportsIp4Multicast = nif -> { 121 try { 122 if (!nif.supportsMulticast() || nif.isLoopback()) { 123 return false; 124 } 125 return hasIp4Addresses.test(nif); 126 } catch (IOException e) { 127 throw new UncheckedIOException(e); 128 } 129 }; 130 131 private final Predicate<NetworkInterface> supportsIp6Multicast = nif -> { 132 try { 133 if (!nif.supportsMulticast() || nif.isLoopback()) { 134 return false; 135 } 136 137 return hasIp6Addresses.test(nif); 138 } catch (IOException e) { 139 throw new UncheckedIOException(e); 140 } 141 }; 142 143 /** 144 * Returns all addresses on all "functional" interfaces. 145 */ 146 public Stream<InetAddress> addresses(NetworkInterface nif) { 147 return Stream.concat(ip4Interfaces.get(nif).stream(), 148 ip6Interfaces.get(nif).stream()); 149 } 150 151 /** 152 * Returns all IPv4 addresses on all "functional" interfaces. 153 */ 154 public Stream<Inet4Address> ip4Addresses() { 155 return ip4Interfaces().flatMap(this::ip4Addresses); 156 } 157 158 /** 159 * Returns all IPv6 addresses on all "functional" interfaces. 160 */ 161 public Stream<Inet6Address> ip6Addresses() { 162 return ip6Interfaces().flatMap(this::ip6Addresses); 163 } 164 165 /** 166 * Returns all IPv4 addresses the given interface. 167 */ 168 public Stream<Inet4Address> ip4Addresses(NetworkInterface nif) { 169 return ip4Interfaces.get(nif).stream(); 170 } 171 172 /** 173 * Returns all IPv6 addresses for the given interface. 174 */ 175 public Stream<Inet6Address> ip6Addresses(NetworkInterface nif) { 176 return ip6Interfaces.get(nif).stream(); 177 } 178 179 /** 180 * Return a NetworkConfiguration instance. 181 */ 182 public static NetworkConfiguration probe() throws IOException { 183 Map<NetworkInterface, List<Inet4Address>> ip4Interfaces = new HashMap<>(); 184 Map<NetworkInterface, List<Inet6Address>> ip6Interfaces = new HashMap<>(); 185 186 List<NetworkInterface> nifs = list(getNetworkInterfaces()); 187 for (NetworkInterface nif : nifs) { 188 // ignore interfaces that are down 189 if (!nif.isUp() || nif.isPointToPoint()) { 190 continue; 191 } 192 193 List<Inet4Address> ip4Addresses = new LinkedList<>(); 194 List<Inet6Address> ip6Addresses = new LinkedList<>(); 195 ip4Interfaces.put(nif, ip4Addresses); 196 ip6Interfaces.put(nif, ip6Addresses); 197 for (InetAddress addr : list(nif.getInetAddresses())) { 198 if (addr instanceof Inet4Address) { 199 ip4Addresses.add((Inet4Address) addr); 200 } else if (addr instanceof Inet6Address) { 201 ip6Addresses.add((Inet6Address) addr); 202 } 203 } 204 } 205 return new NetworkConfiguration(ip4Interfaces, ip6Interfaces); 206 } 207 208 @Override 209 public String toString() { 210 return interfaces().map(NetworkConfiguration::interfaceInformation) 211 .collect(Collectors.joining()); 212 } 213 214 /** Returns detailed information for the given interface. */ 215 public static String interfaceInformation(NetworkInterface nif) { 216 StringBuilder sb = new StringBuilder(); 217 try { 218 sb.append("Display name: ") 219 .append(nif.getDisplayName()) 220 .append("\n"); 221 sb.append("Name: ") 222 .append(nif.getName()) 223 .append("\n"); 224 for (InetAddress inetAddress : list(nif.getInetAddresses())) { 225 sb.append("InetAddress: ") 226 .append(inetAddress) 227 .append("\n"); 228 } 229 sb.append("Up? ") 230 .append(nif.isUp()) 231 .append("\n"); 232 sb.append("Loopback? ") 233 .append(nif.isLoopback()) 234 .append("\n"); 235 sb.append("PointToPoint? ") 236 .append(nif.isPointToPoint()) 237 .append("\n"); 238 sb.append("Supports multicast? ") 239 .append(nif.supportsMulticast()) 240 .append("\n"); 241 sb.append("Virtual? ") 242 .append(nif.isVirtual()) 243 .append("\n"); 244 sb.append("Hardware address: ") 245 .append(Arrays.toString(nif.getHardwareAddress())) 246 .append("\n"); 247 sb.append("MTU: ") 248 .append(nif.getMTU()) 249 .append("\n"); 250 sb.append("Index: ") 251 .append(nif.getIndex()) 252 .append("\n"); 253 sb.append("\n"); 254 return sb.toString(); 255 } catch (IOException e) { 256 throw new UncheckedIOException(e); 257 } 258 } 259 260 /** Prints all the system interface information to the give stream. */ 261 public static void printSystemConfiguration(PrintStream out) { 262 try { 263 out.println("*** all system network interface configuration ***"); 264 for (NetworkInterface nif : list(getNetworkInterfaces())) { 265 out.print(interfaceInformation(nif)); 266 } 267 out.println("*** end ***"); 268 } catch (IOException e) { 269 throw new UncheckedIOException(e); 270 } 271 } 272 }