The Arachne protocol is a simple protocol that allows for clients to connect to an authoritative server using some kind of identification, and will then allow the client and server to communicate with each other. This protocol is very simple and is primarily designed to be used in games, but could potentially be used in other applications as well.
It uses UDP for all communication and allows for 4 different ways of communication:
-
Unreliably, fastest way of communication, but packets can be lost.
-
Reliably, slower way of communication, but packets will never be lost.
No regard for order is taken for ANY packets sent, so the order of received packets is not guaranteed to be the same as the order of sent packets.
The protocol consists of a few different packets, which are mostly used for connection intialization, and connection termination.
The protocol uses 4 different channels and has 8 different packet types. Both the channel and packet type are specified as a single bit packed byte in the packet header. The channel is specified in the high 4 bits, and the packet type is specified in the low 4 bits.
The 4 different channels are:
Unreliable = 0x00
Reliable = 0x10
The 8 different packet types are:
Connection request = 0x00
Connection challenge = 0x01
Connection challenge response = 0x02
Connection response = 0x03
Connection keep alive = 0x04
Application data = 0x05
Connection termination = 0x06
Connection termination ack = 0x07
Server info request = 0x08
Server info response = 0x09
So, a packet header with a first byte of 0x00
would be a Connection request
packet on the Unreliable
channel. A packet header with a first byte of 0x15
would be an Application data
packet on the Reliable
channel.
The entire packet header looks like the following:
[channel + packet type] (1 byte, high 4b = channel, low 4b = type)
[sequence number] (8 bytes)
[sequence ack] (8 bytes)
[ack bits] (4 bytes)
...
[data] (variable length)
A total of 21 bytes of overhead is added to each packet, to allow for the Arachne protocol to function properly.
There 2 different ways to allow for a connection to be established.
-
No authentication - This is the simplest way of connecting, and is used when the server does not require any kind of authentication from the client. The client will simply send a
CR
packet to the server, and the server will respond with aCRS
packet either allowing or denying the connection. -
With authentication - This is a more complex way of connecting, and is used when the server requires some kind of authentication from the client. The client will send a
CR
packet to the server, and the server will respond with aCH
packet, which will contain a challenge for the client. The client will then respond with aCHR
packet, which will contain the challenge response. The server will then respond with aCRS
packet either allowing or denying the connection. The authentication method is up to the developer to implement, however, there are some examples provided if needed.
This packet is sent by the client to the server, and is used to request a connection to the server. The server will then respond with a Connection Response packet.
If the given protocol id
and protocol version
is not supported by the server, the server will respond with a CRS
packet with response code 0x01
(unsupported protocol).
[header] (21 bytes) (always sent on the Reliable channel)
...
[protocol id] (4 bytes)
[protocol version] (4 bytes)
This packet is sent by the server to the client, and is used to challenge the client to prove that it is allowed to connect. The client will then respond with a CHR
packet.
The packet can contain anything that the developer so chooses, and it is up to the developer to implement this.
[header] (21 bytes) (always sent on the Reliable channel)
...
[challenge length] (4 bytes)
[challenge] (variable length)
This packet is sent by the client to the server, and is used to respond to the challenge that the server sent. The server will then respond with a CRS
packet.
[header] (21 bytes) (always sent on the Reliable channel)
...
[response length] (4 bytes)
[response] (variable length)
This packet is sent by the server to the client, and is used to respond to a Connection Request packet. This response will contain a code that will indicate the outcome of the connection request.
[header] (21 bytes) (always sent on the Reliable channel)
...
[response code] (1 byte)
[client id] (8 bytes)
This packet is sent by the client to the server, and is used to keep the connection alive. The server will not respond to this packet, it is only for the server to know if the client is still alive and connected.
KA
packets are sent every 5 seconds by default, but this can be changed by the developer.
If no KA
packets are received from a connected client within a specified timeout, the server will consider the client to be disconnected and will remove the client from its list of connected clients.
[header] (21 bytes) (always sent on the Unreliable channel)
...
(no data, packet type enough)
This packet can be sent by either the client or the server, and is used to send application data to the other party. The packet can contain any kind of data that the developer so chooses.
[header] (21 bytes) (sent on whichever channel the developer chooses)
...
[data length] (4 bytes)
[data] (variable length)
This packet is sent by either the client or the server, and is used to terminate the connection. The packet can contain a reason for the termination. The other party should then respond with a CTA
packet, to acknowledge the termination.
[header] (21 bytes) (always sent on the Reliable channel)
...
[reason length] (4 bytes)
[reason string] (variable length, UTF-8 encoded)
This packet is sent by either the client or the server, and is used to acknowledge the termination of the connection.
[header] (21 bytes) (always sent on the Reliable channel)
...
(no data, packet type enough)
This packet is sent by the client to the server, and is used to request information about the server. The server will then respond with a SIRS
packet.
[header] (21 bytes) (always sent on the Unreliable channel)
...
(no data, packet type enough)
This packet is sent by the server to the client, and is used to respond to a SIR
packet. This response will contain information about the server.
[header] (21 bytes) (always sent on the Unreliable channel)
...
[info] (variable length, raw bytes)
The info
field can contain any kind of data that the developer so chooses, and it is up to the developer to implement this, using an IServerInfoProvider
implementation.