< prev index next >
src/java.base/share/classes/sun/nio/ch/DatagramSocketAdaptor.java
Print this page
rev 57619 : [mq]: MulticastSocketAdaptor
*** 1,7 ****
/*
! * Copyright (c) 2001, 2019, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
--- 1,7 ----
/*
! * Copyright (c) 2001, 2020, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
*** 24,80 ****
*/
package sun.nio.ch;
import java.io.IOException;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodHandles.Lookup;
import java.lang.invoke.VarHandle;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
- import java.net.DatagramSocketImpl;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.NetworkInterface;
import java.net.SocketAddress;
import java.net.SocketException;
import java.net.SocketOption;
import java.net.StandardSocketOptions;
import java.nio.ByteBuffer;
import java.nio.channels.AlreadyConnectedException;
import java.nio.channels.ClosedChannelException;
import java.nio.channels.DatagramChannel;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.util.Set;
import static java.util.concurrent.TimeUnit.MILLISECONDS;
! // Make a datagram-socket channel look like a datagram socket.
! //
! // The methods in this class are defined in exactly the same order as in
! // java.net.DatagramSocket so as to simplify tracking future changes to that
! // class.
! //
!
! class DatagramSocketAdaptor
! extends DatagramSocket
{
// The channel being adapted
private final DatagramChannelImpl dc;
// Timeout "option" value for receives
private volatile int timeout;
! // create DatagramSocket with useless impl
! private DatagramSocketAdaptor(DatagramChannelImpl dc) {
! super(new DummyDatagramSocketImpl());
this.dc = dc;
}
static DatagramSocket create(DatagramChannelImpl dc) {
return new DatagramSocketAdaptor(dc);
}
private void connectInternal(SocketAddress remote) throws SocketException {
try {
dc.connect(remote, false); // skips check for already connected
--- 24,90 ----
*/
package sun.nio.ch;
import java.io.IOException;
+ import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodHandles.Lookup;
+ import java.lang.invoke.MethodType;
import java.lang.invoke.VarHandle;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.NetworkInterface;
+ import java.net.MulticastSocket;
import java.net.SocketAddress;
import java.net.SocketException;
import java.net.SocketOption;
import java.net.StandardSocketOptions;
import java.nio.ByteBuffer;
import java.nio.channels.AlreadyConnectedException;
import java.nio.channels.ClosedChannelException;
import java.nio.channels.DatagramChannel;
+ import java.nio.channels.MembershipKey;
import java.security.AccessController;
import java.security.PrivilegedAction;
+ import java.security.PrivilegedExceptionAction;
+ import java.util.Objects;
import java.util.Set;
+ import java.util.concurrent.locks.ReentrantLock;
import static java.util.concurrent.TimeUnit.MILLISECONDS;
! /**
! * A multicast datagram socket based on a datagram channel.
! *
! * This class overrides every public method defined by java.net.DatagramSocket
! * and java.net.MulticastSocket. The methods in this class are defined in exactly
! * the same order as in java.net.DatagramSocket and java.net.MulticastSocket so
! * as to simplify tracking changes.
! */
! public class DatagramSocketAdaptor
! extends MulticastSocket
{
// The channel being adapted
private final DatagramChannelImpl dc;
// Timeout "option" value for receives
private volatile int timeout;
! private DatagramSocketAdaptor(DatagramChannelImpl dc) throws IOException {
! super(/*SocketAddress*/null);
this.dc = dc;
}
static DatagramSocket create(DatagramChannelImpl dc) {
+ try {
return new DatagramSocketAdaptor(dc);
+ } catch (IOException e) {
+ throw new Error(e);
+ }
}
private void connectInternal(SocketAddress remote) throws SocketException {
try {
dc.connect(remote, false); // skips check for already connected
*** 407,524 ****
@Override
public Set<SocketOption<?>> supportedOptions() {
return dc.supportedOptions();
}
! /**
! * DatagramSocketImpl implementation where all methods throw an error.
! */
! private static class DummyDatagramSocketImpl extends DatagramSocketImpl {
! private static <T> T shouldNotGetHere() {
! throw new InternalError("Should not get here");
! }
! @Override
! protected void create() {
! shouldNotGetHere();
! }
@Override
! protected void bind(int lport, InetAddress laddr) {
! shouldNotGetHere();
}
@Override
! protected void send(DatagramPacket p) {
! shouldNotGetHere();
}
@Override
! protected int peek(InetAddress address) {
! return shouldNotGetHere();
}
@Override
! protected int peekData(DatagramPacket p) {
! return shouldNotGetHere();
}
@Override
! protected void receive(DatagramPacket p) {
! shouldNotGetHere();
}
@Deprecated
! protected void setTTL(byte ttl) {
! shouldNotGetHere();
}
! @Deprecated
! protected byte getTTL() {
! return shouldNotGetHere();
}
@Override
! protected void setTimeToLive(int ttl) {
! shouldNotGetHere();
}
@Override
! protected int getTimeToLive() {
! return shouldNotGetHere();
}
@Override
! protected void join(InetAddress group) {
! shouldNotGetHere();
}
@Override
! protected void leave(InetAddress inetaddr) {
! shouldNotGetHere();
}
! @Override
! protected void joinGroup(SocketAddress group, NetworkInterface netIf) {
! shouldNotGetHere();
}
@Override
! protected void leaveGroup(SocketAddress mcastaddr, NetworkInterface netIf) {
! shouldNotGetHere();
}
@Override
! protected void close() {
! shouldNotGetHere();
}
@Override
! public Object getOption(int optID) {
! return shouldNotGetHere();
}
@Override
! public void setOption(int optID, Object value) {
! shouldNotGetHere();
}
@Override
! protected <T> void setOption(SocketOption<T> name, T value) {
! shouldNotGetHere();
}
! @Override
! protected <T> T getOption(SocketOption<T> name) {
! return shouldNotGetHere();
}
! @Override
! protected Set<SocketOption<?>> supportedOptions() {
! return shouldNotGetHere();
}
}
/**
* Defines static methods to get/set DatagramPacket fields and workaround
* DatagramPacket deficiencies.
--- 417,683 ----
@Override
public Set<SocketOption<?>> supportedOptions() {
return dc.supportedOptions();
}
+ // -- java.net.MulticastSocket --
! // used to coordinate changing TTL with the deprecated send method
! private final ReentrantLock sendLock = new ReentrantLock();
! // cached outgoing interface (for use by setInterface/getInterface)
! private final Object outgoingInterfaceLock = new Object();
! private NetworkInterface outgoingNetworkInterface;
! private InetAddress outgoingInetAddress;
@Override
! @Deprecated
! public void setTTL(byte ttl) throws IOException {
! setTimeToLive(Byte.toUnsignedInt(ttl));
}
@Override
! public void setTimeToLive(int ttl) throws IOException {
! sendLock.lock();
! try {
! setIntOption(StandardSocketOptions.IP_MULTICAST_TTL, ttl);
! } finally {
! sendLock.unlock();
! }
}
@Override
! @Deprecated
! public byte getTTL() throws IOException {
! return (byte) getTimeToLive();
}
@Override
! public int getTimeToLive() throws IOException {
! sendLock.lock();
! try {
! return getIntOption(StandardSocketOptions.IP_MULTICAST_TTL);
! } finally {
! sendLock.unlock();
! }
}
@Override
! @Deprecated
! public void joinGroup(InetAddress group) throws IOException {
! Objects.requireNonNull(group);
! try {
! joinGroup(new InetSocketAddress(group, 0), null);
! } catch (IllegalArgumentException iae) {
! // 1-arg joinGroup does not specify IllegalArgumentException
! throw (SocketException) new SocketException("joinGroup failed").initCause(iae);
! }
}
+ @Override
@Deprecated
! public void leaveGroup(InetAddress group) throws IOException {
! Objects.requireNonNull(group);
! try {
! leaveGroup(new InetSocketAddress(group, 0), null);
! } catch (IllegalArgumentException iae) {
! // 1-arg leaveGroup does not specify IllegalArgumentException
! throw (SocketException) new SocketException("leaveGroup failed").initCause(iae);
! }
}
! /**
! * Checks a SocketAddress to ensure that it is a multicast address.
! *
! * @return the multicast group
! * @throws IllegalArgumentException if group is null, an unsupported address
! * type, or an unresolved address
! * @throws SocketException if group is not a multicast address
! */
! private static InetAddress checkGroup(SocketAddress mcastaddr) throws SocketException {
! if (mcastaddr == null || !(mcastaddr instanceof InetSocketAddress))
! throw new IllegalArgumentException("Unsupported address type");
! InetAddress group = ((InetSocketAddress) mcastaddr).getAddress();
! if (group == null)
! throw new IllegalArgumentException("Unresolved address");
! if (!group.isMulticastAddress())
! throw new SocketException("Not a multicast address");
! return group;
}
@Override
! public void joinGroup(SocketAddress mcastaddr, NetworkInterface netIf) throws IOException {
! InetAddress group = checkGroup(mcastaddr);
! NetworkInterface ni = (netIf != null) ? netIf : defaultNetworkInterface();
! if (isClosed())
! throw new SocketException("Socket is closed");
! synchronized (this) {
! MembershipKey key = dc.findMembership(group, ni);
! if (key != null) {
! // already a member but need to check permission anyway
! SecurityManager sm = System.getSecurityManager();
! if (sm != null)
! sm.checkMulticast(group);
! throw new SocketException("Already a member of group");
! }
! dc.join(group, ni); // checks permission
! }
}
@Override
! public void leaveGroup(SocketAddress mcastaddr, NetworkInterface netIf) throws IOException {
! InetAddress group = checkGroup(mcastaddr);
! NetworkInterface ni = (netIf != null) ? netIf : defaultNetworkInterface();
! if (isClosed())
! throw new SocketException("Socket is closed");
! SecurityManager sm = System.getSecurityManager();
! if (sm != null)
! sm.checkMulticast(group);
! synchronized (this) {
! MembershipKey key = dc.findMembership(group, ni);
! if (key == null)
! throw new SocketException("Not a member of group");
! key.drop();
! }
}
@Override
! @Deprecated
! public void setInterface(InetAddress inf) throws SocketException {
! if (inf == null)
! throw new SocketException("Invalid value 'null'");
! NetworkInterface ni = NetworkInterface.getByInetAddress(inf);
! if (ni == null) {
! String address = inf.getHostAddress();
! throw new SocketException("No network interface with address " + address);
! }
! synchronized (outgoingInterfaceLock) {
! // set interface and update cached values
! setNetworkInterface(ni);
! outgoingNetworkInterface = ni;
! outgoingInetAddress = inf;
! }
}
@Override
! @Deprecated
! public InetAddress getInterface() throws SocketException {
! synchronized (outgoingInterfaceLock) {
! NetworkInterface ni = outgoingNetworkInterface();
! if (ni != null) {
! if (ni.equals(outgoingNetworkInterface)) {
! return outgoingInetAddress;
! } else {
! // network interface has changed so update cached values
! PrivilegedAction<InetAddress> pa;
! pa = () -> ni.inetAddresses().findFirst().orElse(null);
! InetAddress ia = AccessController.doPrivileged(pa);
! if (ia == null)
! throw new SocketException("Network interface has no IP address");
! outgoingNetworkInterface = ni;
! outgoingInetAddress = ia;
! return ia;
! }
! }
}
! // no interface set
! return anyInetAddress();
}
@Override
! public void setNetworkInterface(NetworkInterface netIf) throws SocketException {
! try {
! setOption(StandardSocketOptions.IP_MULTICAST_IF, netIf);
! } catch (IOException e) {
! Net.translateToSocketException(e);
! }
}
@Override
! public NetworkInterface getNetworkInterface() throws SocketException {
! NetworkInterface ni = outgoingNetworkInterface();
! if (ni == null) {
! // return NetworkInterface with index == 0 as placeholder
! ni = anyNetworkInterface();
! }
! return ni;
}
@Override
! @Deprecated
! public void setLoopbackMode(boolean disable) throws SocketException {
! boolean enable = !disable;
! setBooleanOption(StandardSocketOptions.IP_MULTICAST_LOOP, enable);
}
@Override
! @Deprecated
! public boolean getLoopbackMode() throws SocketException {
! boolean enabled = getBooleanOption(StandardSocketOptions.IP_MULTICAST_LOOP);
! return !enabled;
}
@Override
! @Deprecated
! public void send(DatagramPacket p, byte ttl) throws IOException {
! sendLock.lock();
! try {
! int oldValue = getTimeToLive();
! try {
! setTTL(ttl);
! send(p);
! } finally {
! setTimeToLive(oldValue);
! }
! } finally {
! sendLock.unlock();
! }
}
! /**
! * Returns the outgoing NetworkInterface or null if not set.
! */
! private NetworkInterface outgoingNetworkInterface() throws SocketException {
! try {
! return getOption(StandardSocketOptions.IP_MULTICAST_IF);
! } catch (IOException e) {
! Net.translateToSocketException(e);
! return null; // keep compiler happy
! }
}
! /**
! * Returns the default NetworkInterface to use when joining or leaving a
! * multicast group and a network interface is not specified.
! * This method will return the outgoing NetworkInterface if set, otherwise
! * the result of NetworkInterface.getDefault(), otherwise a NetworkInterface
! * with index == 0 as a placeholder for "any network interface".
! */
! private NetworkInterface defaultNetworkInterface() throws SocketException {
! NetworkInterface ni = outgoingNetworkInterface();
! if (ni == null)
! ni = NetworkInterfaces.getDefault(); // macOS
! if (ni == null)
! ni = anyNetworkInterface();
! return ni;
! }
!
! /**
! * Returns the placeholder for "any network interface", its index is 0.
! */
! private NetworkInterface anyNetworkInterface() {
! InetAddress[] addrs = new InetAddress[1];
! addrs[0] = anyInetAddress();
! return NetworkInterfaces.newNetworkInterface(addrs[0].getHostName(), 0, addrs);
}
+
+ /**
+ * Returns the InetAddress representing anyLocalAddress.
+ */
+ private InetAddress anyInetAddress() {
+ return new InetSocketAddress(0).getAddress();
}
/**
* Defines static methods to get/set DatagramPacket fields and workaround
* DatagramPacket deficiencies.
*** 526,542 ****
private static class DatagramPackets {
private static final VarHandle LENGTH;
private static final VarHandle BUF_LENGTH;
static {
try {
! PrivilegedAction<Lookup> pa = () -> {
! try {
! return MethodHandles.privateLookupIn(DatagramPacket.class, MethodHandles.lookup());
! } catch (Exception e) {
! throw new ExceptionInInitializerError(e);
! }
! };
MethodHandles.Lookup l = AccessController.doPrivileged(pa);
LENGTH = l.findVarHandle(DatagramPacket.class, "length", int.class);
BUF_LENGTH = l.findVarHandle(DatagramPacket.class, "bufLength", int.class);
} catch (Exception e) {
throw new ExceptionInInitializerError(e);
--- 685,696 ----
private static class DatagramPackets {
private static final VarHandle LENGTH;
private static final VarHandle BUF_LENGTH;
static {
try {
! PrivilegedExceptionAction<Lookup> pa = () ->
! MethodHandles.privateLookupIn(DatagramPacket.class, MethodHandles.lookup());
MethodHandles.Lookup l = AccessController.doPrivileged(pa);
LENGTH = l.findVarHandle(DatagramPacket.class, "length", int.class);
BUF_LENGTH = l.findVarHandle(DatagramPacket.class, "bufLength", int.class);
} catch (Exception e) {
throw new ExceptionInInitializerError(e);
*** 560,565 ****
--- 714,762 ----
synchronized (p) {
return (int) BUF_LENGTH.get(p);
}
}
}
+
+ /**
+ * Defines static methods to invoke non-public NetworkInterface methods.
+ */
+ private static class NetworkInterfaces {
+ static final MethodHandle GET_DEFAULT;
+ static final MethodHandle CONSTRUCTOR;
+ static {
+ try {
+ PrivilegedExceptionAction<Lookup> pa = () ->
+ MethodHandles.privateLookupIn(NetworkInterface.class, MethodHandles.lookup());
+ MethodHandles.Lookup l = AccessController.doPrivileged(pa);
+ MethodType methodType = MethodType.methodType(NetworkInterface.class);
+ GET_DEFAULT = l.findStatic(NetworkInterface.class, "getDefault", methodType);
+ methodType = MethodType.methodType(void.class, String.class, int.class, InetAddress[].class);
+ CONSTRUCTOR = l.findConstructor(NetworkInterface.class, methodType);
+ } catch (Exception e) {
+ throw new ExceptionInInitializerError(e);
+ }
+ }
+
+ /**
+ * Returns the default network interface or null.
+ */
+ static NetworkInterface getDefault() {
+ try {
+ return (NetworkInterface) GET_DEFAULT.invokeExact();
+ } catch (Throwable e) {
+ throw new InternalError(e);
+ }
+ }
+
+ /**
+ * Creates a NetworkInterface with the given name index and addresses.
+ */
+ static NetworkInterface newNetworkInterface(String name, int index, InetAddress[] addrs) {
+ try {
+ return (NetworkInterface) CONSTRUCTOR.invoke(name, index, addrs);
+ } catch (Throwable e) {
+ throw new InternalError(e);
+ }
+ }
+ }
}
\ No newline at end of file
< prev index next >