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