Skip to content

Commit 236ac68

Browse files
committed
Use a proper thread pool in ServerLoginPacketListenerImpl and MCUtil
1 parent 0ed4b91 commit 236ac68

File tree

1 file changed

+187
-0
lines changed

1 file changed

+187
-0
lines changed
Lines changed: 187 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,187 @@
1+
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
2+
From: egg82 <[email protected]>
3+
Date: Wed, 18 Jan 2023 12:02:42 -0700
4+
Subject: [PATCH] Use a proper thread pool in ServerLoginPacketListenerImpl and
5+
MCUtil
6+
7+
This addresses issue #8797 along with a note from @kennytv about a
8+
similar situation in MCUtil. The cached thread pool in
9+
ServerLoginPacketListenerImpl is replaced by a fixed thread pool and a
10+
bounded ArrayBlockingQueue has been added.
11+
12+
diff --git a/src/main/java/io/papermc/paper/util/MCUtil.java b/src/main/java/io/papermc/paper/util/MCUtil.java
13+
index d1a59c2af0557a816c094983ec60097fb4de060c..74f9e8d400a9f29d4847ce1db5bd9cf579d8579c 100644
14+
--- a/src/main/java/io/papermc/paper/util/MCUtil.java
15+
+++ b/src/main/java/io/papermc/paper/util/MCUtil.java
16+
@@ -56,7 +56,7 @@ import java.util.function.Supplier;
17+
18+
public final class MCUtil {
19+
public static final ThreadPoolExecutor asyncExecutor = new ThreadPoolExecutor(
20+
- 0, 2, 60L, TimeUnit.SECONDS,
21+
+ 2, 2, 60L, TimeUnit.SECONDS, // This pool is currently only used for GameProfileCache#save
22+
new LinkedBlockingQueue<>(),
23+
new ThreadFactoryBuilder()
24+
.setNameFormat("Paper Async Task Handler Thread - %1$d")
25+
diff --git a/src/main/java/net/minecraft/server/network/ServerLoginPacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerLoginPacketListenerImpl.java
26+
index a25306fe8a35bb70a490e6a0c01d0340bbc0d781..35ede90cef6f1b93bb67e45575bb66070e319014 100644
27+
--- a/src/main/java/net/minecraft/server/network/ServerLoginPacketListenerImpl.java
28+
+++ b/src/main/java/net/minecraft/server/network/ServerLoginPacketListenerImpl.java
29+
@@ -124,7 +124,7 @@ public class ServerLoginPacketListenerImpl implements ServerLoginPacketListener,
30+
31+
}
32+
33+
- private static final java.util.concurrent.ExecutorService authenticatorPool = java.util.concurrent.Executors.newCachedThreadPool(new com.google.common.util.concurrent.ThreadFactoryBuilder().setNameFormat("User Authenticator #%d").setUncaughtExceptionHandler(new DefaultUncaughtExceptionHandler(LOGGER)).build()); // Paper - Cache authenticator threads
34+
+ private static final java.util.concurrent.ExecutorService authenticatorPool = new java.util.concurrent.ThreadPoolExecutor(16, 16, 60L, java.util.concurrent.TimeUnit.SECONDS, new java.util.concurrent.ArrayBlockingQueue<>(1024), new com.google.common.util.concurrent.ThreadFactoryBuilder().setNameFormat("User Authenticator #%d").setUncaughtExceptionHandler(new DefaultUncaughtExceptionHandler(LOGGER)).build()); // Paper - Cache authenticator threads
35+
36+
// Spigot start
37+
public void initUUID()
38+
@@ -269,7 +269,8 @@ public class ServerLoginPacketListenerImpl implements ServerLoginPacketListener,
39+
// Paper end
40+
// Spigot start
41+
// Paper start - Cache authenticator threads
42+
- authenticatorPool.execute(new Runnable() {
43+
+ try {
44+
+ authenticatorPool.execute(new Runnable() {
45+
@Override
46+
public void run() {
47+
try {
48+
@@ -280,7 +281,11 @@ public class ServerLoginPacketListenerImpl implements ServerLoginPacketListener,
49+
server.server.getLogger().log(java.util.logging.Level.WARNING, "Exception verifying " + ServerLoginPacketListenerImpl.this.gameProfile.getName(), ex);
50+
}
51+
}
52+
- });
53+
+ });
54+
+ } catch (java.util.concurrent.RejectedExecutionException rejected) {
55+
+ ServerLoginPacketListenerImpl.this.disconnect("Failed to verify username!"); // Don't give attackers confirmation of a successful attack - don't change the message
56+
+ server.server.getLogger().log(java.util.logging.Level.WARNING, "Exception verifying " + ServerLoginPacketListenerImpl.this.gameProfile.getName() + " - auth queue full", rejected);
57+
+ }
58+
// Paper end
59+
// Spigot end
60+
}
61+
@@ -321,52 +326,57 @@ public class ServerLoginPacketListenerImpl implements ServerLoginPacketListener,
62+
}
63+
64+
// Paper start - Cache authenticator threads
65+
- authenticatorPool.execute(new Runnable() {
66+
- public void run() {
67+
- GameProfile gameprofile = ServerLoginPacketListenerImpl.this.gameProfile;
68+
-
69+
- try {
70+
- ServerLoginPacketListenerImpl.this.gameProfile = ServerLoginPacketListenerImpl.this.server.getSessionService().hasJoinedServer(new GameProfile((UUID) null, gameprofile.getName()), s, this.getAddress());
71+
- if (ServerLoginPacketListenerImpl.this.gameProfile != null) {
72+
- // CraftBukkit start - fire PlayerPreLoginEvent
73+
- if (!ServerLoginPacketListenerImpl.this.connection.isConnected()) {
74+
- return;
75+
- }
76+
+ try {
77+
+ authenticatorPool.execute(new Runnable() {
78+
+ public void run() {
79+
+ GameProfile gameprofile = ServerLoginPacketListenerImpl.this.gameProfile;
80+
+
81+
+ try {
82+
+ ServerLoginPacketListenerImpl.this.gameProfile = ServerLoginPacketListenerImpl.this.server.getSessionService().hasJoinedServer(new GameProfile((UUID) null, gameprofile.getName()), s, this.getAddress());
83+
+ if (ServerLoginPacketListenerImpl.this.gameProfile != null) {
84+
+ // CraftBukkit start - fire PlayerPreLoginEvent
85+
+ if (!ServerLoginPacketListenerImpl.this.connection.isConnected()) {
86+
+ return;
87+
+ }
88+
89+
- new LoginHandler().fireEvents();
90+
- } else if (ServerLoginPacketListenerImpl.this.server.isSingleplayer()) {
91+
- ServerLoginPacketListenerImpl.LOGGER.warn("Failed to verify username but will let them in anyway!");
92+
- ServerLoginPacketListenerImpl.this.gameProfile = gameprofile;
93+
- ServerLoginPacketListenerImpl.this.state = ServerLoginPacketListenerImpl.State.READY_TO_ACCEPT;
94+
- } else {
95+
- ServerLoginPacketListenerImpl.this.disconnect(Component.translatable("multiplayer.disconnect.unverified_username"));
96+
- ServerLoginPacketListenerImpl.LOGGER.error("Username '{}' tried to join with an invalid session", gameprofile.getName());
97+
- }
98+
- } catch (AuthenticationUnavailableException authenticationunavailableexception) {
99+
- if (ServerLoginPacketListenerImpl.this.server.isSingleplayer()) {
100+
- ServerLoginPacketListenerImpl.LOGGER.warn("Authentication servers are down but will let them in anyway!");
101+
- ServerLoginPacketListenerImpl.this.gameProfile = gameprofile;
102+
- ServerLoginPacketListenerImpl.this.state = ServerLoginPacketListenerImpl.State.READY_TO_ACCEPT;
103+
- } else {
104+
- ServerLoginPacketListenerImpl.this.disconnect(io.papermc.paper.adventure.PaperAdventure.asVanilla(io.papermc.paper.configuration.GlobalConfiguration.get().messages.kick.authenticationServersDown)); // Paper
105+
- ServerLoginPacketListenerImpl.LOGGER.error("Couldn't verify username because servers are unavailable");
106+
+ new LoginHandler().fireEvents();
107+
+ } else if (ServerLoginPacketListenerImpl.this.server.isSingleplayer()) {
108+
+ ServerLoginPacketListenerImpl.LOGGER.warn("Failed to verify username but will let them in anyway!");
109+
+ ServerLoginPacketListenerImpl.this.gameProfile = gameprofile;
110+
+ ServerLoginPacketListenerImpl.this.state = ServerLoginPacketListenerImpl.State.READY_TO_ACCEPT;
111+
+ } else {
112+
+ ServerLoginPacketListenerImpl.this.disconnect(Component.translatable("multiplayer.disconnect.unverified_username"));
113+
+ ServerLoginPacketListenerImpl.LOGGER.error("Username '{}' tried to join with an invalid session", gameprofile.getName());
114+
+ }
115+
+ } catch (AuthenticationUnavailableException authenticationunavailableexception) {
116+
+ if (ServerLoginPacketListenerImpl.this.server.isSingleplayer()) {
117+
+ ServerLoginPacketListenerImpl.LOGGER.warn("Authentication servers are down but will let them in anyway!");
118+
+ ServerLoginPacketListenerImpl.this.gameProfile = gameprofile;
119+
+ ServerLoginPacketListenerImpl.this.state = ServerLoginPacketListenerImpl.State.READY_TO_ACCEPT;
120+
+ } else {
121+
+ ServerLoginPacketListenerImpl.this.disconnect(io.papermc.paper.adventure.PaperAdventure.asVanilla(io.papermc.paper.configuration.GlobalConfiguration.get().messages.kick.authenticationServersDown)); // Paper
122+
+ ServerLoginPacketListenerImpl.LOGGER.error("Couldn't verify username because servers are unavailable");
123+
+ }
124+
+ // CraftBukkit start - catch all exceptions
125+
+ } catch (Exception exception) {
126+
+ ServerLoginPacketListenerImpl.this.disconnect("Failed to verify username!");
127+
+ server.server.getLogger().log(java.util.logging.Level.WARNING, "Exception verifying " + gameprofile.getName(), exception);
128+
+ // CraftBukkit end
129+
}
130+
- // CraftBukkit start - catch all exceptions
131+
- } catch (Exception exception) {
132+
- ServerLoginPacketListenerImpl.this.disconnect("Failed to verify username!");
133+
- server.server.getLogger().log(java.util.logging.Level.WARNING, "Exception verifying " + gameprofile.getName(), exception);
134+
- // CraftBukkit end
135+
- }
136+
137+
- }
138+
+ }
139+
140+
- @Nullable
141+
- private InetAddress getAddress() {
142+
- SocketAddress socketaddress = ServerLoginPacketListenerImpl.this.connection.getRemoteAddress();
143+
+ @Nullable
144+
+ private InetAddress getAddress() {
145+
+ SocketAddress socketaddress = ServerLoginPacketListenerImpl.this.connection.getRemoteAddress();
146+
147+
- return ServerLoginPacketListenerImpl.this.server.getPreventProxyConnections() && socketaddress instanceof InetSocketAddress ? ((InetSocketAddress) socketaddress).getAddress() : null;
148+
- }
149+
- });
150+
+ return ServerLoginPacketListenerImpl.this.server.getPreventProxyConnections() && socketaddress instanceof InetSocketAddress ? ((InetSocketAddress) socketaddress).getAddress() : null;
151+
+ }
152+
+ });
153+
+ } catch (java.util.concurrent.RejectedExecutionException rejected) {
154+
+ ServerLoginPacketListenerImpl.this.disconnect("Failed to verify username!"); // Don't give attackers confirmation of a successful attack - don't change the message
155+
+ server.server.getLogger().log(java.util.logging.Level.WARNING, "Exception verifying " + (ServerLoginPacketListenerImpl.this.gameProfile != null ? ServerLoginPacketListenerImpl.this.gameProfile.getName() : "(address) " + ServerLoginPacketListenerImpl.this.connection.getRemoteAddress()) + " - auth queue full", rejected);
156+
+ }
157+
// Paper end
158+
}
159+
160+
@@ -458,14 +468,19 @@ public class ServerLoginPacketListenerImpl implements ServerLoginPacketListener,
161+
//TODO Update handling for lazy sessions, might not even have to do anything?
162+
163+
// Proceed with login
164+
- authenticatorPool.execute(() -> {
165+
- try {
166+
- new LoginHandler().fireEvents();
167+
- } catch (Exception ex) {
168+
- disconnect("Failed to verify username!");
169+
- server.server.getLogger().log(java.util.logging.Level.WARNING, "Exception verifying " + gameProfile.getName(), ex);
170+
- }
171+
- });
172+
+ try {
173+
+ authenticatorPool.execute(() -> {
174+
+ try {
175+
+ new LoginHandler().fireEvents();
176+
+ } catch (Exception ex) {
177+
+ disconnect("Failed to verify username!");
178+
+ server.server.getLogger().log(java.util.logging.Level.WARNING, "Exception verifying " + gameProfile.getName(), ex);
179+
+ }
180+
+ });
181+
+ } catch (java.util.concurrent.RejectedExecutionException rejected) {
182+
+ disconnect("Failed to verify username!"); // Don't give attackers confirmation of a successful attack - don't change the message
183+
+ server.server.getLogger().log(java.util.logging.Level.WARNING, "Exception verifying " + gameProfile.getName() + " - auth queue full", rejected);
184+
+ }
185+
return;
186+
}
187+
// Paper end

0 commit comments

Comments
 (0)