Difference between revisions of "Engine/Network Protocol"

From Minetest Developer Wiki
Jump to navigation Jump to search
Line 20: Line 20:
 
== Low-level protocol ==
 
== Low-level protocol ==
  
References: [https://github.com/minetest/minetest/blob/master/src/connection.h connection.h] [https://github.com/minetest/minetest/blob/master/src/connection.cpp connection.cpp]
+
References: [https://github.com/minetest/minetest/blob/master/src/network/connection.h connection.h] [https://github.com/minetest/minetest/blob/master/src/network/connection.cpp connection.cpp]
  
 
The Minetest protocol is a small layer on top of UDP. There is a header and four packet types.
 
The Minetest protocol is a small layer on top of UDP. There is a header and four packet types.

Revision as of 18:25, 26 July 2015

High-level protocol

Please note that the protocol is undergoing restructuring in the code. Links to files may be broken.

The high-level protocol is clearly written down and updated in networkprotocol.h.

For specifics, refer to client.cpp and server.cpp for the sending, and clientpackethandler.cpp and serverpackethandler.cpp for the receiving.

Handshake

From client's standpoint:

  • -> TOSERVER_INIT
  • <- TOCLIENT_INIT
  • -> TOSERVER_INIT2
  • <- Many many things

If you just want to check if a server is alive, you can disconnect after receiving TOCLIENT_INIT.

Low-level protocol

References: connection.h connection.cpp

The Minetest protocol is a small layer on top of UDP. There is a header and four packet types.

All numbers are big-endian.

A packet is sent through a channel to a peer with a basic header:
    Header (7 bytes):
    [0] u32 protocol_id
    [4] u16 sender_peer_id
    [6] u8 channel
sender_peer_id:
    Unique to each peer.
    value 0 is reserved for making new connections
    value 1 is reserved for server
channel:
    The lower the number, the higher the priority is.
    Only channels 0, 1 and 2 exist.
*/
#define BASE_HEADER_SIZE 7
#define PEER_ID_INEXISTENT 0
#define PEER_ID_SERVER 1
#define CHANNEL_COUNT 3

Channels aren't really used much. The channel priority thing hasn't actually ever been implemented and probably never will. Also, channels are intended to provide a few parallel reliable streams when needed - thus if one sends big reliable chunks of data in one channel and then small reliable packets in an another, and one of the pieces of the large chunk gets dropped and has to be re-sent, the small packets will see no delay. Because the order between channels is not maintained, care must be taken to not send stuff in different channels that needs to arrive in the right order.

/*
Packet types:

CONTROL: This is a packet used by the protocol.
- When this is processed, nothing is handed to the user.
    Header (2 byte):
    [0] u8 type
    [1] u8 controltype
controltype and data description:
    CONTROLTYPE_ACK
        [2] u16 seqnum
    CONTROLTYPE_SET_PEER_ID
        [2] u16 peer_id_new
    CONTROLTYPE_PING
    - There is no actual reply, but this can be sent in a reliable
      packet to get a reply
    CONTROLTYPE_DISCO
*/
#define TYPE_CONTROL 0
#define CONTROLTYPE_ACK 0
#define CONTROLTYPE_SET_PEER_ID 1
#define CONTROLTYPE_PING 2
#define CONTROLTYPE_DISCO 3

/*
ORIGINAL: This is a plain packet with no control and no error
checking at all.
- When this is processed, it is directly handed to the user.
    Header (1 byte):
    [0] u8 type
*/
#define TYPE_ORIGINAL 1
#define ORIGINAL_HEADER_SIZE 1

/*
SPLIT: These are sequences of packets forming one bigger piece of
data.
- When processed and all the packet_nums 0...packet_count-1 are
  present (this should be buffered), the resulting data shall be
  directly handed to the user.
- If the data fails to come up in a reasonable time, the buffer shall
  be silently discarded.
- These can be sent as-is or atop of a RELIABLE packet stream.
    Header (7 bytes):
    [0] u8 type
    [1] u16 seqnum
    [3] u16 chunk_count
    [5] u16 chunk_num
*/
#define TYPE_SPLIT 2

/*
RELIABLE: Delivery of all RELIABLE packets shall be forced by ACKs,
and they shall be delivered in the same order as sent. This is done
with a buffer in the receiving and transmitting end.
- When this is processed, the contents of each packet is recursively
  processed as packets.
    Header (3 bytes):
    [0] u8 type
    [1] u16 seqnum

*/
#define TYPE_RELIABLE 3
#define RELIABLE_HEADER_SIZE 3

#define SEQNUM_INITIAL 65500

These packet types are used in practice:

  • CONTROL(data) - unreliable control packet
  • ORIGINAL(data) - unreliable small data
  • SPLIT(piece of data) - unreliable piece of large data
  • RELIABLE(CONTROL(data)) - reliable control packet
  • RELIABLE(ORIGINAL(data)) - reliable small data
  • RELIABLE(SPLIT(piece of data)) - reliable piece of large data

Packet Type Specifics

RELIABLE

The RELIABLE packet wraps any other packet inside it, and once it is received, an ACK/CONTROL is sent back. If ACK/CONTROL isn't received for a sent RELIABLE packet in a short time, it should be periodically re-sent until the related ACK/CONTROL is received.

The sequence number is per-peer-per-connection. It is incremented after every reliable packet that is sent. It is not incremented in re-sent packets.

SPLIT

The SPLIT packet means data is split into multiple packets (because the internet doesn't transfer UDP packets larger than ~500 bytes); once all pieces of a SPLIT packet are received (identified as having the same seqnum and accumulating all the pieces 0...chunk_count-1), the insides is returned to the user of the network stack like data of an ORIGINAL packet.

Low-level control

Timeout

A connection may timeout after 30 seconds of nonresponsiveness to PINGs or RELIABLEs. A peer should send PING/CONTROL packets every 5 seconds or so if it has not sent any other packets.

Connect

A connection is initiated by sending an empty RELIABLE(ORIGINAL()) packet. The server will reply with a SET_PEER_ID/CONTROL packet. The client's peer id from there on is the one received from the server and the client can continue communicating by using it.

Disconnect

A connection is properly disconnected by sending a DISCO/CONTROL packet before dropping a connection.