8223214: Inet6AddressImpl.loopbackAddress() should choose loopback address that is available
authoraeubanks
Wed, 15 May 2019 09:15:59 -0700
changeset 54945 cc92a45f4c73
parent 54944 9f714ef845d5
child 54946 b7c408df5008
child 54947 69d1dff1bb70
8223214: Inet6AddressImpl.loopbackAddress() should choose loopback address that is available Reviewed-by: chegar Contributed-by: aeubanks@google.com
src/java.base/share/classes/java/net/Inet6AddressImpl.java
--- a/src/java.base/share/classes/java/net/Inet6AddressImpl.java	Mon May 20 12:24:05 2019 -0400
+++ b/src/java.base/share/classes/java/net/Inet6AddressImpl.java	Wed May 15 09:15:59 2019 -0700
@@ -32,9 +32,13 @@
  * Package private implementation of InetAddressImpl for dual
  * IPv4/IPv6 stack.
  * <p>
- * If InetAddress.preferIPv6Address is true then anyLocalAddress(),
- * loopbackAddress(), and localHost() will return IPv6 addresses,
- * otherwise IPv4 addresses.
+ * If InetAddress.preferIPv6Address is true then anyLocalAddress()
+ * and localHost() will return IPv6 addresses, otherwise IPv4 addresses.
+ *
+ * loopbackAddress() will return the first valid loopback address in
+ * [IPv6 loopback, IPv4 loopback] if InetAddress.preferIPv6Address is true,
+ * else [IPv4 loopback, IPv6 loopback].
+ * If neither are valid it will fallback to the first address tried.
  *
  * @since 1.4
  */
@@ -103,15 +107,31 @@
 
     public synchronized InetAddress loopbackAddress() {
         if (loopbackAddress == null) {
-             if (InetAddress.preferIPv6Address == PREFER_IPV6_VALUE ||
-                 InetAddress.preferIPv6Address == PREFER_SYSTEM_VALUE) {
-                 byte[] loopback =
-                        {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-                         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01};
-                 loopbackAddress = new Inet6Address("localhost", loopback);
-             } else {
-                loopbackAddress = (new Inet4AddressImpl()).loopbackAddress();
-             }
+            boolean preferIPv6Address =
+                InetAddress.preferIPv6Address == PREFER_IPV6_VALUE ||
+                InetAddress.preferIPv6Address == PREFER_SYSTEM_VALUE;
+            InetAddress loopback4 = (new Inet4AddressImpl()).loopbackAddress();
+            InetAddress loopback6 = new Inet6Address("localhost",
+                new byte[] {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01});
+            // Order the candidate addresses by preference.
+            InetAddress[] addresses = preferIPv6Address
+                ? new InetAddress[] {loopback6, loopback4}
+                : new InetAddress[] {loopback4, loopback6};
+            // In case of failure, default to the preferred address.
+            loopbackAddress = addresses[0];
+            // Pick the first candidate address that actually exists.
+            for (InetAddress address : addresses) {
+                try {
+                    if (NetworkInterface.getByInetAddress(address) == null) {
+                        continue;
+                    }
+                } catch (SocketException e) {
+                    continue;
+                }
+                loopbackAddress = address;
+                break;
+            }
         }
         return loopbackAddress;
     }