001 /*
002 * Copyright 1995-2007 Sun Microsystems, Inc. All Rights Reserved.
003 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
004 *
005 * This code is free software; you can redistribute it and/or modify it
006 * under the terms of the GNU General Public License version 2 only, as
007 * published by the Free Software Foundation. Sun designates this
008 * particular file as subject to the "Classpath" exception as provided
009 * by Sun in the LICENSE file that accompanied this code.
010 *
011 * This code is distributed in the hope that it will be useful, but WITHOUT
012 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
013 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
014 * version 2 for more details (a copy is included in the LICENSE file that
015 * accompanied this code).
016 *
017 * You should have received a copy of the GNU General Public License version
018 * 2 along with this work; if not, write to the Free Software Foundation,
019 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
020 *
021 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
022 * CA 95054 USA or visit www.sun.com if you need additional information or
023 * have any questions.
024 */
025
026 package java.net;
027
028 import java.io.FileDescriptor;
029 import java.io.FileInputStream;
030 import java.io.IOException;
031 import java.nio.channels.FileChannel;
032
033 import sun.net.ConnectionResetException;
034
035 /**
036 * This stream extends FileInputStream to implement a
037 * SocketInputStream. Note that this class should <b>NOT</b> be
038 * public.
039 *
040 * @version 1.42, 06/11/07
041 * @author Jonathan Payne
042 * @author Arthur van Hoff
043 */
044 class SocketInputStream extends FileInputStream {
045 static {
046 init();
047 }
048
049 private boolean eof;
050 private AbstractPlainSocketImpl impl = null;
051 private byte temp[];
052 private Socket socket = null;
053
054 /**
055 * Creates a new SocketInputStream. Can only be called
056 * by a Socket. This method needs to hang on to the owner Socket so
057 * that the fd will not be closed.
058 * @param impl the implemented socket input stream
059 */
060 SocketInputStream(AbstractPlainSocketImpl impl) throws IOException {
061 super (impl.getFileDescriptor());
062 this .impl = impl;
063 socket = impl.getSocket();
064 }
065
066 /**
067 * Returns the unique {@link java.nio.channels.FileChannel FileChannel}
068 * object associated with this file input stream.</p>
069 *
070 * The <code>getChannel</code> method of <code>SocketInputStream</code>
071 * returns <code>null</code> since it is a socket based stream.</p>
072 *
073 * @return the file channel associated with this file input stream
074 *
075 * @since 1.4
076 * @spec JSR-51
077 */
078 public final FileChannel getChannel() {
079 return null;
080 }
081
082 /**
083 * Reads into an array of bytes at the specified offset using
084 * the received socket primitive.
085 * @param fd the FileDescriptor
086 * @param b the buffer into which the data is read
087 * @param off the start offset of the data
088 * @param len the maximum number of bytes read
089 * @param timeout the read timeout in ms
090 * @return the actual number of bytes read, -1 is
091 * returned when the end of the stream is reached.
092 * @exception IOException If an I/O error has occurred.
093 */
094 private native int socketRead0(FileDescriptor fd, byte b[],
095 int off, int len, int timeout) throws IOException;
096
097 /**
098 * Reads into a byte array data from the socket.
099 * @param b the buffer into which the data is read
100 * @return the actual number of bytes read, -1 is
101 * returned when the end of the stream is reached.
102 * @exception IOException If an I/O error has occurred.
103 */
104 public int read(byte b[]) throws IOException {
105 return read(b, 0, b.length);
106 }
107
108 /**
109 * Reads into a byte array <i>b</i> at offset <i>off</i>,
110 * <i>length</i> bytes of data.
111 * @param b the buffer into which the data is read
112 * @param off the start offset of the data
113 * @param len the maximum number of bytes read
114 * @return the actual number of bytes read, -1 is
115 * returned when the end of the stream is reached.
116 * @exception IOException If an I/O error has occurred.
117 */
118 public int read(byte b[], int off, int length) throws IOException {
119 int n;
120
121 // EOF already encountered
122 if (eof) {
123 return -1;
124 }
125
126 // connection reset
127 if (impl.isConnectionReset()) {
128 throw new SocketException("Connection reset");
129 }
130
131 // bounds check
132 if (length <= 0 || off < 0 || off + length > b.length) {
133 if (length == 0) {
134 return 0;
135 }
136 throw new ArrayIndexOutOfBoundsException();
137 }
138
139 boolean gotReset = false;
140
141 // acquire file descriptor and do the read
142 FileDescriptor fd = impl.acquireFD();
143 try {
144 n = socketRead0(fd, b, off, length, impl.getTimeout());
145 if (n > 0) {
146 return n;
147 }
148 } catch (ConnectionResetException rstExc) {
149 gotReset = true;
150 } finally {
151 impl.releaseFD();
152 }
153
154 /*
155 * We receive a "connection reset" but there may be bytes still
156 * buffered on the socket
157 */
158 if (gotReset) {
159 impl.setConnectionResetPending();
160 impl.acquireFD();
161 try {
162 n = socketRead0(fd, b, off, length, impl.getTimeout());
163 if (n > 0) {
164 return n;
165 }
166 } catch (ConnectionResetException rstExc) {
167 } finally {
168 impl.releaseFD();
169 }
170 }
171
172 /*
173 * If we get here we are at EOF, the socket has been closed,
174 * or the connection has been reset.
175 */
176 if (impl.isClosedOrPending()) {
177 throw new SocketException("Socket closed");
178 }
179 if (impl.isConnectionResetPending()) {
180 impl.setConnectionReset();
181 }
182 if (impl.isConnectionReset()) {
183 throw new SocketException("Connection reset");
184 }
185 eof = true;
186 return -1;
187 }
188
189 /**
190 * Reads a single byte from the socket.
191 */
192 public int read() throws IOException {
193 if (eof) {
194 return -1;
195 }
196 temp = new byte[1];
197 int n = read(temp, 0, 1);
198 if (n <= 0) {
199 return -1;
200 }
201 return temp[0] & 0xff;
202 }
203
204 /**
205 * Skips n bytes of input.
206 * @param n the number of bytes to skip
207 * @return the actual number of bytes skipped.
208 * @exception IOException If an I/O error has occurred.
209 */
210 public long skip(long numbytes) throws IOException {
211 if (numbytes <= 0) {
212 return 0;
213 }
214 long n = numbytes;
215 int buflen = (int) Math.min(1024, n);
216 byte data[] = new byte[buflen];
217 while (n > 0) {
218 int r = read(data, 0, (int) Math.min((long) buflen, n));
219 if (r < 0) {
220 break;
221 }
222 n -= r;
223 }
224 return numbytes - n;
225 }
226
227 /**
228 * Returns the number of bytes that can be read without blocking.
229 * @return the number of immediately available bytes
230 */
231 public int available() throws IOException {
232 return impl.available();
233 }
234
235 /**
236 * Closes the stream.
237 */
238 private boolean closing = false;
239
240 public void close() throws IOException {
241 // Prevent recursion. See BugId 4484411
242 if (closing)
243 return;
244 closing = true;
245 if (socket != null) {
246 if (!socket.isClosed())
247 socket.close();
248 } else
249 impl.close();
250 closing = false;
251 }
252
253 void setEOF(boolean eof) {
254 this .eof = eof;
255 }
256
257 /**
258 * Overrides finalize, the fd is closed by the Socket.
259 */
260 protected void finalize() {
261 }
262
263 /**
264 * Perform class load-time initializations.
265 */
266 private native static void init();
267 }
|