src/java.base/share/classes/sun/net/util/IPAddressUtil.java
changeset 55375 96c7427456f9
parent 52499 768b1c612100
child 55711 0c143aaa2c99
equal deleted inserted replaced
55374:5c4f1b7c753b 55375:96c7427456f9
    22  * or visit www.oracle.com if you need additional information or have any
    22  * or visit www.oracle.com if you need additional information or have any
    23  * questions.
    23  * questions.
    24  */
    24  */
    25 
    25 
    26 package sun.net.util;
    26 package sun.net.util;
       
    27 
       
    28 import java.io.IOException;
       
    29 import java.io.UncheckedIOException;
       
    30 import java.net.Inet6Address;
       
    31 import java.net.InetAddress;
       
    32 import java.net.InetSocketAddress;
       
    33 import java.net.NetworkInterface;
       
    34 import java.net.SocketException;
       
    35 import java.security.AccessController;
       
    36 import java.security.PrivilegedExceptionAction;
       
    37 import java.security.PrivilegedActionException;
       
    38 import java.util.List;
       
    39 import java.util.concurrent.ConcurrentHashMap;
       
    40 import java.util.stream.Collectors;
    27 
    41 
    28 public class IPAddressUtil {
    42 public class IPAddressUtil {
    29     private static final int INADDR4SZ = 4;
    43     private static final int INADDR4SZ = 4;
    30     private static final int INADDR16SZ = 16;
    44     private static final int INADDR16SZ = 16;
    31     private static final int INT16SZ = 2;
    45     private static final int INT16SZ = 2;
   285             (addr[11] == (byte)0xff))  {
   299             (addr[11] == (byte)0xff))  {
   286             return true;
   300             return true;
   287         }
   301         }
   288         return false;
   302         return false;
   289     }
   303     }
       
   304     /**
       
   305      * Mapping from unscoped local Inet(6)Address to the same address
       
   306      * including the correct scope-id, determined from NetworkInterface.
       
   307      */
       
   308     private final static ConcurrentHashMap<InetAddress,InetAddress>
       
   309         cache = new ConcurrentHashMap<>();
       
   310 
       
   311     /**
       
   312      * Returns a scoped version of the supplied local, link-local ipv6 address
       
   313      * if that scope-id can be determined from local NetworkInterfaces.
       
   314      * If the address already has a scope-id or if the address is not local, ipv6
       
   315      * or link local, then the original address is returned.
       
   316      *
       
   317      * @param addr
       
   318      * @exception SocketException if the given ipv6 link local address is found
       
   319      *            on more than one local interface
       
   320      * @return
       
   321      */
       
   322     public static InetAddress toScopedAddress(InetAddress address)
       
   323         throws SocketException {
       
   324 
       
   325         if (address instanceof Inet6Address && address.isLinkLocalAddress()
       
   326             && ((Inet6Address) address).getScopeId() == 0) {
       
   327 
       
   328             InetAddress cached = null;
       
   329             try {
       
   330                 cached = cache.computeIfAbsent(address, k -> findScopedAddress(k));
       
   331             } catch (UncheckedIOException e) {
       
   332                 throw (SocketException)e.getCause();
       
   333             }
       
   334             return cached != null ? cached : address;
       
   335         } else {
       
   336             return address;
       
   337         }
       
   338     }
       
   339 
       
   340     /**
       
   341      * Same as above for InetSocketAddress
       
   342      */
       
   343     public static InetSocketAddress toScopedAddress(InetSocketAddress address)
       
   344         throws SocketException {
       
   345         InetAddress addr;
       
   346         InetAddress orig = address.getAddress();
       
   347         if ((addr = toScopedAddress(orig)) == orig) {
       
   348             return address;
       
   349         } else {
       
   350             return new InetSocketAddress(addr, address.getPort());
       
   351         }
       
   352     }
       
   353 
       
   354     private static InetAddress findScopedAddress(InetAddress address) {
       
   355         PrivilegedExceptionAction<List<InetAddress>> pa = () -> NetworkInterface.networkInterfaces()
       
   356                 .flatMap(NetworkInterface::inetAddresses)
       
   357                 .filter(a -> (a instanceof Inet6Address)
       
   358                         && address.equals(a)
       
   359                         && ((Inet6Address) a).getScopeId() != 0)
       
   360                 .collect(Collectors.toList());
       
   361         List<InetAddress> result;
       
   362         try {
       
   363             result = AccessController.doPrivileged(pa);
       
   364             var sz = result.size();
       
   365             if (sz == 0)
       
   366                 return null;
       
   367             if (sz > 1)
       
   368                 throw new UncheckedIOException(new SocketException(
       
   369                     "Duplicate link local addresses: must specify scope-id"));
       
   370             return result.get(0);
       
   371         } catch (PrivilegedActionException pae) {
       
   372             return null;
       
   373         }
       
   374     }
   290 }
   375 }