Relay message protocol

If you’re using the Relay SDK with UTP or with NGO for your project, the Relay message protocol is already supported. However, if you want to use an alternative engine or networking solution, you’ll need to implement the Relay message protocol before using it. Use the Relay message protocol specifications to implement the Relay message protocol.

The Relay message protocol expects you to express field values in big-endian order, also known as the “network order,” where the most significant byte occurs first.

Messages aren't authenticated except for the BIND message, which uses an HMAC signature.

Players can only connect and relay messages with other players from the same Unity project and environment. Relay rejects any attempts to communicate across Unity environments.

All messages have a standard header and a message-specific body. Check out Standard header and Message bodies.

Message types

CodeNameDescription
0BIND messageA BIND message indicates a bind request sent from a client to a Relay server.
1BIND_RECEIVED messageA BIND_RECEIVED message indicates a successful response from the Relay server to a client after receiving a BIND request.
2PING messageA PING message indicates a ping message sent between a client and a Relay server (both directions) to keep the connection alive.
3CONNECT_REQUEST messageA CONNECT_REQUEST message indicates a request from a player (the requesting client) to connect to another player (the target client).
4Reserved.
5Reserved.
6ACCEPTED messageAn ACCEPTED message indicates a confirmation message sent from a Relay server to a requesting client after a successful connection to a target client.
7Reserved.
8Reserved.
9DISCONNECT messageA DISCONNECT message indicates a request to disconnect two connected players.
10RELAY messageA RELAY message indicates a request to send a message between two players (clients).
11CLOSE messageA CLOSE message indicates a request from a client to unbind from a Relay server.
12ERROR messageAn ERROR message indicates an error that has occurred.

Accept mode types

The accept mode defines how a Relay server handles requests from clients trying to connect.

Relay only supports the AUTO accept mode. A connection mode of AUTO means the Relay server automatically accepts the connection if its capacity allows it (the number of connections must not exceed the maximum number of allowed connections).

CodeNameDescription
0AcceptModeAutoAcceptModeAuto indicates that connections to clients will be automatically accepted by the Relay server.
1 Reserved.

Standard header

All message types share a standard header that has a signature, the Relay message protocol version, and the message contained in the body of the packet.

Bytes1 .. 234
PurposeSignatureVersionType

The following table describes each field found in the standard header.

FieldTypeDescription
Signature[]byteThe Signature is always 0xDA72.
Versionuint8The Version is the Relay message protocol version.

The value should be 0 for the initial release.

Typeuint8The Type is an integer representing the message type contained in the body. Check out Message types.

Message bodies

BIND message

BIND messages are sent from a client to a Relay server to create a mapping from a client’s IP address and port for a specific allocation. This message is authenticated to verify the identity of the client.

The response received from the Allocations service has the information necessary for the client to authenticate its BIND messages. The response from the Allocations service to the BIND message shows the binding status.

Clients can send identical BIND messages as long as the client’s IP address and port haven't changed. For example, if a client sends a BIND message on a following connection after changing its IP address or port, the Nonce value must be greater than the previously supplied value.

Bytes1 .. 456 .. 789 .. NN+1 .. 33
PurposeHeader (Type 0)AcceptModeNonceConnectionDataLengthConnectionDataHMAC

The following table describes each field found in a BIND message.

FieldTypeDescription
AcceptModeuint8AcceptMode defines how a Relay server should handle requests from clients trying to connect to the owner of this allocation.

Currently, only the AUTO accept mode is supported.

See Accept mode types.

Nonceuint16Nonce is a single-use cryptographic nonce. Each following BIND message must have an incremented nonce value. It's conventional to start the nonce value at 0.
ConnectionDataLengthuint8ConnectionDataLength describes the byte length of ConnectionData.

The maximum allowed value is 255.

ConnectionData[]byteConnectionData is the encrypted connection data of the connecting client.

This field’s length is variable. The maximum length is 255 bytes.

HMAC[32]byteHMAC is a hash-based message authentication code generated using a known key and the preceding bytes in the message, including the header.

See Authentication.

Security

You must sign the HMAC with the secret key returned from the Allocations service. If the HMAC is invalid, the Relay server silently rejects the BIND message.

The Relay server also validates the nonce value to mitigate message replay attacks by bad actors. If the Relay server determines that a nonce is invalid, it silently rejects it. If it’s the first time the client is binding to a Relay server with a BIND message, the nonce value can be 0.

BIND_RECEIVED message

Relay servers send BIND_RECEIVED messages to requesting clients to confirm they have successfully bound to the Relay server through a BIND message. After receiving the confirmation, the requesting client can initiate communication with a target client using a CONNECT_REQUEST message.

Note: The Relay server sends a BIND_RECEIVED message to the client for each successfully processed BIND request.

Bytes1 .. 4
PurposeHeader (Type 1)

PING message

PING messages are simple messages that keep the binding between a client and a Relay server alive by resetting the client timeout. Relay servers automatically disconnect clients after 10 seconds of inactivity. Any message received by the Relay server involving this client, either as a sender or receiver, resets this timeout. For games with a lower message frequency, the PING message allows clients to reset the disconnection timer.

Tip: Clients must send PING messages every second or two in addition to the other messages to ensure the connection doesn’t timeout. If you’re using Relay with NGO, the network manager automatically keeps the connection alive. However, if you’re using Relay with UTP, you must manually keep the connection alive.

Each PING message has the client’s allocation ID and an arbitrary number that identifies the message.

When a Relay server receives a PING message from a client, it sends the packet back to the client without altering it. This allows you to use PING messages to check connectivity and measure round trip time.

The Relay server doesn't send back an error message if the allocation ID has expired.

Warning: Clients must bind with the Relay server through a BIND message before sending a PING message. The following scenarios will result in the Relay server returning a ErrClientPlayerMismatchERROR message:

  • The client sends a PING message before binding to the Relay server through a BIND message.
  • The client sends a PING message after its IP address has changed and before rebinding to the Relay server with the new IP address.
Bytes1 .. 45 .. 2021 .. 22
PurposeHeader (Type 2)AllocationIDNumber

The following table describes each field found in a PING message.

FieldTypeDescription
AllocationID[16]byteAllocationID is a 16-byte UUID identifying the allocated client sending the ping.
Numberuint16Number is an arbitrary unsigned integer the Relay server echoes back to the client. This can be used by the client to correlate PING messages that are sent and received.

CONNECT_REQUEST message

CONNECT_REQUEST messages are sent from a requesting client to a Relay server to establish a connection to a target client. The target player the requesting client wants to connect to (or the target client) is represented by ToConnectionData, which the Relay server decrypts to determine which player to connect with.

Warning: The target client and the requesting client must be on the same Unity project and environment.

Note: Relay servers have no formal idea of player groups (often referred to as sessions). All players within a logical game session are bound to the same Relay server. By extension of this, Relay doesn’t make any assumptions about the length of a player’s bindings and connections in relation to the game session. It’s up to the game client to determine whether players unbind from the Relay server at the end of a session or use the same binding for multiple sessions.

Bytes1 .. 45 .. 202122 ..
PurposeHeader (Type 3)AllocationIDToConnectionData LengthToConnectionData

The following table describes each field found in a CONNECT_REQUEST message.

FieldTypeDescription
AllocationID[16]byteAllocationID is a 16-byte UUID that identifies the allocated client that's requesting the connection.
ToConnectionDataLengthuint8ToConnectionDataLength is the byte length of ToConnectionData.

The maximum allowed value is 255.

ToConnectionData[]byteToConnectionData is an encrypted data blob that describes the client to connect to. See Connection data.

This field has a variable length. The maximum byte length is 255.

ACCEPTED message

A Relay server sends an ACCEPTED message to a requesting client after a successful connection to a target client.

Note: The Relay server returns the ACCEPTED message to the requesting client if the target client has fewer than their specified maximum connections.

Bytes1 .. 45 .. 2021 .. 36
PurposeHeader (Type 6)FromAllocationIDToAllocationID

The following table describes each field found in an ACCEPTED message.

FieldTypeDescription
FromAllocationID[16]byteFromAllocationID is a 16-byte UUID that identifies the target client.
ToAllocationID[16]byteToAllocationID is a 16-byte UUID that identifies the allocated client that requested the connection (the requesting client).

DISCONNECT message

The DISCONNECT message is the inverse of the CONNECT_REQUEST handshake and allows a client to disconnect from another client. A client can disconnect from any other client it has connected with by sending a DISCONNECT message to the Relay server.

When the Relay server receives the message, it removes the specified allocation ID from the requesting client’s list of connected players. The Relay server also forwards the DISCONNECT request to the host client so the client can update its map of connected players to remove the requesting client's Allocation ID.

The Relay server then sends the DISCONNECT message back to the client as a confirmation. If either of the allocation IDs in the message body is invalid, the Relay server sends an ERROR message instead.

Once a client has disconnected, the Relay server rejects all RELAY messages sent to that client’s allocation ID. A disconnected client can re-establish a connection with a CONNECT_REQUEST message.

Note: The host and connecting clients can both send a DISCONNECT messages. However, if a host client sends a DISCONNECT message, the client must migrate the joined players to a new host or disconnect them all. Relay doesn't handle host migration.

Bytes1 .. 45 .. 2021 .. 36
PurposeHeader (Type 9)FromAllocationIDToAllocationID

The following table describes each field found in a DISCONNECT message.

FieldTypeDescription
FromAllocationID[16]byteFromAllocationID is a 16-byte UUID that identifies the allocated client that's requesting to close the connection (the requesting client).
ToAllocationID[16]byteToAllocationID is a 16-byte UUID that identifies the allocated client whose connection is being closed (the target client).

RELAY message

RELAY messages allow clients to send messages containing any arbitrary payload of bytes between each other without awareness of each other’s IP addresses and ports.

Before sending a RELAY message between clients, the Relay server ensures the client sending the packet has previously been authenticated as the FromAllocationID through a BIND message. If the client hasn't previously bound, the Relay server returns an ErrClientPlayerMismatch ERROR message.

The Relay server also ensures the two clients have an established connection through a earlier CONNECT_REQUEST exchange. The Relay server returns an ErrNotConnectedERROR message if the clients aren't connected.

If all validations pass, the Relay server sends the entire message to the ToAllocationID as-is. The Relay server doesn't send any confirmation message to the FromAllocationID.

Bytes1 .. 45 .. 2021 .. 3637 .. 3839 ..
PurposeHeader (Type 10)FromAllocationIDToAllocationIDLengthContent

Note: The maximum length of a RELAY message isn't guaranteed at the protocol level. It's defined by the configuration of the Relay server itself, which has a default maximum content length of **1400 **bytes and results in a RELAYmessage maximum size of **1438 **bytes.

The following table describes each field found in a RELAY message.

FieldTypeDescription
FromAllocationID[16]byteFromAllocationID is a 16-byte UUID that identifies the allocated client sending the message (the requesting client).
ToAllocationID[16]byteToAllocateID is a 16-byte UUID that identifies the allocated client receiving the message (the target client).
Lengthuint16Length specifies the length of the message content in bytes.

The maximum value is 1400.

Content[]byteContent has the content of the message.

CLOSE message

CLOSE messages are idempotent messages that allow a client to unbind and deallocate from a Relay server. Clients should send a CLOSE message to the Relay server when leaving their game session or when closing the game client. Clients can only close their own bindings to the Relay server; they can't close another client’s binding.

Clients should send CLOSE messages multiple times to increase the chance of successful delivery. Because CLOSE messages are idempotent, there’s no risk of the Relay server sending an ERROR message if the client has already been disconnected.

The CLOSE message is a best effort to gracefully terminate an allocation, and there is no guarantee it will succeed. Because Relay servers can deallocate clients with a timeout, Relay servers don't rely on a CLOSE message to remove a client allocation.

The client sending the CLOSE message must be bound to the Relay server through a earlier BIND request. If the client isn't bound to the Relay server (or the client’s IP address has changed), the Relay server will silently reject the message. Use PING messages to prevent unintended allocation timeouts.

Note: Unbound clients still expire through timeout. See Client timeouts.

Bytes1 .. 45 .. 20
PurposeHeader (Type 11)AllocationID

The following table describes each field found in a CLOSE message.

FieldTypeDescription
AllocationID[16]byteAllocationID is a 16-byte UUID that identifies the client's allocation.

ERROR message

Relay servers use ERROR messages strictly to inform the client that an error has occurred.

Bytes1 .. 45 .. 2021
PurposeHeader (Type 12)AllocationIDErrorCode

The following table describes each field found in an ERROR message.

FieldTypeDescription
AllocationID[16]byteAllocationID is a 16-byte UUID that identifies the client's allocation.
ErrorCodeuint8ErrorCode represents an error code. See Error codes below.

Error codes

The following table describes each of the possible error messages a Relay server can send to a client.

CodeNameDescription
0Invalid protocol version (ErrInvalidProtocolVersion)ErrInvalidProtocolVersion is returned when a parsed message has an unexpected protocol version.
1Player timed out due to inactivity (ErrTimeout)ErrTimeout is returned when a client’s binding to a Relay server has timed out. See Client timeouts.

Clients should use PING messages to prevent this error.

2Unauthorized (ErrUnauthorized)ErrUnauthorized is returned when a client attempts to perform an operation that it's not authorized to perform.
3Allocation ID client mismatch (ErrClientPlayerMismatch)ErrClientPlayerMismatch is returned when a client has sent a RELAY message to the server using an unknown network connection.

It's intended to inform the client that the IP address they're using has changed from the one the Relay server is aware of.

This error message indicates the client should re-bind with a new BIND message.

4Allocation ID not found (ErrAllocationNotFound)ErrAllocationNotFound is returned when the Relay server can't find an allocation for the given allocation ID.
5Not connected (ErrNotConnected)ErrNotConnected is returned when a client attempts to communicate with a client to whom it's not connected.
6Self-connect not allowed (ErrSelfConnectNotAllowed)ErrSelfConnectNotAllowed is returned when a client sends a CONNECT_REQUEST message to a client with the same allocation ID.