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