diff --git a/src/main/java/com/diamante/serverlist/ClientEmulator.java b/src/main/java/com/diamante/serverlist/ClientEmulator.java index c847edc..3fe8988 100644 --- a/src/main/java/com/diamante/serverlist/ClientEmulator.java +++ b/src/main/java/com/diamante/serverlist/ClientEmulator.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2023 Diamante + * Copyright (C) 2025 Diamante * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/src/main/java/com/diamante/serverlist/InfoDumper.java b/src/main/java/com/diamante/serverlist/InfoDumper.java index 02a5bc8..87ad9ed 100644 --- a/src/main/java/com/diamante/serverlist/InfoDumper.java +++ b/src/main/java/com/diamante/serverlist/InfoDumper.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2023 Diamante + * Copyright (C) 2025 Diamante * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/src/main/java/com/diamante/serverlist/Main.java b/src/main/java/com/diamante/serverlist/Main.java index ae7457b..d027173 100644 --- a/src/main/java/com/diamante/serverlist/Main.java +++ b/src/main/java/com/diamante/serverlist/Main.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2023 Diamante + * Copyright (C) 2025 Diamante * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -31,7 +31,7 @@ import org.apache.commons.cli.ParseException; public class Main { private enum Mode { - Emulator, Master, MasterPing, Bad; + Emulator, Master, MasterPing, ServerPing, Bad; } private Mode mode; @@ -66,6 +66,7 @@ public class Main { var master = new Option("master", "master server mode"); var emulator = new Option("emulator", "client emulator mode"); var masterPing = new Option("master_ping", "ping the master server"); + var serverPing = new Option("server_ping", "ping the master server as a server"); var ping = Option.builder("ping") .argName("IP:Port") @@ -76,6 +77,7 @@ public class Main { options.addOption(master); options.addOption(emulator); options.addOption(masterPing); + options.addOption(serverPing); options.addOption(ping); return options; @@ -103,6 +105,8 @@ public class Main { main.setMode(Mode.Emulator); } else if (line.hasOption("master_ping")) { main.setMode(Mode.MasterPing); + } else if (line.hasOption("server_ping")) { + main.setMode(Mode.ServerPing); } if (line.hasOption("ping")) { @@ -127,6 +131,9 @@ public class Main { var ping = new MasterServerPinger(); ping.pingMaster(); ping.readReplyFromMaster(); + } else if (main.getMode() == Mode.ServerPing) { + var ping = new ServerEmulator(); + ping.pingLoop(); } System.out.println("Normal shutdown"); diff --git a/src/main/java/com/diamante/serverlist/MasterServer.java b/src/main/java/com/diamante/serverlist/MasterServer.java index c476125..a232320 100644 --- a/src/main/java/com/diamante/serverlist/MasterServer.java +++ b/src/main/java/com/diamante/serverlist/MasterServer.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2023 Diamante + * Copyright (C) 2025 Diamante * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/src/main/java/com/diamante/serverlist/MasterServerPinger.java b/src/main/java/com/diamante/serverlist/MasterServerPinger.java index 4f0da26..3dc519d 100644 --- a/src/main/java/com/diamante/serverlist/MasterServerPinger.java +++ b/src/main/java/com/diamante/serverlist/MasterServerPinger.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2023 Diamante + * Copyright (C) 2025 Diamante * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -29,16 +29,15 @@ import java.net.UnknownHostException; */ public class MasterServerPinger { - private static final String MASTER = "mw3.totalkillaz.ovh"; + private static final String OFFICIAL_MASTER = "mw3.totalkillaz.ovh"; + private static final String LAN_MASTER = "127.0.0.1"; private static final int MASTER_PORT = 27017; - private static final int CLIENT_VERSION = 17039893; - private Socket clientSocket; public void pingMaster() { try { - clientSocket = new Socket(MASTER, MASTER_PORT); + clientSocket = new Socket(OFFICIAL_MASTER, MASTER_PORT); } catch (IOException ex) { System.err.println("IOException: Failed to open a socket"); @@ -50,7 +49,7 @@ public class MasterServerPinger { var data = new byte[8]; var magicLE = Utils.longSwap(Utils.NEW_CLIENT_MAGIC); - var versionLE = Utils.longSwap(CLIENT_VERSION); + var versionLE = Utils.longSwap(Utils.CLIENT_VERSION); System.arraycopy(magicLE, 0, data, 0, 4); System.arraycopy(versionLE, 0, data, 4, 4); @@ -66,18 +65,33 @@ public class MasterServerPinger { var out = new ByteArrayOutputStream(); try { + System.out.println("readReplyFromMaster: awaiting reply from master server"); var input = clientSocket.getInputStream(); + System.out.println("readReplyFromMaster: finished waiting for a reply from master server"); var bytes = new byte[0x1000 * 0x6 + 0x4]; - int count; - while ((count = input.read(bytes)) > 0) { - out.write(bytes, 0, count); - } + int count = input.read(bytes); + out.write(bytes, 0, count); + + System.out.println("readReplyFromMaster: finished reading bytes from socket"); } catch (IOException ex) { System.err.println("IOException: Failed to read from a socket"); } + if (out.size() == 0) { + System.out.println("readReplyFromMaster: got no reply"); + + try { + out.close(); + } + catch (IOException ex) { + System.err.println("readReplyFromMaster: IOException in out.close()"); + } + + return; + } + var bytes = out.toByteArray(); var serverCountLE = new byte[4]; diff --git a/src/main/java/com/diamante/serverlist/Server.java b/src/main/java/com/diamante/serverlist/Server.java index 9fcc530..c73f945 100644 --- a/src/main/java/com/diamante/serverlist/Server.java +++ b/src/main/java/com/diamante/serverlist/Server.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2023 Diamante + * Copyright (C) 2025 Diamante * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/src/main/java/com/diamante/serverlist/ServerEmulator.java b/src/main/java/com/diamante/serverlist/ServerEmulator.java new file mode 100644 index 0000000..9650344 --- /dev/null +++ b/src/main/java/com/diamante/serverlist/ServerEmulator.java @@ -0,0 +1,124 @@ +/* + * Copyright (C) 2025 Diamante + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.diamante.serverlist; + +import java.io.IOException; +import java.io.OutputStream; + +import java.net.InetAddress; +import java.net.Socket; + +import java.net.UnknownHostException; + +/** + * + * @author Diamante + */ +public class ServerEmulator { + + private static final String OFFICIAL_MASTER = "mw3.totalkillaz.ovh"; + + private Socket socket; + + private int currentPort; + + private boolean valid; + + public ServerEmulator() { + try { + var ip = InetAddress.getByName(OFFICIAL_MASTER); + socket = new Socket(ip, MasterServer.PORT); + currentPort = 0; + valid = true; + } + catch (UnknownHostException ex) { + valid = false; + System.err.println("ServerEmulator: UnknownHostException in InetAddress.getByName()"); + } + catch (IOException ex) { + valid = false; + System.err.println("ServerEmulator: IOException in new Socket()"); + } + } + + public void pingMasterServer(int port, OutputStream out) { + var request = new byte[Utils.PACKET_SERVERT_LEN]; + + var magicLE = Utils.longSwap(Utils.OLD_SERVER_MAGIC); + var versionLE = Utils.longSwap(Utils.CLIENT_VERSION); + var portLE = Utils.longSwap(port); + + System.arraycopy(magicLE, 0, request, 0, 4); + System.arraycopy(versionLE, 0, request, 4, 4); + // Write only two bytes for the port + System.arraycopy(portLE, 0, request, 8, 2); + + try { + out.write(request); + } + catch (IOException ex) { + System.err.println("pingMasterServer: IOException in out.write()"); + setValid(false); + } + } + + public void pingLoop() { + while (Main.running.get() && isValid()) { + var port = currentPort; + currentPort = (currentPort + 1) % 65535; + + try { + var out = socket.getOutputStream(); + pingMasterServer(port, out); + } + catch (IOException ex) { + System.err.println("pingLoop: IOException in socket.getOutputStream()"); + } + + try { + Thread.sleep(80); + } + catch (InterruptedException ex) { + setValid(false); + } + } + + stop(); + } + + public void stop() { + // Can happen if multiple instances are launched + if (socket == null || socket.isClosed()) { + return; + } + + try { + socket.close(); + } + catch (IOException ex) { + System.err.println("stop: IOException in socket.close()"); + } + } + + public boolean isValid() { + return valid; + } + + public void setValid(boolean valid) { + this.valid = valid; + } +} diff --git a/src/main/java/com/diamante/serverlist/ServerList.java b/src/main/java/com/diamante/serverlist/ServerList.java index a658650..7bbc952 100644 --- a/src/main/java/com/diamante/serverlist/ServerList.java +++ b/src/main/java/com/diamante/serverlist/ServerList.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2023 Diamante + * Copyright (C) 2025 Diamante * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/src/main/java/com/diamante/serverlist/Utils.java b/src/main/java/com/diamante/serverlist/Utils.java index 49d7e86..4950740 100644 --- a/src/main/java/com/diamante/serverlist/Utils.java +++ b/src/main/java/com/diamante/serverlist/Utils.java @@ -38,12 +38,13 @@ public class Utils { public static final int PACKET_SERVERT_LEN = 10; // (Warning: Remember to take into account endianness) - // 2023 Update: They magic was changed, client and server were switched (HELP & THEM) - public static final int OLD_SERVER_MAGIC = 1212501072; - public static final int NEW_SERVER_MAGIC = 1414022477; + // 2023 Update: They magic was changed + public static final int OLD_SERVER_MAGIC = 1212501072; // HELP - public static final int OLD_CLIENT_MAGIC = 1414022477; - public static final int NEW_CLIENT_MAGIC = 1212501072; + public static final int OLD_CLIENT_MAGIC = 1414022477; // THEM + public static final int NEW_CLIENT_MAGIC = 1129268293; + + public static final int CLIENT_VERSION = 17039893; public static boolean isServerMagic(int magic) { return magic == OLD_SERVER_MAGIC;