View Javadoc
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  
26  package java.net;
27  
28  import java.io.FileDescriptor;
29  import java.io.FileInputStream;
30  import java.io.IOException;
31  import java.nio.channels.FileChannel;
32  
33  import 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   */
43  class 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      /**
100      * Reads into a byte array data from the socket.
101      * @param b the buffer into which the data is read
102      * @return the actual number of bytes read, -1 is
103      *          returned when the end of the stream is reached.
104      * @exception IOException If an I/O error has occurred.
105      */
106     public int read(byte b[]) throws IOException {
107         return read(b, 0, b.length);
108     }
109 
110     /**
111      * Reads into a byte array <i>b</i> at offset <i>off</i>,
112      * <i>length</i> bytes of data.
113      * @param b the buffer into which the data is read
114      * @param off the start offset of the data
115      * @param length the maximum number of bytes read
116      * @return the actual number of bytes read, -1 is
117      *          returned when the end of the stream is reached.
118      * @exception IOException If an I/O error has occurred.
119      */
120     public int read(byte b[], int off, int length) throws IOException {
121         return read(b, off, length, impl.getTimeout());
122     }
123 
124     int read(byte b[], int off, int length, int timeout) throws IOException {
125         int n;
126 
127         // EOF already encountered
128         if (eof) {
129             return -1;
130         }
131 
132         // connection reset
133         if (impl.isConnectionReset()) {
134             throw new SocketException("Connection reset");
135         }
136 
137         // bounds check
138         if (length <= 0 || off < 0 || off + length > b.length) {
139             if (length == 0) {
140                 return 0;
141             }
142             throw new ArrayIndexOutOfBoundsException();
143         }
144 
145         boolean gotReset = false;
146 
147         // acquire file descriptor and do the read
148         FileDescriptor fd = impl.acquireFD();
149         try {
150             n = socketRead0(fd, b, off, length, timeout);
151             if (n > 0) {
152                 return n;
153             }
154         } catch (ConnectionResetException rstExc) {
155             gotReset = true;
156         } finally {
157             impl.releaseFD();
158         }
159 
160         /*
161          * We receive a "connection reset" but there may be bytes still
162          * buffered on the socket
163          */
164         if (gotReset) {
165             impl.setConnectionResetPending();
166             impl.acquireFD();
167             try {
168                 n = socketRead0(fd, b, off, length, timeout);
169                 if (n > 0) {
170                     return n;
171                 }
172             } catch (ConnectionResetException rstExc) {
173             } finally {
174                 impl.releaseFD();
175             }
176         }
177 
178         /*
179          * If we get here we are at EOF, the socket has been closed,
180          * or the connection has been reset.
181          */
182         if (impl.isClosedOrPending()) {
183             throw new SocketException("Socket closed");
184         }
185         if (impl.isConnectionResetPending()) {
186             impl.setConnectionReset();
187         }
188         if (impl.isConnectionReset()) {
189             throw new SocketException("Connection reset");
190         }
191         eof = true;
192         return -1;
193     }
194 
195     /**
196      * Reads a single byte from the socket.
197      */
198     public int read() throws IOException {
199         if (eof) {
200             return -1;
201         }
202         temp = new byte[1];
203         int n = read(temp, 0, 1);
204         if (n <= 0) {
205             return -1;
206         }
207         return temp[0] & 0xff;
208     }
209 
210     /**
211      * Skips n bytes of input.
212      * @param numbytes the number of bytes to skip
213      * @return  the actual number of bytes skipped.
214      * @exception IOException If an I/O error has occurred.
215      */
216     public long skip(long numbytes) throws IOException {
217         if (numbytes <= 0) {
218             return 0;
219         }
220         long n = numbytes;
221         int buflen = (int) Math.min(1024, n);
222         byte data[] = new byte[buflen];
223         while (n > 0) {
224             int r = read(data, 0, (int) Math.min((long) buflen, n));
225             if (r < 0) {
226                 break;
227             }
228             n -= r;
229         }
230         return numbytes - n;
231     }
232 
233     /**
234      * Returns the number of bytes that can be read without blocking.
235      * @return the number of immediately available bytes
236      */
237     public int available() throws IOException {
238         return impl.available();
239     }
240 
241     /**
242      * Closes the stream.
243      */
244     private boolean closing = false;
245     public void close() throws IOException {
246         // Prevent recursion. See BugId 4484411
247         if (closing)
248             return;
249         closing = true;
250         if (socket != null) {
251             if (!socket.isClosed())
252                 socket.close();
253         } else
254             impl.close();
255         closing = false;
256     }
257 
258     void setEOF(boolean eof) {
259         this.eof = eof;
260     }
261 
262     /**
263      * Overrides finalize, the fd is closed by the Socket.
264      */
265     protected void finalize() {}
266 
267     /**
268      * Perform class load-time initializations.
269      */
270     private native static void init();
271 }