1/* 2 * Copyright (C) 2014 The Android Open Source Project 3 * Copyright (c) 1995, 2010, Oracle and/or its affiliates. All rights reserved. 4 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 5 * 6 * This code is free software; you can redistribute it and/or modify it 7 * under the terms of the GNU General Public License version 2 only, as 8 * published by the Free Software Foundation. Oracle designates this 9 * particular file as subject to the "Classpath" exception as provided 10 * by Oracle in the LICENSE file that accompanied this code. 11 * 12 * This code is distributed in the hope that it will be useful, but WITHOUT 13 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 14 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 15 * version 2 for more details (a copy is included in the LICENSE file that 16 * accompanied this code). 17 * 18 * You should have received a copy of the GNU General Public License version 19 * 2 along with this work; if not, write to the Free Software Foundation, 20 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 21 * 22 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 23 * or visit www.oracle.com if you need additional information or have any 24 * questions. 25 */ 26 27package java.net; 28 29import java.io.FileDescriptor; 30import java.io.FileInputStream; 31import java.io.IOException; 32import java.nio.channels.FileChannel; 33 34import dalvik.system.BlockGuard; 35import sun.misc.IoTrace; 36import sun.net.ConnectionResetException; 37 38/** 39 * This stream extends FileInputStream to implement a 40 * SocketInputStream. Note that this class should <b>NOT</b> be 41 * public. 42 * 43 * @author Jonathan Payne 44 * @author Arthur van Hoff 45 */ 46class SocketInputStream extends FileInputStream 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</code> method of <code>SocketInputStream</code> 70 * returns <code>null</code> 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 /** 99 * Reads into a byte array data from the socket. 100 * @param b the buffer into which the data is read 101 * @return the actual number of bytes read, -1 is 102 * returned when the end of the stream is reached. 103 * @exception IOException If an I/O error has occurred. 104 */ 105 public int read(byte b[]) throws IOException { 106 return read(b, 0, b.length); 107 } 108 109 /** 110 * Reads into a byte array <i>b</i> at offset <i>off</i>, 111 * <i>length</i> bytes of data. 112 * @param b the buffer into which the data is read 113 * @param off the start offset of the data 114 * @param len the maximum number of bytes read 115 * @return the actual number of bytes read, -1 is 116 * returned when the end of the stream is reached. 117 * @exception IOException If an I/O error has occurred. 118 */ 119 public int read(byte b[], int off, int length) throws IOException { 120 return read(b, off, length, impl.getTimeout()); 121 } 122 123 int read(byte b[], int off, int length, int timeout) throws IOException { 124 int n = 0; 125 126 // EOF already encountered 127 if (eof) { 128 return -1; 129 } 130 131 // connection reset 132 if (impl.isConnectionReset()) { 133 throw new SocketException("Connection reset"); 134 } 135 136 // bounds check 137 if (length <= 0 || off < 0 || off + length > b.length) { 138 if (length == 0) { 139 return 0; 140 } 141 throw new ArrayIndexOutOfBoundsException(); 142 } 143 144 boolean gotReset = false; 145 146 Object traceContext = IoTrace.socketReadBegin(); 147 // acquire file descriptor and do the read 148 FileDescriptor fd = impl.acquireFD(); 149 try { 150 BlockGuard.getThreadPolicy().onNetwork(); 151 n = socketRead0(fd, b, off, length, timeout); 152 if (n > 0) { 153 return n; 154 } 155 } catch (ConnectionResetException rstExc) { 156 gotReset = true; 157 } finally { 158 IoTrace.socketReadEnd(traceContext, impl.address, impl.port, 159 timeout, n > 0 ? n : 0); 160 } 161 162 /* 163 * We receive a "connection reset" but there may be bytes still 164 * buffered on the socket 165 */ 166 if (gotReset) { 167 traceContext = IoTrace.socketReadBegin(); 168 impl.setConnectionResetPending(); 169 try { 170 n = socketRead0(fd, b, off, length, timeout); 171 if (n > 0) { 172 return n; 173 } 174 } catch (ConnectionResetException rstExc) { 175 } finally { 176 IoTrace.socketReadEnd(traceContext, impl.address, impl.port, 177 timeout, n > 0 ? n : 0); 178 } 179 } 180 181 /* 182 * If we get here we are at EOF, the socket has been closed, 183 * or the connection has been reset. 184 */ 185 if (impl.isClosedOrPending()) { 186 throw new SocketException("Socket closed"); 187 } 188 if (impl.isConnectionResetPending()) { 189 impl.setConnectionReset(); 190 } 191 if (impl.isConnectionReset()) { 192 throw new SocketException("Connection reset"); 193 } 194 eof = true; 195 return -1; 196 } 197 198 /** 199 * Reads a single byte from the socket. 200 */ 201 public int read() throws IOException { 202 if (eof) { 203 return -1; 204 } 205 temp = new byte[1]; 206 int n = read(temp, 0, 1); 207 if (n <= 0) { 208 return -1; 209 } 210 return temp[0] & 0xff; 211 } 212 213 /** 214 * Skips n bytes of input. 215 * @param numbytes the number of bytes to skip 216 * @return the actual number of bytes skipped. 217 * @exception IOException If an I/O error has occurred. 218 */ 219 public long skip(long numbytes) throws IOException { 220 if (numbytes <= 0) { 221 return 0; 222 } 223 long n = numbytes; 224 int buflen = (int) Math.min(1024, n); 225 byte data[] = new byte[buflen]; 226 while (n > 0) { 227 int r = read(data, 0, (int) Math.min((long) buflen, n)); 228 if (r < 0) { 229 break; 230 } 231 n -= r; 232 } 233 return numbytes - n; 234 } 235 236 /** 237 * Returns the number of bytes that can be read without blocking. 238 * @return the number of immediately available bytes 239 */ 240 public int available() throws IOException { 241 // Android changed : Bug fix, if eof == true, we must indicate that we 242 // have 0 bytes available. 243 if (eof) { 244 return 0; 245 } else { 246 return impl.available(); 247 } 248 } 249 250 /** 251 * Closes the stream. 252 */ 253 private boolean closing = false; 254 public void close() throws IOException { 255 // Prevent recursion. See BugId 4484411 256 if (closing) 257 return; 258 closing = true; 259 if (socket != null) { 260 if (!socket.isClosed()) 261 socket.close(); 262 } else 263 impl.close(); 264 closing = false; 265 } 266 267 void setEOF(boolean eof) { 268 this.eof = eof; 269 } 270 271 /** 272 * Overrides finalize, the fd is closed by the Socket. 273 */ 274 protected void finalize() {} 275} 276