--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/java.base/share/classes/sun/nio/ch/DatagramSocketAdaptor.java Tue Sep 12 19:03:39 2017 +0200
@@ -0,0 +1,410 @@
+/*
+ * Copyright (c) 2001, 2012, 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
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package sun.nio.ch;
+
+import java.io.*;
+import java.net.*;
+import java.nio.*;
+import java.nio.channels.*;
+
+
+// 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.
+//
+
+public class DatagramSocketAdaptor
+ extends DatagramSocket
+{
+
+ // The channel being adapted
+ private final DatagramChannelImpl dc;
+
+ // Timeout "option" value for receives
+ private volatile int timeout;
+
+ // ## super will create a useless impl
+ private DatagramSocketAdaptor(DatagramChannelImpl dc) throws IOException {
+ // Invoke the DatagramSocketAdaptor(SocketAddress) constructor,
+ // passing a dummy DatagramSocketImpl object to aovid any native
+ // resource allocation in super class and invoking our bind method
+ // before the dc field is initialized.
+ super(dummyDatagramSocket);
+ this.dc = dc;
+ }
+
+ public static DatagramSocket create(DatagramChannelImpl dc) {
+ try {
+ return new DatagramSocketAdaptor(dc);
+ } catch (IOException x) {
+ throw new Error(x);
+ }
+ }
+
+ private void connectInternal(SocketAddress remote)
+ throws SocketException
+ {
+ InetSocketAddress isa = Net.asInetSocketAddress(remote);
+ int port = isa.getPort();
+ if (port < 0 || port > 0xFFFF)
+ throw new IllegalArgumentException("connect: " + port);
+ if (remote == null)
+ throw new IllegalArgumentException("connect: null address");
+ if (isClosed())
+ return;
+ try {
+ dc.connect(remote);
+ } catch (Exception x) {
+ Net.translateToSocketException(x);
+ }
+ }
+
+ public void bind(SocketAddress local) throws SocketException {
+ try {
+ if (local == null)
+ local = new InetSocketAddress(0);
+ dc.bind(local);
+ } catch (Exception x) {
+ Net.translateToSocketException(x);
+ }
+ }
+
+ public void connect(InetAddress address, int port) {
+ try {
+ connectInternal(new InetSocketAddress(address, port));
+ } catch (SocketException x) {
+ // Yes, j.n.DatagramSocket really does this
+ }
+ }
+
+ public void connect(SocketAddress remote) throws SocketException {
+ if (remote == null)
+ throw new IllegalArgumentException("Address can't be null");
+ connectInternal(remote);
+ }
+
+ public void disconnect() {
+ try {
+ dc.disconnect();
+ } catch (IOException x) {
+ throw new Error(x);
+ }
+ }
+
+ public boolean isBound() {
+ return dc.localAddress() != null;
+ }
+
+ public boolean isConnected() {
+ return dc.remoteAddress() != null;
+ }
+
+ public InetAddress getInetAddress() {
+ return (isConnected()
+ ? Net.asInetSocketAddress(dc.remoteAddress()).getAddress()
+ : null);
+ }
+
+ public int getPort() {
+ return (isConnected()
+ ? Net.asInetSocketAddress(dc.remoteAddress()).getPort()
+ : -1);
+ }
+
+ public void send(DatagramPacket p) throws IOException {
+ synchronized (dc.blockingLock()) {
+ if (!dc.isBlocking())
+ throw new IllegalBlockingModeException();
+ try {
+ synchronized (p) {
+ ByteBuffer bb = ByteBuffer.wrap(p.getData(),
+ p.getOffset(),
+ p.getLength());
+ if (dc.isConnected()) {
+ if (p.getAddress() == null) {
+ // Legacy DatagramSocket will send in this case
+ // and set address and port of the packet
+ InetSocketAddress isa = (InetSocketAddress)
+ dc.remoteAddress();
+ p.setPort(isa.getPort());
+ p.setAddress(isa.getAddress());
+ dc.write(bb);
+ } else {
+ // Target address may not match connected address
+ dc.send(bb, p.getSocketAddress());
+ }
+ } else {
+ // Not connected so address must be valid or throw
+ dc.send(bb, p.getSocketAddress());
+ }
+ }
+ } catch (IOException x) {
+ Net.translateException(x);
+ }
+ }
+ }
+
+ // Must hold dc.blockingLock()
+ //
+ private SocketAddress receive(ByteBuffer bb) throws IOException {
+ if (timeout == 0) {
+ return dc.receive(bb);
+ }
+
+ dc.configureBlocking(false);
+ try {
+ int n;
+ SocketAddress sender;
+ if ((sender = dc.receive(bb)) != null)
+ return sender;
+ long to = timeout;
+ for (;;) {
+ if (!dc.isOpen())
+ throw new ClosedChannelException();
+ long st = System.currentTimeMillis();
+ int result = dc.poll(Net.POLLIN, to);
+ if (result > 0 &&
+ ((result & Net.POLLIN) != 0)) {
+ if ((sender = dc.receive(bb)) != null)
+ return sender;
+ }
+ to -= System.currentTimeMillis() - st;
+ if (to <= 0)
+ throw new SocketTimeoutException();
+
+ }
+ } finally {
+ if (dc.isOpen())
+ dc.configureBlocking(true);
+ }
+ }
+
+ public void receive(DatagramPacket p) throws IOException {
+ synchronized (dc.blockingLock()) {
+ if (!dc.isBlocking())
+ throw new IllegalBlockingModeException();
+ try {
+ synchronized (p) {
+ ByteBuffer bb = ByteBuffer.wrap(p.getData(),
+ p.getOffset(),
+ p.getLength());
+ SocketAddress sender = receive(bb);
+ p.setSocketAddress(sender);
+ p.setLength(bb.position() - p.getOffset());
+ }
+ } catch (IOException x) {
+ Net.translateException(x);
+ }
+ }
+ }
+
+ public InetAddress getLocalAddress() {
+ if (isClosed())
+ return null;
+ SocketAddress local = dc.localAddress();
+ if (local == null)
+ local = new InetSocketAddress(0);
+ InetAddress result = ((InetSocketAddress)local).getAddress();
+ SecurityManager sm = System.getSecurityManager();
+ if (sm != null) {
+ try {
+ sm.checkConnect(result.getHostAddress(), -1);
+ } catch (SecurityException x) {
+ return new InetSocketAddress(0).getAddress();
+ }
+ }
+ return result;
+ }
+
+ public int getLocalPort() {
+ if (isClosed())
+ return -1;
+ try {
+ SocketAddress local = dc.getLocalAddress();
+ if (local != null) {
+ return ((InetSocketAddress)local).getPort();
+ }
+ } catch (Exception x) {
+ }
+ return 0;
+ }
+
+ public void setSoTimeout(int timeout) throws SocketException {
+ this.timeout = timeout;
+ }
+
+ public int getSoTimeout() throws SocketException {
+ return timeout;
+ }
+
+ private void setBooleanOption(SocketOption<Boolean> name, boolean value)
+ throws SocketException
+ {
+ try {
+ dc.setOption(name, value);
+ } catch (IOException x) {
+ Net.translateToSocketException(x);
+ }
+ }
+
+ private void setIntOption(SocketOption<Integer> name, int value)
+ throws SocketException
+ {
+ try {
+ dc.setOption(name, value);
+ } catch (IOException x) {
+ Net.translateToSocketException(x);
+ }
+ }
+
+ private boolean getBooleanOption(SocketOption<Boolean> name) throws SocketException {
+ try {
+ return dc.getOption(name).booleanValue();
+ } catch (IOException x) {
+ Net.translateToSocketException(x);
+ return false; // keep compiler happy
+ }
+ }
+
+ private int getIntOption(SocketOption<Integer> name) throws SocketException {
+ try {
+ return dc.getOption(name).intValue();
+ } catch (IOException x) {
+ Net.translateToSocketException(x);
+ return -1; // keep compiler happy
+ }
+ }
+
+ public void setSendBufferSize(int size) throws SocketException {
+ if (size <= 0)
+ throw new IllegalArgumentException("Invalid send size");
+ setIntOption(StandardSocketOptions.SO_SNDBUF, size);
+ }
+
+ public int getSendBufferSize() throws SocketException {
+ return getIntOption(StandardSocketOptions.SO_SNDBUF);
+ }
+
+ public void setReceiveBufferSize(int size) throws SocketException {
+ if (size <= 0)
+ throw new IllegalArgumentException("Invalid receive size");
+ setIntOption(StandardSocketOptions.SO_RCVBUF, size);
+ }
+
+ public int getReceiveBufferSize() throws SocketException {
+ return getIntOption(StandardSocketOptions.SO_RCVBUF);
+ }
+
+ public void setReuseAddress(boolean on) throws SocketException {
+ setBooleanOption(StandardSocketOptions.SO_REUSEADDR, on);
+ }
+
+ public boolean getReuseAddress() throws SocketException {
+ return getBooleanOption(StandardSocketOptions.SO_REUSEADDR);
+
+ }
+
+ public void setBroadcast(boolean on) throws SocketException {
+ setBooleanOption(StandardSocketOptions.SO_BROADCAST, on);
+ }
+
+ public boolean getBroadcast() throws SocketException {
+ return getBooleanOption(StandardSocketOptions.SO_BROADCAST);
+ }
+
+ public void setTrafficClass(int tc) throws SocketException {
+ setIntOption(StandardSocketOptions.IP_TOS, tc);
+ }
+
+ public int getTrafficClass() throws SocketException {
+ return getIntOption(StandardSocketOptions.IP_TOS);
+ }
+
+ public void close() {
+ try {
+ dc.close();
+ } catch (IOException x) {
+ throw new Error(x);
+ }
+ }
+
+ public boolean isClosed() {
+ return !dc.isOpen();
+ }
+
+ public DatagramChannel getChannel() {
+ return dc;
+ }
+
+ /*
+ * A dummy implementation of DatagramSocketImpl that can be passed to the
+ * DatagramSocket constructor so that no native resources are allocated in
+ * super class.
+ */
+ private static final DatagramSocketImpl dummyDatagramSocket
+ = new DatagramSocketImpl()
+ {
+ protected void create() throws SocketException {}
+
+ protected void bind(int lport, InetAddress laddr) throws SocketException {}
+
+ protected void send(DatagramPacket p) throws IOException {}
+
+ protected int peek(InetAddress i) throws IOException { return 0; }
+
+ protected int peekData(DatagramPacket p) throws IOException { return 0; }
+
+ protected void receive(DatagramPacket p) throws IOException {}
+
+ @Deprecated
+ protected void setTTL(byte ttl) throws IOException {}
+
+ @Deprecated
+ protected byte getTTL() throws IOException { return 0; }
+
+ protected void setTimeToLive(int ttl) throws IOException {}
+
+ protected int getTimeToLive() throws IOException { return 0;}
+
+ protected void join(InetAddress inetaddr) throws IOException {}
+
+ protected void leave(InetAddress inetaddr) throws IOException {}
+
+ protected void joinGroup(SocketAddress mcastaddr,
+ NetworkInterface netIf) throws IOException {}
+
+ protected void leaveGroup(SocketAddress mcastaddr,
+ NetworkInterface netIf) throws IOException {}
+
+ protected void close() {}
+
+ public Object getOption(int optID) throws SocketException { return null;}
+
+ public void setOption(int optID, Object value) throws SocketException {}
+ };
+}