1/*
2 * Copyright (c) 1996, 2015, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation.  Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26
27package sun.security.ssl;
28
29import java.io.InputStream;
30import java.io.IOException;
31import java.nio.ByteBuffer;
32
33import javax.net.ssl.SSLProtocolException;
34
35/**
36 * InputStream for application data as returned by SSLSocket.getInputStream().
37 *
38 * @author David Brownell
39 */
40final class AppInputStream extends InputStream {
41    // the buffer size for each read of network data
42    private static final int READ_BUFFER_SIZE = 4096;
43
44    // static dummy array we use to implement skip()
45    private static final byte[] SKIP_ARRAY = new byte[256];
46
47    // the related socket of the input stream
48    private final SSLSocketImpl socket;
49
50    // the temporary buffer used to read network
51    private ByteBuffer buffer;
52
53    // Is application data available in the stream?
54    private boolean appDataIsAvailable;
55
56    // One element array used to implement the single byte read() method
57    private final byte[] oneByte = new byte[1];
58
59    AppInputStream(SSLSocketImpl conn) {
60        this.buffer = ByteBuffer.allocate(READ_BUFFER_SIZE);
61        this.socket = conn;
62        this.appDataIsAvailable = false;
63    }
64
65    /**
66     * Return the minimum number of bytes that can be read without blocking.
67     *
68     * Currently not synchronized.
69     */
70    @Override
71    public int available() throws IOException {
72        if ((!appDataIsAvailable) || socket.checkEOF()) {
73            return 0;
74        }
75
76        return buffer.remaining();
77    }
78
79    /**
80     * Read a single byte, returning -1 on non-fault EOF status.
81     */
82    @Override
83    public synchronized int read() throws IOException {
84        int n = read(oneByte, 0, 1);
85        if (n <= 0) { // EOF
86            return -1;
87        }
88        return oneByte[0] & 0xFF;
89    }
90
91    /**
92     * Reads up to {@code len} bytes of data from the input stream into an
93     * array of bytes. An attempt is made to read as many as {@code len} bytes,
94     * but a smaller number may be read. The number of bytes actually read
95     * is returned as an integer.
96     *
97     * If the layer above needs more data, it asks for more, so we
98     * are responsible only for blocking to fill at most one buffer,
99     * and returning "-1" on non-fault EOF status.
100     */
101    @Override
102    public synchronized int read(byte[] b, int off, int len)
103            throws IOException {
104        if (b == null) {
105            throw new NullPointerException();
106        } else if (off < 0 || len < 0 || len > b.length - off) {
107            throw new IndexOutOfBoundsException();
108        } else if (len == 0) {
109            return 0;
110        }
111
112        if (socket.checkEOF()) {
113            return -1;
114        }
115
116        // Read the available bytes at first.
117        int remains = available();
118        if (remains > 0) {
119            int howmany = Math.min(remains, len);
120            buffer.get(b, off, howmany);
121
122            return howmany;
123        }
124
125        appDataIsAvailable = false;
126        int volume = 0;
127
128        try {
129            /*
130             * Read data if needed ... notice that the connection guarantees
131             * that handshake, alert, and change cipher spec data streams are
132             * handled as they arrive, so we never see them here.
133             */
134            while(volume == 0) {
135                // Clear the buffer for a new record reading.
136                buffer.clear();
137
138                //
139                // grow the buffer if needed
140                //
141
142                // Read the header of a record into the buffer, and return
143                // the packet size.
144                int packetLen = socket.bytesInCompletePacket();
145                if (packetLen < 0) {    // EOF
146                    return -1;
147                }
148
149                // Is this packet bigger than SSL/TLS normally allows?
150                if (packetLen > SSLRecord.maxLargeRecordSize) {
151                    throw new SSLProtocolException(
152                        "Illegal packet size: " + packetLen);
153                }
154
155                if (packetLen > buffer.remaining()) {
156                    buffer = ByteBuffer.allocate(packetLen);
157                }
158
159                volume = socket.readRecord(buffer);
160                if (volume < 0) {    // EOF
161                    return -1;
162                } else if (volume > 0) {
163                    appDataIsAvailable = true;
164                    break;
165                }
166            }
167
168            int howmany = Math.min(len, volume);
169            buffer.get(b, off, howmany);
170            return howmany;
171        } catch (Exception e) {
172            // shutdown and rethrow (wrapped) exception as appropriate
173            socket.handleException(e);
174
175            // dummy for compiler
176            return -1;
177        }
178    }
179
180
181    /**
182     * Skip n bytes. This implementation is somewhat less efficient
183     * than possible, but not badly so (redundant copy). We reuse
184     * the read() code to keep things simpler. Note that SKIP_ARRAY
185     * is static and may garbled by concurrent use, but we are not interested
186     * in the data anyway.
187     */
188    @Override
189    public synchronized long skip(long n) throws IOException {
190        long skipped = 0;
191        while (n > 0) {
192            int len = (int)Math.min(n, SKIP_ARRAY.length);
193            int r = read(SKIP_ARRAY, 0, len);
194            if (r <= 0) {
195                break;
196            }
197            n -= r;
198            skipped += r;
199        }
200        return skipped;
201    }
202
203    /*
204     * Socket close is already synchronized, no need to block here.
205     */
206    @Override
207    public void close() throws IOException {
208        socket.close();
209    }
210
211    // inherit default mark/reset behavior (throw Exceptions) from InputStream
212}
213