1 /* 2 * Copyright (c) 2019, 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.ServerSocket; 33 import java.net.Socket; 34 import java.net.SocketException; 35 import java.net.UnknownHostException; 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 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 if (!preferIPv4Stack && !hasIPv4 && !hasIPv6) { 68 throw new AssertionError("IPv4 and IPv6 both not available and java.net.preferIPv4Stack is not true"); 69 } 70 } 71 72 private static boolean hasAddress(InetAddress address) { 73 try (Socket socket = new Socket()) { 74 socket.bind(new InetSocketAddress(address, 0)); 75 return true; 76 } catch (SocketException se) { 77 return false; 78 } catch (IOException e) { 79 throw new UncheckedIOException(e); 80 } 81 } 82 83 private static <T> T runPrivilegedAction(Callable<T> callable) { 84 try { 85 PrivilegedExceptionAction<T> pa = () -> callable.call(); 86 return AccessController.doPrivileged(pa); 87 } catch (PrivilegedActionException pae) { 88 throw new UncheckedIOException((IOException) pae.getCause()); 89 } 90 } 91 92 private IPSupport() { } 93 94 /** 95 * Whether or not IPv4 is supported. 96 */ 97 public static final boolean hasIPv4() { 98 return hasIPv4; 99 } 100 101 /** 102 * Whether or not IPv6 is supported. 103 */ 104 public static final boolean hasIPv6() { 105 return hasIPv6; 106 } 107 108 /** 109 * Whether or not the "java.net.preferIPv4Stack" system property is set. 110 */ 111 public static final boolean preferIPv4Stack() { 112 return preferIPv4Stack; 113 } 114 115 116 /** 117 * Whether or not the current networking configuration is valid or not. 118 * 119 * If preferIPv4Stack is true but there is no IPv4 support, the configuration is invalid. 120 */ 121 public static final boolean currentConfigurationIsValid() { 122 return hasIPv4() || hasIPv6(); 123 } 124 125 /** 126 * Ensures that the platform supports the ability to create a 127 * minimally-operational socket whose protocol is either one of IPv4 128 * or IPv6. 129 * 130 * <p> A minimally-operation socket is one that can be created and 131 * bound to an IP-specific loopback address. IP support is 132 * considered non-operational if a socket cannot be bound to either 133 * one of, an IPv4 loopback address, or the IPv6 loopback address. 134 * 135 * @throws SkippedException if the current networking configuration 136 * is non-operational 137 */ 138 public static void throwSkippedExceptionIfNonOperational() throws SkippedException { 139 if (!currentConfigurationIsValid()) { 140 ByteArrayOutputStream os = new ByteArrayOutputStream(); 141 PrintStream ps = new PrintStream(os); 142 ps.println("Invalid networking configuration"); 143 printPlatformSupport(ps); 144 throw new SkippedException(os.toString()); 145 } 146 } 147 148 /** 149 * Prints the platform supported configurations. 150 */ 151 public static void printPlatformSupport(PrintStream out) { 152 out.println("IPSupport - IPv4: " + hasIPv4()); 153 out.println("IPSupport - IPv6: " + hasIPv6()); 154 out.println("preferIPv4Stack: " + preferIPv4Stack()); 155 } 156 157 }