Reformat with Google code style and enforce Checkstyle.

Fixes #125
This commit is contained in:
Andrew Steinborn
2018-10-27 23:45:35 -04:00
parent 53aa92db92
commit 25b5e00125
208 changed files with 12851 additions and 11620 deletions

View File

@@ -1,8 +1,10 @@
plugins {
id 'java'
id 'checkstyle'
}
apply from: '../gradle/checkerframework.gradle'
apply from: '../gradle/checkstyle.gradle'
dependencies {
compile "com.google.guava:guava:${guavaVersion}"

View File

@@ -1,13 +1,16 @@
package com.velocitypowered.natives;
/**
* This marker interface indicates that this object should be explicitly disposed before the object can no longer be used.
* Not disposing these objects will likely leak native resources and eventually lead to resource exhaustion.
* This marker interface indicates that this object should be explicitly disposed before the object
* can no longer be used. Not disposing these objects will likely leak native resources and
* eventually lead to resource exhaustion.
*/
public interface Disposable {
/**
* Disposes this object. After this call returns, any use of this object becomes invalid. Multiple calls to
* this function should be safe: there should be no side-effects once an object is disposed.
*/
void dispose();
/**
* Disposes this object. After this call returns, any use of this object becomes invalid. Multiple
* calls to this function should be safe: there should be no side-effects once an object is
* disposed.
*/
void dispose();
}

View File

@@ -2,62 +2,62 @@ package com.velocitypowered.natives.compression;
import com.google.common.base.Preconditions;
import io.netty.buffer.ByteBuf;
import java.util.zip.DataFormatException;
import java.util.zip.Deflater;
import java.util.zip.Inflater;
public class JavaVelocityCompressor implements VelocityCompressor {
public static final VelocityCompressorFactory FACTORY = JavaVelocityCompressor::new;
private final Deflater deflater;
private final Inflater inflater;
private final byte[] buf;
private boolean disposed = false;
public static final VelocityCompressorFactory FACTORY = JavaVelocityCompressor::new;
private JavaVelocityCompressor(int level) {
this.deflater = new Deflater(level);
this.inflater = new Inflater();
this.buf = new byte[ZLIB_BUFFER_SIZE];
private final Deflater deflater;
private final Inflater inflater;
private final byte[] buf;
private boolean disposed = false;
private JavaVelocityCompressor(int level) {
this.deflater = new Deflater(level);
this.inflater = new Inflater();
this.buf = new byte[ZLIB_BUFFER_SIZE];
}
@Override
public void inflate(ByteBuf source, ByteBuf destination) throws DataFormatException {
ensureNotDisposed();
byte[] inData = new byte[source.readableBytes()];
source.readBytes(inData);
inflater.setInput(inData);
while (!inflater.finished()) {
int read = inflater.inflate(buf);
destination.writeBytes(buf, 0, read);
}
inflater.reset();
}
@Override
public void inflate(ByteBuf source, ByteBuf destination) throws DataFormatException {
ensureNotDisposed();
@Override
public void deflate(ByteBuf source, ByteBuf destination) throws DataFormatException {
ensureNotDisposed();
byte[] inData = new byte[source.readableBytes()];
source.readBytes(inData);
inflater.setInput(inData);
while (!inflater.finished()) {
int read = inflater.inflate(buf);
destination.writeBytes(buf, 0, read);
}
inflater.reset();
byte[] inData = new byte[source.readableBytes()];
source.readBytes(inData);
deflater.setInput(inData);
deflater.finish();
while (!deflater.finished()) {
int bytes = deflater.deflate(buf);
destination.writeBytes(buf, 0, bytes);
}
deflater.reset();
}
@Override
public void deflate(ByteBuf source, ByteBuf destination) throws DataFormatException {
ensureNotDisposed();
@Override
public void dispose() {
disposed = true;
deflater.end();
inflater.end();
}
byte[] inData = new byte[source.readableBytes()];
source.readBytes(inData);
deflater.setInput(inData);
deflater.finish();
while (!deflater.finished()) {
int bytes = deflater.deflate(buf);
destination.writeBytes(buf, 0, bytes);
}
deflater.reset();
}
@Override
public void dispose() {
disposed = true;
deflater.end();
inflater.end();
}
private void ensureNotDisposed() {
Preconditions.checkState(!disposed, "Object already disposed");
}
private void ensureNotDisposed() {
Preconditions.checkState(!disposed, "Object already disposed");
}
}

View File

@@ -2,75 +2,78 @@ package com.velocitypowered.natives.compression;
import com.google.common.base.Preconditions;
import io.netty.buffer.ByteBuf;
import java.util.zip.DataFormatException;
public class NativeVelocityCompressor implements VelocityCompressor {
public static final VelocityCompressorFactory FACTORY = NativeVelocityCompressor::new;
private final NativeZlibInflate inflate = new NativeZlibInflate();
private final long inflateCtx;
private final NativeZlibDeflate deflate = new NativeZlibDeflate();
private final long deflateCtx;
private boolean disposed = false;
public static final VelocityCompressorFactory FACTORY = NativeVelocityCompressor::new;
private NativeVelocityCompressor(int level) {
this.inflateCtx = inflate.init();
this.deflateCtx = deflate.init(level);
private final NativeZlibInflate inflate = new NativeZlibInflate();
private final long inflateCtx;
private final NativeZlibDeflate deflate = new NativeZlibDeflate();
private final long deflateCtx;
private boolean disposed = false;
private NativeVelocityCompressor(int level) {
this.inflateCtx = inflate.init();
this.deflateCtx = deflate.init(level);
}
@Override
public void inflate(ByteBuf source, ByteBuf destination) throws DataFormatException {
ensureNotDisposed();
source.memoryAddress();
destination.memoryAddress();
while (!inflate.finished && source.isReadable()) {
if (!destination.isWritable()) {
destination.ensureWritable(ZLIB_BUFFER_SIZE);
}
int produced = inflate.process(inflateCtx, source.memoryAddress() + source.readerIndex(),
source.readableBytes(),
destination.memoryAddress() + destination.writerIndex(), destination.writableBytes());
source.readerIndex(source.readerIndex() + inflate.consumed);
destination.writerIndex(destination.writerIndex() + produced);
}
@Override
public void inflate(ByteBuf source, ByteBuf destination) throws DataFormatException {
ensureNotDisposed();
source.memoryAddress();
destination.memoryAddress();
inflate.reset(inflateCtx);
inflate.consumed = 0;
inflate.finished = false;
}
while (!inflate.finished && source.isReadable()) {
if (!destination.isWritable()) {
destination.ensureWritable(ZLIB_BUFFER_SIZE);
}
int produced = inflate.process(inflateCtx, source.memoryAddress() + source.readerIndex(), source.readableBytes(),
destination.memoryAddress() + destination.writerIndex(), destination.writableBytes());
source.readerIndex(source.readerIndex() + inflate.consumed);
destination.writerIndex(destination.writerIndex() + produced);
}
@Override
public void deflate(ByteBuf source, ByteBuf destination) throws DataFormatException {
ensureNotDisposed();
source.memoryAddress();
destination.memoryAddress();
inflate.reset(inflateCtx);
inflate.consumed = 0;
inflate.finished = false;
while (!deflate.finished) {
if (!destination.isWritable()) {
destination.ensureWritable(ZLIB_BUFFER_SIZE);
}
int produced = deflate.process(deflateCtx, source.memoryAddress() + source.readerIndex(),
source.readableBytes(),
destination.memoryAddress() + destination.writerIndex(), destination.writableBytes(),
!source.isReadable());
source.readerIndex(source.readerIndex() + deflate.consumed);
destination.writerIndex(destination.writerIndex() + produced);
}
@Override
public void deflate(ByteBuf source, ByteBuf destination) throws DataFormatException {
ensureNotDisposed();
source.memoryAddress();
destination.memoryAddress();
deflate.reset(deflateCtx);
deflate.consumed = 0;
deflate.finished = false;
}
while (!deflate.finished) {
if (!destination.isWritable()) {
destination.ensureWritable(ZLIB_BUFFER_SIZE);
}
int produced = deflate.process(deflateCtx, source.memoryAddress() + source.readerIndex(), source.readableBytes(),
destination.memoryAddress() + destination.writerIndex(), destination.writableBytes(), !source.isReadable());
source.readerIndex(source.readerIndex() + deflate.consumed);
destination.writerIndex(destination.writerIndex() + produced);
}
private void ensureNotDisposed() {
Preconditions.checkState(!disposed, "Object already disposed");
}
deflate.reset(deflateCtx);
deflate.consumed = 0;
deflate.finished = false;
}
private void ensureNotDisposed() {
Preconditions.checkState(!disposed, "Object already disposed");
}
@Override
public void dispose() {
if (!disposed) {
inflate.free(inflateCtx);
deflate.free(deflateCtx);
}
disposed = true;
@Override
public void dispose() {
if (!disposed) {
inflate.free(inflateCtx);
deflate.free(deflateCtx);
}
disposed = true;
}
}

View File

@@ -4,21 +4,23 @@ package com.velocitypowered.natives.compression;
* Represents a native interface for zlib's deflate functions.
*/
class NativeZlibDeflate {
boolean finished;
int consumed;
native long init(int level);
boolean finished;
int consumed;
native long free(long ctx);
native long init(int level);
native int process(long ctx, long sourceAddress, int sourceLength, long destinationAddress, int destinationLength,
boolean flush);
native long free(long ctx);
native void reset(long ctx);
native int process(long ctx, long sourceAddress, int sourceLength, long destinationAddress,
int destinationLength,
boolean flush);
static {
initIDs();
}
native void reset(long ctx);
private static native void initIDs();
static {
initIDs();
}
private static native void initIDs();
}

View File

@@ -4,20 +4,22 @@ package com.velocitypowered.natives.compression;
* Represents a native interface for zlib's inflate functions.
*/
class NativeZlibInflate {
boolean finished;
int consumed;
native long init();
boolean finished;
int consumed;
native long free(long ctx);
native long init();
native int process(long ctx, long sourceAddress, int sourceLength, long destinationAddress, int destinationLength);
native long free(long ctx);
native void reset(long ctx);
native int process(long ctx, long sourceAddress, int sourceLength, long destinationAddress,
int destinationLength);
static {
initIDs();
}
native void reset(long ctx);
private static native void initIDs();
static {
initIDs();
}
private static native void initIDs();
}

View File

@@ -2,19 +2,19 @@ package com.velocitypowered.natives.compression;
import com.velocitypowered.natives.Disposable;
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 {
/**
* The default preferred output buffer size for zlib.
*/
int ZLIB_BUFFER_SIZE = 8192;
void inflate(ByteBuf source, ByteBuf destination) throws DataFormatException;
/**
* The default preferred output buffer size for zlib.
*/
int ZLIB_BUFFER_SIZE = 8192;
void deflate(ByteBuf source, ByteBuf destination) throws DataFormatException;
void inflate(ByteBuf source, ByteBuf destination) throws DataFormatException;
void deflate(ByteBuf source, ByteBuf destination) throws DataFormatException;
}

View File

@@ -1,5 +1,6 @@
package com.velocitypowered.natives.compression;
public interface VelocityCompressorFactory {
VelocityCompressor create(int level);
VelocityCompressor create(int level);
}

View File

@@ -2,53 +2,54 @@ package com.velocitypowered.natives.encryption;
import com.google.common.base.Preconditions;
import io.netty.buffer.ByteBuf;
import java.security.GeneralSecurityException;
import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.ShortBufferException;
import javax.crypto.spec.IvParameterSpec;
import java.security.GeneralSecurityException;
public class JavaVelocityCipher implements VelocityCipher {
public static final VelocityCipherFactory FACTORY = new VelocityCipherFactory() {
@Override
public VelocityCipher forEncryption(SecretKey key) throws GeneralSecurityException {
return new JavaVelocityCipher(true, key);
}
@Override
public VelocityCipher forDecryption(SecretKey key) throws GeneralSecurityException {
return new JavaVelocityCipher(false, key);
}
};
private final Cipher cipher;
private boolean disposed = false;
private JavaVelocityCipher(boolean encrypt, SecretKey key) throws GeneralSecurityException {
this.cipher = Cipher.getInstance("AES/CFB8/NoPadding");
this.cipher.init(encrypt ? Cipher.ENCRYPT_MODE : Cipher.DECRYPT_MODE, key, new IvParameterSpec(key.getEncoded()));
public static final VelocityCipherFactory FACTORY = new VelocityCipherFactory() {
@Override
public VelocityCipher forEncryption(SecretKey key) throws GeneralSecurityException {
return new JavaVelocityCipher(true, key);
}
@Override
public void process(ByteBuf source, ByteBuf destination) throws ShortBufferException {
ensureNotDisposed();
byte[] sourceAsBytes = new byte[source.readableBytes()];
source.readBytes(sourceAsBytes);
int outputSize = cipher.getOutputSize(sourceAsBytes.length);
byte[] destinationBytes = new byte[outputSize];
cipher.update(sourceAsBytes, 0, sourceAsBytes.length, destinationBytes);
destination.writeBytes(destinationBytes);
public VelocityCipher forDecryption(SecretKey key) throws GeneralSecurityException {
return new JavaVelocityCipher(false, key);
}
};
@Override
public void dispose() {
disposed = true;
}
private final Cipher cipher;
private boolean disposed = false;
private void ensureNotDisposed() {
Preconditions.checkState(!disposed, "Object already disposed");
}
private JavaVelocityCipher(boolean encrypt, SecretKey key) throws GeneralSecurityException {
this.cipher = Cipher.getInstance("AES/CFB8/NoPadding");
this.cipher.init(encrypt ? Cipher.ENCRYPT_MODE : Cipher.DECRYPT_MODE, key,
new IvParameterSpec(key.getEncoded()));
}
@Override
public void process(ByteBuf source, ByteBuf destination) throws ShortBufferException {
ensureNotDisposed();
byte[] sourceAsBytes = new byte[source.readableBytes()];
source.readBytes(sourceAsBytes);
int outputSize = cipher.getOutputSize(sourceAsBytes.length);
byte[] destinationBytes = new byte[outputSize];
cipher.update(sourceAsBytes, 0, sourceAsBytes.length, destinationBytes);
destination.writeBytes(destinationBytes);
}
@Override
public void dispose() {
disposed = true;
}
private void ensureNotDisposed() {
Preconditions.checkState(!disposed, "Object already disposed");
}
}

View File

@@ -1,9 +1,11 @@
package com.velocitypowered.natives.encryption;
public class MbedtlsAesImpl {
native long init(byte[] key);
native void process(long ctx, long sourceAddress, int sourceLength, long destinationAddress, boolean encrypt);
native long init(byte[] key);
native void free(long ptr);
native void process(long ctx, long sourceAddress, int sourceLength, long destinationAddress,
boolean encrypt);
native void free(long ptr);
}

View File

@@ -1,55 +1,55 @@
package com.velocitypowered.natives.encryption;
import io.netty.buffer.ByteBuf;
import java.security.GeneralSecurityException;
import javax.crypto.SecretKey;
import javax.crypto.ShortBufferException;
import java.security.GeneralSecurityException;
public class NativeVelocityCipher implements VelocityCipher {
public static final VelocityCipherFactory FACTORY = new VelocityCipherFactory() {
@Override
public VelocityCipher forEncryption(SecretKey key) throws GeneralSecurityException {
return new NativeVelocityCipher(true, key);
}
@Override
public VelocityCipher forDecryption(SecretKey key) throws GeneralSecurityException {
return new NativeVelocityCipher(false, key);
}
};
private static final MbedtlsAesImpl impl = new MbedtlsAesImpl();
private final long ctx;
private final boolean encrypt;
private boolean disposed = false;
private NativeVelocityCipher(boolean encrypt, SecretKey key) {
this.encrypt = encrypt;
this.ctx = impl.init(key.getEncoded());
public static final VelocityCipherFactory FACTORY = new VelocityCipherFactory() {
@Override
public VelocityCipher forEncryption(SecretKey key) throws GeneralSecurityException {
return new NativeVelocityCipher(true, key);
}
@Override
public void process(ByteBuf source, ByteBuf destination) throws ShortBufferException {
source.memoryAddress();
destination.memoryAddress();
// The exact amount we read in is also the amount we write out.
int len = source.readableBytes();
destination.ensureWritable(len);
impl.process(ctx, source.memoryAddress() + source.readerIndex(), len,
destination.memoryAddress() + destination.writerIndex(), encrypt);
source.skipBytes(len);
destination.writerIndex(destination.writerIndex() + len);
public VelocityCipher forDecryption(SecretKey key) throws GeneralSecurityException {
return new NativeVelocityCipher(false, key);
}
};
private static final MbedtlsAesImpl impl = new MbedtlsAesImpl();
@Override
public void dispose() {
if (!disposed) {
impl.free(ctx);
}
disposed = true;
private final long ctx;
private final boolean encrypt;
private boolean disposed = false;
private NativeVelocityCipher(boolean encrypt, SecretKey key) {
this.encrypt = encrypt;
this.ctx = impl.init(key.getEncoded());
}
@Override
public void process(ByteBuf source, ByteBuf destination) throws ShortBufferException {
source.memoryAddress();
destination.memoryAddress();
// The exact amount we read in is also the amount we write out.
int len = source.readableBytes();
destination.ensureWritable(len);
impl.process(ctx, source.memoryAddress() + source.readerIndex(), len,
destination.memoryAddress() + destination.writerIndex(), encrypt);
source.skipBytes(len);
destination.writerIndex(destination.writerIndex() + len);
}
@Override
public void dispose() {
if (!disposed) {
impl.free(ctx);
}
disposed = true;
}
}

View File

@@ -2,9 +2,9 @@ package com.velocitypowered.natives.encryption;
import com.velocitypowered.natives.Disposable;
import io.netty.buffer.ByteBuf;
import javax.crypto.ShortBufferException;
public interface VelocityCipher extends Disposable {
void process(ByteBuf source, ByteBuf destination) throws ShortBufferException;
void process(ByteBuf source, ByteBuf destination) throws ShortBufferException;
}

View File

@@ -1,10 +1,11 @@
package com.velocitypowered.natives.encryption;
import javax.crypto.SecretKey;
import java.security.GeneralSecurityException;
import javax.crypto.SecretKey;
public interface VelocityCipherFactory {
VelocityCipher forEncryption(SecretKey key) throws GeneralSecurityException;
VelocityCipher forDecryption(SecretKey key) throws GeneralSecurityException;
VelocityCipher forEncryption(SecretKey key) throws GeneralSecurityException;
VelocityCipher forDecryption(SecretKey key) throws GeneralSecurityException;
}

View File

@@ -1,81 +1,85 @@
package com.velocitypowered.natives.util;
import org.checkerframework.checker.nullness.qual.Nullable;
import java.util.List;
import java.util.function.BooleanSupplier;
import java.util.function.Supplier;
import org.checkerframework.checker.nullness.qual.Nullable;
public final class NativeCodeLoader<T> implements Supplier<T> {
private final Variant<T> selected;
NativeCodeLoader(List<Variant<T>> variants) {
this.selected = getVariant(variants);
private final Variant<T> selected;
NativeCodeLoader(List<Variant<T>> variants) {
this.selected = getVariant(variants);
}
@Override
public T get() {
return selected.object;
}
private static <T> Variant<T> getVariant(List<Variant<T>> variants) {
for (Variant<T> variant : variants) {
T got = variant.get();
if (got == null) {
continue;
}
return variant;
}
throw new IllegalArgumentException("Can't find any suitable variants");
}
public String getLoadedVariant() {
return selected.name;
}
static class Variant<T> {
private Status status;
private final Runnable setup;
private final String name;
private final T object;
Variant(BooleanSupplier possiblyAvailable, Runnable setup, String name, T object) {
this.status =
possiblyAvailable.getAsBoolean() ? Status.POSSIBLY_AVAILABLE : Status.NOT_AVAILABLE;
this.setup = setup;
this.name = name;
this.object = object;
}
@Override
public T get() {
return selected.object;
}
public @Nullable T get() {
if (status == Status.NOT_AVAILABLE || status == Status.SETUP_FAILURE) {
return null;
}
private static <T> Variant<T> getVariant(List<Variant<T>> variants) {
for (Variant<T> variant : variants) {
T got = variant.get();
if (got == null) {
continue;
}
return variant;
// Make sure setup happens only once
if (status == Status.POSSIBLY_AVAILABLE) {
try {
setup.run();
status = Status.SETUP;
} catch (Exception e) {
status = Status.SETUP_FAILURE;
return null;
}
throw new IllegalArgumentException("Can't find any suitable variants");
}
return object;
}
}
public String getLoadedVariant() {
return selected.name;
}
private enum Status {
NOT_AVAILABLE,
POSSIBLY_AVAILABLE,
SETUP,
SETUP_FAILURE
}
static class Variant<T> {
private Status status;
private final Runnable setup;
private final String name;
private final T object;
Variant(BooleanSupplier possiblyAvailable, Runnable setup, String name, T object) {
this.status = possiblyAvailable.getAsBoolean() ? Status.POSSIBLY_AVAILABLE : Status.NOT_AVAILABLE;
this.setup = setup;
this.name = name;
this.object = object;
}
public @Nullable T get() {
if (status == Status.NOT_AVAILABLE || status == Status.SETUP_FAILURE) {
return null;
}
// Make sure setup happens only once
if (status == Status.POSSIBLY_AVAILABLE) {
try {
setup.run();
status = Status.SETUP;
} catch (Exception e) {
status = Status.SETUP_FAILURE;
return null;
}
}
return object;
}
}
private enum Status {
NOT_AVAILABLE,
POSSIBLY_AVAILABLE,
SETUP,
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;
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;
}

View File

@@ -6,7 +6,6 @@ import com.velocitypowered.natives.compression.NativeVelocityCompressor;
import com.velocitypowered.natives.compression.VelocityCompressorFactory;
import com.velocitypowered.natives.encryption.JavaVelocityCipher;
import com.velocitypowered.natives.encryption.VelocityCipherFactory;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Files;
@@ -14,55 +13,58 @@ import java.nio.file.Path;
import java.nio.file.StandardCopyOption;
public class Natives {
private Natives() {
throw new AssertionError();
}
private static Runnable copyAndLoadNative(String path) {
return () -> {
try {
Path tempFile = Files.createTempFile("native-", path.substring(path.lastIndexOf('.')));
InputStream nativeLib = Natives.class.getResourceAsStream(path);
if (nativeLib == null) {
throw new IllegalStateException("Native library " + path + " not found.");
}
private Natives() {
throw new AssertionError();
}
Files.copy(nativeLib, tempFile, StandardCopyOption.REPLACE_EXISTING);
Runtime.getRuntime().addShutdownHook(new Thread(() -> {
try {
Files.deleteIfExists(tempFile);
} catch (IOException ignored) {
// Well, it doesn't matter...
}
}));
System.load(tempFile.toAbsolutePath().toString());
} catch (IOException e) {
throw new RuntimeException(e);
}
};
}
private static Runnable copyAndLoadNative(String path) {
return () -> {
try {
Path tempFile = Files.createTempFile("native-", path.substring(path.lastIndexOf('.')));
InputStream nativeLib = Natives.class.getResourceAsStream(path);
if (nativeLib == null) {
throw new IllegalStateException("Native library " + path + " not found.");
}
public static final NativeCodeLoader<VelocityCompressorFactory> compressor = new NativeCodeLoader<>(
ImmutableList.of(
new NativeCodeLoader.Variant<>(NativeCodeLoader.MACOS,
copyAndLoadNative("/macosx/velocity-compress.dylib"), "native (macOS)",
NativeVelocityCompressor.FACTORY),
new NativeCodeLoader.Variant<>(NativeCodeLoader.LINUX,
copyAndLoadNative("/linux_x64/velocity-compress.so"), "native (Linux amd64)",
NativeVelocityCompressor.FACTORY),
new NativeCodeLoader.Variant<>(NativeCodeLoader.ALWAYS, () -> {}, "Java", JavaVelocityCompressor.FACTORY)
)
);
Files.copy(nativeLib, tempFile, StandardCopyOption.REPLACE_EXISTING);
Runtime.getRuntime().addShutdownHook(new Thread(() -> {
try {
Files.deleteIfExists(tempFile);
} catch (IOException ignored) {
// Well, it doesn't matter...
}
}));
System.load(tempFile.toAbsolutePath().toString());
} catch (IOException e) {
throw new RuntimeException(e);
}
};
}
public static final NativeCodeLoader<VelocityCipherFactory> cipher = new NativeCodeLoader<>(
ImmutableList.of(
public static final NativeCodeLoader<VelocityCompressorFactory> compressor = new NativeCodeLoader<>(
ImmutableList.of(
new NativeCodeLoader.Variant<>(NativeCodeLoader.MACOS,
copyAndLoadNative("/macosx/velocity-compress.dylib"), "native (macOS)",
NativeVelocityCompressor.FACTORY),
new NativeCodeLoader.Variant<>(NativeCodeLoader.LINUX,
copyAndLoadNative("/linux_x64/velocity-compress.so"), "native (Linux amd64)",
NativeVelocityCompressor.FACTORY),
new NativeCodeLoader.Variant<>(NativeCodeLoader.ALWAYS, () -> {
}, "Java", JavaVelocityCompressor.FACTORY)
)
);
public static final NativeCodeLoader<VelocityCipherFactory> cipher = new NativeCodeLoader<>(
ImmutableList.of(
/*new NativeCodeLoader.Variant<>(NativeCodeLoader.MACOS,
copyAndLoadNative("/macosx/velocity-cipher.dylib"), "mbed TLS (macOS)",
NativeVelocityCipher.FACTORY),
new NativeCodeLoader.Variant<>(NativeCodeLoader.LINUX,
copyAndLoadNative("/linux_x64/velocity-cipher.so"), "mbed TLS (Linux amd64)",
NativeVelocityCipher.FACTORY),*/
new NativeCodeLoader.Variant<>(NativeCodeLoader.ALWAYS, () -> {}, "Java", JavaVelocityCipher.FACTORY)
)
);
new NativeCodeLoader.Variant<>(NativeCodeLoader.ALWAYS, () -> {
}, "Java", JavaVelocityCipher.FACTORY)
)
);
}

View File

@@ -1,65 +1,66 @@
package com.velocitypowered.natives.compression;
import com.velocitypowered.natives.util.Natives;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.ByteBufUtil;
import io.netty.buffer.Unpooled;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.condition.EnabledOnOs;
import java.util.Random;
import java.util.zip.DataFormatException;
import java.util.zip.Deflater;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.junit.jupiter.api.Assertions.fail;
import static org.junit.jupiter.api.condition.OS.LINUX;
import static org.junit.jupiter.api.condition.OS.MAC;
import com.velocitypowered.natives.util.Natives;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.ByteBufUtil;
import io.netty.buffer.Unpooled;
import java.util.Random;
import java.util.zip.DataFormatException;
import java.util.zip.Deflater;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.condition.EnabledOnOs;
class VelocityCompressorTest {
@BeforeAll
static void checkNatives() {
Natives.compressor.getLoadedVariant();
@BeforeAll
static void checkNatives() {
Natives.compressor.getLoadedVariant();
}
@Test
@EnabledOnOs({MAC, LINUX})
void nativeIntegrityCheck() throws DataFormatException {
VelocityCompressor compressor = Natives.compressor.get().create(Deflater.DEFAULT_COMPRESSION);
if (compressor instanceof JavaVelocityCompressor) {
compressor.dispose();
fail("Loaded regular compressor");
}
check(compressor);
}
@Test
@EnabledOnOs({ MAC, LINUX })
void nativeIntegrityCheck() throws DataFormatException {
VelocityCompressor compressor = Natives.compressor.get().create(Deflater.DEFAULT_COMPRESSION);
if (compressor instanceof JavaVelocityCompressor) {
compressor.dispose();
fail("Loaded regular compressor");
}
check(compressor);
}
@Test
void javaIntegrityCheck() throws DataFormatException {
VelocityCompressor compressor = JavaVelocityCompressor.FACTORY.create(Deflater.DEFAULT_COMPRESSION);
check(compressor);
}
private void check(VelocityCompressor compressor) throws DataFormatException {
ByteBuf source = Unpooled.directBuffer();
ByteBuf dest = Unpooled.directBuffer();
ByteBuf decompressed = Unpooled.directBuffer();
Random random = new Random(1);
byte[] randomBytes = new byte[1 << 16];
random.nextBytes(randomBytes);
source.writeBytes(randomBytes);
try {
compressor.deflate(source, dest);
compressor.inflate(dest, decompressed);
source.readerIndex(0);
assertTrue(ByteBufUtil.equals(source, decompressed));
} finally {
source.release();
dest.release();
decompressed.release();
compressor.dispose();
}
@Test
void javaIntegrityCheck() throws DataFormatException {
VelocityCompressor compressor = JavaVelocityCompressor.FACTORY
.create(Deflater.DEFAULT_COMPRESSION);
check(compressor);
}
private void check(VelocityCompressor compressor) throws DataFormatException {
ByteBuf source = Unpooled.directBuffer();
ByteBuf dest = Unpooled.directBuffer();
ByteBuf decompressed = Unpooled.directBuffer();
Random random = new Random(1);
byte[] randomBytes = new byte[1 << 16];
random.nextBytes(randomBytes);
source.writeBytes(randomBytes);
try {
compressor.deflate(source, dest);
compressor.inflate(dest, decompressed);
source.readerIndex(0);
assertTrue(ByteBufUtil.equals(source, decompressed));
} finally {
source.release();
dest.release();
decompressed.release();
compressor.dispose();
}
}
}

View File

@@ -1,71 +1,71 @@
package com.velocitypowered.natives.encryption;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.junit.jupiter.api.Assertions.fail;
import com.velocitypowered.natives.util.Natives;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.ByteBufUtil;
import io.netty.buffer.Unpooled;
import java.security.GeneralSecurityException;
import java.util.Random;
import javax.crypto.spec.SecretKeySpec;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
import javax.crypto.spec.SecretKeySpec;
import java.security.GeneralSecurityException;
import java.util.Random;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.junit.jupiter.api.Assertions.fail;
class VelocityCipherTest {
private static final int ENCRYPT_DATA_SIZE = 1 << 16;
@BeforeAll
static void checkNatives() {
Natives.cipher.getLoadedVariant();
private static final int ENCRYPT_DATA_SIZE = 1 << 16;
@BeforeAll
static void checkNatives() {
Natives.cipher.getLoadedVariant();
}
@Test
@Disabled
void nativeIntegrityCheck() throws GeneralSecurityException {
VelocityCipherFactory factory = Natives.cipher.get();
if (factory == JavaVelocityCipher.FACTORY) {
fail("Loaded regular compressor");
}
check(factory);
}
@Test
@Disabled
void nativeIntegrityCheck() throws GeneralSecurityException {
VelocityCipherFactory factory = Natives.cipher.get();
if (factory == JavaVelocityCipher.FACTORY) {
fail("Loaded regular compressor");
}
check(factory);
}
@Test
void javaIntegrityCheck() throws GeneralSecurityException {
check(JavaVelocityCipher.FACTORY);
}
private void check(VelocityCipherFactory factory) throws GeneralSecurityException {
// Generate a random 16-byte key.
Random random = new Random(1);
byte[] key = new byte[16];
random.nextBytes(key);
VelocityCipher decrypt = factory.forDecryption(new SecretKeySpec(key, "AES"));
VelocityCipher encrypt = factory.forEncryption(new SecretKeySpec(key, "AES"));
ByteBuf source = Unpooled.directBuffer(ENCRYPT_DATA_SIZE);
ByteBuf dest = Unpooled.directBuffer(ENCRYPT_DATA_SIZE);
ByteBuf decryptionBuf = Unpooled.directBuffer(ENCRYPT_DATA_SIZE);
byte[] randomBytes = new byte[ENCRYPT_DATA_SIZE];
random.nextBytes(randomBytes);
source.writeBytes(randomBytes);
try {
encrypt.process(source, dest);
decrypt.process(dest, decryptionBuf);
source.readerIndex(0);
assertTrue(ByteBufUtil.equals(source, decryptionBuf));
} finally {
source.release();
dest.release();
decryptionBuf.release();
decrypt.dispose();
encrypt.dispose();
}
@Test
void javaIntegrityCheck() throws GeneralSecurityException {
check(JavaVelocityCipher.FACTORY);
}
private void check(VelocityCipherFactory factory) throws GeneralSecurityException {
// Generate a random 16-byte key.
Random random = new Random(1);
byte[] key = new byte[16];
random.nextBytes(key);
VelocityCipher decrypt = factory.forDecryption(new SecretKeySpec(key, "AES"));
VelocityCipher encrypt = factory.forEncryption(new SecretKeySpec(key, "AES"));
ByteBuf source = Unpooled.directBuffer(ENCRYPT_DATA_SIZE);
ByteBuf dest = Unpooled.directBuffer(ENCRYPT_DATA_SIZE);
ByteBuf decryptionBuf = Unpooled.directBuffer(ENCRYPT_DATA_SIZE);
byte[] randomBytes = new byte[ENCRYPT_DATA_SIZE];
random.nextBytes(randomBytes);
source.writeBytes(randomBytes);
try {
encrypt.process(source, dest);
decrypt.process(dest, decryptionBuf);
source.readerIndex(0);
assertTrue(ByteBufUtil.equals(source, decryptionBuf));
} finally {
source.release();
dest.release();
decryptionBuf.release();
decrypt.dispose();
encrypt.dispose();
}
}
}