Skip to content

Commit

Permalink
Allow ZLIB compression
Browse files Browse the repository at this point in the history
  • Loading branch information
Tim203 committed Aug 21, 2024
1 parent c60ac86 commit 2feb504
Show file tree
Hide file tree
Showing 6 changed files with 131 additions and 20 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,19 @@

import com.rtm516.mcxboxbroadcast.core.SessionInfo;
import com.rtm516.mcxboxbroadcast.core.webrtc.bedrock.RedirectPacketHandler;
import com.rtm516.mcxboxbroadcast.core.webrtc.compression.CompressionHandler;
import com.rtm516.mcxboxbroadcast.core.webrtc.encryption.BedrockEncryptionEncoder;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import javax.crypto.SecretKey;
import org.bouncycastle.util.encoders.Hex;
import org.cloudburstmc.protocol.bedrock.codec.BedrockCodec;
import org.cloudburstmc.protocol.bedrock.codec.BedrockCodecHelper;
import org.cloudburstmc.protocol.bedrock.data.DisconnectFailReason;
import org.cloudburstmc.protocol.bedrock.data.PacketCompressionAlgorithm;
import org.cloudburstmc.protocol.bedrock.netty.BedrockPacketWrapper;
import org.cloudburstmc.protocol.bedrock.netty.codec.packet.BedrockPacketCodec;
import org.cloudburstmc.protocol.bedrock.netty.codec.packet.BedrockPacketCodec_v3;
import org.cloudburstmc.protocol.bedrock.packet.BedrockPacket;
import org.cloudburstmc.protocol.bedrock.packet.DisconnectPacket;
import org.cloudburstmc.protocol.bedrock.packet.LoginPacket;
import org.cloudburstmc.protocol.bedrock.util.EncryptionUtils;
import org.cloudburstmc.protocol.common.util.VarInts;
Expand All @@ -28,7 +28,7 @@ public class MinecraftDataHandler implements SCTPByteStreamListener {
private final BedrockCodecHelper helper;
private final RedirectPacketHandler redirectPacketHandler;

private boolean compressionEnabled;
private CompressionHandler compressionHandler;
private BedrockEncryptionEncoder encryptionEncoder;

private ByteBuf concat;
Expand Down Expand Up @@ -56,15 +56,6 @@ public void onMessage(SCTPStream sctpStream, byte[] bytes) {
byte remainingSegments = buf.readByte();
System.out.println("first 100 bytes: " + Hex.toHexString(bytes, 0, Math.min(100, bytes.length)));

if (concat == null) {
if (compressionEnabled) {
if (0xff != buf.readUnsignedByte()) {
throw new IllegalStateException("Expected none compression!");
}
}
expectedLength = VarInts.readUnsignedInt(buf);
}

if (remainingSegments > 0) {
if (concat == null) {
concat = buf;
Expand All @@ -80,6 +71,11 @@ public void onMessage(SCTPStream sctpStream, byte[] bytes) {
concat = null;
}

if (compressionHandler != null) {
buf = compressionHandler.decode(buf);
}

expectedLength = VarInts.readUnsignedInt(buf);
// if (buf.readableBytes() != expectedLength) {
// System.out.println("expected " + expectedLength + " bytes but got " + buf.readableBytes());
// var disconnect = new DisconnectPacket();
Expand Down Expand Up @@ -115,7 +111,7 @@ public void sendPacket(BedrockPacket packet) {
System.out.println("S -> C: " + packet);
try {
ByteBuf dataBuf = Unpooled.buffer(128);
var shiftedBytes = (compressionEnabled ? 1 : 0) + 5; // leave enough room for compression byte & data length
var shiftedBytes = 5; // leave enough room for data length
dataBuf.writerIndex(shiftedBytes);

int packetId = codec.getPacketDefinition(packet.getClass()).getId();
Expand All @@ -135,12 +131,13 @@ public void sendPacket(BedrockPacket packet) {
dataBuf.readerIndex(5 - Utils.varintSize(packetLength));
dataBuf.writerIndex(dataBuf.readerIndex());

if (compressionEnabled) {
dataBuf.writeByte(0xFF);
}
VarInts.writeUnsignedInt(dataBuf, packetLength);
dataBuf.writerIndex(lastPacketByte);

if (compressionHandler != null) {
dataBuf = compressionHandler.encode(dataBuf);
}

var ri = dataBuf.readerIndex();
System.out.println("encoding: " + Hex.toHexString(encode(dataBuf)));
dataBuf.readerIndex(ri);
Expand Down Expand Up @@ -185,8 +182,8 @@ private BedrockPacket readPacket(ByteBuf buf) {
return packet;
}

public void enableCompression() {
compressionEnabled = true;
public void enableCompression(PacketCompressionAlgorithm compressionAlgorithm, int threshold) {
this.compressionHandler = new CompressionHandler(compressionAlgorithm, threshold);
}

public void enableEncryption(SecretKey secretKey) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -105,10 +105,10 @@ public PacketSignal handle(RequestNetworkSettingsPacket packet) {

NetworkSettingsPacket responsePacket = new NetworkSettingsPacket();
responsePacket.setCompressionAlgorithm(algorithm);
responsePacket.setCompressionThreshold(0);
responsePacket.setCompressionThreshold(512);
dataHandler.sendPacket(responsePacket);

dataHandler.enableCompression();
dataHandler.enableCompression(algorithm, 512);

networkSettingsRequested = true;
return PacketSignal.HANDLED;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package com.rtm516.mcxboxbroadcast.core.webrtc.compression;

import io.netty.buffer.ByteBuf;

public interface CompressionCodec {
ByteBuf encode(ByteBuf msg) throws Exception;

ByteBuf decode(ByteBuf msg) throws Exception;

int compressionIdentifier();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package com.rtm516.mcxboxbroadcast.core.webrtc.compression;

import io.netty.buffer.ByteBuf;
import org.cloudburstmc.protocol.bedrock.data.PacketCompressionAlgorithm;

public class CompressionHandler {
private final CompressionCodec chosenCodec;
private final NoneCompressionCodec fallback;
private final int threshold;

public CompressionHandler(PacketCompressionAlgorithm algorithm, int threshold) {
this.chosenCodec = switch (algorithm) {
case ZLIB -> new ZlibCompressionCodec();
case NONE -> new NoneCompressionCodec();
default -> throw new IllegalArgumentException("Unsupported compression algorithm: " + algorithm);
};

if (chosenCodec instanceof NoneCompressionCodec codec) {
this.fallback = codec;
} else {
this.fallback = new NoneCompressionCodec();
}
this.threshold = threshold;
}

public ByteBuf encode(ByteBuf buf) throws Exception {
if (buf.readableBytes() > threshold) {
return chosenCodec.encode(buf);
}
return fallback.encode(buf);
}

public ByteBuf decode(ByteBuf buf) throws Exception {
if (buf.readableBytes() > threshold) {
return chosenCodec.decode(buf);
}
return fallback.decode(buf);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package com.rtm516.mcxboxbroadcast.core.webrtc.compression;

import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;

public class NoneCompressionCodec implements CompressionCodec {
@Override
public ByteBuf encode(ByteBuf msg) throws Exception {
return Unpooled.buffer(msg.readableBytes() + 1)
.writeByte(compressionIdentifier())
.writeBytes(msg);
}

@Override
public ByteBuf decode(ByteBuf msg) throws Exception {
if (msg.readUnsignedByte() != compressionIdentifier()) {
throw new IllegalArgumentException("Unexpected compression identifier");
}
return msg;
}

@Override
public int compressionIdentifier() {
return 0xFF;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package com.rtm516.mcxboxbroadcast.core.webrtc.compression;

import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import org.cloudburstmc.protocol.common.util.Zlib;

public class ZlibCompressionCodec implements CompressionCodec {
private static final int MAX_DECOMPRESSED_BYTES = Integer.getInteger("bedrock.maxDecompressedBytes", 1024 * 1024 * 10);

private final Zlib zlib = Zlib.RAW;
private final int level = 7;

@Override
public ByteBuf encode(ByteBuf msg) throws Exception {
ByteBuf outBuf = Unpooled.buffer(msg.readableBytes() << 3 + 1);
outBuf.writeByte(compressionIdentifier());

try {
zlib.deflate(msg, outBuf, level);
return outBuf.retain();
} finally {
outBuf.release();
}
}

@Override
public ByteBuf decode(ByteBuf msg) throws Exception {
if (msg.readUnsignedByte() != compressionIdentifier()) {
throw new IllegalArgumentException("Unexpected compression identifier");
}
return zlib.inflate(msg, MAX_DECOMPRESSED_BYTES);
}

@Override
public int compressionIdentifier() {
return 0x00;
}
}

0 comments on commit 2feb504

Please sign in to comment.