aboutsummaryrefslogtreecommitdiff
path: root/src/share/classes/java/net/DatagramSocket.java
diff options
context:
space:
mode:
authorduke <none@none>2007-12-01 00:00:00 +0000
committerduke <none@none>2007-12-01 00:00:00 +0000
commit6e45e10b03bafdc125c46a4864ba802c24d6bc78 (patch)
tree182810ab2fece13f57a928d026f93e9ede0827f9 /src/share/classes/java/net/DatagramSocket.java
downloadjdk8u_jdk-6e45e10b03bafdc125c46a4864ba802c24d6bc78.tar.gz
Initial load
Diffstat (limited to 'src/share/classes/java/net/DatagramSocket.java')
-rw-r--r--src/share/classes/java/net/DatagramSocket.java1210
1 files changed, 1210 insertions, 0 deletions
diff --git a/src/share/classes/java/net/DatagramSocket.java b/src/share/classes/java/net/DatagramSocket.java
new file mode 100644
index 0000000000..4a09fa3cc5
--- /dev/null
+++ b/src/share/classes/java/net/DatagramSocket.java
@@ -0,0 +1,1210 @@
+/*
+ * Copyright 1995-2007 Sun Microsystems, Inc. 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. Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package java.net;
+
+import java.io.FileDescriptor;
+import java.io.IOException;
+import java.io.InterruptedIOException;
+import java.nio.channels.DatagramChannel;
+import java.security.AccessController;
+import java.security.PrivilegedExceptionAction;
+
+/**
+ * This class represents a socket for sending and receiving datagram packets.
+ *
+ * <p>A datagram socket is the sending or receiving point for a packet
+ * delivery service. Each packet sent or received on a datagram socket
+ * is individually addressed and routed. Multiple packets sent from
+ * one machine to another may be routed differently, and may arrive in
+ * any order.
+ *
+ * <p>UDP broadcasts sends are always enabled on a DatagramSocket.
+ * In order to receive broadcast packets a DatagramSocket
+ * should be bound to the wildcard address. In some
+ * implementations, broadcast packets may also be received when
+ * a DatagramSocket is bound to a more specific address.
+ * <p>
+ * Example:
+ * <code>
+ * DatagramSocket s = new DatagramSocket(null);
+ * s.bind(new InetSocketAddress(8888));
+ * </code>
+ * Which is equivalent to:
+ * <code>
+ * DatagramSocket s = new DatagramSocket(8888);
+ * </code>
+ * Both cases will create a DatagramSocket able to receive broadcasts on
+ * UDP port 8888.
+ *
+ * @author Pavani Diwanji
+ * @see java.net.DatagramPacket
+ * @see java.nio.channels.DatagramChannel
+ * @since JDK1.0
+ */
+public
+class DatagramSocket implements java.io.Closeable {
+ /**
+ * Various states of this socket.
+ */
+ private boolean created = false;
+ private boolean bound = false;
+ private boolean closed = false;
+ private Object closeLock = new Object();
+
+ /*
+ * The implementation of this DatagramSocket.
+ */
+ DatagramSocketImpl impl;
+
+ /**
+ * Are we using an older DatagramSocketImpl?
+ */
+ boolean oldImpl = false;
+
+ /*
+ * Connection state:
+ * ST_NOT_CONNECTED = socket not connected
+ * ST_CONNECTED = socket connected
+ * ST_CONNECTED_NO_IMPL = socket connected but not at impl level
+ */
+ static final int ST_NOT_CONNECTED = 0;
+ static final int ST_CONNECTED = 1;
+ static final int ST_CONNECTED_NO_IMPL = 2;
+
+ int connectState = ST_NOT_CONNECTED;
+
+ /*
+ * Connected address & port
+ */
+ InetAddress connectedAddress = null;
+ int connectedPort = -1;
+
+ /**
+ * Connects this socket to a remote socket address (IP address + port number).
+ * Binds socket if not already bound.
+ * <p>
+ * @param addr The remote address.
+ * @param port The remote port
+ * @throws SocketException if binding the socket fails.
+ */
+ private synchronized void connectInternal(InetAddress address, int port) throws SocketException {
+ if (port < 0 || port > 0xFFFF) {
+ throw new IllegalArgumentException("connect: " + port);
+ }
+ if (address == null) {
+ throw new IllegalArgumentException("connect: null address");
+ }
+ if (isClosed())
+ return;
+ SecurityManager security = System.getSecurityManager();
+ if (security != null) {
+ if (address.isMulticastAddress()) {
+ security.checkMulticast(address);
+ } else {
+ security.checkConnect(address.getHostAddress(), port);
+ security.checkAccept(address.getHostAddress(), port);
+ }
+ }
+
+ if (!isBound())
+ bind(new InetSocketAddress(0));
+
+ // old impls do not support connect/disconnect
+ if (oldImpl) {
+ connectState = ST_CONNECTED_NO_IMPL;
+ } else {
+ try {
+ getImpl().connect(address, port);
+
+ // socket is now connected by the impl
+ connectState = ST_CONNECTED;
+ } catch (SocketException se) {
+
+ // connection will be emulated by DatagramSocket
+ connectState = ST_CONNECTED_NO_IMPL;
+ }
+ }
+
+ connectedAddress = address;
+ connectedPort = port;
+ }
+
+
+ /**
+ * Constructs a datagram socket and binds it to any available port
+ * on the local host machine. The socket will be bound to the
+ * {@link InetAddress#isAnyLocalAddress wildcard} address,
+ * an IP address chosen by the kernel.
+ *
+ * <p>If there is a security manager,
+ * its <code>checkListen</code> method is first called
+ * with 0 as its argument to ensure the operation is allowed.
+ * This could result in a SecurityException.
+ *
+ * @exception SocketException if the socket could not be opened,
+ * or the socket could not bind to the specified local port.
+ * @exception SecurityException if a security manager exists and its
+ * <code>checkListen</code> method doesn't allow the operation.
+ *
+ * @see SecurityManager#checkListen
+ */
+ public DatagramSocket() throws SocketException {
+ // create a datagram socket.
+ createImpl();
+ try {
+ bind(new InetSocketAddress(0));
+ } catch (SocketException se) {
+ throw se;
+ } catch(IOException e) {
+ throw new SocketException(e.getMessage());
+ }
+ }
+
+ /**
+ * Creates an unbound datagram socket with the specified
+ * DatagramSocketImpl.
+ *
+ * @param impl an instance of a <B>DatagramSocketImpl</B>
+ * the subclass wishes to use on the DatagramSocket.
+ * @since 1.4
+ */
+ protected DatagramSocket(DatagramSocketImpl impl) {
+ if (impl == null)
+ throw new NullPointerException();
+ this.impl = impl;
+ checkOldImpl();
+ }
+
+ /**
+ * Creates a datagram socket, bound to the specified local
+ * socket address.
+ * <p>
+ * If, if the address is <code>null</code>, creates an unbound socket.
+ * <p>
+ * <p>If there is a security manager,
+ * its <code>checkListen</code> method is first called
+ * with the port from the socket address
+ * as its argument to ensure the operation is allowed.
+ * This could result in a SecurityException.
+ *
+ * @param bindaddr local socket address to bind, or <code>null</code>
+ * for an unbound socket.
+ *
+ * @exception SocketException if the socket could not be opened,
+ * or the socket could not bind to the specified local port.
+ * @exception SecurityException if a security manager exists and its
+ * <code>checkListen</code> method doesn't allow the operation.
+ *
+ * @see SecurityManager#checkListen
+ * @since 1.4
+ */
+ public DatagramSocket(SocketAddress bindaddr) throws SocketException {
+ // create a datagram socket.
+ createImpl();
+ if (bindaddr != null) {
+ bind(bindaddr);
+ }
+ }
+
+ /**
+ * Constructs a datagram socket and binds it to the specified port
+ * on the local host machine. The socket will be bound to the
+ * {@link InetAddress#isAnyLocalAddress wildcard} address,
+ * an IP address chosen by the kernel.
+ *
+ * <p>If there is a security manager,
+ * its <code>checkListen</code> method is first called
+ * with the <code>port</code> argument
+ * as its argument to ensure the operation is allowed.
+ * This could result in a SecurityException.
+ *
+ * @param port port to use.
+ * @exception SocketException if the socket could not be opened,
+ * or the socket could not bind to the specified local port.
+ * @exception SecurityException if a security manager exists and its
+ * <code>checkListen</code> method doesn't allow the operation.
+ *
+ * @see SecurityManager#checkListen
+ */
+ public DatagramSocket(int port) throws SocketException {
+ this(port, null);
+ }
+
+ /**
+ * Creates a datagram socket, bound to the specified local
+ * address. The local port must be between 0 and 65535 inclusive.
+ * If the IP address is 0.0.0.0, the socket will be bound to the
+ * {@link InetAddress#isAnyLocalAddress wildcard} address,
+ * an IP address chosen by the kernel.
+ *
+ * <p>If there is a security manager,
+ * its <code>checkListen</code> method is first called
+ * with the <code>port</code> argument
+ * as its argument to ensure the operation is allowed.
+ * This could result in a SecurityException.
+ *
+ * @param port local port to use
+ * @param laddr local address to bind
+ *
+ * @exception SocketException if the socket could not be opened,
+ * or the socket could not bind to the specified local port.
+ * @exception SecurityException if a security manager exists and its
+ * <code>checkListen</code> method doesn't allow the operation.
+ *
+ * @see SecurityManager#checkListen
+ * @since JDK1.1
+ */
+ public DatagramSocket(int port, InetAddress laddr) throws SocketException {
+ this(new InetSocketAddress(laddr, port));
+ }
+
+ private void checkOldImpl() {
+ if (impl == null)
+ return;
+ // DatagramSocketImpl.peekdata() is a protected method, therefore we need to use
+ // getDeclaredMethod, therefore we need permission to access the member
+ try {
+ AccessController.doPrivileged(new PrivilegedExceptionAction() {
+ public Object run() throws NoSuchMethodException {
+ Class[] cl = new Class[1];
+ cl[0] = DatagramPacket.class;
+ impl.getClass().getDeclaredMethod("peekData", cl);
+ return null;
+ }
+ });
+ } catch (java.security.PrivilegedActionException e) {
+ oldImpl = true;
+ }
+ }
+
+ static Class implClass = null;
+
+ void createImpl() throws SocketException {
+ if (impl == null) {
+ if (factory != null) {
+ impl = factory.createDatagramSocketImpl();
+ checkOldImpl();
+ } else {
+ boolean isMulticast = (this instanceof MulticastSocket) ? true : false;
+ impl = DefaultDatagramSocketImplFactory.createDatagramSocketImpl(isMulticast);
+
+ checkOldImpl();
+ }
+ }
+ // creates a udp socket
+ impl.create();
+ created = true;
+ }
+
+ /**
+ * Get the <code>DatagramSocketImpl</code> attached to this socket,
+ * creating it if necessary.
+ *
+ * @return the <code>DatagramSocketImpl</code> attached to that
+ * DatagramSocket
+ * @throws SocketException if creation fails.
+ * @since 1.4
+ */
+ DatagramSocketImpl getImpl() throws SocketException {
+ if (!created)
+ createImpl();
+ return impl;
+ }
+
+ /**
+ * Binds this DatagramSocket to a specific address & port.
+ * <p>
+ * If the address is <code>null</code>, then the system will pick up
+ * an ephemeral port and a valid local address to bind the socket.
+ *<p>
+ * @param addr The address & port to bind to.
+ * @throws SocketException if any error happens during the bind, or if the
+ * socket is already bound.
+ * @throws SecurityException if a security manager exists and its
+ * <code>checkListen</code> method doesn't allow the operation.
+ * @throws IllegalArgumentException if addr is a SocketAddress subclass
+ * not supported by this socket.
+ * @since 1.4
+ */
+ public synchronized void bind(SocketAddress addr) throws SocketException {
+ if (isClosed())
+ throw new SocketException("Socket is closed");
+ if (isBound())
+ throw new SocketException("already bound");
+ if (addr == null)
+ addr = new InetSocketAddress(0);
+ if (!(addr instanceof InetSocketAddress))
+ throw new IllegalArgumentException("Unsupported address type!");
+ InetSocketAddress epoint = (InetSocketAddress) addr;
+ if (epoint.isUnresolved())
+ throw new SocketException("Unresolved address");
+ SecurityManager sec = System.getSecurityManager();
+ if (sec != null) {
+ sec.checkListen(epoint.getPort());
+ }
+ try {
+ getImpl().bind(epoint.getPort(),
+ epoint.getAddress());
+ } catch (SocketException e) {
+ getImpl().close();
+ throw e;
+ }
+ bound = true;
+ }
+
+ /**
+ * Connects the socket to a remote address for this socket. When a
+ * socket is connected to a remote address, packets may only be
+ * sent to or received from that address. By default a datagram
+ * socket is not connected.
+ *
+ * <p>If the remote destination to which the socket is connected does not
+ * exist, or is otherwise unreachable, and if an ICMP destination unreachable
+ * packet has been received for that address, then a subsequent call to
+ * send or receive may throw a PortUnreachableException. Note, there is no
+ * guarantee that the exception will be thrown.
+ *
+ * <p>A caller's permission to send and receive datagrams to a
+ * given host and port are checked at connect time. When a socket
+ * is connected, receive and send <b>will not
+ * perform any security checks</b> on incoming and outgoing
+ * packets, other than matching the packet's and the socket's
+ * address and port. On a send operation, if the packet's address
+ * is set and the packet's address and the socket's address do not
+ * match, an IllegalArgumentException will be thrown. A socket
+ * connected to a multicast address may only be used to send packets.
+ *
+ * @param address the remote address for the socket
+ *
+ * @param port the remote port for the socket.
+ *
+ * @exception IllegalArgumentException if the address is null,
+ * or the port is out of range.
+ *
+ * @exception SecurityException if the caller is not allowed to
+ * send datagrams to and receive datagrams from the address and port.
+ *
+ * @see #disconnect
+ * @see #send
+ * @see #receive
+ */
+ public void connect(InetAddress address, int port) {
+ try {
+ connectInternal(address, port);
+ } catch (SocketException se) {
+ throw new Error("connect failed", se);
+ }
+ }
+
+ /**
+ * Connects this socket to a remote socket address (IP address + port number).
+ * <p>
+ * @param addr The remote address.
+ * @throws SocketException if the connect fails
+ * @throws IllegalArgumentException if addr is null or addr is a SocketAddress
+ * subclass not supported by this socket
+ * @since 1.4
+ * @see #connect
+ */
+ public void connect(SocketAddress addr) throws SocketException {
+ if (addr == null)
+ throw new IllegalArgumentException("Address can't be null");
+ if (!(addr instanceof InetSocketAddress))
+ throw new IllegalArgumentException("Unsupported address type");
+ InetSocketAddress epoint = (InetSocketAddress) addr;
+ if (epoint.isUnresolved())
+ throw new SocketException("Unresolved address");
+ connectInternal(epoint.getAddress(), epoint.getPort());
+ }
+
+ /**
+ * Disconnects the socket. If the socket is closed or not connected,
+ * then this method has no effect.
+ *
+ * @see #connect
+ */
+ public void disconnect() {
+ synchronized (this) {
+ if (isClosed())
+ return;
+ if (connectState == ST_CONNECTED) {
+ impl.disconnect ();
+ }
+ connectedAddress = null;
+ connectedPort = -1;
+ connectState = ST_NOT_CONNECTED;
+ }
+ }
+
+ /**
+ * Returns the binding state of the socket.
+ * <p>
+ * If the socket was bound prior to being {@link #close closed},
+ * then this method will continue to return <code>true</code>
+ * after the socket is closed.
+ *
+ * @return true if the socket successfully bound to an address
+ * @since 1.4
+ */
+ public boolean isBound() {
+ return bound;
+ }
+
+ /**
+ * Returns the connection state of the socket.
+ * <p>
+ * If the socket was connected prior to being {@link #close closed},
+ * then this method will continue to return <code>true</code>
+ * after the socket is closed.
+ *
+ * @return true if the socket successfully connected to a server
+ * @since 1.4
+ */
+ public boolean isConnected() {
+ return connectState != ST_NOT_CONNECTED;
+ }
+
+ /**
+ * Returns the address to which this socket is connected. Returns
+ * <code>null</code> if the socket is not connected.
+ * <p>
+ * If the socket was connected prior to being {@link #close closed},
+ * then this method will continue to return the connected address
+ * after the socket is closed.
+ *
+ * @return the address to which this socket is connected.
+ */
+ public InetAddress getInetAddress() {
+ return connectedAddress;
+ }
+
+ /**
+ * Returns the port number to which this socket is connected.
+ * Returns <code>-1</code> if the socket is not connected.
+ * <p>
+ * If the socket was connected prior to being {@link #close closed},
+ * then this method will continue to return the connected port number
+ * after the socket is closed.
+ *
+ * @return the port number to which this socket is connected.
+ */
+ public int getPort() {
+ return connectedPort;
+ }
+
+ /**
+ * Returns the address of the endpoint this socket is connected to, or
+ * <code>null</code> if it is unconnected.
+ * <p>
+ * If the socket was connected prior to being {@link #close closed},
+ * then this method will continue to return the connected address
+ * after the socket is closed.
+ *
+ * @return a <code>SocketAddress</code> representing the remote
+ * endpoint of this socket, or <code>null</code> if it is
+ * not connected yet.
+ * @see #getInetAddress()
+ * @see #getPort()
+ * @see #connect(SocketAddress)
+ * @since 1.4
+ */
+ public SocketAddress getRemoteSocketAddress() {
+ if (!isConnected())
+ return null;
+ return new InetSocketAddress(getInetAddress(), getPort());
+ }
+
+ /**
+ * Returns the address of the endpoint this socket is bound to.
+ *
+ * @return a <code>SocketAddress</code> representing the local endpoint of this
+ * socket, or <code>null</code> if it is closed or not bound yet.
+ * @see #getLocalAddress()
+ * @see #getLocalPort()
+ * @see #bind(SocketAddress)
+ * @since 1.4
+ */
+
+ public SocketAddress getLocalSocketAddress() {
+ if (isClosed())
+ return null;
+ if (!isBound())
+ return null;
+ return new InetSocketAddress(getLocalAddress(), getLocalPort());
+ }
+
+ /**
+ * Sends a datagram packet from this socket. The
+ * <code>DatagramPacket</code> includes information indicating the
+ * data to be sent, its length, the IP address of the remote host,
+ * and the port number on the remote host.
+ *
+ * <p>If there is a security manager, and the socket is not currently
+ * connected to a remote address, this method first performs some
+ * security checks. First, if <code>p.getAddress().isMulticastAddress()</code>
+ * is true, this method calls the
+ * security manager's <code>checkMulticast</code> method
+ * with <code>p.getAddress()</code> as its argument.
+ * If the evaluation of that expression is false,
+ * this method instead calls the security manager's
+ * <code>checkConnect</code> method with arguments
+ * <code>p.getAddress().getHostAddress()</code> and
+ * <code>p.getPort()</code>. Each call to a security manager method
+ * could result in a SecurityException if the operation is not allowed.
+ *
+ * @param p the <code>DatagramPacket</code> to be sent.
+ *
+ * @exception IOException if an I/O error occurs.
+ * @exception SecurityException if a security manager exists and its
+ * <code>checkMulticast</code> or <code>checkConnect</code>
+ * method doesn't allow the send.
+ * @exception PortUnreachableException may be thrown if the socket is connected
+ * to a currently unreachable destination. Note, there is no
+ * guarantee that the exception will be thrown.
+ * @exception java.nio.channels.IllegalBlockingModeException
+ * if this socket has an associated channel,
+ * and the channel is in non-blocking mode.
+ * @exception IllegalArgumentException if the socket is connected,
+ * and connected address and packet address differ.
+ *
+ * @see java.net.DatagramPacket
+ * @see SecurityManager#checkMulticast(InetAddress)
+ * @see SecurityManager#checkConnect
+ * @revised 1.4
+ * @spec JSR-51
+ */
+ public void send(DatagramPacket p) throws IOException {
+ InetAddress packetAddress = null;
+ synchronized (p) {
+ if (isClosed())
+ throw new SocketException("Socket is closed");
+ if (connectState == ST_NOT_CONNECTED) {
+ // check the address is ok wiht the security manager on every send.
+ SecurityManager security = System.getSecurityManager();
+
+ // The reason you want to synchronize on datagram packet
+ // is because you dont want an applet to change the address
+ // while you are trying to send the packet for example
+ // after the security check but before the send.
+ if (security != null) {
+ if (p.getAddress().isMulticastAddress()) {
+ security.checkMulticast(p.getAddress());
+ } else {
+ security.checkConnect(p.getAddress().getHostAddress(),
+ p.getPort());
+ }
+ }
+ } else {
+ // we're connected
+ packetAddress = p.getAddress();
+ if (packetAddress == null) {
+ p.setAddress(connectedAddress);
+ p.setPort(connectedPort);
+ } else if ((!packetAddress.equals(connectedAddress)) ||
+ p.getPort() != connectedPort) {
+ throw new IllegalArgumentException("connected address " +
+ "and packet address" +
+ " differ");
+ }
+ }
+ // Check whether the socket is bound
+ if (!isBound())
+ bind(new InetSocketAddress(0));
+ // call the method to send
+ getImpl().send(p);
+ }
+ }
+
+ /**
+ * Receives a datagram packet from this socket. When this method
+ * returns, the <code>DatagramPacket</code>'s buffer is filled with
+ * the data received. The datagram packet also contains the sender's
+ * IP address, and the port number on the sender's machine.
+ * <p>
+ * This method blocks until a datagram is received. The
+ * <code>length</code> field of the datagram packet object contains
+ * the length of the received message. If the message is longer than
+ * the packet's length, the message is truncated.
+ * <p>
+ * If there is a security manager, a packet cannot be received if the
+ * security manager's <code>checkAccept</code> method
+ * does not allow it.
+ *
+ * @param p the <code>DatagramPacket</code> into which to place
+ * the incoming data.
+ * @exception IOException if an I/O error occurs.
+ * @exception SocketTimeoutException if setSoTimeout was previously called
+ * and the timeout has expired.
+ * @exception PortUnreachableException may be thrown if the socket is connected
+ * to a currently unreachable destination. Note, there is no guarantee that the
+ * exception will be thrown.
+ * @exception java.nio.channels.IllegalBlockingModeException
+ * if this socket has an associated channel,
+ * and the channel is in non-blocking mode.
+ * @see java.net.DatagramPacket
+ * @see java.net.DatagramSocket
+ * @revised 1.4
+ * @spec JSR-51
+ */
+ public synchronized void receive(DatagramPacket p) throws IOException {
+ synchronized (p) {
+ if (!isBound())
+ bind(new InetSocketAddress(0));
+ if (connectState == ST_NOT_CONNECTED) {
+ // check the address is ok with the security manager before every recv.
+ SecurityManager security = System.getSecurityManager();
+ if (security != null) {
+ while(true) {
+ String peekAd = null;
+ int peekPort = 0;
+ // peek at the packet to see who it is from.
+ if (!oldImpl) {
+ // We can use the new peekData() API
+ DatagramPacket peekPacket = new DatagramPacket(new byte[1], 1);
+ peekPort = getImpl().peekData(peekPacket);
+ peekAd = peekPacket.getAddress().getHostAddress();
+ } else {
+ InetAddress adr = new InetAddress();
+ peekPort = getImpl().peek(adr);
+ peekAd = adr.getHostAddress();
+ }
+ try {
+ security.checkAccept(peekAd, peekPort);
+ // security check succeeded - so now break
+ // and recv the packet.
+ break;
+ } catch (SecurityException se) {
+ // Throw away the offending packet by consuming
+ // it in a tmp buffer.
+ DatagramPacket tmp = new DatagramPacket(new byte[1], 1);
+ getImpl().receive(tmp);
+
+ // silently discard the offending packet
+ // and continue: unknown/malicious
+ // entities on nets should not make
+ // runtime throw security exception and
+ // disrupt the applet by sending random
+ // datagram packets.
+ continue;
+ }
+ } // end of while
+ }
+ }
+ if (connectState == ST_CONNECTED_NO_IMPL) {
+ // We have to do the filtering the old fashioned way since
+ // the native impl doesn't support connect or the connect
+ // via the impl failed.
+ boolean stop = false;
+ while (!stop) {
+ // peek at the packet to see who it is from.
+ InetAddress peekAddress = new InetAddress();
+ int peekPort = getImpl().peek(peekAddress);
+ if ((!connectedAddress.equals(peekAddress)) ||
+ (connectedPort != peekPort)) {
+ // throw the packet away and silently continue
+ DatagramPacket tmp = new DatagramPacket(new byte[1], 1);
+ getImpl().receive(tmp);
+ } else {
+ stop = true;
+ }
+ }
+ }
+ // If the security check succeeds, or the datagram is
+ // connected then receive the packet
+ getImpl().receive(p);
+ }
+ }
+
+ /**
+ * Gets the local address to which the socket is bound.
+ *
+ * <p>If there is a security manager, its
+ * <code>checkConnect</code> method is first called
+ * with the host address and <code>-1</code>
+ * as its arguments to see if the operation is allowed.
+ *
+ * @see SecurityManager#checkConnect
+ * @return the local address to which the socket is bound,
+ * <code>null</code> if the socket is closed, or
+ * an <code>InetAddress</code> representing
+ * {@link InetAddress#isAnyLocalAddress wildcard}
+ * address if either the socket is not bound, or
+ * the security manager <code>checkConnect</code>
+ * method does not allow the operation
+ * @since 1.1
+ */
+ public InetAddress getLocalAddress() {
+ if (isClosed())
+ return null;
+ InetAddress in = null;
+ try {
+ in = (InetAddress) getImpl().getOption(SocketOptions.SO_BINDADDR);
+ if (in.isAnyLocalAddress()) {
+ in = InetAddress.anyLocalAddress();
+ }
+ SecurityManager s = System.getSecurityManager();
+ if (s != null) {
+ s.checkConnect(in.getHostAddress(), -1);
+ }
+ } catch (Exception e) {
+ in = InetAddress.anyLocalAddress(); // "0.0.0.0"
+ }
+ return in;
+ }
+
+ /**
+ * Returns the port number on the local host to which this socket
+ * is bound.
+ *
+ * @return the port number on the local host to which this socket is bound,
+ <code>-1</code> if the socket is closed, or
+ <code>0</code> if it is not bound yet.
+ */
+ public int getLocalPort() {
+ if (isClosed())
+ return -1;
+ try {
+ return getImpl().getLocalPort();
+ } catch (Exception e) {
+ return 0;
+ }
+ }
+
+ /** Enable/disable SO_TIMEOUT with the specified timeout, in
+ * milliseconds. With this option set to a non-zero timeout,
+ * a call to receive() for this DatagramSocket
+ * will block for only this amount of time. If the timeout expires,
+ * a <B>java.net.SocketTimeoutException</B> is raised, though the
+ * DatagramSocket is still valid. The option <B>must</B> be enabled
+ * prior to entering the blocking operation to have effect. The
+ * timeout must be > 0.
+ * A timeout of zero is interpreted as an infinite timeout.
+ *
+ * @param timeout the specified timeout in milliseconds.
+ * @throws SocketException if there is an error in the underlying protocol, such as an UDP error.
+ * @since JDK1.1
+ * @see #getSoTimeout()
+ */
+ public synchronized void setSoTimeout(int timeout) throws SocketException {
+ if (isClosed())
+ throw new SocketException("Socket is closed");
+ getImpl().setOption(SocketOptions.SO_TIMEOUT, new Integer(timeout));
+ }
+
+ /**
+ * Retrieve setting for SO_TIMEOUT. 0 returns implies that the
+ * option is disabled (i.e., timeout of infinity).
+ *
+ * @return the setting for SO_TIMEOUT
+ * @throws SocketException if there is an error in the underlying protocol, such as an UDP error.
+ * @since JDK1.1
+ * @see #setSoTimeout(int)
+ */
+ public synchronized int getSoTimeout() throws SocketException {
+ if (isClosed())
+ throw new SocketException("Socket is closed");
+ if (getImpl() == null)
+ return 0;
+ Object o = getImpl().getOption(SocketOptions.SO_TIMEOUT);
+ /* extra type safety */
+ if (o instanceof Integer) {
+ return ((Integer) o).intValue();
+ } else {
+ return 0;
+ }
+ }
+
+ /**
+ * Sets the SO_SNDBUF option to the specified value for this
+ * <tt>DatagramSocket</tt>. The SO_SNDBUF option is used by the
+ * network implementation as a hint to size the underlying
+ * network I/O buffers. The SO_SNDBUF setting may also be used
+ * by the network implementation to determine the maximum size
+ * of the packet that can be sent on this socket.
+ * <p>
+ * As SO_SNDBUF is a hint, applications that want to verify
+ * what size the buffer is should call {@link #getSendBufferSize()}.
+ * <p>
+ * Increasing the buffer size may allow multiple outgoing packets
+ * to be queued by the network implementation when the send rate
+ * is high.
+ * <p>
+ * Note: If {@link #send(DatagramPacket)} is used to send a
+ * <code>DatagramPacket</code> that is larger than the setting
+ * of SO_SNDBUF then it is implementation specific if the
+ * packet is sent or discarded.
+ *
+ * @param size the size to which to set the send buffer
+ * size. This value must be greater than 0.
+ *
+ * @exception SocketException if there is an error
+ * in the underlying protocol, such as an UDP error.
+ * @exception IllegalArgumentException if the value is 0 or is
+ * negative.
+ * @see #getSendBufferSize()
+ */
+ public synchronized void setSendBufferSize(int size)
+ throws SocketException{
+ if (!(size > 0)) {
+ throw new IllegalArgumentException("negative send size");
+ }
+ if (isClosed())
+ throw new SocketException("Socket is closed");
+ getImpl().setOption(SocketOptions.SO_SNDBUF, new Integer(size));
+ }
+
+ /**
+ * Get value of the SO_SNDBUF option for this <tt>DatagramSocket</tt>, that is the
+ * buffer size used by the platform for output on this <tt>DatagramSocket</tt>.
+ *
+ * @return the value of the SO_SNDBUF option for this <tt>DatagramSocket</tt>
+ * @exception SocketException if there is an error in
+ * the underlying protocol, such as an UDP error.
+ * @see #setSendBufferSize
+ */
+ public synchronized int getSendBufferSize() throws SocketException {
+ if (isClosed())
+ throw new SocketException("Socket is closed");
+ int result = 0;
+ Object o = getImpl().getOption(SocketOptions.SO_SNDBUF);
+ if (o instanceof Integer) {
+ result = ((Integer)o).intValue();
+ }
+ return result;
+ }
+
+ /**
+ * Sets the SO_RCVBUF option to the specified value for this
+ * <tt>DatagramSocket</tt>. The SO_RCVBUF option is used by the
+ * the network implementation as a hint to size the underlying
+ * network I/O buffers. The SO_RCVBUF setting may also be used
+ * by the network implementation to determine the maximum size
+ * of the packet that can be received on this socket.
+ * <p>
+ * Because SO_RCVBUF is a hint, applications that want to
+ * verify what size the buffers were set to should call
+ * {@link #getReceiveBufferSize()}.
+ * <p>
+ * Increasing SO_RCVBUF may allow the network implementation
+ * to buffer multiple packets when packets arrive faster than
+ * are being received using {@link #receive(DatagramPacket)}.
+ * <p>
+ * Note: It is implementation specific if a packet larger
+ * than SO_RCVBUF can be received.
+ *
+ * @param size the size to which to set the receive buffer
+ * size. This value must be greater than 0.
+ *
+ * @exception SocketException if there is an error in
+ * the underlying protocol, such as an UDP error.
+ * @exception IllegalArgumentException if the value is 0 or is
+ * negative.
+ * @see #getReceiveBufferSize()
+ */
+ public synchronized void setReceiveBufferSize(int size)
+ throws SocketException{
+ if (size <= 0) {
+ throw new IllegalArgumentException("invalid receive size");
+ }
+ if (isClosed())
+ throw new SocketException("Socket is closed");
+ getImpl().setOption(SocketOptions.SO_RCVBUF, new Integer(size));
+ }
+
+ /**
+ * Get value of the SO_RCVBUF option for this <tt>DatagramSocket</tt>, that is the
+ * buffer size used by the platform for input on this <tt>DatagramSocket</tt>.
+ *
+ * @return the value of the SO_RCVBUF option for this <tt>DatagramSocket</tt>
+ * @exception SocketException if there is an error in the underlying protocol, such as an UDP error.
+ * @see #setReceiveBufferSize(int)
+ */
+ public synchronized int getReceiveBufferSize()
+ throws SocketException{
+ if (isClosed())
+ throw new SocketException("Socket is closed");
+ int result = 0;
+ Object o = getImpl().getOption(SocketOptions.SO_RCVBUF);
+ if (o instanceof Integer) {
+ result = ((Integer)o).intValue();
+ }
+ return result;
+ }
+
+ /**
+ * Enable/disable the SO_REUSEADDR socket option.
+ * <p>
+ * For UDP sockets it may be necessary to bind more than one
+ * socket to the same socket address. This is typically for the
+ * purpose of receiving multicast packets
+ * (See {@link java.net.MulticastSocket}). The
+ * <tt>SO_REUSEADDR</tt> socket option allows multiple
+ * sockets to be bound to the same socket address if the
+ * <tt>SO_REUSEADDR</tt> socket option is enabled prior
+ * to binding the socket using {@link #bind(SocketAddress)}.
+ * <p>
+ * Note: This functionality is not supported by all existing platforms,
+ * so it is implementation specific whether this option will be ignored
+ * or not. However, if it is not supported then
+ * {@link #getReuseAddress()} will always return <code>false</code>.
+ * <p>
+ * When a <tt>DatagramSocket</tt> is created the initial setting
+ * of <tt>SO_REUSEADDR</tt> is disabled.
+ * <p>
+ * The behaviour when <tt>SO_REUSEADDR</tt> is enabled or
+ * disabled after a socket is bound (See {@link #isBound()})
+ * is not defined.
+ *
+ * @param on whether to enable or disable the
+ * @exception SocketException if an error occurs enabling or
+ * disabling the <tt>SO_RESUEADDR</tt> socket option,
+ * or the socket is closed.
+ * @since 1.4
+ * @see #getReuseAddress()
+ * @see #bind(SocketAddress)
+ * @see #isBound()
+ * @see #isClosed()
+ */
+ public synchronized void setReuseAddress(boolean on) throws SocketException {
+ if (isClosed())
+ throw new SocketException("Socket is closed");
+ // Integer instead of Boolean for compatibility with older DatagramSocketImpl
+ if (oldImpl)
+ getImpl().setOption(SocketOptions.SO_REUSEADDR, new Integer(on?-1:0));
+ else
+ getImpl().setOption(SocketOptions.SO_REUSEADDR, Boolean.valueOf(on));
+ }
+
+ /**
+ * Tests if SO_REUSEADDR is enabled.
+ *
+ * @return a <code>boolean</code> indicating whether or not SO_REUSEADDR is enabled.
+ * @exception SocketException if there is an error
+ * in the underlying protocol, such as an UDP error.
+ * @since 1.4
+ * @see #setReuseAddress(boolean)
+ */
+ public synchronized boolean getReuseAddress() throws SocketException {
+ if (isClosed())
+ throw new SocketException("Socket is closed");
+ Object o = getImpl().getOption(SocketOptions.SO_REUSEADDR);
+ return ((Boolean)o).booleanValue();
+ }
+
+ /**
+ * Enable/disable SO_BROADCAST.
+ * @param on whether or not to have broadcast turned on.
+ * @exception SocketException if there is an error
+ * in the underlying protocol, such as an UDP error.
+ * @since 1.4
+ * @see #getBroadcast()
+ */
+ public synchronized void setBroadcast(boolean on) throws SocketException {
+ if (isClosed())
+ throw new SocketException("Socket is closed");
+ getImpl().setOption(SocketOptions.SO_BROADCAST, Boolean.valueOf(on));
+ }
+
+ /**
+ * Tests if SO_BROADCAST is enabled.
+ * @return a <code>boolean</code> indicating whether or not SO_BROADCAST is enabled.
+ * @exception SocketException if there is an error
+ * in the underlying protocol, such as an UDP error.
+ * @since 1.4
+ * @see #setBroadcast(boolean)
+ */
+ public synchronized boolean getBroadcast() throws SocketException {
+ if (isClosed())
+ throw new SocketException("Socket is closed");
+ return ((Boolean)(getImpl().getOption(SocketOptions.SO_BROADCAST))).booleanValue();
+ }
+
+ /**
+ * Sets traffic class or type-of-service octet in the IP
+ * datagram header for datagrams sent from this DatagramSocket.
+ * As the underlying network implementation may ignore this
+ * value applications should consider it a hint.
+ *
+ * <P> The tc <B>must</B> be in the range <code> 0 <= tc <=
+ * 255</code> or an IllegalArgumentException will be thrown.
+ * <p>Notes:
+ * <p>For Internet Protocol v4 the value consists of an
+ * <code>integer</code>, the least significant 8 bits of which
+ * represent the value of the TOS octet in IP packets sent by
+ * the socket.
+ * RFC 1349 defines the TOS values as follows:
+ * <p>
+ * <UL>
+ * <LI><CODE>IPTOS_LOWCOST (0x02)</CODE></LI>
+ * <LI><CODE>IPTOS_RELIABILITY (0x04)</CODE></LI>
+ * <LI><CODE>IPTOS_THROUGHPUT (0x08)</CODE></LI>
+ * <LI><CODE>IPTOS_LOWDELAY (0x10)</CODE></LI>
+ * </UL>
+ * The last low order bit is always ignored as this
+ * corresponds to the MBZ (must be zero) bit.
+ * <p>
+ * Setting bits in the precedence field may result in a
+ * SocketException indicating that the operation is not
+ * permitted.
+ * <p>
+ * for Internet Protocol v6 <code>tc</code> is the value that
+ * would be placed into the sin6_flowinfo field of the IP header.
+ *
+ * @param tc an <code>int</code> value for the bitset.
+ * @throws SocketException if there is an error setting the
+ * traffic class or type-of-service
+ * @since 1.4
+ * @see #getTrafficClass
+ */
+ public synchronized void setTrafficClass(int tc) throws SocketException {
+ if (tc < 0 || tc > 255)
+ throw new IllegalArgumentException("tc is not in range 0 -- 255");
+
+ if (isClosed())
+ throw new SocketException("Socket is closed");
+ getImpl().setOption(SocketOptions.IP_TOS, new Integer(tc));
+ }
+
+ /**
+ * Gets traffic class or type-of-service in the IP datagram
+ * header for packets sent from this DatagramSocket.
+ * <p>
+ * As the underlying network implementation may ignore the
+ * traffic class or type-of-service set using {@link #setTrafficClass(int)}
+ * this method may return a different value than was previously
+ * set using the {@link #setTrafficClass(int)} method on this
+ * DatagramSocket.
+ *
+ * @return the traffic class or type-of-service already set
+ * @throws SocketException if there is an error obtaining the
+ * traffic class or type-of-service value.
+ * @since 1.4
+ * @see #setTrafficClass(int)
+ */
+ public synchronized int getTrafficClass() throws SocketException {
+ if (isClosed())
+ throw new SocketException("Socket is closed");
+ return ((Integer)(getImpl().getOption(SocketOptions.IP_TOS))).intValue();
+ }
+
+ /**
+ * Closes this datagram socket.
+ * <p>
+ * Any thread currently blocked in {@link #receive} upon this socket
+ * will throw a {@link SocketException}.
+ *
+ * <p> If this socket has an associated channel then the channel is closed
+ * as well.
+ *
+ * @revised 1.4
+ * @spec JSR-51
+ */
+ public void close() {
+ synchronized(closeLock) {
+ if (isClosed())
+ return;
+ impl.close();
+ closed = true;
+ }
+ }
+
+ /**
+ * Returns whether the socket is closed or not.
+ *
+ * @return true if the socket has been closed
+ * @since 1.4
+ */
+ public boolean isClosed() {
+ synchronized(closeLock) {
+ return closed;
+ }
+ }
+
+ /**
+ * Returns the unique {@link java.nio.channels.DatagramChannel} object
+ * associated with this datagram socket, if any.
+ *
+ * <p> A datagram socket will have a channel if, and only if, the channel
+ * itself was created via the {@link java.nio.channels.DatagramChannel#open
+ * DatagramChannel.open} method.
+ *
+ * @return the datagram channel associated with this datagram socket,
+ * or <tt>null</tt> if this socket was not created for a channel
+ *
+ * @since 1.4
+ * @spec JSR-51
+ */
+ public DatagramChannel getChannel() {
+ return null;
+ }
+
+ /**
+ * User defined factory for all datagram sockets.
+ */
+ static DatagramSocketImplFactory factory;
+
+ /**
+ * Sets the datagram socket implementation factory for the
+ * application. The factory can be specified only once.
+ * <p>
+ * When an application creates a new datagram socket, the socket
+ * implementation factory's <code>createDatagramSocketImpl</code> method is
+ * called to create the actual datagram socket implementation.
+ * <p>
+ * Passing <code>null</code> to the method is a no-op unless the factory
+ * was already set.
+ *
+ * <p>If there is a security manager, this method first calls
+ * the security manager's <code>checkSetFactory</code> method
+ * to ensure the operation is allowed.
+ * This could result in a SecurityException.
+ *
+ * @param fac the desired factory.
+ * @exception IOException if an I/O error occurs when setting the
+ * datagram socket factory.
+ * @exception SocketException if the factory is already defined.
+ * @exception SecurityException if a security manager exists and its
+ * <code>checkSetFactory</code> method doesn't allow the
+ operation.
+ * @see
+ java.net.DatagramSocketImplFactory#createDatagramSocketImpl()
+ * @see SecurityManager#checkSetFactory
+ * @since 1.3
+ */
+ public static synchronized void
+ setDatagramSocketImplFactory(DatagramSocketImplFactory fac)
+ throws IOException
+ {
+ if (factory != null) {
+ throw new SocketException("factory already defined");
+ }
+ SecurityManager security = System.getSecurityManager();
+ if (security != null) {
+ security.checkSetFactory();
+ }
+ factory = fac;
+ }
+}