001: /*
002: *
003: *
004: * Copyright 1990-2007 Sun Microsystems, Inc. All Rights Reserved.
005: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER
006: *
007: * This program is free software; you can redistribute it and/or
008: * modify it under the terms of the GNU General Public License version
009: * 2 only, as published by the Free Software Foundation.
010: *
011: * This program is distributed in the hope that it will be useful, but
012: * WITHOUT ANY WARRANTY; without even the implied warranty of
013: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
014: * General Public License version 2 for more details (a copy is
015: * included at /legal/license.txt).
016: *
017: * You should have received a copy of the GNU General Public License
018: * version 2 along with this work; if not, write to the Free Software
019: * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
020: * 02110-1301 USA
021: *
022: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
023: * Clara, CA 95054 or visit www.sun.com if you need additional
024: * information or have any questions.
025: */
026:
027: package com.sun.midp.ssl;
028:
029: import java.io.InputStream;
030: import java.io.IOException;
031: import java.io.InterruptedIOException;
032:
033: /**
034: * This class is a subclass of InputStream and obtains its input bytes
035: * from an SSL connection.
036: * <P />
037: * @see com.sun.midp.ssl.SSLStreamConnection
038: * @see com.sun.midp.ssl.Out
039: */
040: class In extends InputStream {
041: /** Indicates the input stream is closed. */
042: private boolean isClosed = false;
043:
044: /** Underlying SSL record layer from which bytes are read. */
045: private Record rec;
046:
047: /** Start of plain text in data buffer. */
048: private int start;
049: /** Count of unread bytes left in data buffer. */
050: private int cnt;
051: /** Handle for current SSL stream connection. */
052: private SSLStreamConnection ssc;
053: /** Signals end of stream. */
054: private boolean endOfStream = false;
055:
056: /**
057: * Refills the internal store of decrypted bytes. Called when
058: * the byte count in the store reaches zero.
059: *
060: * @param block if true the method will not return until data is available,
061: * or end of stream
062: *
063: * @exception IOException is thrown, if an I/O error occurs filling the
064: * the buffer
065: */
066: private void refill(boolean block) throws IOException {
067: if (endOfStream) {
068: return;
069: }
070:
071: for (;;) {
072: rec.rdRec(block, Record.APP);
073: if (rec.plainTextLength == -1) {
074: endOfStream = true;
075: return;
076: }
077:
078: // Do not unblock on a zero byte record unless asked
079: if (!block || rec.plainTextLength > 0) {
080: break;
081: }
082: }
083:
084: cnt = rec.plainTextLength;
085: start = 0;
086: }
087:
088: /**
089: * Creates a new In object.
090: * <P />
091: * @param r Record layer object from which input bytes are read
092: * @param c SSLStreamConnection object this In object is a part of
093: */
094: In(Record r, SSLStreamConnection c) {
095: rec = r;
096: ssc = c;
097: }
098:
099: /**
100: * Reads a byte from this input stream. The method blocks if no
101: * input is available.
102: * <P />
103: * @return the next byte of data, or -1 if end of stream is reached
104: * @exception IOException if an I/O error occurs
105: */
106: public int read() throws IOException {
107: int val;
108: if (isClosed) {
109: throw new InterruptedIOException("Stream closed");
110: }
111:
112: synchronized (rec) {
113: if (cnt == 0) {
114: refill(true);
115: if (cnt == 0) {
116: return -1; // end of stream
117: }
118: }
119:
120: val = rec.inputData[start++] & 0xff;
121: cnt--;
122: }
123:
124: return val;
125: }
126:
127: /**
128: * Reads up to <CODE>b.length</CODE> bytes of data from this
129: * input stream into the byte array <CODE>b</CODE>. Blocks until
130: * some input is available. This is equivalent to
131: * <CODE>read(b, 0, b.length)</CODE>.
132: * <P />
133: * @param b the buffer into which data is read
134: * @return the actual number of bytes read into the buffer, or -1
135: * if there is no more data and the end of input stream has been
136: * reached
137: * @exception IOException if an I/O error occurs
138: */
139: public int read(byte[] b) throws IOException {
140: return read(b, 0, b.length);
141: }
142:
143: /**
144: * Reads up to <CODE>len</CODE> bytes of data from this input stream
145: * into <CODE>b</CODE> starting at offset <CODE>off</CODE>.
146: * <P />
147: * @param b buffer into which data is read
148: * @param off starting offset where data is read
149: * @param len maximum number of bytes to be read
150: * return the actual number of bytes read into the buffer, or -1
151: * if there is no more data and the end of input stream has been
152: * reached
153: * @return number of bytes read
154: * @exception IOException if an I/O error occurs
155: */
156: public int read(byte[] b, int off, int len) throws IOException {
157:
158: int i = 0;
159: int numBytes;
160:
161: if (isClosed) {
162: throw new InterruptedIOException("Stream closed");
163: }
164:
165: synchronized (rec) {
166: if (cnt == 0) {
167: // Record buffer empty, block until it is refilled.
168: refill(true);
169: if (cnt == 0) {
170: return -1; // end of stream
171: }
172: }
173:
174: if (len > cnt) {
175: numBytes = cnt;
176: } else {
177: numBytes = len;
178: }
179:
180: System.arraycopy(rec.inputData, start, b, off, numBytes);
181: start += numBytes;
182: cnt -= numBytes;
183: }
184:
185: return numBytes;
186: }
187:
188: /**
189: * Close the stream connection.
190: *
191: * @exception IOException is thrown, if an I/O error occurs while
192: * shutting down the connection
193: */
194: synchronized public void close() throws IOException {
195: if (isClosed) {
196: return;
197: }
198:
199: isClosed = true;
200: if (ssc != null) {
201: ssc.inputStreamState = SSLStreamConnection.CLOSED;
202: rec.closeInputStream();
203: ssc.cleanupIfNeeded();
204: }
205: }
206:
207: /**
208: * Returns the number of bytes that can be read (or skipped over) from
209: * this input stream without blocking by the next caller of a method for
210: * this input stream. The next caller might be the same thread or
211: * another thread.
212: *
213: * @return the number of bytes that can be read from this input stream
214: * without blocking.
215: *
216: * @exception IOException if an I/O error occurs.
217: */
218: public int available() throws IOException {
219: if (isClosed) {
220: throw new InterruptedIOException("Stream closed");
221: }
222:
223: synchronized (rec) {
224: if (cnt == 0) {
225: // The record buffer is empty, try to refill it without blocking.
226: refill(false);
227: }
228: return cnt;
229: }
230: }
231:
232: /*
233: * The remaining methods: markSupported(), mark(int),
234: * reset() need not be overridden
235: */
236: }
|