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