diff --git a/transport-native-epoll/src/main/c/netty_epoll_linuxsocket.c b/transport-native-epoll/src/main/c/netty_epoll_linuxsocket.c index 2d24132be5..3bb7b2010f 100644 --- a/transport-native-epoll/src/main/c/netty_epoll_linuxsocket.c +++ b/transport-native-epoll/src/main/c/netty_epoll_linuxsocket.c @@ -711,113 +711,83 @@ static jint dynamicMethodsTableSize() { } static JNINativeMethod* createDynamicMethodsTable(const char* packagePrefix) { - JNINativeMethod* dynamicMethods = malloc(sizeof(JNINativeMethod) * dynamicMethodsTableSize()); + char* dynamicTypeName = NULL; + size_t size = sizeof(JNINativeMethod) * dynamicMethodsTableSize(); + JNINativeMethod* dynamicMethods = malloc(size); + if (dynamicMethods == NULL) { + return NULL; + } + memset(dynamicMethods, 0, size); memcpy(dynamicMethods, fixed_method_table, sizeof(fixed_method_table)); + JNINativeMethod* dynamicMethod = &dynamicMethods[fixed_method_table_size]; - char* dynamicTypeName = netty_unix_util_prepend(packagePrefix, "io/netty/channel/unix/PeerCredentials;"); + NETTY_PREPEND(packagePrefix, "io/netty/channel/unix/PeerCredentials;", dynamicTypeName, error); + NETTY_PREPEND("(I)L", dynamicTypeName, dynamicMethod->signature, error); dynamicMethod->name = "getPeerCredentials"; - dynamicMethod->signature = netty_unix_util_prepend("(I)L", dynamicTypeName); dynamicMethod->fnPtr = (void *) netty_epoll_linuxsocket_getPeerCredentials; - free(dynamicTypeName); + netty_unix_util_free_dynamic_name(&dynamicTypeName); ++dynamicMethod; - dynamicTypeName = netty_unix_util_prepend(packagePrefix, "io/netty/channel/DefaultFileRegion;JJJ)J"); + NETTY_PREPEND(packagePrefix, "io/netty/channel/DefaultFileRegion;JJJ)J", dynamicTypeName, error); + NETTY_PREPEND("(IL", dynamicTypeName, dynamicMethod->signature, error); dynamicMethod->name = "sendFile"; - dynamicMethod->signature = netty_unix_util_prepend("(IL", dynamicTypeName); dynamicMethod->fnPtr = (void *) netty_epoll_linuxsocket_sendFile; - free(dynamicTypeName); + netty_unix_util_free_dynamic_name(&dynamicTypeName); return dynamicMethods; +error: + free(dynamicTypeName); + netty_unix_util_free_dynamic_methods_table(dynamicMethods, fixed_method_table_size, dynamicMethodsTableSize()); + return NULL; } -static void freeDynamicMethodsTable(JNINativeMethod* dynamicMethods) { - jint fullMethodTableSize = dynamicMethodsTableSize(); - jint i = fixed_method_table_size; - for (; i < fullMethodTableSize; ++i) { - free(dynamicMethods[i].signature); - } - free(dynamicMethods); -} // JNI Method Registration Table End jint netty_epoll_linuxsocket_JNI_OnLoad(JNIEnv* env, const char* packagePrefix) { + int ret = JNI_ERR; + char* nettyClassName = NULL; + jclass fileRegionCls = NULL; + jclass fileChannelCls = NULL; + jclass fileDescriptorCls = NULL; + // Register the methods which are not referenced by static member variables JNINativeMethod* dynamicMethods = createDynamicMethodsTable(packagePrefix); + if (dynamicMethods == NULL) { + goto done; + } if (netty_unix_util_register_natives(env, packagePrefix, "io/netty/channel/epoll/LinuxSocket", dynamicMethods, dynamicMethodsTableSize()) != 0) { - freeDynamicMethodsTable(dynamicMethods); - return JNI_ERR; + goto done; } - freeDynamicMethodsTable(dynamicMethods); - dynamicMethods = NULL; - char* nettyClassName = netty_unix_util_prepend(packagePrefix, "io/netty/channel/unix/PeerCredentials"); - jclass localPeerCredsClass = (*env)->FindClass(env, nettyClassName); + 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_GET_METHOD(env, peerCredentialsClass, peerCredentialsMethodId, "", "(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_GET_FIELD(env, fileRegionCls, fileChannelFieldId, "file", "Ljava/nio/channels/FileChannel;", done); + NETTY_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_FIND_CLASS(env, fileDescriptorCls, "java/io/FileDescriptor", done); + NETTY_GET_FIELD(env, fileDescriptorCls, fdFieldId, "fd", "I", done); + + ret = NETTY_JNI_VERSION; +done: + netty_unix_util_free_dynamic_methods_table(dynamicMethods, fixed_method_table_size, dynamicMethodsTableSize()); 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, "", "(II[I)V"); - if (peerCredentialsMethodId == NULL) { - netty_unix_errors_throwRuntimeException(env, "failed to get method ID: PeerCredentials.(int, int, int[])"); - return JNI_ERR; - } - 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; - } - - return NETTY_JNI_VERSION; + return ret; } void netty_epoll_linuxsocket_JNI_OnUnLoad(JNIEnv* env) { - if (peerCredentialsClass != NULL) { - (*env)->DeleteGlobalRef(env, peerCredentialsClass); - peerCredentialsClass = NULL; - } + NETTY_UNLOAD_CLASS(env, peerCredentialsClass); } diff --git a/transport-native-epoll/src/main/c/netty_epoll_native.c b/transport-native-epoll/src/main/c/netty_epoll_native.c index fda29b5890..697e26a8d0 100644 --- a/transport-native-epoll/src/main/c/netty_epoll_native.c +++ b/transport-native-epoll/src/main/c/netty_epoll_native.c @@ -516,42 +516,48 @@ static jint dynamicMethodsTableSize() { } static JNINativeMethod* createDynamicMethodsTable(const char* packagePrefix) { - JNINativeMethod* dynamicMethods = malloc(sizeof(JNINativeMethod) * dynamicMethodsTableSize()); - memcpy(dynamicMethods, fixed_method_table, sizeof(fixed_method_table)); - - char* dynamicTypeName = netty_unix_util_prepend(packagePrefix, "io/netty/channel/epoll/NativeDatagramPacketArray$NativeDatagramPacket;II)I"); - JNINativeMethod* dynamicMethod = &dynamicMethods[fixed_method_table_size]; - dynamicMethod->name = "sendmmsg0"; - dynamicMethod->signature = netty_unix_util_prepend("(IZ[L", dynamicTypeName); - dynamicMethod->fnPtr = (void *) netty_epoll_native_sendmmsg0; - free(dynamicTypeName); - - dynamicTypeName = netty_unix_util_prepend(packagePrefix, "io/netty/channel/epoll/NativeDatagramPacketArray$NativeDatagramPacket;II)I"); - dynamicMethod = &dynamicMethods[fixed_method_table_size + 1]; - dynamicMethod->name = "recvmmsg0"; - dynamicMethod->signature = netty_unix_util_prepend("(IZ[L", dynamicTypeName); - dynamicMethod->fnPtr = (void *) netty_epoll_native_recvmmsg0; - free(dynamicTypeName); - return dynamicMethods; -} - -static void freeDynamicMethodsTable(JNINativeMethod* dynamicMethods) { - jint fullMethodTableSize = dynamicMethodsTableSize(); - jint i = fixed_method_table_size; - for (; i < fullMethodTableSize; ++i) { - free(dynamicMethods[i].signature); + char* dynamicTypeName = NULL; + size_t size = sizeof(JNINativeMethod) * dynamicMethodsTableSize(); + JNINativeMethod* dynamicMethods = malloc(size); + if (dynamicMethods == NULL) { + return NULL; } - free(dynamicMethods); + memset(dynamicMethods, 0, size); + 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); + dynamicMethod->name = "sendmmsg0"; + dynamicMethod->fnPtr = (void *) netty_epoll_native_sendmmsg0; + netty_unix_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); + dynamicMethod->name = "recvmmsg0"; + dynamicMethod->fnPtr = (void *) netty_epoll_native_recvmmsg0; + netty_unix_util_free_dynamic_name(&dynamicTypeName); + + return dynamicMethods; +error: + free(dynamicTypeName); + netty_unix_util_free_dynamic_methods_table(dynamicMethods, fixed_method_table_size, dynamicMethodsTableSize()); + return NULL; } + // JNI Method Registration Table End static jint netty_epoll_native_JNI_OnLoad(JNIEnv* env, const char* packagePrefix) { + int ret = JNI_ERR; int limitsOnLoadCalled = 0; int errorsOnLoadCalled = 0; int filedescriptorOnLoadCalled = 0; int socketOnLoadCalled = 0; int bufferOnLoadCalled = 0; int linuxsocketOnLoadCalled = 0; + char* nettyClassName = NULL; + jclass nativeDatagramPacketCls = NULL; // We must register the statically referenced methods first! if (netty_unix_util_register_natives(env, @@ -559,122 +565,97 @@ static jint netty_epoll_native_JNI_OnLoad(JNIEnv* env, const char* packagePrefix "io/netty/channel/epoll/NativeStaticallyReferencedJniMethods", statically_referenced_fixed_method_table, statically_referenced_fixed_method_table_size) != 0) { - goto error; + goto done; } // Register the methods which are not referenced by static member variables JNINativeMethod* dynamicMethods = createDynamicMethodsTable(packagePrefix); + if (dynamicMethods == NULL) { + goto done; + } + if (netty_unix_util_register_natives(env, packagePrefix, "io/netty/channel/epoll/Native", dynamicMethods, dynamicMethodsTableSize()) != 0) { - freeDynamicMethodsTable(dynamicMethods); - goto error; + goto done; } - freeDynamicMethodsTable(dynamicMethods); - dynamicMethods = NULL; // Load all c modules that we depend upon if (netty_unix_limits_JNI_OnLoad(env, packagePrefix) == JNI_ERR) { - goto error; + goto done; } limitsOnLoadCalled = 1; if (netty_unix_errors_JNI_OnLoad(env, packagePrefix) == JNI_ERR) { - goto error; + goto done; } errorsOnLoadCalled = 1; if (netty_unix_filedescriptor_JNI_OnLoad(env, packagePrefix) == JNI_ERR) { - goto error; + goto done; } filedescriptorOnLoadCalled = 1; if (netty_unix_socket_JNI_OnLoad(env, packagePrefix) == JNI_ERR) { - goto error; + goto done; } socketOnLoadCalled = 1; if (netty_unix_buffer_JNI_OnLoad(env, packagePrefix) == JNI_ERR) { - goto error; + goto done; } bufferOnLoadCalled = 1; if (netty_epoll_linuxsocket_JNI_OnLoad(env, packagePrefix) == JNI_ERR) { - goto error; + goto done; } linuxsocketOnLoadCalled = 1; // Initialize this module - char* nettyClassName = netty_unix_util_prepend(packagePrefix, "io/netty/channel/epoll/NativeDatagramPacketArray$NativeDatagramPacket"); - jclass nativeDatagramPacketCls = (*env)->FindClass(env, nettyClassName); + 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_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); + + ret = NETTY_JNI_VERSION; +done: + + netty_unix_util_free_dynamic_methods_table(dynamicMethods, fixed_method_table_size, dynamicMethodsTableSize()); 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; + if (ret == JNI_ERR) { + 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; + packetAddrLenFieldId = NULL; + packetScopeIdFieldId = NULL; + packetPortFieldId = NULL; + packetMemoryAddressFieldId = NULL; + packetCountFieldId = NULL; } - packetAddrLenFieldId = (*env)->GetFieldID(env, nativeDatagramPacketCls, "addrLen", "I"); - if (packetAddrLenFieldId == NULL) { - netty_unix_errors_throwRuntimeException(env, "failed to get field ID: NativeDatagramPacket.addrLen"); - 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; - packetAddrLenFieldId = NULL; - packetScopeIdFieldId = NULL; - packetPortFieldId = NULL; - packetMemoryAddressFieldId = NULL; - packetCountFieldId = NULL; - - return JNI_ERR; + return ret; } static void netty_epoll_native_JNI_OnUnLoad(JNIEnv* env) { @@ -717,11 +698,7 @@ static jint JNI_OnLoad_netty_transport_native_epoll0(JavaVM* vm, void* reserved) #endif /* NETTY_BUILD_STATIC */ jint ret = netty_epoll_native_JNI_OnLoad(env, packagePrefix); - if (packagePrefix != NULL) { - free(packagePrefix); - packagePrefix = NULL; - } - + free(packagePrefix); return ret; } diff --git a/transport-native-kqueue/src/main/c/netty_kqueue_bsdsocket.c b/transport-native-kqueue/src/main/c/netty_kqueue_bsdsocket.c index e9e13030c7..53a376901e 100644 --- a/transport-native-kqueue/src/main/c/netty_kqueue_bsdsocket.c +++ b/transport-native-kqueue/src/main/c/netty_kqueue_bsdsocket.c @@ -109,8 +109,19 @@ static jobjectArray netty_kqueue_bsdsocket_getAcceptFilter(JNIEnv* env, jclass c return NULL; } jobjectArray resultArray = (*env)->NewObjectArray(env, 2, stringClass, NULL); - (*env)->SetObjectArrayElement(env, resultArray, 0, (*env)->NewStringUTF(env, &af.af_name[0])); - (*env)->SetObjectArrayElement(env, resultArray, 1, (*env)->NewStringUTF(env, &af.af_arg[0])); + if (resultArray == NULL) { + return NULL; + } + jstring name = (*env)->NewStringUTF(env, &af.af_name[0]); + if (name == NULL) { + return NULL; + } + jstring arg = (*env)->NewStringUTF(env, &af.af_arg[0]); + if (arg == NULL) { + return NULL; + } + (*env)->SetObjectArrayElement(env, resultArray, 0, name); + (*env)->SetObjectArrayElement(env, resultArray, 1, arg); return resultArray; #else // No know replacement on MacOS // Don't throw here because this is used when getting a list of all options. @@ -151,11 +162,15 @@ static jobject netty_kqueue_bsdsocket_getPeerCredentials(JNIEnv *env, jclass cla } jintArray gids = NULL; if (credentials.cr_ngroups > 1) { - gids = (*env)->NewIntArray(env, credentials.cr_ngroups); + if ((gids = (*env)->NewIntArray(env, credentials.cr_ngroups)) == NULL) { + return NULL; + } (*env)->SetIntArrayRegion(env, gids, 0, credentials.cr_ngroups, (jint*) credentials.cr_groups); } else { // It has been observed on MacOS that cr_ngroups may not be set, but the cr_gid field is set. - gids = (*env)->NewIntArray(env, 1); + if ((gids = (*env)->NewIntArray(env, 1)) == NULL) { + return NULL; + } (*env)->SetIntArrayRegion(env, gids, 0, 1, (jint*) &credentials.cr_gid); } @@ -189,130 +204,87 @@ static jint dynamicMethodsTableSize() { } static JNINativeMethod* createDynamicMethodsTable(const char* packagePrefix) { - JNINativeMethod* dynamicMethods = malloc(sizeof(JNINativeMethod) * dynamicMethodsTableSize()); + char* dynamicTypeName = NULL; + size_t size = sizeof(JNINativeMethod) * dynamicMethodsTableSize(); + JNINativeMethod* dynamicMethods = malloc(size); + if (dynamicMethods == NULL) { + return NULL; + } + memset(dynamicMethods, 0, size); memcpy(dynamicMethods, fixed_method_table, sizeof(fixed_method_table)); - char* dynamicTypeName = netty_unix_util_prepend(packagePrefix, "io/netty/channel/DefaultFileRegion;JJJ)J"); + 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); dynamicMethod->name = "sendFile"; - dynamicMethod->signature = netty_unix_util_prepend("(IL", dynamicTypeName); dynamicMethod->fnPtr = (void *) netty_kqueue_bsdsocket_sendFile; - free(dynamicTypeName); + netty_unix_util_free_dynamic_name(&dynamicTypeName); ++dynamicMethod; - dynamicTypeName = netty_unix_util_prepend(packagePrefix, "io/netty/channel/unix/PeerCredentials;"); + NETTY_PREPEND(packagePrefix, "io/netty/channel/unix/PeerCredentials;", dynamicTypeName, error); + NETTY_PREPEND("(I)L", dynamicTypeName, dynamicMethod->signature, error); dynamicMethod->name = "getPeerCredentials"; - dynamicMethod->signature = netty_unix_util_prepend("(I)L", dynamicTypeName); dynamicMethod->fnPtr = (void *) netty_kqueue_bsdsocket_getPeerCredentials; - free(dynamicTypeName); + netty_unix_util_free_dynamic_name(&dynamicTypeName); return dynamicMethods; +error: + free(dynamicTypeName); + netty_unix_util_free_dynamic_methods_table(dynamicMethods, fixed_method_table_size, dynamicMethodsTableSize()); + return NULL; } -static void freeDynamicMethodsTable(JNINativeMethod* dynamicMethods) { - jint fullMethodTableSize = dynamicMethodsTableSize(); - jint i = fixed_method_table_size; - for (; i < fullMethodTableSize; ++i) { - free(dynamicMethods[i].signature); - } - free(dynamicMethods); -} // JNI Method Registration Table End jint netty_kqueue_bsdsocket_JNI_OnLoad(JNIEnv* env, const char* packagePrefix) { + int ret = JNI_ERR; + char* nettyClassName = NULL; + jclass fileRegionCls = NULL; + jclass fileChannelCls = NULL; + jclass fileDescriptorCls = NULL; // Register the methods which are not referenced by static member variables JNINativeMethod* dynamicMethods = createDynamicMethodsTable(packagePrefix); + if (dynamicMethods == NULL) { + goto done; + } if (netty_unix_util_register_natives(env, packagePrefix, "io/netty/channel/kqueue/BsdSocket", dynamicMethods, dynamicMethodsTableSize()) != 0) { - freeDynamicMethodsTable(dynamicMethods); - return JNI_ERR; + goto done; } - freeDynamicMethodsTable(dynamicMethods); - dynamicMethods = NULL; // Initialize this module - char* nettyClassName = netty_unix_util_prepend(packagePrefix, "io/netty/channel/DefaultFileRegion"); - jclass fileRegionCls = (*env)->FindClass(env, nettyClassName); + NETTY_PREPEND(packagePrefix, "io/netty/channel/DefaultFileRegion", nettyClassName, done); + NETTY_FIND_CLASS(env, fileRegionCls, nettyClassName, done); + netty_unix_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_FIND_CLASS(env, fileChannelCls, "sun/nio/ch/FileChannelImpl", done); + NETTY_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_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_GET_METHOD(env, peerCredentialsClass, peerCredentialsMethodId, "", "(II[I)V", done); + ret = NETTY_JNI_VERSION; +done: + netty_unix_util_free_dynamic_methods_table(dynamicMethods, fixed_method_table_size, dynamicMethodsTableSize()); 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; - } - jclass stringCls = (*env)->FindClass(env, "java/lang/String"); - if (stringCls == NULL) { - // pending exception... - return JNI_ERR; - } - if ((stringClass = (*env)->NewGlobalRef(env, stringCls)) == NULL) { - // out-of-memory! - netty_unix_errors_throwOutOfMemoryError(env); - 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, "", "(II[I)V"); - if (peerCredentialsMethodId == NULL) { - netty_unix_errors_throwRuntimeException(env, "failed to get method ID: PeerCredentials.(int, int, int[])"); - return JNI_ERR; - } - - return NETTY_JNI_VERSION; + return ret; } void netty_kqueue_bsdsocket_JNI_OnUnLoad(JNIEnv* env) { - if (peerCredentialsClass != NULL) { - (*env)->DeleteGlobalRef(env, peerCredentialsClass); - peerCredentialsClass = NULL; - } - if (stringClass != NULL) { - (*env)->DeleteGlobalRef(env, stringClass); - stringClass = NULL; - } + NETTY_UNLOAD_CLASS(env, peerCredentialsClass); + NETTY_UNLOAD_CLASS(env, stringClass); } diff --git a/transport-native-kqueue/src/main/c/netty_kqueue_native.c b/transport-native-kqueue/src/main/c/netty_kqueue_native.c index 86f2d18586..9e995ec913 100644 --- a/transport-native-kqueue/src/main/c/netty_kqueue_native.c +++ b/transport-native-kqueue/src/main/c/netty_kqueue_native.c @@ -388,10 +388,8 @@ static jint JNI_OnLoad_netty_transport_native_kqueue0(JavaVM* vm, void* reserved #endif /* NETTY_BUILD_STATIC */ jint ret = netty_kqueue_native_JNI_OnLoad(env, packagePrefix); - if (packagePrefix != NULL) { - free(packagePrefix); - packagePrefix = NULL; - } + // It's safe to call free(...) with a NULL argument as well. + free(packagePrefix); return ret; } diff --git a/transport-native-unix-common/src/main/c/netty_unix_errors.c b/transport-native-unix-common/src/main/c/netty_unix_errors.c index 8298f910b8..634c99bc4a 100644 --- a/transport-native-unix-common/src/main/c/netty_unix_errors.c +++ b/transport-native-unix-common/src/main/c/netty_unix_errors.c @@ -21,6 +21,7 @@ #include "netty_unix_jni.h" #include "netty_unix_util.h" +static jclass oomErrorClass = NULL; static jclass runtimeExceptionClass = NULL; static jclass channelExceptionClass = NULL; static jclass ioExceptionClass = NULL; @@ -43,12 +44,18 @@ void netty_unix_errors_throwRuntimeException(JNIEnv* env, char* message) { void netty_unix_errors_throwRuntimeExceptionErrorNo(JNIEnv* env, char* message, int errorNumber) { char* allocatedMessage = exceptionMessage(message, errorNumber); + if (allocatedMessage == NULL) { + return; + } (*env)->ThrowNew(env, runtimeExceptionClass, allocatedMessage); free(allocatedMessage); } void netty_unix_errors_throwChannelExceptionErrorNo(JNIEnv* env, char* message, int errorNumber) { char* allocatedMessage = exceptionMessage(message, errorNumber); + if (allocatedMessage == NULL) { + return; + } (*env)->ThrowNew(env, channelExceptionClass, allocatedMessage); free(allocatedMessage); } @@ -63,18 +70,23 @@ void netty_unix_errors_throwPortUnreachableException(JNIEnv* env, char* message) void netty_unix_errors_throwIOExceptionErrorNo(JNIEnv* env, char* message, int errorNumber) { char* allocatedMessage = exceptionMessage(message, errorNumber); + if (allocatedMessage == NULL) { + return; + } (*env)->ThrowNew(env, ioExceptionClass, allocatedMessage); free(allocatedMessage); } void netty_unix_errors_throwClosedChannelException(JNIEnv* env) { jobject exception = (*env)->NewObject(env, closedChannelExceptionClass, closedChannelExceptionMethodId); + if (exception == NULL) { + return; + } (*env)->Throw(env, exception); } void netty_unix_errors_throwOutOfMemoryError(JNIEnv* env) { - jclass exceptionClass = (*env)->FindClass(env, "java/lang/OutOfMemoryError"); - (*env)->ThrowNew(env, exceptionClass, ""); + (*env)->ThrowNew(env, oomErrorClass, ""); } // JNI Registered Methods Begin @@ -151,6 +163,7 @@ static const jint statically_referenced_fixed_method_table_size = sizeof(statica // JNI Method Registration Table End 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, packagePrefix, @@ -160,98 +173,33 @@ jint netty_unix_errors_JNI_OnLoad(JNIEnv* env, const char* packagePrefix) { return JNI_ERR; } - jclass localRuntimeExceptionClass = (*env)->FindClass(env, "java/lang/RuntimeException"); - if (localRuntimeExceptionClass == NULL) { - // pending exception... - return JNI_ERR; - } - runtimeExceptionClass = (jclass) (*env)->NewGlobalRef(env, localRuntimeExceptionClass); - if (runtimeExceptionClass == NULL) { - // out-of-memory! - netty_unix_errors_throwOutOfMemoryError(env); - return JNI_ERR; - } + NETTY_LOAD_CLASS(env, oomErrorClass, "java/lang/OutOfMemoryError", error); - char* nettyClassName = netty_unix_util_prepend(packagePrefix, "io/netty/channel/ChannelException"); - jclass localChannelExceptionClass = (*env)->FindClass(env, nettyClassName); - free(nettyClassName); - nettyClassName = NULL; - if (localChannelExceptionClass == NULL) { - // pending exception... - return JNI_ERR; - } - channelExceptionClass = (jclass) (*env)->NewGlobalRef(env, localChannelExceptionClass); - if (channelExceptionClass == NULL) { - // out-of-memory! - netty_unix_errors_throwOutOfMemoryError(env); - return JNI_ERR; - } + NETTY_LOAD_CLASS(env, runtimeExceptionClass, "java/lang/RuntimeException", error); - // cache classes that are used within other jni methods for performance reasons - jclass localClosedChannelExceptionClass = (*env)->FindClass(env, "java/nio/channels/ClosedChannelException"); - if (localClosedChannelExceptionClass == NULL) { - // pending exception... - return JNI_ERR; - } - closedChannelExceptionClass = (jclass) (*env)->NewGlobalRef(env, localClosedChannelExceptionClass); - if (closedChannelExceptionClass == NULL) { - // out-of-memory! - netty_unix_errors_throwOutOfMemoryError(env); - return JNI_ERR; - } - closedChannelExceptionMethodId = (*env)->GetMethodID(env, closedChannelExceptionClass, "", "()V"); - if (closedChannelExceptionMethodId == NULL) { - netty_unix_errors_throwRuntimeException(env, "failed to get method ID: ClosedChannelException.()"); - return JNI_ERR; - } + NETTY_PREPEND(packagePrefix, "io/netty/channel/ChannelException", nettyClassName, error); + NETTY_LOAD_CLASS(env, channelExceptionClass, nettyClassName, error); + netty_unix_util_free_dynamic_name(&nettyClassName); - jclass localIoExceptionClass = (*env)->FindClass(env, "java/io/IOException"); - if (localIoExceptionClass == NULL) { - // pending exception... - return JNI_ERR; - } - ioExceptionClass = (jclass) (*env)->NewGlobalRef(env, localIoExceptionClass); - if (ioExceptionClass == NULL) { - // out-of-memory! - netty_unix_errors_throwOutOfMemoryError(env); - return JNI_ERR; - } + NETTY_LOAD_CLASS(env, closedChannelExceptionClass, "java/nio/channels/ClosedChannelException", error); + NETTY_GET_METHOD(env, closedChannelExceptionClass, closedChannelExceptionMethodId, "", "()V", error); - jclass localPortUnreachableExceptionClass = (*env)->FindClass(env, "java/net/PortUnreachableException"); - if (localPortUnreachableExceptionClass == NULL) { - // pending exception... - return JNI_ERR; - } - portUnreachableExceptionClass = (jclass) (*env)->NewGlobalRef(env, localPortUnreachableExceptionClass); - if (portUnreachableExceptionClass == NULL) { - // out-of-memory! - netty_unix_errors_throwOutOfMemoryError(env); - return JNI_ERR; - } + NETTY_LOAD_CLASS(env, ioExceptionClass, "java/io/IOException", error); + + NETTY_LOAD_CLASS(env, portUnreachableExceptionClass, "java/net/PortUnreachableException", error); return NETTY_JNI_VERSION; +error: + free(nettyClassName); + return JNI_ERR; } void netty_unix_errors_JNI_OnUnLoad(JNIEnv* env) { // delete global references so the GC can collect them - if (runtimeExceptionClass != NULL) { - (*env)->DeleteGlobalRef(env, runtimeExceptionClass); - runtimeExceptionClass = NULL; - } - if (channelExceptionClass != NULL) { - (*env)->DeleteGlobalRef(env, channelExceptionClass); - channelExceptionClass = NULL; - } - if (ioExceptionClass != NULL) { - (*env)->DeleteGlobalRef(env, ioExceptionClass); - ioExceptionClass = NULL; - } - if (portUnreachableExceptionClass != NULL) { - (*env)->DeleteGlobalRef(env, portUnreachableExceptionClass); - portUnreachableExceptionClass = NULL; - } - if (closedChannelExceptionClass != NULL) { - (*env)->DeleteGlobalRef(env, closedChannelExceptionClass); - closedChannelExceptionClass = NULL; - } + 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); } diff --git a/transport-native-unix-common/src/main/c/netty_unix_filedescriptor.c b/transport-native-unix-common/src/main/c/netty_unix_filedescriptor.c index d13ffb0d1c..7e08bb5153 100644 --- a/transport-native-unix-common/src/main/c/netty_unix_filedescriptor.c +++ b/transport-native-unix-common/src/main/c/netty_unix_filedescriptor.c @@ -276,65 +276,41 @@ static const jint method_table_size = sizeof(method_table) / sizeof(method_table // JNI Method Registration Table End 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, "io/netty/channel/unix/FileDescriptor", method_table, method_table_size) != 0) { - return JNI_ERR; + goto done; } - void* mem = malloc(1); - if (mem == NULL) { - netty_unix_errors_throwOutOfMemoryError(env); - return JNI_ERR; + if ((mem = malloc(1)) == NULL) { + goto done; } jobject directBuffer = (*env)->NewDirectByteBuffer(env, mem, 1); if (directBuffer == NULL) { - free(mem); - - netty_unix_errors_throwOutOfMemoryError(env); - return JNI_ERR; + goto done; } if ((*env)->GetDirectBufferAddress(env, directBuffer) == NULL) { - free(mem); - - netty_unix_errors_throwRuntimeException(env, "failed to get direct buffer address"); - return JNI_ERR; + goto done; } - jclass cls = (*env)->GetObjectClass(env, directBuffer); - + if (cls == NULL) { + goto done; + } + // 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); + NETTY_GET_METHOD(env, cls, posId, "position", "()I", done); + NETTY_GET_METHOD(env, cls, limitId, "limit", "()I", done); - // 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); - } + NETTY_TRY_GET_FIELD(env, cls, posFieldId, "position", "I"); + NETTY_TRY_GET_FIELD(env, cls, limitFieldId, "limit", "I"); + ret = NETTY_JNI_VERSION; +done: free(mem); - return NETTY_JNI_VERSION; + return ret; } void netty_unix_filedescriptor_JNI_OnUnLoad(JNIEnv* env) { } diff --git a/transport-native-unix-common/src/main/c/netty_unix_socket.c b/transport-native-unix-common/src/main/c/netty_unix_socket.c index 2f817159b2..83a507fe60 100644 --- a/transport-native-unix-common/src/main/c/netty_unix_socket.c +++ b/transport-native-unix-common/src/main/c/netty_unix_socket.c @@ -85,7 +85,9 @@ static jobject createDatagramSocketAddress(JNIEnv* env, const struct sockaddr_st int scopeId; int ipLength = netty_unix_socket_ipAddressLength(addr); jbyteArray addressBytes = (*env)->NewByteArray(env, ipLength); - + if (addressBytes == NULL) { + return NULL; + } if (addr->ss_family == AF_INET) { struct sockaddr_in* s = (struct sockaddr_in*) addr; port = ntohs(s->sin_port); @@ -174,7 +176,9 @@ static void initInetSocketAddressArray(JNIEnv* env, const struct sockaddr_storag static jbyteArray createInetSocketAddressArray(JNIEnv* env, const struct sockaddr_storage* addr) { jsize len = addressLength(addr); jbyteArray bArray = (*env)->NewByteArray(env, len); - + if (bArray == NULL) { + return NULL; + } initInetSocketAddressArray(env, addr, bArray, 0, len); return bArray; } @@ -1009,128 +1013,87 @@ static jint dynamicMethodsTableSize() { } static JNINativeMethod* createDynamicMethodsTable(const char* packagePrefix) { - JNINativeMethod* dynamicMethods = malloc(sizeof(JNINativeMethod) * dynamicMethodsTableSize()); + char* dynamicTypeName = NULL; + size_t size = sizeof(JNINativeMethod) * dynamicMethodsTableSize(); + JNINativeMethod* dynamicMethods = malloc(size); + if (dynamicMethods == NULL) { + return NULL; + } + memset(dynamicMethods, 0, size); memcpy(dynamicMethods, fixed_method_table, sizeof(fixed_method_table)); - char* dynamicTypeName = netty_unix_util_prepend(packagePrefix, "io/netty/channel/unix/DatagramSocketAddress;"); + 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); dynamicMethod->name = "recvFrom"; - dynamicMethod->signature = netty_unix_util_prepend("(ILjava/nio/ByteBuffer;II)L", dynamicTypeName); dynamicMethod->fnPtr = (void *) netty_unix_socket_recvFrom; - free(dynamicTypeName); + netty_unix_util_free_dynamic_name(&dynamicTypeName); ++dynamicMethod; - dynamicTypeName = netty_unix_util_prepend(packagePrefix, "io/netty/channel/unix/DatagramSocketAddress;"); + NETTY_PREPEND(packagePrefix, "io/netty/channel/unix/DatagramSocketAddress;", dynamicTypeName, error); + NETTY_PREPEND("(IJII)L", dynamicTypeName, dynamicMethod->signature, error); dynamicMethod->name = "recvFromAddress"; - dynamicMethod->signature = netty_unix_util_prepend("(IJII)L", dynamicTypeName); dynamicMethod->fnPtr = (void *) netty_unix_socket_recvFromAddress; - free(dynamicTypeName); + netty_unix_util_free_dynamic_name(&dynamicTypeName); return dynamicMethods; +error: + free(dynamicTypeName); + netty_unix_util_free_dynamic_methods_table(dynamicMethods, fixed_method_table_size, dynamicMethodsTableSize()); + return NULL; } -static void freeDynamicMethodsTable(JNINativeMethod* dynamicMethods) { - jint fullMethodTableSize = dynamicMethodsTableSize(); - jint i = fixed_method_table_size; - for (; i < fullMethodTableSize; ++i) { - free(dynamicMethods[i].signature); - } - free(dynamicMethods); -} // JNI Method Registration Table End jint netty_unix_socket_JNI_OnLoad(JNIEnv* env, const char* packagePrefix) { + int ret = JNI_ERR; + char* nettyClassName = NULL; + void* mem = NULL; JNINativeMethod* dynamicMethods = createDynamicMethodsTable(packagePrefix); + if (dynamicMethods == NULL) { + goto done; + } if (netty_unix_util_register_natives(env, packagePrefix, "io/netty/channel/unix/Socket", dynamicMethods, dynamicMethodsTableSize()) != 0) { - freeDynamicMethodsTable(dynamicMethods); - return JNI_ERR; - } - freeDynamicMethodsTable(dynamicMethods); - dynamicMethods = NULL; - char* nettyClassName = netty_unix_util_prepend(packagePrefix, "io/netty/channel/unix/DatagramSocketAddress"); - jclass localDatagramSocketAddressClass = (*env)->FindClass(env, nettyClassName); - if (localDatagramSocketAddressClass == NULL) { - free(nettyClassName); - nettyClassName = NULL; - // pending exception... - return JNI_ERR; - } - datagramSocketAddressClass = (jclass) (*env)->NewGlobalRef(env, localDatagramSocketAddressClass); - if (datagramSocketAddressClass == NULL) { - free(nettyClassName); - nettyClassName = NULL; - // out-of-memory! - netty_unix_errors_throwOutOfMemoryError(env); - return JNI_ERR; + goto done; } + + NETTY_PREPEND(packagePrefix, "io/netty/channel/unix/DatagramSocketAddress", nettyClassName, done); + NETTY_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, "", parameters, done); - datagramSocketAddrMethodId = (*env)->GetMethodID(env, datagramSocketAddressClass, "", parameters); - if (datagramSocketAddrMethodId == NULL) { - char msg[1024] = {0}; - snprintf(msg, sizeof(msg), "failed to get method ID: %s.(byte[], int, int, int, %s)", nettyClassName, nettyClassName); - free(nettyClassName); - nettyClassName = NULL; - netty_unix_errors_throwRuntimeException(env, msg); - return JNI_ERR; + NETTY_LOAD_CLASS(env, inetSocketAddressClass, "java/net/InetSocketAddress", done); + NETTY_GET_METHOD(env, inetSocketAddressClass, inetSocketAddrMethodId, "", "(Ljava/lang/String;I)V", done); + + if ((mem = malloc(1)) == NULL) { + goto done; } - free(nettyClassName); - nettyClassName = NULL; - - jclass localInetSocketAddressClass = (*env)->FindClass(env, "java/net/InetSocketAddress"); - if (localInetSocketAddressClass == NULL) { - // pending exception... - return JNI_ERR; - } - inetSocketAddressClass = (jclass) (*env)->NewGlobalRef(env, localInetSocketAddressClass); - if (inetSocketAddressClass == NULL) { - // out-of-memory! - netty_unix_errors_throwOutOfMemoryError(env); - return JNI_ERR; - } - inetSocketAddrMethodId = (*env)->GetMethodID(env, inetSocketAddressClass, "", "(Ljava/lang/String;I)V"); - if (inetSocketAddrMethodId == NULL) { - netty_unix_errors_throwRuntimeException(env, "failed to get method ID: InetSocketAddress.(String, int)"); - return JNI_ERR; - } - - 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; + goto done; } if ((*env)->GetDirectBufferAddress(env, directBuffer) == NULL) { - free(mem); - - netty_unix_errors_throwRuntimeException(env, "failed to get direct buffer address"); - return JNI_ERR; + goto done; } - free(mem); - return NETTY_JNI_VERSION; + ret = NETTY_JNI_VERSION; +done: + netty_unix_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) { - if (datagramSocketAddressClass != NULL) { - (*env)->DeleteGlobalRef(env, datagramSocketAddressClass); - datagramSocketAddressClass = NULL; - } - if (inetSocketAddressClass != NULL) { - (*env)->DeleteGlobalRef(env, inetSocketAddressClass); - inetSocketAddressClass = NULL; - } + NETTY_UNLOAD_CLASS(env, datagramSocketAddressClass); + NETTY_UNLOAD_CLASS(env, inetSocketAddressClass); } diff --git a/transport-native-unix-common/src/main/c/netty_unix_util.c b/transport-native-unix-common/src/main/c/netty_unix_util.c index 7ff91c5a94..3d7bda871d 100644 --- a/transport-native-unix-common/src/main/c/netty_unix_util.c +++ b/transport-native-unix-common/src/main/c/netty_unix_util.c @@ -29,12 +29,17 @@ 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) { + char* result = NULL; if (prefix == NULL) { - char* result = (char*) malloc(sizeof(char) * (strlen(str) + 1)); + if ((result = (char*) malloc(sizeof(char) * (strlen(str) + 1))) == NULL) { + return NULL; + } strcpy(result, str); return result; } - char* result = (char*) malloc(sizeof(char) * (strlen(prefix) + strlen(str) + 1)); + if ((result = (char*) malloc(sizeof(char) * (strlen(prefix) + strlen(str) + 1))) == NULL) { + return NULL; + } strcpy(result, prefix); strcat(result, str); return result; @@ -82,7 +87,10 @@ char* netty_unix_util_parse_package_prefix(const char* libraryPathName, const ch // packagePrefix length is > 0 // Make a copy so we can modify the value without impacting libraryPathName. size_t packagePrefixLen = packageNameEnd - packagePrefix; - packagePrefix = strndup(packagePrefix, packagePrefixLen); + 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; @@ -95,7 +103,9 @@ char* netty_unix_util_parse_package_prefix(const char* libraryPathName, const ch // Make sure packagePrefix is terminated with the '/' JNI package separator. if(*(--temp) != '/') { temp = packagePrefix; - packagePrefix = netty_unix_util_prepend(packagePrefix, "/"); + if ((packagePrefix = netty_unix_util_prepend(packagePrefix, "/")) == NULL) { + *status = JNI_ERR; + } free(temp); } return packagePrefix; @@ -185,13 +195,34 @@ jboolean netty_unix_util_initialize_wait_clock(clockid_t* clockId) { } jint netty_unix_util_register_natives(JNIEnv* env, const char* packagePrefix, const char* className, const JNINativeMethod* methods, jint numMethods) { - char* nettyClassName = netty_unix_util_prepend(packagePrefix, className); + char* nettyClassName = NULL; + int ret = JNI_ERR; + NETTY_PREPEND(packagePrefix, className, nettyClassName, done); + jclass nativeCls = (*env)->FindClass(env, nettyClassName); - free(nettyClassName); - nettyClassName = NULL; if (nativeCls == NULL) { - return JNI_ERR; + goto done; } - return (*env)->RegisterNatives(env, nativeCls, methods, numMethods); + ret = (*env)->RegisterNatives(env, nativeCls, methods, numMethods); +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; + } } diff --git a/transport-native-unix-common/src/main/c/netty_unix_util.h b/transport-native-unix-common/src/main/c/netty_unix_util.h index aba672dc5f..5aa9e7f15e 100644 --- a/transport-native-unix-common/src/main/c/netty_unix_util.h +++ b/transport-native-unix-common/src/main/c/netty_unix_util.h @@ -36,6 +36,72 @@ 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
prefix + str
. * @@ -84,4 +150,7 @@ jboolean netty_unix_util_timespec_subtract_ns(struct timespec* ts, uint64_t nano */ jint netty_unix_util_register_natives(JNIEnv* env, const char* packagePrefix, const char* className, const JNINativeMethod* methods, jint numMethods); +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_ */