diff --git a/pom.xml b/pom.xml
index 4f0fb9a..7d68023 100644
--- a/pom.xml
+++ b/pom.xml
@@ -11,6 +11,11 @@
commons-cli
1.5.0
+
+ com.googlecode.json-simple
+ json-simple
+ 1.1.1
+
diff --git a/src/main/java/com/diamante/serverlist/ClientEmulator.java b/src/main/java/com/diamante/serverlist/ClientEmulator.java
index a745320..c847edc 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) 2022 Diamante
+ * Copyright (C) 2023 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
@@ -144,7 +144,7 @@ public class ClientEmulator implements Runnable {
}
var rawData = response.getData();
- InfoDumper.dumpServerResponse(rawData);
+ InfoDumper.dumpServerResponse(server, rawData);
}
@Override
diff --git a/src/main/java/com/diamante/serverlist/InfoDumper.java b/src/main/java/com/diamante/serverlist/InfoDumper.java
index 4d9a025..ffdc0e8 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) 2022 Diamante
+ * Copyright (C) 2023 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
@@ -16,15 +16,21 @@
*/
package com.diamante.serverlist;
+import java.io.BufferedWriter;
+import java.io.FileWriter;
+import java.io.IOException;
+
import java.nio.charset.StandardCharsets;
+import org.json.simple.JSONObject;
+
/**
*
* @author Diamante
*/
public class InfoDumper {
- public static void dumpServerResponse(byte[] data) {
+ public static void dumpServerResponse(Server server, byte[] data) {
assert data.length == ClientEmulator.SERVER_INFO_SIZE;
var magicLE = new byte[4];
@@ -47,5 +53,27 @@ public class InfoDumper {
String infoString = new String(rawDataLE, StandardCharsets.UTF_8);
System.out.println(infoString);
+
+ // Save to JSON for easier inspection
+ var magicBE = Utils.longSwap(magicLE);
+
+ var obj = new JSONObject();
+ obj.put("server", server.toString());
+ obj.put("magic", magicBE);
+ obj.put("players", playersBE);
+ obj.put("sv_maxClients", maxPlayersBE);
+
+ saveJSONFile(String.format("dump\\stats_%d", server.hashCode()), obj);
+ }
+
+ public static void saveJSONFile(String fileName, JSONObject obj) {
+ try {
+ var writer = new BufferedWriter(new FileWriter(fileName));
+ writer.write(obj.toJSONString());
+ writer.close();
+ }
+ catch (IOException ex) {
+ System.err.println("saveJSONFile: IOException while writing a JSON file");
+ }
}
}
diff --git a/src/main/java/com/diamante/serverlist/Main.java b/src/main/java/com/diamante/serverlist/Main.java
index 174775f..ae7457b 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) 2022 Diamante
+ * Copyright (C) 2023 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, Bad;
+ Emulator, Master, MasterPing, Bad;
}
private Mode mode;
@@ -65,7 +65,7 @@ public class Main {
var master = new Option("master", "master server mode");
var emulator = new Option("emulator", "client emulator mode");
- var magicOverride = new Option("magic_override", "master server will send all servers to the client");
+ var masterPing = new Option("master_ping", "ping the master server");
var ping = Option.builder("ping")
.argName("IP:Port")
@@ -75,7 +75,7 @@ public class Main {
options.addOption(master);
options.addOption(emulator);
- options.addOption(magicOverride);
+ options.addOption(masterPing);
options.addOption(ping);
return options;
@@ -92,7 +92,6 @@ public class Main {
var main = new Main();
var options = main.createOptions();
- var magicOverride = false;
var ip = new String();
var parser = new DefaultParser();
@@ -102,10 +101,8 @@ public class Main {
main.setMode(Mode.Master);
} else if (line.hasOption("emulator")) {
main.setMode(Mode.Emulator);
- }
-
- if (line.hasOption("magic_override")) {
- magicOverride = true;
+ } else if (line.hasOption("master_ping")) {
+ main.setMode(Mode.MasterPing);
}
if (line.hasOption("ping")) {
@@ -126,6 +123,10 @@ public class Main {
} else if (main.getMode() == Mode.Emulator) {
var emulator = new ClientEmulator();
emulator.pingSingleServer(ip);
+ } else if (main.getMode() == Mode.MasterPing) {
+ var ping = new MasterServerPinger();
+ ping.pingMaster();
+ ping.readReplyFromMaster();
}
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 752050d..c476125 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) 2022 Diamante
+ * Copyright (C) 2023 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
new file mode 100644
index 0000000..4f0da26
--- /dev/null
+++ b/src/main/java/com/diamante/serverlist/MasterServerPinger.java
@@ -0,0 +1,98 @@
+/*
+ * Copyright (C) 2023 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.ByteArrayOutputStream;
+import java.io.IOException;
+
+import java.net.Socket;
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+
+/**
+ *
+ * @author Diamante
+ */
+public class MasterServerPinger {
+
+ private static final String MASTER = "mw3.totalkillaz.ovh";
+ 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);
+ }
+ catch (IOException ex) {
+ System.err.println("IOException: Failed to open a socket");
+ return;
+ }
+
+ try {
+ var output = clientSocket.getOutputStream();
+ var data = new byte[8];
+
+ var magicLE = Utils.longSwap(Utils.NEW_CLIENT_MAGIC);
+ var versionLE = Utils.longSwap(CLIENT_VERSION);
+
+ System.arraycopy(magicLE, 0, data, 0, 4);
+ System.arraycopy(versionLE, 0, data, 4, 4);
+
+ output.write(data);
+ }
+ catch (IOException ex) {
+ System.err.println("IOException: Failed to write to a socket");
+ }
+ }
+
+ public void readReplyFromMaster() {
+ var out = new ByteArrayOutputStream();
+
+ try {
+ var input = clientSocket.getInputStream();
+ var bytes = new byte[0x1000 * 0x6 + 0x4];
+
+ int count;
+ while ((count = input.read(bytes)) > 0) {
+ out.write(bytes, 0, count);
+ }
+ }
+ catch (IOException ex) {
+ System.err.println("IOException: Failed to read from a socket");
+ }
+
+ var bytes = out.toByteArray();
+
+ var serverCountLE = new byte[4];
+
+ System.arraycopy(bytes, 0, serverCountLE, 0, 4);
+
+ var serverCountBE = Utils.longSwap(serverCountLE);
+
+ System.out.println(String.format("readReplyFromMaster: got %d servers", serverCountBE));
+
+ try {
+ out.close();
+ }
+ catch (IOException ex) {
+ System.err.println("readReplyFromMaster: IOException in out.close()");
+ }
+ }
+}
diff --git a/src/main/java/com/diamante/serverlist/Server.java b/src/main/java/com/diamante/serverlist/Server.java
index 1bb8819..9fcc530 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) 2022 Diamante
+ * Copyright (C) 2023 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/ServerList.java b/src/main/java/com/diamante/serverlist/ServerList.java
index 2f7f90c..a658650 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) 2022 Diamante
+ * Copyright (C) 2023 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 fbe3681..49d7e86 100644
--- a/src/main/java/com/diamante/serverlist/Utils.java
+++ b/src/main/java/com/diamante/serverlist/Utils.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2022 Diamante
+ * Copyright (C) 2023 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