Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix packet decoding #8

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
import java.net.InetSocketAddress;
import java.net.Socket;
import java.net.SocketException;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
Expand Down Expand Up @@ -248,8 +248,19 @@ public boolean fetchData() {
DataOutputStream dataOutputStream = new DataOutputStream(outputStream);
InputStream inputStream = socket.getInputStream();
InputStreamReader inputStreamReader = new InputStreamReader(inputStream,
Charset.forName("UTF-16BE"));
dataOutputStream.write(new byte[]{-2, 1});
StandardCharsets.UTF_16BE);

// Send server list ping request, in 1.4-1.5 format
// See https://wiki.vg/Server_List_Ping#1.4_to_1.5
dataOutputStream.write(0xFE);
dataOutputStream.write(0x01);

// Then, read the ping response (a kick packet)
// Beta 1.8 - 1.3 servers should respond with this format: https://wiki.vg/Server_List_Ping#Beta_1.8_to_1.3
// 1.4+ servers should respond with this format: https://wiki.vg/Server_List_Ping#1.4_to_1.5
// which uses the same response format as: https://wiki.vg/Server_List_Ping#1.6

// Read packet ID field (1 byte), should be 0xFF (kick packet ID)
int packetId = inputStream.read();
if (packetId == -1) {
try {
Expand All @@ -259,14 +270,16 @@ public boolean fetchData() {
socket = null;
return false;
}
if (packetId != 255) {
if (packetId != 0xFF) {
try {
socket.close();
} catch (IOException iOException) {
}
socket = null;
return false;
}

// Read string length field (2 bytes)
int length = inputStreamReader.read();
if (length == -1) {
try {
Expand All @@ -284,6 +297,8 @@ public boolean fetchData() {
socket = null;
return false;
}

// Read string (length bytes)
char[] chars = new char[length];
if (inputStreamReader.read(chars, 0, length) != length) {
try {
Expand All @@ -294,16 +309,27 @@ public boolean fetchData() {
return false;
}
String string = new String(chars);
if (string.startsWith("&")) {
String[] data = string.split("\000");

// Read the fields of the string
if (string.startsWith("§")) {
// If the string starts with '§', the server is probably running 1.4+
// See https://wiki.vg/Server_List_Ping#1.4_to_1.5
// and https://wiki.vg/Server_List_Ping#1.6

// In this format, fields are delimited by '\0' characters
String[] data = string.split("\0");
setPingVersion(Integer.parseInt(data[0].substring(1)));
setProtocolVersion(Integer.parseInt(data[1]));
setGameVersion(data[2]);
setMotd(data[3]);
setPlayersOnline(Integer.parseInt(data[4]));
setMaxPlayers(Integer.parseInt(data[5]));
} else {
String[] data = string.split("&");
// If the string doesn't start with '§', the server is probably running Beta 1.8 - 1.3
// See https://wiki.vg/Server_List_Ping#Beta_1.8_to_1.3

// In this format, fields are delimited by '§' characters
String[] data = string.split("§");
setMotd(data[0]);
setPlayersOnline(Integer.parseInt(data[1]));
setMaxPlayers(Integer.parseInt(data[2]));
Expand Down