1 /*
   2  * Copyright (c) 2001, 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.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package sun.nio.ch;
  27 
  28 import java.io.IOException;
  29 import java.lang.invoke.MethodHandle;
  30 import java.lang.invoke.MethodHandles;
  31 import java.lang.invoke.MethodHandles.Lookup;
  32 import java.lang.invoke.MethodType;
  33 import java.lang.invoke.VarHandle;
  34 import java.net.DatagramPacket;
  35 import java.net.DatagramSocket;
  36 import java.net.InetAddress;
  37 import java.net.InetSocketAddress;
  38 import java.net.NetworkInterface;
  39 import java.net.MulticastSocket;
  40 import java.net.SocketAddress;
  41 import java.net.SocketException;
  42 import java.net.SocketOption;
  43 import java.net.StandardSocketOptions;
  44 import java.nio.ByteBuffer;
  45 import java.nio.channels.AlreadyConnectedException;
  46 import java.nio.channels.ClosedChannelException;
  47 import java.nio.channels.DatagramChannel;
  48 import java.nio.channels.MembershipKey;
  49 import java.security.AccessController;
  50 import java.security.PrivilegedAction;
  51 import java.security.PrivilegedExceptionAction;
  52 import java.util.Objects;
  53 import java.util.Set;
  54 import java.util.concurrent.locks.ReentrantLock;
  55 
  56 import static java.util.concurrent.TimeUnit.MILLISECONDS;
  57 
  58 /**
  59  * A multicast datagram socket based on a datagram channel.
  60  *
  61  * This class overrides every public method defined by java.net.DatagramSocket
  62  * and java.net.MulticastSocket. The methods in this class are defined in exactly
  63  * the same order as in java.net.DatagramSocket and java.net.MulticastSocket so
  64  * as to simplify tracking changes.
  65  */
  66 public class DatagramSocketAdaptor
  67     extends MulticastSocket
  68 {
  69     // The channel being adapted
  70     private final DatagramChannelImpl dc;
  71 
  72     // Timeout "option" value for receives
  73     private volatile int timeout;
  74 
  75     private DatagramSocketAdaptor(DatagramChannelImpl dc) throws IOException {
  76         super(/*SocketAddress*/null);
  77         this.dc = dc;
  78     }
  79 
  80     static DatagramSocket create(DatagramChannelImpl dc) {
  81         try {
  82             return new DatagramSocketAdaptor(dc);
  83         } catch (IOException e) {
  84             throw new Error(e);
  85         }
  86     }
  87 
  88     private void connectInternal(SocketAddress remote) throws SocketException {
  89         try {
  90             dc.connect(remote, false); // skips check for already connected
  91         } catch (ClosedChannelException e) {
  92             // ignore
  93         } catch (Exception x) {
  94             Net.translateToSocketException(x);
  95         }
  96     }
  97 
  98     @Override
  99     public void bind(SocketAddress local) throws SocketException {
 100         if (local != null) {
 101             local = Net.asInetSocketAddress(local);
 102         } else {
 103             local = new InetSocketAddress(0);
 104         }
 105         try {
 106             dc.bind(local);
 107         } catch (Exception x) {
 108             Net.translateToSocketException(x);
 109         }
 110     }
 111 
 112     @Override
 113     public void connect(InetAddress address, int port) {
 114         if (address == null)
 115             throw new IllegalArgumentException("Address can't be null");
 116         try {
 117             connectInternal(new InetSocketAddress(address, port));
 118         } catch (SocketException x) {
 119             throw new Error(x);
 120         }
 121     }
 122 
 123     @Override
 124     public void connect(SocketAddress remote) throws SocketException {
 125         if (remote == null)
 126             throw new IllegalArgumentException("Address can't be null");
 127         connectInternal(Net.asInetSocketAddress(remote));
 128     }
 129 
 130     @Override
 131     public void disconnect() {
 132         try {
 133             dc.disconnect();
 134         } catch (IOException x) {
 135             throw new Error(x);
 136         }
 137     }
 138 
 139     @Override
 140     public boolean isBound() {
 141         return dc.localAddress() != null;
 142     }
 143 
 144     @Override
 145     public boolean isConnected() {
 146         return dc.remoteAddress() != null;
 147     }
 148 
 149     @Override
 150     public InetAddress getInetAddress() {
 151         InetSocketAddress remote = dc.remoteAddress();
 152         return (remote != null) ? remote.getAddress() : null;
 153     }
 154 
 155     @Override
 156     public int getPort() {
 157         InetSocketAddress remote = dc.remoteAddress();
 158         return (remote != null) ? remote.getPort() : -1;
 159     }
 160 
 161     @Override
 162     public SocketAddress getRemoteSocketAddress() {
 163         return dc.remoteAddress();
 164     }
 165 
 166     @Override
 167     public SocketAddress getLocalSocketAddress() {
 168         try {
 169             return dc.getLocalAddress();
 170         } catch (ClosedChannelException e) {
 171             return null;
 172         } catch (Exception x) {
 173             throw new Error(x);
 174         }
 175     }
 176 
 177     @Override
 178     public void send(DatagramPacket p) throws IOException {
 179         ByteBuffer bb = null;
 180         try {
 181             InetSocketAddress target;
 182             synchronized (p) {
 183                 // copy bytes to temporary direct buffer
 184                 int len = p.getLength();
 185                 bb = Util.getTemporaryDirectBuffer(len);
 186                 bb.put(p.getData(), p.getOffset(), len);
 187                 bb.flip();
 188 
 189                 // target address
 190                 if (p.getAddress() == null) {
 191                     InetSocketAddress remote = dc.remoteAddress();
 192                     if (remote == null) {
 193                         // not specified by DatagramSocket
 194                         throw new IllegalArgumentException("Address not set");
 195                     }
 196                     // set address/port to maintain compatibility with DatagramSocket
 197                     p.setAddress(remote.getAddress());
 198                     p.setPort(remote.getPort());
 199                     target = remote;
 200                 } else {
 201                     // throws IllegalArgumentException if port not set
 202                     target = (InetSocketAddress) p.getSocketAddress();
 203                 }
 204             }
 205             // send datagram
 206             try {
 207                 dc.blockingSend(bb, target);
 208             } catch (AlreadyConnectedException e) {
 209                 throw new IllegalArgumentException("Connected and packet address differ");
 210             } catch (ClosedChannelException e) {
 211                 var exc = new SocketException("Socket closed");
 212                 exc.initCause(e);
 213                 throw exc;
 214             }
 215         } finally {
 216             if (bb != null) {
 217                 Util.offerFirstTemporaryDirectBuffer(bb);
 218             }
 219         }
 220     }
 221 
 222     @Override
 223     public void receive(DatagramPacket p) throws IOException {
 224         // get temporary direct buffer with a capacity of p.bufLength
 225         int bufLength = DatagramPackets.getBufLength(p);
 226         ByteBuffer bb = Util.getTemporaryDirectBuffer(bufLength);
 227         try {
 228             long nanos = MILLISECONDS.toNanos(timeout);
 229             SocketAddress sender = dc.blockingReceive(bb, nanos);
 230             bb.flip();
 231             synchronized (p) {
 232                 // copy bytes to the DatagramPacket and set length
 233                 int len = Math.min(bb.limit(), DatagramPackets.getBufLength(p));
 234                 bb.get(p.getData(), p.getOffset(), len);
 235                 DatagramPackets.setLength(p, len);
 236 
 237                 // sender address
 238                 p.setSocketAddress(sender);
 239             }
 240         } catch (ClosedChannelException e) {
 241             var exc = new SocketException("Socket closed");
 242             exc.initCause(e);
 243             throw exc;
 244         } finally {
 245             Util.offerFirstTemporaryDirectBuffer(bb);
 246         }
 247     }
 248 
 249     @Override
 250     public InetAddress getLocalAddress() {
 251         if (isClosed())
 252             return null;
 253         InetSocketAddress local = dc.localAddress();
 254         if (local == null)
 255             local = new InetSocketAddress(0);
 256         InetAddress result = local.getAddress();
 257         SecurityManager sm = System.getSecurityManager();
 258         if (sm != null) {
 259             try {
 260                 sm.checkConnect(result.getHostAddress(), -1);
 261             } catch (SecurityException x) {
 262                 return new InetSocketAddress(0).getAddress();
 263             }
 264         }
 265         return result;
 266     }
 267 
 268     @Override
 269     public int getLocalPort() {
 270         if (isClosed())
 271             return -1;
 272         InetSocketAddress local = dc.localAddress();
 273         if (local != null) {
 274             return local.getPort();
 275         }
 276         return 0;
 277     }
 278 
 279     @Override
 280     public void setSoTimeout(int timeout) throws SocketException {
 281         if (isClosed())
 282             throw new SocketException("Socket is closed");
 283         if (timeout < 0)
 284             throw new IllegalArgumentException("timeout < 0");
 285         this.timeout = timeout;
 286     }
 287 
 288     @Override
 289     public int getSoTimeout() throws SocketException {
 290         if (isClosed())
 291             throw new SocketException("Socket is closed");
 292         return timeout;
 293     }
 294 
 295     private void setBooleanOption(SocketOption<Boolean> name, boolean value)
 296         throws SocketException
 297     {
 298         try {
 299             dc.setOption(name, value);
 300         } catch (IOException x) {
 301             Net.translateToSocketException(x);
 302         }
 303     }
 304 
 305     private void setIntOption(SocketOption<Integer> name, int value)
 306         throws SocketException
 307     {
 308         try {
 309             dc.setOption(name, value);
 310         } catch (IOException x) {
 311             Net.translateToSocketException(x);
 312         }
 313     }
 314 
 315     private boolean getBooleanOption(SocketOption<Boolean> name) throws SocketException {
 316         try {
 317             return dc.getOption(name).booleanValue();
 318         } catch (IOException x) {
 319             Net.translateToSocketException(x);
 320             return false;       // keep compiler happy
 321         }
 322     }
 323 
 324     private int getIntOption(SocketOption<Integer> name) throws SocketException {
 325         try {
 326             return dc.getOption(name).intValue();
 327         } catch (IOException x) {
 328             Net.translateToSocketException(x);
 329             return -1;          // keep compiler happy
 330         }
 331     }
 332 
 333     @Override
 334     public void setSendBufferSize(int size) throws SocketException {
 335         if (size <= 0)
 336             throw new IllegalArgumentException("Invalid send size");
 337         setIntOption(StandardSocketOptions.SO_SNDBUF, size);
 338     }
 339 
 340     @Override
 341     public int getSendBufferSize() throws SocketException {
 342         return getIntOption(StandardSocketOptions.SO_SNDBUF);
 343     }
 344 
 345     @Override
 346     public void setReceiveBufferSize(int size) throws SocketException {
 347         if (size <= 0)
 348             throw new IllegalArgumentException("Invalid receive size");
 349         setIntOption(StandardSocketOptions.SO_RCVBUF, size);
 350     }
 351 
 352     @Override
 353     public int getReceiveBufferSize() throws SocketException {
 354         return getIntOption(StandardSocketOptions.SO_RCVBUF);
 355     }
 356 
 357     @Override
 358     public void setReuseAddress(boolean on) throws SocketException {
 359         setBooleanOption(StandardSocketOptions.SO_REUSEADDR, on);
 360     }
 361 
 362     @Override
 363     public boolean getReuseAddress() throws SocketException {
 364         return getBooleanOption(StandardSocketOptions.SO_REUSEADDR);
 365     }
 366 
 367     @Override
 368     public void setBroadcast(boolean on) throws SocketException {
 369         setBooleanOption(StandardSocketOptions.SO_BROADCAST, on);
 370     }
 371 
 372     @Override
 373     public boolean getBroadcast() throws SocketException {
 374         return getBooleanOption(StandardSocketOptions.SO_BROADCAST);
 375     }
 376 
 377     @Override
 378     public void setTrafficClass(int tc) throws SocketException {
 379         setIntOption(StandardSocketOptions.IP_TOS, tc);
 380     }
 381 
 382     @Override
 383     public int getTrafficClass() throws SocketException {
 384         return getIntOption(StandardSocketOptions.IP_TOS);
 385     }
 386 
 387     @Override
 388     public void close() {
 389         try {
 390             dc.close();
 391         } catch (IOException x) {
 392             throw new Error(x);
 393         }
 394     }
 395 
 396     @Override
 397     public boolean isClosed() {
 398         return !dc.isOpen();
 399     }
 400 
 401     @Override
 402     public DatagramChannel getChannel() {
 403         return dc;
 404     }
 405 
 406     @Override
 407     public <T> DatagramSocket setOption(SocketOption<T> name, T value) throws IOException {
 408         dc.setOption(name, value);
 409         return this;
 410     }
 411 
 412     @Override
 413     public <T> T getOption(SocketOption<T> name) throws IOException {
 414         return dc.getOption(name);
 415     }
 416 
 417     @Override
 418     public Set<SocketOption<?>> supportedOptions() {
 419         return dc.supportedOptions();
 420     }
 421 
 422     // -- java.net.MulticastSocket --
 423 
 424     // used to coordinate changing TTL with the deprecated send method
 425     private final ReentrantLock sendLock = new ReentrantLock();
 426 
 427     // cached outgoing interface (for use by setInterface/getInterface)
 428     private final Object outgoingInterfaceLock = new Object();
 429     private NetworkInterface outgoingNetworkInterface;
 430     private InetAddress outgoingInetAddress;
 431 
 432     @Override
 433     @Deprecated
 434     public void setTTL(byte ttl) throws IOException {
 435         setTimeToLive(Byte.toUnsignedInt(ttl));
 436     }
 437 
 438     @Override
 439     public void setTimeToLive(int ttl) throws IOException {
 440         sendLock.lock();
 441         try {
 442             setIntOption(StandardSocketOptions.IP_MULTICAST_TTL, ttl);
 443         } finally {
 444             sendLock.unlock();
 445         }
 446     }
 447 
 448     @Override
 449     @Deprecated
 450     public byte getTTL() throws IOException {
 451         return (byte) getTimeToLive();
 452     }
 453 
 454     @Override
 455     public int getTimeToLive() throws IOException {
 456         sendLock.lock();
 457         try {
 458             return getIntOption(StandardSocketOptions.IP_MULTICAST_TTL);
 459         } finally {
 460             sendLock.unlock();
 461         }
 462     }
 463 
 464     @Override
 465     @Deprecated
 466     public void joinGroup(InetAddress group) throws IOException {
 467         Objects.requireNonNull(group);
 468         try {
 469             joinGroup(new InetSocketAddress(group, 0), null);
 470         } catch (IllegalArgumentException iae) {
 471             // 1-arg joinGroup does not specify IllegalArgumentException
 472             throw (SocketException) new SocketException().initCause(iae);
 473         }
 474     }
 475 
 476     @Override
 477     @Deprecated
 478     public void leaveGroup(InetAddress group) throws IOException {
 479         Objects.requireNonNull(group);
 480         try {
 481             leaveGroup(new InetSocketAddress(group, 0), null);
 482         } catch (IllegalArgumentException iae) {
 483             // 1-arg leaveGroup does not specify IllegalArgumentException
 484             throw (SocketException) new SocketException().initCause(iae);
 485         }
 486     }
 487 
 488     /**
 489      * Checks a SocketAddress to ensure that it is a multicast address.
 490      *
 491      * @return the multicast group
 492      * @throws IllegalArgumentException if group is null, an unsupported address
 493      *         type, or an unresolved address
 494      * @throws SocketException if group is not a multicast address
 495      */
 496     private static InetAddress checkGroup(SocketAddress mcastaddr) throws SocketException {
 497         if (mcastaddr == null || !(mcastaddr instanceof InetSocketAddress))
 498             throw new IllegalArgumentException("Unsupported address type");
 499         InetAddress group = ((InetSocketAddress) mcastaddr).getAddress();
 500         if (group == null)
 501             throw new IllegalArgumentException("Unresolved address");
 502         if (!group.isMulticastAddress())
 503             throw new SocketException("Not a multicast address");
 504         return group;
 505     }
 506 
 507     @Override
 508     public void joinGroup(SocketAddress mcastaddr, NetworkInterface netIf) throws IOException {
 509         InetAddress group = checkGroup(mcastaddr);
 510         NetworkInterface ni = (netIf != null) ? netIf : defaultNetworkInterface();
 511         if (isClosed())
 512             throw new SocketException("Socket is closed");
 513         synchronized (this) {
 514             MembershipKey key = dc.findMembership(group, ni);
 515             if (key != null) {
 516                 // already a member but need to check permission anyway
 517                 SecurityManager sm = System.getSecurityManager();
 518                 if (sm != null)
 519                     sm.checkMulticast(group);
 520                 throw new SocketException("Already a member of group");
 521             }
 522             dc.join(group, ni);  // checks permission
 523         }
 524     }
 525 
 526     @Override
 527     public void leaveGroup(SocketAddress mcastaddr, NetworkInterface netIf) throws IOException {
 528         InetAddress group = checkGroup(mcastaddr);
 529         NetworkInterface ni = (netIf != null) ? netIf : defaultNetworkInterface();
 530         if (isClosed())
 531             throw new SocketException("Socket is closed");
 532         SecurityManager sm = System.getSecurityManager();
 533         if (sm != null)
 534             sm.checkMulticast(group);
 535         synchronized (this) {
 536             MembershipKey key = dc.findMembership(group, ni);
 537             if (key == null)
 538                 throw new SocketException("Not a member of group");
 539             key.drop();
 540         }
 541     }
 542 
 543     @Override
 544     @Deprecated
 545     public void setInterface(InetAddress inf) throws SocketException {
 546         if (inf == null)
 547             throw new SocketException("Invalid value 'null'");
 548         NetworkInterface ni = NetworkInterface.getByInetAddress(inf);
 549         if (ni == null) {
 550             String address = inf.getHostAddress();
 551             throw new SocketException("No network interface with address " + address);
 552         }
 553         synchronized (outgoingInterfaceLock) {
 554             // set interface and update cached values
 555             setNetworkInterface(ni);
 556             outgoingNetworkInterface = ni;
 557             outgoingInetAddress = inf;
 558         }
 559     }
 560 
 561     @Override
 562     @Deprecated
 563     public InetAddress getInterface() throws SocketException {
 564         synchronized (outgoingInterfaceLock) {
 565             NetworkInterface ni = outgoingNetworkInterface();
 566             if (ni != null) {
 567                 if (ni.equals(outgoingNetworkInterface)) {
 568                     return outgoingInetAddress;
 569                 } else {
 570                     // network interface has changed so update cached values
 571                     PrivilegedAction<InetAddress> pa;
 572                     pa = () -> ni.inetAddresses().findFirst().orElse(null);
 573                     InetAddress ia = AccessController.doPrivileged(pa);
 574                     if (ia == null)
 575                         throw new SocketException("Network interface has no IP address");
 576                     outgoingNetworkInterface = ni;
 577                     outgoingInetAddress = ia;
 578                     return ia;
 579                 }
 580             }
 581         }
 582 
 583         // no interface set
 584         return anyInetAddress();
 585     }
 586 
 587     @Override
 588     public void setNetworkInterface(NetworkInterface netIf) throws SocketException {
 589         try {
 590             setOption(StandardSocketOptions.IP_MULTICAST_IF, netIf);
 591         } catch (IOException e) {
 592             Net.translateToSocketException(e);
 593         }
 594     }
 595 
 596     @Override
 597     public NetworkInterface getNetworkInterface() throws SocketException {
 598         NetworkInterface ni = outgoingNetworkInterface();
 599         if (ni == null) {
 600             // return NetworkInterface with index == 0 as placeholder
 601             ni = anyNetworkInterface();
 602         }
 603         return ni;
 604     }
 605 
 606     @Override
 607     @Deprecated
 608     public void setLoopbackMode(boolean disable) throws SocketException {
 609         boolean enable = !disable;
 610         setBooleanOption(StandardSocketOptions.IP_MULTICAST_LOOP, enable);
 611     }
 612 
 613     @Override
 614     @Deprecated
 615     public boolean getLoopbackMode() throws SocketException {
 616         boolean enabled = getBooleanOption(StandardSocketOptions.IP_MULTICAST_LOOP);
 617         return !enabled;
 618     }
 619 
 620     @Override
 621     @Deprecated
 622     public void send(DatagramPacket p, byte ttl) throws IOException {
 623         sendLock.lock();
 624         try {
 625             int oldValue = getTimeToLive();
 626             try {
 627                 setTTL(ttl);
 628                 send(p);
 629             } finally {
 630                 setTimeToLive(oldValue);
 631             }
 632         } finally {
 633             sendLock.unlock();
 634         }
 635     }
 636 
 637     /**
 638      * Returns the outgoing NetworkInterface or null if not set.
 639      */
 640     private NetworkInterface outgoingNetworkInterface() throws SocketException {
 641         try {
 642             return getOption(StandardSocketOptions.IP_MULTICAST_IF);
 643         } catch (IOException e) {
 644             Net.translateToSocketException(e);
 645             return null; // keep compiler happy
 646         }
 647     }
 648 
 649     /**
 650      * Returns the default NetworkInterface to use when joining or leaving a
 651      * multicast group and a network interface is not specified.
 652      * This method will return the outgoing NetworkInterface if set, otherwise
 653      * the result of NetworkInterface.getDefault(), otherwise a NetworkInterface
 654      * with index == 0 as a placeholder for "any network interface".
 655      */
 656     private NetworkInterface defaultNetworkInterface() throws SocketException {
 657         NetworkInterface ni = outgoingNetworkInterface();
 658         if (ni == null)
 659             ni = NetworkInterfaces.getDefault();   // macOS
 660         if (ni == null)
 661             ni = anyNetworkInterface();
 662         return ni;
 663     }
 664 
 665     /**
 666      * Returns the placeholder for "any network interface", its index is 0.
 667      */
 668     private NetworkInterface anyNetworkInterface() {
 669         InetAddress[] addrs = new InetAddress[1];
 670         addrs[0] = anyInetAddress();
 671         return NetworkInterfaces.newNetworkInterface(addrs[0].getHostName(), 0, addrs);
 672     }
 673 
 674     /**
 675      * Returns the InetAddress representing anyLocalAddress.
 676      */
 677     private InetAddress anyInetAddress() {
 678         return new InetSocketAddress(0).getAddress();
 679     }
 680 
 681     /**
 682      * Defines static methods to get/set DatagramPacket fields and workaround
 683      * DatagramPacket deficiencies.
 684      */
 685     private static class DatagramPackets {
 686         private static final VarHandle LENGTH;
 687         private static final VarHandle BUF_LENGTH;
 688         static {
 689             try {
 690                 PrivilegedExceptionAction<Lookup> pa = () ->
 691                     MethodHandles.privateLookupIn(DatagramPacket.class, MethodHandles.lookup());
 692                 MethodHandles.Lookup l = AccessController.doPrivileged(pa);
 693                 LENGTH = l.findVarHandle(DatagramPacket.class, "length", int.class);
 694                 BUF_LENGTH = l.findVarHandle(DatagramPacket.class, "bufLength", int.class);
 695             } catch (Exception e) {
 696                 throw new ExceptionInInitializerError(e);
 697             }
 698         }
 699 
 700         /**
 701          * Sets the DatagramPacket.length field. DatagramPacket.setLength cannot be
 702          * used at this time because it sets both the length and bufLength fields.
 703          */
 704         static void setLength(DatagramPacket p, int value) {
 705             synchronized (p) {
 706                 LENGTH.set(p, value);
 707             }
 708         }
 709 
 710         /**
 711          * Returns the value of the DatagramPacket.bufLength field.
 712          */
 713         static int getBufLength(DatagramPacket p) {
 714             synchronized (p) {
 715                 return (int) BUF_LENGTH.get(p);
 716             }
 717         }
 718     }
 719 
 720     /**
 721      * Defines static methods to invoke non-public NetworkInterface methods.
 722      */
 723     private static class NetworkInterfaces {
 724         static final MethodHandle GET_DEFAULT;
 725         static final MethodHandle CONSTRUCTOR;
 726         static {
 727             try {
 728                 PrivilegedExceptionAction<Lookup> pa = () ->
 729                     MethodHandles.privateLookupIn(NetworkInterface.class, MethodHandles.lookup());
 730                 MethodHandles.Lookup l = AccessController.doPrivileged(pa);
 731                 MethodType methodType = MethodType.methodType(NetworkInterface.class);
 732                 GET_DEFAULT = l.findStatic(NetworkInterface.class, "getDefault", methodType);
 733                 methodType = MethodType.methodType(void.class, String.class, int.class, InetAddress[].class);
 734                 CONSTRUCTOR = l.findConstructor(NetworkInterface.class, methodType);
 735             } catch (Exception e) {
 736                 throw new ExceptionInInitializerError(e);
 737             }
 738         }
 739 
 740         /**
 741          * Returns the default network interface or null.
 742          */
 743         static NetworkInterface getDefault() {
 744             try {
 745                 return (NetworkInterface) GET_DEFAULT.invokeExact();
 746             } catch (Throwable e) {
 747                 throw new InternalError(e);
 748             }
 749         }
 750 
 751         /**
 752          * Creates a NetworkInterface with the given name index and addresses.
 753          */
 754         static NetworkInterface newNetworkInterface(String name, int index, InetAddress[] addrs) {
 755             try {
 756                 return (NetworkInterface) CONSTRUCTOR.invoke(name, index, addrs);
 757             } catch (Throwable e) {
 758                 throw new InternalError(e);
 759             }
 760         }
 761     }
 762 }