Skip to content

Commit 11ee8b7

Browse files
committed
Use a proper thread pool in ServerLoginPacketListenerImpl
1 parent 0ed4b91 commit 11ee8b7

File tree

1 file changed

+170
-20
lines changed

1 file changed

+170
-20
lines changed

patches/server/0111-Cache-user-authenticator-threads.patch

Lines changed: 170 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -5,59 +5,209 @@ Subject: [PATCH] Cache user authenticator threads
55

66

77
diff --git a/src/main/java/net/minecraft/server/network/ServerLoginPacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerLoginPacketListenerImpl.java
8-
index a6e90e70730e106d1cac01abf7a41df8df787d89..453a9dd794c39be5e7221b05fabb71b802691003 100644
8+
index a6e90e70730e106d1cac01abf7a41df8df787d89..b6103cfe2a5cce6feba51a2771cd0fa2dea97e43 100644
99
--- a/src/main/java/net/minecraft/server/network/ServerLoginPacketListenerImpl.java
1010
+++ b/src/main/java/net/minecraft/server/network/ServerLoginPacketListenerImpl.java
1111
@@ -112,6 +112,8 @@ public class ServerLoginPacketListenerImpl implements ServerLoginPacketListener,
1212

1313
}
1414

15-
+ 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
15+
+ 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
1616
+
1717
// Spigot start
1818
public void initUUID()
1919
{
20-
@@ -208,8 +210,8 @@ public class ServerLoginPacketListenerImpl implements ServerLoginPacketListener,
20+
@@ -208,19 +210,25 @@ public class ServerLoginPacketListenerImpl implements ServerLoginPacketListener,
2121
this.connection.send(new ClientboundHelloPacket("", this.server.getKeyPair().getPublic().getEncoded(), this.challenge));
2222
} else {
2323
// Spigot start
2424
- new Thread("User Authenticator #" + ServerLoginPacketListenerImpl.UNIQUE_THREAD_ID.incrementAndGet()) {
2525
-
26+
- @Override
27+
- public void run() {
28+
- try {
29+
- ServerLoginPacketListenerImpl.this.initUUID();
30+
- new LoginHandler().fireEvents();
31+
- } catch (Exception ex) {
32+
- ServerLoginPacketListenerImpl.this.disconnect("Failed to verify username!");
33+
- server.server.getLogger().log(java.util.logging.Level.WARNING, "Exception verifying " + ServerLoginPacketListenerImpl.this.gameProfile.getName(), ex);
2634
+ // Paper start - Cache authenticator threads
27-
+ authenticatorPool.execute(new Runnable() {
28-
@Override
29-
public void run() {
30-
try {
31-
@@ -220,7 +222,8 @@ public class ServerLoginPacketListenerImpl implements ServerLoginPacketListener,
32-
server.server.getLogger().log(java.util.logging.Level.WARNING, "Exception verifying " + ServerLoginPacketListenerImpl.this.gameProfile.getName(), ex);
35+
+ try {
36+
+ authenticatorPool.execute(new Runnable() {
37+
+ @Override
38+
+ public void run() {
39+
+ try {
40+
+ ServerLoginPacketListenerImpl.this.initUUID();
41+
+ new LoginHandler().fireEvents();
42+
+ } catch (Exception ex) {
43+
+ ServerLoginPacketListenerImpl.this.disconnect("Failed to verify username!");
44+
+ server.server.getLogger().log(java.util.logging.Level.WARNING, "Exception verifying " + ServerLoginPacketListenerImpl.this.gameProfile.getName(), ex);
45+
+ }
3346
}
34-
}
47+
- }
3548
- }.start();
36-
+ });
49+
+ });
50+
+ } catch (java.util.concurrent.RejectedExecutionException rejected) {
51+
+ ServerLoginPacketListenerImpl.this.disconnect("Failed to verify username!"); // Don't give attackers confirmation of a successful attack - don't change the message
52+
+ server.server.getLogger().log(java.util.logging.Level.WARNING, "Exception verifying " + ServerLoginPacketListenerImpl.this.gameProfile.getName() + " - auth queue full", rejected);
53+
+ }
3754
+ // Paper end
3855
// Spigot end
3956
}
4057

41-
@@ -257,7 +260,8 @@ public class ServerLoginPacketListenerImpl implements ServerLoginPacketListener,
58+
@@ -257,55 +265,59 @@ public class ServerLoginPacketListenerImpl implements ServerLoginPacketListener,
4259
throw new IllegalStateException("Protocol error", cryptographyexception);
4360
}
4461

4562
- Thread thread = new Thread("User Authenticator #" + ServerLoginPacketListenerImpl.UNIQUE_THREAD_ID.incrementAndGet()) {
63+
- public void run() {
64+
- GameProfile gameprofile = ServerLoginPacketListenerImpl.this.gameProfile;
4665
+ // Paper start - Cache authenticator threads
47-
+ authenticatorPool.execute(new Runnable() {
48-
public void run() {
49-
GameProfile gameprofile = ServerLoginPacketListenerImpl.this.gameProfile;
66+
+ try {
67+
+ authenticatorPool.execute(new Runnable() {
68+
+ public void run() {
69+
+ GameProfile gameprofile = ServerLoginPacketListenerImpl.this.gameProfile;
70+
+
71+
+ try {
72+
+ ServerLoginPacketListenerImpl.this.gameProfile = ServerLoginPacketListenerImpl.this.server.getSessionService().hasJoinedServer(new GameProfile((UUID) null, gameprofile.getName()), s, this.getAddress());
73+
+ if (ServerLoginPacketListenerImpl.this.gameProfile != null) {
74+
+ // CraftBukkit start - fire PlayerPreLoginEvent
75+
+ if (!ServerLoginPacketListenerImpl.this.connection.isConnected()) {
76+
+ return;
77+
+ }
78+
79+
- try {
80+
- ServerLoginPacketListenerImpl.this.gameProfile = ServerLoginPacketListenerImpl.this.server.getSessionService().hasJoinedServer(new GameProfile((UUID) null, gameprofile.getName()), s, this.getAddress());
81+
- if (ServerLoginPacketListenerImpl.this.gameProfile != null) {
82+
- // CraftBukkit start - fire PlayerPreLoginEvent
83+
- if (!ServerLoginPacketListenerImpl.this.connection.isConnected()) {
84+
- return;
85+
+ new LoginHandler().fireEvents();
86+
+ } else if (ServerLoginPacketListenerImpl.this.server.isSingleplayer()) {
87+
+ ServerLoginPacketListenerImpl.LOGGER.warn("Failed to verify username but will let them in anyway!");
88+
+ ServerLoginPacketListenerImpl.this.gameProfile = gameprofile;
89+
+ ServerLoginPacketListenerImpl.this.state = ServerLoginPacketListenerImpl.State.READY_TO_ACCEPT;
90+
+ } else {
91+
+ ServerLoginPacketListenerImpl.this.disconnect(Component.translatable("multiplayer.disconnect.unverified_username"));
92+
+ ServerLoginPacketListenerImpl.LOGGER.error("Username '{}' tried to join with an invalid session", gameprofile.getName());
93+
}
94+
-
95+
- new LoginHandler().fireEvents();
96+
- } else if (ServerLoginPacketListenerImpl.this.server.isSingleplayer()) {
97+
- ServerLoginPacketListenerImpl.LOGGER.warn("Failed to verify username but will let them in anyway!");
98+
- ServerLoginPacketListenerImpl.this.gameProfile = gameprofile;
99+
- ServerLoginPacketListenerImpl.this.state = ServerLoginPacketListenerImpl.State.READY_TO_ACCEPT;
100+
- } else {
101+
- ServerLoginPacketListenerImpl.this.disconnect(Component.translatable("multiplayer.disconnect.unverified_username"));
102+
- ServerLoginPacketListenerImpl.LOGGER.error("Username '{}' tried to join with an invalid session", gameprofile.getName());
103+
- }
104+
- } catch (AuthenticationUnavailableException authenticationunavailableexception) {
105+
- if (ServerLoginPacketListenerImpl.this.server.isSingleplayer()) {
106+
- ServerLoginPacketListenerImpl.LOGGER.warn("Authentication servers are down but will let them in anyway!");
107+
- ServerLoginPacketListenerImpl.this.gameProfile = gameprofile;
108+
- ServerLoginPacketListenerImpl.this.state = ServerLoginPacketListenerImpl.State.READY_TO_ACCEPT;
109+
- } else {
110+
- ServerLoginPacketListenerImpl.this.disconnect(Component.translatable("multiplayer.disconnect.authservers_down"));
111+
- ServerLoginPacketListenerImpl.LOGGER.error("Couldn't verify username because servers are unavailable");
112+
+ } catch (AuthenticationUnavailableException authenticationunavailableexception) {
113+
+ if (ServerLoginPacketListenerImpl.this.server.isSingleplayer()) {
114+
+ ServerLoginPacketListenerImpl.LOGGER.warn("Authentication servers are down but will let them in anyway!");
115+
+ ServerLoginPacketListenerImpl.this.gameProfile = gameprofile;
116+
+ ServerLoginPacketListenerImpl.this.state = ServerLoginPacketListenerImpl.State.READY_TO_ACCEPT;
117+
+ } else {
118+
+ ServerLoginPacketListenerImpl.this.disconnect(io.papermc.paper.adventure.PaperAdventure.asVanilla(io.papermc.paper.configuration.GlobalConfiguration.get().messages.kick.authenticationServersDown)); // Paper
119+
+ ServerLoginPacketListenerImpl.LOGGER.error("Couldn't verify username because servers are unavailable");
120+
+ }
121+
+ // CraftBukkit start - catch all exceptions
122+
+ } catch (Exception exception) {
123+
+ ServerLoginPacketListenerImpl.this.disconnect("Failed to verify username!");
124+
+ server.server.getLogger().log(java.util.logging.Level.WARNING, "Exception verifying " + gameprofile.getName(), exception);
125+
+ // CraftBukkit end
126+
}
127+
- // CraftBukkit start - catch all exceptions
128+
- } catch (Exception exception) {
129+
- ServerLoginPacketListenerImpl.this.disconnect("Failed to verify username!");
130+
- server.server.getLogger().log(java.util.logging.Level.WARNING, "Exception verifying " + gameprofile.getName(), exception);
131+
- // CraftBukkit end
132+
- }
50133

51-
@@ -302,10 +306,8 @@ public class ServerLoginPacketListenerImpl implements ServerLoginPacketListener,
134+
- }
135+
-
136+
- @Nullable
137+
- private InetAddress getAddress() {
138+
- SocketAddress socketaddress = ServerLoginPacketListenerImpl.this.connection.getRemoteAddress();
139+
+ }
52140

53-
return ServerLoginPacketListenerImpl.this.server.getPreventProxyConnections() && socketaddress instanceof InetSocketAddress ? ((InetSocketAddress) socketaddress).getAddress() : null;
54-
}
141+
- return ServerLoginPacketListenerImpl.this.server.getPreventProxyConnections() && socketaddress instanceof InetSocketAddress ? ((InetSocketAddress) socketaddress).getAddress() : null;
142+
- }
55143
- };
56-
-
144+
+ @Nullable
145+
+ private InetAddress getAddress() {
146+
+ SocketAddress socketaddress = ServerLoginPacketListenerImpl.this.connection.getRemoteAddress();
147+
57148
- thread.setUncaughtExceptionHandler(new DefaultUncaughtExceptionHandler(ServerLoginPacketListenerImpl.LOGGER));
58149
- thread.start();
59-
+ });
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+
+ }
60157
+ // Paper end
61158
}
62159

63160
// Spigot start
161+
@@ -351,6 +363,52 @@ public class ServerLoginPacketListenerImpl implements ServerLoginPacketListener,
162+
// Spigot end
163+
164+
public void handleCustomQueryPacket(ServerboundCustomQueryPacket packet) {
165+
+ // Paper start - Velocity support
166+
+ if (io.papermc.paper.configuration.GlobalConfiguration.get().proxies.velocity.enabled && packet.getTransactionId() == this.velocityLoginMessageId) {
167+
+ net.minecraft.network.FriendlyByteBuf buf = packet.getData();
168+
+ if (buf == null) {
169+
+ this.disconnect("This server requires you to connect with Velocity.");
170+
+ return;
171+
+ }
172+
+
173+
+ if (!com.destroystokyo.paper.proxy.VelocityProxy.checkIntegrity(buf)) {
174+
+ this.disconnect("Unable to verify player details");
175+
+ return;
176+
+ }
177+
+
178+
+ int version = buf.readVarInt();
179+
+ if (version > com.destroystokyo.paper.proxy.VelocityProxy.MAX_SUPPORTED_FORWARDING_VERSION) {
180+
+ throw new IllegalStateException("Unsupported forwarding version " + version + ", wanted upto " + com.destroystokyo.paper.proxy.VelocityProxy.MAX_SUPPORTED_FORWARDING_VERSION);
181+
+ }
182+
+
183+
+ java.net.SocketAddress listening = this.connection.getRemoteAddress();
184+
+ int port = 0;
185+
+ if (listening instanceof java.net.InetSocketAddress) {
186+
+ port = ((java.net.InetSocketAddress) listening).getPort();
187+
+ }
188+
+ this.connection.address = new java.net.InetSocketAddress(com.destroystokyo.paper.proxy.VelocityProxy.readAddress(buf), port);
189+
+
190+
+ this.gameProfile = com.destroystokyo.paper.proxy.VelocityProxy.createProfile(buf);
191+
+
192+
+ //TODO Update handling for lazy sessions, might not even have to do anything?
193+
+
194+
+ // Proceed with login
195+
+ try {
196+
+ authenticatorPool.execute(() -> {
197+
+ try {
198+
+ new LoginHandler().fireEvents();
199+
+ } catch (Exception ex) {
200+
+ disconnect("Failed to verify username!");
201+
+ server.server.getLogger().log(java.util.logging.Level.WARNING, "Exception verifying " + gameProfile.getName(), ex);
202+
+ }
203+
+ });
204+
+ } catch (java.util.concurrent.RejectedExecutionException rejected) {
205+
+ disconnect("Failed to verify username!"); // Don't give attackers confirmation of a successful attack - don't change the message
206+
+ server.server.getLogger().log(java.util.logging.Level.WARNING, "Exception verifying " + gameProfile.getName() + " - auth queue full", rejected);
207+
+ }
208+
+ return;
209+
+ }
210+
+ // Paper end
211+
this.disconnect(Component.translatable("multiplayer.disconnect.unexpected_query_response"));
212+
}
213+

0 commit comments

Comments
 (0)