| /* |
| * Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed with |
| * this work for additional information regarding copyright ownership. |
| * The ASF licenses this file to You under the Apache License, Version 2.0 |
| * (the "License"); you may not use this file except in compliance with |
| * the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| package org.apache.harmony.xnet.provider.jsse; |
| |
| import java.io.IOException; |
| import java.io.InputStream; |
| import javax.net.ssl.SSLException; |
| |
| /** |
| * This class provides input data stream functionality |
| * for SSLSocket. It accumulates the application data |
| * received by SSL protocol. |
| */ |
| public final class SSLSocketInputStream |
| extends InputStream { |
| |
| // The size of the internal data buffer. |
| // It should not be less than maximum data chunk enclosed |
| // in one ssl packet. |
| private final int size = SSLRecordProtocol.MAX_DATA_LENGTH; |
| |
| // Internal buffer accumulating the received application data |
| private byte[] buffer = new byte[size]; |
| |
| // position of the next byte to read from the buffer |
| private int pos; |
| |
| // position of the last byte to read + 1 |
| private int end; |
| |
| // the ssl socket owning the stream |
| private final SSLSocketImpl owner; |
| |
| // the flag indicating that the end of the (owner's) input stream |
| // has been reached |
| private boolean end_reached = false; |
| |
| /** |
| * Creates the application data input stream for specified socket. |
| * @param owner the socket which will provide this input stream |
| * to client applications. |
| */ |
| protected SSLSocketInputStream(SSLSocketImpl owner) { |
| this.owner = owner; |
| } |
| |
| // The helper delivering the application data from the record layer |
| protected Adapter dataPoint = new Adapter(); |
| |
| /** |
| * Tells to the stream that the end of the income data has |
| * been reached. |
| */ |
| protected void setEnd() { |
| end_reached = true; |
| } |
| |
| // ------------------ InputStream implementetion ------------------- |
| |
| /** |
| * Returns the number of bytes available for reading without blocking. |
| * @return the number of available bytes. |
| * @throws IOException |
| */ |
| @Override |
| public int available() throws IOException { |
| return end - pos; |
| } |
| |
| /** |
| * Closes the stream |
| * @throws IOException |
| */ |
| @Override |
| public void close() throws IOException { |
| buffer = null; |
| } |
| |
| /** |
| * Reads one byte. If there is no data in the underlying buffer, |
| * this operation can block until the data will be |
| * available. |
| * @return read value. |
| * @throws IOException |
| */ |
| @Override |
| public int read() throws IOException { |
| if (buffer == null) { |
| throw new IOException("Stream was closed."); |
| } |
| while (pos == end) { |
| if (end_reached) { |
| return -1; |
| } |
| // If there is no data in the buffer |
| // - will block untill the data will be provided by |
| // record layer |
| owner.needAppData(); |
| } |
| return buffer[pos++] & 0xFF; |
| } |
| |
| /** |
| * Method acts as described in spec for superclass. |
| * @see java.io.InputStream#read(byte[]) |
| */ |
| @Override |
| public int read(byte[] b) throws IOException { |
| return read(b, 0, b.length); |
| } |
| |
| /** |
| * Method acts as described in spec for superclass. |
| * @see java.io.InputStream#read(byte[],int,int) |
| */ |
| @Override |
| public int read(byte[] b, int off, int len) throws IOException { |
| int read_b; |
| int i = 0; |
| do { |
| if ((read_b = read()) == -1) { |
| return (i == 0) ? -1 : i; |
| } |
| b[off+i] = (byte) read_b; |
| i++; |
| } while ((available() != 0) && (i<len)); |
| return i; |
| } |
| |
| /** |
| * Method acts as described in spec for superclass. |
| * @see java.io.InputStream#skip(long) |
| */ |
| @Override |
| public long skip(long n) throws IOException { |
| long i = 0; |
| int av = available(); |
| if (av < n) { |
| n = av; |
| } |
| while ((i < n) && (read() != -1)) { |
| i++; |
| } |
| return i; |
| } |
| |
| // The helper class devivering the application data from the record layer |
| // to this input stream. |
| // It 'adapts' the InputStream interface to Appendable, which is used for |
| // transmition of income data from the record protocol to its clients. |
| private class Adapter implements org.apache.harmony.xnet.provider.jsse.Appendable { |
| /** |
| * Appends the data to the stream. |
| * This method could be implemented in the outer class |
| * itself, but it could be insecure. |
| */ |
| public void append(byte[] src) { |
| int length = src.length; |
| if (size - (end - pos) < length) { |
| // If the size of the buffer is greater than or equals to |
| // SSLRecordProtocol.MAX_DATA_LENGTH this situation will |
| // happen iff: |
| // 1. the length of received data fragment is greater |
| // than allowed by the spec |
| // 2. it is rehandhaking stage and we have got several |
| // extra app data messages. |
| // In any case it is better to throw alert exception. |
| throw new AlertException(AlertProtocol.INTERNAL_ERROR, |
| new SSLException("Could not accept income app data.")); |
| } |
| if (end + length > size) { |
| // move the content of the buffer to the beginnig |
| System.arraycopy(buffer, pos, buffer, 0, end-pos); |
| end -= pos; |
| pos = 0; |
| } |
| System.arraycopy(src, 0, buffer, end, length); |
| end = end + length; |
| } |
| } |
| } |
| |