From ffd0758857594384c867d03fdb9ac5939f06729c Mon Sep 17 00:00:00 2001 From: Dereku Date: Mon, 4 Dec 2023 02:25:04 +0700 Subject: [PATCH 01/10] =?UTF-8?q?1.3.=20=D0=9E=D0=BA=D0=B0=D0=B7=D1=8B?= =?UTF-8?q?=D0=B2=D0=B0=D0=B5=D1=82=D1=81=D1=8F,=20=D0=B7=D0=B0=D0=BA?= =?UTF-8?q?=D1=80=D1=8B=D0=B2=D0=B0=D1=82=D1=8C=20=D1=81=D0=BE=D0=BA=D0=B5?= =?UTF-8?q?=D1=82=20=D0=BD=D0=B5=20=D0=BD=D0=B0=D0=B4=D0=BE,=20=D0=BA?= =?UTF-8?q?=D0=BB=D0=B8=D0=B5=D0=BD=D1=82=20=D1=81=D0=B0=D0=BC=20=D1=81?= =?UTF-8?q?=D0=B4=D0=B5=D0=BB=D0=B0=D0=B5=D1=82.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/net/rubeta/legacyping/ServerThread.java | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/main/java/net/rubeta/legacyping/ServerThread.java b/src/main/java/net/rubeta/legacyping/ServerThread.java index d03ee9b..0afe05b 100644 --- a/src/main/java/net/rubeta/legacyping/ServerThread.java +++ b/src/main/java/net/rubeta/legacyping/ServerThread.java @@ -12,8 +12,9 @@ public class ServerThread extends Thread { private static final String MODERN_RESPONSE = "{\"version\": {\"name\": \"b1.7.3\",\"protocol\": -17}," + - "\"players\": {\"max\": %max%,\"online\": %now%,\"sample\": []}," + - "\"description\": {\"text\": \"%motd%\"},\"enforcesSecureChat\": false}"; + "\"players\": {\"max\": %max%,\"online\": %now%}," + + "\"description\": {\"text\": \"%motd%\"}," + + "\"enforcesSecureChat\": false,\"previewsChat\": true}"; private final ServerSocket serverSocket; private final AtomicBoolean working = new AtomicBoolean(false); private final Server minecraftServer; @@ -62,7 +63,7 @@ public class ServerThread extends Thread { this.responseForModernPing(outputStream); } outputStream.flush(); - socket.close(); + //socket.close(); } catch (SocketTimeoutException ignore) { } catch (IOException ex) { System.out.println("Exception caught: " + ex); From 5932933f77ef5b29fdcb3f1ad625d4b814b93ed7 Mon Sep 17 00:00:00 2001 From: Dereku Date: Sat, 2 Mar 2024 21:06:54 +0700 Subject: [PATCH 02/10] =?UTF-8?q?1.4:=20=D0=A2=D0=B5=D0=BF=D0=B5=D1=80?= =?UTF-8?q?=D1=8C=20=D0=BC=D0=BE=D0=B6=D0=BD=D0=BE=20=D1=83=D0=BA=D0=B0?= =?UTF-8?q?=D0=B7=D1=8B=D0=B2=D0=B0=D1=82=D1=8C=20=D0=BE=D1=82=D0=B4=D0=B0?= =?UTF-8?q?=D0=B2=D0=B0=D0=B5=D0=BC=D1=83=D1=8E=20=D0=B2=D0=B5=D1=80=D1=81?= =?UTF-8?q?=D0=B8=D1=8E=20=D0=B8=D0=B3=D1=80=D1=8B=20=D0=B8=20id=20=D0=BF?= =?UTF-8?q?=D1=80=D0=BE=D1=82=D0=BE=D0=BA=D0=BE=D0=BB=D0=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pom.xml | 2 +- .../net/rubeta/legacyping/LegacyPing.java | 4 +- .../net/rubeta/legacyping/ServerThread.java | 43 +++++++------------ src/main/resources/config.yml | 2 + 4 files changed, 22 insertions(+), 29 deletions(-) diff --git a/pom.xml b/pom.xml index 0bbf5cf..35934c0 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ net.rubeta LegacyPing - 1.2 + 1.4 jar LegacyPing diff --git a/src/main/java/net/rubeta/legacyping/LegacyPing.java b/src/main/java/net/rubeta/legacyping/LegacyPing.java index 1b3b756..2d93a48 100644 --- a/src/main/java/net/rubeta/legacyping/LegacyPing.java +++ b/src/main/java/net/rubeta/legacyping/LegacyPing.java @@ -17,9 +17,11 @@ public final class LegacyPing extends JavaPlugin { final FileConfiguration config = this.getConfig(); final String host = config.getString("host", "0.0.0.0"); final List ports = config.getIntegerList("port"); + final String version = config.getString("displayedVersion", "b1.7.3"); + final int protocol = config.getInt("displayedProtocol", 17); for (int port : ports) { try { - this.threads.add(new ServerThread(this.getServer(), host, port)); + this.threads.add(new ServerThread(this.getServer(), host, port, version, protocol)); } catch (IOException e) { this.getLogger().log(Level.WARNING, "Failed to create ServerSocket", e); } diff --git a/src/main/java/net/rubeta/legacyping/ServerThread.java b/src/main/java/net/rubeta/legacyping/ServerThread.java index 0afe05b..180e4bf 100644 --- a/src/main/java/net/rubeta/legacyping/ServerThread.java +++ b/src/main/java/net/rubeta/legacyping/ServerThread.java @@ -11,17 +11,21 @@ import java.util.concurrent.atomic.AtomicBoolean; public class ServerThread extends Thread { private static final String MODERN_RESPONSE = - "{\"version\": {\"name\": \"b1.7.3\",\"protocol\": -17}," + + "{\"version\": {\"name\": \"%version%\",\"protocol\": -%protocol%}," + "\"players\": {\"max\": %max%,\"online\": %now%}," + "\"description\": {\"text\": \"%motd%\"}," + "\"enforcesSecureChat\": false,\"previewsChat\": true}"; private final ServerSocket serverSocket; private final AtomicBoolean working = new AtomicBoolean(false); private final Server minecraftServer; + private final String version; + private final int protocol; - public ServerThread(final Server server, final String host, int port) throws IOException { + public ServerThread(final Server server, final String host, int port, String version, int protocol) throws IOException { this.minecraftServer = server; this.setName("LegacyPing thread listening " + host + ":" + port); + this.version = version; + this.protocol = Math.abs(protocol); final InetAddress address = InetAddress.getByName(host); this.serverSocket = new ServerSocket(port, 10, address); this.serverSocket.setSoTimeout((int) TimeUnit.SECONDS.toMillis(10L)); @@ -31,6 +35,8 @@ public class ServerThread extends Thread { public ServerThread(final String host, int port) throws IOException { this.minecraftServer = null; this.setName("LegacyPing thread listening " + host + ":" + port); + this.version = "dummy"; + this.protocol = 0; final InetAddress address = InetAddress.getByName(host); this.serverSocket = new ServerSocket(port, 10, address); this.serverSocket.setSoTimeout((int) TimeUnit.SECONDS.toMillis(10L)); @@ -52,15 +58,10 @@ public class ServerThread extends Thread { final InputStream inputStream = socket.getInputStream(); final OutputStream outputStream = socket.getOutputStream(); final int firstByte = inputStream.read(); - switch (firstByte) { - case 0: - this.responseForRuBetaModdedClient(outputStream); - break; - case 254: - this.responseForLegacyPing(outputStream); - break; - default: - this.responseForModernPing(outputStream); + if (firstByte == 254) { + this.responseForLegacyPing(outputStream); + } else { + this.responseForModernPing(outputStream); } outputStream.flush(); //socket.close(); @@ -79,21 +80,6 @@ public class ServerThread extends Thread { } } - private void responseForRuBetaModdedClient(final OutputStream outputStream) throws IOException { - final ByteArrayOutputStream result = new ByteArrayOutputStream(); - final DataOutputStream dos = new DataOutputStream(result); - dos.write(255); // Packet 0xFF (PacketDisconnect) - final String response = this.getMotd() + '\u0000' + this.getOnlinePlayers() + '\u0000' + this.getMaxPlayers(); - dos.writeShort(response.length()); - for (char c : response.toCharArray()) { - dos.writeChar(c); - } - // Packet data end - final DataOutputStream clientOutput = new DataOutputStream(outputStream); - clientOutput.writeInt(result.size()); - clientOutput.write(result.toByteArray()); - } - @SuppressWarnings("UnnecessaryUnicodeEscape") private void responseForLegacyPing(final OutputStream outputStream) throws IOException { final DataOutputStream clientOutput = new DataOutputStream(outputStream); @@ -107,7 +93,10 @@ public class ServerThread extends Thread { } private void responseForModernPing(final OutputStream outputStream) throws IOException { - final String responseJson = MODERN_RESPONSE.replace("%max%", String.valueOf(this.getMaxPlayers())) + final String responseJson = MODERN_RESPONSE + .replace("%version%", String.valueOf(this.version)) + .replace("%protocol%", String.valueOf(this.protocol)) + .replace("%max%", String.valueOf(this.getMaxPlayers())) .replace("%now%", String.valueOf(this.getOnlinePlayers())) .replace("%motd%", this.getMotd()); byte[] bytes = responseJson.getBytes(); diff --git a/src/main/resources/config.yml b/src/main/resources/config.yml index 803f05f..f06ef01 100644 --- a/src/main/resources/config.yml +++ b/src/main/resources/config.yml @@ -2,3 +2,5 @@ host: '0.0.0.0' port: - 25566 - 25567 +displayedVersion: 'b1.7.3' +displayedProtocol: 17 From 7608e43669fc010e6221c6b41e13ede14c6d4cd4 Mon Sep 17 00:00:00 2001 From: Dereku Date: Wed, 4 Sep 2024 10:06:08 +0700 Subject: [PATCH 03/10] Removed Legacy response; update modern response. 1.5 --- pom.xml | 2 +- .../net/rubeta/legacyping/ServerThread.java | 109 ++++++++++++------ 2 files changed, 73 insertions(+), 38 deletions(-) diff --git a/pom.xml b/pom.xml index 35934c0..6427ea9 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ net.rubeta LegacyPing - 1.4 + 1.5 jar LegacyPing diff --git a/src/main/java/net/rubeta/legacyping/ServerThread.java b/src/main/java/net/rubeta/legacyping/ServerThread.java index 180e4bf..2a46093 100644 --- a/src/main/java/net/rubeta/legacyping/ServerThread.java +++ b/src/main/java/net/rubeta/legacyping/ServerThread.java @@ -5,16 +5,19 @@ import org.bukkit.craftbukkit.CraftServer; import java.io.*; import java.net.*; +import java.nio.charset.StandardCharsets; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; public class ServerThread extends Thread { private static final String MODERN_RESPONSE = - "{\"version\": {\"name\": \"%version%\",\"protocol\": -%protocol%}," + + "{\"version\": {\"name\": \"%version%\",\"protocol\": %protocol%}," + "\"players\": {\"max\": %max%,\"online\": %now%}," + "\"description\": {\"text\": \"%motd%\"}," + "\"enforcesSecureChat\": false,\"previewsChat\": true}"; + private static final String DISCONNECT_REASON = "[\"\",{\"text\":\"This is b1.7.3 server. Visit \"}," + + "{\"text\":\"https://rubeta.net\",\"underlined\":true},{\"text\":\" for more information.\"}]"; private final ServerSocket serverSocket; private final AtomicBoolean working = new AtomicBoolean(false); private final Server minecraftServer; @@ -25,7 +28,7 @@ public class ServerThread extends Thread { this.minecraftServer = server; this.setName("LegacyPing thread listening " + host + ":" + port); this.version = version; - this.protocol = Math.abs(protocol); + this.protocol = protocol; final InetAddress address = InetAddress.getByName(host); this.serverSocket = new ServerSocket(port, 10, address); this.serverSocket.setSoTimeout((int) TimeUnit.SECONDS.toMillis(10L)); @@ -47,6 +50,7 @@ public class ServerThread extends Thread { new ServerThread("", 25565).start(); } + @SuppressWarnings("unused") @Override public void run() { this.working.set(true); @@ -54,17 +58,32 @@ public class ServerThread extends Thread { try { final Socket socket = this.serverSocket.accept(); socket.setTrafficClass(SocketOptions.TCP_NODELAY & SocketOptions.IP_TOS); - System.out.println("[LegacyPing] Got new ping from " + socket.getRemoteSocketAddress()); - final InputStream inputStream = socket.getInputStream(); - final OutputStream outputStream = socket.getOutputStream(); - final int firstByte = inputStream.read(); - if (firstByte == 254) { - this.responseForLegacyPing(outputStream); +// System.out.println("[LegacyPing] Got new ping from " + socket.getRemoteSocketAddress()); + final DataInputStream inputStream = new DataInputStream(socket.getInputStream()); + final DataOutputStream outputStream = new DataOutputStream(socket.getOutputStream()); + final int packetLength = inputStream.readByte() | inputStream.readByte() << 1; // idk why it doesn't a VarInt + final int protocolVersion = this.readVarInt(inputStream); + final String hostname = this.readUtf(inputStream); + final int port = inputStream.readShort(); + final int status = this.readVarInt(inputStream); +// System.out.println(packetLength + "; Protocol version: " + protocolVersion + ", host: " + hostname +// + ", port: " + port + ", status: " + status); + if (status != 2) { + this.responseForModernPing(outputStream, MODERN_RESPONSE); } else { - this.responseForModernPing(outputStream); + this.responseForModernPing(outputStream, DISCONNECT_REASON); } outputStream.flush(); - //socket.close(); + + inputStream.readShort(); // legacy data + + this.writeVarInt(outputStream, this.readVarInt(inputStream)); // Packet length (9) + this.writeVarInt(outputStream, this.readVarInt(inputStream)); // Packet id (1) + outputStream.writeLong(inputStream.readLong()); // timestamp + + inputStream.close(); + outputStream.close(); + socket.close(); } catch (SocketTimeoutException ignore) { } catch (IOException ex) { System.out.println("Exception caught: " + ex); @@ -80,32 +99,20 @@ public class ServerThread extends Thread { } } - @SuppressWarnings("UnnecessaryUnicodeEscape") - private void responseForLegacyPing(final OutputStream outputStream) throws IOException { - final DataOutputStream clientOutput = new DataOutputStream(outputStream); - clientOutput.write(255); - final String response = this.getMotd() + '\u00a7' + this.getOnlinePlayers() + '\u00a7' + this.getMaxPlayers(); - clientOutput.writeShort(response.length()); - for (char c : response.toCharArray()) { - clientOutput.writeChar(c); - } - // Packet data end - } - - private void responseForModernPing(final OutputStream outputStream) throws IOException { - final String responseJson = MODERN_RESPONSE + private void responseForModernPing(final DataOutputStream outputStream, String response) throws IOException { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + DataOutputStream dos = new DataOutputStream(baos); + final String responseJson = response .replace("%version%", String.valueOf(this.version)) .replace("%protocol%", String.valueOf(this.protocol)) .replace("%max%", String.valueOf(this.getMaxPlayers())) .replace("%now%", String.valueOf(this.getOnlinePlayers())) .replace("%motd%", this.getMotd()); - byte[] bytes = responseJson.getBytes(); - final DataOutputStream clientOutput = new DataOutputStream(outputStream); - this.writeVarInt(clientOutput, bytes.length + 3); - this.writeVarInt(clientOutput, 0); - this.writeVarInt(clientOutput, bytes.length); - clientOutput.write(bytes); - // Packet data end + this.writeVarInt(dos, 0); + this.writeUtf(dos, responseJson); + dos.close(); + this.writeVarInt(outputStream, baos.size()); + outputStream.write(baos.toByteArray()); } private String getMotd() { @@ -120,14 +127,42 @@ public class ServerThread extends Thread { return this.minecraftServer == null ? 37 : this.minecraftServer.getMaxPlayers(); } - private void writeVarInt(DataOutputStream out, int paramInt) throws IOException { - while (true) { - if ((paramInt & 0xFFFFFF80) == 0) { - out.writeByte(paramInt); - return; + public int readVarInt(DataInputStream in) throws IOException { + int i = 0; + int j = 0; + byte b0; + do { + b0 = in.readByte(); + i |= (b0 & 127) << j++ * 7; + if (j > 5) { + throw new RuntimeException("VarInt too big"); } - out.writeByte(paramInt & 0x7F | 0x80); + } while((b0 & 128) == 128); + return i; + } + + private void writeVarInt(DataOutputStream out, int paramInt) throws IOException { + while((paramInt & 0xffffff80) != 0) { + out.writeByte(paramInt & 0x7f | 0x80); paramInt >>>= 7; } + out.writeByte(paramInt); + } + + @SuppressWarnings("ResultOfMethodCallIgnored") + private String readUtf(DataInputStream in) throws IOException { + int length = this.readVarInt(in); + byte[] data = new byte[length]; + in.read(data); + return new String(data, StandardCharsets.UTF_8); + } + + private void writeUtf(DataOutputStream out, String string) throws IOException { + byte[] data = string.getBytes(StandardCharsets.UTF_8); + if (data.length > 32767) { + throw new RuntimeException("String too big (was " + data.length + " bytes encoded, max 32767"); + } + this.writeVarInt(out, data.length); + out.write(data); } } From 6729de5894fbdf6320965ae3578de9d4e6d28e57 Mon Sep 17 00:00:00 2001 From: Dereku Date: Wed, 4 Sep 2024 10:21:01 +0700 Subject: [PATCH 04/10] Ignore EOFException too. try-catch + auto-closeable --- .../java/net/rubeta/legacyping/ServerThread.java | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) diff --git a/src/main/java/net/rubeta/legacyping/ServerThread.java b/src/main/java/net/rubeta/legacyping/ServerThread.java index 2a46093..bf2aae1 100644 --- a/src/main/java/net/rubeta/legacyping/ServerThread.java +++ b/src/main/java/net/rubeta/legacyping/ServerThread.java @@ -55,12 +55,11 @@ public class ServerThread extends Thread { public void run() { this.working.set(true); while (this.working.get() && !this.serverSocket.isClosed()) { - try { - final Socket socket = this.serverSocket.accept(); + try (final Socket socket = this.serverSocket.accept(); + final DataInputStream inputStream = new DataInputStream(socket.getInputStream()); + final DataOutputStream outputStream = new DataOutputStream(socket.getOutputStream())) { socket.setTrafficClass(SocketOptions.TCP_NODELAY & SocketOptions.IP_TOS); -// System.out.println("[LegacyPing] Got new ping from " + socket.getRemoteSocketAddress()); - final DataInputStream inputStream = new DataInputStream(socket.getInputStream()); - final DataOutputStream outputStream = new DataOutputStream(socket.getOutputStream()); + final int packetLength = inputStream.readByte() | inputStream.readByte() << 1; // idk why it doesn't a VarInt final int protocolVersion = this.readVarInt(inputStream); final String hostname = this.readUtf(inputStream); @@ -76,15 +75,10 @@ public class ServerThread extends Thread { outputStream.flush(); inputStream.readShort(); // legacy data - this.writeVarInt(outputStream, this.readVarInt(inputStream)); // Packet length (9) this.writeVarInt(outputStream, this.readVarInt(inputStream)); // Packet id (1) outputStream.writeLong(inputStream.readLong()); // timestamp - - inputStream.close(); - outputStream.close(); - socket.close(); - } catch (SocketTimeoutException ignore) { + } catch (SocketTimeoutException | EOFException ignore) { } catch (IOException ex) { System.out.println("Exception caught: " + ex); } From 9f0ba79d91186a556e0b2fcb687f7992e31cabae Mon Sep 17 00:00:00 2001 From: Dereku Date: Sat, 14 Sep 2024 20:30:44 +0700 Subject: [PATCH 05/10] Autorecovery on failure --- pom.xml | 2 +- .../net/rubeta/legacyping/ServerThread.java | 94 +++++++++++-------- 2 files changed, 58 insertions(+), 38 deletions(-) diff --git a/pom.xml b/pom.xml index 6427ea9..3edbb1e 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ net.rubeta LegacyPing - 1.5 + 1.6 jar LegacyPing diff --git a/src/main/java/net/rubeta/legacyping/ServerThread.java b/src/main/java/net/rubeta/legacyping/ServerThread.java index bf2aae1..97edb4d 100644 --- a/src/main/java/net/rubeta/legacyping/ServerThread.java +++ b/src/main/java/net/rubeta/legacyping/ServerThread.java @@ -13,26 +13,26 @@ public class ServerThread extends Thread { private static final String MODERN_RESPONSE = "{\"version\": {\"name\": \"%version%\",\"protocol\": %protocol%}," + - "\"players\": {\"max\": %max%,\"online\": %now%}," + - "\"description\": {\"text\": \"%motd%\"}," + - "\"enforcesSecureChat\": false,\"previewsChat\": true}"; + "\"players\": {\"max\": %max%,\"online\": %now%}," + + "\"description\": {\"text\": \"%motd%\"}," + + "\"enforcesSecureChat\": false,\"previewsChat\": true}"; private static final String DISCONNECT_REASON = "[\"\",{\"text\":\"This is b1.7.3 server. Visit \"}," + "{\"text\":\"https://rubeta.net\",\"underlined\":true},{\"text\":\" for more information.\"}]"; - private final ServerSocket serverSocket; private final AtomicBoolean working = new AtomicBoolean(false); private final Server minecraftServer; private final String version; private final int protocol; + private final InetAddress address; + private final int port; + private ServerSocket serverSocket; public ServerThread(final Server server, final String host, int port, String version, int protocol) throws IOException { this.minecraftServer = server; this.setName("LegacyPing thread listening " + host + ":" + port); this.version = version; this.protocol = protocol; - final InetAddress address = InetAddress.getByName(host); - this.serverSocket = new ServerSocket(port, 10, address); - this.serverSocket.setSoTimeout((int) TimeUnit.SECONDS.toMillis(10L)); - this.serverSocket.setPerformancePreferences(0, 2, 1); + this.address = InetAddress.getByName(host); + this.port = port; } public ServerThread(final String host, int port) throws IOException { @@ -40,10 +40,8 @@ public class ServerThread extends Thread { this.setName("LegacyPing thread listening " + host + ":" + port); this.version = "dummy"; this.protocol = 0; - final InetAddress address = InetAddress.getByName(host); - this.serverSocket = new ServerSocket(port, 10, address); - this.serverSocket.setSoTimeout((int) TimeUnit.SECONDS.toMillis(10L)); - this.serverSocket.setPerformancePreferences(0, 2, 1); + this.address = InetAddress.getByName(host); + this.port = port; } public static void main(String[] args) throws IOException { @@ -54,33 +52,48 @@ public class ServerThread extends Thread { @Override public void run() { this.working.set(true); - while (this.working.get() && !this.serverSocket.isClosed()) { - try (final Socket socket = this.serverSocket.accept(); - final DataInputStream inputStream = new DataInputStream(socket.getInputStream()); - final DataOutputStream outputStream = new DataOutputStream(socket.getOutputStream())) { - socket.setTrafficClass(SocketOptions.TCP_NODELAY & SocketOptions.IP_TOS); + while (this.working.get()) { + try { + this.serverSocket = new ServerSocket(port, 10, address); + this.serverSocket.setSoTimeout((int) TimeUnit.SECONDS.toMillis(10L)); + this.serverSocket.setPerformancePreferences(0, 2, 1); + } catch (IOException e) { + System.out.println("Failed to start ServerSocket: " + e); + this.pause(); + continue; + } - final int packetLength = inputStream.readByte() | inputStream.readByte() << 1; // idk why it doesn't a VarInt - final int protocolVersion = this.readVarInt(inputStream); - final String hostname = this.readUtf(inputStream); - final int port = inputStream.readShort(); - final int status = this.readVarInt(inputStream); + while (!this.serverSocket.isClosed()) { + if (!this.working.get()) { + break; + } + try (final Socket socket = this.serverSocket.accept()) { + final DataInputStream inputStream = new DataInputStream(socket.getInputStream()); + final DataOutputStream outputStream = new DataOutputStream(socket.getOutputStream()); + socket.setTrafficClass(SocketOptions.TCP_NODELAY & SocketOptions.IP_TOS); + + final int packetLength = inputStream.readByte() | inputStream.readByte() << 1; // idk why it doesn't a VarInt + final int protocolVersion = this.readVarInt(inputStream); + final String hostname = this.readUtf(inputStream); + final int port = inputStream.readShort(); + final int status = this.readVarInt(inputStream); // System.out.println(packetLength + "; Protocol version: " + protocolVersion + ", host: " + hostname // + ", port: " + port + ", status: " + status); - if (status != 2) { - this.responseForModernPing(outputStream, MODERN_RESPONSE); - } else { - this.responseForModernPing(outputStream, DISCONNECT_REASON); - } - outputStream.flush(); + if (status != 2) { + this.responseForModernPing(outputStream, MODERN_RESPONSE); + } else { + this.responseForModernPing(outputStream, DISCONNECT_REASON); + } + outputStream.flush(); - inputStream.readShort(); // legacy data - this.writeVarInt(outputStream, this.readVarInt(inputStream)); // Packet length (9) - this.writeVarInt(outputStream, this.readVarInt(inputStream)); // Packet id (1) - outputStream.writeLong(inputStream.readLong()); // timestamp - } catch (SocketTimeoutException | EOFException ignore) { - } catch (IOException ex) { - System.out.println("Exception caught: " + ex); + inputStream.readShort(); // legacy data + this.writeVarInt(outputStream, this.readVarInt(inputStream)); // Packet length (9) + this.writeVarInt(outputStream, this.readVarInt(inputStream)); // Packet id (1) + outputStream.writeLong(inputStream.readLong()); // timestamp + } catch (SocketTimeoutException | EOFException ignore) { + } catch (Exception ex) { + System.out.println("Exception caught: " + ex); + } } } } @@ -93,6 +106,13 @@ public class ServerThread extends Thread { } } + void pause() { + try { + Thread.sleep(TimeUnit.SECONDS.toMillis(30L)); + } catch (InterruptedException ignored) { + } + } + private void responseForModernPing(final DataOutputStream outputStream, String response) throws IOException { ByteArrayOutputStream baos = new ByteArrayOutputStream(); DataOutputStream dos = new DataOutputStream(baos); @@ -131,12 +151,12 @@ public class ServerThread extends Thread { if (j > 5) { throw new RuntimeException("VarInt too big"); } - } while((b0 & 128) == 128); + } while ((b0 & 128) == 128); return i; } private void writeVarInt(DataOutputStream out, int paramInt) throws IOException { - while((paramInt & 0xffffff80) != 0) { + while ((paramInt & 0xffffff80) != 0) { out.writeByte(paramInt & 0x7f | 0x80); paramInt >>>= 7; } From 56d4318dbe0c296befc2471c878ee41aaa2d651b Mon Sep 17 00:00:00 2001 From: Dereku Date: Thu, 19 Sep 2024 00:59:21 +0700 Subject: [PATCH 06/10] Fix of fixes --- pom.xml | 2 +- .../net/rubeta/legacyping/LegacyPing.java | 2 +- .../net/rubeta/legacyping/ServerThread.java | 28 +++++++++++++++---- 3 files changed, 25 insertions(+), 7 deletions(-) diff --git a/pom.xml b/pom.xml index 3edbb1e..e5cc334 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ net.rubeta LegacyPing - 1.6 + 1.7 jar LegacyPing diff --git a/src/main/java/net/rubeta/legacyping/LegacyPing.java b/src/main/java/net/rubeta/legacyping/LegacyPing.java index 2d93a48..a00d242 100644 --- a/src/main/java/net/rubeta/legacyping/LegacyPing.java +++ b/src/main/java/net/rubeta/legacyping/LegacyPing.java @@ -21,7 +21,7 @@ public final class LegacyPing extends JavaPlugin { final int protocol = config.getInt("displayedProtocol", 17); for (int port : ports) { try { - this.threads.add(new ServerThread(this.getServer(), host, port, version, protocol)); + this.threads.add(new ServerThread(this, host, port, version, protocol)); } catch (IOException e) { this.getLogger().log(Level.WARNING, "Failed to create ServerSocket", e); } diff --git a/src/main/java/net/rubeta/legacyping/ServerThread.java b/src/main/java/net/rubeta/legacyping/ServerThread.java index 97edb4d..6b49faa 100644 --- a/src/main/java/net/rubeta/legacyping/ServerThread.java +++ b/src/main/java/net/rubeta/legacyping/ServerThread.java @@ -8,6 +8,8 @@ import java.net.*; import java.nio.charset.StandardCharsets; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; +import java.util.logging.Level; +import java.util.logging.Logger; public class ServerThread extends Thread { @@ -24,10 +26,12 @@ public class ServerThread extends Thread { private final int protocol; private final InetAddress address; private final int port; + private final Logger logger; private ServerSocket serverSocket; - public ServerThread(final Server server, final String host, int port, String version, int protocol) throws IOException { - this.minecraftServer = server; + public ServerThread(final LegacyPing plugin, final String host, int port, String version, int protocol) throws IOException { + this.minecraftServer = plugin.getServer(); + this.logger = plugin.getLogger(); this.setName("LegacyPing thread listening " + host + ":" + port); this.version = version; this.protocol = protocol; @@ -38,6 +42,7 @@ public class ServerThread extends Thread { public ServerThread(final String host, int port) throws IOException { this.minecraftServer = null; this.setName("LegacyPing thread listening " + host + ":" + port); + this.logger = Logger.getLogger(host + ":" + port); this.version = "dummy"; this.protocol = 0; this.address = InetAddress.getByName(host); @@ -58,7 +63,7 @@ public class ServerThread extends Thread { this.serverSocket.setSoTimeout((int) TimeUnit.SECONDS.toMillis(10L)); this.serverSocket.setPerformancePreferences(0, 2, 1); } catch (IOException e) { - System.out.println("Failed to start ServerSocket: " + e); + this.logger.log(Level.WARNING, "Failed to start ServerSocket", e); this.pause(); continue; } @@ -77,6 +82,7 @@ public class ServerThread extends Thread { final String hostname = this.readUtf(inputStream); final int port = inputStream.readShort(); final int status = this.readVarInt(inputStream); + this.logger.info("Ping from " + socket.getRemoteSocketAddress() + " to " + hostname + ":" + port); // System.out.println(packetLength + "; Protocol version: " + protocolVersion + ", host: " + hostname // + ", port: " + port + ", status: " + status); if (status != 2) { @@ -86,13 +92,21 @@ public class ServerThread extends Thread { } outputStream.flush(); + this.pause(50L); + if (socket.isClosed() || !socket.isConnected() || inputStream.available() == 0) { + continue; + } inputStream.readShort(); // legacy data + this.pause(50L); + if (socket.isClosed() || !socket.isConnected() || inputStream.available() == 0) { + continue; + } this.writeVarInt(outputStream, this.readVarInt(inputStream)); // Packet length (9) this.writeVarInt(outputStream, this.readVarInt(inputStream)); // Packet id (1) outputStream.writeLong(inputStream.readLong()); // timestamp } catch (SocketTimeoutException | EOFException ignore) { } catch (Exception ex) { - System.out.println("Exception caught: " + ex); + this.logger.log(Level.WARNING, "Unexpectable exception in " + this.getName(), ex); } } } @@ -107,8 +121,12 @@ public class ServerThread extends Thread { } void pause() { + this.pause(TimeUnit.SECONDS.toMillis(30L)); + } + + void pause(long millis) { try { - Thread.sleep(TimeUnit.SECONDS.toMillis(30L)); + Thread.sleep(millis); } catch (InterruptedException ignored) { } } From 060afeeb36544b697a1ba4c5830319ff905c58e4 Mon Sep 17 00:00:00 2001 From: Dereku Date: Tue, 24 Sep 2024 17:16:22 +0700 Subject: [PATCH 07/10] +command to restart threads. --- pom.xml | 2 +- .../net/rubeta/legacyping/LegacyPing.java | 20 +++++++++++++ .../net/rubeta/legacyping/ServerThread.java | 29 ++++++++++++------- src/main/resources/plugin.yml | 7 +++++ 4 files changed, 47 insertions(+), 11 deletions(-) diff --git a/pom.xml b/pom.xml index e5cc334..1ef3156 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ net.rubeta LegacyPing - 1.7 + 1.8 jar LegacyPing diff --git a/src/main/java/net/rubeta/legacyping/LegacyPing.java b/src/main/java/net/rubeta/legacyping/LegacyPing.java index a00d242..5f17d66 100644 --- a/src/main/java/net/rubeta/legacyping/LegacyPing.java +++ b/src/main/java/net/rubeta/legacyping/LegacyPing.java @@ -1,5 +1,8 @@ package net.rubeta.legacyping; +import org.bukkit.ChatColor; +import org.bukkit.command.Command; +import org.bukkit.command.CommandSender; import org.bukkit.configuration.file.FileConfiguration; import org.bukkit.plugin.java.JavaPlugin; @@ -14,6 +17,10 @@ public final class LegacyPing extends JavaPlugin { @Override public void onEnable() { this.saveDefaultConfig(); + this.startThreads(); + } + + private void startThreads() { final FileConfiguration config = this.getConfig(); final String host = config.getString("host", "0.0.0.0"); final List ports = config.getIntegerList("port"); @@ -33,4 +40,17 @@ public final class LegacyPing extends JavaPlugin { public void onDisable() { this.threads.forEach(ServerThread::shutdown); } + + @Override + public boolean onCommand(CommandSender sender, Command command, String label, String[] args) { + if (!sender.isOp()) { + return true; + } + + this.threads.forEach(ServerThread::shutdown); + this.threads.clear(); + this.startThreads(); + sender.sendMessage(ChatColor.GOLD + "Restarted"); + return true; + } } diff --git a/src/main/java/net/rubeta/legacyping/ServerThread.java b/src/main/java/net/rubeta/legacyping/ServerThread.java index 6b49faa..fdfb5a2 100644 --- a/src/main/java/net/rubeta/legacyping/ServerThread.java +++ b/src/main/java/net/rubeta/legacyping/ServerThread.java @@ -72,9 +72,11 @@ public class ServerThread extends Thread { if (!this.working.get()) { break; } + InetAddress address = null; try (final Socket socket = this.serverSocket.accept()) { final DataInputStream inputStream = new DataInputStream(socket.getInputStream()); final DataOutputStream outputStream = new DataOutputStream(socket.getOutputStream()); + address = socket.getInetAddress(); socket.setTrafficClass(SocketOptions.TCP_NODELAY & SocketOptions.IP_TOS); final int packetLength = inputStream.readByte() | inputStream.readByte() << 1; // idk why it doesn't a VarInt @@ -89,6 +91,8 @@ public class ServerThread extends Thread { this.responseForModernPing(outputStream, MODERN_RESPONSE); } else { this.responseForModernPing(outputStream, DISCONNECT_REASON); + socket.close(); + continue; } outputStream.flush(); @@ -106,7 +110,8 @@ public class ServerThread extends Thread { outputStream.writeLong(inputStream.readLong()); // timestamp } catch (SocketTimeoutException | EOFException ignore) { } catch (Exception ex) { - this.logger.log(Level.WARNING, "Unexpectable exception in " + this.getName(), ex); + this.logger.warning("An exception occurred while communicating with " + address); + this.logger.log(Level.WARNING, "Exception in " + this.getName(), ex); } } } @@ -159,17 +164,21 @@ public class ServerThread extends Thread { return this.minecraftServer == null ? 37 : this.minecraftServer.getMaxPlayers(); } - public int readVarInt(DataInputStream in) throws IOException { + public int readVarInt(DataInputStream in) { int i = 0; int j = 0; - byte b0; - do { - b0 = in.readByte(); - i |= (b0 & 127) << j++ * 7; - if (j > 5) { - throw new RuntimeException("VarInt too big"); - } - } while ((b0 & 128) == 128); + try { + byte b0; + do { + b0 = in.readByte(); + i |= (b0 & 127) << j++ * 7; + if (j > 5) { + throw new RuntimeException("VarInt too big"); + } + } while ((b0 & 128) == 128); + } catch (Exception ignore) { + return 0; + } return i; } diff --git a/src/main/resources/plugin.yml b/src/main/resources/plugin.yml index 284ec33..20fa2c4 100644 --- a/src/main/resources/plugin.yml +++ b/src/main/resources/plugin.yml @@ -1,3 +1,10 @@ name: LegacyPing version: '${project.version}' main: net.rubeta.legacyping.LegacyPing +commands: + legacyping: + permission: legacyping.command.legacyping + +permissions: + legacyping.command.legacyping: + default: op From 26e0436b91a6a6bd6d8352b1c5fc2ea6ebc939a9 Mon Sep 17 00:00:00 2001 From: Dereku Date: Mon, 18 Nov 2024 21:40:27 +0700 Subject: [PATCH 08/10] 25565 mirror port --- pom.xml | 2 +- .../legacyping/CrutchBukkitMirrorThread.java | 106 ++++++++++++++++++ .../net/rubeta/legacyping/LegacyPing.java | 12 +- .../net/rubeta/legacyping/ServerThread.java | 2 +- 4 files changed, 119 insertions(+), 3 deletions(-) create mode 100644 src/main/java/net/rubeta/legacyping/CrutchBukkitMirrorThread.java diff --git a/pom.xml b/pom.xml index 1ef3156..e4be042 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ net.rubeta LegacyPing - 1.8 + 2.0 jar LegacyPing diff --git a/src/main/java/net/rubeta/legacyping/CrutchBukkitMirrorThread.java b/src/main/java/net/rubeta/legacyping/CrutchBukkitMirrorThread.java new file mode 100644 index 0000000..b422206 --- /dev/null +++ b/src/main/java/net/rubeta/legacyping/CrutchBukkitMirrorThread.java @@ -0,0 +1,106 @@ +package net.rubeta.legacyping; + +import net.minecraft.network.packets.Packet; +import net.minecraft.network.packets.Packet255KickDisconnect; +import org.bukkit.craftbukkit.CraftServer; +import org.bukkit.craftbukkit.event.CraftEventFactory; +import org.bukkit.event.server.ServerListPingEvent; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.EOFException; +import java.io.IOException; +import java.net.*; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.logging.Level; +import java.util.logging.Logger; + +public class CrutchBukkitMirrorThread extends Thread { + + private final AtomicBoolean working = new AtomicBoolean(false); + private final Logger logger; + private ServerSocket serverSocket; + private final InetAddress address; + private final LegacyPing plugin; + + public CrutchBukkitMirrorThread(final LegacyPing plugin) { + this.plugin = plugin; + this.logger = Logger.getLogger("mirror:25565"); + + try { + this.address = InetAddress.getByName("0.0.0.0"); + } catch (UnknownHostException e) { + throw new RuntimeException(e); + } + } + + @Override + public void run() { + this.working.set(true); + while (this.working.get()) { + try { + this.serverSocket = new ServerSocket(25565, 10, address); + this.serverSocket.setSoTimeout((int) TimeUnit.SECONDS.toMillis(10L)); + this.serverSocket.setPerformancePreferences(0, 2, 1); + } catch (IOException e) { + this.logger.log(Level.WARNING, "Failed to start ServerSocket", e); + this.pause(); + continue; + } + + while (!this.serverSocket.isClosed()) { + if (!this.working.get()) { + break; + } + + InetAddress address = null; + try (final Socket socket = this.serverSocket.accept()) { + final DataInputStream inputStream = new DataInputStream(socket.getInputStream()); + final DataOutputStream outputStream = new DataOutputStream(socket.getOutputStream()); + address = socket.getInetAddress(); + socket.setTrafficClass(SocketOptions.TCP_NODELAY & SocketOptions.IP_TOS); + inputStream.readInt(); // Packet length + Packet packet = Packet.readPacket(inputStream); + if (packet != null && packet.getPacketId() == 254) { + CraftServer server = (CraftServer) this.plugin.getServer(); + ServerListPingEvent pingEvent = CraftEventFactory.callServerListPingEvent( + server, address, server.getServer().motd, + server.getOnlinePlayers().length, server.getMaxPlayers() + ); + String s = pingEvent.getMotd() + "\u0000" + server.getOnlinePlayers().length + "\u0000" + pingEvent.getMaxPlayers(); + Packet255KickDisconnect response = new Packet255KickDisconnect(s); + outputStream.writeInt(s.length() + 1); + outputStream.writeByte(255); + response.writePacketData(outputStream); + } + } catch (SocketTimeoutException | EOFException ignore) { + } catch (Exception ex) { + this.logger.warning("An exception occurred while communicating with " + address); + this.logger.log(Level.WARNING, "Exception in " + this.getName(), ex); + } + } + } + } + + + public void shutdown() { + this.working.set(false); + try { + this.serverSocket.close(); + } catch (IOException ignore) { + } + } + + + void pause() { + this.pause(TimeUnit.SECONDS.toMillis(30L)); + } + + void pause(long millis) { + try { + Thread.sleep(millis); + } catch (InterruptedException ignored) { + } + } +} diff --git a/src/main/java/net/rubeta/legacyping/LegacyPing.java b/src/main/java/net/rubeta/legacyping/LegacyPing.java index 5f17d66..050d286 100644 --- a/src/main/java/net/rubeta/legacyping/LegacyPing.java +++ b/src/main/java/net/rubeta/legacyping/LegacyPing.java @@ -13,6 +13,7 @@ import java.util.logging.Level; public final class LegacyPing extends JavaPlugin { private final List threads = new ArrayList<>(); + private CrutchBukkitMirrorThread mirror = null; @Override public void onEnable() { @@ -33,11 +34,18 @@ public final class LegacyPing extends JavaPlugin { this.getLogger().log(Level.WARNING, "Failed to create ServerSocket", e); } } + if (config.getBoolean("enableMirrorPort", false)) { + this.mirror = new CrutchBukkitMirrorThread(this); + this.mirror.start(); + } this.threads.forEach(Thread::start); } @Override public void onDisable() { + if (this.mirror != null) { + this.mirror.shutdown(); + } this.threads.forEach(ServerThread::shutdown); } @@ -46,7 +54,9 @@ public final class LegacyPing extends JavaPlugin { if (!sender.isOp()) { return true; } - + if (this.mirror != null) { + this.mirror.shutdown(); + } this.threads.forEach(ServerThread::shutdown); this.threads.clear(); this.startThreads(); diff --git a/src/main/java/net/rubeta/legacyping/ServerThread.java b/src/main/java/net/rubeta/legacyping/ServerThread.java index fdfb5a2..cfeea8f 100644 --- a/src/main/java/net/rubeta/legacyping/ServerThread.java +++ b/src/main/java/net/rubeta/legacyping/ServerThread.java @@ -50,7 +50,7 @@ public class ServerThread extends Thread { } public static void main(String[] args) throws IOException { - new ServerThread("", 25565).start(); + new ServerThread("", 25569).start(); } @SuppressWarnings("unused") From 871ffbdc2cea5d5ec4481c8957e537aae902ace6 Mon Sep 17 00:00:00 2001 From: Dereku Date: Tue, 6 Jan 2026 19:25:53 +0700 Subject: [PATCH 09/10] Warm "hello" for the slowstack.tv --- pom.xml | 2 +- .../java/net/rubeta/legacyping/LegacyPing.java | 2 +- .../java/net/rubeta/legacyping/ServerThread.java | 14 ++++++++++---- 3 files changed, 12 insertions(+), 6 deletions(-) diff --git a/pom.xml b/pom.xml index e4be042..57901bf 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ net.rubeta LegacyPing - 2.0 + 2.1 jar LegacyPing diff --git a/src/main/java/net/rubeta/legacyping/LegacyPing.java b/src/main/java/net/rubeta/legacyping/LegacyPing.java index 050d286..fc15d1d 100644 --- a/src/main/java/net/rubeta/legacyping/LegacyPing.java +++ b/src/main/java/net/rubeta/legacyping/LegacyPing.java @@ -26,7 +26,7 @@ public final class LegacyPing extends JavaPlugin { final String host = config.getString("host", "0.0.0.0"); final List ports = config.getIntegerList("port"); final String version = config.getString("displayedVersion", "b1.7.3"); - final int protocol = config.getInt("displayedProtocol", 17); + final int protocol = config.getInt("displayedProtocol", 14); for (int port : ports) { try { this.threads.add(new ServerThread(this, host, port, version, protocol)); diff --git a/src/main/java/net/rubeta/legacyping/ServerThread.java b/src/main/java/net/rubeta/legacyping/ServerThread.java index cfeea8f..ef59f93 100644 --- a/src/main/java/net/rubeta/legacyping/ServerThread.java +++ b/src/main/java/net/rubeta/legacyping/ServerThread.java @@ -17,9 +17,10 @@ public class ServerThread extends Thread { "{\"version\": {\"name\": \"%version%\",\"protocol\": %protocol%}," + "\"players\": {\"max\": %max%,\"online\": %now%}," + "\"description\": {\"text\": \"%motd%\"}," + - "\"enforcesSecureChat\": false,\"previewsChat\": true}"; + "\"enforcesSecureChat\": false,\"previewsChat\": false}"; private static final String DISCONNECT_REASON = "[\"\",{\"text\":\"This is b1.7.3 server. Visit \"}," + "{\"text\":\"https://rubeta.net\",\"underlined\":true},{\"text\":\" for more information.\"}]"; + private static final String SLOWSTACK_ID = "slowstack.tv"; private final AtomicBoolean working = new AtomicBoolean(false); private final Server minecraftServer; private final String version; @@ -85,10 +86,15 @@ public class ServerThread extends Thread { final int port = inputStream.readShort(); final int status = this.readVarInt(inputStream); this.logger.info("Ping from " + socket.getRemoteSocketAddress() + " to " + hostname + ":" + port); -// System.out.println(packetLength + "; Protocol version: " + protocolVersion + ", host: " + hostname -// + ", port: " + port + ", status: " + status); + boolean slowstack = hostname.equalsIgnoreCase(SLOWSTACK_ID); if (status != 2) { - this.responseForModernPing(outputStream, MODERN_RESPONSE); + if (slowstack) { + this.responseForModernPing(outputStream, MODERN_RESPONSE.replace( + "%motd%", "%motd% \nHello, slowstack.tv!" + )); + } else { + this.responseForModernPing(outputStream, MODERN_RESPONSE); + } } else { this.responseForModernPing(outputStream, DISCONNECT_REASON); socket.close(); From fefd3eee9a7d3ddf24084022aaef227d741dea68 Mon Sep 17 00:00:00 2001 From: Dereku Date: Fri, 23 Oct 2026 08:59:59 +0700 Subject: [PATCH 10/10] Warm "hello" for the matscan. Removing garbage when shutting down a listener thread --- pom.xml | 2 +- .../java/net/rubeta/legacyping/ServerThread.java | 15 +++++++++++---- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/pom.xml b/pom.xml index 57901bf..ded2704 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ net.rubeta LegacyPing - 2.1 + 2.2 jar LegacyPing diff --git a/src/main/java/net/rubeta/legacyping/ServerThread.java b/src/main/java/net/rubeta/legacyping/ServerThread.java index ef59f93..8448a5f 100644 --- a/src/main/java/net/rubeta/legacyping/ServerThread.java +++ b/src/main/java/net/rubeta/legacyping/ServerThread.java @@ -21,6 +21,7 @@ public class ServerThread extends Thread { private static final String DISCONNECT_REASON = "[\"\",{\"text\":\"This is b1.7.3 server. Visit \"}," + "{\"text\":\"https://rubeta.net\",\"underlined\":true},{\"text\":\" for more information.\"}]"; private static final String SLOWSTACK_ID = "slowstack.tv"; + private static final String MATSCAN_ID = "matscan"; private final AtomicBoolean working = new AtomicBoolean(false); private final Server minecraftServer; private final String version; @@ -86,12 +87,16 @@ public class ServerThread extends Thread { final int port = inputStream.readShort(); final int status = this.readVarInt(inputStream); this.logger.info("Ping from " + socket.getRemoteSocketAddress() + " to " + hostname + ":" + port); - boolean slowstack = hostname.equalsIgnoreCase(SLOWSTACK_ID); if (status != 2) { - if (slowstack) { + if (hostname.equalsIgnoreCase(SLOWSTACK_ID)) { this.responseForModernPing(outputStream, MODERN_RESPONSE.replace( "%motd%", "%motd% \nHello, slowstack.tv!" )); + } else if (hostname.equalsIgnoreCase(MATSCAN_ID)) { + this.responseForModernPing(outputStream, MODERN_RESPONSE + .replace("%motd%", "%motd% \nHello, matscan!") + .replace("%version%", "⚠ Error") + ); } else { this.responseForModernPing(outputStream, MODERN_RESPONSE); } @@ -116,8 +121,10 @@ public class ServerThread extends Thread { outputStream.writeLong(inputStream.readLong()); // timestamp } catch (SocketTimeoutException | EOFException ignore) { } catch (Exception ex) { - this.logger.warning("An exception occurred while communicating with " + address); - this.logger.log(Level.WARNING, "Exception in " + this.getName(), ex); + if (this.working.get()) { + this.logger.warning("An exception occurred while communicating with " + address); + this.logger.log(Level.WARNING, "Exception in " + this.getName(), ex); + } } } }