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 #include "jdk_internal_net_rdma_LinuxRdmaSocketDispatcherImpl.h" 27 #include "nio.h" 28 #include "nio_util.h" 29 #include <Rsocket.h> 30 31 static int preCloseFD = -1; /* File descriptor to which we dup other fd's 32 before closing them for real */ 33 static jfieldID fd_fdID; 34 35 jint 36 convertReturnVal(JNIEnv *env, jint n, jboolean reading) { 37 if (n > 0) 38 return n; 39 else if (n == 0) { 40 if (reading) { 41 return IOS_EOF; 42 } else { 43 return 0; 44 } 45 } 46 else if (errno == EAGAIN) 47 return IOS_UNAVAILABLE; 48 else if (errno == EINTR) 49 return IOS_INTERRUPTED; 50 else { 51 const char *msg = reading ? "Read failed" : "Write failed"; 52 JNU_ThrowIOExceptionWithLastError(env, msg); 53 return IOS_THROWN; 54 } 55 } 56 57 jlong 58 convertLongReturnVal(JNIEnv *env, jlong n, jboolean reading) { 59 if (n > 0) 60 return n; 61 else if (n == 0) { 62 if (reading) { 63 return IOS_EOF; 64 } else { 65 return 0; 66 } 67 } 68 else if (errno == EAGAIN) 69 return IOS_UNAVAILABLE; 70 else if (errno == EINTR) 71 return IOS_INTERRUPTED; 72 else { 73 const char *msg = reading ? "Read failed" : "Write failed"; 74 JNU_ThrowIOExceptionWithLastError(env, msg); 75 return IOS_THROWN; 76 } 77 } 78 79 JNIEXPORT void JNICALL 80 Java_jdk_internal_net_rdma_LinuxRdmaSocketDispatcherImpl_init(JNIEnv *env, 81 jclass cl) { 82 loadRdmaFuncs(env); 83 CHECK_NULL(cl = (*env)->FindClass(env, "java/io/FileDescriptor")); 84 CHECK_NULL(fd_fdID = (*env)->GetFieldID(env, cl, "fd", "I")); 85 86 int sp[2]; 87 if (socketpair(PF_UNIX, SOCK_STREAM, 0, sp) < 0) { 88 JNU_ThrowIOExceptionWithLastError(env, "socketpair failed"); 89 return; 90 } 91 preCloseFD = sp[0]; 92 rs_close(sp[1]); 93 } 94 95 JNIEXPORT jint JNICALL 96 Java_jdk_internal_net_rdma_LinuxRdmaSocketDispatcherImpl_read0(JNIEnv *env, 97 jclass clazz, jobject fdo, jlong address, jint len) { 98 jint fd = (*env)->GetIntField(env, fdo, fd_fdID); 99 void *buf = (void *)jlong_to_ptr(address); 100 return convertReturnVal(env, rs_read(fd, buf, len), JNI_TRUE); 101 } 102 103 JNIEXPORT jlong JNICALL 104 Java_jdk_internal_net_rdma_LinuxRdmaSocketDispatcherImpl_readv0(JNIEnv *env, 105 jclass clazz, jobject fdo, jlong address, jint len) { 106 jint fd = (*env)->GetIntField(env, fdo, fd_fdID); 107 struct iovec *iov = (struct iovec *)jlong_to_ptr(address); 108 return convertLongReturnVal(env, rs_readv(fd, iov, len), JNI_TRUE); 109 } 110 111 JNIEXPORT jint JNICALL 112 Java_jdk_internal_net_rdma_LinuxRdmaSocketDispatcherImpl_write0(JNIEnv *env, 113 jclass clazz, jobject fdo, jlong address, jint len) { 114 jint fd = (*env)->GetIntField(env, fdo, fd_fdID); 115 void *buf = (void *)jlong_to_ptr(address); 116 return convertReturnVal(env, rs_write(fd, buf, len), JNI_FALSE); 117 } 118 119 JNIEXPORT jlong JNICALL 120 Java_jdk_internal_net_rdma_LinuxRdmaSocketDispatcherImpl_writev0(JNIEnv *env, 121 jclass clazz, jobject fdo, jlong address, jint len) { 122 jint fd = (*env)->GetIntField(env, fdo, fd_fdID); 123 struct iovec *iov = (struct iovec *)jlong_to_ptr(address); 124 return convertLongReturnVal(env, rs_writev(fd, iov, len), JNI_FALSE); 125 } 126 127 static void closeFileDescriptor(JNIEnv *env, int fd) { 128 if (fd != -1) { 129 int result = rs_close(fd); 130 if (result < 0) 131 JNU_ThrowIOExceptionWithLastError(env, "Close failed"); 132 } 133 } 134 135 JNIEXPORT void JNICALL 136 Java_jdk_internal_net_rdma_LinuxRdmaSocketDispatcherImpl_close0(JNIEnv *env, 137 jclass clazz, jobject fdo) { 138 jint fd = (*env)->GetIntField(env, fdo, fd_fdID); 139 closeFileDescriptor(env, fd); 140 }