Skip to content

Commit

Permalink
Fix race condition when handling unknown packets. (#3508)
Browse files Browse the repository at this point in the history
(cherry picked from commit 875cc14)
  • Loading branch information
modmuss50 committed Jan 5, 2024
1 parent 6fb5fe4 commit d89921f
Show file tree
Hide file tree
Showing 2 changed files with 41 additions and 6 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,10 @@

package net.fabricmc.fabric.mixin.networking.client;

import org.slf4j.Logger;
import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
Expand All @@ -32,6 +35,10 @@

@Mixin(ClientCommonNetworkHandler.class)
public abstract class ClientCommonNetworkHandlerMixin implements NetworkHandlerExtensions {
@Shadow
@Final
private static Logger LOGGER;

@Inject(method = "onCustomPayload(Lnet/minecraft/network/packet/s2c/common/CustomPayloadS2CPacket;)V", at = @At("HEAD"), cancellable = true)
public void onCustomPayload(CustomPayloadS2CPacket packet, CallbackInfo ci) {
if (packet.payload() instanceof ResolvablePayload payload) {
Expand All @@ -45,14 +52,15 @@ public void onCustomPayload(CustomPayloadS2CPacket packet, CallbackInfo ci) {
throw new IllegalStateException("Unknown network addon");
}

if (handled) {
ci.cancel();
} else if (payload instanceof RetainedPayload retained && retained.buf().refCnt() > 0) {
// Vanilla forces to use the render thread for its payloads,
// that means this method can get called multiple times.
if (!handled && payload instanceof RetainedPayload retained && retained.buf().refCnt() > 0) {
// Duplicate the vanilla log message, as we cancel further processing.
LOGGER.warn("Unknown custom packet payload: {}", payload.id());

retained.buf().skipBytes(retained.buf().readableBytes());
retained.buf().release();
}

ci.cancel();
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
import static net.minecraft.server.command.CommandManager.literal;

import java.util.List;
import java.util.UUID;

import com.mojang.brigadier.Command;
import com.mojang.brigadier.CommandDispatcher;
Expand All @@ -38,6 +39,7 @@

import net.fabricmc.api.ModInitializer;
import net.fabricmc.fabric.api.command.v2.CommandRegistrationCallback;
import net.fabricmc.fabric.api.event.lifecycle.v1.ServerTickEvents;
import net.fabricmc.fabric.api.networking.v1.FabricPacket;
import net.fabricmc.fabric.api.networking.v1.PacketByteBufs;
import net.fabricmc.fabric.api.networking.v1.PacketType;
Expand All @@ -47,6 +49,7 @@
public final class NetworkingPlayPacketTest implements ModInitializer {
public static final Identifier TEST_CHANNEL = NetworkingTestmods.id("test_channel");
private static final Identifier UNKNOWN_TEST_CHANNEL = NetworkingTestmods.id("unknown_test_channel");
private static boolean spamUnknownPackets = false;

public static void sendToTestChannel(ServerPlayerEntity player, String stuff) {
ServerPlayNetworking.getSender(player).sendPacket(new OverlayPacket(Text.literal(stuff)), future -> {
Expand All @@ -55,7 +58,13 @@ public static void sendToTestChannel(ServerPlayerEntity player, String stuff) {
}

private static void sendToUnknownChannel(ServerPlayerEntity player) {
ServerPlayNetworking.getSender(player).sendPacket(UNKNOWN_TEST_CHANNEL, PacketByteBufs.create());
PacketByteBuf buf = PacketByteBufs.create();

for (int i = 0; i < 20; i++) {
buf.writeUuid(UUID.randomUUID());
}

ServerPlayNetworking.getSender(player).sendPacket(UNKNOWN_TEST_CHANNEL, buf);
}

public static void registerCommand(CommandDispatcher<ServerCommandSource> dispatcher) {
Expand All @@ -71,6 +80,11 @@ public static void registerCommand(CommandDispatcher<ServerCommandSource> dispat
sendToUnknownChannel(ctx.getSource().getPlayer());
return Command.SINGLE_SUCCESS;
}))
.then(literal("spamUnknown").executes(ctx -> {
spamUnknownPackets = true;
ctx.getSource().sendMessage(Text.literal("Spamming unknown packets state:" + spamUnknownPackets));
return Command.SINGLE_SUCCESS;
}))
.then(literal("bufctor").executes(ctx -> {
PacketByteBuf buf = PacketByteBufs.create();
buf.writeIdentifier(TEST_CHANNEL);
Expand Down Expand Up @@ -106,6 +120,19 @@ public void onInitialize() {
CommandRegistrationCallback.EVENT.register((dispatcher, registryAccess, environment) -> {
NetworkingPlayPacketTest.registerCommand(dispatcher);
});

ServerTickEvents.START_SERVER_TICK.register(server -> {
if (!spamUnknownPackets) {
return;
}

// Send many unknown packets, used to debug https://github.com/FabricMC/fabric/issues/3505
for (ServerPlayerEntity player : server.getPlayerManager().getPlayerList()) {
for (int i = 0; i < 50; i++) {
sendToUnknownChannel(player);
}
}
});
}

public record OverlayPacket(Text message) implements FabricPacket {
Expand Down

0 comments on commit d89921f

Please sign in to comment.