From 3a79adcaaeaeaf4a7cb6fe9e3d50a54fd58d580b Mon Sep 17 00:00:00 2001 From: Collin Smith Date: Tue, 23 Jun 2020 18:40:17 -0700 Subject: [PATCH] Removing previous iteration --- .../src/com/riiablo/net/reliable/Packet.java | 426 +++++++++--------- .../riiablo/net/reliable/ReliableConfig.java | 17 - 2 files changed, 224 insertions(+), 219 deletions(-) delete mode 100644 server/netty/src/com/riiablo/net/reliable/ReliableConfig.java diff --git a/server/netty/src/com/riiablo/net/reliable/Packet.java b/server/netty/src/com/riiablo/net/reliable/Packet.java index 4d07333d..4058ee12 100644 --- a/server/netty/src/com/riiablo/net/reliable/Packet.java +++ b/server/netty/src/com/riiablo/net/reliable/Packet.java @@ -3,11 +3,14 @@ package com.riiablo.net.reliable; import io.netty.buffer.ByteBuf; import org.apache.commons.lang3.builder.ToStringBuilder; -import com.badlogic.gdx.Gdx; +import com.badlogic.gdx.utils.Pool; +import com.badlogic.gdx.utils.Pools; -public abstract class Packet { +public class Packet { private static final String TAG = "Packet"; - + + public static final int USHORT_MAX_VALUE = 0xFFFF; + static final int MAX_PACKET_HEADER_SIZE = 10; static final int FRAGMENT_HEADER_SIZE = 6; @@ -27,11 +30,24 @@ public abstract class Packet { static final int ACK_BYTE2_MASK = 0x00FF0000; static final int ACK_BYTE3_MASK = 0xFF000000; - public static boolean isSinglePacket(int prefixByte) { - return (prefixByte & TYPE_MASK) == SINGLE; + private static final int FLAGS_OFFSET = 0; + private static final int CHANNEL_OFFSET = 1; + + public static byte getFlags(ByteBuf bb) { + return bb.getByte(FLAGS_OFFSET); } - static int getAckBitByteFlags(int ackBits, int prefixByte) { + public static int getChannelId(ByteBuf bb) { + return bb.getUnsignedByte(CHANNEL_OFFSET); + } + + private Packet() {} + + public static boolean isFragmented(byte flags) { + return (flags & TYPE_MASK) == FRAGMENTED; + } + + private static int getAckBitsFlags(int ackBits, int prefixByte) { if ((ackBits & ACK_BYTE0_MASK) != ACK_BYTE0_MASK) prefixByte |= ACK_BYTE0; if ((ackBits & ACK_BYTE1_MASK) != ACK_BYTE1_MASK) prefixByte |= ACK_BYTE1; if ((ackBits & ACK_BYTE2_MASK) != ACK_BYTE2_MASK) prefixByte |= ACK_BYTE2; @@ -39,54 +55,202 @@ public abstract class Packet { return prefixByte; } - static void writeAckBitByteFlags(ByteBuf bb, int ackBits) { + private static void writeAckBitsFlags(ByteBuf bb, int ackBits) { if ((ackBits & ACK_BYTE0_MASK) != ACK_BYTE0_MASK) bb.writeByte(ackBits); if ((ackBits & ACK_BYTE1_MASK) != ACK_BYTE1_MASK) bb.writeByte(ackBits >> 8); if ((ackBits & ACK_BYTE2_MASK) != ACK_BYTE2_MASK) bb.writeByte(ackBits >> 16); if ((ackBits & ACK_BYTE3_MASK) != ACK_BYTE3_MASK) bb.writeByte(ackBits >> 24); } - static void logError(String format, Object... args) { - logError(String.format(format, args)); + public static int writeAck(ByteBuf bb, int channelId, int ack, int ackBits) { + int startIndex = bb.writerIndex(); + final int flags = getAckBitsFlags(ackBits, ACK); + bb.writeByte(flags); + bb.writeByte(channelId); + bb.writeShortLE(ack); + writeAckBitsFlags(bb, ackBits); + return bb.writerIndex() - startIndex; } - static void logError(String format) { - Gdx.app.error(TAG, format); - } + public static int writePacketHeader(ByteBuf bb, int channelId, int sequence, int ack, int ackBits) { + int startIndex = bb.writerIndex(); + int flags = getAckBitsFlags(ackBits, SINGLE); - // Used for debugging purposes - @Deprecated - public static Packet readHeader(ReliableConfig config, ByteBuf bb) { - if (bb.readableBytes() < 1) { - logError("buffer too small for packet header"); - return null; - } + int sequenceDiff = sequence - ack; + if (sequenceDiff < 0) sequenceDiff += USHORT_MAX_VALUE; + if (sequenceDiff <= 0xFF) flags |= SEQ_DIFF; - byte prefixByte = bb.readByte(); - Packet packet; - if (isSinglePacket(prefixByte)) { - packet = new SinglePacket(); + bb.writeByte(flags); + bb.writeByte(channelId); + bb.writeShortLE(sequence); + + if (sequenceDiff <= 0xFF) { + bb.writeByte(sequenceDiff); } else { - packet = new FragmentedPacket(); + bb.writeShortLE(ack); } - packet.readHeader(config, bb, prefixByte); - return packet; + writeAckBitsFlags(bb, ackBits); + return bb.writerIndex() - startIndex; } - abstract int readHeader(ReliableConfig config, ByteBuf bb, final byte prefixByte); + public static int readPacketHeader(ReliableConfiguration config, ByteBuf bb, HeaderData out) { + assert out != null; + int startIndex = bb.readerIndex(); + if (bb.readableBytes() < 4) { + Log.error(TAG, "buffer too small for packet header (1)"); + return out.headerSize = -1; + } - static class SinglePacket extends Packet { - public int channelId; - public int sequence; - public int ack; - public int ackBits; + final byte flags = out.flags = bb.readByte(); + if ((flags & TYPE_MASK) != SINGLE) { + Log.error(TAG, "packet header not flagged as single packet"); + return out.headerSize = -1; + } - int headerSize; + out.channelId = bb.readUnsignedByte(); + out.sequence = (flags & ACK) == ACK ? 0 : bb.readUnsignedShortLE(); // ACK doesn't have sequence + + if ((flags & SEQ_DIFF) == SEQ_DIFF) { + if (bb.readableBytes() < 1) { + Log.error(TAG, "buffer too small for packet header (2)"); + return out.headerSize = -1; + } + + int sequenceDiff = bb.readUnsignedByte(); + out.ack = (out.sequence - sequenceDiff) & USHORT_MAX_VALUE; + } else { + if (bb.readableBytes() < 2) { + Log.error(TAG, "buffer too small for packet header (3)"); + return out.headerSize = -1; + } + + out.ack = bb.readUnsignedShortLE(); + } + + int expectedBytes = 0; + for (int i = ACK_BYTE0; i <= ACK_BYTE3; i <<= 1) { + if ((flags & i) == i) expectedBytes++; + } + + if (bb.readableBytes() < expectedBytes) { + Log.error(TAG, "buffer too small for packet header (4)"); + return out.headerSize = -1; + } + + int ackBits = 0xFFFFFFFF; + if ((flags & ACK_BYTE0) == ACK_BYTE0) { + ackBits &= ~ACK_BYTE0_MASK; + ackBits |= bb.readByte(); + } + if ((flags & ACK_BYTE1) == ACK_BYTE1) { + ackBits &= ~ACK_BYTE1_MASK; + ackBits |= (bb.readByte() << 8); + } + if ((flags & ACK_BYTE2) == ACK_BYTE2) { + ackBits &= ~ACK_BYTE2_MASK; + ackBits |= (bb.readByte() << 16); + } + if ((flags & ACK_BYTE3) == ACK_BYTE3) { + ackBits &= ~ACK_BYTE3_MASK; + ackBits |= (bb.readByte() << 24); + } + + out.ackBits = ackBits; + return out.headerSize = bb.readerIndex() - startIndex; + } + + public static int readFragmentHeader(ReliableConfiguration config, ByteBuf bb, FragmentedHeaderData out) { + assert out != null; + int startIndex = bb.readerIndex(); + if (bb.readableBytes() < FRAGMENT_HEADER_SIZE) { + Log.error(TAG, "buffer too small for fragment header"); + return out.headerSize = -1; + } + + final byte flags = out.flags = bb.readByte(); + if ((flags & TYPE_MASK) != FRAGMENTED) { + Log.error(TAG, "packet header not flagged as fragmented packet"); + return out.headerSize = -1; + } + + final int channelId = out.channelId = bb.readUnsignedByte(); + final int sequence = out.sequence = bb.readUnsignedShortLE(); + + final int fragmentId = out.fragmentId = bb.readUnsignedByte(); + final int numFragments = out.numFragments = bb.readUnsignedByte(); + + if (numFragments > config.maxFragments) { + Log.error(TAG, "num fragments %d outside of range of max fragments %d", numFragments, config.maxFragments); + return out.headerSize = -1; + } + + if (fragmentId >= numFragments) { + Log.error(TAG, "fragment id %d outside of range of num fragments %d", fragmentId, numFragments); + return out.headerSize = -1; + } + + if (fragmentId == 0) { + if (bb.readableBytes() < 1) { + Log.error(TAG, "buffer too small for packet header"); + return out.headerSize = -1; + } + + final HeaderData packetHeader = out.header; + int headerSize = readPacketHeader(config, bb, packetHeader); + if (headerSize < 0) { + Log.error(TAG, "bad packet header in fragment"); + return out.headerSize = -1; + } + + if (packetHeader.sequence != sequence) { + Log.error(TAG, "bad packet sequence in fragment. expected %d, got %d", sequence, packetHeader.sequence); + return out.headerSize = -1; + } + + out.ack = packetHeader.ack; + out.ackBits = packetHeader.ackBits; + } else { + out.ack = 0; + out.ackBits = 0; + } + + final int fragmentSize = out.fragmentSize = bb.readableBytes(); + if (fragmentSize > config.fragmentSize) { + Log.error(TAG, "fragment bytes %d > fragment size %d", fragmentSize, config.fragmentSize); + return out.headerSize = -1; + } + + if (fragmentId != numFragments - 1 && fragmentSize != config.fragmentSize) { + Log.error(TAG, "fragment %d is %d bytes, which is not the expected fragment size %d bytes", fragmentId, fragmentSize, config.fragmentSize); + return out.headerSize = -1; + } + + return out.headerSize = bb.readerIndex() - startIndex; + } + + private static final Pool HEADER_DATA_POOL = Pools.get(HeaderData.class); + + public static HeaderData obtainData() { + return HEADER_DATA_POOL.obtain(); + } + + public static class HeaderData { + public byte flags; + public int channelId; + public int sequence; + public int ack; + public int ackBits; + public int headerSize; + + public void free() { + HEADER_DATA_POOL.free(this); + } @Override public String toString() { return new ToStringBuilder(this) + .append("flags", String.format("%02x", flags)) .append("channelId", channelId) .append("sequence", sequence) .append("ack", ack) @@ -94,190 +258,48 @@ public abstract class Packet { .append("headerSize", headerSize) .build(); } - - @Override - int readHeader(ReliableConfig config, ByteBuf bb, byte prefixByte) { - if ((prefixByte & TYPE_MASK) != SINGLE) { - logError("packet header not flagged as single packet"); - return -1; - } - - int startIndex = bb.readerIndex(); - - if (bb.readableBytes() < 3) { - logError("buffer too small for packet header (1)"); - return -1; - } - channelId = bb.readUnsignedByte(); - - // ack packets don't have sequence numbers - sequence = (prefixByte & ACK) == ACK ? 0 : bb.readUnsignedShortLE(); - - if ((prefixByte & SEQ_DIFF) == SEQ_DIFF) { - if (bb.readableBytes() < 1) { - logError("buffer too small for packet header (2)"); - return -1; - } - int sequenceDiff = bb.readUnsignedByte(); - ack = (sequence - sequenceDiff) & 0xFFFF; - } else { - if (bb.readableBytes() < 2) { - logError("buffer too small for packet header (3)"); - return -1; - } - ack = bb.readUnsignedShortLE(); - } - - int expectedBytes = 0; - for (int i = ACK_BYTE0; i <= ACK_BYTE3; i <<= 1) { - if ((prefixByte & i) == i) expectedBytes++; - } - - if (bb.readableBytes() < expectedBytes) { - logError("buffer too small for packet header (4)"); - return -1; - } - ackBits = 0xFFFFFFFF; - if ((prefixByte & ACK_BYTE0) == ACK_BYTE0) { - ackBits &= ~ACK_BYTE0_MASK; - ackBits |= bb.readByte(); - } - if ((prefixByte & ACK_BYTE1) == ACK_BYTE1) { - ackBits &= ~ACK_BYTE1_MASK; - ackBits |= (bb.readByte() << 8); - } - if ((prefixByte & ACK_BYTE2) == ACK_BYTE2) { - ackBits &= ~ACK_BYTE2_MASK; - ackBits |= (bb.readByte() << 16); - } - if ((prefixByte & ACK_BYTE3) == ACK_BYTE3) { - ackBits &= ~ACK_BYTE3_MASK; - ackBits |= (bb.readByte() << 24); - } - - headerSize = bb.readerIndex() - startIndex + 1; // include prefixByte - return headerSize; - } - - static void writeHeader(ByteBuf bb, int channelId, int sequence, int ack, int ackBits) { - int prefixByte = getAckBitByteFlags(ackBits, 0); - - int sequenceDiff = sequence - ack; - if (sequenceDiff < 0) sequenceDiff += 0xFFFF; - if (sequenceDiff <= 0xFF) prefixByte |= SEQ_DIFF; - - bb.writeByte(prefixByte); - bb.writeByte(channelId); - bb.writeShortLE(sequence); - - if (sequenceDiff <= 0xFF) { - bb.writeByte(sequenceDiff); - } else { - bb.writeShortLE(ack); - } - - writeAckBitByteFlags(bb, ackBits); - } - - static void writeAck(ByteBuf bb, int channelId, int ack, int ackBits) { - int prefixByte = getAckBitByteFlags(ackBits, ACK); - - bb.writeByte(prefixByte); - bb.writeByte(channelId); - bb.writeShortLE(ack); - - writeAckBitByteFlags(bb, ackBits); - } } - static class FragmentedPacket extends Packet { - public int channelId; - public int sequence; - public int ack; - public int ackBits; + private static final Pool FRAGMENTED_HEADER_DATA_POOL = Pools.get(FragmentedHeaderData.class); - public int fragmentId; - public int numFragments; + public static FragmentedHeaderData obtainFragmentedData() { + return FRAGMENTED_HEADER_DATA_POOL.obtain(); + } - int headerSize; - int fragmentSize; + public static class FragmentedHeaderData { + public byte flags; + public int channelId; + public int sequence; + public int ack; + public int ackBits; + public int headerSize; + + public int fragmentId; + public int numFragments; + public int fragmentSize; + + public final HeaderData header = new HeaderData(); + + public void free() { + FRAGMENTED_HEADER_DATA_POOL.free(this); + } @Override public String toString() { return new ToStringBuilder(this) + .append("flags", String.format("%02x", flags)) .append("channelId", channelId) .append("sequence", sequence) .append("ack", ack) .append("ackBits", String.format("%08x", ackBits)) + .append("headerSize", headerSize) + .append("fragmentId", fragmentId) .append("numFragments", numFragments) + .append("fragmentSize", fragmentSize) + + .append("header", header) .build(); } - - @Override - int readHeader(ReliableConfig config, ByteBuf bb, final byte prefixByte) { - if ((prefixByte & TYPE_MASK) != FRAGMENTED) { - logError("packet header not flagged as fragmented packet"); - return -1; - } - - int startIndex = bb.readerIndex(); - - if (bb.readableBytes() < FRAGMENT_HEADER_SIZE) { - logError("buffer too small for fragment header"); - return -1; - } - channelId = bb.readUnsignedByte(); - sequence = bb.readUnsignedShortLE(); - - fragmentId = bb.readUnsignedByte(); - numFragments = bb.readUnsignedByte() + 1; - - if (numFragments > config.maxFragments) { - logError("num fragments %d outside of range of max fragments %d", numFragments, config.maxFragments); - return -1; - } - if (fragmentId >= numFragments) { - logError("fragment id %d outside of range of num fragments %d", fragmentId, numFragments); - return -1; - } - - if (fragmentId == 0) { - if (bb.readableBytes() < 1) { - logError("buffer too small for packet header"); - return -1; - } - SinglePacket packetHeader = new SinglePacket(); - int packetHeaderSize = packetHeader.readHeader(config, bb, bb.readByte()); - if (packetHeaderSize < 0) { - logError("bad packet header in fragment"); - return -1; - } - if (packetHeader.sequence != sequence) { - logError("bad packet sequence in fragment. expected %d, got %d", sequence, packetHeader.sequence); - return -1; - } - ack = packetHeader.ack; - ackBits = packetHeader.ackBits; - fragmentSize = bb.readableBytes(); - } else { - ack = 0; - ackBits = 0; - fragmentSize = bb.readableBytes(); - } - - if (fragmentSize > config.fragmentSize) { - logError("fragment bytes %d > fragment size %d", fragmentSize, config.fragmentSize); - return -1; - } - - if (fragmentId != numFragments - 1 && fragmentSize != config.fragmentSize) { - logError("fragment %d is %d bytes, which is not the expected fragment size %d bytes", fragmentId, fragmentSize, config.fragmentSize); - return -1; - } - - headerSize = bb.readerIndex() - startIndex + 1; // include prefixByte - return headerSize; - } } } diff --git a/server/netty/src/com/riiablo/net/reliable/ReliableConfig.java b/server/netty/src/com/riiablo/net/reliable/ReliableConfig.java deleted file mode 100644 index 693f38f1..00000000 --- a/server/netty/src/com/riiablo/net/reliable/ReliableConfig.java +++ /dev/null @@ -1,17 +0,0 @@ -package com.riiablo.net.reliable; - -public class ReliableConfig { - public static final ReliableConfig DEFAULT_CONFIG = new ReliableConfig(); - - public int maxPacketSize = 16384; - public int fragmentThreshold = 1024; - public int maxFragments = 16; - public int fragmentSize = 1024; - public int sentPacketBufferSize = 256; - public int receivedPacketBufferSize = 256; - public int fragmentReassemblyBufferSize = 64; - public float rttSmoothingFactor = 0.25f; - public float packetLossSmoothingFactor = 0.1f; - public float bandwidthSmoothingFactor = 0.1f; - public int packetHeaderSize = 28; -}