From e1942ae03fd8dc8ceb15a407b3f73362eb79b608 Mon Sep 17 00:00:00 2001 From: nathan Date: Tue, 8 Mar 2016 03:18:12 +0100 Subject: [PATCH] Code polish. Removed optional compression (because for small data, it doesn't matter with AES padding) --- .../KryoCryptoSerializationManager.java | 36 ++--- src/dorkbox/network/connection/KryoExtra.java | 140 ++++++++---------- 2 files changed, 76 insertions(+), 100 deletions(-) diff --git a/src/dorkbox/network/connection/KryoCryptoSerializationManager.java b/src/dorkbox/network/connection/KryoCryptoSerializationManager.java index cb224a97..3817365e 100644 --- a/src/dorkbox/network/connection/KryoCryptoSerializationManager.java +++ b/src/dorkbox/network/connection/KryoCryptoSerializationManager.java @@ -470,23 +470,7 @@ class KryoCryptoSerializationManager implements CryptoSerializationManager { void write(final ByteBuf buffer, final Object message) throws IOException { final KryoExtra kryo = kryoPool.take(); try { - kryo.write(null, buffer, message); - } finally { - kryoPool.put(kryo); - } - } - - /** - * Waits until a kryo is available to write, using CAS operations to prevent having to synchronize. - *

- * There is a small speed penalty if there were no kryo's available to use. - */ - @Override - public final - void writeWithCrypto(final ConnectionImpl connection, final ByteBuf buffer, final Object message) throws IOException { - final KryoExtra kryo = kryoPool.take(); - try { - kryo.writeCrypto(connection, buffer, message, logger); + kryo.write(buffer, message); } finally { kryoPool.put(kryo); } @@ -504,7 +488,23 @@ class KryoCryptoSerializationManager implements CryptoSerializationManager { Object read(final ByteBuf buffer, final int length) throws IOException { final KryoExtra kryo = kryoPool.take(); try { - return kryo.read(null, buffer); + return kryo.read(buffer); + } finally { + kryoPool.put(kryo); + } + } + + /** + * Waits until a kryo is available to write, using CAS operations to prevent having to synchronize. + *

+ * There is a small speed penalty if there were no kryo's available to use. + */ + @Override + public final + void writeWithCrypto(final ConnectionImpl connection, final ByteBuf buffer, final Object message) throws IOException { + final KryoExtra kryo = kryoPool.take(); + try { + kryo.writeCrypto(connection, buffer, message, logger); } finally { kryoPool.put(kryo); } diff --git a/src/dorkbox/network/connection/KryoExtra.java b/src/dorkbox/network/connection/KryoExtra.java index 710aecca..603429bc 100644 --- a/src/dorkbox/network/connection/KryoExtra.java +++ b/src/dorkbox/network/connection/KryoExtra.java @@ -35,13 +35,9 @@ import java.io.IOException; */ public class KryoExtra extends Kryo { - // this is the minimum size that LZ4 can compress. Anything smaller than this will result in an output LARGER than the input. - private static final int LZ4_COMPRESSION_MIN_SIZE = 32; - /** * bit masks */ - private static final byte compress = (byte) 1; static final byte crypto = (byte) (1 << 1); // snappycomp : 7.534 micros/op; 518.5 MB/s (output: 55.1%) @@ -88,11 +84,9 @@ class KryoExtra extends Kryo { } public synchronized - void write(final ConnectionImpl connection, final ByteBuf buffer, final Object message) throws IOException { - // connection will ALWAYS be of type Connection or NULL. - // used by RMI/some serializers to determine which connection wrote this object - // NOTE: this is only valid in the context of this thread, which RMI stuff is accessed in -- so this is SAFE for RMI - this.connection = connection; + void write(final ByteBuf buffer, final Object message) throws IOException { + // connection will always be NULL during connection initialization + this.connection = null; // during INIT and handshake, we don't use connection encryption/compression // magic byte @@ -105,11 +99,9 @@ class KryoExtra extends Kryo { } public synchronized - Object read(final ConnectionImpl connection, final ByteBuf buffer) throws IOException { - // connection will ALWAYS be of type IConnection or NULL. - // used by RMI/some serializers to determine which connection read this object - // NOTE: this is only valid in the context of this thread, which RMI stuff is accessed in -- so this is SAFE for RMI - this.connection = connection; + Object read(final ByteBuf buffer) throws IOException { + // connection will always be NULL during connection initialization + this.connection = null; //////////////// @@ -131,7 +123,6 @@ class KryoExtra extends Kryo { public synchronized void writeCrypto(final ConnectionImpl connection, final ByteBuf buffer, final Object message, final Logger logger) throws IOException { final boolean traceEnabled = logger.isTraceEnabled(); - byte magicByte = (byte) 0x00000000; ByteBuf objectOutputBuffer = this.tempBuffer; objectOutputBuffer.clear(); // always have to reset everything @@ -176,47 +167,43 @@ class KryoExtra extends Kryo { inputOffset = 0; } - if (length > LZ4_COMPRESSION_MIN_SIZE) { - if (traceEnabled) { - logger.trace("Compressing data {}", connection); - } + // we AWALYS compress our data stream -- because of how AES-GCM pads data out, the small input (that would result in a larger + // output), will be negated by the increase in size by the encryption - byte[] compressOutput = this.compressOutput; - - int maxCompressedLength = compressor.maxCompressedLength(length); - - // add 4 so there is room to write the compressed size to the buffer - int maxCompressedLengthWithOffset = maxCompressedLength + 4; - - // lazy initialize the compression output buffer - if (maxCompressedLengthWithOffset > compressOutputLength) { - compressOutputLength = maxCompressedLengthWithOffset; - compressOutput = new byte[maxCompressedLengthWithOffset]; - this.compressOutput = compressOutput; - } - - - // LZ4 compress. output offset 4 to leave room for length of tempOutput data - int compressedLength = compressor.compress(inputArray, inputOffset, length, compressOutput, 4, maxCompressedLength); - - // bytes can now be written to, because our compressed data is stored in a temp array. - // ONLY do this if our compressed length is LESS than our uncompressed length. - if (compressedLength < length) { - // now write the ORIGINAL (uncompressed) length to the front of the byte array. This is so we can use the FAST - // decompress version - BigEndian.Int_.toBytes(length, compressOutput); - - magicByte |= compress; - - // corrected length - length = compressedLength + 4; // +4 for the uncompressed size bytes - - // correct input. compression output is now encryption input - inputArray = compressOutput; - inputOffset = 0; - } + if (traceEnabled) { + logger.trace("Compressing data {}", connection); } + byte[] compressOutput = this.compressOutput; + + int maxCompressedLength = compressor.maxCompressedLength(length); + + // add 4 so there is room to write the compressed size to the buffer + int maxCompressedLengthWithOffset = maxCompressedLength + 4; + + // lazy initialize the compression output buffer + if (maxCompressedLengthWithOffset > compressOutputLength) { + compressOutputLength = maxCompressedLengthWithOffset; + compressOutput = new byte[maxCompressedLengthWithOffset]; + this.compressOutput = compressOutput; + } + + + // LZ4 compress. output offset 4 to leave room for length of tempOutput data + int compressedLength = compressor.compress(inputArray, inputOffset, length, compressOutput, 4, maxCompressedLength); + + // bytes can now be written to, because our compressed data is stored in a temp array. + + // now write the ORIGINAL (uncompressed) length to the front of the byte array. This is so we can use the FAST decompress version + BigEndian.Int_.toBytes(length, compressOutput); + + // corrected length + length = compressedLength + 4; // +4 for the uncompressed size bytes + + // correct input. compression output is now encryption input + inputArray = compressOutput; + inputOffset = 0; + if (traceEnabled) { logger.trace("AES encrypting data {}", connection); } @@ -251,10 +238,8 @@ class KryoExtra extends Kryo { throw new IOException("Unable to AES encrypt the data", e); } - magicByte |= crypto; - // write out the "magic" byte. - buffer.writeByte(magicByte); + buffer.writeByte(crypto); // have to copy over the orig data, because we used the temp buffer buffer.writeBytes(cryptoOutput, 0, encryptedLength); @@ -282,10 +267,6 @@ class KryoExtra extends Kryo { // have to adjust for the magic byte length -= 1; - // it's ALWAYS encrypted, but MAYBE compressed - final boolean isCompressed = (magicByte & compress) == compress; - - if (logger.isTraceEnabled()) { logger.trace("AES decrypting data {}", connection); } @@ -350,33 +331,28 @@ class KryoExtra extends Kryo { throw new IOException("Unable to AES decrypt the data", e); } - if (isCompressed) { - inputArray = decryptOutputArray; - inputOffset = 4; // because 4 bytes for the decompressed size + // decompress -- as it's ALWAYS compressed + inputArray = decryptOutputArray; + inputOffset = 4; // because 4 bytes for the decompressed size - // get the decompressed length (at the beginning of the array) - final int uncompressedLength = BigEndian.Int_.from(inputArray); + // get the decompressed length (at the beginning of the array) + final int uncompressedLength = BigEndian.Int_.from(inputArray); - byte[] decompressOutputArray = this.decompressOutput; - if (uncompressedLength > decompressOutputLength) { - decompressOutputLength = uncompressedLength; - decompressOutputArray = new byte[uncompressedLength]; - this.decompressOutput = decompressOutputArray; + byte[] decompressOutputArray = this.decompressOutput; + if (uncompressedLength > decompressOutputLength) { + decompressOutputLength = uncompressedLength; + decompressOutputArray = new byte[uncompressedLength]; + this.decompressOutput = decompressOutputArray; - decompressBuf = Unpooled.wrappedBuffer(decompressOutputArray); // so we can read via kryo - } - - // LZ4 decompress, requires the size of the ORIGINAL length (because we use the FAST decompressor - decompressor.decompress(inputArray, inputOffset, decompressOutputArray, 0, uncompressedLength); - - decompressBuf.setIndex(0, uncompressedLength); - inputBuf = decompressBuf; - } - else { - decryptBuf.setIndex(0, decryptedLength); - inputBuf = decryptBuf; + decompressBuf = Unpooled.wrappedBuffer(decompressOutputArray); // so we can read via kryo } + // LZ4 decompress, requires the size of the ORIGINAL length (because we use the FAST decompressor + decompressor.decompress(inputArray, inputOffset, decompressOutputArray, 0, uncompressedLength); + + decompressBuf.setIndex(0, uncompressedLength); + inputBuf = decompressBuf; + // read the object from the buffer. reader.setBuffer(inputBuf);