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 42static jfieldID fd_fdID; /* for jint 'fd' in java.io.FileDescriptor */ 43 44static 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 50JNIEXPORT jboolean JNICALL 51IOUtil_randomBytes(JNIEnv *env, jclass clazz, 52 jbyteArray randArray) 53{ 54 JNU_ThrowByName(env, "java/lang/UnsupportedOperationException", NULL); 55 return JNI_FALSE; 56} 57 58JNIEXPORT jint JNICALL 59IOUtil_fdVal(JNIEnv *env, jclass clazz, jobject fdo) 60{ 61 return (*env)->GetIntField(env, fdo, fd_fdID); 62} 63 64JNIEXPORT void JNICALL 65IOUtil_setfdVal(JNIEnv *env, jclass clazz, jobject fdo, jint val) 66{ 67 (*env)->SetIntField(env, fdo, fd_fdID, val); 68} 69 70static int 71configureBlocking(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 79JNIEXPORT void JNICALL 80IOUtil_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 87JNIEXPORT jlong JNICALL 88IOUtil_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 108JNIEXPORT jboolean JNICALL 109IOUtil_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 125JNIEXPORT jint JNICALL 126IOUtil_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 143jint 144convertReturnVal(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 166JNIEXPORT jint JNICALL 167IOUtil_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 178jlong 179convertLongReturnVal(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 201jint 202fdval(JNIEnv *env, jobject fdo) 203{ 204 return (*env)->GetIntField(env, fdo, fd_fdID); 205} 206 207static 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 218void register_sun_nio_ch_IOUtil(JNIEnv* env) { 219 jniRegisterNativeMethods(env, "sun/nio/ch/IOUtil", gMethods, NELEM(gMethods)); 220 221 IOUtil_initIDs(env); 222} 223