From 9bbe25fc9078bcef42326365a867451c53b038e7 Mon Sep 17 00:00:00 2001 From: Andrew Steinborn Date: Fri, 28 Dec 2018 13:02:41 -0500 Subject: [PATCH] Improve efficiency of Java implementation of natives. --- native/build.gradle | 2 +- .../encryption/JavaVelocityCipher.java | 39 ++++++++++++++++--- .../encryption/NativeVelocityCipher.java | 13 +++++++ .../natives/encryption/VelocityCipher.java | 3 ++ .../natives/util/NativeCodeLoader.java | 6 --- .../natives/util/NativeConstraints.java | 19 +++++++++ .../velocitypowered/natives/util/Natives.java | 8 ++-- .../netty/MinecraftCipherDecoder.java | 9 +---- 8 files changed, 74 insertions(+), 25 deletions(-) create mode 100644 native/src/main/java/com/velocitypowered/natives/util/NativeConstraints.java diff --git a/native/build.gradle b/native/build.gradle index ced801284..00b298325 100644 --- a/native/build.gradle +++ b/native/build.gradle @@ -8,7 +8,7 @@ apply from: '../gradle/checkstyle.gradle' dependencies { compile "com.google.guava:guava:${guavaVersion}" - compile "io.netty:netty-buffer:${nettyVersion}" + compile "io.netty:netty-handler:${nettyVersion}" compile "org.checkerframework:checker-qual:${checkerFrameworkVersion}" testCompile "org.junit.jupiter:junit-jupiter-api:${junitVersion}" diff --git a/native/src/main/java/com/velocitypowered/natives/encryption/JavaVelocityCipher.java b/native/src/main/java/com/velocitypowered/natives/encryption/JavaVelocityCipher.java index d446c92a4..75e16922f 100644 --- a/native/src/main/java/com/velocitypowered/natives/encryption/JavaVelocityCipher.java +++ b/native/src/main/java/com/velocitypowered/natives/encryption/JavaVelocityCipher.java @@ -2,6 +2,7 @@ package com.velocitypowered.natives.encryption; import com.google.common.base.Preconditions; import io.netty.buffer.ByteBuf; +import io.netty.channel.ChannelHandlerContext; import java.security.GeneralSecurityException; import javax.crypto.Cipher; import javax.crypto.SecretKey; @@ -21,6 +22,9 @@ public class JavaVelocityCipher implements VelocityCipher { return new JavaVelocityCipher(false, key); } }; + private static final int INITIAL_BUFFER_SIZE = 1024 * 16; + private static final ThreadLocal inBufLocal = ThreadLocal.withInitial( + () -> new byte[INITIAL_BUFFER_SIZE]); private final Cipher cipher; private boolean disposed = false; @@ -35,13 +39,36 @@ public class JavaVelocityCipher implements VelocityCipher { public void process(ByteBuf source, ByteBuf destination) throws ShortBufferException { ensureNotDisposed(); - byte[] sourceAsBytes = new byte[source.readableBytes()]; - source.readBytes(sourceAsBytes); + int inBytes = source.readableBytes(); + byte[] inBuf = slurp(source); - int outputSize = cipher.getOutputSize(sourceAsBytes.length); - byte[] destinationBytes = new byte[outputSize]; - cipher.update(sourceAsBytes, 0, sourceAsBytes.length, destinationBytes); - destination.writeBytes(destinationBytes); + int outputSize = cipher.getOutputSize(inBytes); + byte[] outBuf = new byte[outputSize]; + cipher.update(inBuf, 0, inBytes, outBuf); + destination.writeBytes(outBuf); + } + + @Override + public ByteBuf process(ChannelHandlerContext ctx, ByteBuf source) throws ShortBufferException { + ensureNotDisposed(); + + int inBytes = source.readableBytes(); + byte[] inBuf = slurp(source); + + ByteBuf out = ctx.alloc().heapBuffer(cipher.getOutputSize(inBytes)); + out.writerIndex(cipher.update(inBuf, 0, inBytes, out.array(), out.arrayOffset())); + return out; + } + + private static byte[] slurp(ByteBuf source) { + int inBytes = source.readableBytes(); + byte[] inBuf = inBufLocal.get(); + if (inBuf.length <= inBytes) { + inBuf = new byte[inBytes]; + inBufLocal.set(inBuf); + } + source.readBytes(inBuf, 0, inBytes); + return inBuf; } @Override diff --git a/native/src/main/java/com/velocitypowered/natives/encryption/NativeVelocityCipher.java b/native/src/main/java/com/velocitypowered/natives/encryption/NativeVelocityCipher.java index 81e778264..eaafadbfd 100644 --- a/native/src/main/java/com/velocitypowered/natives/encryption/NativeVelocityCipher.java +++ b/native/src/main/java/com/velocitypowered/natives/encryption/NativeVelocityCipher.java @@ -1,6 +1,7 @@ package com.velocitypowered.natives.encryption; import io.netty.buffer.ByteBuf; +import io.netty.channel.ChannelHandlerContext; import java.security.GeneralSecurityException; import javax.crypto.SecretKey; import javax.crypto.ShortBufferException; @@ -45,6 +46,18 @@ public class NativeVelocityCipher implements VelocityCipher { destination.writerIndex(destination.writerIndex() + len); } + @Override + public ByteBuf process(ChannelHandlerContext ctx, ByteBuf source) throws ShortBufferException { + ByteBuf out = ctx.alloc().directBuffer(source.readableBytes()); + try { + process(source, out); + return out; + } catch (Exception e) { + out.release(); + throw e; + } + } + @Override public void dispose() { if (!disposed) { diff --git a/native/src/main/java/com/velocitypowered/natives/encryption/VelocityCipher.java b/native/src/main/java/com/velocitypowered/natives/encryption/VelocityCipher.java index 31dbeaa97..6b7317bc5 100644 --- a/native/src/main/java/com/velocitypowered/natives/encryption/VelocityCipher.java +++ b/native/src/main/java/com/velocitypowered/natives/encryption/VelocityCipher.java @@ -2,9 +2,12 @@ package com.velocitypowered.natives.encryption; import com.velocitypowered.natives.Disposable; import io.netty.buffer.ByteBuf; +import io.netty.channel.ChannelHandlerContext; import javax.crypto.ShortBufferException; public interface VelocityCipher extends Disposable { void process(ByteBuf source, ByteBuf destination) throws ShortBufferException; + + ByteBuf process(ChannelHandlerContext ctx, ByteBuf source) throws ShortBufferException; } diff --git a/native/src/main/java/com/velocitypowered/natives/util/NativeCodeLoader.java b/native/src/main/java/com/velocitypowered/natives/util/NativeCodeLoader.java index 060de76a0..494b352ad 100644 --- a/native/src/main/java/com/velocitypowered/natives/util/NativeCodeLoader.java +++ b/native/src/main/java/com/velocitypowered/natives/util/NativeCodeLoader.java @@ -75,11 +75,5 @@ public final class NativeCodeLoader implements Supplier { SETUP_FAILURE } - static final BooleanSupplier MACOS = () -> - System.getProperty("os.name", "").equalsIgnoreCase("Mac OS X") - && System.getProperty("os.arch").equals("x86_64"); - static final BooleanSupplier LINUX = () -> - System.getProperties().getProperty("os.name", "").equalsIgnoreCase("Linux") - && System.getProperty("os.arch").equals("amd64"); static final BooleanSupplier ALWAYS = () -> true; } diff --git a/native/src/main/java/com/velocitypowered/natives/util/NativeConstraints.java b/native/src/main/java/com/velocitypowered/natives/util/NativeConstraints.java new file mode 100644 index 000000000..089690d30 --- /dev/null +++ b/native/src/main/java/com/velocitypowered/natives/util/NativeConstraints.java @@ -0,0 +1,19 @@ +package com.velocitypowered.natives.util; + +import java.util.function.BooleanSupplier; + +public class NativeConstraints { + private static final boolean NATIVES_ENABLED = !Boolean.getBoolean("velocity.natives-disabled"); + + static final BooleanSupplier MACOS = () -> { + return NATIVES_ENABLED + && System.getProperty("os.name", "").equalsIgnoreCase("Mac OS X") + && System.getProperty("os.arch").equals("x86_64"); + }; + + static final BooleanSupplier LINUX = () -> { + return NATIVES_ENABLED + && System.getProperty("os.name", "").equalsIgnoreCase("Linux") + && System.getProperty("os.arch").equals("amd64"); + }; +} diff --git a/native/src/main/java/com/velocitypowered/natives/util/Natives.java b/native/src/main/java/com/velocitypowered/natives/util/Natives.java index 1fce4f0b6..44329434a 100644 --- a/native/src/main/java/com/velocitypowered/natives/util/Natives.java +++ b/native/src/main/java/com/velocitypowered/natives/util/Natives.java @@ -46,10 +46,10 @@ public class Natives { public static final NativeCodeLoader compress = new NativeCodeLoader<>( ImmutableList.of( - new NativeCodeLoader.Variant<>(NativeCodeLoader.MACOS, + new NativeCodeLoader.Variant<>(NativeConstraints.MACOS, copyAndLoadNative("/macosx/velocity-compress.dylib"), "native (macOS)", NativeVelocityCompressor.FACTORY), - new NativeCodeLoader.Variant<>(NativeCodeLoader.LINUX, + new NativeCodeLoader.Variant<>(NativeConstraints.LINUX, copyAndLoadNative("/linux_x64/velocity-compress.so"), "native (Linux amd64)", NativeVelocityCompressor.FACTORY), new NativeCodeLoader.Variant<>(NativeCodeLoader.ALWAYS, () -> { @@ -59,10 +59,10 @@ public class Natives { public static final NativeCodeLoader cipher = new NativeCodeLoader<>( ImmutableList.of( - new NativeCodeLoader.Variant<>(NativeCodeLoader.MACOS, + new NativeCodeLoader.Variant<>(NativeConstraints.MACOS, copyAndLoadNative("/macosx/velocity-cipher.dylib"), "mbed TLS (macOS)", NativeVelocityCipher.FACTORY), - new NativeCodeLoader.Variant<>(NativeCodeLoader.LINUX, + new NativeCodeLoader.Variant<>(NativeConstraints.LINUX, copyAndLoadNative("/linux_x64/velocity-cipher.so"), "mbed TLS (Linux amd64)", NativeVelocityCipher.FACTORY), new NativeCodeLoader.Variant<>(NativeCodeLoader.ALWAYS, () -> { diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/netty/MinecraftCipherDecoder.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/netty/MinecraftCipherDecoder.java index 0d630b77d..373b88af5 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/netty/MinecraftCipherDecoder.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/netty/MinecraftCipherDecoder.java @@ -17,14 +17,7 @@ public class MinecraftCipherDecoder extends ByteToMessageDecoder { @Override protected void decode(ChannelHandlerContext ctx, ByteBuf in, List out) throws Exception { - ByteBuf decrypted = ctx.alloc().buffer(in.readableBytes()); - try { - cipher.process(in, decrypted); - out.add(decrypted); - } catch (Exception e) { - decrypted.release(); - throw e; - } + out.add(cipher.process(ctx, in)); } @Override