Preload classes before calling native OnLoad function to prevent clas… (#11215)
Motivation: It turns out it is quite easy to cause a classloader deadlock in more recent java updates if you cause classloading while you are in native code. Because of this we should just workaround this issue by pre-load all the classes that needs to be accessed in the OnLoad function. Modifications: - Preload all classes that would otherwise be loaded by native OnLoad functions. Result: Workaround for https://github.com/netty/netty/issues/11209 and https://bugs.openjdk.java.net/browse/JDK-8266310
This commit is contained in:
parent
617c26d344
commit
6b3ec62e6e
@ -0,0 +1,48 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2021 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:
|
||||||
|
*
|
||||||
|
* https://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.
|
||||||
|
*/
|
||||||
|
package io.netty.util.internal;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Utility which ensures that classes are loaded by the {@link ClassLoader}.
|
||||||
|
*/
|
||||||
|
public final class ClassInitializerUtil {
|
||||||
|
|
||||||
|
private ClassInitializerUtil() { }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Preload the given classes and so ensure the {@link ClassLoader} has these loaded after this method call.
|
||||||
|
*
|
||||||
|
* @param loadingClass the {@link Class} that wants to load the classes.
|
||||||
|
* @param classes the classes to load.
|
||||||
|
*/
|
||||||
|
public static void tryLoadClasses(Class<?> loadingClass, Class<?>... classes) {
|
||||||
|
ClassLoader loader = PlatformDependent.getClassLoader(loadingClass);
|
||||||
|
for (Class<?> clazz: classes) {
|
||||||
|
tryLoadClass(loader, clazz.getName());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void tryLoadClass(ClassLoader classLoader, String className) {
|
||||||
|
try {
|
||||||
|
// Load the class and also ensure we init it which means its linked etc.
|
||||||
|
Class.forName(className, true, classLoader);
|
||||||
|
} catch (ClassNotFoundException ignore) {
|
||||||
|
// Ignore
|
||||||
|
} catch (SecurityException ignore) {
|
||||||
|
// Ignore
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -162,6 +162,8 @@ static void netty_resolver_dns_native_macos_JNI_OnUnLoad(JNIEnv* env) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// IMPORTANT: If you add any NETTY_JNI_UTIL_LOAD_CLASS or NETTY_JNI_UTIL_FIND_CLASS calls you also need to update
|
||||||
|
// MacOSDnsServerAddressStreamProvider to reflect that.
|
||||||
static jint netty_resolver_dns_native_macos_JNI_OnLoad(JNIEnv* env, const char* packagePrefix) {
|
static jint netty_resolver_dns_native_macos_JNI_OnLoad(JNIEnv* env, const char* packagePrefix) {
|
||||||
int ret = JNI_ERR;
|
int ret = JNI_ERR;
|
||||||
int providerRegistered = 0;
|
int providerRegistered = 0;
|
||||||
|
@ -19,6 +19,7 @@ import io.netty.resolver.dns.DnsServerAddressStream;
|
|||||||
import io.netty.resolver.dns.DnsServerAddressStreamProvider;
|
import io.netty.resolver.dns.DnsServerAddressStreamProvider;
|
||||||
import io.netty.resolver.dns.DnsServerAddressStreamProviders;
|
import io.netty.resolver.dns.DnsServerAddressStreamProviders;
|
||||||
import io.netty.resolver.dns.DnsServerAddresses;
|
import io.netty.resolver.dns.DnsServerAddresses;
|
||||||
|
import io.netty.util.internal.ClassInitializerUtil;
|
||||||
import io.netty.util.internal.NativeLibraryLoader;
|
import io.netty.util.internal.NativeLibraryLoader;
|
||||||
import io.netty.util.internal.PlatformDependent;
|
import io.netty.util.internal.PlatformDependent;
|
||||||
import io.netty.util.internal.StringUtil;
|
import io.netty.util.internal.StringUtil;
|
||||||
@ -51,6 +52,16 @@ public final class MacOSDnsServerAddressStreamProvider implements DnsServerAddre
|
|||||||
private static final long REFRESH_INTERVAL = TimeUnit.SECONDS.toNanos(10);
|
private static final long REFRESH_INTERVAL = TimeUnit.SECONDS.toNanos(10);
|
||||||
|
|
||||||
static {
|
static {
|
||||||
|
// Preload all classes that will be used in the OnLoad(...) function of JNI to eliminate the possiblity of a
|
||||||
|
// class-loader deadlock. This is a workaround for https://github.com/netty/netty/issues/11209.
|
||||||
|
|
||||||
|
// This needs to match all the classes that are loaded via NETTY_JNI_UTIL_LOAD_CLASS or looked up via
|
||||||
|
// NETTY_JNI_UTIL_FIND_CLASS.
|
||||||
|
ClassInitializerUtil.tryLoadClasses(MacOSDnsServerAddressStreamProvider.class,
|
||||||
|
// netty_resolver_dns_macos
|
||||||
|
byte[].class, String.class
|
||||||
|
);
|
||||||
|
|
||||||
Throwable cause = null;
|
Throwable cause = null;
|
||||||
try {
|
try {
|
||||||
loadNativeLibrary();
|
loadNativeLibrary();
|
||||||
|
@ -746,6 +746,8 @@ error:
|
|||||||
|
|
||||||
// JNI Method Registration Table End
|
// JNI Method Registration Table End
|
||||||
|
|
||||||
|
// IMPORTANT: If you add any NETTY_JNI_UTIL_LOAD_CLASS or NETTY_JNI_UTIL_FIND_CLASS calls you also need to update
|
||||||
|
// Native to reflect that.
|
||||||
jint netty_epoll_linuxsocket_JNI_OnLoad(JNIEnv* env, const char* packagePrefix) {
|
jint netty_epoll_linuxsocket_JNI_OnLoad(JNIEnv* env, const char* packagePrefix) {
|
||||||
int ret = JNI_ERR;
|
int ret = JNI_ERR;
|
||||||
char* nettyClassName = NULL;
|
char* nettyClassName = NULL;
|
||||||
|
@ -727,6 +727,8 @@ error:
|
|||||||
|
|
||||||
// JNI Method Registration Table End
|
// JNI Method Registration Table End
|
||||||
|
|
||||||
|
// IMPORTANT: If you add any NETTY_JNI_UTIL_LOAD_CLASS or NETTY_JNI_UTIL_FIND_CLASS calls you also need to update
|
||||||
|
// Native to reflect that.
|
||||||
static jint netty_epoll_native_JNI_OnLoad(JNIEnv* env, const char* packagePrefix) {
|
static jint netty_epoll_native_JNI_OnLoad(JNIEnv* env, const char* packagePrefix) {
|
||||||
int ret = JNI_ERR;
|
int ret = JNI_ERR;
|
||||||
int staticallyRegistered = 0;
|
int staticallyRegistered = 0;
|
||||||
|
@ -15,9 +15,12 @@
|
|||||||
*/
|
*/
|
||||||
package io.netty.channel.epoll;
|
package io.netty.channel.epoll;
|
||||||
|
|
||||||
|
import io.netty.channel.DefaultFileRegion;
|
||||||
import io.netty.channel.unix.FileDescriptor;
|
import io.netty.channel.unix.FileDescriptor;
|
||||||
|
import io.netty.channel.unix.PeerCredentials;
|
||||||
import io.netty.channel.unix.Socket;
|
import io.netty.channel.unix.Socket;
|
||||||
import io.netty.channel.unix.Unix;
|
import io.netty.channel.unix.Unix;
|
||||||
|
import io.netty.util.internal.ClassInitializerUtil;
|
||||||
import io.netty.util.internal.NativeLibraryLoader;
|
import io.netty.util.internal.NativeLibraryLoader;
|
||||||
import io.netty.util.internal.PlatformDependent;
|
import io.netty.util.internal.PlatformDependent;
|
||||||
import io.netty.util.internal.SystemPropertyUtil;
|
import io.netty.util.internal.SystemPropertyUtil;
|
||||||
@ -26,6 +29,7 @@ import io.netty.util.internal.logging.InternalLogger;
|
|||||||
import io.netty.util.internal.logging.InternalLoggerFactory;
|
import io.netty.util.internal.logging.InternalLoggerFactory;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.nio.channels.FileChannel;
|
||||||
import java.nio.channels.Selector;
|
import java.nio.channels.Selector;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
|
|
||||||
@ -61,6 +65,19 @@ public final class Native {
|
|||||||
} catch (IOException ignore) {
|
} catch (IOException ignore) {
|
||||||
// Just ignore
|
// Just ignore
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Preload all classes that will be used in the OnLoad(...) function of JNI to eliminate the possiblity of a
|
||||||
|
// class-loader deadlock. This is a workaround for https://github.com/netty/netty/issues/11209.
|
||||||
|
|
||||||
|
// This needs to match all the classes that are loaded via NETTY_JNI_UTIL_LOAD_CLASS or looked up via
|
||||||
|
// NETTY_JNI_UTIL_FIND_CLASS.
|
||||||
|
ClassInitializerUtil.tryLoadClasses(Native.class,
|
||||||
|
// netty_epoll_linuxsocket
|
||||||
|
PeerCredentials.class, DefaultFileRegion.class, FileChannel.class, java.io.FileDescriptor.class,
|
||||||
|
// netty_epoll_native
|
||||||
|
NativeDatagramPacketArray.NativeDatagramPacket.class
|
||||||
|
);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// First, try calling a side-effect free JNI method to see if the library was already
|
// First, try calling a side-effect free JNI method to see if the library was already
|
||||||
// loaded by the application.
|
// loaded by the application.
|
||||||
|
@ -238,6 +238,8 @@ error:
|
|||||||
|
|
||||||
// JNI Method Registration Table End
|
// JNI Method Registration Table End
|
||||||
|
|
||||||
|
// IMPORTANT: If you add any NETTY_JNI_UTIL_LOAD_CLASS or NETTY_JNI_UTIL_FIND_CLASS calls you also need to update
|
||||||
|
// Native to reflect that.
|
||||||
jint netty_kqueue_bsdsocket_JNI_OnLoad(JNIEnv* env, const char* packagePrefix) {
|
jint netty_kqueue_bsdsocket_JNI_OnLoad(JNIEnv* env, const char* packagePrefix) {
|
||||||
int ret = JNI_ERR;
|
int ret = JNI_ERR;
|
||||||
char* nettyClassName = NULL;
|
char* nettyClassName = NULL;
|
||||||
|
@ -38,6 +38,8 @@ static const jint fixed_method_table_size = sizeof(fixed_method_table) / sizeof(
|
|||||||
|
|
||||||
// JNI Method Registration Table End
|
// JNI Method Registration Table End
|
||||||
|
|
||||||
|
// IMPORTANT: If you add any NETTY_JNI_UTIL_LOAD_CLASS or NETTY_JNI_UTIL_FIND_CLASS calls you also need to update
|
||||||
|
// Native to reflect that.
|
||||||
jint netty_kqueue_eventarray_JNI_OnLoad(JNIEnv* env, const char* packagePrefix) {
|
jint netty_kqueue_eventarray_JNI_OnLoad(JNIEnv* env, const char* packagePrefix) {
|
||||||
if (netty_jni_util_register_natives(env,
|
if (netty_jni_util_register_natives(env,
|
||||||
packagePrefix,
|
packagePrefix,
|
||||||
|
@ -281,6 +281,8 @@ static const JNINativeMethod fixed_method_table[] = {
|
|||||||
static const jint fixed_method_table_size = sizeof(fixed_method_table) / sizeof(fixed_method_table[0]);
|
static const jint fixed_method_table_size = sizeof(fixed_method_table) / sizeof(fixed_method_table[0]);
|
||||||
// JNI Method Registration Table End
|
// JNI Method Registration Table End
|
||||||
|
|
||||||
|
// IMPORTANT: If you add any NETTY_JNI_UTIL_LOAD_CLASS or NETTY_JNI_UTIL_FIND_CLASS calls you also need to update
|
||||||
|
// Native to reflect that.
|
||||||
static jint netty_kqueue_native_JNI_OnLoad(JNIEnv* env, const char* packagePrefix) {
|
static jint netty_kqueue_native_JNI_OnLoad(JNIEnv* env, const char* packagePrefix) {
|
||||||
int staticallyRegistered = 0;
|
int staticallyRegistered = 0;
|
||||||
int nativeRegistered = 0;
|
int nativeRegistered = 0;
|
||||||
|
@ -15,8 +15,11 @@
|
|||||||
*/
|
*/
|
||||||
package io.netty.channel.kqueue;
|
package io.netty.channel.kqueue;
|
||||||
|
|
||||||
|
import io.netty.channel.DefaultFileRegion;
|
||||||
import io.netty.channel.unix.FileDescriptor;
|
import io.netty.channel.unix.FileDescriptor;
|
||||||
|
import io.netty.channel.unix.PeerCredentials;
|
||||||
import io.netty.channel.unix.Unix;
|
import io.netty.channel.unix.Unix;
|
||||||
|
import io.netty.util.internal.ClassInitializerUtil;
|
||||||
import io.netty.util.internal.NativeLibraryLoader;
|
import io.netty.util.internal.NativeLibraryLoader;
|
||||||
import io.netty.util.internal.PlatformDependent;
|
import io.netty.util.internal.PlatformDependent;
|
||||||
import io.netty.util.internal.SystemPropertyUtil;
|
import io.netty.util.internal.SystemPropertyUtil;
|
||||||
@ -25,6 +28,7 @@ import io.netty.util.internal.logging.InternalLogger;
|
|||||||
import io.netty.util.internal.logging.InternalLoggerFactory;
|
import io.netty.util.internal.logging.InternalLoggerFactory;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.nio.channels.FileChannel;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
|
|
||||||
import static io.netty.channel.kqueue.KQueueStaticallyReferencedJniMethods.evAdd;
|
import static io.netty.channel.kqueue.KQueueStaticallyReferencedJniMethods.evAdd;
|
||||||
@ -51,6 +55,16 @@ final class Native {
|
|||||||
private static final InternalLogger logger = InternalLoggerFactory.getInstance(Native.class);
|
private static final InternalLogger logger = InternalLoggerFactory.getInstance(Native.class);
|
||||||
|
|
||||||
static {
|
static {
|
||||||
|
// Preload all classes that will be used in the OnLoad(...) function of JNI to eliminate the possiblity of a
|
||||||
|
// class-loader deadlock. This is a workaround for https://github.com/netty/netty/issues/11209.
|
||||||
|
|
||||||
|
// This needs to match all the classes that are loaded via NETTY_JNI_UTIL_LOAD_CLASS or looked up via
|
||||||
|
// NETTY_JNI_UTIL_FIND_CLASS.
|
||||||
|
ClassInitializerUtil.tryLoadClasses(Native.class,
|
||||||
|
// netty_kqueue_bsdsocket
|
||||||
|
PeerCredentials.class, DefaultFileRegion.class, FileChannel.class, java.io.FileDescriptor.class
|
||||||
|
);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// First, try calling a side-effect free JNI method to see if the library was already
|
// First, try calling a side-effect free JNI method to see if the library was already
|
||||||
// loaded by the application.
|
// loaded by the application.
|
||||||
|
@ -22,6 +22,8 @@
|
|||||||
#include "netty_unix_socket.h"
|
#include "netty_unix_socket.h"
|
||||||
#include "netty_unix_util.h"
|
#include "netty_unix_util.h"
|
||||||
|
|
||||||
|
// IMPORTANT: If you add any NETTY_JNI_UTIL_LOAD_CLASS or NETTY_JNI_UTIL_FIND_CLASS calls you also need to update
|
||||||
|
// Unix to reflect that.
|
||||||
jint netty_unix_register(JNIEnv* env, const char* packagePrefix) {
|
jint netty_unix_register(JNIEnv* env, const char* packagePrefix) {
|
||||||
int limitsOnLoadCalled = 0;
|
int limitsOnLoadCalled = 0;
|
||||||
int errorsOnLoadCalled = 0;
|
int errorsOnLoadCalled = 0;
|
||||||
|
@ -39,6 +39,8 @@ static const JNINativeMethod statically_referenced_fixed_method_table[] = {
|
|||||||
static const jint statically_referenced_fixed_method_table_size = sizeof(statically_referenced_fixed_method_table) / sizeof(statically_referenced_fixed_method_table[0]);
|
static const jint statically_referenced_fixed_method_table_size = sizeof(statically_referenced_fixed_method_table) / sizeof(statically_referenced_fixed_method_table[0]);
|
||||||
// JNI Method Registration Table End
|
// JNI Method Registration Table End
|
||||||
|
|
||||||
|
// IMPORTANT: If you add any NETTY_JNI_UTIL_LOAD_CLASS or NETTY_JNI_UTIL_FIND_CLASS calls you also need to update
|
||||||
|
// Unix to reflect that.
|
||||||
jint netty_unix_buffer_JNI_OnLoad(JNIEnv* env, const char* packagePrefix) {
|
jint netty_unix_buffer_JNI_OnLoad(JNIEnv* env, const char* packagePrefix) {
|
||||||
// We must register the statically referenced methods first!
|
// We must register the statically referenced methods first!
|
||||||
if (netty_jni_util_register_natives(env,
|
if (netty_jni_util_register_natives(env,
|
||||||
|
@ -212,6 +212,8 @@ static const JNINativeMethod statically_referenced_fixed_method_table[] = {
|
|||||||
static const jint statically_referenced_fixed_method_table_size = sizeof(statically_referenced_fixed_method_table) / sizeof(statically_referenced_fixed_method_table[0]);
|
static const jint statically_referenced_fixed_method_table_size = sizeof(statically_referenced_fixed_method_table) / sizeof(statically_referenced_fixed_method_table[0]);
|
||||||
// JNI Method Registration Table End
|
// JNI Method Registration Table End
|
||||||
|
|
||||||
|
// IMPORTANT: If you add any NETTY_JNI_UTIL_LOAD_CLASS or NETTY_JNI_UTIL_FIND_CLASS calls you also need to update
|
||||||
|
// Unix to reflect that.
|
||||||
jint netty_unix_errors_JNI_OnLoad(JNIEnv* env, const char* packagePrefix) {
|
jint netty_unix_errors_JNI_OnLoad(JNIEnv* env, const char* packagePrefix) {
|
||||||
char* nettyClassName = NULL;
|
char* nettyClassName = NULL;
|
||||||
// We must register the statically referenced methods first!
|
// We must register the statically referenced methods first!
|
||||||
|
@ -278,6 +278,8 @@ static const JNINativeMethod method_table[] = {
|
|||||||
static const jint method_table_size = sizeof(method_table) / sizeof(method_table[0]);
|
static const jint method_table_size = sizeof(method_table) / sizeof(method_table[0]);
|
||||||
// JNI Method Registration Table End
|
// JNI Method Registration Table End
|
||||||
|
|
||||||
|
// IMPORTANT: If you add any NETTY_JNI_UTIL_LOAD_CLASS or NETTY_JNI_UTIL_FIND_CLASS calls you also need to update
|
||||||
|
// Unix to reflect that.
|
||||||
jint netty_unix_filedescriptor_JNI_OnLoad(JNIEnv* env, const char* packagePrefix) {
|
jint netty_unix_filedescriptor_JNI_OnLoad(JNIEnv* env, const char* packagePrefix) {
|
||||||
int ret = JNI_ERR;
|
int ret = JNI_ERR;
|
||||||
void* mem = NULL;
|
void* mem = NULL;
|
||||||
|
@ -69,6 +69,8 @@ static const JNINativeMethod statically_referenced_fixed_method_table[] = {
|
|||||||
static const jint statically_referenced_fixed_method_table_size = sizeof(statically_referenced_fixed_method_table) / sizeof(statically_referenced_fixed_method_table[0]);
|
static const jint statically_referenced_fixed_method_table_size = sizeof(statically_referenced_fixed_method_table) / sizeof(statically_referenced_fixed_method_table[0]);
|
||||||
// JNI Method Registration Table End
|
// JNI Method Registration Table End
|
||||||
|
|
||||||
|
// IMPORTANT: If you add any NETTY_JNI_UTIL_LOAD_CLASS or NETTY_JNI_UTIL_FIND_CLASS calls you also need to update
|
||||||
|
// Unix to reflect that.
|
||||||
jint netty_unix_limits_JNI_OnLoad(JNIEnv* env, const char* packagePrefix) {
|
jint netty_unix_limits_JNI_OnLoad(JNIEnv* env, const char* packagePrefix) {
|
||||||
// We must register the statically referenced methods first!
|
// We must register the statically referenced methods first!
|
||||||
if (netty_jni_util_register_natives(env,
|
if (netty_jni_util_register_natives(env,
|
||||||
|
@ -1011,6 +1011,8 @@ error:
|
|||||||
|
|
||||||
// JNI Method Registration Table End
|
// JNI Method Registration Table End
|
||||||
|
|
||||||
|
// IMPORTANT: If you add any NETTY_JNI_UTIL_LOAD_CLASS or NETTY_JNI_UTIL_FIND_CLASS calls you also need to update
|
||||||
|
// Unix to reflect that.
|
||||||
jint netty_unix_socket_JNI_OnLoad(JNIEnv* env, const char* packagePrefix) {
|
jint netty_unix_socket_JNI_OnLoad(JNIEnv* env, const char* packagePrefix) {
|
||||||
int ret = JNI_ERR;
|
int ret = JNI_ERR;
|
||||||
char* nettyClassName = NULL;
|
char* nettyClassName = NULL;
|
||||||
|
@ -15,8 +15,13 @@
|
|||||||
*/
|
*/
|
||||||
package io.netty.channel.unix;
|
package io.netty.channel.unix;
|
||||||
|
|
||||||
|
import io.netty.util.internal.ClassInitializerUtil;
|
||||||
import io.netty.util.internal.UnstableApi;
|
import io.netty.util.internal.UnstableApi;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.net.InetSocketAddress;
|
||||||
|
import java.net.PortUnreachableException;
|
||||||
|
import java.nio.channels.ClosedChannelException;
|
||||||
import java.util.concurrent.atomic.AtomicBoolean;
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -26,6 +31,22 @@ import java.util.concurrent.atomic.AtomicBoolean;
|
|||||||
public final class Unix {
|
public final class Unix {
|
||||||
private static final AtomicBoolean registered = new AtomicBoolean();
|
private static final AtomicBoolean registered = new AtomicBoolean();
|
||||||
|
|
||||||
|
static {
|
||||||
|
// Preload all classes that will be used in the OnLoad(...) function of JNI to eliminate the possiblity of a
|
||||||
|
// class-loader deadlock. This is a workaround for https://github.com/netty/netty/issues/11209.
|
||||||
|
|
||||||
|
// This needs to match all the classes that are loaded via NETTY_JNI_UTIL_LOAD_CLASS or looked up via
|
||||||
|
// NETTY_JNI_UTIL_FIND_CLASS.
|
||||||
|
ClassInitializerUtil.tryLoadClasses(Unix.class,
|
||||||
|
// netty_unix_errors
|
||||||
|
OutOfMemoryError.class, RuntimeException.class, ClosedChannelException.class,
|
||||||
|
IOException.class, PortUnreachableException.class,
|
||||||
|
|
||||||
|
// netty_unix_socket
|
||||||
|
DatagramSocketAddress.class, InetSocketAddress.class
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Internal method... Should never be called from the user.
|
* Internal method... Should never be called from the user.
|
||||||
*
|
*
|
||||||
|
Loading…
Reference in New Issue
Block a user