/* * @(#)Protocol.java 1.33 06/10/13 * * Copyright 1990-2008 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER * * This program 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. * * This program 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 at /legal/license.txt). * * 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 or visit www.sun.com if you need additional * information or have any questions. * */ package com.sun.cdc.io.j2me.datagram; import java.io.*; import java.net.*; import javax.microedition.io.*; import com.sun.cdc.io.j2me.*; import com.sun.cdc.io.*; /** * This implements the "datagram://" protocol for J2SE in a not very * efficient way. * * @version 1.1 11/19/99 */ public class Protocol extends ConnectionBase implements DatagramConnection,UDPDatagramConnection { DatagramSocket endpoint; /** * Machine name */ private String host = null; /** * Port */ private int port = 0; protected boolean open; public String getLocalAddress() throws IOException { if (!open) { throw new IOException("Connection closed"); } if (host != null) return host; else /* it is datagram://: string, server endpoint */ return InetAddress.getLocalHost().getHostAddress(); } public int getLocalPort() throws IOException { if (!open) { throw new IOException("Connection closed"); } return endpoint.getLocalPort(); } /** * Local function to get the machine address from a string */ protected static String getAddress(String name) throws IOException { /* Look for the : */ int colon = name.indexOf(':'); if(colon < 0) { throw new IllegalArgumentException("No ':' in protocol name "+name); } if(colon == 0) { return null; } else { return parseHostName(name, colon); } } protected static String parseHostName(String connection, int colon) { /* IPv6 addresses are enclosed within [] */ if ((connection.indexOf("[") == 0) && (connection.indexOf("]") > 0)) { return parseIPv6Address(connection, colon); } else { return parseIPv4Address(connection, colon); } } protected static String parseIPv4Address(String name, int colon) { return name.substring(0, colon); } protected static String parseIPv6Address(String address, int colon) { int closing = address.indexOf("]"); /* beginning '[' and closing ']' should be included in the hostname*/ return address.substring(0, closing+1); } /** * Local function to get the port number from a string */ protected static int getPort(String name) throws IOException, NumberFormatException { /* Look for the : */ int colon = name.lastIndexOf(':'); if(colon < 0) { throw new IllegalArgumentException("No ':' in protocol name "+name); } return Integer.parseInt(name.substring(colon+1)); } /* * We will throw a SecurityException if permission * checks fail. For CDC the DatagramSocket obect * creation will do this itself so we can use that * checking. This method should be overriden by MIDP * protocol handlers to properly check MIDP permissions. */ protected void checkPermission(String host, int port) { return; } /* * Check permission when opening an OutputStream. MIDP * versions of the protocol handler should override this * with an empty method. Throw a SecurityException if * the connection is not allowed. Currently the datagram * protocol handler does not make a permission check at * this point so this method is empty. */ protected void outputStreamPermissionCheck() { return; } /* * Check permission when opening an InputStream. MIDP * versions of the protocol handler should override this * with an empty method. A SecurityException will be * raised if the connection is not allowed. Currently the * datagram protocol handler does not make a permission * check at this point so this method is empty. */ protected void inputStreamPermissionCheck() { return; } /** * Open a connection to a target. <p> * * The name string for this protocol should be: * "[address:][port]" * * @param name the target of the connection * @param writeable a flag that is true if the caller intends to * write to the connection. * @param timeouts A flag to indicate that the called wants timeout exceptions */ public void open(String name, int mode, boolean timeout) throws IOException { if(name.charAt(0) != '/' || name.charAt(1) != '/') { throw new IllegalArgumentException("Protocol must start with \"//\" "+name); } name = name.substring(2); /* * If 'name' == null then we are a server endpoint at port 'port' * * If 'name' != null we are a client endpoint at an port decided by the system * and the default address for datagrams to be send is 'host':'port' */ /* If name does not have port number, just a colon, it should at * system assigned port. Otherwise use the port and host specified. */ if (name.substring(name.indexOf(':') + 1).length() != 0) { host = getAddress(name); port = getPort(name); if(port <= 0) { throw new IllegalArgumentException("Bad port number \"//\" "+name); } } checkPermission(host, port); if(host == null) { /* Open a server datagram socket (no host given) */ endpoint = new DatagramSocket(port); } else { /* Open a random port for a datagram client */ endpoint = new DatagramSocket(); } open = true; try { byte[] testbuf = new byte[256]; DatagramPacket testdgram = new DatagramPacket(testbuf, 256); if (host != null) { testdgram.setAddress(InetAddress.getByName(host)); } else { testdgram.setAddress(InetAddress.getByName("localhost")); } testdgram.setPort(port); } catch(NumberFormatException x) { throw new IllegalArgumentException("Invalid datagram address " +host+":"+port); } catch(UnknownHostException x) { throw new IllegalArgumentException("Unknown host "+host+":"+port); } catch(SecurityException se) { // Don't need to report on the security // exceptions yet at this point } } /** * Get the address represented by this datagram endpoint * * @return address The datagram addre4ss */ public String getAddress() { InetAddress addr = endpoint.getLocalAddress(); return "datagram://" + addr.getHostName() + ":" + addr.getHostAddress(); } /** * Get the maximum length a datagram can be. * * @return address The length */ public int getMaximumLength() throws IOException { try { int receiveLen = endpoint.getReceiveBufferSize(); int sendLen = endpoint.getSendBufferSize(); /* return lesser of the two */ return (receiveLen < sendLen ? receiveLen : sendLen); } catch(java.net.SocketException x) { throw new IOException(x.getMessage()); } } /** * Get the nominal length of a datagram. * * @return address The length */ public int getNominalLength() throws IOException { return getMaximumLength(); } /** * Change the timeout period * * @param milliseconds The maximum time to wait */ public void setTimeout(int milliseconds) { } /** * Send a datagram * * @param dgram A datagram * @exception IOException If an I/O error occurs */ public void send(Datagram dgram) throws IOException { DatagramObject dh = (DatagramObject)dgram; endpoint.send(dh.dgram); } /** * Receive a datagram * * @param dgram A datagram * @exception IOException If an I/O error occurs */ public void receive(Datagram dgram) throws IOException { DatagramObject dh = (DatagramObject)dgram; endpoint.receive(dh.dgram); // Set the return DatagramObject handle to have the address from the // received DatagramPacket int recv_port = dh.dgram.getPort(); String recv_host = dh.dgram.getAddress().getHostName(); if(recv_host != null) { try { dh.setAddress("datagram://" + recv_host + ":" + recv_port); } catch(IOException x) { throw new RuntimeException("IOException in datagram::receive"); } } else { try { dh.setAddress("datagram://:"+recv_port); } catch(IOException x) { throw new RuntimeException("IOException in datagram::receive"); } } dh.pointer = 0; } /** * Close the connection to the target. * * @exception IOException If an I/O error occurs */ public void close() throws IOException { if (open) { open = false; } endpoint.close(); } /** * Get a new datagram object * * @return A new datagram */ public Datagram newDatagram(int size) throws IllegalArgumentException, IOException { // Check for negative size if (size < 0) { throw new IllegalArgumentException("Size is negative: "+size); } return newDatagram(new byte[size], size); } /** * Get a new datagram object * * @param addr The address to which the datagram must go * @return A new datagram */ public Datagram newDatagram(int size, String addr) throws IOException , IllegalArgumentException { // Check for negative size if (size < 0) { throw new IllegalArgumentException("Size is negative: "+size); } return newDatagram(new byte[size], size, addr); } /** * Get a new datagram object * * @return A new datagram */ public Datagram newDatagram(byte[] buf, int size) throws IOException, IllegalArgumentException { // Check for negative size if (size < 0) { throw new IllegalArgumentException("Size is negative: "+size); } // Check if size > max size try { if (size > getMaximumLength()) { throw new IllegalArgumentException("Size: "+size+" is more than max size: "+getMaximumLength()); } } catch (IOException e) { throw (e); } // Check for a null value for buf if (buf == null) { throw new IllegalArgumentException("buf is null"); } DatagramObject dg = new DatagramObject(new DatagramPacket(buf,size)); if(host != null) { try { dg.setAddress("datagram://"+host+":"+port); } catch(IOException x) { throw new RuntimeException("IOException in datagram::newDatagram"); } } /* Fix CR 6557544 */ /* else { try { dg.setAddress("datagram://:"+port); } catch(IOException x) { throw new RuntimeException("IOException in datagram::newDatagram"); } } */ return dg; } /** * Get a new datagram object * * @param addr The address to which the datagram must go * @return A new datagram */ public Datagram newDatagram(byte[] buf, int size, String addr) throws IOException , IllegalArgumentException { // Check for negative size if (size < 0) { throw new IllegalArgumentException("Size is negative: "+size); } // Check if size > max size try { if (size > getMaximumLength()) { throw new IllegalArgumentException("Size: "+size+" is more than max size: "+getMaximumLength()); } } catch (IOException e) { throw (e); } // Check if addr is null if (addr == null) { throw new IllegalArgumentException("addr is null"); } // Check for a null value for buf if (buf == null) { throw new IllegalArgumentException("buf is null"); } DatagramObject dh = (DatagramObject)newDatagram(buf, size); dh.setAddress(addr); return dh; } }