Home | History | Annotate | Download | only in net
      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 
     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.misc.IoTrace;
     36 import 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  */
     46 class 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