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