From c702a66c71153a18697ed73625f0faea84747410 Mon Sep 17 00:00:00 2001 From: Tim203 Date: Tue, 19 Mar 2024 20:20:13 +0100 Subject: [PATCH] Made the debug addon a bit more dumb --- .../floodgate/core/addon/DebugAddon.java | 10 +- .../addon/debug/ChannelInDebugHandler.java | 20 +- .../addon/debug/ChannelOutDebugHandler.java | 21 +- .../core/addon/debug/StateChangeDetector.java | 193 ------------------ .../floodgate/core/util/Constants.java | 2 + .../geysermc/floodgate/core/util/Utils.java | 16 -- 6 files changed, 24 insertions(+), 238 deletions(-) delete mode 100644 core/src/main/java/org/geysermc/floodgate/core/addon/debug/StateChangeDetector.java diff --git a/core/src/main/java/org/geysermc/floodgate/core/addon/DebugAddon.java b/core/src/main/java/org/geysermc/floodgate/core/addon/DebugAddon.java index 044b888f..71760d56 100644 --- a/core/src/main/java/org/geysermc/floodgate/core/addon/DebugAddon.java +++ b/core/src/main/java/org/geysermc/floodgate/core/addon/DebugAddon.java @@ -30,10 +30,10 @@ import jakarta.inject.Inject; import jakarta.inject.Named; import jakarta.inject.Singleton; +import java.util.concurrent.atomic.AtomicInteger; import org.geysermc.floodgate.api.inject.InjectorAddon; import org.geysermc.floodgate.core.addon.debug.ChannelInDebugHandler; import org.geysermc.floodgate.core.addon.debug.ChannelOutDebugHandler; -import org.geysermc.floodgate.core.addon.debug.StateChangeDetector; import org.geysermc.floodgate.core.config.FloodgateConfig; import org.geysermc.floodgate.core.logger.FloodgateLogger; import org.geysermc.floodgate.core.util.Utils; @@ -59,16 +59,14 @@ public final class DebugAddon implements InjectorAddon { public void onInject(Channel channel, boolean toServer) { logger.info("Successfully called onInject. To server? {} ({})", toServer, channel.id()); - StateChangeDetector changeDetector = new StateChangeDetector( - channel, packetEncoder, packetDecoder, logger - ); + var packetCount = new AtomicInteger(); channel.pipeline().addBefore( packetEncoder, "floodgate_debug_out", - new ChannelOutDebugHandler(implementationName, toServer, changeDetector, logger) + new ChannelOutDebugHandler(implementationName, toServer, packetCount, logger) ).addBefore( packetDecoder, "floodgate_debug_in", - new ChannelInDebugHandler(implementationName, toServer, changeDetector, logger) + new ChannelInDebugHandler(implementationName, toServer, packetCount, logger) ); } diff --git a/core/src/main/java/org/geysermc/floodgate/core/addon/debug/ChannelInDebugHandler.java b/core/src/main/java/org/geysermc/floodgate/core/addon/debug/ChannelInDebugHandler.java index 1ff68975..669e41c6 100644 --- a/core/src/main/java/org/geysermc/floodgate/core/addon/debug/ChannelInDebugHandler.java +++ b/core/src/main/java/org/geysermc/floodgate/core/addon/debug/ChannelInDebugHandler.java @@ -30,25 +30,25 @@ import io.netty.channel.ChannelHandler.Sharable; import io.netty.channel.ChannelHandlerContext; import io.netty.channel.SimpleChannelInboundHandler; +import java.util.concurrent.atomic.AtomicInteger; import org.geysermc.floodgate.core.logger.FloodgateLogger; +import org.geysermc.floodgate.core.util.Constants; @Sharable public final class ChannelInDebugHandler extends SimpleChannelInboundHandler { private final String direction; private final FloodgateLogger logger; - private final boolean toServer; - private final StateChangeDetector changeDetector; + private final AtomicInteger packetCount; public ChannelInDebugHandler( String implementationType, boolean toServer, - StateChangeDetector changeDetector, + AtomicInteger packetCount, FloodgateLogger logger) { this.direction = (toServer ? "Server -> " : "Player -> ") + implementationType; this.logger = logger; - this.toServer = toServer; - this.changeDetector = changeDetector; + this.packetCount = packetCount; } @Override @@ -56,22 +56,20 @@ protected void channelRead0(ChannelHandlerContext ctx, ByteBuf msg) { try { int index = msg.readerIndex(); - if (changeDetector.shouldPrintPacket(msg, !toServer)) { + if (packetCount.getAndIncrement() < Constants.MAX_DEBUG_PACKET_COUNT) { logger.info("{} {}:\n{}", direction, - changeDetector.getCurrentState(), + packetCount.get(), ByteBufUtil.prettyHexDump(msg) ); - - changeDetector.checkPacket(msg, !toServer); } // reset index msg.readerIndex(index); ctx.fireChannelRead(msg.retain()); - } catch (Exception e) { - e.printStackTrace(); + } catch (Exception exception) { + logger.error("Error in ChannelInDebugHandler", exception); } } } diff --git a/core/src/main/java/org/geysermc/floodgate/core/addon/debug/ChannelOutDebugHandler.java b/core/src/main/java/org/geysermc/floodgate/core/addon/debug/ChannelOutDebugHandler.java index e79687c6..d4fe5c0e 100644 --- a/core/src/main/java/org/geysermc/floodgate/core/addon/debug/ChannelOutDebugHandler.java +++ b/core/src/main/java/org/geysermc/floodgate/core/addon/debug/ChannelOutDebugHandler.java @@ -30,25 +30,25 @@ import io.netty.channel.ChannelHandler.Sharable; import io.netty.channel.ChannelHandlerContext; import io.netty.handler.codec.MessageToByteEncoder; +import java.util.concurrent.atomic.AtomicInteger; import org.geysermc.floodgate.core.logger.FloodgateLogger; +import org.geysermc.floodgate.core.util.Constants; @Sharable public final class ChannelOutDebugHandler extends MessageToByteEncoder { private final String direction; private final FloodgateLogger logger; - private final boolean toServer; - private final StateChangeDetector changeDetector; + private final AtomicInteger packetCount; public ChannelOutDebugHandler( String implementationType, boolean toServer, - StateChangeDetector changeDetector, + AtomicInteger packetCount, FloodgateLogger logger) { this.direction = implementationType + (toServer ? " -> Server" : " -> Player"); this.logger = logger; - this.toServer = toServer; - this.changeDetector = changeDetector; + this.packetCount = packetCount; } @Override @@ -56,24 +56,21 @@ protected void encode(ChannelHandlerContext ctx, ByteBuf msg, ByteBuf out) { try { int index = msg.readerIndex(); - if (changeDetector.shouldPrintPacket(msg, toServer)) { + if (packetCount.getAndIncrement() < Constants.MAX_DEBUG_PACKET_COUNT) { logger.info( "{} {}:\n{}", direction, - changeDetector.getCurrentState(), + packetCount.get(), ByteBufUtil.prettyHexDump(msg) ); - - // proxy acts as a client when it connects to a server - changeDetector.checkPacket(msg, toServer); } // reset index msg.readerIndex(index); out.writeBytes(msg); - } catch (Exception e) { - e.printStackTrace(); + } catch (Exception exception) { + logger.error("Error in ChannelOutDebugHandler", exception); } } } diff --git a/core/src/main/java/org/geysermc/floodgate/core/addon/debug/StateChangeDetector.java b/core/src/main/java/org/geysermc/floodgate/core/addon/debug/StateChangeDetector.java deleted file mode 100644 index 50f0ce57..00000000 --- a/core/src/main/java/org/geysermc/floodgate/core/addon/debug/StateChangeDetector.java +++ /dev/null @@ -1,193 +0,0 @@ -/* - * Copyright (c) 2019-2023 GeyserMC. http://geysermc.org - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - * - * @author GeyserMC - * @link https://github.com/GeyserMC/Floodgate - */ - -package org.geysermc.floodgate.core.addon.debug; - -import io.netty.buffer.ByteBuf; -import io.netty.channel.Channel; -import io.netty.channel.ChannelHandler; -import io.netty.channel.ChannelPipeline; -import java.nio.charset.StandardCharsets; -import org.geysermc.floodgate.core.logger.FloodgateLogger; -import org.geysermc.floodgate.core.util.Constants; -import org.geysermc.floodgate.core.util.Utils; - -public class StateChangeDetector { - private static volatile int pluginMessageToClientId = -1; - private static volatile int pluginMessageToServerId = -1; - - private final Channel channel; - private final FloodgateLogger logger; - private final String packetEncoderName; - private final String packetDecoderName; - - private volatile boolean enableCompressionNext; - private volatile State currentState = State.HANDSHAKE; - - public StateChangeDetector( - Channel channel, - String packetEncoderName, - String packetDecoderName, - FloodgateLogger logger) { - this.channel = channel; - this.packetEncoderName = packetEncoderName; - this.packetDecoderName = packetDecoderName; - this.logger = logger; - } - - /** - * Checks (and acts) if the current packet is one of the packets that we need to switch states. - * - * @param packet the packet to check - * @param fromClient if the packet is clientbound or serverbound - */ - public void checkPacket(ByteBuf packet, boolean fromClient) { - int index = packet.readerIndex(); - - if (enableCompressionNext) { - // data length - Utils.readVarInt(packet); - - fixCompressionPipes(); - enableCompressionNext = false; - } - - int packetId = Utils.readVarInt(packet); - - if (fromClient) { - if (currentState == State.HANDSHAKE && packetId == Constants.HANDSHAKE_PACKET_ID) { - // have to read the content to determine the next state - - // protocol version - Utils.readVarInt(packet); - // server address - int hostLength = Utils.readVarInt(packet); - // read server address + port (short = 2 bytes) - packet.readerIndex(packet.readerIndex() + hostLength + 2); - // next state - currentState = State.getById(Utils.readVarInt(packet)); - } - } else { - if (currentState == State.LOGIN) { - if (packetId == Constants.LOGIN_SUCCESS_PACKET_ID) { - currentState = State.PLAY; - } - if (packetId == Constants.SET_COMPRESSION_PACKET_ID) { - enableCompressionNext = true; - } - } - } - - // reset index - packet.readerIndex(index); - } - - private void fixCompressionPipes() { - // The previous packet was the compression packet, meaning that starting with this - // packet the data can already be compressed. The compression handler has been added - // directly before the packet encoder and decoder, so we have to reclaim that place. - // If we don't, we'll see the compressed data. - - ChannelPipeline pipeline = channel.pipeline(); - - ChannelHandler outDebug = pipeline.remove(ChannelOutDebugHandler.class); - ChannelHandler inDebug = pipeline.remove(ChannelInDebugHandler.class); - - pipeline.addBefore(packetEncoderName, "floodgate_debug_out", outDebug); - pipeline.addBefore(packetDecoderName, "floodgate_debug_in", inDebug); - } - - public boolean shouldPrintPacket(ByteBuf packet, boolean clientbound) { - return Constants.PRINT_ALL_PACKETS || - currentState == State.HANDSHAKE || currentState == State.LOGIN || - currentState != State.STATUS && shouldPrintPlayPacket(packet, clientbound); - } - - public boolean shouldPrintPlayPacket(ByteBuf packet, boolean clientbound) { - int index = packet.readerIndex(); - - int packetId = Utils.readVarInt(packet); - - // we're only interested in the plugin message packets - - // use cached packet ids - if (clientbound && pluginMessageToClientId != -1) { - return pluginMessageToClientId == packetId; - } - if (!clientbound && pluginMessageToServerId != -1) { - return pluginMessageToServerId == packetId; - } - - boolean shouldPrint = false; - - if (packet.isReadable()) { - // format plugin message packet: channel - remaining data - try { - int channelLength = Utils.readVarInt(packet); - - if (channelLength >= 1 && channelLength <= 128 && - packet.isReadable(channelLength)) { - - byte[] channelBytes = new byte[channelLength]; - packet.readBytes(channelBytes); - - String channelName = new String(channelBytes, StandardCharsets.UTF_8); - if (channelName.contains(":")) { - // some other packets will still match, - // but since plugin message packets are send early on - // we can almost know for certain that this is a plugin message packet - printIdentified(clientbound, packetId); - if (clientbound) { - pluginMessageToClientId = packetId; - } else { - pluginMessageToServerId = packetId; - } - shouldPrint = true; - } - } - } catch (RuntimeException ignored) { - // not the plugin message packet - } - } - - // reset index - packet.readerIndex(index); - - return shouldPrint; - } - - private void printIdentified(boolean clientbound, int packetId) { - logger.info( - "Identified plugin message packet ({}) as {} ({})", - clientbound ? "clientbound" : "serverbound", - packetId, - Integer.toHexString(packetId) - ); - } - - public State getCurrentState() { - return currentState; - } -} diff --git a/core/src/main/java/org/geysermc/floodgate/core/util/Constants.java b/core/src/main/java/org/geysermc/floodgate/core/util/Constants.java index 1f7b7bea..85232804 100644 --- a/core/src/main/java/org/geysermc/floodgate/core/util/Constants.java +++ b/core/src/main/java/org/geysermc/floodgate/core/util/Constants.java @@ -31,6 +31,8 @@ public final class Constants { public static final int CONFIG_VERSION = 3; public static final int PROTOCOL_HEX_COLOR = 713; // added in 20w17a (1.16 snapshot) + + public static final int MAX_DEBUG_PACKET_COUNT = 20; public static final boolean DEBUG_MODE = false; public static final boolean PRINT_ALL_PACKETS = false; diff --git a/core/src/main/java/org/geysermc/floodgate/core/util/Utils.java b/core/src/main/java/org/geysermc/floodgate/core/util/Utils.java index ac8eeb04..27d4912d 100644 --- a/core/src/main/java/org/geysermc/floodgate/core/util/Utils.java +++ b/core/src/main/java/org/geysermc/floodgate/core/util/Utils.java @@ -25,7 +25,6 @@ package org.geysermc.floodgate.core.util; -import io.netty.buffer.ByteBuf; import io.netty.channel.ChannelHandler; import io.netty.channel.ChannelPipeline; import java.io.IOException; @@ -119,21 +118,6 @@ public static char generateCodeChar() { return (char) ('A' + codeChar); } - public static int readVarInt(ByteBuf buffer) { - int out = 0; - int count = 0; - byte current; - do { - current = buffer.readByte(); - out |= (current & 0x7F) << (count++ * 7); - - if (count > 5) { - throw new RuntimeException("VarInt is bigger then allowed"); - } - } while ((current & 0x80) != 0); - return out; - } - public static String getStackTrace(Throwable throwable) { StringWriter writer = new StringWriter(); throwable.printStackTrace(new PrintWriter(writer));