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