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