From a09d2614ad9b728a8e3adfaf172cddfc9d21229c Mon Sep 17 00:00:00 2001 From: bixilon Date: Tue, 2 Jun 2020 20:30:03 +0200 Subject: [PATCH] packet handler (own thread), buffer fix, moved packets into own packages, disconnect after pong --- .../minosoft/objects/ServerListPing.java | 5 +++ .../minosoft/protocol/network/Connection.java | 42 +++++++++++++++++-- .../minosoft/protocol/network/Network.java | 37 +++++++--------- .../protocol/packets/ClientboundPacket.java | 3 ++ .../PacketStatusPong.java | 15 ++++++- .../PacketStatusResponse.java | 12 +++++- .../PacketStatusPing.java | 14 +++---- .../PacketStatusRequest.java | 6 ++- .../protocol/protocol/InByteBuffer.java | 17 +++----- .../protocol/protocol/OutByteBuffer.java | 9 +--- .../protocol/protocol/PacketHandler.java | 27 ++++++++++++ .../minosoft/protocol/protocol/Protocol.java | 4 +- 12 files changed, 132 insertions(+), 59 deletions(-) rename src/main/java/de/bixilon/minosoft/protocol/packets/clientbound/{handshaking => status}/PacketStatusPong.java (55%) rename src/main/java/de/bixilon/minosoft/protocol/packets/clientbound/{handshaking => status}/PacketStatusResponse.java (67%) rename src/main/java/de/bixilon/minosoft/protocol/packets/serverbound/{handshaking => status}/PacketStatusPing.java (72%) rename src/main/java/de/bixilon/minosoft/protocol/packets/serverbound/{handshaking => status}/PacketStatusRequest.java (66%) create mode 100644 src/main/java/de/bixilon/minosoft/protocol/protocol/PacketHandler.java diff --git a/src/main/java/de/bixilon/minosoft/objects/ServerListPing.java b/src/main/java/de/bixilon/minosoft/objects/ServerListPing.java index 1451f63b4..42c611776 100644 --- a/src/main/java/de/bixilon/minosoft/objects/ServerListPing.java +++ b/src/main/java/de/bixilon/minosoft/objects/ServerListPing.java @@ -28,4 +28,9 @@ public class ServerListPing { public String getBase64EncodedFavicon() { return raw.getString("favicon"); } + + public String getMotd() { + //ToDo TextComponent handling + return raw.getString("description"); + } } diff --git a/src/main/java/de/bixilon/minosoft/protocol/network/Connection.java b/src/main/java/de/bixilon/minosoft/protocol/network/Connection.java index 9fbb323ce..1a912eac9 100644 --- a/src/main/java/de/bixilon/minosoft/protocol/network/Connection.java +++ b/src/main/java/de/bixilon/minosoft/protocol/network/Connection.java @@ -1,15 +1,22 @@ package de.bixilon.minosoft.protocol.network; +import de.bixilon.minosoft.protocol.packets.ClientboundPacket; import de.bixilon.minosoft.protocol.packets.serverbound.handshaking.PacketHandshake; -import de.bixilon.minosoft.protocol.packets.serverbound.handshaking.PacketStatusPing; -import de.bixilon.minosoft.protocol.packets.serverbound.handshaking.PacketStatusRequest; +import de.bixilon.minosoft.protocol.packets.serverbound.status.PacketStatusPing; +import de.bixilon.minosoft.protocol.packets.serverbound.status.PacketStatusRequest; import de.bixilon.minosoft.protocol.protocol.ConnectionState; +import de.bixilon.minosoft.protocol.protocol.PacketHandler; import de.bixilon.minosoft.protocol.protocol.ProtocolVersion; +import de.bixilon.minosoft.util.Util; + +import java.util.ArrayList; public class Connection { private final String host; private final int port; private final Network network; + private final PacketHandler handler; + private final ArrayList handlingQueue; private ConnectionState state = ConnectionState.DISCONNECTED; private boolean onlyPing; @@ -18,6 +25,18 @@ public class Connection { this.host = host; this.port = port; network = new Network(this); + handlingQueue = new ArrayList<>(); + handler = new PacketHandler(this); + Thread handleThread = new Thread(() -> { + while (getConnectionState() != ConnectionState.DISCONNECTING) { + while (handlingQueue.size() > 0) { + handlingQueue.get(0).handle(getHandler()); + handlingQueue.remove(0); + } + Util.sleep(1); + } + }); + handleThread.start(); } /** @@ -26,7 +45,6 @@ public class Connection { public void ping() { onlyPing = true; network.connect(); - } /** @@ -65,7 +83,7 @@ public class Connection { setConnectionState(next); break; case STATUS: - // send staus request and ping + // send status request and ping network.sendPacket(new PacketStatusRequest()); network.sendPacket(new PacketStatusPing(0)); break; @@ -76,4 +94,20 @@ public class Connection { //ToDo: static right now return ProtocolVersion.VERSION_1_7_10; } + + public PacketHandler getHandler() { + return this.handler; + } + + public void handle(ClientboundPacket p) { + handlingQueue.add(p); + } + + public boolean isOnlyPing() { + return onlyPing; + } + + public void disconnect() { + setConnectionState(ConnectionState.DISCONNECTING); + } } diff --git a/src/main/java/de/bixilon/minosoft/protocol/network/Network.java b/src/main/java/de/bixilon/minosoft/protocol/network/Network.java index d2dc98703..94d663689 100644 --- a/src/main/java/de/bixilon/minosoft/protocol/network/Network.java +++ b/src/main/java/de/bixilon/minosoft/protocol/network/Network.java @@ -5,7 +5,6 @@ import de.bixilon.minosoft.protocol.packets.ServerboundPacket; import de.bixilon.minosoft.protocol.protocol.ConnectionState; import de.bixilon.minosoft.protocol.protocol.InPacketBuffer; import de.bixilon.minosoft.protocol.protocol.Protocol; -import de.bixilon.minosoft.protocol.protocol.ProtocolDefinition; import de.bixilon.minosoft.util.Util; import java.io.DataInputStream; @@ -60,25 +59,25 @@ public class Network { dOut.write(b); dOut.flush(); binQueue.remove(0); - System.out.println(String.format("Sent packet (%s)", b[1])); + System.out.println(String.format("[OUT] (%s)", b[1])); } // everything sent for now, waiting for data while (dIn.available() > 0) { - int numRead = 0; - int len = 0; - byte read; - do { - read = dIn.readByte(); - int value = (read & 0b01111111); - len |= (value << (7 * numRead)); + int numRead = 0; + int len = 0; + byte read; + do { + read = dIn.readByte(); + int value = (read & 0b01111111); + len |= (value << (7 * numRead)); - numRead++; - if (numRead > 5) { - throw new RuntimeException("VarInt is too big"); - } - } while ((read & 0b10000000) != 0); + numRead++; + if (numRead > 5) { + throw new RuntimeException("VarInt is too big"); + } + } while ((read & 0b10000000) != 0); byte[] in = dIn.readNBytes(len); @@ -89,6 +88,7 @@ public class Network { Util.sleep(1); } + connection.setConnectionState(ConnectionState.DISCONNECTED); } catch (IOException e) { // Could not connect connection.setConnectionState(ConnectionState.DISCONNECTED); @@ -114,17 +114,17 @@ public class Network { // read data InPacketBuffer inPacketBuffer = new InPacketBuffer(binQueueIn.get(0)); - System.out.println("Received packet with command=" + inPacketBuffer.getCommand()); Class clazz = Protocol.getPacketByPacket(connection.getVersion().getProtocol().getPacketByCommand(connection.getConnectionState(), inPacketBuffer.getCommand())); if (clazz == null) { - System.out.println("Unknown packet received with command=" + inPacketBuffer.getCommand()); + System.out.println("[IN] Unknown: " + inPacketBuffer.getCommand()); binQueueIn.remove(0); continue; } try { ClientboundPacket packet = clazz.getConstructor().newInstance(); packet.read(inPacketBuffer, connection.getVersion()); + connection.handle(packet); } catch (InstantiationException | IllegalAccessException | InvocationTargetException | NoSuchMethodException e) { // safety first, but will not occur e.printStackTrace(); @@ -141,11 +141,6 @@ public class Network { } - public void disconnect() { - connection.setConnectionState(ConnectionState.DISCONNECTING); - - } - public void sendPacket(ServerboundPacket p) { queue.add(p); diff --git a/src/main/java/de/bixilon/minosoft/protocol/packets/ClientboundPacket.java b/src/main/java/de/bixilon/minosoft/protocol/packets/ClientboundPacket.java index 6b8bea0f5..838ca42f9 100644 --- a/src/main/java/de/bixilon/minosoft/protocol/packets/ClientboundPacket.java +++ b/src/main/java/de/bixilon/minosoft/protocol/packets/ClientboundPacket.java @@ -1,9 +1,12 @@ package de.bixilon.minosoft.protocol.packets; import de.bixilon.minosoft.protocol.protocol.InPacketBuffer; +import de.bixilon.minosoft.protocol.protocol.PacketHandler; import de.bixilon.minosoft.protocol.protocol.ProtocolVersion; // packet to send to client public interface ClientboundPacket extends Packet { void read(InPacketBuffer buffer, ProtocolVersion v); + + void handle(PacketHandler h); } diff --git a/src/main/java/de/bixilon/minosoft/protocol/packets/clientbound/handshaking/PacketStatusPong.java b/src/main/java/de/bixilon/minosoft/protocol/packets/clientbound/status/PacketStatusPong.java similarity index 55% rename from src/main/java/de/bixilon/minosoft/protocol/packets/clientbound/handshaking/PacketStatusPong.java rename to src/main/java/de/bixilon/minosoft/protocol/packets/clientbound/status/PacketStatusPong.java index 1a68a4038..f5e8eb0e4 100644 --- a/src/main/java/de/bixilon/minosoft/protocol/packets/clientbound/handshaking/PacketStatusPong.java +++ b/src/main/java/de/bixilon/minosoft/protocol/packets/clientbound/status/PacketStatusPong.java @@ -1,18 +1,29 @@ -package de.bixilon.minosoft.protocol.packets.clientbound.handshaking; +package de.bixilon.minosoft.protocol.packets.clientbound.status; import de.bixilon.minosoft.protocol.packets.ClientboundPacket; import de.bixilon.minosoft.protocol.protocol.InPacketBuffer; +import de.bixilon.minosoft.protocol.protocol.PacketHandler; import de.bixilon.minosoft.protocol.protocol.ProtocolVersion; public class PacketStatusPong implements ClientboundPacket { + Long id; @Override public void read(InPacketBuffer buffer, ProtocolVersion v) { - System.out.println("Pong received"); + this.id = buffer.readLong(); } @Override public void log() { // ToDo } + + @Override + public void handle(PacketHandler h) { + h.handle(this); + } + + public Long getID() { + return this.id; + } } diff --git a/src/main/java/de/bixilon/minosoft/protocol/packets/clientbound/handshaking/PacketStatusResponse.java b/src/main/java/de/bixilon/minosoft/protocol/packets/clientbound/status/PacketStatusResponse.java similarity index 67% rename from src/main/java/de/bixilon/minosoft/protocol/packets/clientbound/handshaking/PacketStatusResponse.java rename to src/main/java/de/bixilon/minosoft/protocol/packets/clientbound/status/PacketStatusResponse.java index 248f1a9e6..ac4041725 100644 --- a/src/main/java/de/bixilon/minosoft/protocol/packets/clientbound/handshaking/PacketStatusResponse.java +++ b/src/main/java/de/bixilon/minosoft/protocol/packets/clientbound/status/PacketStatusResponse.java @@ -1,8 +1,9 @@ -package de.bixilon.minosoft.protocol.packets.clientbound.handshaking; +package de.bixilon.minosoft.protocol.packets.clientbound.status; import de.bixilon.minosoft.objects.ServerListPing; import de.bixilon.minosoft.protocol.packets.ClientboundPacket; import de.bixilon.minosoft.protocol.protocol.InPacketBuffer; +import de.bixilon.minosoft.protocol.protocol.PacketHandler; import de.bixilon.minosoft.protocol.protocol.ProtocolVersion; public class PacketStatusResponse implements ClientboundPacket { @@ -18,4 +19,13 @@ public class PacketStatusResponse implements ClientboundPacket { public void log() { // ToDo } + + @Override + public void handle(PacketHandler h) { + h.handle(this); + } + + public ServerListPing getResponse() { + return this.response; + } } diff --git a/src/main/java/de/bixilon/minosoft/protocol/packets/serverbound/handshaking/PacketStatusPing.java b/src/main/java/de/bixilon/minosoft/protocol/packets/serverbound/status/PacketStatusPing.java similarity index 72% rename from src/main/java/de/bixilon/minosoft/protocol/packets/serverbound/handshaking/PacketStatusPing.java rename to src/main/java/de/bixilon/minosoft/protocol/packets/serverbound/status/PacketStatusPing.java index 86469989d..eff945ef2 100644 --- a/src/main/java/de/bixilon/minosoft/protocol/packets/serverbound/handshaking/PacketStatusPing.java +++ b/src/main/java/de/bixilon/minosoft/protocol/packets/serverbound/status/PacketStatusPing.java @@ -1,4 +1,4 @@ -package de.bixilon.minosoft.protocol.packets.serverbound.handshaking; +package de.bixilon.minosoft.protocol.packets.serverbound.status; import de.bixilon.minosoft.protocol.packets.ServerboundPacket; import de.bixilon.minosoft.protocol.protocol.OutPacketBuffer; @@ -6,21 +6,21 @@ import de.bixilon.minosoft.protocol.protocol.Packets; import de.bixilon.minosoft.protocol.protocol.ProtocolVersion; public class PacketStatusPing implements ServerboundPacket { - final Long ms; + final Long id; - public PacketStatusPing(Long ms) { - this.ms = ms; + public PacketStatusPing(Long id) { + this.id = id; } - public PacketStatusPing(int ms) { - this.ms = (long) ms; + public PacketStatusPing(int id) { + this.id = (long) id; } @Override public OutPacketBuffer write(ProtocolVersion v) { // no version checking, is the same in all versions (1.7.x - 1.15.2) OutPacketBuffer buffer = new OutPacketBuffer(v.getPacketCommand(Packets.Serverbound.STATUS_PING)); - buffer.writeLong(ms); + buffer.writeLong(id); return buffer; } diff --git a/src/main/java/de/bixilon/minosoft/protocol/packets/serverbound/handshaking/PacketStatusRequest.java b/src/main/java/de/bixilon/minosoft/protocol/packets/serverbound/status/PacketStatusRequest.java similarity index 66% rename from src/main/java/de/bixilon/minosoft/protocol/packets/serverbound/handshaking/PacketStatusRequest.java rename to src/main/java/de/bixilon/minosoft/protocol/packets/serverbound/status/PacketStatusRequest.java index c8313e5c4..da9dd10f5 100644 --- a/src/main/java/de/bixilon/minosoft/protocol/packets/serverbound/handshaking/PacketStatusRequest.java +++ b/src/main/java/de/bixilon/minosoft/protocol/packets/serverbound/status/PacketStatusRequest.java @@ -1,7 +1,9 @@ -package de.bixilon.minosoft.protocol.packets.serverbound.handshaking; +package de.bixilon.minosoft.protocol.packets.serverbound.status; import de.bixilon.minosoft.protocol.packets.ServerboundPacket; -import de.bixilon.minosoft.protocol.protocol.*; +import de.bixilon.minosoft.protocol.protocol.OutPacketBuffer; +import de.bixilon.minosoft.protocol.protocol.Packets; +import de.bixilon.minosoft.protocol.protocol.ProtocolVersion; public class PacketStatusRequest implements ServerboundPacket { diff --git a/src/main/java/de/bixilon/minosoft/protocol/protocol/InByteBuffer.java b/src/main/java/de/bixilon/minosoft/protocol/protocol/InByteBuffer.java index 11fb90f44..43e62798a 100644 --- a/src/main/java/de/bixilon/minosoft/protocol/protocol/InByteBuffer.java +++ b/src/main/java/de/bixilon/minosoft/protocol/protocol/InByteBuffer.java @@ -4,7 +4,6 @@ import de.bixilon.minosoft.objects.BlockPosition; import org.json.JSONObject; import java.nio.ByteBuffer; -import java.nio.ByteOrder; import java.nio.charset.StandardCharsets; import java.util.UUID; @@ -39,36 +38,31 @@ public class InByteBuffer { public short readShort() { ByteBuffer buffer = ByteBuffer.allocate(Short.BYTES); buffer.put(readBytes(Short.BYTES)); - buffer.order(ByteOrder.BIG_ENDIAN); - return buffer.getShort(); + return buffer.getShort(0); } public int readInteger() { ByteBuffer buffer = ByteBuffer.allocate(Integer.BYTES); buffer.put(readBytes(Integer.BYTES)); - buffer.order(ByteOrder.BIG_ENDIAN); - return buffer.getInt(); + return buffer.getInt(0); } public Long readLong() { ByteBuffer buffer = ByteBuffer.allocate(Long.BYTES); buffer.put(readBytes(Long.BYTES)); - buffer.order(ByteOrder.BIG_ENDIAN); - return buffer.getLong(); + return buffer.getLong(0); } public Float readFloat() { ByteBuffer buffer = ByteBuffer.allocate(Float.BYTES); buffer.put(readBytes(Float.BYTES)); - buffer.order(ByteOrder.BIG_ENDIAN); - return buffer.getFloat(); + return buffer.getFloat(0); } public Double readDouble() { ByteBuffer buffer = ByteBuffer.allocate(Double.BYTES); buffer.put(readBytes(Double.BYTES)); - buffer.order(ByteOrder.BIG_ENDIAN); - return buffer.getDouble(); + return buffer.getDouble(0); } public String readString() { @@ -83,7 +77,6 @@ public class InByteBuffer { public UUID readUUID() { ByteBuffer buffer = ByteBuffer.allocate(16); // UUID.BYTES buffer.put(readBytes(16)); - buffer.order(ByteOrder.BIG_ENDIAN); return new UUID(buffer.getLong(0), buffer.getLong(1)); } diff --git a/src/main/java/de/bixilon/minosoft/protocol/protocol/OutByteBuffer.java b/src/main/java/de/bixilon/minosoft/protocol/protocol/OutByteBuffer.java index 5b30de6fb..eb5410638 100644 --- a/src/main/java/de/bixilon/minosoft/protocol/protocol/OutByteBuffer.java +++ b/src/main/java/de/bixilon/minosoft/protocol/protocol/OutByteBuffer.java @@ -4,14 +4,13 @@ import de.bixilon.minosoft.objects.BlockPosition; import org.json.JSONObject; import java.nio.ByteBuffer; -import java.nio.ByteOrder; import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.List; import java.util.UUID; public class OutByteBuffer { - private List bytes = new ArrayList<>(); + private final List bytes = new ArrayList<>(); public OutByteBuffer() { } @@ -37,7 +36,6 @@ public class OutByteBuffer { public void writeShort(short s) { ByteBuffer buffer = ByteBuffer.allocate(Short.BYTES); buffer.putShort(s); - buffer.order(ByteOrder.BIG_ENDIAN); for (byte b : buffer.array()) { bytes.add(b); } @@ -46,7 +44,6 @@ public class OutByteBuffer { public void writeInteger(int i) { ByteBuffer buffer = ByteBuffer.allocate(Integer.BYTES); buffer.putInt(i); - buffer.order(ByteOrder.BIG_ENDIAN); for (byte b : buffer.array()) { bytes.add(b); } @@ -55,7 +52,6 @@ public class OutByteBuffer { public void writeLong(Long l) { ByteBuffer buffer = ByteBuffer.allocate(Long.BYTES); buffer.putLong(l); - buffer.order(ByteOrder.BIG_ENDIAN); for (byte b : buffer.array()) { bytes.add(b); } @@ -64,7 +60,6 @@ public class OutByteBuffer { public void writeFloat(Float f) { ByteBuffer buffer = ByteBuffer.allocate(Float.BYTES); buffer.putFloat(f); - buffer.order(ByteOrder.BIG_ENDIAN); for (byte b : buffer.array()) { bytes.add(b); } @@ -73,7 +68,6 @@ public class OutByteBuffer { public void writeDouble(Double d) { ByteBuffer buffer = ByteBuffer.allocate(Double.BYTES); buffer.putDouble(d); - buffer.order(ByteOrder.BIG_ENDIAN); for (byte b : buffer.array()) { bytes.add(b); } @@ -94,7 +88,6 @@ public class OutByteBuffer { ByteBuffer buffer = ByteBuffer.allocate(16); // UUID.BYTES buffer.putLong(u.getMostSignificantBits()); buffer.putLong(u.getLeastSignificantBits()); - buffer.order(ByteOrder.BIG_ENDIAN); for (byte b : buffer.array()) { bytes.add(b); } diff --git a/src/main/java/de/bixilon/minosoft/protocol/protocol/PacketHandler.java b/src/main/java/de/bixilon/minosoft/protocol/protocol/PacketHandler.java new file mode 100644 index 000000000..62b7d2348 --- /dev/null +++ b/src/main/java/de/bixilon/minosoft/protocol/protocol/PacketHandler.java @@ -0,0 +1,27 @@ +package de.bixilon.minosoft.protocol.protocol; + +import de.bixilon.minosoft.protocol.network.Connection; +import de.bixilon.minosoft.protocol.packets.clientbound.status.PacketStatusPong; +import de.bixilon.minosoft.protocol.packets.clientbound.status.PacketStatusResponse; + +public class PacketHandler { + Connection connection; + + public PacketHandler(Connection connection) { + this.connection = connection; + } + + public void handle(PacketStatusResponse pkg) { + System.out.println(String.format("Status response received: %s/%s online. MotD: '%s'", pkg.getResponse().getPlayerOnline(), pkg.getResponse().getMaxPlayers(), pkg.getResponse().getMotd())); + + } + + public void handle(PacketStatusPong pkg) { + System.out.println("Pong: " + pkg.getID()); + if (connection.isOnlyPing()) { + // pong arrived, closing connection + connection.disconnect(); + + } + } +} diff --git a/src/main/java/de/bixilon/minosoft/protocol/protocol/Protocol.java b/src/main/java/de/bixilon/minosoft/protocol/protocol/Protocol.java index b7a5ec1f4..8906b1035 100644 --- a/src/main/java/de/bixilon/minosoft/protocol/protocol/Protocol.java +++ b/src/main/java/de/bixilon/minosoft/protocol/protocol/Protocol.java @@ -1,8 +1,8 @@ package de.bixilon.minosoft.protocol.protocol; import de.bixilon.minosoft.protocol.packets.ClientboundPacket; -import de.bixilon.minosoft.protocol.packets.clientbound.handshaking.PacketStatusPong; -import de.bixilon.minosoft.protocol.packets.clientbound.handshaking.PacketStatusResponse; +import de.bixilon.minosoft.protocol.packets.clientbound.status.PacketStatusPong; +import de.bixilon.minosoft.protocol.packets.clientbound.status.PacketStatusResponse; import java.util.HashMap;