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