FileDocCategorySizeDatePackage
Protocol.javaAPI DocJ2ME MIDP 2.020027Thu Nov 07 12:02:22 GMT 2002com.sun.midp.io.j2me.datagram

Protocol

public class Protocol extends Object implements com.sun.cldc.io.ConnectionBaseInterface, UDPDatagramConnection
This is the default "datagram://" protocol for J2ME that maps onto UDP.
author
Nik Shaylor
version
1.1 11/19/99

Fields Summary
private static SecurityToken
classSecurityToken
This class has a different security domain than the MIDlet suite
private int
handle
Used by native code to hold the file descriptor handle.
private String
host
Machine name from the URL connection string.
private int
port
Port number from the URL connection string.
private boolean
open
Open flag to indicate if the connection is currently open.
Constructors Summary
Methods Summary
public voidclose()
Close the connection to the target.

exception
IOException if an I/O error occurs

        if (open) {
            open = false;
            close0();
        } 

    
private native voidclose0()
Close the native socket, handle field is accessed by the native code.

exception
IOException if an I/O error occurs

private DatagramcreateDatagram(boolean createBuffer, byte[] buf, int size)
Create a new datagram object with error checking. If there is a host associated with the connection, set the address of the datagram.

param
createBuffer if true the buffer is created
param
buf the buffer to be used in the datagram
param
size the length of the buffer to be allocated for the datagram
return
a new datagram
exception
IOException if an I/O error occurs, or the connection was closed
exception
IllegalArgumentException if the length is negative or larger than the buffer, or if the address or buffer parameters is invalid


        Datagram dgram;

        ensureOpen();

        if (size < 0) {
            throw new IllegalArgumentException("Size is negative");
        }

        if (createBuffer) {
            buf = new byte[size];
        } else if (buf == null) {
            throw new IllegalArgumentException("Buffer is invalid");
        } else if (size > buf.length) {
            throw new
                IllegalArgumentException("Size bigger than the buffer");
        }

        dgram = new DatagramObject(buf, size);

        if (host != null) {
            dgram.setAddress("datagram://" + host + ":" + port);
        }

        return dgram;
    
voidensureOpen()
Ensure that the connection is open.

exception
IOException if the connection was closed

        if (!open) {
            throw new IOException("Connection closed");
        }
    
private native voidfinalize()
Native finalizer.

private native java.lang.StringgetHost0()
Get the requested IP number.

return
the IP address as a String

static native java.lang.StringgetHostByAddr(int ipn)
Get a hostname for a raw IPv4 address.

param
ipn raw IPv4 address
return
hostname or the dot notation if not found

static native intgetIpNumber(byte[] szHost)
Get a raw IPv4 address for hostname.

param
szHost hostname as ASCII chars with zero terminator
return
raw IPv4 address or -1 if there was an error

public java.lang.StringgetLocalAddress()
Gets the local address to which the socket is bound.

The host address(IP number) that can be used to connect to this end of the socket connection from an external system. Since IP addresses may be dynamically assigned a remote application will need to be robust in the face of IP number reasssignment.

The local hostname (if available) can be accessed from System.getProperty("microedition.hostname")

return
the local address to which the socket is bound.
exception
IOException if the connection was closed
see
ServerSocketConnection

        ensureOpen();
	return getHost0();
    
public intgetLocalPort()
Returns the local port to which this socket is bound.

return
the local port number to which this socket is connected
exception
IOException if the connection was closed
see
ServerSocketConnection

        ensureOpen();
	return getPort0(); 
    
public intgetMaximumLength()
Get the maximum length a datagram can be.

return
the length
exception
IOException if the connection was closed

        ensureOpen();
        return getMaximumLength0();
    
native intgetMaximumLength0()
Get the maximum length of a datagram.

return
maximum length of a datagram
exception
IOException if an I/O error occurs

public intgetNominalLength()
Get the nominal length of a datagram.

return
address the length
exception
IOException if the connection was closed

        ensureOpen();
        return getNominalLength0();
    
native intgetNominalLength0()
Get the nominal length of a datagram.

return
nomimal length of a datagram
exception
IOException if an I/O error occurs

private native intgetPort0()
Get the requested port number.

return
the port number of the requested end point

public static voidinitSecurityToken(SecurityToken token)
Initializes the security token for this class, so it can perform actions that a normal MIDlet Suite cannot.

param
token security token for this class.

        NetworkConnectionBase.initializeNativeNetwork();
    
	if (classSecurityToken != null) {
	    return;
	}
	
	classSecurityToken = token;
    
public DatagramnewDatagram(int size, java.lang.String addr)
Get a new datagram object.

param
size the length of the buffer to be allocated for the datagram
param
addr the address to which the datagram must go
return
a new datagram
exception
IOException if an I/O error occurs
exception
IllegalArgumentException if the length is negative or larger than the buffer, or if the address parameter is invalid

        Datagram dgram = createDatagram(true, null, size);
        dgram.setAddress(addr); // override the address
        return dgram;
    
public DatagramnewDatagram(byte[] buf, int size)
Get a new datagram object.

param
buf the buffer to be used in the datagram
param
size the length of the buffer to be allocated for the datagram
return
a new datagram
exception
IOException if an I/O error occurs
exception
IllegalArgumentException if the length is negative or larger than the buffer, or if the address or buffer parameters is invalid

        return createDatagram(false, buf, size);
    
public DatagramnewDatagram(byte[] buf, int size, java.lang.String addr)
Get a new datagram object.

param
buf the buffer to be used in the datagram
param
size the length of the buffer to be allocated for the datagram
param
addr the address to which the datagram must go
exception
IOException if an I/O error occurs
return
a new datagram


        Datagram dgram = createDatagram(false, buf, size);
        dgram.setAddress(addr); // override the address
        return dgram;
    
public DatagramnewDatagram(int size)
Get a new datagram object.

param
size the length of the buffer to be allocated for the datagram
return
a new datagram
exception
IOException if an I/O error occurs
exception
IllegalArgumentException if the length is negative or larger than the buffer


        Datagram dgram;

        ensureOpen();

        if (size < 0) {
            throw new IllegalArgumentException("Size is negative");
        }

	byte[] buf = new byte[size];

        dgram = new DatagramObject(buf, size);

        if (host != null) {
	    try {
		dgram.setAddress("datagram://" + host + ":" + port);
	    } catch (IllegalArgumentException iae) {
		// Intercept a bad address, here.
		// It'll be caught on send if used.
	    }
        }

        return dgram;
    
private native voidopen0(int port, byte[] storage)
Open a connection to a target, and fillin the handle field.

param
port port to listen on, or 0 to have one selected
param
storage name of current suite storage
exception
IOException if some other kind of I/O error occurs or if reserved by another suite

public ConnectionopenPrim(java.lang.String name, int mode, boolean timeouts)
Open a connection to a target.

The name string for this protocol should be: "//[address:][port]"

param
name the target of the connection
param
mode a flag that is true if the caller intends to write to the connection, ignored
param
timeouts a flag to indicate that the called wants timeout exceptions, ignored
return
this connection
exception
IllegalArgumentException if a parameter is invalid
throws
IOException if an I/O operation failed
exception
SecurityException if a caller is not authorized for UDP

        int incommingPort = 0;
        Scheduler scheduler = Scheduler.getScheduler();
        MIDletSuite midletSuite = scheduler.getMIDletSuite();

        // parse name into host and port
        HttpUrl url = new HttpUrl("datagram", name);

        /*
         * Since we reused the <code>HttpUrl</code> parser, we must
	 * make sure that there was nothing past the authority in the
	 * URL.
         */
        if (url.path != null || url.query != null || url.fragment != null) {
            throw new IllegalArgumentException("Malformed address");
        }

        host = url.host;
        port = url.port;

        if (name.charAt(0) != '/" || name.charAt(1) != '/") {
            throw new IllegalArgumentException(
                      "Protocol must start with slash slash");
        }

	/*
         * If 'host' == null then we are a server endpoint at
         * port 'port'.
         *
         * If 'host' != null we are a client endpoint at a port
         * decided by the system and the default address for
         * datagrams to be send is 'host':'port'
	 *
	 * If 'host' and 'port' are omitted in 
	 * the name, then 
	 * the application is requesting a system assigned port
	 * number.
         */
        if (host == null) {
            try {
                // When asking permission use Internet protocol name.
                midletSuite.checkForPermission(Permissions.UDP_SERVER,
                    "UDP:" + name);
            } catch (SecurityException e) {
                // Give back the connection to AMS
                PushRegistryImpl.checkInConnectionInternal(
                    classSecurityToken, "datagram:" + name);
                    
                throw e;
            } catch (InterruptedException ie) {
                throw new InterruptedIOException(
                    "Interrupted while trying to ask the user permission");
            }

            if (port > 0) {
                incommingPort = port;
            }
        } else {
            if (port < 0) {
                throw new IllegalArgumentException("Missing port number");
            }

            try {
                // When asking permission use Internet protocol name.
                midletSuite.checkForPermission(Permissions.UDP,
                                               "UDP:" + name);
            } catch (InterruptedException ie) {
                throw new InterruptedIOException(
                    "Interrupted while trying to ask the user permission");
            }
        }

	/* Check the mode parameter. (See NetworkConnectionAdapter). */
        switch (mode) {
        case Connector.READ:
        case Connector.WRITE:
        case Connector.READ_WRITE:
            break;

        default:
            throw new IllegalArgumentException("Illegal mode");
        }

	String root = midletSuite.getStorageName();

        byte[] asciiStorage = Util.toCString(root);

        open0(incommingPort, asciiStorage);
        registerCleanup();
        open = true;
        return this;
    
public synchronized voidreceive(Datagram dgram)
Receive a datagram.

param
dgram a datagram
exception
IOException if an I/O error occurs


        synchronized (dgram) {
            int length;
            long res;
            int count;
            int ipNumber;
            String host;
            int port;
            String addr;

            ensureOpen();

            length = dgram.getLength();

            if (length <= 0) {
                throw new IOException("Bad datagram length");
            }

            while (true) {
                try {
                    res = receive0(dgram.getData(), dgram.getOffset(),
                                   length);
                } finally {
                    if (!open) {
                        throw new InterruptedIOException("Socket closed");
                    }
                }

                // check res, not count so we can receive zero length datagrams
                if (res != 0) {
                    break;
                }

                /* Wait a while for I/O to become ready */
                GeneralBase.iowait(); 
            }

            count = ((int)res) & 0xffff;

            /*
             * There should be another field for bytes received so
             * the datagram can be reused without an extra effort, but
             * to be consistant with J2SE DatagramSocket we shrink the buffer
             * length.
             */
            dgram.setLength(count);

            ipNumber = (int)((res >> 32));
            host = getHostByAddr(ipNumber).trim();
            port = (int)((res >> 16)) & 0xffff;
            addr = "datagram://" + host + ":" + port;

            if (dgram instanceof DatagramObject) {
                // save this data for sending back a message
                DatagramObject dh = (DatagramObject)dgram;
                dh.address = addr;
                dh.ipNumber = ipNumber;
                dh.port = port;
            } else {
                dgram.setAddress("datagram://" + host + ":" + port);
            }
        }
    
private native longreceive0(byte[] buf, int off, int len)
Receive a datagram, handle field is accessed by the native code.

param
buf the data buffer
param
off the offset into the data buffer
param
len the length of the data in the buffer
return
upper 32 bits: raw IPv4 address, middle 16 bits: port, bytes in datagram
exception
IOException if an I/O error occurs

private native voidregisterCleanup()
Register this object's native cleanup function.

public voidsend(Datagram dgram)
Send a datagram.

param
dgram a datagram
exception
IOException if an I/O error occurs

        synchronized (dgram) {
            int length;
            int ipNumber;
            int port;

            ensureOpen();

            length = dgram.getLength();

            // allow zero length datagrams to be sent
            if (length < 0) {
                throw new IOException("Bad datagram length");
            }

            if (dgram instanceof DatagramObject) {
                DatagramObject dh = (DatagramObject)dgram;

                ipNumber = dh.ipNumber;
                if (ipNumber == 0) {
                    throw new IOException(
                        "No address in datagram");
                }

                port = dh.port;
            } else {
                // address is a datagram url
                String addr;
                HttpUrl url;
                String host;

                addr = dgram.getAddress();
                if (addr == null) {
                    throw new IOException(
                         "No address in datagram");
                }

                url = new HttpUrl(addr);
                host = url.host;
                port = url.port;

                if (host == null) {
                    throw new IOException("Missing host");
                }
            
                if (port == -1) {
                    throw new IOException("Missing port");
                }

                ipNumber = getIpNumber(Util.toCString(host));

                if (ipNumber == -1) {
                    throw new IOException("Invalid host");
                }
            }

            while (true) {
                int res;

                try {
                    res = send0(ipNumber, port, dgram.getData(),
                                dgram.getOffset(), length);
                } finally {
                    if (!open) {
                        throw new InterruptedIOException("Socket closed");
                    }
                }

                if (res == dgram.getLength()) {
                    break;
                }

                if (res != 0) {
                    throw new IOException("Failed to send datagram");
                }

                /* Wait a while for I/O to become ready */
                GeneralBase.iowait(); 
            }
        }
    
private native intsend0(int ipNumber, int port, byte[] buf, int off, int len)
Send a datagram, handle field is accessed by the native code.

param
ipNumber raw IPv4 address
param
port UDP port
param
buf the data buffer
param
off the offset into the data buffer
param
len the length of the data in the buffer
return
number of bytes to send
exception
IOException if an I/O error occurs