/************************************************************************** * Parts copyright (c) 2001 by Punch Telematix. All rights reserved. * * Parts copyright (c) 2007, 2009 by /k/ Embedded Java Solutions. * * All rights reserved. * * * * Redistribution and use in source and binary forms, with or without * * modification, are permitted provided that the following conditions * * are met: * * 1. Redistributions of source code must retain the above copyright * * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * * notice, this list of conditions and the following disclaimer in the * * documentation and/or other materials provided with the distribution. * * 3. Neither the name of Punch Telematix or of /k/ Embedded Java Solutions* * nor the names of other contributors may be used to endorse or promote* * products derived from this software without specific prior written * * permission. * * * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED * * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * * IN NO EVENT SHALL PUNCH TELEMATIX, /K/ EMBEDDED JAVA SOLUTIONS OR OTHER * * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * **************************************************************************/ package java.net; import java.io.IOException; public class DatagramSocket { private DatagramPacket peekGarbage; DatagramSocketImpl dsocket; InetAddress remoteAddress; int remoteport=-1; static DatagramSocketImplFactory theFactory; public static void setDatagramSocketImplFactory(DatagramSocketImplFactory factory) throws IOException { if (theFactory != null) { throw new SocketException(); } InetAddress.factoryCheck(); theFactory = factory; } static void multicastCheck(InetAddress addr) { if (wonka.vm.SecurityConfiguration.ENABLE_SECURITY_CHECKS) { SecurityManager sm = System.getSecurityManager(); if (sm != null) { sm.checkMulticast(addr); } } } /** ** Special Constructor to create MulticastSockets ... */ DatagramSocket(boolean Multicast){ } public DatagramSocket(SocketAddress saddr) throws SocketException { this(saddr == null ? 0 : ((InetSocketAddress)saddr).port, saddr == null ? null : ((InetSocketAddress)saddr).addr); } public DatagramSocket() throws SocketException, SecurityException { this(0,null); } public DatagramSocket(int port) throws SocketException, SecurityException { if(port < 0 || port > 65535) { throw new IllegalArgumentException(); } InetAddress.listenCheck(port); if(theFactory != null){ dsocket = theFactory.createDatagramSocketImpl(); } else { String s = GetSystemProperty.DATAGRAM_SOCKET_IMPL; try { dsocket = (DatagramSocketImpl) Class.forName(s).newInstance(); } catch(Exception e) { dsocket = new PlainDatagramSocketImpl(); } } dsocket.create(); dsocket.bind(port, InetAddress.allZeroAddress); } public DatagramSocket(int port, InetAddress laddr) throws SocketException, SecurityException { if(port < 0 || port > 65535) { throw new IllegalArgumentException(); } InetAddress.listenCheck(port); if(theFactory != null){ dsocket = theFactory.createDatagramSocketImpl(); } else { String s = GetSystemProperty.DATAGRAM_SOCKET_IMPL; try { dsocket = (DatagramSocketImpl) Class.forName(s).newInstance(); } catch(Exception e) { dsocket = new PlainDatagramSocketImpl(); } } dsocket.create(); dsocket.bind(port, laddr == null ? InetAddress.allZeroAddress : laddr); } public void setReuseAddress (boolean on) throws SocketException { if (dsocket == null) { throw new SocketException("DatagramSocket is closed"); } dsocket.setOption(SocketOptions.SO_REUSEADDR, new Boolean(on)); } public void setTrafficClass (int tc) throws SocketException { throw new SocketException("not yet implemented"); } public void bind(SocketAddress bindAddr) throws SocketException { if(dsocket == null) { throw new SocketException("DatagramSocket is closed"); } if (remoteAddress != null) { throw new SocketException("Datagram socket is already connected"); } if (bindAddr == null) { // TODO: we should bind to an ephemeral port and a valid local address throw new SocketException("Bind datagram socket to null address not yet implemented"); } else { try { InetSocketAddress isa = (InetSocketAddress)bindAddr; InetAddress address = isa.getAddress(); int port = isa.getPort(); if (wonka.vm.SecurityConfiguration.ENABLE_SECURITY_CHECKS) { SecurityManager sm = System.getSecurityManager(); if (sm != null) { sm.checkListen(port); } } dsocket.bind(port, address); } catch (ClassCastException cce) { throw new IllegalArgumentException(); } } } /** * * Connects the datagramsocket to a remote address. * Connecting a socket * will bypass security checks if you send packets to the connected socket. * * All other destination are not allowed ... */ public void connect(InetAddress address, int port) throws SecurityException { if (address == null || port < 0 || port > 65535) { throw new IllegalArgumentException(); } if (this.dsocket != null) { if (address.isMulticastAddress()) { multicastCheck(address); } else { InetAddress.connectCheck(address.getHostAddress(), port); } remoteAddress = address; remoteport = port; } } /** * * Connects the datagramsocket to a remote address. * Connecting a socket * will bypass security checks if you send packets to the connected socket. * * All other destination are not allowed ... */ public void connect(SocketAddress sa) throws SecurityException { InetSocketAddress isa; try { isa = (InetSocketAddress)sa; } catch (ClassCastException cce) { throw new IllegalArgumentException(); } connect(isa.getAddress(), isa.getPort()); } /** ** Disconnects the socket. This does nothing if the socket is not connected. ** */ public void disconnect() { remoteAddress = null; remoteport = -1; } public boolean getBroadcast() throws SocketException { if (dsocket == null) { throw new SocketException("DatagramSocket is closed"); } return ((Boolean) dsocket.getOption(SocketOptions.SO_BROADCAST)).booleanValue(); } public void setBroadcast(boolean on) throws SocketException { if (dsocket == null) { throw new SocketException("DatagramSocket is closed"); } dsocket.setOption(SocketOptions.SO_BROADCAST, new Boolean(on)); } /** ** The address to which this socket is connected or null if not connected. */ public InetAddress getInetAddress() { return remoteAddress; } /** ** The local address to which this socket is bound or null if not bound. */ public SocketAddress getLocalSocketAddress() { InetAddress localAddress = getLocalAddress(); if (localAddress == null) { return null; } int localport = getLocalPort(); return new InetSocketAddress(localAddress, localport); } /** ** The remote address to which this socket is connected or null if not connected. */ public SocketAddress getRemoteSocketAddress() { if (remoteAddress == null) { return null; } return new InetSocketAddress(remoteAddress, remoteport); } /** ** The port off the socket t o which this socket is connected or -1 if this socket is not connected. */ public int getPort() { return remoteport; } /** ** Sends a datagram packet from this socket. */ public void send(DatagramPacket p) throws IOException { if(dsocket == null) { throw new IOException("DatagramSocket is closed"); } if (remoteAddress == null) { // we are not connected all Packets are allowed to be send unless ... InetAddress addr = p.getAddress(); if (addr.isMulticastAddress()){ multicastCheck(addr); } else{ InetAddress.connectCheck(addr.getHostAddress(), p.getPort()); } } else if (!remoteAddress.equals(p.getAddress()) || remoteport != p.getPort()) { //only packets to remoteAddress at remoteport are allowed ... throw new IllegalArgumentException("packet has wrong destination"); } dsocket.send(p); } /** ** Receives a datagram packet from this socket. ** @remark if the incoming packet contians more bytes than the buffer of the packet can handle, then they are lost. */ public synchronized void receive(DatagramPacket p) throws IOException { if(dsocket == null) { throw new IOException("DatagramSocket is closed"); } //we stay in receive until we receive a packet that is allowed to be received ... if (remoteAddress == null) { // we are not connected all Packets received are allowed unless ... while (true) { dsocket.receive(p); try { InetAddress.acceptCheck(p.getAddress().getHostName(), p.getPort()); break; } catch(SecurityException se){} } } else { if(p == null){ throw new NullPointerException(); } //peek is used to make sure p doesn't get corrupted when an error occurs // or contain information that should not been seen for security reasons if(peekGarbage == null){ peekGarbage = new DatagramPacket(new byte[2],2); } InetAddress inAddr = new InetAddress(); while (remoteport != (dsocket.peek(inAddr)) || !inAddr.equals(remoteAddress)) { //only packets to remoteAddress at remoteport are allowed ... dsocket.receive(peekGarbage); } dsocket.receive(p); } } /** * * gets the local address to which the socket is bound. */ public InetAddress getLocalAddress() { if (dsocket != null) { try { InetAddress addr = (InetAddress) dsocket .getOption(SocketOptions.SO_BINDADDR); InetAddress.connectCheck(addr.getHostName(), -1); return addr; } catch (SocketException e) { } catch (SecurityException se) { } } return InetAddress.loopbackAddress; } /** ** The port number on the local host to which this socket is bound. */ public int getLocalPort() { return dsocket == null ? -1 : dsocket.localPort; } /** ** set the socket timeout values. ** @throws throws an IllegalArgumentException if timeout < 0 */ public synchronized void setSoTimeout(int timeout) throws SocketException { if (dsocket == null) { throw new SocketException("DatagramSocket is closed"); } if (timeout < 0 ) { throw new IllegalArgumentException(); } dsocket.setOption(SocketOptions.SO_TIMEOUT , new Integer(timeout)); } /** ** returns the timeout value of this socket. */ public synchronized int getSoTimeout() throws SocketException { if (dsocket == null) { throw new SocketException("DatagramSocket is closed"); } return ((Integer) dsocket.getOption(SocketOptions.SO_TIMEOUT)).intValue(); } public int getTrafficCless() { // TODO ... return 0; } /** ** This method tries to set the 'send' buffersize. There is no guarantee this call will have ** an effect on the native socket ... */ public synchronized void setSendBufferSize(int size) throws SocketException { if (dsocket == null) { throw new SocketException("DatagramSocket is closed"); } if (size <= 0 ) { throw new IllegalArgumentException("size should be > 0, but got "+size); } dsocket.setOption(SocketOptions.SO_SNDBUF , new Integer(size)); } /** ** returns the size of the 'send' buffers of this socket. */ public synchronized int getSendBufferSize() throws SocketException { if (dsocket == null) { throw new SocketException("DatagramSocket is closed"); } return ((Integer) dsocket.getOption(SocketOptions.SO_SNDBUF)).intValue(); } /** ** This method tries to set the 'recieve' buffersize. There is no guarantee this call will have ** an effect on the native socket ... */ public synchronized void setReceiveBufferSize(int size) throws SocketException { if (dsocket == null) { throw new SocketException("DatagramSocket is closed"); } if (size <= 0 ) { throw new IllegalArgumentException("size should be > 0, but got "+size); } dsocket.setOption(SocketOptions.SO_RCVBUF , new Integer(size)); } /** ** returns the size of the 'recieve' buffers of this socket. */ public synchronized int getReceiveBufferSize() throws SocketException { if (dsocket == null) { throw new SocketException("DatagramSocket is closed"); } return ((Integer) dsocket.getOption(SocketOptions.SO_RCVBUF)).intValue(); } public boolean getReuseAddress() throws SocketException { if (dsocket == null) { throw new SocketException("DatagramSocket is closed"); } return ((Boolean) dsocket.getOption(SocketOptions.SO_REUSEADDR)).booleanValue(); } /** ** closes this socket. */ public void close() { disconnect(); if (dsocket != null) { dsocket.close(); dsocket = null; } } public boolean isBound() { return getLocalAddress() != null; } public boolean isConnected() { return remoteAddress != null; } public boolean isClosed() { return dsocket == null; } }