0001: /*
0002: * @(#)DatagramSocket.java 1.59 06/10/10
0003: *
0004: * Copyright 1990-2006 Sun Microsystems, Inc. All Rights Reserved.
0005: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER
0006: *
0007: * This program is free software; you can redistribute it and/or
0008: * modify it under the terms of the GNU General Public License version
0009: * 2 only, as published by the Free Software Foundation.
0010: *
0011: * This program is distributed in the hope that it will be useful, but
0012: * WITHOUT ANY WARRANTY; without even the implied warranty of
0013: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
0014: * General Public License version 2 for more details (a copy is
0015: * included at /legal/license.txt).
0016: *
0017: * You should have received a copy of the GNU General Public License
0018: * version 2 along with this work; if not, write to the Free Software
0019: * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
0020: * 02110-1301 USA
0021: *
0022: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
0023: * Clara, CA 95054 or visit www.sun.com if you need additional
0024: * information or have any questions.
0025: *
0026: */
0027:
0028: package java.net;
0029:
0030: import java.io.FileDescriptor;
0031: import java.io.IOException;
0032: import java.io.InterruptedIOException;
0033: import java.security.AccessController;
0034: import java.security.PrivilegedExceptionAction;
0035: import sun.security.action.GetPropertyAction;
0036:
0037: /**
0038: * This class represents a socket for sending and receiving datagram packets.
0039: *
0040: * <p>A datagram socket is the sending or receiving point for a packet
0041: * delivery service. Each packet sent or received on a datagram socket
0042: * is individually addressed and routed. Multiple packets sent from
0043: * one machine to another may be routed differently, and may arrive in
0044: * any order.
0045: *
0046: * <p>UDP broadcasts sends are always enabled on a DatagramSocket.
0047: * In order to receive broadcast packets a DatagramSocket
0048: * should be bound to the wildcard address. In some
0049: * implementations, broadcast packets may also be received when
0050: * a DatagramSocket is bound to a more specific address.
0051: * <p>
0052: * Example:
0053: * <code>
0054: * DatagramSocket s = new DatagramSocket(null);
0055: * s.bind(new InetSocketAddress(8888));
0056: * </code>
0057: * Which is equivalent to:
0058: * <code>
0059: * DatagramSocket s = new DatagramSocket(8888);
0060: * </code>
0061: * Both cases will create a DatagramSocket able to receive broadcasts on
0062: * UDP port 8888.
0063: *
0064: * @author Pavani Diwanji
0065: * @version 1.49, 02/02/00
0066: * @see java.net.DatagramPacket
0067: * @since JDK1.0
0068: */
0069: public class DatagramSocket {
0070: /**
0071: * Various states of this socket.
0072: */
0073: private boolean created = false;
0074: private boolean bound = false;
0075: private boolean closed = false;
0076: private Object closeLock = new Object();
0077:
0078: /*
0079: * The implementation of this DatagramSocket.
0080: */
0081: DatagramSocketImpl impl;
0082:
0083: /**
0084: * Are we using an older DatagramSocketImpl?
0085: */
0086: boolean oldImpl = false;
0087:
0088: /*
0089: * Connection state:
0090: * ST_NOT_CONNECTED = socket not connected
0091: * ST_CONNECTED = socket connected
0092: * ST_CONNECTED_NO_IMPL = socket connected but not at impl level
0093: */
0094: static final int ST_NOT_CONNECTED = 0;
0095: static final int ST_CONNECTED = 1;
0096: static final int ST_CONNECTED_NO_IMPL = 2;
0097:
0098: int connectState = ST_NOT_CONNECTED;
0099:
0100: /*
0101: * Connected address & port
0102: */
0103: InetAddress connectedAddress = null;
0104: int connectedPort = -1;
0105:
0106: /**
0107: * Connects this socket to a remote socket address (IP address + port number).
0108: * Binds socket if not already bound.
0109: * <p>
0110: * @param addr The remote address.
0111: * @param port The remote port
0112: * @throws SocketException if binding the socket fails.
0113: */
0114: private synchronized void connectInternal(InetAddress address,
0115: int port) throws SocketException {
0116: if (port < 0 || port > 0xFFFF) {
0117: throw new IllegalArgumentException("connect: " + port);
0118: }
0119: if (address == null) {
0120: throw new IllegalArgumentException("connect: null address");
0121: }
0122: if (isClosed())
0123: return;
0124: SecurityManager security = System.getSecurityManager();
0125: if (security != null) {
0126: if (address.isMulticastAddress()) {
0127: security.checkMulticast(address);
0128: } else {
0129: security.checkConnect(address.getHostAddress(), port);
0130: security.checkAccept(address.getHostAddress(), port);
0131: }
0132: }
0133:
0134: if (!isBound())
0135: bind(new InetSocketAddress(0));
0136:
0137: // old impls do not support connect/disconnect
0138: if (oldImpl) {
0139: connectState = ST_CONNECTED_NO_IMPL;
0140: } else {
0141: try {
0142: getImpl().connect(address, port);
0143:
0144: // socket is now connected by the impl
0145: connectState = ST_CONNECTED;
0146: } catch (SocketException se) {
0147:
0148: // connection will be emulated by DatagramSocket
0149: connectState = ST_CONNECTED_NO_IMPL;
0150: }
0151: }
0152:
0153: connectedAddress = address;
0154: connectedPort = port;
0155: }
0156:
0157: /**
0158: * Constructs a datagram socket and binds it to any available port
0159: * on the local host machine. The socket will be bound to the wildcard
0160: * address, an IP address chosen by the kernel.
0161: *
0162: * <p>If there is a security manager,
0163: * its <code>checkListen</code> method is first called
0164: * with 0 as its argument to ensure the operation is allowed.
0165: * This could result in a SecurityException.
0166: *
0167: * @exception SocketException if the socket could not be opened,
0168: * or the socket could not bind to the specified local port.
0169: * @exception SecurityException if a security manager exists and its
0170: * <code>checkListen</code> method doesn't allow the operation.
0171: *
0172: * @see SecurityManager#checkListen
0173: */
0174: public DatagramSocket() throws SocketException {
0175: // create a datagram socket.
0176: createImpl();
0177: try {
0178: bind(new InetSocketAddress(0));
0179: } catch (SocketException se) {
0180: throw se;
0181: } catch (IOException e) {
0182: throw new SocketException(e.getMessage());
0183: }
0184: }
0185:
0186: /**
0187: * Creates an unbound datagram socket with the specified
0188: * DatagramSocketImpl.
0189: *
0190: * @param impl an instance of a <B>DatagramSocketImpl</B>
0191: * the subclass wishes to use on the DatagramSocket.
0192: * @since 1.4
0193: */
0194: protected DatagramSocket(DatagramSocketImpl impl) {
0195: if (impl == null)
0196: throw new NullPointerException();
0197: this .impl = impl;
0198: checkOldImpl();
0199: }
0200:
0201: /**
0202: * Creates a datagram socket, bound to the specified local
0203: * socket address.
0204: * <p>
0205: * If, if the address is <code>null</code>, creates an unbound socket.
0206: * <p>
0207: * <p>If there is a security manager,
0208: * its <code>checkListen</code> method is first called
0209: * with the port from the socket address
0210: * as its argument to ensure the operation is allowed.
0211: * This could result in a SecurityException.
0212: *
0213: * @param bindaddr local socket address to bind, or <code>null</code>
0214: * for an unbound socket.
0215: *
0216: * @exception SocketException if the socket could not be opened,
0217: * or the socket could not bind to the specified local port.
0218: * @exception SecurityException if a security manager exists and its
0219: * <code>checkListen</code> method doesn't allow the operation.
0220: *
0221: * @see SecurityManager#checkListen
0222: * @since 1.4
0223: */
0224: public DatagramSocket(SocketAddress bindaddr)
0225: throws SocketException {
0226: // create a datagram socket.
0227: createImpl();
0228: if (bindaddr != null) {
0229: bind(bindaddr);
0230: }
0231: }
0232:
0233: /**
0234: * Constructs a datagram socket and binds it to the specified port
0235: * on the local host machine. The socket will be bound to the wildcard
0236: * address, an IP address chosen by the kernel.
0237: *
0238: * <p>If there is a security manager,
0239: * its <code>checkListen</code> method is first called
0240: * with the <code>port</code> argument
0241: * as its argument to ensure the operation is allowed.
0242: * This could result in a SecurityException.
0243: *
0244: * @param port port to use.
0245: * @exception SocketException if the socket could not be opened,
0246: * or the socket could not bind to the specified local port.
0247: * @exception SecurityException if a security manager exists and its
0248: * <code>checkListen</code> method doesn't allow the operation.
0249: *
0250: * @see SecurityManager#checkListen
0251: */
0252: public DatagramSocket(int port) throws SocketException {
0253: this (port, null);
0254: }
0255:
0256: /**
0257: * Creates a datagram socket, bound to the specified local
0258: * address. The local port must be between 0 and 65535 inclusive.
0259: * If the IP address is 0.0.0.0, the socket will be bound to the
0260: * wildcard address, an IP address chosen by the kernel.
0261: *
0262: * <p>If there is a security manager,
0263: * its <code>checkListen</code> method is first called
0264: * with the <code>port</code> argument
0265: * as its argument to ensure the operation is allowed.
0266: * This could result in a SecurityException.
0267: *
0268: * @param port local port to use
0269: * @param laddr local address to bind
0270: *
0271: * @exception SocketException if the socket could not be opened,
0272: * or the socket could not bind to the specified local port.
0273: * @exception SecurityException if a security manager exists and its
0274: * <code>checkListen</code> method doesn't allow the operation.
0275: *
0276: * @see SecurityManager#checkListen
0277: * @since JDK1.1
0278: */
0279: public DatagramSocket(int port, InetAddress laddr)
0280: throws SocketException {
0281: this (new InetSocketAddress(laddr, port));
0282: }
0283:
0284: private void checkOldImpl() {
0285: if (impl == null)
0286: return;
0287: // DatagramSocketImpl.peekdata() is a protected method, therefore we need to use
0288: // getDeclaredMethod, therefore we need permission to access the member
0289: try {
0290: AccessController
0291: .doPrivileged(new PrivilegedExceptionAction() {
0292: public Object run()
0293: throws NoSuchMethodException {
0294: Class[] cl = new Class[1];
0295: cl[0] = DatagramPacket.class;
0296: impl.getClass().getDeclaredMethod(
0297: "peekData", cl);
0298: return null;
0299: }
0300: });
0301: } catch (java.security.PrivilegedActionException e) {
0302: oldImpl = true;
0303: }
0304: }
0305:
0306: static Class implClass = null;
0307:
0308: void createImpl() throws SocketException {
0309: if (impl == null) {
0310: if (factory != null) {
0311: impl = factory.createDatagramSocketImpl();
0312: checkOldImpl();
0313: } else {
0314: if (implClass == null) {
0315: String prefix = null;
0316: try {
0317: prefix = (String) AccessController
0318: .doPrivileged(new sun.security.action.GetPropertyAction(
0319: "impl.prefix", "Plain"));
0320: implClass = Class.forName("java.net." + prefix
0321: + "DatagramSocketImpl");
0322: } catch (Exception e) {
0323: System.err
0324: .println("Can't find class: java.net."
0325: + prefix
0326: + "DatagramSocketImpl: check impl.prefix property");
0327: }
0328: if (implClass == null)
0329: implClass = java.net.PlainDatagramSocketImpl.class;
0330: }
0331: try {
0332: impl = (DatagramSocketImpl) implClass.newInstance();
0333: } catch (Exception e) {
0334: throw new SocketException(
0335: "can't instantiate DatagramSocketImpl");
0336: }
0337: // No need to do a checkOldImpl() here, we know it's an up to date
0338: // SocketImpl!
0339: if (!(impl instanceof java.net.PlainDatagramSocketImpl))
0340: checkOldImpl();
0341: }
0342: }
0343: // creates a udp socket
0344: impl.create();
0345: created = true;
0346: }
0347:
0348: /**
0349: * Get the <code>DatagramSocketImpl</code> attached to this socket,
0350: * creating it if necessary.
0351: *
0352: * @return the <code>DatagramSocketImpl</code> attached to that
0353: * DatagramSocket
0354: * @throws SocketException if creation fails.
0355: * @since 1.4
0356: */
0357: DatagramSocketImpl getImpl() throws SocketException {
0358: if (!created)
0359: createImpl();
0360: return impl;
0361: }
0362:
0363: /**
0364: * Binds this DatagramSocket to a specific address & port.
0365: * <p>
0366: * If the address is <code>null</code>, then the system will pick up
0367: * an ephemeral port and a valid local address to bind the socket.
0368: *<p>
0369: * @param addr The address & port to bind to.
0370: * @throws SocketException if any error happens during the bind, or if the
0371: * socket is already bound.
0372: * @throws SecurityException if a security manager exists and its
0373: * <code>checkListen</code> method doesn't allow the operation.
0374: * @throws IllegalArgumentException if addr is a SocketAddress subclass
0375: * not supported by this socket.
0376: * @since 1.4
0377: */
0378: public synchronized void bind(SocketAddress addr)
0379: throws SocketException {
0380: if (isClosed())
0381: throw new SocketException("Socket is closed");
0382: if (isBound())
0383: throw new SocketException("already bound");
0384: if (addr == null)
0385: addr = new InetSocketAddress(0);
0386: if (!(addr instanceof InetSocketAddress))
0387: throw new IllegalArgumentException(
0388: "Unsupported address type!");
0389: InetSocketAddress epoint = (InetSocketAddress) addr;
0390: if (epoint.isUnresolved())
0391: throw new SocketException("Unresolved address");
0392: SecurityManager sec = System.getSecurityManager();
0393: if (sec != null) {
0394: sec.checkListen(epoint.getPort());
0395: }
0396: try {
0397: getImpl().bind(epoint.getPort(), epoint.getAddress());
0398: } catch (SocketException e) {
0399: getImpl().close();
0400: throw e;
0401: }
0402: bound = true;
0403: }
0404:
0405: /**
0406: * Connects the socket to a remote address for this socket. When a
0407: * socket is connected to a remote address, packets may only be
0408: * sent to or received from that address. By default a datagram
0409: * socket is not connected.
0410: *
0411: * <p>If the remote destination to which the socket is connected does not
0412: * exist, or is otherwise unreachable, and if an ICMP destination unreachable
0413: * packet has been received for that address, then a subsequent call to
0414: * send or receive may throw a PortUnreachableException. Note, there is no
0415: * guarantee that the exception will be thrown.
0416: *
0417: * <p>A caller's permission to send and receive datagrams to a
0418: * given host and port are checked at connect time. When a socket
0419: * is connected, receive and send <b>will not
0420: * perform any security checks</b> on incoming and outgoing
0421: * packets, other than matching the packet's and the socket's
0422: * address and port. On a send operation, if the packet's address
0423: * is set and the packet's address and the socket's address do not
0424: * match, an IllegalArgumentException will be thrown. A socket
0425: * connected to a multicast address may only be used to send packets.
0426: *
0427: * @param address the remote address for the socket
0428: *
0429: * @param port the remote port for the socket.
0430: *
0431: * @exception IllegalArgumentException if the address is null,
0432: * or the port is out of range.
0433: *
0434: * @exception SecurityException if the caller is not allowed to
0435: * send datagrams to and receive datagrams from the address and port.
0436: *
0437: * @see #disconnect
0438: * @see #send
0439: * @see #receive
0440: */
0441: public void connect(InetAddress address, int port) {
0442: try {
0443: connectInternal(address, port);
0444: } catch (SocketException se) {
0445: throw new Error("connect failed", se);
0446: }
0447: }
0448:
0449: /**
0450: * Connects this socket to a remote socket address (IP address + port number).
0451: * <p>
0452: * @param addr The remote address.
0453: * @throws SocketException if the connect fails
0454: * @throws IllegalArgumentException if addr is null or addr is a SocketAddress
0455: * subclass not supported by this socket
0456: * @since 1.4
0457: * @see #connect
0458: */
0459: public void connect(SocketAddress addr) throws SocketException {
0460: if (addr == null)
0461: throw new IllegalArgumentException("Address can't be null");
0462: if (!(addr instanceof InetSocketAddress))
0463: throw new IllegalArgumentException(
0464: "Unsupported address type");
0465: InetSocketAddress epoint = (InetSocketAddress) addr;
0466: if (epoint.isUnresolved())
0467: throw new SocketException("Unresolved address");
0468: connectInternal(epoint.getAddress(), epoint.getPort());
0469: }
0470:
0471: /**
0472: * Disconnects the socket. This does nothing if the socket is not
0473: * connected.
0474: *
0475: * @see #connect
0476: */
0477: public void disconnect() {
0478: synchronized (this ) {
0479: if (isClosed())
0480: return;
0481: if (connectState == ST_CONNECTED) {
0482: impl.disconnect();
0483: }
0484: connectedAddress = null;
0485: connectedPort = -1;
0486: connectState = ST_NOT_CONNECTED;
0487: }
0488: }
0489:
0490: /**
0491: * Returns the binding state of the socket.
0492: *
0493: * @return true if the socket succesfuly bound to an address
0494: * @since 1.4
0495: */
0496: public boolean isBound() {
0497: return bound;
0498: }
0499:
0500: /**
0501: * Returns the connection state of the socket.
0502: *
0503: * @return true if the socket succesfuly connected to a server
0504: * @since 1.4
0505: */
0506: public boolean isConnected() {
0507: return connectState != ST_NOT_CONNECTED;
0508: }
0509:
0510: /**
0511: * Returns the address to which this socket is connected. Returns null
0512: * if the socket is not connected.
0513: *
0514: * @return the address to which this socket is connected.
0515: */
0516: public InetAddress getInetAddress() {
0517: return connectedAddress;
0518: }
0519:
0520: /**
0521: * Returns the port for this socket. Returns -1 if the socket is not
0522: * connected.
0523: *
0524: * @return the port to which this socket is connected.
0525: */
0526: public int getPort() {
0527: return connectedPort;
0528: }
0529:
0530: /**
0531: * Returns the address of the endpoint this socket is connected to, or
0532: * <code>null</null> if it is unconnected.
0533: * @return a <code>SocketAddress</code> reprensenting the remote endpoint of this
0534: * socket, or <code>null</code> if it is not connected yet.
0535: * @see #getInetAddress()
0536: * @see #getPort()
0537: * @see #connect(SocketAddress)
0538: * @since 1.4
0539: */
0540: public SocketAddress getRemoteSocketAddress() {
0541: if (!isConnected())
0542: return null;
0543: return new InetSocketAddress(getInetAddress(), getPort());
0544: }
0545:
0546: /**
0547: * Returns the address of the endpoint this socket is bound to, or
0548: * <code>null</code> if it is not bound yet.
0549: *
0550: * @return a <code>SocketAddress</code> representing the local endpoint of this
0551: * socket, or <code>null</code> if it is not bound yet.
0552: * @see #getLocalAddress()
0553: * @see #getLocalPort()
0554: * @see #bind(SocketAddress)
0555: * @since 1.4
0556: */
0557:
0558: public SocketAddress getLocalSocketAddress() {
0559: if (!isBound())
0560: return null;
0561: return new InetSocketAddress(getLocalAddress(), getLocalPort());
0562: }
0563:
0564: /**
0565: * Sends a datagram packet from this socket. The
0566: * <code>DatagramPacket</code> includes information indicating the
0567: * data to be sent, its length, the IP address of the remote host,
0568: * and the port number on the remote host.
0569: *
0570: * <p>If there is a security manager, and the socket is not currently
0571: * connected to a remote address, this method first performs some
0572: * security checks. First, if <code>p.getAddress().isMulticastAddress()</code>
0573: * is true, this method calls the
0574: * security manager's <code>checkMulticast</code> method
0575: * with <code>p.getAddress()</code> as its argument.
0576: * If the evaluation of that expression is false,
0577: * this method instead calls the security manager's
0578: * <code>checkConnect</code> method with arguments
0579: * <code>p.getAddress().getHostAddress()</code> and
0580: * <code>p.getPort()</code>. Each call to a security manager method
0581: * could result in a SecurityException if the operation is not allowed.
0582: *
0583: * @param p the <code>DatagramPacket</code> to be sent.
0584: *
0585: * @exception IOException if an I/O error occurs.
0586: * @exception SecurityException if a security manager exists and its
0587: * <code>checkMulticast</code> or <code>checkConnect</code>
0588: * method doesn't allow the send.
0589: * @exception PortUnreachableException may be thrown if the socket is connected
0590: * to a currently unreachable destination. Note, there is no
0591: * guarantee that the exception will be thrown.
0592: *
0593: * @see java.net.DatagramPacket
0594: * @see SecurityManager#checkMulticast(InetAddress)
0595: * @see SecurityManager#checkConnect
0596: * @revised 1.4
0597: * @spec JSR-51
0598: */
0599: public void send(DatagramPacket p) throws IOException {
0600: InetAddress packetAddress = null;
0601: synchronized (p) {
0602: if (isClosed())
0603: throw new SocketException("Socket is closed");
0604: if (connectState == ST_NOT_CONNECTED) {
0605: // check the address is ok wiht the security manager on every send.
0606: SecurityManager security = System.getSecurityManager();
0607:
0608: // The reason you want to synchronize on datagram packet
0609: // is because you dont want an applet to change the address
0610: // while you are trying to send the packet for example
0611: // after the security check but before the send.
0612: if (security != null) {
0613: if (p.getAddress().isMulticastAddress()) {
0614: security.checkMulticast(p.getAddress());
0615: } else {
0616: security.checkConnect(p.getAddress()
0617: .getHostAddress(), p.getPort());
0618: }
0619: }
0620: } else {
0621: // we're connected
0622: packetAddress = p.getAddress();
0623: if (packetAddress == null) {
0624: p.setAddress(connectedAddress);
0625: p.setPort(connectedPort);
0626: } else if ((!packetAddress.equals(connectedAddress))
0627: || p.getPort() != connectedPort) {
0628: throw new IllegalArgumentException(
0629: "connected address " + "and packet address"
0630: + " differ");
0631: }
0632: }
0633: // Check whether the socket is bound
0634: if (!isBound())
0635: bind(new InetSocketAddress(0));
0636: // call the method to send
0637: getImpl().send(p);
0638: }
0639: }
0640:
0641: /**
0642: * Receives a datagram packet from this socket. When this method
0643: * returns, the <code>DatagramPacket</code>'s buffer is filled with
0644: * the data received. The datagram packet also contains the sender's
0645: * IP address, and the port number on the sender's machine.
0646: * <p>
0647: * This method blocks until a datagram is received. The
0648: * <code>length</code> field of the datagram packet object contains
0649: * the length of the received message. If the message is longer than
0650: * the packet's length, the message is truncated.
0651: * <p>
0652: * If there is a security manager, a packet cannot be received if the
0653: * security manager's <code>checkAccept</code> method
0654: * does not allow it.
0655: *
0656: * @param p the <code>DatagramPacket</code> into which to place
0657: * the incoming data.
0658: * @exception IOException if an I/O error occurs.
0659: * @exception SocketTimeoutException if setSoTimeout was previously called
0660: * and the timeout has expired.
0661: * @exception PortUnreachableException may be thrown if the socket is connected
0662: * to a currently unreachable destination. Note, there is no guarantee that the
0663: * exception will be thrown.
0664: * @see java.net.DatagramPacket
0665: * @see java.net.DatagramSocket
0666: * @revised 1.4
0667: * @spec JSR-51
0668: */
0669: public synchronized void receive(DatagramPacket p)
0670: throws IOException {
0671: synchronized (p) {
0672: if (!isBound())
0673: bind(new InetSocketAddress(0));
0674: if (connectState == ST_NOT_CONNECTED) {
0675: // check the address is ok with the security manager before every recv.
0676: SecurityManager security = System.getSecurityManager();
0677: if (security != null) {
0678: while (true) {
0679: String peekAd = null;
0680: int peekPort = 0;
0681: // peek at the packet to see who it is from.
0682: if (!oldImpl) {
0683: // We can use the new peekData() API
0684: DatagramPacket peekPacket = new DatagramPacket(
0685: new byte[1], 1);
0686: peekPort = getImpl().peekData(peekPacket);
0687: peekAd = peekPacket.getAddress()
0688: .getHostAddress();
0689: } else {
0690: InetAddress adr = new InetAddress();
0691: peekPort = getImpl().peek(adr);
0692: peekAd = adr.getHostAddress();
0693: }
0694: try {
0695: security.checkAccept(peekAd, peekPort);
0696: // security check succeeded - so now break
0697: // and recv the packet.
0698: break;
0699: } catch (SecurityException se) {
0700: // Throw away the offending packet by consuming
0701: // it in a tmp buffer.
0702: DatagramPacket tmp = new DatagramPacket(
0703: new byte[1], 1);
0704: getImpl().receive(tmp);
0705:
0706: // silently discard the offending packet
0707: // and continue: unknown/malicious
0708: // entities on nets should not make
0709: // runtime throw security exception and
0710: // disrupt the applet by sending random
0711: // datagram packets.
0712: continue;
0713: }
0714: } // end of while
0715: }
0716: }
0717: if (connectState == ST_CONNECTED_NO_IMPL) {
0718: // We have to do the filtering the old fashioned way since
0719: // the native impl doesn't support connect or the connect
0720: // via the impl failed.
0721: boolean stop = false;
0722: while (!stop) {
0723: // peek at the packet to see who it is from.
0724: InetAddress peekAddress = new InetAddress();
0725: int peekPort = getImpl().peek(peekAddress);
0726: if ((!connectedAddress.equals(peekAddress))
0727: || (connectedPort != peekPort)) {
0728: // throw the packet away and silently continue
0729: DatagramPacket tmp = new DatagramPacket(
0730: new byte[1], 1);
0731: getImpl().receive(tmp);
0732: } else {
0733: stop = true;
0734: }
0735: }
0736: }
0737: // If the security check succeeds, or the datagram is
0738: // connected then receive the packet
0739: getImpl().receive(p);
0740: }
0741: }
0742:
0743: /**
0744: * Gets the local address to which the socket is bound.
0745: *
0746: * <p>If there is a security manager, its
0747: * <code>checkConnect</code> method is first called
0748: * with the host address and <code>-1</code>
0749: * as its arguments to see if the operation is allowed.
0750: *
0751: * @see SecurityManager#checkConnect
0752: * @return the local address to which the socket is bound, or
0753: * an <code>InetAddress</code> representing any local
0754: * address if either the socket is not bound, or
0755: * the security manager <code>checkConnect</code>
0756: * method does not allow the operation
0757: * @since 1.1
0758: */
0759: public InetAddress getLocalAddress() {
0760: if (isClosed())
0761: return null;
0762: InetAddress in = null;
0763: try {
0764: in = (InetAddress) getImpl().getOption(
0765: SocketOptions.SO_BINDADDR);
0766: if (in.isAnyLocalAddress()) {
0767: in = InetAddress.anyLocalAddress();
0768: }
0769: SecurityManager s = System.getSecurityManager();
0770: if (s != null) {
0771: s.checkConnect(in.getHostAddress(), -1);
0772: }
0773: } catch (Exception e) {
0774: in = InetAddress.anyLocalAddress(); // "0.0.0.0"
0775: }
0776: return in;
0777: }
0778:
0779: /**
0780: * Returns the port number on the local host to which this socket is bound.
0781: *
0782: * @return the port number on the local host to which this socket is bound.
0783: */
0784: public int getLocalPort() {
0785: if (isClosed())
0786: return -1;
0787: try {
0788: return getImpl().getLocalPort();
0789: } catch (Exception e) {
0790: return 0;
0791: }
0792: }
0793:
0794: /** Enable/disable SO_TIMEOUT with the specified timeout, in
0795: * milliseconds. With this option set to a non-zero timeout,
0796: * a call to receive() for this DatagramSocket
0797: * will block for only this amount of time. If the timeout expires,
0798: * a <B>java.net.SocketTimeoutException</B> is raised, though the
0799: * DatagramSocket is still valid. The option <B>must</B> be enabled
0800: * prior to entering the blocking operation to have effect. The
0801: * timeout must be > 0.
0802: * A timeout of zero is interpreted as an infinite timeout.
0803: *
0804: * @param timeout the specified timeout in milliseconds.
0805: * @throws SocketException if there is an error in the underlying protocol, such as an UDP error.
0806: * @since JDK1.1
0807: * @see #getSoTimeout()
0808: */
0809: public synchronized void setSoTimeout(int timeout)
0810: throws SocketException {
0811: if (isClosed())
0812: throw new SocketException("Socket is closed");
0813: getImpl().setOption(SocketOptions.SO_TIMEOUT,
0814: new Integer(timeout));
0815: }
0816:
0817: /**
0818: * Retrive setting for SO_TIMEOUT. 0 returns implies that the
0819: * option is disabled (i.e., timeout of infinity).
0820: *
0821: * @return the setting for SO_TIMEOUT
0822: * @throws SocketException if there is an error in the underlying protocol, such as an UDP error.
0823: * @since JDK1.1
0824: * @see #setSoTimeout(int)
0825: */
0826: public synchronized int getSoTimeout() throws SocketException {
0827: if (isClosed())
0828: throw new SocketException("Socket is closed");
0829: if (getImpl() == null)
0830: return 0;
0831: Object o = getImpl().getOption(SocketOptions.SO_TIMEOUT);
0832: /* extra type safety */
0833: if (o instanceof Integer) {
0834: return ((Integer) o).intValue();
0835: } else {
0836: return 0;
0837: }
0838: }
0839:
0840: /**
0841: * Sets the SO_SNDBUF option to the specified value for this
0842: * <tt>DatagramSocket</tt>. The SO_SNDBUF option is used by the
0843: * network implementation as a hint to size the underlying
0844: * network I/O buffers. The SO_SNDBUF setting may also be used
0845: * by the network implementation to determine the maximum size
0846: * of the packet that can be sent on this socket.
0847: * <p>
0848: * As SO_SNDBUF is a hint, applications that want to verify
0849: * what size the buffer is should call {@link #getSendBufferSize()}.
0850: * <p>
0851: * Increasing the buffer size may allow multiple outgoing packets
0852: * to be queued by the network implementation when the send rate
0853: * is high.
0854: * <p>
0855: * Note: If {@link #send()} is used to send a
0856: * <code>DatagramPacket</code> that is larger than the setting
0857: * of SO_SNDBUF then it is implementation specific if the
0858: * packet is sent or discarded.
0859: *
0860: * @param size the size to which to set the send buffer
0861: * size. This value must be greater than 0.
0862: *
0863: * @exception SocketException if there is an error
0864: * in the underlying protocol, such as an UDP error.
0865: * @exception IllegalArgumentException if the value is 0 or is
0866: * negative.
0867: * @see #getSendBufferSize()
0868: */
0869: public synchronized void setSendBufferSize(int size)
0870: throws SocketException {
0871: if (!(size > 0)) {
0872: throw new IllegalArgumentException("negative send size");
0873: }
0874: if (isClosed())
0875: throw new SocketException("Socket is closed");
0876: getImpl().setOption(SocketOptions.SO_SNDBUF, new Integer(size));
0877: }
0878:
0879: /**
0880: * Get value of the SO_SNDBUF option for this <tt>DatagramSocket</tt>, that is the
0881: * buffer size used by the platform for output on this <tt>DatagramSocket</tt>.
0882: *
0883: * @return the value of the SO_SNDBUF option for this <tt>DatagramSocket</tt>
0884: * @exception SocketException if there is an error in
0885: * the underlying protocol, such as an UDP error.
0886: * @see #setSendBufferSize
0887: */
0888: public synchronized int getSendBufferSize() throws SocketException {
0889: if (isClosed())
0890: throw new SocketException("Socket is closed");
0891: int result = 0;
0892: Object o = getImpl().getOption(SocketOptions.SO_SNDBUF);
0893: if (o instanceof Integer) {
0894: result = ((Integer) o).intValue();
0895: }
0896: return result;
0897: }
0898:
0899: /**
0900: * Sets the SO_RCVBUF option to the specified value for this
0901: * <tt>DatagramSocket</tt>. The SO_RCVBUF option is used by the
0902: * the network implementation as a hint to size the underlying
0903: * network I/O buffers. The SO_RCVBUF setting may also be used
0904: * by the network implementation to determine the maximum size
0905: * of the packet that can be received on this socket.
0906: * <p>
0907: * Because SO_RCVBUF is a hint, applications that want to
0908: * verify what size the buffers were set to should call
0909: * {@link #getReceiveBufferSize()}.
0910: * <p>
0911: * Increasing SO_RCVBUF may allow the network implementation
0912: * to buffer multiple packets when packets arrive faster than
0913: * are being received using {@link #receive()}.
0914: * <p>
0915: * Note: It is implementation specific if a packet larger
0916: * than SO_RCVBUF can be received.
0917: *
0918: * @param size the size to which to set the receive buffer
0919: * size. This value must be greater than 0.
0920: *
0921: * @exception SocketException if there is an error in
0922: * the underlying protocol, such as an UDP error.
0923: * @exception IllegalArgumentException if the value is 0 or is
0924: * negative.
0925: * @see #getReceiveBufferSize()
0926: */
0927: public synchronized void setReceiveBufferSize(int size)
0928: throws SocketException {
0929: if (size <= 0) {
0930: throw new IllegalArgumentException("invalid receive size");
0931: }
0932: if (isClosed())
0933: throw new SocketException("Socket is closed");
0934: getImpl().setOption(SocketOptions.SO_RCVBUF, new Integer(size));
0935: }
0936:
0937: /**
0938: * Get value of the SO_RCVBUF option for this <tt>DatagramSocket</tt>, that is the
0939: * buffer size used by the platform for input on this <tt>DatagramSocket</tt>.
0940: *
0941: * @return the value of the SO_RCVBUF option for this <tt>DatagramSocket</tt>
0942: * @exception SocketException if there is an error in the underlying protocol, such as an UDP error.
0943: * @see #setReceiveBufferSize(int)
0944: */
0945: public synchronized int getReceiveBufferSize()
0946: throws SocketException {
0947: if (isClosed())
0948: throw new SocketException("Socket is closed");
0949: int result = 0;
0950: Object o = getImpl().getOption(SocketOptions.SO_RCVBUF);
0951: if (o instanceof Integer) {
0952: result = ((Integer) o).intValue();
0953: }
0954: return result;
0955: }
0956:
0957: /**
0958: * Enable/disable the SO_REUSEADDR socket option.
0959: * <p>
0960: * For UDP sockets it may be necessary to bind more than one
0961: * socket to the same socket address. This is typically for the
0962: * purpose of receiving multicast packets.
0963: * The <tt>SO_REUSEADDR</tt> socket option allows multiple
0964: * sockets to be bound to the same socket address if the
0965: * <tt>SO_REUSEADDR</tt> socket option is enabled prior
0966: * to binding the socket using {@link #bind(SocketAddress)}.
0967: * <p>
0968: * When a <tt>DatagramSocket</tt> is created the initial setting
0969: * of <tt>SO_REUSEADDR</tt> is disabled.
0970: * <p>
0971: * The behaviour when <tt>SO_REUSEADDR</tt> is enabled or
0972: * disabled after a socket is bound (See {@link #isBound()})
0973: * is not defined.
0974: *
0975: * @param on whether to enable or disable the
0976: * @exception SocketException if an error occurs enabling or
0977: * disabling the <tt>SO_RESUEADDR</tt> socket option,
0978: * or the socket is closed.
0979: * @since 1.4
0980: * @see #getReuseAddress()
0981: * @see #bind(SocketAddress)
0982: * @see #isBound()
0983: * @see #isClosed()
0984: */
0985: public synchronized void setReuseAddress(boolean on)
0986: throws SocketException {
0987: if (isClosed())
0988: throw new SocketException("Socket is closed");
0989: // Integer instead of Boolean for compatibility with older DatagramSocketImpl
0990: if (oldImpl)
0991: getImpl().setOption(SocketOptions.SO_REUSEADDR,
0992: new Integer(on ? -1 : 0));
0993: else
0994: getImpl().setOption(SocketOptions.SO_REUSEADDR,
0995: new Boolean(on));
0996: }
0997:
0998: /**
0999: * Tests if SO_REUSEADDR is enabled.
1000: *
1001: * @return a <code>boolean</code> indicating whether or not SO_REUSEADDR is enabled.
1002: * @exception SocketException if there is an error
1003: * in the underlying protocol, such as an UDP error.
1004: * @since 1.4
1005: * @see #setReuseAddress(boolean)
1006: */
1007: public synchronized boolean getReuseAddress()
1008: throws SocketException {
1009: if (isClosed())
1010: throw new SocketException("Socket is closed");
1011: Object o = getImpl().getOption(SocketOptions.SO_REUSEADDR);
1012: return ((Boolean) o).booleanValue();
1013: }
1014:
1015: /**
1016: * Enable/disable SO_BROADCAST.
1017: * @param on whether or not to have broadcast turned on.
1018: * @exception SocketException if there is an error
1019: * in the underlying protocol, such as an UDP error.
1020: * @since 1.4
1021: * @see #getBroadcast()
1022: */
1023: public synchronized void setBroadcast(boolean on)
1024: throws SocketException {
1025: if (isClosed())
1026: throw new SocketException("Socket is closed");
1027: getImpl()
1028: .setOption(SocketOptions.SO_BROADCAST, new Boolean(on));
1029: }
1030:
1031: /**
1032: * Tests if SO_BROADCAST is enabled.
1033: * @return a <code>boolean</code> indicating whether or not SO_BROADCAST is enabled.
1034: * @exception SocketException if there is an error
1035: * in the underlying protocol, such as an UDP error.
1036: * @since 1.4
1037: * @see #setBroadcast(boolean)
1038: */
1039: public synchronized boolean getBroadcast() throws SocketException {
1040: if (isClosed())
1041: throw new SocketException("Socket is closed");
1042: return ((Boolean) (getImpl()
1043: .getOption(SocketOptions.SO_BROADCAST))).booleanValue();
1044: }
1045:
1046: /**
1047: * Sets traffic class or type-of-service octet in the IP
1048: * datagram header for datagrams sent from this DatagramSocket.
1049: * As the underlying network implementation may ignore this
1050: * value applications should consider it a hint.
1051: *
1052: * <P> The tc <B>must</B> be in the range <code> 0 <= tc <=
1053: * 255</code> or an IllegalArgumentException will be thrown.
1054: * <p>Notes:
1055: * <p> for Internet Protocol v4 the value consists of an octet
1056: * with precedence and TOS fields as detailed in RFC 1349. The
1057: * TOS field is bitset created by bitwise-or'ing values such
1058: * the following :-
1059: * <p>
1060: * <UL>
1061: * <LI><CODE>IPTOS_LOWCOST (0x02)</CODE></LI>
1062: * <LI><CODE>IPTOS_RELIABILITY (0x04)</CODE></LI>
1063: * <LI><CODE>IPTOS_THROUGHPUT (0x08)</CODE></LI>
1064: * <LI><CODE>IPTOS_LOWDELAY (0x10)</CODE></LI>
1065: * </UL>
1066: * The last low order bit is always ignored as this
1067: * corresponds to the MBZ (must be zero) bit.
1068: * <p>
1069: * Setting bits in the precedence field may result in a
1070: * SocketException indicating that the operation is not
1071: * permitted.
1072: * <p>
1073: * for Internet Protocol v6 <code>tc</code> is the value that
1074: * would be placed into the sin6_flowinfo field of the IP header.
1075: *
1076: * @param tc an <code>int</code> value for the bitset.
1077: * @throws SocketException if there is an error setting the
1078: * traffic class or type-of-service
1079: * @since 1.4
1080: * @see #getTrafficClass
1081: */
1082: public synchronized void setTrafficClass(int tc)
1083: throws SocketException {
1084: if (tc < 0 || tc > 255)
1085: throw new IllegalArgumentException(
1086: "tc is not in range 0 -- 255");
1087:
1088: if (isClosed())
1089: throw new SocketException("Socket is closed");
1090: getImpl().setOption(SocketOptions.IP_TOS, new Integer(tc));
1091: }
1092:
1093: /**
1094: * Gets traffic class or type-of-service in the IP datagram
1095: * header for packets sent from this DatagramSocket.
1096: * <p>
1097: * As the underlying network implementation may ignore the
1098: * traffic class or type-of-service set using {@link #setTrafficClass()}
1099: * this method may return a different value than was previously
1100: * set using the {@link #setTrafficClass()} method on this
1101: * DatagramSocket.
1102: *
1103: * @return the traffic class or type-of-service already set
1104: * @throws SocketException if there is an error obtaining the
1105: * traffic class or type-of-service value.
1106: * @since 1.4
1107: * @see #setTrafficClass
1108: */
1109: public synchronized int getTrafficClass() throws SocketException {
1110: if (isClosed())
1111: throw new SocketException("Socket is closed");
1112: return ((Integer) (getImpl().getOption(SocketOptions.IP_TOS)))
1113: .intValue();
1114: }
1115:
1116: /**
1117: * Closes this datagram socket.
1118: * <p>
1119: * Any thread currently blocked in {#link receive} upon this socket
1120: * will throw a {@link SocketException}.
1121: *
1122: * <p> If this socket has an associated channel then the channel is closed
1123: * as well.
1124: *
1125: * @revised 1.4
1126: * @spec JSR-51
1127: */
1128: public void close() {
1129: synchronized (closeLock) {
1130: if (isClosed())
1131: return;
1132: impl.close();
1133: closed = true;
1134: }
1135: }
1136:
1137: /**
1138: * Returns wether the socket is closed or not.
1139: *
1140: * @return true if the socket has been closed
1141: * @since 1.4
1142: */
1143: public boolean isClosed() {
1144: synchronized (closeLock) {
1145: return closed;
1146: }
1147: }
1148:
1149: /**
1150: * Returns the unique {@link java.nio.channels.DatagramChannel} object
1151: * associated with this datagram socket, if any.
1152: *
1153: * <p> A datagram socket will have a channel if, and only if, the channel
1154: * itself was created via the {@link java.nio.channels.DatagramChannel#open
1155: * DatagramChannel.open} method.
1156: *
1157: * @return the datagram channel associated with this datagram socket,
1158: * or <tt>null</tt> if this socket was not created for a channel
1159: *
1160: * @since 1.4
1161: * @spec JSR-51
1162: */
1163: /* Not needed for CDC
1164: public DatagramChannel getChannel() {
1165: return null;
1166: }
1167: */
1168: /**
1169: * The factory for all datagram sockets.
1170: */
1171: static DatagramSocketImplFactory factory;
1172:
1173: /**
1174: * Sets the datagram socket implementation factory for the
1175: * application. The factory can be specified only once.
1176: * <p>
1177: * When an application creates a new datagram socket, the socket
1178: * implementation factory's <code>createDatagramSocketImpl</code> method is
1179: * called to create the actual datagram socket implementation.
1180: *
1181: * <p>If there is a security manager, this method first calls
1182: * the security manager's <code>checkSetFactory</code> method
1183: * to ensure the operation is allowed.
1184: * This could result in a SecurityException.
1185: *
1186: * @param fac the desired factory.
1187: * @exception IOException if an I/O error occurs when setting the
1188: * datagram socket factory.
1189: * @exception SocketException if the factory is already defined.
1190: * @exception SecurityException if a security manager exists and its
1191: * <code>checkSetFactory</code> method doesn't allow the
1192: operation.
1193: * @see
1194: java.net.DatagramSocketImplFactory#createDatagramSocketImpl()
1195: * @see SecurityManager#checkSetFactory
1196: */
1197: public static synchronized void setDatagramSocketImplFactory(
1198: DatagramSocketImplFactory fac) throws IOException {
1199: if (factory != null) {
1200: throw new SocketException("factory already defined");
1201: }
1202: SecurityManager security = System.getSecurityManager();
1203: if (security != null) {
1204: security.checkSetFactory();
1205: }
1206: factory = fac;
1207: }
1208: }
|