Fix login compression setup ordering/race condition (#13929)

This commit is contained in:
Beanes 2026-08-07 09:03:16 +02:00 committed by GitHub
parent ae22db2692
commit 2951b50613
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 60 additions and 20 deletions

View file

@ -28,7 +28,7 @@ and then catch exceptions and close if they fire.
Part of this commit was authored by: Spottedleaf, sandtechnology
diff --git a/net/minecraft/network/Connection.java b/net/minecraft/network/Connection.java
index 6e7331dc7bc5f7e69f21eec0b42141dde36a6c08..fceaac42791034a047d2af4acfd160a14a25a59a 100644
index cc91fceced12698146766a6b09a8dce8f573f39e..3f10ea62d2ef70e7e4f01c83942cd9051249954c 100644
--- a/net/minecraft/network/Connection.java
+++ b/net/minecraft/network/Connection.java
@@ -65,7 +65,7 @@ public class Connection extends SimpleChannelInboundHandler<Packet<?>> {
@ -102,7 +102,7 @@ index 6e7331dc7bc5f7e69f21eec0b42141dde36a6c08..fceaac42791034a047d2af4acfd160a1
}
}
@@ -420,21 +451,42 @@ public class Connection extends SimpleChannelInboundHandler<Packet<?>> {
@@ -444,21 +475,42 @@ public class Connection extends SimpleChannelInboundHandler<Packet<?>> {
}
private void doSendPacket(final Packet<?> packet, final @Nullable ChannelFutureListener listener, final boolean flush) {
@ -125,7 +125,7 @@ index 6e7331dc7bc5f7e69f21eec0b42141dde36a6c08..fceaac42791034a047d2af4acfd160a1
} else {
- this.channel.write(packet, this.channel.voidPromise());
+ future = this.channel.write(packet, this.channel.voidPromise()); // Paper - Optimize network
+ }
}
+
+ // Paper start - Optimize network
+ if (packet.hasFinishListener()) {
@ -136,7 +136,7 @@ index 6e7331dc7bc5f7e69f21eec0b42141dde36a6c08..fceaac42791034a047d2af4acfd160a1
+ Component reason = Component.translatable("disconnect.genericReason", "Internal Exception: " + e.getMessage());
+ this.send(new ClientboundDisconnectPacket(reason), PacketSendListener.thenRun(() -> this.disconnect(reason)));
+ packet.onPacketDispatchFinish(player, null);
}
+ }
+ // Paper end - Optimize network
}
@ -149,7 +149,7 @@ index 6e7331dc7bc5f7e69f21eec0b42141dde36a6c08..fceaac42791034a047d2af4acfd160a1
}
}
@@ -446,16 +498,57 @@ public class Connection extends SimpleChannelInboundHandler<Packet<?>> {
@@ -470,16 +522,57 @@ public class Connection extends SimpleChannelInboundHandler<Packet<?>> {
}
}
@ -212,7 +212,7 @@ index 6e7331dc7bc5f7e69f21eec0b42141dde36a6c08..fceaac42791034a047d2af4acfd160a1
private static final int MAX_PER_TICK = io.papermc.paper.configuration.GlobalConfiguration.get().misc.maxJoinsPerTick; // Paper - Buffer joins to world
private static int joinAttemptsThisTick; // Paper - Buffer joins to world
@@ -525,6 +618,7 @@ public class Connection extends SimpleChannelInboundHandler<Packet<?>> {
@@ -549,6 +642,7 @@ public class Connection extends SimpleChannelInboundHandler<Packet<?>> {
public void disconnect(final DisconnectionDetails details) {
this.preparing = false; // Spigot
@ -220,7 +220,7 @@ index 6e7331dc7bc5f7e69f21eec0b42141dde36a6c08..fceaac42791034a047d2af4acfd160a1
if (this.channel == null) {
this.delayedDisconnect = details;
}
@@ -714,7 +808,7 @@ public class Connection extends SimpleChannelInboundHandler<Packet<?>> {
@@ -738,7 +832,7 @@ public class Connection extends SimpleChannelInboundHandler<Packet<?>> {
public void handleDisconnection() {
if (this.channel != null && !this.channel.isOpen()) {
if (this.disconnectionHandled) {
@ -229,7 +229,7 @@ index 6e7331dc7bc5f7e69f21eec0b42141dde36a6c08..fceaac42791034a047d2af4acfd160a1
} else {
this.disconnectionHandled = true;
PacketListener packetListener = this.getPacketListener();
@@ -725,7 +819,7 @@ public class Connection extends SimpleChannelInboundHandler<Packet<?>> {
@@ -749,7 +843,7 @@ public class Connection extends SimpleChannelInboundHandler<Packet<?>> {
);
disconnectListener.onDisconnect(details);
}
@ -238,7 +238,7 @@ index 6e7331dc7bc5f7e69f21eec0b42141dde36a6c08..fceaac42791034a047d2af4acfd160a1
// Paper start - Add PlayerConnectionCloseEvent
if (packetListener instanceof net.minecraft.server.network.ServerCommonPacketListenerImpl commonPacketListener) {
/* Player was logged in, either game listener or configuration listener */
@@ -768,4 +862,96 @@ public class Connection extends SimpleChannelInboundHandler<Packet<?>> {
@@ -792,4 +886,96 @@ public class Connection extends SimpleChannelInboundHandler<Packet<?>> {
public @Nullable UUID getIntendedProfileId() {
return this.intendedProfileId;
}
@ -372,7 +372,7 @@ index 1480d0db90f5797e3dee19503e52d1e783493ac3..bd76e55ea56dd7c1e232806d1d13a747
+ // Paper end
}
diff --git a/net/minecraft/server/network/ServerConnectionListener.java b/net/minecraft/server/network/ServerConnectionListener.java
index ffa34134e3b4b6fdeafc0922e4eb49be12c6fbb7..c5e029444adb05c129d51b51f63fcf63a8c70ce8 100644
index b7476ff3f5570b92e9e4ca8fc756f3a8098b1385..1a60071f32a0c92c69f60c75035e5324aa144fb4 100644
--- a/net/minecraft/server/network/ServerConnectionListener.java
+++ b/net/minecraft/server/network/ServerConnectionListener.java
@@ -55,11 +55,13 @@ public class ServerConnectionListener {

View file

@ -267,10 +267,10 @@ index 595db570b0ade9cad7de77d2ab7b10d9e68699df..ac095f59d9f17d8239d6493d1c1e3942
+ // Paper end - Use Velocity cipher
}
diff --git a/net/minecraft/network/Connection.java b/net/minecraft/network/Connection.java
index fceaac42791034a047d2af4acfd160a14a25a59a..01e5ff70c70dd7fab089d8965bd1c237fa239f45 100644
index 3f10ea62d2ef70e7e4f01c83942cd9051249954c..9a04309584a5b9b55d0d383619113835190ad8f9 100644
--- a/net/minecraft/network/Connection.java
+++ b/net/minecraft/network/Connection.java
@@ -744,10 +744,24 @@ public class Connection extends SimpleChannelInboundHandler<Packet<?>> {
@@ -768,10 +768,24 @@ public class Connection extends SimpleChannelInboundHandler<Packet<?>> {
return connection;
}
@ -298,7 +298,7 @@ index fceaac42791034a047d2af4acfd160a14a25a59a..01e5ff70c70dd7fab089d8965bd1c237
public boolean isConnected() {
return this.channel != null && this.channel.isOpen();
@@ -781,16 +795,17 @@ public class Connection extends SimpleChannelInboundHandler<Packet<?>> {
@@ -805,16 +819,17 @@ public class Connection extends SimpleChannelInboundHandler<Packet<?>> {
public void setupCompression(final int threshold, final boolean validateDecompressed) {
if (threshold >= 0) {
@ -320,7 +320,7 @@ index fceaac42791034a047d2af4acfd160a14a25a59a..01e5ff70c70dd7fab089d8965bd1c237
this.channel.pipeline().fireUserEventTriggered(io.papermc.paper.network.ConnectionEvent.COMPRESSION_THRESHOLD_SET); // Paper - Add Channel initialization listeners
} else {
diff --git a/net/minecraft/server/network/ServerConnectionListener.java b/net/minecraft/server/network/ServerConnectionListener.java
index c5e029444adb05c129d51b51f63fcf63a8c70ce8..4552ebad6154c0178f928a4e9a5fe061f6fbde52 100644
index 1a60071f32a0c92c69f60c75035e5324aa144fb4..e84e243f35b09691d03e9a9cf3de0c093b1d5cfb 100644
--- a/net/minecraft/server/network/ServerConnectionListener.java
+++ b/net/minecraft/server/network/ServerConnectionListener.java
@@ -80,6 +80,10 @@ public class ServerConnectionListener {
@ -335,10 +335,10 @@ index c5e029444adb05c129d51b51f63fcf63a8c70ce8..4552ebad6154c0178f928a4e9a5fe061
.add(
new ServerBootstrap()
diff --git a/net/minecraft/server/network/ServerLoginPacketListenerImpl.java b/net/minecraft/server/network/ServerLoginPacketListenerImpl.java
index 98f8d7001ba7af6373bea630c376af3c02cafac4..fb5a84d2a00528d5c8f549f238abb6aa20d1ccad 100644
index d6b6c6e7dce618c3f4aecc0969b7423771eab3ba..b94e01aa54b932b29370d1742b00ed73254fe4dc 100644
--- a/net/minecraft/server/network/ServerLoginPacketListenerImpl.java
+++ b/net/minecraft/server/network/ServerLoginPacketListenerImpl.java
@@ -255,9 +255,7 @@ public class ServerLoginPacketListenerImpl implements ServerLoginPacketListener,
@@ -257,9 +257,7 @@ public class ServerLoginPacketListenerImpl implements ServerLoginPacketListener,
SecretKey secretKey = packet.getSecretKey(serverPrivateKey);
digest = new BigInteger(Crypt.digestData("", this.server.getKeyPair().getPublic(), secretKey)).toString(16);
this.state = ServerLoginPacketListenerImpl.State.AUTHENTICATING;

View file

@ -182,6 +182,37 @@
} catch (RejectedExecutionException ignored) {
this.disconnect(Component.translatable("multiplayer.disconnect.server_shutdown"));
} catch (ClassCastException exception) {
@@ -297,6 +_,30 @@
}
}
+ // Paper start - Add netty task scheduling helper
+ /**
+ * Schedules a task on the channel's event loop after all currently queued packets have been submitted for writing.
+ * This allows the compression packet to be written and compression to be enabled in the same event-loop task.
+ * Vanilla enables compression from a write-future listener, which may run after another packet has already been
+ * queued without compression.
+ *
+ * @see <a href="https://mojira.dev/MC-308621">MC-308621</a>
+ */
+ public void scheduleNettyTask(final Runnable task) {
+ final boolean connected = this.isConnected();
+ if (!connected && !this.preparing) {
+ return;
+ }
+
+ if (connected && this.pendingActions.isEmpty()) {
+ this.channel.eventLoop().execute(task);
+ } else {
+ this.pendingActions.add(new WrappedConsumer(connection -> connection.channel.eventLoop().execute(task)));
+ this.flushQueue();
+ }
+ }
+ // Paper end - Add netty task scheduling helper
+
private void sendPacket(final Packet<?> packet, final @Nullable ChannelFutureListener listener, final boolean flush) {
this.sentPackets++;
if (this.channel.eventLoop().inEventLoop()) {
@@ -344,10 +_,30 @@
}
}

View file

@ -143,7 +143,7 @@
}
}
}
@@ -139,11 +_,11 @@
@@ -139,21 +_,23 @@
private void verifyLoginAndFinishConnectionSetup(final GameProfile profile) {
PlayerList playerList = this.server.getPlayerList();
@ -157,9 +157,18 @@
+ this.disconnectAsync(CommonComponents.CONNECT_FAILED); // Paper
} else {
if (this.server.getCompressionThreshold() >= 0 && !this.connection.isMemoryConnection()) {
this.connection
@@ -153,7 +_,7 @@
);
- this.connection
- .send(
- new ClientboundLoginCompressionPacket(this.server.getCompressionThreshold()),
- PacketSendListener.thenRun(() -> this.connection.setupCompression(this.server.getCompressionThreshold(), true))
- );
+ // Paper start - Keep compression packet write and setup in the same Netty task
+ final int compressionThreshold = this.server.getCompressionThreshold();
+ this.connection.scheduleNettyTask(() -> {
+ this.connection.send(new ClientboundLoginCompressionPacket(compressionThreshold));
+ this.connection.setupCompression(compressionThreshold, true);
+ });
+ // Paper end - Keep compression packet write and setup in the same Netty task
}
- boolean waitForDisconnection = playerList.disconnectAllPlayersWithProfile(profile.id());