Use netty-jni-util and so remove a lot of duplication (#10735)

Motivation:

We had a lot of duplication in our jni code which was mostly due macros but also related to how we support shading. By using netty-jni-util we can share all the code between netty and netty-tcnative ( and possible other jni based netty projects in the future).

Modifications:

- Use netty-jni-util and re-use its macros / functions
- Remove duplicated code
- Adjust build files

Result:

Less code duplication for JNI
This commit is contained in:
Norman Maurer 2020-10-29 16:36:07 +01:00
parent 180f0b6ced
commit 475f20aa0f
17 changed files with 227 additions and 478 deletions

View File

@ -25,6 +25,11 @@
#include "netty_unix_socket.h"
#include "netty_unix_errors.h"
// Add define if NETTY_BUILD_STATIC is defined so it is picked up in netty_jni_util.c
#ifdef NETTY_BUILD_STATIC
#define NETTY_JNI_UTIL_BUILD_STATIC
#endif
static jclass dnsResolverClass = NULL;
static jclass byteArrayClass = NULL;
static jclass stringClass = NULL;

View File

@ -33,7 +33,7 @@
<unix.common.lib.unpacked.dir>${unix.common.lib.dir}/META-INF/native/lib</unix.common.lib.unpacked.dir>
<unix.common.include.unpacked.dir>${unix.common.lib.dir}/META-INF/native/include</unix.common.include.unpacked.dir>
<jni.compiler.args.cflags>CFLAGS=-O3 -Werror -fno-omit-frame-pointer -Wunused-variable -fvisibility=hidden -I${unix.common.include.unpacked.dir}</jni.compiler.args.cflags>
<jni.compiler.args.ldflags>LDFLAGS=-L${unix.common.lib.unpacked.dir} -Wl,--no-as-needed -lrt -Wl,--whole-archive -l${unix.common.lib.name} -Wl,--no-whole-archive</jni.compiler.args.ldflags>
<jni.compiler.args.ldflags>LDFLAGS=-L${unix.common.lib.unpacked.dir} -Wl,--no-as-needed -lrt -ldl -Wl,--whole-archive -l${unix.common.lib.name} -Wl,--no-whole-archive</jni.compiler.args.ldflags>
<nativeSourceDirectory>${project.basedir}/src/main/c</nativeSourceDirectory>
<skipTests>true</skipTests>
</properties>

View File

@ -723,22 +723,22 @@ static JNINativeMethod* createDynamicMethodsTable(const char* packagePrefix) {
memcpy(dynamicMethods, fixed_method_table, sizeof(fixed_method_table));
JNINativeMethod* dynamicMethod = &dynamicMethods[fixed_method_table_size];
NETTY_PREPEND(packagePrefix, "io/netty/channel/unix/PeerCredentials;", dynamicTypeName, error);
NETTY_PREPEND("(I)L", dynamicTypeName, dynamicMethod->signature, error);
NETTY_JNI_UTIL_PREPEND(packagePrefix, "io/netty/channel/unix/PeerCredentials;", dynamicTypeName, error);
NETTY_JNI_UTIL_PREPEND("(I)L", dynamicTypeName, dynamicMethod->signature, error);
dynamicMethod->name = "getPeerCredentials";
dynamicMethod->fnPtr = (void *) netty_epoll_linuxsocket_getPeerCredentials;
netty_unix_util_free_dynamic_name(&dynamicTypeName);
netty_jni_util_free_dynamic_name(&dynamicTypeName);
++dynamicMethod;
NETTY_PREPEND(packagePrefix, "io/netty/channel/DefaultFileRegion;JJJ)J", dynamicTypeName, error);
NETTY_PREPEND("(IL", dynamicTypeName, dynamicMethod->signature, error);
NETTY_JNI_UTIL_PREPEND(packagePrefix, "io/netty/channel/DefaultFileRegion;JJJ)J", dynamicTypeName, error);
NETTY_JNI_UTIL_PREPEND("(IL", dynamicTypeName, dynamicMethod->signature, error);
dynamicMethod->name = "sendFile";
dynamicMethod->fnPtr = (void *) netty_epoll_linuxsocket_sendFile;
netty_unix_util_free_dynamic_name(&dynamicTypeName);
netty_jni_util_free_dynamic_name(&dynamicTypeName);
return dynamicMethods;
error:
free(dynamicTypeName);
netty_unix_util_free_dynamic_methods_table(dynamicMethods, fixed_method_table_size, dynamicMethodsTableSize());
netty_jni_util_free_dynamic_methods_table(dynamicMethods, fixed_method_table_size, dynamicMethodsTableSize());
return NULL;
}
@ -755,7 +755,7 @@ jint netty_epoll_linuxsocket_JNI_OnLoad(JNIEnv* env, const char* packagePrefix)
if (dynamicMethods == NULL) {
goto done;
}
if (netty_unix_util_register_natives(env,
if (netty_jni_util_register_natives(env,
packagePrefix,
LINUXSOCKET_CLASSNAME,
dynamicMethods,
@ -763,35 +763,35 @@ jint netty_epoll_linuxsocket_JNI_OnLoad(JNIEnv* env, const char* packagePrefix)
goto done;
}
NETTY_PREPEND(packagePrefix, "io/netty/channel/unix/PeerCredentials", nettyClassName, done);
NETTY_LOAD_CLASS(env, peerCredentialsClass, nettyClassName, done);
netty_unix_util_free_dynamic_name(&nettyClassName);
NETTY_JNI_UTIL_PREPEND(packagePrefix, "io/netty/channel/unix/PeerCredentials", nettyClassName, done);
NETTY_JNI_UTIL_LOAD_CLASS(env, peerCredentialsClass, nettyClassName, done);
netty_jni_util_free_dynamic_name(&nettyClassName);
NETTY_GET_METHOD(env, peerCredentialsClass, peerCredentialsMethodId, "<init>", "(II[I)V", done);
NETTY_JNI_UTIL_GET_METHOD(env, peerCredentialsClass, peerCredentialsMethodId, "<init>", "(II[I)V", done);
NETTY_PREPEND(packagePrefix, "io/netty/channel/DefaultFileRegion", nettyClassName, done);
NETTY_FIND_CLASS(env, fileRegionCls, nettyClassName, done);
netty_unix_util_free_dynamic_name(&nettyClassName);
NETTY_JNI_UTIL_PREPEND(packagePrefix, "io/netty/channel/DefaultFileRegion", nettyClassName, done);
NETTY_JNI_UTIL_FIND_CLASS(env, fileRegionCls, nettyClassName, done);
netty_jni_util_free_dynamic_name(&nettyClassName);
NETTY_GET_FIELD(env, fileRegionCls, fileChannelFieldId, "file", "Ljava/nio/channels/FileChannel;", done);
NETTY_GET_FIELD(env, fileRegionCls, transferredFieldId, "transferred", "J", done);
NETTY_JNI_UTIL_GET_FIELD(env, fileRegionCls, fileChannelFieldId, "file", "Ljava/nio/channels/FileChannel;", done);
NETTY_JNI_UTIL_GET_FIELD(env, fileRegionCls, transferredFieldId, "transferred", "J", done);
NETTY_FIND_CLASS(env, fileChannelCls, "sun/nio/ch/FileChannelImpl", done);
NETTY_GET_FIELD(env, fileChannelCls, fileDescriptorFieldId, "fd", "Ljava/io/FileDescriptor;", done);
NETTY_JNI_UTIL_FIND_CLASS(env, fileChannelCls, "sun/nio/ch/FileChannelImpl", done);
NETTY_JNI_UTIL_GET_FIELD(env, fileChannelCls, fileDescriptorFieldId, "fd", "Ljava/io/FileDescriptor;", done);
NETTY_FIND_CLASS(env, fileDescriptorCls, "java/io/FileDescriptor", done);
NETTY_GET_FIELD(env, fileDescriptorCls, fdFieldId, "fd", "I", done);
NETTY_JNI_UTIL_FIND_CLASS(env, fileDescriptorCls, "java/io/FileDescriptor", done);
NETTY_JNI_UTIL_GET_FIELD(env, fileDescriptorCls, fdFieldId, "fd", "I", done);
ret = NETTY_JNI_VERSION;
ret = NETTY_JNI_UTIL_JNI_VERSION;
done:
netty_unix_util_free_dynamic_methods_table(dynamicMethods, fixed_method_table_size, dynamicMethodsTableSize());
netty_jni_util_free_dynamic_methods_table(dynamicMethods, fixed_method_table_size, dynamicMethodsTableSize());
free(nettyClassName);
return ret;
}
void netty_epoll_linuxsocket_JNI_OnUnLoad(JNIEnv* env, const char* packagePrefix) {
NETTY_UNLOAD_CLASS(env, peerCredentialsClass);
NETTY_JNI_UTIL_UNLOAD_CLASS(env, peerCredentialsClass);
netty_unix_util_unregister_natives(env, packagePrefix, LINUXSOCKET_CLASSNAME);
netty_jni_util_unregister_natives(env, packagePrefix, LINUXSOCKET_CLASSNAME);
}

View File

@ -49,6 +49,11 @@
#include "netty_unix_socket.h"
#include "netty_unix_util.h"
// Add define if NETTY_BUILD_STATIC is defined so it is picked up in netty_jni_util.c
#ifdef NETTY_BUILD_STATIC
#define NETTY_JNI_UTIL_BUILD_STATIC
#endif
#define STATICALLY_CLASSNAME "io/netty/channel/epoll/NativeStaticallyReferencedJniMethods"
#define NATIVE_CLASSNAME "io/netty/channel/epoll/Native"
@ -101,7 +106,6 @@ static jfieldID packetScopeIdFieldId = NULL;
static jfieldID packetPortFieldId = NULL;
static jfieldID packetMemoryAddressFieldId = NULL;
static jfieldID packetCountFieldId = NULL;
static char* staticPackagePrefix = NULL;
// util methods
static int getSysctlValue(const char * property, int* returnValue) {
@ -544,23 +548,23 @@ static JNINativeMethod* createDynamicMethodsTable(const char* packagePrefix) {
memcpy(dynamicMethods, fixed_method_table, sizeof(fixed_method_table));
JNINativeMethod* dynamicMethod = &dynamicMethods[fixed_method_table_size];
NETTY_PREPEND(packagePrefix, "io/netty/channel/epoll/NativeDatagramPacketArray$NativeDatagramPacket;II)I", dynamicTypeName, error);
NETTY_PREPEND("(IZ[L", dynamicTypeName, dynamicMethod->signature, error);
NETTY_JNI_UTIL_PREPEND(packagePrefix, "io/netty/channel/epoll/NativeDatagramPacketArray$NativeDatagramPacket;II)I", dynamicTypeName, error);
NETTY_JNI_UTIL_PREPEND("(IZ[L", dynamicTypeName, dynamicMethod->signature, error);
dynamicMethod->name = "sendmmsg0";
dynamicMethod->fnPtr = (void *) netty_epoll_native_sendmmsg0;
netty_unix_util_free_dynamic_name(&dynamicTypeName);
netty_jni_util_free_dynamic_name(&dynamicTypeName);
++dynamicMethod;
NETTY_PREPEND(packagePrefix, "io/netty/channel/epoll/NativeDatagramPacketArray$NativeDatagramPacket;II)I", dynamicTypeName, error);
NETTY_PREPEND("(IZ[L", dynamicTypeName, dynamicMethod->signature, error);
NETTY_JNI_UTIL_PREPEND(packagePrefix, "io/netty/channel/epoll/NativeDatagramPacketArray$NativeDatagramPacket;II)I", dynamicTypeName, error);
NETTY_JNI_UTIL_PREPEND("(IZ[L", dynamicTypeName, dynamicMethod->signature, error);
dynamicMethod->name = "recvmmsg0";
dynamicMethod->fnPtr = (void *) netty_epoll_native_recvmmsg0;
netty_unix_util_free_dynamic_name(&dynamicTypeName);
netty_jni_util_free_dynamic_name(&dynamicTypeName);
return dynamicMethods;
error:
free(dynamicTypeName);
netty_unix_util_free_dynamic_methods_table(dynamicMethods, fixed_method_table_size, dynamicMethodsTableSize());
netty_jni_util_free_dynamic_methods_table(dynamicMethods, fixed_method_table_size, dynamicMethodsTableSize());
return NULL;
}
@ -581,7 +585,7 @@ static jint netty_epoll_native_JNI_OnLoad(JNIEnv* env, const char* packagePrefix
JNINativeMethod* dynamicMethods = NULL;
// We must register the statically referenced methods first!
if (netty_unix_util_register_natives(env,
if (netty_jni_util_register_natives(env,
packagePrefix,
STATICALLY_CLASSNAME,
statically_referenced_fixed_method_table,
@ -596,7 +600,7 @@ static jint netty_epoll_native_JNI_OnLoad(JNIEnv* env, const char* packagePrefix
goto done;
}
if (netty_unix_util_register_natives(env,
if (netty_jni_util_register_natives(env,
packagePrefix,
NATIVE_CLASSNAME,
dynamicMethods,
@ -637,29 +641,29 @@ static jint netty_epoll_native_JNI_OnLoad(JNIEnv* env, const char* packagePrefix
linuxsocketOnLoadCalled = 1;
// Initialize this module
NETTY_PREPEND(packagePrefix, "io/netty/channel/epoll/NativeDatagramPacketArray$NativeDatagramPacket", nettyClassName, done);
NETTY_FIND_CLASS(env, nativeDatagramPacketCls, nettyClassName, done);
netty_unix_util_free_dynamic_name(&nettyClassName);
NETTY_JNI_UTIL_PREPEND(packagePrefix, "io/netty/channel/epoll/NativeDatagramPacketArray$NativeDatagramPacket", nettyClassName, done);
NETTY_JNI_UTIL_FIND_CLASS(env, nativeDatagramPacketCls, nettyClassName, done);
netty_jni_util_free_dynamic_name(&nettyClassName);
NETTY_GET_FIELD(env, nativeDatagramPacketCls, packetAddrFieldId, "addr", "[B", done);
NETTY_GET_FIELD(env, nativeDatagramPacketCls, packetAddrLenFieldId, "addrLen", "I", done);
NETTY_GET_FIELD(env, nativeDatagramPacketCls, packetScopeIdFieldId, "scopeId", "I", done);
NETTY_GET_FIELD(env, nativeDatagramPacketCls, packetPortFieldId, "port", "I", done);
NETTY_GET_FIELD(env, nativeDatagramPacketCls, packetMemoryAddressFieldId, "memoryAddress", "J", done);
NETTY_GET_FIELD(env, nativeDatagramPacketCls, packetCountFieldId, "count", "I", done);
NETTY_JNI_UTIL_GET_FIELD(env, nativeDatagramPacketCls, packetAddrFieldId, "addr", "[B", done);
NETTY_JNI_UTIL_GET_FIELD(env, nativeDatagramPacketCls, packetAddrLenFieldId, "addrLen", "I", done);
NETTY_JNI_UTIL_GET_FIELD(env, nativeDatagramPacketCls, packetScopeIdFieldId, "scopeId", "I", done);
NETTY_JNI_UTIL_GET_FIELD(env, nativeDatagramPacketCls, packetPortFieldId, "port", "I", done);
NETTY_JNI_UTIL_GET_FIELD(env, nativeDatagramPacketCls, packetMemoryAddressFieldId, "memoryAddress", "J", done);
NETTY_JNI_UTIL_GET_FIELD(env, nativeDatagramPacketCls, packetCountFieldId, "count", "I", done);
ret = NETTY_JNI_VERSION;
ret = NETTY_JNI_UTIL_JNI_VERSION;
done:
netty_unix_util_free_dynamic_methods_table(dynamicMethods, fixed_method_table_size, dynamicMethodsTableSize());
netty_jni_util_free_dynamic_methods_table(dynamicMethods, fixed_method_table_size, dynamicMethodsTableSize());
free(nettyClassName);
if (ret == JNI_ERR) {
if (staticallyRegistered == 1) {
netty_unix_util_unregister_natives(env, packagePrefix, STATICALLY_CLASSNAME);
netty_jni_util_unregister_natives(env, packagePrefix, STATICALLY_CLASSNAME);
}
if (nativeRegistered == 1) {
netty_unix_util_unregister_natives(env, packagePrefix, NATIVE_CLASSNAME);
netty_jni_util_unregister_natives(env, packagePrefix, NATIVE_CLASSNAME);
}
if (limitsOnLoadCalled == 1) {
netty_unix_limits_JNI_OnUnLoad(env, packagePrefix);
@ -689,7 +693,7 @@ done:
return ret;
}
static void netty_epoll_native_JNI_OnUnLoad(JNIEnv* env, const char* packagePrefix) {
static void netty_epoll_native_JNI_OnUnload(JNIEnv* env, const char* packagePrefix) {
netty_unix_limits_JNI_OnUnLoad(env, packagePrefix);
netty_unix_errors_JNI_OnUnLoad(env, packagePrefix);
netty_unix_filedescriptor_JNI_OnUnLoad(env, packagePrefix);
@ -704,72 +708,31 @@ static void netty_epoll_native_JNI_OnUnLoad(JNIEnv* env, const char* packagePref
packetMemoryAddressFieldId = NULL;
packetCountFieldId = NULL;
netty_unix_util_unregister_natives(env, packagePrefix, STATICALLY_CLASSNAME);
netty_unix_util_unregister_natives(env, packagePrefix, NATIVE_CLASSNAME);
netty_jni_util_unregister_natives(env, packagePrefix, STATICALLY_CLASSNAME);
netty_jni_util_unregister_natives(env, packagePrefix, NATIVE_CLASSNAME);
}
// Invoked by the JVM when statically linked
static jint JNI_OnLoad_netty_transport_native_epoll0(JavaVM* vm, void* reserved) {
JNIEnv* env;
if ((*vm)->GetEnv(vm, (void**) &env, NETTY_JNI_VERSION) != JNI_OK) {
return JNI_ERR;
}
char* packagePrefix = NULL;
#ifndef NETTY_BUILD_STATIC
Dl_info dlinfo;
jint status = 0;
// We need to use an address of a function that is uniquely part of this library, so choose a static
// function. See https://github.com/netty/netty/issues/4840.
if (!dladdr((void*) netty_epoll_native_JNI_OnUnLoad, &dlinfo)) {
fprintf(stderr, "FATAL: transport-native-epoll JNI call to dladdr failed!\n");
return JNI_ERR;
}
packagePrefix = netty_unix_util_parse_package_prefix(dlinfo.dli_fname, "netty_transport_native_epoll", &status);
if (status == JNI_ERR) {
fprintf(stderr, "FATAL: transport-native-epoll JNI encountered unexpected dlinfo.dli_fname: %s\n", dlinfo.dli_fname);
return JNI_ERR;
}
#endif /* NETTY_BUILD_STATIC */
jint ret = netty_epoll_native_JNI_OnLoad(env, packagePrefix);
if (ret == JNI_ERR) {
free(packagePrefix);
staticPackagePrefix = NULL;
} else {
staticPackagePrefix = packagePrefix;
}
return ret;
}
static void JNI_OnUnload_netty_transport_native_epoll0(JavaVM* vm, void* reserved) {
JNIEnv* env;
if ((*vm)->GetEnv(vm, (void**) &env, NETTY_JNI_VERSION) != JNI_OK) {
// Something is wrong but nothing we can do about this :(
return;
}
netty_epoll_native_JNI_OnUnLoad(env, staticPackagePrefix);
free(staticPackagePrefix);
staticPackagePrefix = NULL;
}
// We build with -fvisibility=hidden so ensure we mark everything that needs to be visible with JNIEXPORT
// https://mail.openjdk.java.net/pipermail/core-libs-dev/2013-February/014549.html
// Invoked by the JVM when statically linked
JNIEXPORT jint JNI_OnLoad_netty_transport_native_epoll(JavaVM* vm, void* reserved) {
return JNI_OnLoad_netty_transport_native_epoll0(vm, reserved);
return netty_jni_util_JNI_OnLoad(vm, reserved, "netty_transport_native_epoll", netty_epoll_native_JNI_OnLoad);
}
// Invoked by the JVM when statically linked
JNIEXPORT void JNI_OnUnload_netty_transport_native_epoll(JavaVM* vm, void* reserved) {
JNI_OnUnload_netty_transport_native_epoll0(vm, reserved);
netty_jni_util_JNI_OnUnload(vm, reserved, netty_epoll_native_JNI_OnUnload);
}
#ifndef NETTY_BUILD_STATIC
JNIEXPORT jint JNI_OnLoad(JavaVM* vm, void* reserved) {
return JNI_OnLoad_netty_transport_native_epoll0(vm, reserved);
return netty_jni_util_JNI_OnLoad(vm, reserved, "netty_transport_native_epoll", netty_epoll_native_JNI_OnLoad);
}
JNIEXPORT void JNI_OnUnload(JavaVM* vm, void* reserved) {
JNI_OnUnload_netty_transport_native_epoll0(vm, reserved);
netty_jni_util_JNI_OnUnload(vm, reserved, netty_epoll_native_JNI_OnUnload);
}
#endif /* NETTY_BUILD_STATIC */

View File

@ -216,23 +216,23 @@ static JNINativeMethod* createDynamicMethodsTable(const char* packagePrefix) {
memcpy(dynamicMethods, fixed_method_table, sizeof(fixed_method_table));
JNINativeMethod* dynamicMethod = &dynamicMethods[fixed_method_table_size];
NETTY_PREPEND(packagePrefix, "io/netty/channel/DefaultFileRegion;JJJ)J", dynamicTypeName, error);
NETTY_PREPEND("(IL", dynamicTypeName, dynamicMethod->signature, error);
NETTY_JNI_UTIL_PREPEND(packagePrefix, "io/netty/channel/DefaultFileRegion;JJJ)J", dynamicTypeName, error);
NETTY_JNI_UTIL_PREPEND("(IL", dynamicTypeName, dynamicMethod->signature, error);
dynamicMethod->name = "sendFile";
dynamicMethod->fnPtr = (void *) netty_kqueue_bsdsocket_sendFile;
netty_unix_util_free_dynamic_name(&dynamicTypeName);
netty_jni_util_free_dynamic_name(&dynamicTypeName);
++dynamicMethod;
NETTY_PREPEND(packagePrefix, "io/netty/channel/unix/PeerCredentials;", dynamicTypeName, error);
NETTY_PREPEND("(I)L", dynamicTypeName, dynamicMethod->signature, error);
NETTY_JNI_UTIL_PREPEND(packagePrefix, "io/netty/channel/unix/PeerCredentials;", dynamicTypeName, error);
NETTY_JNI_UTIL_PREPEND("(I)L", dynamicTypeName, dynamicMethod->signature, error);
dynamicMethod->name = "getPeerCredentials";
dynamicMethod->fnPtr = (void *) netty_kqueue_bsdsocket_getPeerCredentials;
netty_unix_util_free_dynamic_name(&dynamicTypeName);
netty_jni_util_free_dynamic_name(&dynamicTypeName);
return dynamicMethods;
error:
free(dynamicTypeName);
netty_unix_util_free_dynamic_methods_table(dynamicMethods, fixed_method_table_size, dynamicMethodsTableSize());
netty_jni_util_free_dynamic_methods_table(dynamicMethods, fixed_method_table_size, dynamicMethodsTableSize());
return NULL;
}
@ -249,7 +249,7 @@ jint netty_kqueue_bsdsocket_JNI_OnLoad(JNIEnv* env, const char* packagePrefix) {
if (dynamicMethods == NULL) {
goto done;
}
if (netty_unix_util_register_natives(env,
if (netty_jni_util_register_natives(env,
packagePrefix,
BSDSOCKET_CLASSNAME,
dynamicMethods,
@ -258,37 +258,37 @@ jint netty_kqueue_bsdsocket_JNI_OnLoad(JNIEnv* env, const char* packagePrefix) {
}
// Initialize this module
NETTY_PREPEND(packagePrefix, "io/netty/channel/DefaultFileRegion", nettyClassName, done);
NETTY_FIND_CLASS(env, fileRegionCls, nettyClassName, done);
netty_unix_util_free_dynamic_name(&nettyClassName);
NETTY_JNI_UTIL_PREPEND(packagePrefix, "io/netty/channel/DefaultFileRegion", nettyClassName, done);
NETTY_JNI_UTIL_FIND_CLASS(env, fileRegionCls, nettyClassName, done);
netty_jni_util_free_dynamic_name(&nettyClassName);
NETTY_GET_FIELD(env, fileRegionCls, fileChannelFieldId, "file", "Ljava/nio/channels/FileChannel;", done);
NETTY_GET_FIELD(env, fileRegionCls, transferredFieldId, "transferred", "J", done);
NETTY_JNI_UTIL_GET_FIELD(env, fileRegionCls, fileChannelFieldId, "file", "Ljava/nio/channels/FileChannel;", done);
NETTY_JNI_UTIL_GET_FIELD(env, fileRegionCls, transferredFieldId, "transferred", "J", done);
NETTY_FIND_CLASS(env, fileChannelCls, "sun/nio/ch/FileChannelImpl", done);
NETTY_GET_FIELD(env, fileChannelCls, fileDescriptorFieldId, "fd", "Ljava/io/FileDescriptor;", done);
NETTY_JNI_UTIL_FIND_CLASS(env, fileChannelCls, "sun/nio/ch/FileChannelImpl", done);
NETTY_JNI_UTIL_GET_FIELD(env, fileChannelCls, fileDescriptorFieldId, "fd", "Ljava/io/FileDescriptor;", done);
NETTY_FIND_CLASS(env, fileDescriptorCls, "java/io/FileDescriptor", done);
NETTY_GET_FIELD(env, fileDescriptorCls, fdFieldId, "fd", "I", done);
NETTY_JNI_UTIL_FIND_CLASS(env, fileDescriptorCls, "java/io/FileDescriptor", done);
NETTY_JNI_UTIL_GET_FIELD(env, fileDescriptorCls, fdFieldId, "fd", "I", done);
NETTY_LOAD_CLASS(env, stringClass, "java/lang/String", done);
NETTY_JNI_UTIL_LOAD_CLASS(env, stringClass, "java/lang/String", done);
NETTY_PREPEND(packagePrefix, "io/netty/channel/unix/PeerCredentials", nettyClassName, done);
NETTY_LOAD_CLASS(env, peerCredentialsClass, nettyClassName, done);
netty_unix_util_free_dynamic_name(&nettyClassName);
NETTY_JNI_UTIL_PREPEND(packagePrefix, "io/netty/channel/unix/PeerCredentials", nettyClassName, done);
NETTY_JNI_UTIL_LOAD_CLASS(env, peerCredentialsClass, nettyClassName, done);
netty_jni_util_free_dynamic_name(&nettyClassName);
NETTY_GET_METHOD(env, peerCredentialsClass, peerCredentialsMethodId, "<init>", "(II[I)V", done);
ret = NETTY_JNI_VERSION;
NETTY_JNI_UTIL_GET_METHOD(env, peerCredentialsClass, peerCredentialsMethodId, "<init>", "(II[I)V", done);
ret = NETTY_JNI_UTIL_JNI_VERSION;
done:
netty_unix_util_free_dynamic_methods_table(dynamicMethods, fixed_method_table_size, dynamicMethodsTableSize());
netty_jni_util_free_dynamic_methods_table(dynamicMethods, fixed_method_table_size, dynamicMethodsTableSize());
free(nettyClassName);
return ret;
}
void netty_kqueue_bsdsocket_JNI_OnUnLoad(JNIEnv* env, const char* packagePrefix) {
NETTY_UNLOAD_CLASS(env, peerCredentialsClass);
NETTY_UNLOAD_CLASS(env, stringClass);
NETTY_JNI_UTIL_UNLOAD_CLASS(env, peerCredentialsClass);
NETTY_JNI_UTIL_UNLOAD_CLASS(env, stringClass);
netty_unix_util_unregister_natives(env, packagePrefix, BSDSOCKET_CLASSNAME);
netty_jni_util_unregister_natives(env, packagePrefix, BSDSOCKET_CLASSNAME);
}

View File

@ -39,16 +39,16 @@ static const jint fixed_method_table_size = sizeof(fixed_method_table) / sizeof(
// JNI Method Registration Table End
jint netty_kqueue_eventarray_JNI_OnLoad(JNIEnv* env, const char* packagePrefix) {
if (netty_unix_util_register_natives(env,
if (netty_jni_util_register_natives(env,
packagePrefix,
EVENT_ARRAY_CLASSNAME,
fixed_method_table,
fixed_method_table_size) != 0) {
return JNI_ERR;
}
return NETTY_JNI_VERSION;
return NETTY_JNI_UTIL_JNI_VERSION;
}
void netty_kqueue_eventarray_JNI_OnUnLoad(JNIEnv* env, const char* packagePrefix) {
netty_unix_util_unregister_natives(env, packagePrefix, EVENT_ARRAY_CLASSNAME);
netty_jni_util_unregister_natives(env, packagePrefix, EVENT_ARRAY_CLASSNAME);
}

View File

@ -36,6 +36,11 @@
#include "netty_unix_socket.h"
#include "netty_unix_util.h"
// Add define if NETTY_BUILD_STATIC is defined so it is picked up in netty_jni_util.c
#ifdef NETTY_BUILD_STATIC
#define NETTY_JNI_UTIL_BUILD_STATIC
#endif
#define STATICALLY_CLASSNAME "io/netty/channel/kqueue/KQueueStaticallyReferencedJniMethods"
#define NATIVE_CLASSNAME "io/netty/channel/kqueue/Native"
@ -71,8 +76,6 @@
static clockid_t waitClockId = 0; // initialized by netty_unix_util_initialize_wait_clock
static char* staticPackagePrefix;
static jint netty_kqueue_native_kqueueCreate(JNIEnv* env, jclass clazz) {
jint kq = kqueue();
if (kq < 0) {
@ -281,7 +284,7 @@ static jint netty_kqueue_native_JNI_OnLoad(JNIEnv* env, const char* packagePrefi
int eventarrayOnLoadCalled = 0;
// We must register the statically referenced methods first!
if (netty_unix_util_register_natives(env,
if (netty_jni_util_register_natives(env,
packagePrefix,
STATICALLY_CLASSNAME,
statically_referenced_fixed_method_table,
@ -291,11 +294,10 @@ static jint netty_kqueue_native_JNI_OnLoad(JNIEnv* env, const char* packagePrefi
staticallyRegistered = 1;
// Register the methods which are not referenced by static member variables
if (netty_unix_util_register_natives(env, packagePrefix, NATIVE_CLASSNAME, fixed_method_table, fixed_method_table_size) != 0) {
if (netty_jni_util_register_natives(env, packagePrefix, NATIVE_CLASSNAME, fixed_method_table, fixed_method_table_size) != 0) {
goto error;
}
nativeRegistered = 1;
// Load all c modules that we depend upon
if (netty_unix_limits_JNI_OnLoad(env, packagePrefix) == JNI_ERR) {
goto error;
@ -336,16 +338,17 @@ static jint netty_kqueue_native_JNI_OnLoad(JNIEnv* env, const char* packagePrefi
if (!netty_unix_util_initialize_wait_clock(&waitClockId)) {
fprintf(stderr, "FATAL: could not find a clock for clock_gettime!\n");
fflush(stderr);
goto error;
}
return NETTY_JNI_VERSION;
return NETTY_JNI_UTIL_JNI_VERSION;
error:
if (staticallyRegistered == 1) {
netty_unix_util_unregister_natives(env, packagePrefix, STATICALLY_CLASSNAME);
netty_jni_util_unregister_natives(env, packagePrefix, STATICALLY_CLASSNAME);
}
if (nativeRegistered == 1) {
netty_unix_util_unregister_natives(env, packagePrefix, NATIVE_CLASSNAME);
netty_jni_util_unregister_natives(env, packagePrefix, NATIVE_CLASSNAME);
}
if (limitsOnLoadCalled == 1) {
netty_unix_limits_JNI_OnUnLoad(env, packagePrefix);
@ -371,10 +374,7 @@ error:
return JNI_ERR;
}
static void netty_kqueue_native_JNI_OnUnLoad(JNIEnv* env, const char* packagePrefix) {
netty_unix_util_unregister_natives(env, packagePrefix, STATICALLY_CLASSNAME);
netty_unix_util_unregister_natives(env, packagePrefix, NATIVE_CLASSNAME);
static void netty_kqueue_native_JNI_OnUnload(JNIEnv* env, const char* packagePrefix) {
netty_unix_limits_JNI_OnUnLoad(env, packagePrefix);
netty_unix_errors_JNI_OnUnLoad(env, packagePrefix);
netty_unix_filedescriptor_JNI_OnUnLoad(env, packagePrefix);
@ -382,50 +382,9 @@ static void netty_kqueue_native_JNI_OnUnLoad(JNIEnv* env, const char* packagePre
netty_unix_buffer_JNI_OnUnLoad(env, packagePrefix);
netty_kqueue_bsdsocket_JNI_OnUnLoad(env, packagePrefix);
netty_kqueue_eventarray_JNI_OnUnLoad(env, packagePrefix);
}
static jint JNI_OnLoad_netty_transport_native_kqueue0(JavaVM* vm, void* reserved) {
JNIEnv* env;
if ((*vm)->GetEnv(vm, (void**) &env, NETTY_JNI_VERSION) != JNI_OK) {
return JNI_ERR;
}
char* packagePrefix = NULL;
#ifndef NETTY_BUILD_STATIC
Dl_info dlinfo;
jint status = 0;
// We need to use an address of a function that is uniquely part of this library, so choose a static
// function. See https://github.com/netty/netty/issues/4840.
if (!dladdr((void*) netty_kqueue_native_JNI_OnUnLoad, &dlinfo)) {
fprintf(stderr, "FATAL: transport-native-kqueue JNI call to dladdr failed!\n");
return JNI_ERR;
}
packagePrefix = netty_unix_util_parse_package_prefix(dlinfo.dli_fname, "netty_transport_native_kqueue", &status);
if (status == JNI_ERR) {
fprintf(stderr, "FATAL: transport-native-kqueue JNI encountered unexpected dlinfo.dli_fname: %s\n", dlinfo.dli_fname);
return JNI_ERR;
}
#endif /* NETTY_BUILD_STATIC */
jint ret = netty_kqueue_native_JNI_OnLoad(env, packagePrefix);
if (ret == JNI_ERR) {
free(packagePrefix);
staticPackagePrefix = NULL;
} else {
staticPackagePrefix = packagePrefix;
}
return ret;
}
static void JNI_OnUnload_netty_transport_native_kqueue0(JavaVM* vm, void* reserved) {
JNIEnv* env;
if ((*vm)->GetEnv(vm, (void**) &env, NETTY_JNI_VERSION) != JNI_OK) {
// Something is wrong but nothing we can do about this :(
return;
}
netty_kqueue_native_JNI_OnUnLoad(env, staticPackagePrefix);
free(staticPackagePrefix);
staticPackagePrefix = NULL;
netty_jni_util_unregister_natives(env, packagePrefix, STATICALLY_CLASSNAME);
netty_jni_util_unregister_natives(env, packagePrefix, NATIVE_CLASSNAME);
}
// We build with -fvisibility=hidden so ensure we mark everything that needs to be visible with JNIEXPORT
@ -433,20 +392,20 @@ static void JNI_OnUnload_netty_transport_native_kqueue0(JavaVM* vm, void* reserv
// Invoked by the JVM when statically linked
JNIEXPORT jint JNI_OnLoad_netty_transport_native_kqueue(JavaVM* vm, void* reserved) {
return JNI_OnLoad_netty_transport_native_kqueue0(vm, reserved);
return netty_jni_util_JNI_OnLoad(vm, reserved, "netty_transport_native_kqueue", netty_kqueue_native_JNI_OnLoad);
}
// Invoked by the JVM when statically linked
JNIEXPORT void JNI_OnUnload_netty_transport_native_kqueue(JavaVM* vm, void* reserved) {
JNI_OnUnload_netty_transport_native_kqueue0(vm, reserved);
netty_jni_util_JNI_OnUnload(vm, reserved, netty_kqueue_native_JNI_OnUnload);
}
#ifndef NETTY_BUILD_STATIC
JNIEXPORT jint JNI_OnLoad(JavaVM* vm, void* reserved) {
return JNI_OnLoad_netty_transport_native_kqueue0(vm, reserved);
return netty_jni_util_JNI_OnLoad(vm, reserved, "netty_transport_native_kqueue", netty_kqueue_native_JNI_OnLoad);
}
JNIEXPORT void JNI_OnUnload(JavaVM* vm, void* reserved) {
return JNI_OnUnload_netty_transport_native_kqueue0(vm, reserved);
netty_jni_util_JNI_OnUnload(vm, reserved, netty_kqueue_native_JNI_OnUnload);
}
#endif /* NETTY_BUILD_STATIC */

View File

@ -23,14 +23,17 @@
# LIB_NAME - the name of the native library
SRC_DIR = src/main/c
UTIL_SRC_DIR = target/netty-jni-util/src/c
JNI_INCLUDE_DIR = $(JAVA_HOME)/include
JNI_INCLUDES = -I$(JNI_INCLUDE_DIR) -I$(JNI_INCLUDE_DIR)/$(JNI_PLATFORM)
LIB = $(LIB_DIR)/$(LIB_NAME).a
CFLAGS += $(JNI_INCLUDES)
CFLAGS += $(JNI_INCLUDES) -I$(UTIL_SRC_DIR)
SRCS = $(wildcard $(SRC_DIR)/*.c)
OBJS = $(SRCS:$(SRC_DIR)/%.c=$(OBJ_DIR)/%.o)
UTIL_SRCS = $(wildcard $(UTIL_SRC_DIR)/*.c)
OBJS = $(SRCS:$(SRC_DIR)/%.c=$(OBJ_DIR)/%.o) $(UTIL_SRCS:$(UTIL_SRC_DIR)/%.c=$(OBJ_DIR)/%.o)
all: $(LIB)
@ -42,6 +45,11 @@ $(OBJ_DIR)/%.o: $(SRC_DIR)/%.c
mkdir -p $(OBJ_DIR)
$(CC) -o $@ -c $< $(CFLAGS)
$(OBJ_DIR)/%.o: $(UTIL_SRC_DIR)/%.c
mkdir -p $(OBJ_DIR)
$(CC) -o $@ -c $< $(CFLAGS)
clean:
rm -rf $(LIB_DIR) $(OBJ_DIR)

View File

@ -37,6 +37,8 @@
<exe.archiver>ar</exe.archiver>
<nativeLibName>libnetty-unix-common</nativeLibName>
<nativeIncludeDir>${project.basedir}/src/main/c</nativeIncludeDir>
<jniUtilCheckoutDir>${project.build.directory}/netty-jni-util</jniUtilCheckoutDir>
<jniUtilIncludeDir>${project.build.directory}/netty-jni-util/src/c</jniUtilIncludeDir>
<nativeJarWorkdir>${project.build.directory}/native-jar-work</nativeJarWorkdir>
<nativeObjsOnlyDir>${project.build.directory}/native-objs-only</nativeObjsOnlyDir>
<nativeLibOnlyDir>${project.build.directory}/native-lib-only</nativeLibOnlyDir>
@ -46,6 +48,30 @@
<build>
<plugins>
<!-- Download the netty-jni-util source -->
<plugin>
<artifactId>maven-scm-plugin</artifactId>
<version>1.11.2</version>
<executions>
<execution>
<id>get-netty-jni-util</id>
<phase>generate-sources</phase>
<goals>
<goal>checkout</goal>
</goals>
<configuration>
<checkoutDirectory>${jniUtilCheckoutDir}</checkoutDirectory>
<connectionType>developerConnection</connectionType>
<developerConnectionUrl>scm:git:https://github.com/netty/netty-jni-util.git</developerConnectionUrl>
<scmVersion>0.0.1</scmVersion>
<scmVersionType>tag</scmVersionType>
<skipCheckoutIfExists>true</skipCheckoutIfExists>
</configuration>
</execution>
</executions>
</plugin>
<!-- Also include c files in source jar -->
<plugin>
<groupId>org.codehaus.mojo</groupId>
@ -104,6 +130,10 @@
<zipfileset dir="${nativeIncludeDir}" />
<regexpmapper handledirsep="yes" from="^(?:[^/]+/)*([^/]+).h$" to="META-INF/native/include/\1.h" />
</copy>
<copy todir="${nativeJarWorkdir}" includeEmptyDirs="false">
<zipfileset dir="${jniUtilIncludeDir}" />
<regexpmapper handledirsep="yes" from="^(?:[^/]+/)*([^/]+).h$" to="META-INF/native/include/\1.h" />
</copy>
<jar destfile="${nativeJarFile}" manifest="${nativeJarWorkdir}/META-INF/MANIFEST.MF" basedir="${nativeJarWorkdir}" index="true" excludes="META-INF/MANIFEST.MF,META-INF/INDEX.LIST" />
<attachartifact file="${nativeJarFile}" classifier="${jni.classifier}" type="jar" />
</target>
@ -175,6 +205,10 @@
<zipfileset dir="${nativeIncludeDir}" />
<regexpmapper handledirsep="yes" from="^(?:[^/]+/)*([^/]+).h$" to="META-INF/native/include/\1.h" />
</copy>
<copy todir="${nativeJarWorkdir}" includeEmptyDirs="false">
<zipfileset dir="${jniUtilIncludeDir}" />
<regexpmapper handledirsep="yes" from="^(?:[^/]+/)*([^/]+).h$" to="META-INF/native/include/\1.h" />
</copy>
<jar destfile="${nativeJarFile}" manifest="${nativeJarWorkdir}/META-INF/MANIFEST.MF" basedir="${nativeJarWorkdir}" index="true" excludes="META-INF/MANIFEST.MF,META-INF/INDEX.LIST" />
<attachartifact file="${nativeJarFile}" classifier="${jni.classifier}" type="jar" />
</target>
@ -240,6 +274,10 @@
<zipfileset dir="${nativeIncludeDir}" />
<regexpmapper handledirsep="yes" from="^(?:[^/]+/)*([^/]+).h$" to="META-INF/native/include/\1.h" />
</copy>
<copy todir="${nativeJarWorkdir}" includeEmptyDirs="false">
<zipfileset dir="${jniUtilIncludeDir}" />
<regexpmapper handledirsep="yes" from="^(?:[^/]+/)*([^/]+).h$" to="META-INF/native/include/\1.h" />
</copy>
<jar destfile="${nativeJarFile}" manifest="${nativeJarWorkdir}/META-INF/MANIFEST.MF" basedir="${nativeJarWorkdir}" index="true" excludes="META-INF/MANIFEST.MF,META-INF/INDEX.LIST" />
<attachartifact file="${nativeJarFile}" classifier="${jni.classifier}" type="jar" />
</target>
@ -310,6 +348,10 @@
<zipfileset dir="${nativeIncludeDir}" />
<regexpmapper handledirsep="yes" from="^(?:[^/]+/)*([^/]+).h$" to="META-INF/native/include/\1.h" />
</copy>
<copy todir="${nativeJarWorkdir}" includeEmptyDirs="false">
<zipfileset dir="${nativeIncludeDir}" />
<regexpmapper handledirsep="yes" from="^(?:[^/]+/)*([^/]+).h$" to="META-INF/native/include/\1.h" />
</copy>
<jar destfile="${nativeJarFile}" manifest="${nativeJarWorkdir}/META-INF/MANIFEST.MF" basedir="${nativeJarWorkdir}" index="true" excludes="META-INF/MANIFEST.MF,META-INF/INDEX.LIST" />
<attachartifact file="${nativeJarFile}" classifier="${jni.classifier}" type="jar" />
</target>
@ -380,6 +422,10 @@
<zipfileset dir="${nativeIncludeDir}" />
<regexpmapper handledirsep="yes" from="^(?:[^/]+/)*([^/]+).h$" to="META-INF/native/include/\1.h" />
</copy>
<copy todir="${nativeJarWorkdir}" includeEmptyDirs="false">
<zipfileset dir="${jniUtilIncludeDir}" />
<regexpmapper handledirsep="yes" from="^(?:[^/]+/)*([^/]+).h$" to="META-INF/native/include/\1.h" />
</copy>
<jar destfile="${nativeJarFile}" manifest="${nativeJarWorkdir}/META-INF/MANIFEST.MF" basedir="${nativeJarWorkdir}" index="true" excludes="META-INF/MANIFEST.MF,META-INF/INDEX.LIST" />
<attachartifact file="${nativeJarFile}" classifier="${jni.classifier}" type="jar" />
</target>

View File

@ -16,6 +16,7 @@
#include "netty_unix_jni.h"
#include "netty_unix_util.h"
#include "netty_unix_buffer.h"
#include "netty_jni_util.h"
#define BUFFER_CLASSNAME "io/netty/channel/unix/Buffer"
@ -40,7 +41,7 @@ static const jint statically_referenced_fixed_method_table_size = sizeof(statica
jint netty_unix_buffer_JNI_OnLoad(JNIEnv* env, const char* packagePrefix) {
// We must register the statically referenced methods first!
if (netty_unix_util_register_natives(env,
if (netty_jni_util_register_natives(env,
packagePrefix,
BUFFER_CLASSNAME,
statically_referenced_fixed_method_table,
@ -48,9 +49,9 @@ jint netty_unix_buffer_JNI_OnLoad(JNIEnv* env, const char* packagePrefix) {
return JNI_ERR;
}
return NETTY_JNI_VERSION;
return NETTY_JNI_UTIL_JNI_VERSION;
}
void netty_unix_buffer_JNI_OnUnLoad(JNIEnv* env, const char* packagePrefix) {
netty_unix_util_unregister_natives(env, packagePrefix, BUFFER_CLASSNAME);
netty_jni_util_unregister_natives(env, packagePrefix, BUFFER_CLASSNAME);
}

View File

@ -20,6 +20,7 @@
#include "netty_unix_errors.h"
#include "netty_unix_jni.h"
#include "netty_unix_util.h"
#include "netty_jni_util.h"
#define ERRORS_CLASSNAME "io/netty/channel/unix/ErrorsStaticallyReferencedJniMethods"
@ -81,7 +82,7 @@ static char* exceptionMessage(char* msg, int error) {
}
} while (result == ERANGE);
char* combined = netty_unix_util_prepend(msg, strerrbuf);
char* combined = netty_jni_util_prepend(msg, strerrbuf);
free(strerrbuf);
return combined;
}
@ -214,7 +215,7 @@ static const jint statically_referenced_fixed_method_table_size = sizeof(statica
jint netty_unix_errors_JNI_OnLoad(JNIEnv* env, const char* packagePrefix) {
char* nettyClassName = NULL;
// We must register the statically referenced methods first!
if (netty_unix_util_register_natives(env,
if (netty_jni_util_register_natives(env,
packagePrefix,
ERRORS_CLASSNAME,
statically_referenced_fixed_method_table,
@ -222,22 +223,22 @@ jint netty_unix_errors_JNI_OnLoad(JNIEnv* env, const char* packagePrefix) {
return JNI_ERR;
}
NETTY_LOAD_CLASS(env, oomErrorClass, "java/lang/OutOfMemoryError", error);
NETTY_JNI_UTIL_LOAD_CLASS(env, oomErrorClass, "java/lang/OutOfMemoryError", error);
NETTY_LOAD_CLASS(env, runtimeExceptionClass, "java/lang/RuntimeException", error);
NETTY_JNI_UTIL_LOAD_CLASS(env, runtimeExceptionClass, "java/lang/RuntimeException", error);
NETTY_PREPEND(packagePrefix, "io/netty/channel/ChannelException", nettyClassName, error);
NETTY_LOAD_CLASS(env, channelExceptionClass, nettyClassName, error);
netty_unix_util_free_dynamic_name(&nettyClassName);
NETTY_JNI_UTIL_PREPEND(packagePrefix, "io/netty/channel/ChannelException", nettyClassName, error);
NETTY_JNI_UTIL_LOAD_CLASS(env, channelExceptionClass, nettyClassName, error);
netty_jni_util_free_dynamic_name(&nettyClassName);
NETTY_LOAD_CLASS(env, closedChannelExceptionClass, "java/nio/channels/ClosedChannelException", error);
NETTY_GET_METHOD(env, closedChannelExceptionClass, closedChannelExceptionMethodId, "<init>", "()V", error);
NETTY_JNI_UTIL_LOAD_CLASS(env, closedChannelExceptionClass, "java/nio/channels/ClosedChannelException", error);
NETTY_JNI_UTIL_GET_METHOD(env, closedChannelExceptionClass, closedChannelExceptionMethodId, "<init>", "()V", error);
NETTY_LOAD_CLASS(env, ioExceptionClass, "java/io/IOException", error);
NETTY_JNI_UTIL_LOAD_CLASS(env, ioExceptionClass, "java/io/IOException", error);
NETTY_LOAD_CLASS(env, portUnreachableExceptionClass, "java/net/PortUnreachableException", error);
NETTY_JNI_UTIL_LOAD_CLASS(env, portUnreachableExceptionClass, "java/net/PortUnreachableException", error);
return NETTY_JNI_VERSION;
return NETTY_JNI_UTIL_JNI_VERSION;
error:
free(nettyClassName);
return JNI_ERR;
@ -245,12 +246,12 @@ error:
void netty_unix_errors_JNI_OnUnLoad(JNIEnv* env, const char* packagePrefix) {
// delete global references so the GC can collect them
NETTY_UNLOAD_CLASS(env, oomErrorClass);
NETTY_UNLOAD_CLASS(env, runtimeExceptionClass);
NETTY_UNLOAD_CLASS(env, channelExceptionClass);
NETTY_UNLOAD_CLASS(env, ioExceptionClass);
NETTY_UNLOAD_CLASS(env, portUnreachableExceptionClass);
NETTY_UNLOAD_CLASS(env, closedChannelExceptionClass);
NETTY_JNI_UTIL_UNLOAD_CLASS(env, oomErrorClass);
NETTY_JNI_UTIL_UNLOAD_CLASS(env, runtimeExceptionClass);
NETTY_JNI_UTIL_UNLOAD_CLASS(env, channelExceptionClass);
NETTY_JNI_UTIL_UNLOAD_CLASS(env, ioExceptionClass);
NETTY_JNI_UTIL_UNLOAD_CLASS(env, portUnreachableExceptionClass);
NETTY_JNI_UTIL_UNLOAD_CLASS(env, closedChannelExceptionClass);
netty_unix_util_unregister_natives(env, packagePrefix, ERRORS_CLASSNAME);
netty_jni_util_unregister_natives(env, packagePrefix, ERRORS_CLASSNAME);
}

View File

@ -25,6 +25,7 @@
#include "netty_unix_filedescriptor.h"
#include "netty_unix_jni.h"
#include "netty_unix_util.h"
#include "netty_jni_util.h"
#define FILEDESCRIPTOR_CLASSNAME "io/netty/channel/unix/FileDescriptor"
@ -280,7 +281,7 @@ static const jint method_table_size = sizeof(method_table) / sizeof(method_table
jint netty_unix_filedescriptor_JNI_OnLoad(JNIEnv* env, const char* packagePrefix) {
int ret = JNI_ERR;
void* mem = NULL;
if (netty_unix_util_register_natives(env, packagePrefix, FILEDESCRIPTOR_CLASSNAME, method_table, method_table_size) != 0) {
if (netty_jni_util_register_natives(env, packagePrefix, FILEDESCRIPTOR_CLASSNAME, method_table, method_table_size) != 0) {
goto done;
}
if ((mem = malloc(1)) == NULL) {
@ -300,21 +301,21 @@ jint netty_unix_filedescriptor_JNI_OnLoad(JNIEnv* env, const char* packagePrefix
// 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.
NETTY_GET_METHOD(env, cls, posId, "position", "()I", done);
NETTY_GET_METHOD(env, cls, limitId, "limit", "()I", done);
NETTY_JNI_UTIL_GET_METHOD(env, cls, posId, "position", "()I", done);
NETTY_JNI_UTIL_GET_METHOD(env, cls, limitId, "limit", "()I", done);
// 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(...).
NETTY_TRY_GET_FIELD(env, cls, posFieldId, "position", "I");
NETTY_TRY_GET_FIELD(env, cls, limitFieldId, "limit", "I");
NETTY_JNI_UTIL_TRY_GET_FIELD(env, cls, posFieldId, "position", "I");
NETTY_JNI_UTIL_TRY_GET_FIELD(env, cls, limitFieldId, "limit", "I");
ret = NETTY_JNI_VERSION;
ret = NETTY_JNI_UTIL_JNI_VERSION;
done:
free(mem);
return ret;
}
void netty_unix_filedescriptor_JNI_OnUnLoad(JNIEnv* env, const char* packagePrefix) {
netty_unix_util_unregister_natives(env, packagePrefix, FILEDESCRIPTOR_CLASSNAME);
netty_jni_util_unregister_natives(env, packagePrefix, FILEDESCRIPTOR_CLASSNAME);
}

View File

@ -18,8 +18,4 @@
#include <jni.h>
#ifndef NETTY_JNI_VERSION
#define NETTY_JNI_VERSION JNI_VERSION_1_6
#endif
#endif /* NETTY_UNIX_JNI_H_ */

View File

@ -20,6 +20,7 @@
#include "netty_unix_jni.h"
#include "netty_unix_limits.h"
#include "netty_unix_util.h"
#include "netty_jni_util.h"
#define LIMITS_CLASSNAME "io/netty/channel/unix/LimitsStaticallyReferencedJniMethods"
@ -70,7 +71,7 @@ static const jint statically_referenced_fixed_method_table_size = sizeof(statica
jint netty_unix_limits_JNI_OnLoad(JNIEnv* env, const char* packagePrefix) {
// We must register the statically referenced methods first!
if (netty_unix_util_register_natives(env,
if (netty_jni_util_register_natives(env,
packagePrefix,
LIMITS_CLASSNAME,
statically_referenced_fixed_method_table,
@ -78,9 +79,9 @@ jint netty_unix_limits_JNI_OnLoad(JNIEnv* env, const char* packagePrefix) {
return JNI_ERR;
}
return NETTY_JNI_VERSION;
return NETTY_JNI_UTIL_JNI_VERSION;
}
void netty_unix_limits_JNI_OnUnLoad(JNIEnv* env, const char* packagePrefix) {
netty_unix_util_unregister_natives(env, packagePrefix, LIMITS_CLASSNAME);
netty_jni_util_unregister_natives(env, packagePrefix, LIMITS_CLASSNAME);
}

View File

@ -30,6 +30,7 @@
#include "netty_unix_jni.h"
#include "netty_unix_socket.h"
#include "netty_unix_util.h"
#include "netty_jni_util.h"
#define SOCKET_CLASSNAME "io/netty/channel/unix/Socket"
// Define SO_REUSEPORT if not found to fix build issues.
@ -1030,23 +1031,23 @@ static JNINativeMethod* createDynamicMethodsTable(const char* packagePrefix) {
memcpy(dynamicMethods, fixed_method_table, sizeof(fixed_method_table));
JNINativeMethod* dynamicMethod = &dynamicMethods[fixed_method_table_size];
NETTY_PREPEND(packagePrefix, "io/netty/channel/unix/DatagramSocketAddress;", dynamicTypeName, error);
NETTY_PREPEND("(ILjava/nio/ByteBuffer;II)L", dynamicTypeName, dynamicMethod->signature, error);
NETTY_JNI_UTIL_PREPEND(packagePrefix, "io/netty/channel/unix/DatagramSocketAddress;", dynamicTypeName, error);
NETTY_JNI_UTIL_PREPEND("(ILjava/nio/ByteBuffer;II)L", dynamicTypeName, dynamicMethod->signature, error);
dynamicMethod->name = "recvFrom";
dynamicMethod->fnPtr = (void *) netty_unix_socket_recvFrom;
netty_unix_util_free_dynamic_name(&dynamicTypeName);
netty_jni_util_free_dynamic_name(&dynamicTypeName);
++dynamicMethod;
NETTY_PREPEND(packagePrefix, "io/netty/channel/unix/DatagramSocketAddress;", dynamicTypeName, error);
NETTY_PREPEND("(IJII)L", dynamicTypeName, dynamicMethod->signature, error);
NETTY_JNI_UTIL_PREPEND(packagePrefix, "io/netty/channel/unix/DatagramSocketAddress;", dynamicTypeName, error);
NETTY_JNI_UTIL_PREPEND("(IJII)L", dynamicTypeName, dynamicMethod->signature, error);
dynamicMethod->name = "recvFromAddress";
dynamicMethod->fnPtr = (void *) netty_unix_socket_recvFromAddress;
netty_unix_util_free_dynamic_name(&dynamicTypeName);
netty_jni_util_free_dynamic_name(&dynamicTypeName);
return dynamicMethods;
error:
free(dynamicTypeName);
netty_unix_util_free_dynamic_methods_table(dynamicMethods, fixed_method_table_size, dynamicMethodsTableSize());
netty_jni_util_free_dynamic_methods_table(dynamicMethods, fixed_method_table_size, dynamicMethodsTableSize());
return NULL;
}
@ -1060,7 +1061,7 @@ jint netty_unix_socket_JNI_OnLoad(JNIEnv* env, const char* packagePrefix) {
if (dynamicMethods == NULL) {
goto done;
}
if (netty_unix_util_register_natives(env,
if (netty_jni_util_register_natives(env,
packagePrefix,
SOCKET_CLASSNAME,
dynamicMethods,
@ -1068,17 +1069,17 @@ jint netty_unix_socket_JNI_OnLoad(JNIEnv* env, const char* packagePrefix) {
goto done;
}
NETTY_PREPEND(packagePrefix, "io/netty/channel/unix/DatagramSocketAddress", nettyClassName, done);
NETTY_LOAD_CLASS(env, datagramSocketAddressClass, nettyClassName, done);
NETTY_JNI_UTIL_PREPEND(packagePrefix, "io/netty/channel/unix/DatagramSocketAddress", nettyClassName, done);
NETTY_JNI_UTIL_LOAD_CLASS(env, datagramSocketAddressClass, nettyClassName, done);
// Respect shading...
char parameters[1024] = {0};
snprintf(parameters, sizeof(parameters), "([BIIIL%s;)V", nettyClassName);
netty_unix_util_free_dynamic_name(&nettyClassName);
NETTY_GET_METHOD(env, datagramSocketAddressClass, datagramSocketAddrMethodId, "<init>", parameters, done);
netty_jni_util_free_dynamic_name(&nettyClassName);
NETTY_JNI_UTIL_GET_METHOD(env, datagramSocketAddressClass, datagramSocketAddrMethodId, "<init>", parameters, done);
NETTY_LOAD_CLASS(env, inetSocketAddressClass, "java/net/InetSocketAddress", done);
NETTY_GET_METHOD(env, inetSocketAddressClass, inetSocketAddrMethodId, "<init>", "(Ljava/lang/String;I)V", done);
NETTY_JNI_UTIL_LOAD_CLASS(env, inetSocketAddressClass, "java/net/InetSocketAddress", done);
NETTY_JNI_UTIL_GET_METHOD(env, inetSocketAddressClass, inetSocketAddrMethodId, "<init>", "(Ljava/lang/String;I)V", done);
if ((mem = malloc(1)) == NULL) {
goto done;
@ -1092,17 +1093,17 @@ jint netty_unix_socket_JNI_OnLoad(JNIEnv* env, const char* packagePrefix) {
goto done;
}
ret = NETTY_JNI_VERSION;
ret = NETTY_JNI_UTIL_JNI_VERSION;
done:
netty_unix_util_free_dynamic_methods_table(dynamicMethods, fixed_method_table_size, dynamicMethodsTableSize());
netty_jni_util_free_dynamic_methods_table(dynamicMethods, fixed_method_table_size, dynamicMethodsTableSize());
free(nettyClassName);
free(mem);
return ret;
}
void netty_unix_socket_JNI_OnUnLoad(JNIEnv* env, const char* packagePrefix) {
NETTY_UNLOAD_CLASS(env, datagramSocketAddressClass);
NETTY_UNLOAD_CLASS(env, inetSocketAddressClass);
NETTY_JNI_UTIL_UNLOAD_CLASS(env, datagramSocketAddressClass);
NETTY_JNI_UTIL_UNLOAD_CLASS(env, inetSocketAddressClass);
netty_unix_util_unregister_natives(env, packagePrefix, SOCKET_CLASSNAME);
netty_jni_util_unregister_natives(env, packagePrefix, SOCKET_CLASSNAME);
}

View File

@ -28,102 +28,6 @@ static const uint64_t NETTY_BILLION = 1000000000L;
#endif /* NETTY_USE_MACH_INSTEAD_OF_CLOCK */
char* netty_unix_util_prepend(const char* prefix, const char* str) {
if (str == NULL) {
// If str is NULL we should just return NULL as passing NULL to strlen is undefined behavior.
return NULL;
}
char* result = NULL;
if (prefix == NULL) {
if ((result = (char*) malloc(sizeof(char) * (strlen(str) + 1))) == NULL) {
return NULL;
}
strcpy(result, str);
return result;
}
if ((result = (char*) malloc(sizeof(char) * (strlen(prefix) + strlen(str) + 1))) == NULL) {
return NULL;
}
strcpy(result, prefix);
strcat(result, str);
return result;
}
char* netty_unix_util_rstrstr(char* s1rbegin, const char* s1rend, const char* s2) {
if (s1rbegin == NULL || s1rend == NULL || s2 == NULL) {
// Return NULL if any of the parameters is NULL to not risk a segfault
return NULL;
}
size_t s2len = strlen(s2);
char *s = s1rbegin - s2len;
for (; s >= s1rend; --s) {
if (strncmp(s, s2, s2len) == 0) {
return s;
}
}
return NULL;
}
static char* netty_unix_util_strstr_last(const char* haystack, const char* needle) {
if (haystack == NULL || needle == NULL) {
// calling strstr with NULL is undefined behavior. Better just return NULL and not risk a crash.
return NULL;
}
char* prevptr = NULL;
char* ptr = (char*) haystack;
while ((ptr = strstr(ptr, needle)) != NULL) {
// Just store the ptr and continue searching.
prevptr = ptr;
++ptr;
}
return prevptr;
}
char* netty_unix_util_parse_package_prefix(const char* libraryPathName, const char* libraryName, jint* status) {
char* packageNameEnd = netty_unix_util_strstr_last(libraryPathName, libraryName);
if (packageNameEnd == NULL) {
*status = JNI_ERR;
return NULL;
}
char* packagePrefix = netty_unix_util_rstrstr(packageNameEnd, libraryPathName, "lib");
if (packagePrefix == NULL) {
*status = JNI_ERR;
return NULL;
}
packagePrefix += 3;
if (packagePrefix == packageNameEnd) {
return NULL;
}
// packagePrefix length is > 0
// Make a copy so we can modify the value without impacting libraryPathName.
size_t packagePrefixLen = packageNameEnd - packagePrefix;
if ((packagePrefix = strndup(packagePrefix, packagePrefixLen)) == NULL) {
*status = JNI_ERR;
return NULL;
}
// Make sure the packagePrefix is in the correct format for the JNI functions it will be used with.
char* temp = packagePrefix;
packageNameEnd = packagePrefix + packagePrefixLen;
// Package names must be sanitized, in JNI packages names are separated by '/' characters.
for (; temp != packageNameEnd; ++temp) {
if (*temp == '_') {
*temp = '/';
}
}
// Make sure packagePrefix is terminated with the '/' JNI package separator.
if(*(--temp) != '/') {
temp = packagePrefix;
if ((packagePrefix = netty_unix_util_prepend(packagePrefix, "/")) == NULL) {
*status = JNI_ERR;
}
free(temp);
}
return packagePrefix;
}
// util methods
uint64_t netty_unix_util_timespec_elapsed_ns(const struct timespec* begin, const struct timespec* end) {
return NETTY_BILLION * (end->tv_sec - begin->tv_sec) + (end->tv_nsec - begin->tv_nsec);
@ -206,52 +110,3 @@ jboolean netty_unix_util_initialize_wait_clock(clockid_t* clockId) {
return JNI_FALSE;
}
jint netty_unix_util_register_natives(JNIEnv* env, const char* packagePrefix, const char* className, const JNINativeMethod* methods, jint numMethods) {
char* nettyClassName = NULL;
int ret = JNI_ERR;
NETTY_PREPEND(packagePrefix, className, nettyClassName, done);
jclass nativeCls = (*env)->FindClass(env, nettyClassName);
if (nativeCls == NULL) {
goto done;
}
ret = (*env)->RegisterNatives(env, nativeCls, methods, numMethods);
done:
free(nettyClassName);
return ret;
}
jint netty_unix_util_unregister_natives(JNIEnv* env, const char* packagePrefix, const char* className) {
char* nettyClassName = NULL;
int ret = JNI_ERR;
NETTY_PREPEND(packagePrefix, className, nettyClassName, done);
jclass nativeCls = (*env)->FindClass(env, nettyClassName);
if (nativeCls == NULL) {
goto done;
}
ret = (*env)->UnregisterNatives(env, nativeCls);
done:
free(nettyClassName);
return ret;
}
void netty_unix_util_free_dynamic_methods_table(JNINativeMethod* dynamicMethods, jint fixedMethodTableSize, jint fullMethodTableSize) {
if (dynamicMethods != NULL) {
jint i = fixedMethodTableSize;
for (; i < fullMethodTableSize; ++i) {
free(dynamicMethods[i].signature);
}
free(dynamicMethods);
}
}
void netty_unix_util_free_dynamic_name(char** dynamicName) {
if (dynamicName != NULL && *dynamicName != NULL) {
free(*dynamicName);
*dynamicName = NULL;
}
}

View File

@ -20,6 +20,8 @@
#include <jni.h>
#include <stdint.h>
#include <time.h>
#include "netty_jni_util.h"
#if defined(__MACH__) && !defined(CLOCK_REALTIME)
#define NETTY_USE_MACH_INSTEAD_OF_CLOCK
@ -36,87 +38,6 @@ typedef int clockid_t;
#endif /* __MACH__ */
#define NETTY_BEGIN_MACRO if (1) {
#define NETTY_END_MACRO } else (void)(0)
#define NETTY_FIND_CLASS(E, C, N, R) \
NETTY_BEGIN_MACRO \
C = (*(E))->FindClass((E), N); \
if (C == NULL) { \
(*(E))->ExceptionClear((E)); \
goto R; \
} \
NETTY_END_MACRO
#define NETTY_LOAD_CLASS(E, C, N, R) \
NETTY_BEGIN_MACRO \
jclass _##C = (*(E))->FindClass((E), N); \
if (_##C == NULL) { \
(*(E))->ExceptionClear((E)); \
goto R; \
} \
C = (*(E))->NewGlobalRef((E), _##C); \
(*(E))->DeleteLocalRef((E), _##C); \
if (C == NULL) { \
goto R; \
} \
NETTY_END_MACRO
#define NETTY_UNLOAD_CLASS(E, C) \
NETTY_BEGIN_MACRO \
if (C != NULL) { \
(*(E))->DeleteGlobalRef((E), (C)); \
C = NULL; \
} \
NETTY_END_MACRO
#define NETTY_GET_METHOD(E, C, M, N, S, R) \
NETTY_BEGIN_MACRO \
M = (*(E))->GetMethodID((E), C, N, S); \
if (M == NULL) { \
goto R; \
} \
NETTY_END_MACRO
#define NETTY_GET_FIELD(E, C, F, N, S, R) \
NETTY_BEGIN_MACRO \
F = (*(E))->GetFieldID((E), C, N, S); \
if (F == NULL) { \
goto R; \
} \
NETTY_END_MACRO
#define NETTY_TRY_GET_FIELD(E, C, F, N, S) \
NETTY_BEGIN_MACRO \
F = (*(E))->GetFieldID((E), C, N, S); \
if (F == NULL) { \
(*(E))->ExceptionClear((E)); \
} \
NETTY_END_MACRO
#define NETTY_PREPEND(P, S, N, R) \
NETTY_BEGIN_MACRO \
if ((N = netty_unix_util_prepend(P, S)) == NULL) { \
goto R; \
} \
NETTY_END_MACRO
/**
* Return a new string (caller must free this string) which is equivalent to <pre>prefix + str</pre>.
*
* Caller must free the return value!
*/
char* netty_unix_util_prepend(const char* prefix, const char* str);
char* netty_unix_util_rstrstr(char* s1rbegin, const char* s1rend, const char* s2);
/**
* The expected format of the library name is "lib<>$libraryName" where the <> portion is what we will return.
* If status != JNI_ERR then the caller MUST call free on the return value.
*/
char* netty_unix_util_parse_package_prefix(const char* libraryPathName, const char* libraryName, jint* status);
/**
* Get a clock which can be used to measure execution time.
*
@ -145,13 +66,4 @@ uint64_t netty_unix_util_timespec_elapsed_ns(const struct timespec* begin, const
*/
jboolean netty_unix_util_timespec_subtract_ns(struct timespec* ts, uint64_t nanos);
/**
* Return type is as defined in https://docs.oracle.com/javase/7/docs/technotes/guides/jni/spec/functions.html#wp5833.
*/
jint netty_unix_util_register_natives(JNIEnv* env, const char* packagePrefix, const char* className, const JNINativeMethod* methods, jint numMethods);
jint netty_unix_util_unregister_natives(JNIEnv* env, const char* packagePrefix, const char* className);
void netty_unix_util_free_dynamic_methods_table(JNINativeMethod* dynamicMethods, jint fixedMethodTableSize, jint fullMethodTableSize);
void netty_unix_util_free_dynamic_name(char** dynamicName);
#endif /* NETTY_UNIX_UTIL_H_ */