package org.artisanlogiciel.games.minetest.net; import com.github.luben.zstd.Zstd; import org.artisanlogiciel.games.minetest.MapBlock; import org.artisanlogiciel.games.minetest.MapNode; import org.artisanlogiciel.games.minetest.core.PacketException; import org.artisanlogiciel.games.minetest.core.Serialize; import org.artisanlogiciel.games.minetest.core.v2s16; import org.artisanlogiciel.games.minetest.core.v3s16; import java.nio.ByteBuffer; /** * see src/network/networkprotocol.h of minetest sources * * * === NOTES === * * A packet is sent through a channel to a peer with a basic header: * Header (7 bytes): * [0] u32 protocol_id * [4] session_t sender_peer_id * [6] u8 channel * sender_peer_id: * Unique to each peer. * value 0 (PEER_ID_INEXISTENT) is reserved for making new connections * value 1 (PEER_ID_SERVER) is reserved for server * these constants are defined in constants.h * channel: * Channel numbers have no intrinsic meaning. Currently only 0, 1, 2 exist. * * * */ public class PacketHandler { ReliablePacketBuffer reliableBuffer = null; IncomingSplitBuffer[] incomingChanneleSplitBuffer = new IncomingSplitBuffer[4]; // server serialization in hello version int ser_version; // minetest protocol should be 0x4f457403 static int readProtocolId(byte[] buffer, int length) throws PacketException { return Serialize.readU32(buffer, 0, length); } static int readPeerId(byte[] buffer, int length) throws PacketException { return Serialize.readU16(buffer,4,length); } static int readChannel(byte[] buffer, int length) throws PacketException { return Serialize.readU8(buffer, 6, length); } NetworkPacket handleAny(byte[] buffer, int length) throws PacketException { int protocol_id = readProtocolId(buffer, length); int peer_id = readPeerId(buffer, length); int channel = readChannel(buffer, length); int type = Serialize.readU8(buffer,7,length); PacketType packetType = PacketType.getPacketType(type); NetworkPacket networkPacket = new NetworkPacket(protocol_id,peer_id,channel,packetType, buffer, length); // offset of packet within buffer. networkPacket.addOffset(BufferedPacket.BASE_HEADER_SIZE); System.out.println("length " + length + " protocol_id " + String.format("%x", protocol_id) + " peer_id " + peer_id + " channel " + channel + " type " + packetType); return networkPacket; } void handlePacketType_Control(NetworkPacket networkPacket) throws PacketException { } void handlePacketType_Reliable(NetworkPacket networkPacket) throws PacketException { // TODO handle misordered... /* if ( reliableBuffer == null ) { reliableBuffer = new ReliablePacketBuffer(); } BufferedPacket packet = new BufferedPacket(buffer); int nextExpected = 0; reliableBuffer.insert(packet, nextExpected); */ // handle nested packet networkPacket.addOffset(3); int offset = networkPacket.getOffset(); byte buffer[] = networkPacket.getBuffer(); int length = networkPacket.getLength(); PacketType packetType = PacketType.getPacketType(Serialize.readU8(buffer,offset,length)); System.out.println( "reliable " + packetType.toString()); switch (packetType) { case PACKET_TYPE_CONTROL: // handlePacketType_Control(networkPacket); break; case PACKET_TYPE_ORIGINAL: handlePacketType_Original(networkPacket); break; case PACKET_TYPE_SPLIT: handlePacketType_Split(networkPacket); break; case PACKET_TYPE_RELIABLE: // this is an error, no nested reliable accepted. throw new PacketException("nested reliable"); default: // error throw new PacketException("unknown type"); } } void handleCommand_Hello(NetworkPacket networkPacket) throws PacketException { // u8 deployed serialisation version ByteBuffer buffer = networkPacket.getByteBuffer(); int ser_ver = Serialize.readU8(buffer); ser_version = ser_ver; // u16 deployed network compression mode int net_compress = Serialize.readU16(buffer); // u16 deployed protocol version int deployed = Serialize.readU16(buffer); System.out.println(String.format("HELLO ser_ver=%d net_compress %d deployed %d", ser_ver,net_compress,deployed)); // u32 supported auth methods // std::string username that should be used for legacy hash (for proper casing) } // clientpackethandler.cpp Client::handleCommand_BlockData(NetworkPacket* pkt) // TOCLIENT_BLOCKDATA void handleCommand_BlockData(NetworkPacket networkPacket) throws PacketException { v3s16 p = networkPacket.v3s16(); // will be used to get vector... // v2s16 p2d = new v2s16(p.X,p.Z); System.out.println(String.format(" (X,Y,Z) %d %d %d", p.X, p.Y,p.Z)); // networkPacket.addOffset(6); // FIXME get it from handshake int version = 28; // Should be a MapBlock MapBlock block = new MapBlock(); block.deSerialize(networkPacket.getByteBuffer(),version); // now we have a block ! what to do with it ? } void handlePacketCommand(NetworkPacket networkPacket) throws PacketException { // consume type and ??? well ... 2 int command = Serialize.readU16(networkPacket.getBuffer(),networkPacket.getOffset(),networkPacket.getLength()); System.out.println(String.format("command %x length %d", command, networkPacket.getLength())); networkPacket.addOffset(2); // Original ... toClient - toServer switch (command) { case 0x02: { System.out.println("TOCLIENT_HELLO"); handleCommand_Hello(networkPacket); } break; case 0x20: { System.out.println("TOCLIENT_BLOCKDATA"); handleCommand_BlockData(networkPacket); } break; case 0x4f: { //TOCLIENT_SET_SKY = 0x4f, System.out.println("TOCLIENT_SET_SKY"); } break; } } void handlePacketType_Original(NetworkPacket networkPacket) throws PacketException { // eat original type 1. networkPacket.addOffset(1); handlePacketCommand(networkPacket); } void handlePacketType_Split(NetworkPacket networkPacket) throws PacketException { int channel = networkPacket.getChannel(); if ( channel < incomingChanneleSplitBuffer.length) { IncomingSplitBuffer splitBuffer = incomingChanneleSplitBuffer[channel]; if ( splitBuffer == null ) { splitBuffer = new IncomingSplitBuffer(); incomingChanneleSplitBuffer[channel] = splitBuffer; } if ( splitBuffer != null ) { BufferedPacket bufferedPacket = splitBuffer.insert(networkPacket); if ( bufferedPacket != null ) { // well should handle it. System.out.println("Reassembled packet size " + bufferedPacket.m_data.length); // reset it. incomingChanneleSplitBuffer[channel] = new IncomingSplitBuffer(); handleBufferedPacket(bufferedPacket); } } } else { throw new PacketException("invalid channel " + channel); } } void handleBufferedPacket(BufferedPacket bufferedPacket) throws PacketException { // FIXME, why a BufferedPacket anyway since we finaly need a NetworkPacket ? NetworkPacket networkPacket = new NetworkPacket(0,0,0, PacketType.PACKET_TYPE_ORIGINAL,bufferedPacket.m_data, bufferedPacket.size()); networkPacket.addOffset(BufferedPacket.BASE_HEADER_SIZE); handlePacketCommand(networkPacket); } void fromServer(byte[] buffer, int length) throws PacketException { System.out.print(" <- "); NetworkPacket networkPacket = handleAny(buffer,length); switch (networkPacket.packetType) { case PACKET_TYPE_CONTROL: // handlePacketType_Control(networkPacket); break; case PACKET_TYPE_RELIABLE: // handlePacketType_Reliable(networkPacket); break; case PACKET_TYPE_ORIGINAL: handlePacketType_Original(networkPacket); break; case PACKET_TYPE_SPLIT: handlePacketType_Split(networkPacket); break; default: // error throw new PacketException("unknown type"); } } void fromClient(byte[] buffer, int length) throws PacketException { System.out.print(" -> "); handleAny(buffer,length); } }