FileDocCategorySizeDatePackage
In.javaAPI DocphoneME MR2 API (J2ME)7141Wed May 02 18:00:00 BST 2007com.sun.midp.ssl

In.java

/*
 *   
 *
 * Copyright  1990-2007 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.midp.ssl;

import java.io.InputStream;
import java.io.IOException;
import java.io.InterruptedIOException;

/**
 * This class is a subclass of InputStream and obtains its input bytes
 * from an SSL connection.
 * <P />
 * @see com.sun.midp.ssl.SSLStreamConnection
 * @see com.sun.midp.ssl.Out
 */ 
class In extends InputStream {
    /** Indicates the input stream is closed. */
    private boolean isClosed = false;

    /** Underlying SSL record layer from which bytes are read. */
    private Record rec;
    
    /** Start of plain text in data buffer. */
    private int start;
    /** Count of unread bytes left in data buffer. */
    private int cnt;
    /** Handle for current SSL stream connection. */
    private SSLStreamConnection ssc;
    /** Signals end of stream. */
    private boolean endOfStream = false;

    /**
     * Refills the internal store of decrypted bytes. Called when 
     * the byte count in the store reaches zero.
     *
     * @param block if true the method will not return until data is available,
     *              or end of stream
     *
     * @exception IOException is thrown, if an I/O error occurs filling the
     * the buffer
     */
    private void refill(boolean block) throws IOException {
        if (endOfStream) {
            return;
        }

        for (; ;) {
            rec.rdRec(block, Record.APP);
            if (rec.plainTextLength == -1) {
                endOfStream = true;
                return;
            }

            // Do not unblock on a zero byte record unless asked
            if (!block || rec.plainTextLength > 0) {
                break;
            }
        }

        cnt = rec.plainTextLength;
        start = 0;
    }

    /**
     * Creates a new In object.
     * <P />
     * @param r Record layer object from which input bytes are read
     * @param c SSLStreamConnection object this In object is a part of
     */ 
    In(Record r, SSLStreamConnection c) {
        rec = r;
        ssc = c;
    }

    /**
     * Reads a byte from this input stream. The method blocks if no
     * input is available.
     * <P />
     * @return the next byte of data, or -1 if end of stream is reached
     * @exception IOException if an I/O error occurs
     */ 
    public int read() throws IOException {
        int val;
        if (isClosed) {
            throw new InterruptedIOException("Stream closed");
        }

        synchronized(rec) {
            if (cnt == 0) {
                refill(true);
                if (cnt == 0) {
                    return -1; // end of stream
                }
            }
    
            val = rec.inputData[start++] & 0xff;
            cnt--;
        }

        return val;
    }
    
    /**
     * Reads up to <CODE>b.length</CODE> bytes of data from this
     * input stream into the byte array <CODE>b</CODE>. Blocks until 
     * some input is available. This is equivalent to 
     * <CODE>read(b, 0, b.length)</CODE>.
     * <P />
     * @param b the buffer into which data is read
     * @return the actual number of bytes read into the buffer, or -1
     * if there is no more data and the end of input stream has been
     * reached
     * @exception IOException if an I/O error occurs
     */ 
    public int read(byte[] b) throws IOException {
	    return read(b, 0, b.length);
    }

    /**
     * Reads up to <CODE>len</CODE> bytes of data from this input stream
     * into <CODE>b</CODE> starting at offset <CODE>off</CODE>.
     * <P />
     * @param b buffer into which data is read
     * @param off starting offset where data is read
     * @param len maximum number of bytes to be read
     * return the actual number of bytes read into the buffer, or -1
     * if there is no more data and the end of input stream has been
     * reached
     * @return number of bytes read
     * @exception IOException if an I/O error occurs
     */ 
    public int read(byte[] b, int off, int len) throws IOException {

        int i = 0;
        int numBytes;

        if (isClosed) {
            throw new InterruptedIOException("Stream closed");
        }

        synchronized(rec) {
            if (cnt == 0) {
                // Record buffer empty, block until it is refilled.
                refill(true);
                if (cnt == 0) {
                    return -1; // end of stream
                }
            }

            if (len > cnt) {
                numBytes = cnt;
            } else {
                numBytes = len;
            }

            System.arraycopy(rec.inputData, start, b, off, numBytes);
            start += numBytes;
            cnt -= numBytes;
        }

        return numBytes;
    }

    /**
     * Close the stream connection.
     *
     * @exception IOException is thrown, if an I/O error occurs while
     * shutting down the connection
     */
    synchronized public void close() throws IOException {
        if (isClosed) {
            return;
        }

        isClosed = true;
        if (ssc != null) {
            ssc.inputStreamState = SSLStreamConnection.CLOSED;
            rec.closeInputStream();
            ssc.cleanupIfNeeded();
        }
    }

    /**
     * Returns the number of bytes that can be read (or skipped over) from
     * this input stream without blocking by the next caller of a method for
     * this input stream.  The next caller might be the same thread or
     * another thread.
     *
     * @return     the number of bytes that can be read from this input stream
     *             without blocking.
     *
     * @exception  IOException  if an I/O error occurs.
     */
    public int available() throws IOException {
        if (isClosed) {
            throw new InterruptedIOException("Stream closed");
        }

        synchronized(rec) {
            if (cnt == 0) {
                // The record buffer is empty, try to refill it without blocking.
                refill(false);
            }
            return cnt;
        }
    }

    /*
     * The remaining methods: markSupported(), mark(int), 
     * reset() need not be overridden
     */ 
}