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 rdma.ch; 27 28 import java.io.FileDescriptor; 29 import java.io.FileInputStream; 30 import java.io.IOException; 31 import java.nio.channels.FileChannel; 32 import java.net.Socket; 33 import java.net.SocketException; 34 35 import sun.net.ConnectionResetException; 36 37 class RdmaSocketInputStream extends FileInputStream 38 { 39 static { 40 init(); 41 } 42 43 private boolean eof; 44 private RdmaSocketImpl impl = null; 45 private byte temp[]; 46 private Socket socket = null; 47 48 RdmaSocketInputStream(RdmaSocketImpl impl) throws IOException { 49 super(impl.getFileDescriptor()); 50 this.impl = impl; 51 socket = impl.getSocket(); 52 } 53 54 public final FileChannel getChannel() { 55 return null; 56 } 57 58 private native int rdmaSocketRead0(FileDescriptor fd, 59 byte b[], int off, int len, 60 int timeout) 61 throws IOException; 62 63 64 private int rdmaSocketRead(FileDescriptor fd, 65 byte b[], int off, int len, 66 int timeout) 67 throws IOException { 68 return rdmaSocketRead0(fd, b, off, len, timeout); 69 } 70 71 public int read(byte b[]) throws IOException { 72 return read(b, 0, b.length); 73 } 74 75 public int read(byte b[], int off, int length) throws IOException { 76 return read(b, off, length, impl.getTimeout()); 77 } 78 79 int read(byte b[], int off, int length, int timeout) throws IOException { 80 int n; 81 82 if (eof) { 83 return -1; 84 } 85 86 if (impl.isConnectionReset()) { 87 throw new SocketException("Connection reset"); 88 } 89 90 if (length <= 0 || off < 0 || length > b.length - off) { 91 if (length == 0) { 92 return 0; 93 } 94 throw new ArrayIndexOutOfBoundsException("length == " + length 95 + " off == " + off + " buffer length == " + b.length); 96 } 97 98 boolean gotReset = false; 99 100 FileDescriptor fd = impl.acquireFD(); 101 try { 102 n = rdmaSocketRead(fd, b, off, length, timeout); 103 if (n > 0) { 104 return n; 105 } 106 } catch (ConnectionResetException rstExc) { 107 gotReset = true; 108 } finally { 109 impl.releaseFD(); 110 } 111 112 if (gotReset) { 113 impl.setConnectionResetPending(); 114 impl.acquireFD(); 115 try { 116 n = rdmaSocketRead(fd, b, off, length, timeout); 117 if (n > 0) { 118 return n; 119 } 120 } catch (ConnectionResetException rstExc) { 121 } finally { 122 impl.releaseFD(); 123 } 124 } 125 126 if (impl.isClosedOrPending()) { 127 throw new SocketException("Socket closed"); 128 } 129 if (impl.isConnectionResetPending()) { 130 impl.setConnectionReset(); 131 } 132 if (impl.isConnectionReset()) { 133 throw new SocketException("Connection reset"); 134 } 135 eof = true; 136 return -1; 137 } 138 139 /** 140 * Reads a single byte from the socket. 141 */ 142 public int read() throws IOException { 143 if (eof) { 144 return -1; 145 } 146 temp = new byte[1]; 147 int n = read(temp, 0, 1); 148 if (n <= 0) { 149 return -1; 150 } 151 return temp[0] & 0xff; 152 } 153 154 /** 155 * Skips n bytes of input. 156 * @param numbytes the number of bytes to skip 157 * @return the actual number of bytes skipped. 158 * @exception IOException If an I/O error has occurred. 159 */ 160 public long skip(long numbytes) throws IOException { 161 if (numbytes <= 0) { 162 return 0; 163 } 164 long n = numbytes; 165 int buflen = (int) Math.min(1024, n); 166 byte data[] = new byte[buflen]; 167 while (n > 0) { 168 int r = read(data, 0, (int) Math.min((long) buflen, n)); 169 if (r < 0) { 170 break; 171 } 172 n -= r; 173 } 174 return numbytes - n; 175 } 176 177 /** 178 * Returns the number of bytes that can be read without blocking. 179 * @return the number of immediately available bytes 180 */ 181 public int available() throws IOException { 182 return impl.available(); 183 } 184 185 /** 186 * Closes the stream. 187 */ 188 private boolean closing = false; 189 public void close() throws IOException { 190 // Prevent recursion. See BugId 4484411 191 if (closing) 192 return; 193 closing = true; 194 if (socket != null) { 195 if (!socket.isClosed()) 196 socket.close(); 197 } else 198 impl.close(); 199 closing = false; 200 } 201 202 void setEOF(boolean eof) { 203 this.eof = eof; 204 } 205 206 /** 207 * Perform class load-time initializations. 208 */ 209 private static native void init(); 210 }