- prototype - between client and server, allow to capture all exchanges and potentially change them - created to capture server maps in laby - first test get only MapBlock, support version serialization version 28 - prepartion for 29 with zstd but untested. # Conflicts: # fetch_dependencies.sh
288 lines
9.2 KiB
Java
288 lines
9.2 KiB
Java
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);
|
|
}
|
|
|
|
}
|