diff --git a/native/src/main/java/com/velocitypowered/natives/Native.java b/native/src/main/java/com/velocitypowered/natives/Native.java new file mode 100644 index 000000000..26cdd0ba4 --- /dev/null +++ b/native/src/main/java/com/velocitypowered/natives/Native.java @@ -0,0 +1,5 @@ +package com.velocitypowered.natives; + +public interface Native { + boolean isNative(); +} diff --git a/native/src/main/java/com/velocitypowered/natives/compression/JavaVelocityCompressor.java b/native/src/main/java/com/velocitypowered/natives/compression/JavaVelocityCompressor.java index 5ab78fafa..f86c32c12 100644 --- a/native/src/main/java/com/velocitypowered/natives/compression/JavaVelocityCompressor.java +++ b/native/src/main/java/com/velocitypowered/natives/compression/JavaVelocityCompressor.java @@ -62,4 +62,9 @@ public class JavaVelocityCompressor implements VelocityCompressor { private void ensureNotDisposed() { Preconditions.checkState(!disposed, "Object already disposed"); } + + @Override + public boolean isNative() { + return false; + } } diff --git a/native/src/main/java/com/velocitypowered/natives/compression/NativeVelocityCompressor.java b/native/src/main/java/com/velocitypowered/natives/compression/NativeVelocityCompressor.java index a541ea6dd..015c976a1 100644 --- a/native/src/main/java/com/velocitypowered/natives/compression/NativeVelocityCompressor.java +++ b/native/src/main/java/com/velocitypowered/natives/compression/NativeVelocityCompressor.java @@ -78,4 +78,9 @@ public class NativeVelocityCompressor implements VelocityCompressor { } disposed = true; } + + @Override + public boolean isNative() { + return true; + } } diff --git a/native/src/main/java/com/velocitypowered/natives/compression/VelocityCompressor.java b/native/src/main/java/com/velocitypowered/natives/compression/VelocityCompressor.java index ad554c352..be9bc6c65 100644 --- a/native/src/main/java/com/velocitypowered/natives/compression/VelocityCompressor.java +++ b/native/src/main/java/com/velocitypowered/natives/compression/VelocityCompressor.java @@ -1,13 +1,14 @@ package com.velocitypowered.natives.compression; import com.velocitypowered.natives.Disposable; +import com.velocitypowered.natives.Native; import io.netty.buffer.ByteBuf; import java.util.zip.DataFormatException; /** * Provides an interface to inflate and deflate {@link ByteBuf}s using zlib. */ -public interface VelocityCompressor extends Disposable { +public interface VelocityCompressor extends Disposable, Native { void inflate(ByteBuf source, ByteBuf destination) throws DataFormatException; void deflate(ByteBuf source, ByteBuf destination) throws DataFormatException; 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 75e16922f..550df2e9c 100644 --- a/native/src/main/java/com/velocitypowered/natives/encryption/JavaVelocityCipher.java +++ b/native/src/main/java/com/velocitypowered/natives/encryption/JavaVelocityCipher.java @@ -79,4 +79,9 @@ public class JavaVelocityCipher implements VelocityCipher { private void ensureNotDisposed() { Preconditions.checkState(!disposed, "Object already disposed"); } + + @Override + public boolean isNative() { + return false; + } } 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 eaafadbfd..56905c085 100644 --- a/native/src/main/java/com/velocitypowered/natives/encryption/NativeVelocityCipher.java +++ b/native/src/main/java/com/velocitypowered/natives/encryption/NativeVelocityCipher.java @@ -1,5 +1,6 @@ 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; @@ -32,6 +33,7 @@ public class NativeVelocityCipher implements VelocityCipher { @Override public void process(ByteBuf source, ByteBuf destination) throws ShortBufferException { + ensureNotDisposed(); source.memoryAddress(); destination.memoryAddress(); @@ -65,4 +67,13 @@ public class NativeVelocityCipher implements VelocityCipher { } disposed = true; } + + private void ensureNotDisposed() { + Preconditions.checkState(!disposed, "Object already disposed"); + } + + @Override + public boolean isNative() { + return true; + } } 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 6b7317bc5..c52c88737 100644 --- a/native/src/main/java/com/velocitypowered/natives/encryption/VelocityCipher.java +++ b/native/src/main/java/com/velocitypowered/natives/encryption/VelocityCipher.java @@ -1,11 +1,12 @@ package com.velocitypowered.natives.encryption; import com.velocitypowered.natives.Disposable; +import com.velocitypowered.natives.Native; import io.netty.buffer.ByteBuf; import io.netty.channel.ChannelHandlerContext; import javax.crypto.ShortBufferException; -public interface VelocityCipher extends Disposable { +public interface VelocityCipher extends Disposable, Native { void process(ByteBuf source, ByteBuf destination) throws ShortBufferException; diff --git a/native/src/main/java/com/velocitypowered/natives/util/MoreByteBufUtils.java b/native/src/main/java/com/velocitypowered/natives/util/MoreByteBufUtils.java new file mode 100644 index 000000000..e948da46d --- /dev/null +++ b/native/src/main/java/com/velocitypowered/natives/util/MoreByteBufUtils.java @@ -0,0 +1,33 @@ +package com.velocitypowered.natives.util; + +import com.velocitypowered.natives.Native; +import io.netty.buffer.ByteBuf; +import io.netty.buffer.ByteBufAllocator; + +public class MoreByteBufUtils { + private MoreByteBufUtils() { + throw new AssertionError(); + } + + /** + * Ensures the {@code buf} will work with the specified {@code nativeThing}. After this function + * is called, you should decrement the reference count on the {@code buf} with + * {@link ByteBuf#release()}. + * + * @param alloc the {@link ByteBufAllocator} to use + * @param nativeStuff the native we are working with + * @param buf the buffer we are working with + * @return a buffer compatible with the native + */ + public static ByteBuf ensureCompatible(ByteBufAllocator alloc, Native nativeStuff, ByteBuf buf) { + if (!nativeStuff.isNative() || buf.hasMemoryAddress()) { + // Will always work in either case. + return buf.retain(); + } + + // It's not, so we must make a memory copy. + ByteBuf newBuf = alloc.directBuffer(); + newBuf.writeBytes(buf); + return newBuf; + } +} diff --git a/native/src/main/java/com/velocitypowered/natives/util/NativeConstraints.java b/native/src/main/java/com/velocitypowered/natives/util/NativeConstraints.java index 089690d30..0657577a2 100644 --- a/native/src/main/java/com/velocitypowered/natives/util/NativeConstraints.java +++ b/native/src/main/java/com/velocitypowered/natives/util/NativeConstraints.java @@ -1,18 +1,32 @@ package com.velocitypowered.natives.util; +import io.netty.buffer.ByteBuf; +import io.netty.buffer.Unpooled; import java.util.function.BooleanSupplier; public class NativeConstraints { private static final boolean NATIVES_ENABLED = !Boolean.getBoolean("velocity.natives-disabled"); + private static final boolean CAN_GET_MEMORYADDRESS; + + static { + ByteBuf test = Unpooled.directBuffer(); + try { + CAN_GET_MEMORYADDRESS = test.hasMemoryAddress(); + } finally { + test.release(); + } + } static final BooleanSupplier MACOS = () -> { return NATIVES_ENABLED + && CAN_GET_MEMORYADDRESS && System.getProperty("os.name", "").equalsIgnoreCase("Mac OS X") && System.getProperty("os.arch").equals("x86_64"); }; static final BooleanSupplier LINUX = () -> { return NATIVES_ENABLED + && CAN_GET_MEMORYADDRESS && System.getProperty("os.name", "").equalsIgnoreCase("Linux") && System.getProperty("os.arch").equals("amd64"); };