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