SocketInputStream.java revision 12745:f068a4ffddd2
1/*
2 * Copyright (c) 1995, 2013, 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
26package java.net;
27
28import java.io.FileDescriptor;
29import java.io.FileInputStream;
30import java.io.IOException;
31import java.nio.channels.FileChannel;
32
33import sun.net.ConnectionResetException;
34
35/**
36 * This stream extends FileInputStream to implement a
37 * SocketInputStream. Note that this class should <b>NOT</b> be
38 * public.
39 *
40 * @author      Jonathan Payne
41 * @author      Arthur van Hoff
42 */
43class SocketInputStream extends FileInputStream
44{
45    static {
46        init();
47    }
48
49    private boolean eof;
50    private AbstractPlainSocketImpl impl = null;
51    private byte temp[];
52    private Socket socket = null;
53
54    /**
55     * Creates a new SocketInputStream. Can only be called
56     * by a Socket. This method needs to hang on to the owner Socket so
57     * that the fd will not be closed.
58     * @param impl the implemented socket input stream
59     */
60    SocketInputStream(AbstractPlainSocketImpl impl) throws IOException {
61        super(impl.getFileDescriptor());
62        this.impl = impl;
63        socket = impl.getSocket();
64    }
65
66    /**
67     * Returns the unique {@link java.nio.channels.FileChannel FileChannel}
68     * object associated with this file input stream.</p>
69     *
70     * The {@code getChannel} method of {@code SocketInputStream}
71     * returns {@code null} since it is a socket based stream.</p>
72     *
73     * @return  the file channel associated with this file input stream
74     *
75     * @since 1.4
76     * @spec JSR-51
77     */
78    public final FileChannel getChannel() {
79        return null;
80    }
81
82    /**
83     * Reads into an array of bytes at the specified offset using
84     * the received socket primitive.
85     * @param fd the FileDescriptor
86     * @param b the buffer into which the data is read
87     * @param off the start offset of the data
88     * @param len the maximum number of bytes read
89     * @param timeout the read timeout in ms
90     * @return the actual number of bytes read, -1 is
91     *          returned when the end of the stream is reached.
92     * @exception IOException If an I/O error has occurred.
93     */
94    private native int socketRead0(FileDescriptor fd,
95                                   byte b[], int off, int len,
96                                   int timeout)
97        throws IOException;
98
99    // wrap native call to allow instrumentation
100    /**
101     * Reads into an array of bytes at the specified offset using
102     * the received socket primitive.
103     * @param fd the FileDescriptor
104     * @param b the buffer into which the data is read
105     * @param off the start offset of the data
106     * @param len the maximum number of bytes read
107     * @param timeout the read timeout in ms
108     * @return the actual number of bytes read, -1 is
109     *          returned when the end of the stream is reached.
110     * @exception IOException If an I/O error has occurred.
111     */
112    private int socketRead(FileDescriptor fd,
113                           byte b[], int off, int len,
114                           int timeout)
115        throws IOException {
116        return socketRead0(fd, b, off, len, timeout);
117    }
118
119    /**
120     * Reads into a byte array data from the socket.
121     * @param b the buffer into which the data is read
122     * @return the actual number of bytes read, -1 is
123     *          returned when the end of the stream is reached.
124     * @exception IOException If an I/O error has occurred.
125     */
126    public int read(byte b[]) throws IOException {
127        return read(b, 0, b.length);
128    }
129
130    /**
131     * Reads into a byte array <i>b</i> at offset <i>off</i>,
132     * <i>length</i> bytes of data.
133     * @param b the buffer into which the data is read
134     * @param off the start offset of the data
135     * @param length the maximum number of bytes read
136     * @return the actual number of bytes read, -1 is
137     *          returned when the end of the stream is reached.
138     * @exception IOException If an I/O error has occurred.
139     */
140    public int read(byte b[], int off, int length) throws IOException {
141        return read(b, off, length, impl.getTimeout());
142    }
143
144    int read(byte b[], int off, int length, int timeout) throws IOException {
145        int n;
146
147        // EOF already encountered
148        if (eof) {
149            return -1;
150        }
151
152        // connection reset
153        if (impl.isConnectionReset()) {
154            throw new SocketException("Connection reset");
155        }
156
157        // bounds check
158        if (length <= 0 || off < 0 || off + length > b.length) {
159            if (length == 0) {
160                return 0;
161            }
162            throw new ArrayIndexOutOfBoundsException();
163        }
164
165        boolean gotReset = false;
166
167        // acquire file descriptor and do the read
168        FileDescriptor fd = impl.acquireFD();
169        try {
170            n = socketRead(fd, b, off, length, timeout);
171            if (n > 0) {
172                return n;
173            }
174        } catch (ConnectionResetException rstExc) {
175            gotReset = true;
176        } finally {
177            impl.releaseFD();
178        }
179
180        /*
181         * We receive a "connection reset" but there may be bytes still
182         * buffered on the socket
183         */
184        if (gotReset) {
185            impl.setConnectionResetPending();
186            impl.acquireFD();
187            try {
188                n = socketRead(fd, b, off, length, timeout);
189                if (n > 0) {
190                    return n;
191                }
192            } catch (ConnectionResetException rstExc) {
193            } finally {
194                impl.releaseFD();
195            }
196        }
197
198        /*
199         * If we get here we are at EOF, the socket has been closed,
200         * or the connection has been reset.
201         */
202        if (impl.isClosedOrPending()) {
203            throw new SocketException("Socket closed");
204        }
205        if (impl.isConnectionResetPending()) {
206            impl.setConnectionReset();
207        }
208        if (impl.isConnectionReset()) {
209            throw new SocketException("Connection reset");
210        }
211        eof = true;
212        return -1;
213    }
214
215    /**
216     * Reads a single byte from the socket.
217     */
218    public int read() throws IOException {
219        if (eof) {
220            return -1;
221        }
222        temp = new byte[1];
223        int n = read(temp, 0, 1);
224        if (n <= 0) {
225            return -1;
226        }
227        return temp[0] & 0xff;
228    }
229
230    /**
231     * Skips n bytes of input.
232     * @param numbytes the number of bytes to skip
233     * @return  the actual number of bytes skipped.
234     * @exception IOException If an I/O error has occurred.
235     */
236    public long skip(long numbytes) throws IOException {
237        if (numbytes <= 0) {
238            return 0;
239        }
240        long n = numbytes;
241        int buflen = (int) Math.min(1024, n);
242        byte data[] = new byte[buflen];
243        while (n > 0) {
244            int r = read(data, 0, (int) Math.min((long) buflen, n));
245            if (r < 0) {
246                break;
247            }
248            n -= r;
249        }
250        return numbytes - n;
251    }
252
253    /**
254     * Returns the number of bytes that can be read without blocking.
255     * @return the number of immediately available bytes
256     */
257    public int available() throws IOException {
258        return impl.available();
259    }
260
261    /**
262     * Closes the stream.
263     */
264    private boolean closing = false;
265    public void close() throws IOException {
266        // Prevent recursion. See BugId 4484411
267        if (closing)
268            return;
269        closing = true;
270        if (socket != null) {
271            if (!socket.isClosed())
272                socket.close();
273        } else
274            impl.close();
275        closing = false;
276    }
277
278    void setEOF(boolean eof) {
279        this.eof = eof;
280    }
281
282    /**
283     * Overrides finalize, the fd is closed by the Socket.
284     */
285    protected void finalize() {}
286
287    /**
288     * Perform class load-time initializations.
289     */
290    private static native void init();
291}
292