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