1 /* 2 * Copyright (c) 2019, 2021, 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.net; 25 26 import java.io.ByteArrayOutputStream; 27 import java.io.IOException; 28 import java.io.PrintStream; 29 import java.io.UncheckedIOException; 30 import java.net.Inet4Address; 31 import java.net.Inet6Address; 32 import java.net.InetAddress; 33 import java.net.ProtocolFamily; 34 import java.net.StandardProtocolFamily; 35 import java.nio.channels.SocketChannel; 36 import java.security.AccessController; 37 import java.security.PrivilegedActionException; 38 import java.security.PrivilegedExceptionAction; 39 import java.util.concurrent.Callable; 40 import jtreg.SkippedException; 41 42 /** 43 * Determines Internet Protocol version support at the TCP socket level. 44 */ 45 public class IPSupport { 46 47 private static final boolean hasIPv4; 48 private static final boolean hasIPv6; 49 private static final boolean preferIPv4Stack; 50 private static final boolean preferIPv6Addresses; 51 52 static { 53 hasIPv4 = runPrivilegedAction(() -> isSupported(Inet4Address.class)); 54 hasIPv6 = runPrivilegedAction(() -> isSupported(Inet6Address.class)); 55 preferIPv4Stack = runPrivilegedAction(() -> Boolean.parseBoolean( 56 System.getProperty("java.net.preferIPv4Stack"))); 57 preferIPv6Addresses = runPrivilegedAction(() -> Boolean.parseBoolean( 58 System.getProperty("java.net.preferIPv6Addresses"))); 59 if (!preferIPv4Stack && !hasIPv4 && !hasIPv6) { 60 throw new AssertionError("IPv4 and IPv6 both not available and java.net.preferIPv4Stack is not true"); 61 } 62 } 63 64 private static boolean isSupported(Class<? extends InetAddress> addressType) { 65 ProtocolFamily family = addressType == Inet4Address.class ? 66 StandardProtocolFamily.INET : StandardProtocolFamily.INET6; 67 try (var sc = SocketChannel.open(family)) { 68 return true; 69 } catch (IOException | UnsupportedOperationException ex) { 70 return false; 71 } 72 } 73 74 private static <T> T runPrivilegedAction(Callable<T> callable) { 75 try { 76 PrivilegedExceptionAction<T> pa = () -> callable.call(); 77 return AccessController.doPrivileged(pa); 78 } catch (PrivilegedActionException pae) { 79 throw new UncheckedIOException((IOException) pae.getCause()); 80 } 81 } 82 83 private IPSupport() { } 84 85 /** 86 * Whether or not IPv4 is supported. 87 */ 88 public static final boolean hasIPv4() { 89 return hasIPv4; 90 } 91 92 /** 93 * Whether or not IPv6 is supported. 94 */ 95 public static final boolean hasIPv6() { 96 return hasIPv6; 97 } 98 99 /** 100 * Whether or not the "java.net.preferIPv4Stack" system property is set. 101 */ 102 public static final boolean preferIPv4Stack() { 103 return preferIPv4Stack; 104 } 105 106 /** 107 * Whether or not the "java.net.preferIPv6Addresses" system property is set. 108 */ 109 public static final boolean preferIPv6Addresses() { 110 return preferIPv6Addresses; 111 } 112 113 114 /** 115 * Whether or not the current networking configuration is valid or not. 116 * 117 * If preferIPv4Stack is true but there is no IPv4 support, the configuration is invalid. 118 */ 119 public static final boolean currentConfigurationIsValid() { 120 return hasIPv4() || hasIPv6(); 121 } 122 123 /** 124 * Ensures that the platform supports the ability to create a 125 * minimally-operational socket whose protocol is either one of IPv4 126 * or IPv6. 127 * 128 * <p> A minimally-operation socket is one that can be created and 129 * bound to an IP-specific loopback address. IP support is 130 * considered non-operational if a socket cannot be bound to either 131 * one of, an IPv4 loopback address, or the IPv6 loopback address. 132 * 133 * @throws SkippedException if the current networking configuration 134 * is non-operational 135 */ 136 public static void throwSkippedExceptionIfNonOperational() throws SkippedException { 137 if (!currentConfigurationIsValid()) { 138 ByteArrayOutputStream os = new ByteArrayOutputStream(); 139 PrintStream ps = new PrintStream(os); 140 ps.println("Invalid networking configuration"); 141 printPlatformSupport(ps); 142 throw new SkippedException(os.toString()); 143 } 144 } 145 146 /** 147 * Prints the platform supported configurations. 148 */ 149 public static void printPlatformSupport(PrintStream out) { 150 out.println("IPSupport - IPv4: " + hasIPv4()); 151 out.println("IPSupport - IPv6: " + hasIPv6()); 152 out.println("preferIPv4Stack: " + preferIPv4Stack()); 153 out.println("preferIPv6Addresses: " + preferIPv6Addresses()); 154 } 155 156 } --- EOF ---