JNIEXPORT jlong JNICALL Java_io_netty_channel_epoll_Native_sendfile0(JNIEnv* env, jclass clazz, jint fd, jobject fileRegion, jlong base_off, jlong off, jlong len) { jobject fileChannel = (*env)->GetObjectField(env, fileRegion, fileChannelFieldId); if (fileChannel == NULL) { netty_unix_errors_throwRuntimeException(env, "failed to get DefaultFileRegion.file"); return -1; } jobject fileDescriptor = (*env)->GetObjectField(env, fileChannel, fileDescriptorFieldId); if (fileDescriptor == NULL) { netty_unix_errors_throwRuntimeException(env, "failed to get FileChannelImpl.fd"); return -1; } jint srcFd = (*env)->GetIntField(env, fileDescriptor, fdFieldId); if (srcFd == -1) { netty_unix_errors_throwRuntimeException(env, "failed to get FileDescriptor.fd"); return -1; } ssize_t res; off_t offset = base_off + off; int err; do { res = sendfile(fd, srcFd, &offset, (size_t) len); } while (res == -1 && ((err = errno) == EINTR)); if (res < 0) { return -err; } if (res > 0) { // update the transfered field in DefaultFileRegion (*env)->SetLongField(env, fileRegion, transferedFieldId, off + res); } return res; }
jint netty_unix_filedescriptor_JNI_OnLoad(JNIEnv* env, const char* nettyPackagePrefix) { void* mem = malloc(1); if (mem == NULL) { netty_unix_errors_throwOutOfMemoryError(env); return JNI_ERR; } jobject directBuffer = (*env)->NewDirectByteBuffer(env, mem, 1); if (directBuffer == NULL) { free(mem); netty_unix_errors_throwOutOfMemoryError(env); return JNI_ERR; } if ((*env)->GetDirectBufferAddress(env, directBuffer) == NULL) { free(mem); netty_unix_errors_throwRuntimeException(env, "failed to get direct buffer address"); return JNI_ERR; } jclass cls = (*env)->GetObjectClass(env, directBuffer); // Get the method id for Buffer.position() and Buffer.limit(). These are used as fallback if // it is not possible to obtain the position and limit using the fields directly. posId = (*env)->GetMethodID(env, cls, "position", "()I"); if (posId == NULL) { free(mem); // position method was not found.. something is wrong so bail out netty_unix_errors_throwRuntimeException(env, "failed to get method ID: ByteBuffer.position()"); return JNI_ERR; } limitId = (*env)->GetMethodID(env, cls, "limit", "()I"); if (limitId == NULL) { free(mem); // limit method was not found.. something is wrong so bail out netty_unix_errors_throwRuntimeException(env, "failed to get method ID: ByteBuffer.limit()"); return JNI_ERR; } // Try to get the ids of the position and limit fields. We later then check if we was able // to find them and if so use them get the position and limit of the buffer. This is // much faster then call back into java via (*env)->CallIntMethod(...). posFieldId = (*env)->GetFieldID(env, cls, "position", "I"); if (posFieldId == NULL) { // this is ok as we can still use the method so just clear the exception (*env)->ExceptionClear(env); } limitFieldId = (*env)->GetFieldID(env, cls, "limit", "I"); if (limitFieldId == NULL) { // this is ok as we can still use the method so just clear the exception (*env)->ExceptionClear(env); } free(mem); }
jint netty_kqueue_eventarray_JNI_OnLoad(JNIEnv* env, const char* packagePrefix) { JNINativeMethod* dynamicMethods = createDynamicMethodsTable(packagePrefix); if (netty_unix_util_register_natives(env, packagePrefix, "io/netty/channel/kqueue/KQueueEventArray", dynamicMethods, dynamicMethodsTableSize()) != 0) { freeDynamicMethodsTable(dynamicMethods); return JNI_ERR; } freeDynamicMethodsTable(dynamicMethods); dynamicMethods = NULL; char* nettyClassName = netty_unix_util_prepend(packagePrefix, "io/netty/channel/kqueue/AbstractKQueueChannel"); jclass kqueueChannelCls = (*env)->FindClass(env, nettyClassName); free(nettyClassName); nettyClassName = NULL; if (kqueueChannelCls == NULL) { return JNI_ERR; } kqueueJniPtrFieldId = (*env)->GetFieldID(env, kqueueChannelCls, "jniSelfPtr", "J"); if (kqueueJniPtrFieldId == NULL) { netty_unix_errors_throwRuntimeException(env, "failed to get field ID: AbstractKQueueChannel.jniSelfPtr"); return JNI_ERR; } return JNI_VERSION_1_6; }
static void netty_epoll_native_eventFdRead(JNIEnv* env, jclass clazz, jint fd) { uint64_t eventfd_t; if (eventfd_read(fd, &eventfd_t) != 0) { // something is serious wrong netty_unix_errors_throwRuntimeException(env, "eventfd_read() failed"); } }
JNIEXPORT void JNICALL Java_io_netty_channel_epoll_Native_eventFdRead(JNIEnv* env, jclass clazz, jint fd) { uint64_t eventfd_t; if (eventfd_read(fd, &eventfd_t) != 0) { // something is serious wrong netty_unix_errors_throwRuntimeException(env, "eventfd_read() failed"); } }
// JNI Registered Methods Begin static jlong netty_kqueue_bsdsocket_sendFile(JNIEnv* env, jclass clazz, jint socketFd, jobject fileRegion, jlong base_off, jlong off, jlong len) { jobject fileChannel = (*env)->GetObjectField(env, fileRegion, fileChannelFieldId); if (fileChannel == NULL) { netty_unix_errors_throwRuntimeException(env, "failed to get DefaultFileRegion.file"); return -1; } jobject fileDescriptor = (*env)->GetObjectField(env, fileChannel, fileDescriptorFieldId); if (fileDescriptor == NULL) { netty_unix_errors_throwRuntimeException(env, "failed to get FileChannelImpl.fd"); return -1; } jint srcFd = (*env)->GetIntField(env, fileDescriptor, fdFieldId); if (srcFd == -1) { netty_unix_errors_throwRuntimeException(env, "failed to get FileDescriptor.fd"); return -1; } const jlong lenBefore = len; off_t sbytes; int res, err; do { #ifdef __APPLE__ // sbytes is an input (how many to write) and output (how many were written) parameter. sbytes = len; res = sendfile(srcFd, socketFd, base_off + off, &sbytes, NULL, 0); #else sbytes = 0; res = sendfile(srcFd, socketFd, base_off + off, len, NULL, &sbytes, 0); #endif len -= sbytes; } while (res < 0 && ((err = errno) == EINTR)); sbytes = lenBefore - len; if (sbytes > 0) { // update the transferred field in DefaultFileRegion (*env)->SetLongField(env, fileRegion, transferredFieldId, off + sbytes); return sbytes; } return res < 0 ? -err : 0; }
static jint netty_epoll_native_JNI_OnLoad(JNIEnv* env, const char* packagePrefix) { int limitsOnLoadCalled = 0; int errorsOnLoadCalled = 0; int filedescriptorOnLoadCalled = 0; int socketOnLoadCalled = 0; int bufferOnLoadCalled = 0; int linuxsocketOnLoadCalled = 0; // We must register the statically referenced methods first! if (netty_unix_util_register_natives(env, packagePrefix, "io/netty/channel/epoll/NativeStaticallyReferencedJniMethods", statically_referenced_fixed_method_table, statically_referenced_fixed_method_table_size) != 0) { goto error; } // Register the methods which are not referenced by static member variables JNINativeMethod* dynamicMethods = createDynamicMethodsTable(packagePrefix); if (netty_unix_util_register_natives(env, packagePrefix, "io/netty/channel/epoll/Native", dynamicMethods, dynamicMethodsTableSize()) != 0) { freeDynamicMethodsTable(dynamicMethods); goto error; } freeDynamicMethodsTable(dynamicMethods); dynamicMethods = NULL; // Load all c modules that we depend upon if (netty_unix_limits_JNI_OnLoad(env, packagePrefix) == JNI_ERR) { goto error; } limitsOnLoadCalled = 1; if (netty_unix_errors_JNI_OnLoad(env, packagePrefix) == JNI_ERR) { goto error; } errorsOnLoadCalled = 1; if (netty_unix_filedescriptor_JNI_OnLoad(env, packagePrefix) == JNI_ERR) { goto error; } filedescriptorOnLoadCalled = 1; if (netty_unix_socket_JNI_OnLoad(env, packagePrefix) == JNI_ERR) { goto error; } socketOnLoadCalled = 1; if (netty_unix_buffer_JNI_OnLoad(env, packagePrefix) == JNI_ERR) { goto error; } bufferOnLoadCalled = 1; if (netty_epoll_linuxsocket_JNI_OnLoad(env, packagePrefix) == JNI_ERR) { goto error; } linuxsocketOnLoadCalled = 1; // Initialize this module char* nettyClassName = netty_unix_util_prepend(packagePrefix, "io/netty/channel/epoll/NativeDatagramPacketArray$NativeDatagramPacket"); jclass nativeDatagramPacketCls = (*env)->FindClass(env, nettyClassName); free(nettyClassName); nettyClassName = NULL; if (nativeDatagramPacketCls == NULL) { // pending exception... goto error; } packetAddrFieldId = (*env)->GetFieldID(env, nativeDatagramPacketCls, "addr", "[B"); if (packetAddrFieldId == NULL) { netty_unix_errors_throwRuntimeException(env, "failed to get field ID: NativeDatagramPacket.addr"); goto error; } packetScopeIdFieldId = (*env)->GetFieldID(env, nativeDatagramPacketCls, "scopeId", "I"); if (packetScopeIdFieldId == NULL) { netty_unix_errors_throwRuntimeException(env, "failed to get field ID: NativeDatagramPacket.scopeId"); goto error; } packetPortFieldId = (*env)->GetFieldID(env, nativeDatagramPacketCls, "port", "I"); if (packetPortFieldId == NULL) { netty_unix_errors_throwRuntimeException(env, "failed to get field ID: NativeDatagramPacket.port"); goto error; } packetMemoryAddressFieldId = (*env)->GetFieldID(env, nativeDatagramPacketCls, "memoryAddress", "J"); if (packetMemoryAddressFieldId == NULL) { netty_unix_errors_throwRuntimeException(env, "failed to get field ID: NativeDatagramPacket.memoryAddress"); goto error; } packetCountFieldId = (*env)->GetFieldID(env, nativeDatagramPacketCls, "count", "I"); if (packetCountFieldId == NULL) { netty_unix_errors_throwRuntimeException(env, "failed to get field ID: NativeDatagramPacket.count"); goto error; } return NETTY_JNI_VERSION; error: if (limitsOnLoadCalled == 1) { netty_unix_limits_JNI_OnUnLoad(env); } if (errorsOnLoadCalled == 1) { netty_unix_errors_JNI_OnUnLoad(env); } if (filedescriptorOnLoadCalled == 1) { netty_unix_filedescriptor_JNI_OnUnLoad(env); } if (socketOnLoadCalled == 1) { netty_unix_socket_JNI_OnUnLoad(env); } if (bufferOnLoadCalled == 1) { netty_unix_buffer_JNI_OnUnLoad(env); } if (linuxsocketOnLoadCalled == 1) { netty_epoll_linuxsocket_JNI_OnUnLoad(env); } packetAddrFieldId = NULL; packetScopeIdFieldId = NULL; packetPortFieldId = NULL; packetMemoryAddressFieldId = NULL; packetCountFieldId = NULL; return JNI_ERR; }
jint netty_kqueue_bsdsocket_JNI_OnLoad(JNIEnv* env, const char* packagePrefix) { // Register the methods which are not referenced by static member variables JNINativeMethod* dynamicMethods = createDynamicMethodsTable(packagePrefix); if (netty_unix_util_register_natives(env, packagePrefix, "io/netty/channel/kqueue/BsdSocket", dynamicMethods, dynamicMethodsTableSize()) != 0) { freeDynamicMethodsTable(dynamicMethods); return JNI_ERR; } freeDynamicMethodsTable(dynamicMethods); dynamicMethods = NULL; // Initialize this module char* nettyClassName = netty_unix_util_prepend(packagePrefix, "io/netty/channel/DefaultFileRegion"); jclass fileRegionCls = (*env)->FindClass(env, nettyClassName); free(nettyClassName); nettyClassName = NULL; if (fileRegionCls == NULL) { return JNI_ERR; } fileChannelFieldId = (*env)->GetFieldID(env, fileRegionCls, "file", "Ljava/nio/channels/FileChannel;"); if (fileChannelFieldId == NULL) { netty_unix_errors_throwRuntimeException(env, "failed to get field ID: DefaultFileRegion.file"); return JNI_ERR; } transferredFieldId = (*env)->GetFieldID(env, fileRegionCls, "transferred", "J"); if (transferredFieldId == NULL) { netty_unix_errors_throwRuntimeException(env, "failed to get field ID: DefaultFileRegion.transferred"); return JNI_ERR; } jclass fileChannelCls = (*env)->FindClass(env, "sun/nio/ch/FileChannelImpl"); if (fileChannelCls == NULL) { // pending exception... return JNI_ERR; } fileDescriptorFieldId = (*env)->GetFieldID(env, fileChannelCls, "fd", "Ljava/io/FileDescriptor;"); if (fileDescriptorFieldId == NULL) { netty_unix_errors_throwRuntimeException(env, "failed to get field ID: FileChannelImpl.fd"); return JNI_ERR; } jclass fileDescriptorCls = (*env)->FindClass(env, "java/io/FileDescriptor"); if (fileDescriptorCls == NULL) { // pending exception... return JNI_ERR; } fdFieldId = (*env)->GetFieldID(env, fileDescriptorCls, "fd", "I"); if (fdFieldId == NULL) { netty_unix_errors_throwRuntimeException(env, "failed to get field ID: FileDescriptor.fd"); return JNI_ERR; } stringCls = (*env)->FindClass(env, "java/lang/String"); if (stringCls == NULL) { // pending exception... return JNI_ERR; } nettyClassName = netty_unix_util_prepend(packagePrefix, "io/netty/channel/unix/PeerCredentials"); jclass localPeerCredsClass = (*env)->FindClass(env, nettyClassName); free(nettyClassName); nettyClassName = NULL; if (localPeerCredsClass == NULL) { // pending exception... return JNI_ERR; } peerCredentialsClass = (jclass) (*env)->NewGlobalRef(env, localPeerCredsClass); if (peerCredentialsClass == NULL) { // out-of-memory! netty_unix_errors_throwOutOfMemoryError(env); return JNI_ERR; } peerCredentialsMethodId = (*env)->GetMethodID(env, peerCredentialsClass, "<init>", "(II[I)V"); if (peerCredentialsMethodId == NULL) { netty_unix_errors_throwRuntimeException(env, "failed to get method ID: PeerCredentials.<init>(int, int, int[])"); return JNI_ERR; } return NETTY_JNI_VERSION; }
static inline jint epollCtl(JNIEnv* env, jint efd, int op, jint fd, jint flags) { uint32_t events = flags; struct epoll_event ev = { .data.fd = fd, .events = events }; return epoll_ctl(efd, op, fd, &ev); } // util methods end jint JNI_OnLoad(JavaVM* vm, void* reserved) { JNIEnv* env; if ((*vm)->GetEnv(vm, (void**) &env, JNI_VERSION_1_6) != JNI_OK) { return JNI_ERR; } else { // Load the prefix to use when looking for Netty classes jclass systemCls = (*env)->FindClass(env, "java/lang/System"); if (systemCls == NULL) { return JNI_ERR; } jmethodID getPropertyMethod = (*env)->GetStaticMethodID(env, systemCls, "getProperty", "(Ljava/lang/String;)Ljava/lang/String;"); if (getPropertyMethod == NULL) { return JNI_ERR; } jstring propertyName = (*env)->NewStringUTF(env, "io.netty.native.epoll.nettyPackagePrefix"); nettyPackagePrefixJString = (*env)->CallStaticObjectMethod(env, systemCls, getPropertyMethod, propertyName); if (nettyPackagePrefixJString != NULL) { nettyPackagePrefix = (*env)->GetStringUTFChars(env, nettyPackagePrefixJString, 0); } if (netty_unix_errors_JNI_OnLoad(env, nettyPackagePrefix) == JNI_ERR) { return JNI_ERR; } if (netty_unix_filedescriptor_JNI_OnLoad(env, nettyPackagePrefix) == JNI_ERR) { return JNI_ERR; } if (netty_unix_socket_JNI_OnLoad(env, nettyPackagePrefix) == JNI_ERR) { return JNI_ERR; } nettyClassName = netty_unix_util_prepend(nettyPackagePrefix, "io/netty/channel/DefaultFileRegion"); jclass fileRegionCls = (*env)->FindClass(env, nettyClassName); free(nettyClassName); nettyClassName = NULL; if (fileRegionCls == NULL) { // pending exception... return JNI_ERR; } fileChannelFieldId = (*env)->GetFieldID(env, fileRegionCls, "file", "Ljava/nio/channels/FileChannel;"); if (fileChannelFieldId == NULL) { netty_unix_errors_throwRuntimeException(env, "failed to get field ID: DefaultFileRegion.file"); return JNI_ERR; } transferedFieldId = (*env)->GetFieldID(env, fileRegionCls, "transfered", "J"); if (transferedFieldId == NULL) { netty_unix_errors_throwRuntimeException(env, "failed to get field ID: DefaultFileRegion.transfered"); return JNI_ERR; } jclass fileChannelCls = (*env)->FindClass(env, "sun/nio/ch/FileChannelImpl"); if (fileChannelCls == NULL) { // pending exception... return JNI_ERR; } fileDescriptorFieldId = (*env)->GetFieldID(env, fileChannelCls, "fd", "Ljava/io/FileDescriptor;"); if (fileDescriptorFieldId == NULL) { netty_unix_errors_throwRuntimeException(env, "failed to get field ID: FileChannelImpl.fd"); return JNI_ERR; } jclass fileDescriptorCls = (*env)->FindClass(env, "java/io/FileDescriptor"); if (fileDescriptorCls == NULL) { // pending exception... return JNI_ERR; } fdFieldId = (*env)->GetFieldID(env, fileDescriptorCls, "fd", "I"); if (fdFieldId == NULL) { netty_unix_errors_throwRuntimeException(env, "failed to get field ID: FileDescriptor.fd"); return JNI_ERR; } nettyClassName = netty_unix_util_prepend(nettyPackagePrefix, "io/netty/channel/epoll/NativeDatagramPacketArray$NativeDatagramPacket"); jclass nativeDatagramPacketCls = (*env)->FindClass(env, nettyClassName); free(nettyClassName); nettyClassName = NULL; if (nativeDatagramPacketCls == NULL) { // pending exception... return JNI_ERR; } packetAddrFieldId = (*env)->GetFieldID(env, nativeDatagramPacketCls, "addr", "[B"); if (packetAddrFieldId == NULL) { netty_unix_errors_throwRuntimeException(env, "failed to get field ID: NativeDatagramPacket.addr"); return JNI_ERR; } packetScopeIdFieldId = (*env)->GetFieldID(env, nativeDatagramPacketCls, "scopeId", "I"); if (packetScopeIdFieldId == NULL) { netty_unix_errors_throwRuntimeException(env, "failed to get field ID: NativeDatagramPacket.scopeId"); return JNI_ERR; } packetPortFieldId = (*env)->GetFieldID(env, nativeDatagramPacketCls, "port", "I"); if (packetPortFieldId == NULL) { netty_unix_errors_throwRuntimeException(env, "failed to get field ID: NativeDatagramPacket.port"); return JNI_ERR; } packetMemoryAddressFieldId = (*env)->GetFieldID(env, nativeDatagramPacketCls, "memoryAddress", "J"); if (packetMemoryAddressFieldId == NULL) { netty_unix_errors_throwRuntimeException(env, "failed to get field ID: NativeDatagramPacket.memoryAddress"); return JNI_ERR; } packetCountFieldId = (*env)->GetFieldID(env, nativeDatagramPacketCls, "count", "I"); if (packetCountFieldId == NULL) { netty_unix_errors_throwRuntimeException(env, "failed to get field ID: NativeDatagramPacket.count"); return JNI_ERR; } if (nettyPackagePrefixJString != NULL) { (*env)->ReleaseStringUTFChars(env, nettyPackagePrefixJString, nettyPackagePrefix); nettyPackagePrefix = NULL; nettyPackagePrefixJString = NULL; } return JNI_VERSION_1_6; } }