@@ -5,59 +5,209 @@ Subject: [PATCH] Cache user authenticator threads
5
5
6
6
7
7
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
9
9
--- a/src/main/java/net/minecraft/server/network/ServerLoginPacketListenerImpl.java
10
10
+++ b/src/main/java/net/minecraft/server/network/ServerLoginPacketListenerImpl.java
11
11
@@ -112,6 +112,8 @@ public class ServerLoginPacketListenerImpl implements ServerLoginPacketListener,
12
12
13
13
}
14
14
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
16
16
+
17
17
// Spigot start
18
18
public void initUUID()
19
19
{
20
- @@ -208,8 +210,8 @@ public class ServerLoginPacketListenerImpl implements ServerLoginPacketListener,
20
+ @@ -208,19 +210,25 @@ public class ServerLoginPacketListenerImpl implements ServerLoginPacketListener,
21
21
this.connection.send(new ClientboundHelloPacket("", this.server.getKeyPair().getPublic().getEncoded(), this.challenge));
22
22
} else {
23
23
// Spigot start
24
24
- new Thread("User Authenticator #" + ServerLoginPacketListenerImpl.UNIQUE_THREAD_ID.incrementAndGet()) {
25
25
-
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);
26
34
+ // 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
+ + }
33
46
}
34
- }
47
+ - }
35
48
- }.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
+ + }
37
54
+ // Paper end
38
55
// Spigot end
39
56
}
40
57
41
- @@ -257,7 +260,8 @@ public class ServerLoginPacketListenerImpl implements ServerLoginPacketListener,
58
+ @@ -257,55 +265,59 @@ public class ServerLoginPacketListenerImpl implements ServerLoginPacketListener,
42
59
throw new IllegalStateException("Protocol error", cryptographyexception);
43
60
}
44
61
45
62
- Thread thread = new Thread("User Authenticator #" + ServerLoginPacketListenerImpl.UNIQUE_THREAD_ID.incrementAndGet()) {
63
+ - public void run() {
64
+ - GameProfile gameprofile = ServerLoginPacketListenerImpl.this.gameProfile;
46
65
+ // 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
+ - }
50
133
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
+ + }
52
140
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
+ - }
55
143
- };
56
- -
144
+ + @Nullable
145
+ + private InetAddress getAddress() {
146
+ + SocketAddress socketaddress = ServerLoginPacketListenerImpl.this.connection.getRemoteAddress();
147
+
57
148
- thread.setUncaughtExceptionHandler(new DefaultUncaughtExceptionHandler(ServerLoginPacketListenerImpl.LOGGER));
58
149
- 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
+ + }
60
157
+ // Paper end
61
158
}
62
159
63
160
// 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