diff --git a/transport-native-epoll/src/main/c/io_netty_channel_epoll_Native.c b/transport-native-epoll/src/main/c/io_netty_channel_epoll_Native.c index b15450d346..903634ec7e 100644 --- a/transport-native-epoll/src/main/c/io_netty_channel_epoll_Native.c +++ b/transport-native-epoll/src/main/c/io_netty_channel_epoll_Native.c @@ -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); diff --git a/transport-native-epoll/src/main/c/io_netty_channel_unix_Errors.c b/transport-native-epoll/src/main/c/io_netty_channel_unix_Errors.c index 30df59b11d..0a4ff6b88e 100644 --- a/transport-native-epoll/src/main/c/io_netty_channel_unix_Errors.c +++ b/transport-native-epoll/src/main/c/io_netty_channel_unix_Errors.c @@ -17,6 +17,7 @@ #include #include #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; diff --git a/transport-native-epoll/src/main/c/io_netty_channel_unix_FileDescriptor.c b/transport-native-epoll/src/main/c/io_netty_channel_unix_FileDescriptor.c index f8859f7b00..a8c21a70ca 100644 --- a/transport-native-epoll/src/main/c/io_netty_channel_unix_FileDescriptor.c +++ b/transport-native-epoll/src/main/c/io_netty_channel_unix_FileDescriptor.c @@ -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); diff --git a/transport-native-epoll/src/main/c/io_netty_channel_unix_Socket.c b/transport-native-epoll/src/main/c/io_netty_channel_unix_Socket.c index 25bf6d5915..8b05e19852 100644 --- a/transport-native-epoll/src/main/c/io_netty_channel_unix_Socket.c +++ b/transport-native-epoll/src/main/c/io_netty_channel_unix_Socket.c @@ -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.(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; diff --git a/transport-native-epoll/src/main/c/netty_unix_errors.h b/transport-native-epoll/src/main/c/netty_unix_errors.h index e23f383f0b..1637b83459 100644 --- a/transport-native-epoll/src/main/c/netty_unix_errors.h +++ b/transport-native-epoll/src/main/c/netty_unix_errors.h @@ -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_ */ diff --git a/transport-native-epoll/src/main/c/netty_unix_filedescriptor.h b/transport-native-epoll/src/main/c/netty_unix_filedescriptor.h index f5311168cb..221ce181aa 100644 --- a/transport-native-epoll/src/main/c/netty_unix_filedescriptor.h +++ b/transport-native-epoll/src/main/c/netty_unix_filedescriptor.h @@ -19,7 +19,7 @@ #include // 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_ */ diff --git a/transport-native-epoll/src/main/c/netty_unix_socket.h b/transport-native-epoll/src/main/c/netty_unix_socket.h index 8a8c1ab652..eb5552cae2 100644 --- a/transport-native-epoll/src/main/c/netty_unix_socket.h +++ b/transport-native-epoll/src/main/c/netty_unix_socket.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_ */ diff --git a/transport-native-epoll/src/main/c/netty_unix_util.c b/transport-native-epoll/src/main/c/netty_unix_util.c new file mode 100644 index 0000000000..6662271342 --- /dev/null +++ b/transport-native-epoll/src/main/c/netty_unix_util.c @@ -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 +#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; +} diff --git a/transport-native-epoll/src/main/c/netty_unix_util.h b/transport-native-epoll/src/main/c/netty_unix_util.h new file mode 100644 index 0000000000..3ab0aa549c --- /dev/null +++ b/transport-native-epoll/src/main/c/netty_unix_util.h @@ -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
prefix + str
. + * + * Caller must free the return value! + */ +char* netty_unix_util_prepend(const char* prefix, const char* str); + +#endif /* NETTY_UNIX_UTIL_H_ */