Native Transport Netty Class Package Prefix
Motivation: transport-native-epoll finds java classes from JNI using fully qualified class names. If a shaded version of Netty is used then these lookups will fail. Modifications: - Allow a prefix to be appended to Netty class names in JNI code. Result: JNI code can be used with shaded version of Netty.
This commit is contained in:
parent
bf24ffd335
commit
dea337b4cf
@ -38,6 +38,7 @@
|
||||
#include "netty_unix_filedescriptor.h"
|
||||
#include "netty_unix_socket.h"
|
||||
#include "netty_unix_errors.h"
|
||||
#include "netty_unix_util.h"
|
||||
|
||||
// TCP_NOTSENT_LOWAT is defined in linux 3.12. We define this here so older kernels can compile.
|
||||
#ifndef TCP_NOTSENT_LOWAT
|
||||
@ -84,6 +85,9 @@ jfieldID packetScopeIdFieldId = NULL;
|
||||
jfieldID packetPortFieldId = NULL;
|
||||
jfieldID packetMemoryAddressFieldId = NULL;
|
||||
jfieldID packetCountFieldId = NULL;
|
||||
static jstring nettyPackagePrefixJString = NULL;
|
||||
static const char* nettyPackagePrefix = NULL;
|
||||
static char* nettyClassName = NULL;
|
||||
|
||||
// util methods
|
||||
static int getSysctlValue(const char * property, int* returnValue) {
|
||||
@ -116,17 +120,35 @@ jint JNI_OnLoad(JavaVM* vm, void* reserved) {
|
||||
if ((*vm)->GetEnv(vm, (void**) &env, JNI_VERSION_1_6) != JNI_OK) {
|
||||
return JNI_ERR;
|
||||
} else {
|
||||
if (netty_unix_errors_JNI_OnLoad(env) == JNI_ERR) {
|
||||
// Load the prefix to use when looking for Netty classes
|
||||
jclass systemCls = (*env)->FindClass(env, "java/lang/System");
|
||||
if (systemCls == NULL) {
|
||||
return JNI_ERR;
|
||||
}
|
||||
if (netty_unix_filedescriptor_JNI_OnLoad(env) == JNI_ERR) {
|
||||
jmethodID getPropertyMethod = (*env)->GetStaticMethodID(env, systemCls, "getProperty", "(Ljava/lang/String;)Ljava/lang/String;");
|
||||
if (getPropertyMethod == NULL) {
|
||||
return JNI_ERR;
|
||||
}
|
||||
if (netty_unix_socket_JNI_OnLoad(env) == 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;
|
||||
}
|
||||
|
||||
jclass fileRegionCls = (*env)->FindClass(env, "io/netty/channel/DefaultFileRegion");
|
||||
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;
|
||||
@ -164,7 +186,10 @@ jint JNI_OnLoad(JavaVM* vm, void* reserved) {
|
||||
return JNI_ERR;
|
||||
}
|
||||
|
||||
jclass nativeDatagramPacketCls = (*env)->FindClass(env, "io/netty/channel/epoll/NativeDatagramPacketArray$NativeDatagramPacket");
|
||||
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;
|
||||
@ -197,6 +222,12 @@ jint JNI_OnLoad(JavaVM* vm, void* reserved) {
|
||||
return JNI_ERR;
|
||||
}
|
||||
|
||||
if (nettyPackagePrefixJString != NULL) {
|
||||
(*env)->ReleaseStringUTFChars(env, nettyPackagePrefixJString, nettyPackagePrefix);
|
||||
nettyPackagePrefix = NULL;
|
||||
nettyPackagePrefixJString = NULL;
|
||||
}
|
||||
|
||||
return JNI_VERSION_1_6;
|
||||
}
|
||||
}
|
||||
@ -208,6 +239,15 @@ void JNI_OnUnload(JavaVM* vm, void* reserved) {
|
||||
return;
|
||||
} else {
|
||||
// delete global references so the GC can collect them
|
||||
if (nettyPackagePrefixJString != NULL) {
|
||||
(*env)->ReleaseStringUTFChars(env, nettyPackagePrefixJString, nettyPackagePrefix);
|
||||
nettyPackagePrefix = NULL;
|
||||
nettyPackagePrefixJString = NULL;
|
||||
}
|
||||
if (nettyClassName != NULL) {
|
||||
free(nettyClassName);
|
||||
nettyClassName = NULL;
|
||||
}
|
||||
netty_unix_errors_JNI_OnUnLoad(env);
|
||||
netty_unix_filedescriptor_JNI_OnUnLoad(env);
|
||||
netty_unix_socket_JNI_OnUnLoad(env);
|
||||
|
@ -17,6 +17,7 @@
|
||||
#include <stdlib.h>
|
||||
#include <errno.h>
|
||||
#include "netty_unix_errors.h"
|
||||
#include "netty_unix_util.h"
|
||||
#include "io_netty_channel_unix_Errors.h"
|
||||
|
||||
static jclass runtimeExceptionClass = NULL;
|
||||
@ -24,22 +25,14 @@ static jclass channelExceptionClass = NULL;
|
||||
static jclass ioExceptionClass = NULL;
|
||||
static jclass closedChannelExceptionClass = NULL;
|
||||
static jmethodID closedChannelExceptionMethodId = NULL;
|
||||
static char* nettyClassName = NULL;
|
||||
|
||||
/** Notice: every usage of exceptionMessage needs to release the allocated memory for the sequence of char */
|
||||
static char* exceptionMessage(char* msg, int error) {
|
||||
if (error < 0) {
|
||||
// some functions return negative values
|
||||
// and it's hard to keep track of when to send -error and when not
|
||||
// this will just take care when things are forgotten
|
||||
// what would generate a proper error
|
||||
error = error * -1;
|
||||
}
|
||||
//strerror is returning a constant, so no need to free anything coming from strerror
|
||||
char* err = strerror(error);
|
||||
char* result = malloc(strlen(msg) + strlen(err) + 1);
|
||||
strcpy(result, msg);
|
||||
strcat(result, err);
|
||||
return result;
|
||||
// strerror is returning a constant, so no need to free anything coming from strerror
|
||||
// error may be negative because some functions return negative values. we should make sure it is always
|
||||
// positive when passing to standard library functions.
|
||||
return netty_unix_util_prepend(msg, strerror(error < 0 ? -error : error));
|
||||
}
|
||||
|
||||
// Exported C methods
|
||||
@ -79,7 +72,7 @@ void netty_unix_errors_throwOutOfMemoryError(JNIEnv* env) {
|
||||
(*env)->ThrowNew(env, exceptionClass, "");
|
||||
}
|
||||
|
||||
jint netty_unix_errors_JNI_OnLoad(JNIEnv* env) {
|
||||
jint netty_unix_errors_JNI_OnLoad(JNIEnv* env, const char* nettyPackagePrefix) {
|
||||
jclass localRuntimeExceptionClass = (*env)->FindClass(env, "java/lang/RuntimeException");
|
||||
if (localRuntimeExceptionClass == NULL) {
|
||||
// pending exception...
|
||||
@ -92,7 +85,10 @@ jint netty_unix_errors_JNI_OnLoad(JNIEnv* env) {
|
||||
return JNI_ERR;
|
||||
}
|
||||
|
||||
jclass localChannelExceptionClass = (*env)->FindClass(env, "io/netty/channel/ChannelException");
|
||||
nettyClassName = netty_unix_util_prepend(nettyPackagePrefix, "io/netty/channel/ChannelException");
|
||||
jclass localChannelExceptionClass = (*env)->FindClass(env, nettyClassName);
|
||||
free(nettyClassName);
|
||||
nettyClassName = NULL;
|
||||
if (localChannelExceptionClass == NULL) {
|
||||
// pending exception...
|
||||
return JNI_ERR;
|
||||
@ -139,6 +135,10 @@ jint netty_unix_errors_JNI_OnLoad(JNIEnv* env) {
|
||||
|
||||
void netty_unix_errors_JNI_OnUnLoad(JNIEnv* env) {
|
||||
// delete global references so the GC can collect them
|
||||
if (nettyClassName != NULL) {
|
||||
free(nettyClassName);
|
||||
nettyClassName = NULL;
|
||||
}
|
||||
if (runtimeExceptionClass != NULL) {
|
||||
(*env)->DeleteGlobalRef(env, runtimeExceptionClass);
|
||||
runtimeExceptionClass = NULL;
|
||||
|
@ -74,7 +74,7 @@ static jint _read(JNIEnv* env, jclass clazz, jint fd, void* buffer, jint pos, ji
|
||||
return (jint) res;
|
||||
}
|
||||
|
||||
jint netty_unix_filedescriptor_JNI_OnLoad(JNIEnv* env) {
|
||||
jint netty_unix_filedescriptor_JNI_OnLoad(JNIEnv* env, const char* nettyPackagePrefix) {
|
||||
void* mem = malloc(1);
|
||||
if (mem == NULL) {
|
||||
netty_unix_errors_throwOutOfMemoryError(env);
|
||||
|
@ -26,6 +26,7 @@
|
||||
|
||||
#include "netty_unix_errors.h"
|
||||
#include "netty_unix_socket.h"
|
||||
#include "netty_unix_util.h"
|
||||
#include "io_netty_channel_unix_Socket.h"
|
||||
|
||||
static jclass datagramSocketAddressClass = NULL;
|
||||
@ -35,6 +36,7 @@ static jclass inetSocketAddressClass = NULL;
|
||||
static jclass netUtilClass = NULL;
|
||||
static jmethodID netUtilClassIpv4PreferredMethodId = NULL;
|
||||
static int socketType;
|
||||
static char* nettyClassName = NULL;
|
||||
static const char* ip4prefix = "::ffff:";
|
||||
|
||||
// Optional external methods
|
||||
@ -301,8 +303,11 @@ int netty_unix_socket_setOption(JNIEnv* env, jint fd, int level, int optname, co
|
||||
return rc;
|
||||
}
|
||||
|
||||
jint netty_unix_socket_JNI_OnLoad(JNIEnv* env) {
|
||||
jclass localDatagramSocketAddressClass = (*env)->FindClass(env, "io/netty/channel/unix/DatagramSocketAddress");
|
||||
jint netty_unix_socket_JNI_OnLoad(JNIEnv* env, const char* nettyPackagePrefix) {
|
||||
nettyClassName = netty_unix_util_prepend(nettyPackagePrefix, "io/netty/channel/unix/DatagramSocketAddress");
|
||||
jclass localDatagramSocketAddressClass = (*env)->FindClass(env, nettyClassName);
|
||||
free(nettyClassName);
|
||||
nettyClassName = NULL;
|
||||
if (localDatagramSocketAddressClass == NULL) {
|
||||
// pending exception...
|
||||
return JNI_ERR;
|
||||
@ -334,7 +339,10 @@ jint netty_unix_socket_JNI_OnLoad(JNIEnv* env) {
|
||||
netty_unix_errors_throwRuntimeException(env, "failed to get method ID: InetSocketAddress.<init>(String, int)");
|
||||
return JNI_ERR;
|
||||
}
|
||||
jclass localNetUtilClass = (*env)->FindClass(env, "io/netty/util/NetUtil" );
|
||||
nettyClassName = netty_unix_util_prepend(nettyPackagePrefix, "io/netty/util/NetUtil");
|
||||
jclass localNetUtilClass = (*env)->FindClass(env, nettyClassName);
|
||||
free(nettyClassName);
|
||||
nettyClassName = NULL;
|
||||
if (localNetUtilClass == NULL) {
|
||||
// pending exception...
|
||||
return JNI_ERR;
|
||||
@ -376,6 +384,10 @@ jint netty_unix_socket_JNI_OnLoad(JNIEnv* env) {
|
||||
}
|
||||
|
||||
void netty_unix_socket_JNI_OnUnLoad(JNIEnv* env) {
|
||||
if (nettyClassName != NULL) {
|
||||
free(nettyClassName);
|
||||
nettyClassName = NULL;
|
||||
}
|
||||
if (datagramSocketAddressClass != NULL) {
|
||||
(*env)->DeleteGlobalRef(env, datagramSocketAddressClass);
|
||||
datagramSocketAddressClass = NULL;
|
||||
|
@ -27,7 +27,7 @@ void netty_unix_errors_throwClosedChannelException(JNIEnv* env);
|
||||
void netty_unix_errors_throwOutOfMemoryError(JNIEnv* env);
|
||||
|
||||
// JNI initialization hooks. Users of this file are responsible for calling these in the JNI_OnLoad and JNI_OnUnload methods.
|
||||
jint netty_unix_errors_JNI_OnLoad(JNIEnv* env);
|
||||
jint netty_unix_errors_JNI_OnLoad(JNIEnv* env, const char* nettyPackagePrefix);
|
||||
void netty_unix_errors_JNI_OnUnLoad(JNIEnv* env);
|
||||
|
||||
#endif /* NETTY_UNIX_ERRORS_H_ */
|
||||
|
@ -19,7 +19,7 @@
|
||||
#include <jni.h>
|
||||
|
||||
// JNI initialization hooks. Users of this file are responsible for calling these in the JNI_OnLoad and JNI_OnUnload methods.
|
||||
jint netty_unix_filedescriptor_JNI_OnLoad(JNIEnv* env);
|
||||
jint netty_unix_filedescriptor_JNI_OnLoad(JNIEnv* env, const char* nettyPackagePrefix);
|
||||
void netty_unix_filedescriptor_JNI_OnUnLoad(JNIEnv* env);
|
||||
|
||||
#endif /* NETTY_UNIX_FILEDESCRIPTOR_H_ */
|
||||
|
@ -25,7 +25,7 @@ int netty_unix_socket_getOption(JNIEnv* env, jint fd, int level, int optname, vo
|
||||
int netty_unix_socket_setOption(JNIEnv* env, jint fd, int level, int optname, const void* optval, socklen_t len);
|
||||
|
||||
// JNI initialization hooks. Users of this file are responsible for calling these in the JNI_OnLoad and JNI_OnUnload methods.
|
||||
jint netty_unix_socket_JNI_OnLoad(JNIEnv* env);
|
||||
jint netty_unix_socket_JNI_OnLoad(JNIEnv* env, const char* nettyPackagePrefix);
|
||||
void netty_unix_socket_JNI_OnUnLoad(JNIEnv* env);
|
||||
|
||||
#endif /* NETTY_UNIX_SOCKET_H_ */
|
||||
|
30
transport-native-epoll/src/main/c/netty_unix_util.c
Normal file
30
transport-native-epoll/src/main/c/netty_unix_util.c
Normal file
@ -0,0 +1,30 @@
|
||||
/*
|
||||
* Copyright 2016 The Netty Project
|
||||
*
|
||||
* The Netty Project licenses this file to you under the Apache License,
|
||||
* version 2.0 (the "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at:
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include "netty_unix_util.h"
|
||||
|
||||
char* netty_unix_util_prepend(const char* prefix, const char* str) {
|
||||
if (prefix == NULL) {
|
||||
char* result = (char*) malloc(sizeof(char) * (strlen(str) + 1));
|
||||
strcpy(result, str);
|
||||
return result;
|
||||
}
|
||||
char* result = (char*) malloc(sizeof(char) * (strlen(prefix) + strlen(str) + 1));
|
||||
strcpy(result, prefix);
|
||||
strcat(result, str);
|
||||
return result;
|
||||
}
|
27
transport-native-epoll/src/main/c/netty_unix_util.h
Normal file
27
transport-native-epoll/src/main/c/netty_unix_util.h
Normal file
@ -0,0 +1,27 @@
|
||||
/*
|
||||
* Copyright 2016 The Netty Project
|
||||
*
|
||||
* The Netty Project licenses this file to you under the Apache License,
|
||||
* version 2.0 (the "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at:
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
#ifndef NETTY_UNIX_UTIL_H_
|
||||
#define NETTY_UNIX_UTIL_H_
|
||||
|
||||
/**
|
||||
* 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);
|
||||
|
||||
#endif /* NETTY_UNIX_UTIL_H_ */
|
Loading…
Reference in New Issue
Block a user