Replace reflection usage with MethodHandles when performance matters (#10097)
Motivation: As we have java8 as a minimum target we can use MethodHandles. We should do so when we expect to have a method called multiple times. Modifications: - Replace usage of reflection with MethodHandles where it makes sense - Remove some code which was there to support java < 8 Result: Faster code
This commit is contained in:
parent
d639f55764
commit
fd0d06ee39
@ -20,7 +20,6 @@ import static java.util.Objects.requireNonNull;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.util.ByteProcessor;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.zip.Adler32;
|
||||
import java.util.zip.CRC32;
|
||||
@ -33,43 +32,34 @@ import java.util.zip.Checksum;
|
||||
* byte array ({@link ByteBuf#hasArray()} is {@code true}) or not.
|
||||
*/
|
||||
abstract class ByteBufChecksum implements Checksum {
|
||||
private static final Method ADLER32_UPDATE_METHOD;
|
||||
private static final Method CRC32_UPDATE_METHOD;
|
||||
|
||||
static {
|
||||
// See if we can use fast-path when using ByteBuf that is not heap based as Adler32 and CRC32 added support
|
||||
// for update(ByteBuffer) in JDK8.
|
||||
ADLER32_UPDATE_METHOD = updateByteBuffer(new Adler32());
|
||||
CRC32_UPDATE_METHOD = updateByteBuffer(new CRC32());
|
||||
}
|
||||
|
||||
private final ByteProcessor updateProcessor = value -> {
|
||||
update(value);
|
||||
return true;
|
||||
};
|
||||
|
||||
private static Method updateByteBuffer(Checksum checksum) {
|
||||
try {
|
||||
Method method = checksum.getClass().getDeclaredMethod("update", ByteBuffer.class);
|
||||
method.invoke(checksum, ByteBuffer.allocate(1));
|
||||
return method;
|
||||
} catch (Throwable ignore) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
static ByteBufChecksum wrapChecksum(Checksum checksum) {
|
||||
requireNonNull(checksum, "checksum");
|
||||
if (checksum instanceof ByteBufChecksum) {
|
||||
return (ByteBufChecksum) checksum;
|
||||
}
|
||||
if (checksum instanceof Adler32 && ADLER32_UPDATE_METHOD != null) {
|
||||
return new ReflectiveByteBufChecksum(checksum, ADLER32_UPDATE_METHOD);
|
||||
if (checksum instanceof Adler32) {
|
||||
return new OptimizedByteBufChecksum<Adler32>((Adler32) checksum) {
|
||||
@Override
|
||||
public void update(ByteBuffer b) {
|
||||
checksum.update(b);
|
||||
}
|
||||
};
|
||||
}
|
||||
if (checksum instanceof CRC32 && CRC32_UPDATE_METHOD != null) {
|
||||
return new ReflectiveByteBufChecksum(checksum, CRC32_UPDATE_METHOD);
|
||||
if (checksum instanceof CRC32) {
|
||||
return new OptimizedByteBufChecksum<CRC32>((CRC32) checksum) {
|
||||
@Override
|
||||
public void update(ByteBuffer b) {
|
||||
checksum.update(b);
|
||||
}
|
||||
};
|
||||
}
|
||||
return new SlowByteBufChecksum(checksum);
|
||||
return new SlowByteBufChecksum<>(checksum);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -83,12 +73,9 @@ abstract class ByteBufChecksum implements Checksum {
|
||||
}
|
||||
}
|
||||
|
||||
private static final class ReflectiveByteBufChecksum extends SlowByteBufChecksum {
|
||||
private final Method method;
|
||||
|
||||
ReflectiveByteBufChecksum(Checksum checksum, Method method) {
|
||||
private abstract static class OptimizedByteBufChecksum<T extends Checksum> extends SlowByteBufChecksum<T> {
|
||||
OptimizedByteBufChecksum(T checksum) {
|
||||
super(checksum);
|
||||
this.method = method;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -97,19 +84,21 @@ abstract class ByteBufChecksum implements Checksum {
|
||||
update(b.array(), b.arrayOffset() + off, len);
|
||||
} else {
|
||||
try {
|
||||
method.invoke(checksum, CompressionUtil.safeNioBuffer(b, off, len));
|
||||
update(CompressionUtil.safeNioBuffer(b, off, len));
|
||||
} catch (Throwable cause) {
|
||||
throw new Error();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public abstract void update(ByteBuffer b);
|
||||
}
|
||||
|
||||
private static class SlowByteBufChecksum extends ByteBufChecksum {
|
||||
private static class SlowByteBufChecksum<T extends Checksum> extends ByteBufChecksum {
|
||||
|
||||
protected final Checksum checksum;
|
||||
protected final T checksum;
|
||||
|
||||
SlowByteBufChecksum(Checksum checksum) {
|
||||
SlowByteBufChecksum(T checksum) {
|
||||
this.checksum = checksum;
|
||||
}
|
||||
|
||||
|
@ -18,8 +18,10 @@ package io.netty.util.internal;
|
||||
import io.netty.util.internal.logging.InternalLogger;
|
||||
import io.netty.util.internal.logging.InternalLoggerFactory;
|
||||
|
||||
import java.lang.invoke.MethodHandle;
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.lang.invoke.MethodType;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.security.AccessController;
|
||||
import java.security.PrivilegedAction;
|
||||
@ -33,15 +35,15 @@ import java.security.PrivilegedAction;
|
||||
*/
|
||||
final class CleanerJava6 implements Cleaner {
|
||||
private static final long CLEANER_FIELD_OFFSET;
|
||||
private static final Method CLEAN_METHOD;
|
||||
private static final Field CLEANER_FIELD;
|
||||
private static final MethodHandle CLEAN_HANDLE;
|
||||
private static final MethodHandle CLEANER_FIELD_HANDLE;
|
||||
|
||||
private static final InternalLogger logger = InternalLoggerFactory.getInstance(CleanerJava6.class);
|
||||
|
||||
static {
|
||||
long fieldOffset;
|
||||
Method clean;
|
||||
Field cleanerField;
|
||||
MethodHandle cleanHandle = null;
|
||||
MethodHandle cleanerFieldHandle = null;
|
||||
Throwable error = null;
|
||||
final ByteBuffer direct = ByteBuffer.allocateDirect(1);
|
||||
try {
|
||||
@ -62,7 +64,8 @@ final class CleanerJava6 implements Cleaner {
|
||||
throw (Throwable) mayBeCleanerField;
|
||||
}
|
||||
|
||||
cleanerField = (Field) mayBeCleanerField;
|
||||
Field cleanerField = (Field) mayBeCleanerField;
|
||||
MethodHandles.Lookup lookup = MethodHandles.lookup();
|
||||
|
||||
final Object cleaner;
|
||||
|
||||
@ -74,15 +77,16 @@ final class CleanerJava6 implements Cleaner {
|
||||
} else {
|
||||
fieldOffset = -1;
|
||||
cleaner = cleanerField.get(direct);
|
||||
cleanerFieldHandle = lookup.unreflectGetter(cleanerField);
|
||||
}
|
||||
clean = cleaner.getClass().getDeclaredMethod("clean");
|
||||
clean.invoke(cleaner);
|
||||
cleanHandle = lookup.findVirtual(cleaner.getClass(), "clean", MethodType.methodType(void.class));
|
||||
cleanHandle.invoke(cleaner);
|
||||
} catch (Throwable t) {
|
||||
// We don't have ByteBuffer.cleaner().
|
||||
fieldOffset = -1;
|
||||
clean = null;
|
||||
cleanerFieldHandle = null;
|
||||
cleanHandle = null;
|
||||
error = t;
|
||||
cleanerField = null;
|
||||
}
|
||||
|
||||
if (error == null) {
|
||||
@ -90,13 +94,13 @@ final class CleanerJava6 implements Cleaner {
|
||||
} else {
|
||||
logger.debug("java.nio.ByteBuffer.cleaner(): unavailable", error);
|
||||
}
|
||||
CLEANER_FIELD = cleanerField;
|
||||
CLEANER_FIELD_HANDLE = cleanerFieldHandle;
|
||||
CLEANER_FIELD_OFFSET = fieldOffset;
|
||||
CLEAN_METHOD = clean;
|
||||
CLEAN_HANDLE = cleanHandle;
|
||||
}
|
||||
|
||||
static boolean isSupported() {
|
||||
return CLEANER_FIELD_OFFSET != -1 || CLEANER_FIELD != null;
|
||||
return CLEANER_FIELD_OFFSET != -1 || CLEANER_FIELD_HANDLE != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -129,17 +133,17 @@ final class CleanerJava6 implements Cleaner {
|
||||
}
|
||||
}
|
||||
|
||||
private static void freeDirectBuffer0(ByteBuffer buffer) throws Exception {
|
||||
private static void freeDirectBuffer0(ByteBuffer buffer) throws Throwable {
|
||||
final Object cleaner;
|
||||
// If CLEANER_FIELD_OFFSET == -1 we need to use reflection to access the cleaner, otherwise we can use
|
||||
// sun.misc.Unsafe.
|
||||
if (CLEANER_FIELD_OFFSET == -1) {
|
||||
cleaner = CLEANER_FIELD.get(buffer);
|
||||
cleaner = CLEANER_FIELD_HANDLE.invoke(buffer);
|
||||
} else {
|
||||
cleaner = PlatformDependent0.getObject(buffer, CLEANER_FIELD_OFFSET);
|
||||
}
|
||||
if (cleaner != null) {
|
||||
CLEAN_METHOD.invoke(cleaner);
|
||||
CLEAN_HANDLE.invoke(cleaner);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -18,8 +18,10 @@ package io.netty.util.internal;
|
||||
import io.netty.util.internal.logging.InternalLogger;
|
||||
import io.netty.util.internal.logging.InternalLoggerFactory;
|
||||
|
||||
import java.lang.invoke.MethodHandle;
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.lang.invoke.MethodType;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.security.AccessController;
|
||||
import java.security.PrivilegedAction;
|
||||
@ -30,34 +32,40 @@ import java.security.PrivilegedAction;
|
||||
final class CleanerJava9 implements Cleaner {
|
||||
private static final InternalLogger logger = InternalLoggerFactory.getInstance(CleanerJava9.class);
|
||||
|
||||
private static final Method INVOKE_CLEANER;
|
||||
private static final MethodHandle INVOKE_CLEANER_HANDLE;
|
||||
|
||||
static {
|
||||
final Method method;
|
||||
final MethodHandle invokeCleanerHandle;
|
||||
final Throwable error;
|
||||
if (PlatformDependent0.hasUnsafe()) {
|
||||
final ByteBuffer buffer = ByteBuffer.allocateDirect(1);
|
||||
Object maybeInvokeMethod = AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
|
||||
Object maybeInvokeMethodHandle = AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
|
||||
try {
|
||||
MethodHandles.Lookup lookup = MethodHandles.lookup();
|
||||
// See https://bugs.openjdk.java.net/browse/JDK-8171377
|
||||
Method m = PlatformDependent0.UNSAFE.getClass().getDeclaredMethod(
|
||||
"invokeCleaner", ByteBuffer.class);
|
||||
m.invoke(PlatformDependent0.UNSAFE, buffer);
|
||||
MethodHandle m = lookup.findVirtual(
|
||||
PlatformDependent0.UNSAFE.getClass(),
|
||||
"invokeCleaner",
|
||||
MethodType.methodType(void.class, ByteBuffer.class)).bindTo(PlatformDependent0.UNSAFE);
|
||||
m.invokeExact(buffer);
|
||||
return m;
|
||||
} catch (NoSuchMethodException | InvocationTargetException | IllegalAccessException e) {
|
||||
return e;
|
||||
} catch (Throwable cause) {
|
||||
PlatformDependent0.throwException(cause);
|
||||
return cause;
|
||||
}
|
||||
});
|
||||
|
||||
if (maybeInvokeMethod instanceof Throwable) {
|
||||
method = null;
|
||||
error = (Throwable) maybeInvokeMethod;
|
||||
if (maybeInvokeMethodHandle instanceof Throwable) {
|
||||
invokeCleanerHandle = null;
|
||||
error = (Throwable) maybeInvokeMethodHandle;
|
||||
} else {
|
||||
method = (Method) maybeInvokeMethod;
|
||||
invokeCleanerHandle = (MethodHandle) maybeInvokeMethodHandle;
|
||||
error = null;
|
||||
}
|
||||
} else {
|
||||
method = null;
|
||||
invokeCleanerHandle = null;
|
||||
error = new UnsupportedOperationException("sun.misc.Unsafe unavailable");
|
||||
}
|
||||
if (error == null) {
|
||||
@ -65,11 +73,11 @@ final class CleanerJava9 implements Cleaner {
|
||||
} else {
|
||||
logger.debug("java.nio.ByteBuffer.cleaner(): unavailable", error);
|
||||
}
|
||||
INVOKE_CLEANER = method;
|
||||
INVOKE_CLEANER_HANDLE = invokeCleanerHandle;
|
||||
}
|
||||
|
||||
static boolean isSupported() {
|
||||
return INVOKE_CLEANER != null;
|
||||
return INVOKE_CLEANER_HANDLE != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -78,7 +86,7 @@ final class CleanerJava9 implements Cleaner {
|
||||
// See https://bugs.openjdk.java.net/browse/JDK-8191053.
|
||||
if (System.getSecurityManager() == null) {
|
||||
try {
|
||||
INVOKE_CLEANER.invoke(PlatformDependent0.UNSAFE, buffer);
|
||||
INVOKE_CLEANER_HANDLE.invokeExact(buffer);
|
||||
} catch (Throwable cause) {
|
||||
PlatformDependent0.throwException(cause);
|
||||
}
|
||||
@ -90,9 +98,11 @@ final class CleanerJava9 implements Cleaner {
|
||||
private static void freeDirectBufferPrivileged(final ByteBuffer buffer) {
|
||||
Exception error = AccessController.doPrivileged((PrivilegedAction<Exception>) () -> {
|
||||
try {
|
||||
INVOKE_CLEANER.invoke(PlatformDependent0.UNSAFE, buffer);
|
||||
INVOKE_CLEANER_HANDLE.invokeExact(PlatformDependent0.UNSAFE, buffer);
|
||||
} catch (InvocationTargetException | IllegalAccessException e) {
|
||||
return e;
|
||||
} catch (Throwable cause) {
|
||||
PlatformDependent.throwException(cause);
|
||||
}
|
||||
return null;
|
||||
});
|
||||
|
@ -19,6 +19,9 @@ import io.netty.util.internal.logging.InternalLogger;
|
||||
import io.netty.util.internal.logging.InternalLoggerFactory;
|
||||
import sun.misc.Unsafe;
|
||||
|
||||
import java.lang.invoke.MethodHandle;
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.lang.invoke.MethodType;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
@ -38,14 +41,13 @@ final class PlatformDependent0 {
|
||||
private static final InternalLogger logger = InternalLoggerFactory.getInstance(PlatformDependent0.class);
|
||||
private static final long ADDRESS_FIELD_OFFSET;
|
||||
private static final long BYTE_ARRAY_BASE_OFFSET;
|
||||
private static final Constructor<?> DIRECT_BUFFER_CONSTRUCTOR;
|
||||
private static final MethodHandle DIRECT_BUFFER_CONSTRUCTOR_HANDLE;
|
||||
private static final Throwable EXPLICIT_NO_UNSAFE_CAUSE = explicitNoUnsafeCause0();
|
||||
private static final Method ALLOCATE_ARRAY_METHOD;
|
||||
private static final MethodHandle ALLOCATE_ARRAY_HANDLE;
|
||||
private static final int JAVA_VERSION = javaVersion0();
|
||||
private static final boolean IS_ANDROID = isAndroid0();
|
||||
|
||||
private static final Throwable UNSAFE_UNAVAILABILITY_CAUSE;
|
||||
private static final Object INTERNAL_UNSAFE;
|
||||
private static final boolean IS_EXPLICIT_TRY_REFLECTION_SET_ACCESSIBLE = explicitTryReflectionSetAccessible0();
|
||||
|
||||
static final Unsafe UNSAFE;
|
||||
@ -66,16 +68,14 @@ final class PlatformDependent0 {
|
||||
static {
|
||||
final ByteBuffer direct;
|
||||
Field addressField = null;
|
||||
Method allocateArrayMethod = null;
|
||||
Throwable unsafeUnavailabilityCause = null;
|
||||
MethodHandle allocateArrayHandle = null;
|
||||
Throwable unsafeUnavailabilityCause;
|
||||
Unsafe unsafe;
|
||||
Object internalUnsafe = null;
|
||||
|
||||
if ((unsafeUnavailabilityCause = EXPLICIT_NO_UNSAFE_CAUSE) != null) {
|
||||
direct = null;
|
||||
addressField = null;
|
||||
unsafe = null;
|
||||
internalUnsafe = null;
|
||||
} else {
|
||||
direct = ByteBuffer.allocateDirect(1);
|
||||
|
||||
@ -189,13 +189,13 @@ final class PlatformDependent0 {
|
||||
ADDRESS_FIELD_OFFSET = -1;
|
||||
BYTE_ARRAY_BASE_OFFSET = -1;
|
||||
UNALIGNED = false;
|
||||
DIRECT_BUFFER_CONSTRUCTOR = null;
|
||||
ALLOCATE_ARRAY_METHOD = null;
|
||||
DIRECT_BUFFER_CONSTRUCTOR_HANDLE = null;
|
||||
ALLOCATE_ARRAY_HANDLE = null;
|
||||
} else {
|
||||
Constructor<?> directBufferConstructor;
|
||||
MethodHandle directBufferConstructorHandle;
|
||||
long address = -1;
|
||||
try {
|
||||
final Object maybeDirectBufferConstructor =
|
||||
final Object maybeDirectBufferConstructorHandle =
|
||||
AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
|
||||
try {
|
||||
final Constructor<?> constructor =
|
||||
@ -204,34 +204,34 @@ final class PlatformDependent0 {
|
||||
if (cause != null) {
|
||||
return cause;
|
||||
}
|
||||
return constructor;
|
||||
} catch (NoSuchMethodException | SecurityException e) {
|
||||
return MethodHandles.lookup().unreflectConstructor(constructor);
|
||||
} catch (NoSuchMethodException | SecurityException | IllegalAccessException e) {
|
||||
return e;
|
||||
}
|
||||
});
|
||||
|
||||
if (maybeDirectBufferConstructor instanceof Constructor<?>) {
|
||||
if (maybeDirectBufferConstructorHandle instanceof MethodHandle) {
|
||||
address = UNSAFE.allocateMemory(1);
|
||||
// try to use the constructor now
|
||||
try {
|
||||
((Constructor<?>) maybeDirectBufferConstructor).newInstance(address, 1);
|
||||
directBufferConstructor = (Constructor<?>) maybeDirectBufferConstructor;
|
||||
directBufferConstructorHandle = (MethodHandle) maybeDirectBufferConstructorHandle;
|
||||
directBufferConstructorHandle.invoke(address, 1);
|
||||
logger.debug("direct buffer constructor: available");
|
||||
} catch (InstantiationException | IllegalAccessException | InvocationTargetException e) {
|
||||
directBufferConstructor = null;
|
||||
} catch (Throwable ignore) {
|
||||
directBufferConstructorHandle = null;
|
||||
}
|
||||
} else {
|
||||
logger.debug(
|
||||
"direct buffer constructor: unavailable",
|
||||
(Throwable) maybeDirectBufferConstructor);
|
||||
directBufferConstructor = null;
|
||||
(Throwable) maybeDirectBufferConstructorHandle);
|
||||
directBufferConstructorHandle = null;
|
||||
}
|
||||
} finally {
|
||||
if (address != -1) {
|
||||
UNSAFE.freeMemory(address);
|
||||
}
|
||||
}
|
||||
DIRECT_BUFFER_CONSTRUCTOR = directBufferConstructor;
|
||||
DIRECT_BUFFER_CONSTRUCTOR_HANDLE = directBufferConstructorHandle;
|
||||
ADDRESS_FIELD_OFFSET = objectFieldOffset(addressField);
|
||||
BYTE_ARRAY_BASE_OFFSET = UNSAFE.arrayBaseOffset(byte[].class);
|
||||
final boolean unaligned;
|
||||
@ -300,24 +300,25 @@ final class PlatformDependent0 {
|
||||
}
|
||||
});
|
||||
if (!(maybeException instanceof Throwable)) {
|
||||
internalUnsafe = maybeException;
|
||||
final Object finalInternalUnsafe = internalUnsafe;
|
||||
final Object finalInternalUnsafe = maybeException;
|
||||
maybeException = AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
|
||||
try {
|
||||
return finalInternalUnsafe.getClass().getDeclaredMethod(
|
||||
"allocateUninitializedArray", Class.class, int.class);
|
||||
} catch (NoSuchMethodException | SecurityException e) {
|
||||
return MethodHandles.lookup().findVirtual(finalInternalUnsafe.getClass(),
|
||||
"allocateUninitializedArray",
|
||||
MethodType.methodType(byte[].class, Class.class, int.class))
|
||||
.bindTo(finalInternalUnsafe);
|
||||
} catch (NoSuchMethodException | SecurityException | IllegalAccessException e) {
|
||||
return e;
|
||||
}
|
||||
});
|
||||
|
||||
if (maybeException instanceof Method) {
|
||||
if (maybeException instanceof MethodHandle) {
|
||||
try {
|
||||
Method m = (Method) maybeException;
|
||||
MethodHandle m = (MethodHandle) maybeException;
|
||||
byte[] bytes = (byte[]) m.invoke(finalInternalUnsafe, byte.class, 8);
|
||||
assert bytes.length == 8;
|
||||
allocateArrayMethod = m;
|
||||
} catch (IllegalAccessException | InvocationTargetException e) {
|
||||
allocateArrayHandle = m;
|
||||
} catch (Throwable e) {
|
||||
maybeException = e;
|
||||
}
|
||||
}
|
||||
@ -332,13 +333,11 @@ final class PlatformDependent0 {
|
||||
} else {
|
||||
logger.debug("jdk.internal.misc.Unsafe.allocateUninitializedArray(int): unavailable prior to Java9");
|
||||
}
|
||||
ALLOCATE_ARRAY_METHOD = allocateArrayMethod;
|
||||
ALLOCATE_ARRAY_HANDLE = allocateArrayHandle;
|
||||
}
|
||||
|
||||
INTERNAL_UNSAFE = internalUnsafe;
|
||||
|
||||
logger.debug("java.nio.DirectByteBuffer.<init>(long, int): {}",
|
||||
DIRECT_BUFFER_CONSTRUCTOR != null ? "available" : "unavailable");
|
||||
DIRECT_BUFFER_CONSTRUCTOR_HANDLE != null ? "available" : "unavailable");
|
||||
}
|
||||
|
||||
static boolean isExplicitNoUnsafe() {
|
||||
@ -387,7 +386,7 @@ final class PlatformDependent0 {
|
||||
}
|
||||
|
||||
static boolean hasDirectBufferNoCleanerConstructor() {
|
||||
return DIRECT_BUFFER_CONSTRUCTOR != null;
|
||||
return DIRECT_BUFFER_CONSTRUCTOR_HANDLE != null;
|
||||
}
|
||||
|
||||
static ByteBuffer reallocateDirectNoCleaner(ByteBuffer buffer, int capacity) {
|
||||
@ -402,13 +401,16 @@ final class PlatformDependent0 {
|
||||
}
|
||||
|
||||
static boolean hasAllocateArrayMethod() {
|
||||
return ALLOCATE_ARRAY_METHOD != null;
|
||||
return ALLOCATE_ARRAY_HANDLE != null;
|
||||
}
|
||||
|
||||
static byte[] allocateUninitializedArray(int size) {
|
||||
try {
|
||||
return (byte[]) ALLOCATE_ARRAY_METHOD.invoke(INTERNAL_UNSAFE, byte.class, size);
|
||||
} catch (IllegalAccessException | InvocationTargetException e) {
|
||||
return (byte[]) ALLOCATE_ARRAY_HANDLE.invoke(byte.class, size);
|
||||
} catch (Throwable e) {
|
||||
if (e instanceof Error) {
|
||||
throw (Error) e;
|
||||
}
|
||||
throw new Error(e);
|
||||
}
|
||||
}
|
||||
@ -417,7 +419,7 @@ final class PlatformDependent0 {
|
||||
ObjectUtil.checkPositiveOrZero(capacity, "capacity");
|
||||
|
||||
try {
|
||||
return (ByteBuffer) DIRECT_BUFFER_CONSTRUCTOR.newInstance(address, capacity);
|
||||
return (ByteBuffer) DIRECT_BUFFER_CONSTRUCTOR_HANDLE.invoke(address, capacity);
|
||||
} catch (Throwable cause) {
|
||||
// Not expected to ever throw!
|
||||
if (cause instanceof Error) {
|
||||
|
@ -16,8 +16,9 @@
|
||||
package io.netty.handler.ssl;
|
||||
|
||||
import javax.net.ssl.SSLEngine;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.invoke.MethodHandle;
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.lang.invoke.MethodType;
|
||||
|
||||
/**
|
||||
* Contains methods that can be used to detect if conscrypt is usable.
|
||||
@ -25,14 +26,17 @@ import java.lang.reflect.Method;
|
||||
final class Conscrypt {
|
||||
// This class exists to avoid loading other conscrypt related classes using features only available in JDK8+,
|
||||
// because we need to maintain JDK6+ runtime compatibility.
|
||||
private static final Method IS_CONSCRYPT_SSLENGINE = loadIsConscryptEngine();
|
||||
private static final MethodHandle IS_CONSCRYPT_SSLENGINE = loadIsConscryptEngine();
|
||||
private static final boolean CAN_INSTANCE_PROVIDER = canInstanceProvider();
|
||||
|
||||
private static Method loadIsConscryptEngine() {
|
||||
private static MethodHandle loadIsConscryptEngine() {
|
||||
try {
|
||||
MethodHandles.Lookup lookup = MethodHandles.lookup();
|
||||
|
||||
Class<?> conscryptClass = Class.forName("org.conscrypt.Conscrypt", true,
|
||||
ConscryptAlpnSslEngine.class.getClassLoader());
|
||||
return conscryptClass.getMethod("isConscrypt", SSLEngine.class);
|
||||
return lookup.findStatic(conscryptClass, "isConscrypt",
|
||||
MethodType.methodType(boolean.class, SSLEngine.class));
|
||||
} catch (Throwable ignore) {
|
||||
// Conscrypt was not loaded.
|
||||
return null;
|
||||
@ -43,7 +47,8 @@ final class Conscrypt {
|
||||
try {
|
||||
Class<?> providerClass = Class.forName("org.conscrypt.OpenSSLProvider", true,
|
||||
ConscryptAlpnSslEngine.class.getClassLoader());
|
||||
providerClass.newInstance();
|
||||
MethodHandles.Lookup lookup = MethodHandles.lookup();
|
||||
lookup.findConstructor(providerClass, MethodType.methodType(void.class)).invoke();
|
||||
return true;
|
||||
} catch (Throwable ignore) {
|
||||
return false;
|
||||
@ -62,13 +67,16 @@ final class Conscrypt {
|
||||
}
|
||||
|
||||
private static boolean isConscryptEngine(SSLEngine engine) {
|
||||
try {
|
||||
return (Boolean) IS_CONSCRYPT_SSLENGINE.invoke(null, engine);
|
||||
} catch (IllegalAccessException ignore) {
|
||||
return false;
|
||||
} catch (InvocationTargetException ex) {
|
||||
throw new RuntimeException(ex);
|
||||
if (IS_CONSCRYPT_SSLENGINE != null) {
|
||||
try {
|
||||
return (boolean) IS_CONSCRYPT_SSLENGINE.invokeExact(engine);
|
||||
} catch (IllegalAccessException ignore) {
|
||||
return false;
|
||||
} catch (Throwable cause) {
|
||||
throw new RuntimeException(cause);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private Conscrypt() { }
|
||||
|
@ -19,7 +19,9 @@ package io.netty.handler.ssl;
|
||||
import javax.net.ssl.SSLContext;
|
||||
import javax.net.ssl.SSLEngine;
|
||||
import javax.net.ssl.SSLParameters;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.invoke.MethodHandle;
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.lang.invoke.MethodType;
|
||||
import java.security.AccessController;
|
||||
import java.security.PrivilegedExceptionAction;
|
||||
import java.util.List;
|
||||
@ -32,44 +34,52 @@ import io.netty.util.internal.logging.InternalLoggerFactory;
|
||||
|
||||
final class Java9SslUtils {
|
||||
private static final InternalLogger logger = InternalLoggerFactory.getInstance(Java9SslUtils.class);
|
||||
private static final Method SET_APPLICATION_PROTOCOLS;
|
||||
private static final Method GET_APPLICATION_PROTOCOL;
|
||||
private static final Method GET_HANDSHAKE_APPLICATION_PROTOCOL;
|
||||
private static final Method SET_HANDSHAKE_APPLICATION_PROTOCOL_SELECTOR;
|
||||
private static final Method GET_HANDSHAKE_APPLICATION_PROTOCOL_SELECTOR;
|
||||
private static final MethodHandle SET_APPLICATION_PROTOCOLS;
|
||||
private static final MethodHandle GET_APPLICATION_PROTOCOL;
|
||||
private static final MethodHandle GET_HANDSHAKE_APPLICATION_PROTOCOL;
|
||||
private static final MethodHandle SET_HANDSHAKE_APPLICATION_PROTOCOL_SELECTOR;
|
||||
private static final MethodHandle GET_HANDSHAKE_APPLICATION_PROTOCOL_SELECTOR;
|
||||
|
||||
static {
|
||||
Method getHandshakeApplicationProtocol = null;
|
||||
Method getApplicationProtocol = null;
|
||||
Method setApplicationProtocols = null;
|
||||
Method setHandshakeApplicationProtocolSelector = null;
|
||||
Method getHandshakeApplicationProtocolSelector = null;
|
||||
MethodHandle getHandshakeApplicationProtocol;
|
||||
MethodHandle getApplicationProtocol;
|
||||
MethodHandle setApplicationProtocols;
|
||||
MethodHandle setHandshakeApplicationProtocolSelector;
|
||||
MethodHandle getHandshakeApplicationProtocolSelector;
|
||||
|
||||
try {
|
||||
SSLContext context = SSLContext.getInstance(JdkSslContext.PROTOCOL);
|
||||
context.init(null, null, null);
|
||||
SSLEngine engine = context.createSSLEngine();
|
||||
getHandshakeApplicationProtocol = AccessController.doPrivileged((PrivilegedExceptionAction<Method>) () ->
|
||||
SSLEngine.class.getMethod("getHandshakeApplicationProtocol"));
|
||||
getHandshakeApplicationProtocol.invoke(engine);
|
||||
getApplicationProtocol = AccessController.doPrivileged((PrivilegedExceptionAction<Method>) () ->
|
||||
SSLEngine.class.getMethod("getApplicationProtocol"));
|
||||
getApplicationProtocol.invoke(engine);
|
||||
MethodHandles.Lookup lookup = MethodHandles.lookup();
|
||||
getHandshakeApplicationProtocol =
|
||||
AccessController.doPrivileged((PrivilegedExceptionAction<MethodHandle>) () ->
|
||||
lookup.findVirtual(SSLEngine.class, "getHandshakeApplicationProtocol",
|
||||
MethodType.methodType(String.class)));
|
||||
getHandshakeApplicationProtocol.invokeExact(engine);
|
||||
|
||||
setApplicationProtocols = AccessController.doPrivileged((PrivilegedExceptionAction<Method>) () ->
|
||||
SSLParameters.class.getMethod("setApplicationProtocols", String[].class));
|
||||
setApplicationProtocols.invoke(engine.getSSLParameters(), new Object[]{EmptyArrays.EMPTY_STRINGS});
|
||||
getApplicationProtocol = AccessController.doPrivileged((PrivilegedExceptionAction<MethodHandle>) () ->
|
||||
lookup.findVirtual(SSLEngine.class, "getApplicationProtocol",
|
||||
MethodType.methodType(String.class)));
|
||||
getApplicationProtocol.invokeExact(engine);
|
||||
|
||||
setApplicationProtocols = AccessController.doPrivileged((PrivilegedExceptionAction<MethodHandle>) () ->
|
||||
lookup.findVirtual(SSLParameters.class, "setApplicationProtocols",
|
||||
MethodType.methodType(void.class, String[].class)));
|
||||
setApplicationProtocols.invokeExact(engine.getSSLParameters(), EmptyArrays.EMPTY_STRINGS);
|
||||
|
||||
setHandshakeApplicationProtocolSelector =
|
||||
AccessController.doPrivileged((PrivilegedExceptionAction<Method>) () ->
|
||||
SSLEngine.class.getMethod("setHandshakeApplicationProtocolSelector", BiFunction.class));
|
||||
setHandshakeApplicationProtocolSelector.invoke(engine,
|
||||
AccessController.doPrivileged((PrivilegedExceptionAction<MethodHandle>) () ->
|
||||
lookup.findVirtual(SSLEngine.class, "setHandshakeApplicationProtocolSelector",
|
||||
MethodType.methodType(void.class, BiFunction.class)));
|
||||
setHandshakeApplicationProtocolSelector.invokeExact(engine,
|
||||
(BiFunction<SSLEngine, List<String>, String>) (sslEngine, strings) -> null);
|
||||
|
||||
getHandshakeApplicationProtocolSelector =
|
||||
AccessController.doPrivileged((PrivilegedExceptionAction<Method>) () ->
|
||||
SSLEngine.class.getMethod("getHandshakeApplicationProtocolSelector"));
|
||||
getHandshakeApplicationProtocolSelector.invoke(engine);
|
||||
AccessController.doPrivileged((PrivilegedExceptionAction<MethodHandle>) () ->
|
||||
lookup.findVirtual(SSLEngine.class, "getHandshakeApplicationProtocolSelector",
|
||||
MethodType.methodType(BiFunction.class)));
|
||||
getHandshakeApplicationProtocolSelector.invokeExact(engine);
|
||||
} catch (Throwable t) {
|
||||
logger.error("Unable to initialize Java9SslUtils, but the detected javaVersion was: {}",
|
||||
PlatformDependent.javaVersion(), t);
|
||||
@ -95,20 +105,20 @@ final class Java9SslUtils {
|
||||
|
||||
static String getApplicationProtocol(SSLEngine sslEngine) {
|
||||
try {
|
||||
return (String) GET_APPLICATION_PROTOCOL.invoke(sslEngine);
|
||||
return (String) GET_APPLICATION_PROTOCOL.invokeExact(sslEngine);
|
||||
} catch (UnsupportedOperationException ex) {
|
||||
throw ex;
|
||||
} catch (Exception ex) {
|
||||
} catch (Throwable ex) {
|
||||
throw new IllegalStateException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
static String getHandshakeApplicationProtocol(SSLEngine sslEngine) {
|
||||
try {
|
||||
return (String) GET_HANDSHAKE_APPLICATION_PROTOCOL.invoke(sslEngine);
|
||||
return (String) GET_HANDSHAKE_APPLICATION_PROTOCOL.invokeExact(sslEngine);
|
||||
} catch (UnsupportedOperationException ex) {
|
||||
throw ex;
|
||||
} catch (Exception ex) {
|
||||
} catch (Throwable ex) {
|
||||
throw new IllegalStateException(ex);
|
||||
}
|
||||
}
|
||||
@ -118,10 +128,10 @@ final class Java9SslUtils {
|
||||
|
||||
String[] protocolArray = supportedProtocols.toArray(EmptyArrays.EMPTY_STRINGS);
|
||||
try {
|
||||
SET_APPLICATION_PROTOCOLS.invoke(parameters, new Object[]{protocolArray});
|
||||
SET_APPLICATION_PROTOCOLS.invokeExact(parameters, protocolArray);
|
||||
} catch (UnsupportedOperationException ex) {
|
||||
throw ex;
|
||||
} catch (Exception ex) {
|
||||
} catch (Throwable ex) {
|
||||
throw new IllegalStateException(ex);
|
||||
}
|
||||
engine.setSSLParameters(parameters);
|
||||
@ -130,21 +140,22 @@ final class Java9SslUtils {
|
||||
static void setHandshakeApplicationProtocolSelector(
|
||||
SSLEngine engine, BiFunction<SSLEngine, List<String>, String> selector) {
|
||||
try {
|
||||
SET_HANDSHAKE_APPLICATION_PROTOCOL_SELECTOR.invoke(engine, selector);
|
||||
SET_HANDSHAKE_APPLICATION_PROTOCOL_SELECTOR.invokeExact(engine, selector);
|
||||
} catch (UnsupportedOperationException ex) {
|
||||
throw ex;
|
||||
} catch (Exception ex) {
|
||||
} catch (Throwable ex) {
|
||||
throw new IllegalStateException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
static BiFunction<SSLEngine, List<String>, String> getHandshakeApplicationProtocolSelector(SSLEngine engine) {
|
||||
try {
|
||||
return (BiFunction<SSLEngine, List<String>, String>)
|
||||
GET_HANDSHAKE_APPLICATION_PROTOCOL_SELECTOR.invoke(engine);
|
||||
GET_HANDSHAKE_APPLICATION_PROTOCOL_SELECTOR.invokeExact(engine);
|
||||
} catch (UnsupportedOperationException ex) {
|
||||
throw ex;
|
||||
} catch (Exception ex) {
|
||||
} catch (Throwable ex) {
|
||||
throw new IllegalStateException(ex);
|
||||
}
|
||||
}
|
||||
|
5
pom.xml
5
pom.xml
@ -810,6 +810,11 @@
|
||||
<version>1.0</version>
|
||||
</signature>
|
||||
<ignores>
|
||||
<!--
|
||||
We need to whitelist MethodHandle as animal-sniffer can not handle it correctly
|
||||
https://github.com/mojohaus/animal-sniffer/issues/67
|
||||
-->
|
||||
<ignore>java.lang.invoke.MethodHandle</ignore>
|
||||
<ignore>sun.misc.Unsafe</ignore>
|
||||
<ignore>sun.misc.Cleaner</ignore>
|
||||
<ignore>sun.nio.ch.DirectBuffer</ignore>
|
||||
|
@ -19,7 +19,9 @@ import io.netty.util.internal.PlatformDependent;
|
||||
import io.netty.util.internal.logging.InternalLogger;
|
||||
import io.netty.util.internal.logging.InternalLoggerFactory;
|
||||
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.invoke.MethodHandle;
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.lang.invoke.MethodType;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.security.AccessController;
|
||||
@ -34,10 +36,10 @@ public final class DnsServerAddressStreamProviders {
|
||||
|
||||
private static final InternalLogger LOGGER =
|
||||
InternalLoggerFactory.getInstance(DnsServerAddressStreamProviders.class);
|
||||
private static final Constructor<? extends DnsServerAddressStreamProvider> STREAM_PROVIDER_CONSTRUCTOR;
|
||||
private static final MethodHandle STREAM_PROVIDER_CONSTRUCTOR_HANDLE;
|
||||
|
||||
static {
|
||||
Constructor<? extends DnsServerAddressStreamProvider> constructor = null;
|
||||
MethodHandle constructorHandle = null;
|
||||
if (PlatformDependent.isOsx()) {
|
||||
try {
|
||||
// As MacOSDnsServerAddressStreamProvider is contained in another jar which depends on this jar
|
||||
@ -56,20 +58,22 @@ public final class DnsServerAddressStreamProviders {
|
||||
@SuppressWarnings("unchecked")
|
||||
Class<? extends DnsServerAddressStreamProvider> providerClass =
|
||||
(Class<? extends DnsServerAddressStreamProvider>) maybeProvider;
|
||||
|
||||
MethodHandles.Lookup lookup = MethodHandles.lookup();
|
||||
Method method = providerClass.getMethod("ensureAvailability");
|
||||
method.invoke(null);
|
||||
constructor = providerClass.getConstructor();
|
||||
constructor.newInstance();
|
||||
constructorHandle = lookup.findConstructor(providerClass, MethodType.methodType(void.class));
|
||||
constructorHandle.invoke();
|
||||
} else if (!(maybeProvider instanceof ClassNotFoundException)) {
|
||||
throw (Throwable) maybeProvider;
|
||||
}
|
||||
} catch (Throwable cause) {
|
||||
LOGGER.debug(
|
||||
"Unable to use MacOSDnsServerAddressStreamProvider, fallback to system defaults", cause);
|
||||
constructor = null;
|
||||
constructorHandle = null;
|
||||
}
|
||||
}
|
||||
STREAM_PROVIDER_CONSTRUCTOR = constructor;
|
||||
STREAM_PROVIDER_CONSTRUCTOR_HANDLE = constructorHandle;
|
||||
}
|
||||
|
||||
private DnsServerAddressStreamProviders() {
|
||||
@ -83,11 +87,13 @@ public final class DnsServerAddressStreamProviders {
|
||||
* configuration.
|
||||
*/
|
||||
public static DnsServerAddressStreamProvider platformDefault() {
|
||||
if (STREAM_PROVIDER_CONSTRUCTOR != null) {
|
||||
if (STREAM_PROVIDER_CONSTRUCTOR_HANDLE != null) {
|
||||
try {
|
||||
return STREAM_PROVIDER_CONSTRUCTOR.newInstance();
|
||||
return (DnsServerAddressStreamProvider) STREAM_PROVIDER_CONSTRUCTOR_HANDLE.invoke();
|
||||
} catch (IllegalAccessException | InstantiationException | InvocationTargetException e) {
|
||||
// ignore
|
||||
} catch (Throwable cause) {
|
||||
PlatformDependent.throwException(cause);
|
||||
}
|
||||
}
|
||||
return unixDefault();
|
||||
|
Binary file not shown.
@ -19,13 +19,13 @@ import io.netty.channel.ChannelException;
|
||||
import io.netty.channel.ChannelOption;
|
||||
import io.netty.channel.socket.DatagramChannelConfig;
|
||||
import io.netty.channel.socket.DefaultDatagramChannelConfig;
|
||||
import io.netty.util.internal.PlatformDependent;
|
||||
import io.netty.util.internal.SocketUtils;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.io.IOException;
|
||||
import java.net.InetAddress;
|
||||
import java.net.NetworkInterface;
|
||||
import java.net.SocketException;
|
||||
import java.net.StandardSocketOptions;
|
||||
import java.nio.channels.DatagramChannel;
|
||||
import java.util.Enumeration;
|
||||
import java.util.Map;
|
||||
@ -35,82 +35,6 @@ import java.util.Map;
|
||||
*/
|
||||
class NioDatagramChannelConfig extends DefaultDatagramChannelConfig {
|
||||
|
||||
private static final Object IP_MULTICAST_TTL;
|
||||
private static final Object IP_MULTICAST_IF;
|
||||
private static final Object IP_MULTICAST_LOOP;
|
||||
private static final Method GET_OPTION;
|
||||
private static final Method SET_OPTION;
|
||||
|
||||
static {
|
||||
ClassLoader classLoader = PlatformDependent.getClassLoader(DatagramChannel.class);
|
||||
Class<?> socketOptionType = null;
|
||||
try {
|
||||
socketOptionType = Class.forName("java.net.SocketOption", true, classLoader);
|
||||
} catch (Exception e) {
|
||||
// Not Java 7+
|
||||
}
|
||||
Class<?> stdSocketOptionType = null;
|
||||
try {
|
||||
stdSocketOptionType = Class.forName("java.net.StandardSocketOptions", true, classLoader);
|
||||
} catch (Exception e) {
|
||||
// Not Java 7+
|
||||
}
|
||||
|
||||
Object ipMulticastTtl = null;
|
||||
Object ipMulticastIf = null;
|
||||
Object ipMulticastLoop = null;
|
||||
Method getOption = null;
|
||||
Method setOption = null;
|
||||
if (socketOptionType != null) {
|
||||
try {
|
||||
ipMulticastTtl = stdSocketOptionType.getDeclaredField("IP_MULTICAST_TTL").get(null);
|
||||
} catch (Exception e) {
|
||||
throw new Error("cannot locate the IP_MULTICAST_TTL field", e);
|
||||
}
|
||||
|
||||
try {
|
||||
ipMulticastIf = stdSocketOptionType.getDeclaredField("IP_MULTICAST_IF").get(null);
|
||||
} catch (Exception e) {
|
||||
throw new Error("cannot locate the IP_MULTICAST_IF field", e);
|
||||
}
|
||||
|
||||
try {
|
||||
ipMulticastLoop = stdSocketOptionType.getDeclaredField("IP_MULTICAST_LOOP").get(null);
|
||||
} catch (Exception e) {
|
||||
throw new Error("cannot locate the IP_MULTICAST_LOOP field", e);
|
||||
}
|
||||
|
||||
Class<?> networkChannelClass = null;
|
||||
try {
|
||||
networkChannelClass = Class.forName("java.nio.channels.NetworkChannel", true, classLoader);
|
||||
} catch (Throwable ignore) {
|
||||
// Not Java 7+
|
||||
}
|
||||
|
||||
if (networkChannelClass == null) {
|
||||
getOption = null;
|
||||
setOption = null;
|
||||
} else {
|
||||
try {
|
||||
getOption = networkChannelClass.getDeclaredMethod("getOption", socketOptionType);
|
||||
} catch (Exception e) {
|
||||
throw new Error("cannot locate the getOption() method", e);
|
||||
}
|
||||
|
||||
try {
|
||||
setOption = networkChannelClass.getDeclaredMethod("setOption", socketOptionType, Object.class);
|
||||
} catch (Exception e) {
|
||||
throw new Error("cannot locate the setOption() method", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
IP_MULTICAST_TTL = ipMulticastTtl;
|
||||
IP_MULTICAST_IF = ipMulticastIf;
|
||||
IP_MULTICAST_LOOP = ipMulticastLoop;
|
||||
GET_OPTION = getOption;
|
||||
SET_OPTION = setOption;
|
||||
}
|
||||
|
||||
private final DatagramChannel javaChannel;
|
||||
|
||||
NioDatagramChannelConfig(NioDatagramChannel channel, DatagramChannel javaChannel) {
|
||||
@ -120,13 +44,21 @@ class NioDatagramChannelConfig extends DefaultDatagramChannelConfig {
|
||||
|
||||
@Override
|
||||
public int getTimeToLive() {
|
||||
return (Integer) getOption0(IP_MULTICAST_TTL);
|
||||
try {
|
||||
return javaChannel.getOption(StandardSocketOptions.IP_MULTICAST_TTL);
|
||||
} catch (IOException e) {
|
||||
throw new ChannelException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public DatagramChannelConfig setTimeToLive(int ttl) {
|
||||
setOption0(IP_MULTICAST_TTL, ttl);
|
||||
return this;
|
||||
try {
|
||||
javaChannel.setOption(StandardSocketOptions.IP_MULTICAST_TTL, ttl);
|
||||
return this;
|
||||
} catch (IOException e) {
|
||||
throw new ChannelException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -153,24 +85,40 @@ class NioDatagramChannelConfig extends DefaultDatagramChannelConfig {
|
||||
|
||||
@Override
|
||||
public NetworkInterface getNetworkInterface() {
|
||||
return (NetworkInterface) getOption0(IP_MULTICAST_IF);
|
||||
try {
|
||||
return javaChannel.getOption(StandardSocketOptions.IP_MULTICAST_IF);
|
||||
} catch (IOException e) {
|
||||
throw new ChannelException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public DatagramChannelConfig setNetworkInterface(NetworkInterface networkInterface) {
|
||||
setOption0(IP_MULTICAST_IF, networkInterface);
|
||||
return this;
|
||||
try {
|
||||
javaChannel.setOption(StandardSocketOptions.IP_MULTICAST_IF, networkInterface);
|
||||
return this;
|
||||
} catch (IOException e) {
|
||||
throw new ChannelException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isLoopbackModeDisabled() {
|
||||
return (Boolean) getOption0(IP_MULTICAST_LOOP);
|
||||
try {
|
||||
return javaChannel.getOption(StandardSocketOptions.IP_MULTICAST_LOOP);
|
||||
} catch (IOException e) {
|
||||
throw new ChannelException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public DatagramChannelConfig setLoopbackModeDisabled(boolean loopbackModeDisabled) {
|
||||
setOption0(IP_MULTICAST_LOOP, loopbackModeDisabled);
|
||||
return this;
|
||||
try {
|
||||
javaChannel.setOption(StandardSocketOptions.IP_MULTICAST_LOOP, loopbackModeDisabled);
|
||||
return this;
|
||||
} catch (IOException e) {
|
||||
throw new ChannelException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -184,30 +132,6 @@ class NioDatagramChannelConfig extends DefaultDatagramChannelConfig {
|
||||
((NioDatagramChannel) channel).clearReadPending0();
|
||||
}
|
||||
|
||||
private Object getOption0(Object option) {
|
||||
if (GET_OPTION == null) {
|
||||
throw new UnsupportedOperationException();
|
||||
} else {
|
||||
try {
|
||||
return GET_OPTION.invoke(javaChannel, option);
|
||||
} catch (Exception e) {
|
||||
throw new ChannelException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void setOption0(Object option, Object value) {
|
||||
if (SET_OPTION == null) {
|
||||
throw new UnsupportedOperationException();
|
||||
} else {
|
||||
try {
|
||||
SET_OPTION.invoke(javaChannel, option, value);
|
||||
} catch (Exception e) {
|
||||
throw new ChannelException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> boolean setOption(ChannelOption<T> option, T value) {
|
||||
if (option instanceof NioChannelOption) {
|
||||
|
Loading…
Reference in New Issue
Block a user