1 /* 2 * Copyright (c) 2000, 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 #include "jni.h" 27 #include "jni_util.h" 28 #include "jvm.h" 29 #include "jlong.h" 30 #include "nio_util.h" 31 #include "rdma_ch_LinuxRdmaSocketDispatcherImpl.h" 32 #include "java_lang_Long.h" 33 #include <sys/types.h> 34 #include <sys/socket.h> 35 #include <rdma/rsocket.h> 36 #include <fcntl.h> 37 #include <sys/uio.h> 38 #include <unistd.h> 39 #include <sys/statvfs.h> 40 #include <linux/fs.h> 41 #include <sys/ioctl.h> 42 #include "nio.h" 43 44 static int preCloseFD = -1; /* File descriptor to which we dup other fd's 45 before closing them for real */ 46 static jfieldID fd_fdID; 47 48 jint 49 convertReturnVal(JNIEnv *env, jint n, jboolean reading) 50 { 51 if (n > 0) 52 return n; 53 else if (n == 0) { 54 if (reading) { 55 return IOS_EOF; 56 } else { 57 return 0; 58 } 59 } 60 else if (errno == EAGAIN) 61 return IOS_UNAVAILABLE; 62 else if (errno == EINTR) 63 return IOS_INTERRUPTED; 64 else { 65 const char *msg = reading ? "Read failed" : "Write failed"; 66 JNU_ThrowIOExceptionWithLastError(env, msg); 67 return IOS_THROWN; 68 } 69 } 70 71 jlong 72 convertLongReturnVal(JNIEnv *env, jlong n, jboolean reading) 73 { 74 if (n > 0) 75 return n; 76 else if (n == 0) { 77 if (reading) { 78 return IOS_EOF; 79 } else { 80 return 0; 81 } 82 } 83 else if (errno == EAGAIN) 84 return IOS_UNAVAILABLE; 85 else if (errno == EINTR) 86 return IOS_INTERRUPTED; 87 else { 88 const char *msg = reading ? "Read failed" : "Write failed"; 89 JNU_ThrowIOExceptionWithLastError(env, msg); 90 return IOS_THROWN; 91 } 92 } 93 94 JNIEXPORT void JNICALL 95 Java_rdma_ch_LinuxRdmaSocketDispatcherImpl_init(JNIEnv *env, jclass cl) 96 { 97 CHECK_NULL(cl = (*env)->FindClass(env, "java/io/FileDescriptor")); 98 CHECK_NULL(fd_fdID = (*env)->GetFieldID(env, cl, "fd", "I")); 99 100 int sp[2]; 101 if (socketpair(PF_UNIX, SOCK_STREAM, 0, sp) < 0) { 102 JNU_ThrowIOExceptionWithLastError(env, "socketpair failed"); 103 return; 104 } 105 preCloseFD = sp[0]; 106 rclose(sp[1]); 107 } 108 109 JNIEXPORT jint JNICALL 110 Java_rdma_ch_LinuxRdmaSocketDispatcherImpl_read0(JNIEnv *env, jclass clazz, 111 jobject fdo, jlong address, jint len) 112 { 113 jint fd = (*env)->GetIntField(env, fdo, fd_fdID); 114 void *buf = (void *)jlong_to_ptr(address); 115 return convertReturnVal(env, rread(fd, buf, len), JNI_TRUE); 116 } 117 118 JNIEXPORT jlong JNICALL 119 Java_rdma_ch_LinuxRdmaSocketDispatcherImpl_readv0(JNIEnv *env, jclass clazz, 120 jobject fdo, jlong address, jint len) 121 { 122 jint fd = (*env)->GetIntField(env, fdo, fd_fdID); 123 struct iovec *iov = (struct iovec *)jlong_to_ptr(address); 124 return convertLongReturnVal(env, rreadv(fd, iov, len), JNI_TRUE); 125 } 126 127 JNIEXPORT jint JNICALL 128 Java_rdma_ch_LinuxRdmaSocketDispatcherImpl_write0(JNIEnv *env, jclass clazz, 129 jobject fdo, jlong address, jint len) 130 { 131 jint fd = (*env)->GetIntField(env, fdo, fd_fdID); 132 void *buf = (void *)jlong_to_ptr(address); 133 return convertReturnVal(env, rwrite(fd, buf, len), JNI_FALSE); 134 } 135 136 JNIEXPORT jlong JNICALL 137 Java_rdma_ch_LinuxRdmaSocketDispatcherImpl_writev0(JNIEnv *env, jclass clazz, 138 jobject fdo, jlong address, jint len) 139 { 140 jint fd = (*env)->GetIntField(env, fdo, fd_fdID); 141 struct iovec *iov = (struct iovec *)jlong_to_ptr(address); 142 return convertLongReturnVal(env, rwritev(fd, iov, len), JNI_FALSE); 143 } 144 145 static jlong 146 handle(JNIEnv *env, jlong rv, char *msg) 147 { 148 if (rv >= 0) 149 return rv; 150 if (errno == EINTR) 151 return IOS_INTERRUPTED; 152 JNU_ThrowIOExceptionWithLastError(env, msg); 153 return IOS_THROWN; 154 } 155 156 static void closeFileDescriptor(JNIEnv *env, int fd) { 157 if (fd != -1) { 158 int result = rclose(fd); 159 if (result < 0) 160 JNU_ThrowIOExceptionWithLastError(env, "Close failed"); 161 } 162 } 163 164 JNIEXPORT void JNICALL 165 Java_rdma_ch_LinuxRdmaSocketDispatcherImpl_close0(JNIEnv *env, jclass clazz, jobject fdo) 166 { 167 jint fd = (*env)->GetIntField(env, fdo, fd_fdID); 168 closeFileDescriptor(env, fd); 169 } 170 171 JNIEXPORT void JNICALL 172 Java_rdma_ch_LinuxRdmaSocketDispatcherImpl_preClose0(JNIEnv *env, jclass clazz, jobject fdo) 173 { 174 /* 175 jint fd = (*env)->GetIntField(env, fdo, fd_fdID); 176 if (preCloseFD >= 0) { 177 if (dup2(preCloseFD, fd) < 0) 178 JNU_ThrowIOExceptionWithLastError(env, "dup2 failed"); 179 } 180 */ 181 }