1 /* 2 * Copyright (c) 2000, 2010, 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 <sys/types.h> 27 #include <string.h> 28 #include <sys/resource.h> 29 30 #include "jni.h" 31 #include "jni_util.h" 32 #include "jvm.h" 33 #include "jlong.h" 34 #include "java_lang_Integer.h" 35 #include "nio.h" 36 #include "nio_util.h" 37 #include "JNIHelp.h" 38 39 #define NATIVE_METHOD(className, functionName, signature) \ 40 { #functionName, signature, (void*)(className ## _ ## functionName) } 41 42 static jfieldID fd_fdID; /* for jint 'fd' in java.io.FileDescriptor */ 43 44 static void IOUtil_initIDs(JNIEnv *env) 45 { 46 jclass clazz = (*env)->FindClass(env, "java/io/FileDescriptor"); 47 fd_fdID = (*env)->GetFieldID(env, clazz, "descriptor", "I"); 48 } 49 50 JNIEXPORT jboolean JNICALL 51 IOUtil_randomBytes(JNIEnv *env, jclass clazz, 52 jbyteArray randArray) 53 { 54 JNU_ThrowByName(env, "java/lang/UnsupportedOperationException", NULL); 55 return JNI_FALSE; 56 } 57 58 JNIEXPORT jint JNICALL 59 IOUtil_fdVal(JNIEnv *env, jclass clazz, jobject fdo) 60 { 61 return (*env)->GetIntField(env, fdo, fd_fdID); 62 } 63 64 JNIEXPORT void JNICALL 65 IOUtil_setfdVal(JNIEnv *env, jclass clazz, jobject fdo, jint val) 66 { 67 (*env)->SetIntField(env, fdo, fd_fdID, val); 68 } 69 70 static int 71 configureBlocking(int fd, jboolean blocking) 72 { 73 int flags = fcntl(fd, F_GETFL); 74 int newflags = blocking ? (flags & ~O_NONBLOCK) : (flags | O_NONBLOCK); 75 76 return (flags == newflags) ? 0 : fcntl(fd, F_SETFL, newflags); 77 } 78 79 JNIEXPORT void JNICALL 80 IOUtil_configureBlocking(JNIEnv *env, jclass clazz, 81 jobject fdo, jboolean blocking) 82 { 83 if (configureBlocking(fdval(env, fdo), blocking) < 0) 84 JNU_ThrowIOExceptionWithLastError(env, "Configure blocking failed"); 85 } 86 87 JNIEXPORT jlong JNICALL 88 IOUtil_makePipe(JNIEnv *env, jobject this, jboolean blocking) 89 { 90 int fd[2]; 91 92 if (pipe(fd) < 0) { 93 JNU_ThrowIOExceptionWithLastError(env, "Pipe failed"); 94 return 0; 95 } 96 if (blocking == JNI_FALSE) { 97 if ((configureBlocking(fd[0], JNI_FALSE) < 0) 98 || (configureBlocking(fd[1], JNI_FALSE) < 0)) { 99 JNU_ThrowIOExceptionWithLastError(env, "Configure blocking failed"); 100 close(fd[0]); 101 close(fd[1]); 102 return 0; 103 } 104 } 105 return ((jlong) fd[0] << 32) | (jlong) fd[1]; 106 } 107 108 JNIEXPORT jboolean JNICALL 109 IOUtil_drain(JNIEnv *env, jclass cl, jint fd) 110 { 111 char buf[128]; 112 int tn = 0; 113 114 for (;;) { 115 int n = read(fd, buf, sizeof(buf)); 116 tn += n; 117 if ((n < 0) && (errno != EAGAIN)) 118 JNU_ThrowIOExceptionWithLastError(env, "Drain"); 119 if (n == (int)sizeof(buf)) 120 continue; 121 return (tn > 0) ? JNI_TRUE : JNI_FALSE; 122 } 123 } 124 125 JNIEXPORT jint JNICALL 126 IOUtil_fdLimit(JNIEnv *env, jclass this) 127 { 128 struct rlimit rlp; 129 if (getrlimit(RLIMIT_NOFILE, &rlp) < 0) { 130 JNU_ThrowIOExceptionWithLastError(env, "getrlimit failed"); 131 return -1; 132 } 133 // Android-changed: Remove the rlimit < 0 check. 134 if (rlp.rlim_max > java_lang_Integer_MAX_VALUE) { 135 return java_lang_Integer_MAX_VALUE; 136 } else { 137 return (jint)rlp.rlim_max; 138 } 139 } 140 141 /* Declared in nio_util.h for use elsewhere in NIO */ 142 143 jint 144 convertReturnVal(JNIEnv *env, jint n, jboolean reading) 145 { 146 if (n > 0) /* Number of bytes written */ 147 return n; 148 else if (n == 0) { 149 if (reading) { 150 return IOS_EOF; /* EOF is -1 in javaland */ 151 } else { 152 return 0; 153 } 154 } 155 else if (errno == EAGAIN) 156 return IOS_UNAVAILABLE; 157 else if (errno == EINTR) 158 return IOS_INTERRUPTED; 159 else { 160 const char *msg = reading ? "Read failed" : "Write failed"; 161 JNU_ThrowIOExceptionWithLastError(env, msg); 162 return IOS_THROWN; 163 } 164 } 165 166 JNIEXPORT jint JNICALL 167 IOUtil_iovMax(JNIEnv *env, jclass this) 168 { 169 jlong iov_max = sysconf(_SC_IOV_MAX); 170 if (iov_max == -1) 171 iov_max = 16; 172 return (jint)iov_max; 173 } 174 175 176 /* Declared in nio_util.h for use elsewhere in NIO */ 177 178 jlong 179 convertLongReturnVal(JNIEnv *env, jlong n, jboolean reading) 180 { 181 if (n > 0) /* Number of bytes written */ 182 return n; 183 else if (n == 0) { 184 if (reading) { 185 return IOS_EOF; /* EOF is -1 in javaland */ 186 } else { 187 return 0; 188 } 189 } 190 else if (errno == EAGAIN) 191 return IOS_UNAVAILABLE; 192 else if (errno == EINTR) 193 return IOS_INTERRUPTED; 194 else { 195 const char *msg = reading ? "Read failed" : "Write failed"; 196 JNU_ThrowIOExceptionWithLastError(env, msg); 197 return IOS_THROWN; 198 } 199 } 200 201 jint 202 fdval(JNIEnv *env, jobject fdo) 203 { 204 return (*env)->GetIntField(env, fdo, fd_fdID); 205 } 206 207 static JNINativeMethod gMethods[] = { 208 NATIVE_METHOD(IOUtil, iovMax, "()I"), 209 NATIVE_METHOD(IOUtil, fdLimit, "()I"), 210 NATIVE_METHOD(IOUtil, drain, "(I)Z"), 211 NATIVE_METHOD(IOUtil, makePipe, "(Z)J"), 212 NATIVE_METHOD(IOUtil, configureBlocking, "(Ljava/io/FileDescriptor;Z)V"), 213 NATIVE_METHOD(IOUtil, setfdVal, "(Ljava/io/FileDescriptor;I)V"), 214 NATIVE_METHOD(IOUtil, fdVal, "(Ljava/io/FileDescriptor;)I"), 215 NATIVE_METHOD(IOUtil, randomBytes, "([B)Z"), 216 }; 217 218 void register_sun_nio_ch_IOUtil(JNIEnv* env) { 219 jniRegisterNativeMethods(env, "sun/nio/ch/IOUtil", gMethods, NELEM(gMethods)); 220 221 IOUtil_initIDs(env); 222 } 223