Server Query Protocol

The Server Query Protocol (SQP) allows clients to retrieve information about a running game server using UDP/IP packets.

A client initiates queries by sending a ChallengeRequest to the server. In response, the server sends a ChallengeResponse that includes a ChallengeId. Once the client receives the ChallengeResponse, it can continue to query the server for information.

The following sections describe the technical specifications of SQP, including data types, request types, and packet formats.

Game server state information that SQP supports includes:

  • Server name: The name of the game server.
  • Build ID: The identifier of the game image the game server is running.
  • Current players: The current number of connected players.
  • Max players: The maximum number of players that can join the game server.
  • IP address: The IP address of the machine the game server is hosted on.
  • Port: The port of the game server by which clients can connect to the specific game server on the host machine.
  • Game type: The game that the game server is running.
  • Map: The game map that's currently loaded on the game server.

Note: SQP works with the Game Server Hosting game server monitoring process to ensure reports by the game server match the information in Game Server Hosting’s database.

Requirements

On the game client end, you must populate the ServerInfoData object with all the game server information to ensure the game server reports the correct information.

There are some requirements that a game must meet before you can implement SQP as the game server query protocol:

  • On the game client end, you should populate the ServerInfoData object with all the game server information to ensure the game server reports the correct information.
  • You must include com.unity.transport as a package dependency.

Reference implementation

See go-svrquery for an example implementation of SQP. go-svrquery is a Golang client or talking to game servers using various query protocols, including SQP.

Data Types

All server queries consist of five basic types of data packed together into a data stream. The following table describes each of these types. All types are big-endian.

NameDescription
byteAn 8-bit character or an unsigned integer.
ushortA 16-bit unsigned integer.
uintA 32-bit unsigned integer.
ulongA 64-bit unsigned integer.
stringA variable-length byte field, encoded in UTF-8, and prefixed with a byte containing the length of the string. Strings are limited to 255 bytes.

Request Types

A client can make five types of requests to a server. The following table specifies the response a client should expect from the server for each request type.

RequestResponse
ChallengeRequestThe server returns a challenge number for the client to use in query request responses.
QueryRequest with ServerInfo chunkThe server returns basic information about the server, for example, the current number of players, the max players, the game type, and the build ID.

Packet Types

The following table contains the distinct types of SQP packets.

Packet typeByte value
ChallengeRequest0
ChallengeResponse0
QueryRequest1
QueryResponse1

Headers

All SQP packets, whether they're a request or a response, contain a header with the following data.

DataTypeComment
TypebyteContains the packet type. See Packet types.
ChallengeTokenuintThe ChallengeToken contains the challenge number. The challenge number is required for QueryRequest and QueryResponse packet types. See Challenge numbers.
Payload Contains the body of the packet (if the packet has a body).

Challenge Numbers

SQP uses a challenge number (which is a random 32-bit integer) to ensure the client making query requests is the same client that received the challenge number.

When a client first sends a request to a server, the server randomly selects the challenge number and includes it in the packet header. The client must then include the same challenge number in the header of all subsequent requests.

Challenge Packets

Clients can use challenge packets to retrieve a usable challenge number for a subsequent request.

Note: Challenge packets only have a header. There is no payload.

Request Format

DataComment
HeaderSee Headers.

The following code snippet has an example of a ChallengeRequest packet:

[0x00000000] 0x00 '\0' unsigned char
[0x00000001] 0x00 '\0' unsigned char
[0x00000002] 0x00 '\0' unsigned char
[0x00000003] 0x00 '\0' unsigned char
[0x00000004] 0x00 '\0' unsigned char

Response Format

DataComment
HeaderSee Headers.

The following code snippet contains an example of a ChallengeResponse packet:

[0x00000000] 0x00 '\0' unsigned char
[0x00000001] 0x80 '€' unsigned char
[0x00000002] 0x90 '•' unsigned char
[0x00000003] 0x23 '#' unsigned char
[0x00000004] 0x48 'H' unsigned char

Query Packets

Clients can send query packets to retrieve information about a server. Game Server Hosting only requires game servers to respond to queries with ServerInfo chunks. You can use the other request types but they're not necessary for Game Server Hosting.

Chunk Types

There are four different types of chunks that clients can request with a query packet. However, this documentation only includes the ServerInfo chunk type since it's the only one Game Server Hosting supports.

The byte value of each chunk type indicates the response chunk that the requesting client expects. When a server receives a query packet, it inspects the RequestedChunks field in the request and performs a bitwise AND operation using the byte value of the chunk type. The server knows a chunk type has been requested if the result of this operation is greater than zero.

For example, the server responds with a ServerInfo chunk if RequestedChunks&1 > 0. See note below.

Note: Although there are four types of chunk types available in the SQP protocol, Game Server Hosting only supports the ServerInfo chunk type.

Example RequestedChunkMeaningChecks
00000001ServerInfoRequestedChunks & 0x01 > 0
00000010ReservedRequestedChunks & 0x02 > 0
00000100ReservedRequestedChunks & 0x04 > 0
00000010ReservedRequestedChunks & 0x08 > 0

Note: RequestedChunks can request more than one chunk at the same time, so your implementation must be able to perform the correct bitwise checks on the RequestedChunks value.

Request Format

The request format is the same for all query requests.

Note: Game Server Hosting only requires a server to respond to ServerInfo requests. Therefore, all other request types are omitted.

DataTypeComment
Header See Headers.
VersionushortContains the version of SQP to use.
RequestedChunksbyteContains the requested ChunkTypes. See Chunk types.

The following code snippet has an example of a QueryRequest packet:

[0x00000000] 0x01 '\x1' unsigned char
[0x00000001] 0x80 '€' unsigned char
[0x00000002] 0x31 '1' unsigned char
[0x00000003] 0xbe '¾' unsigned char
[0x00000004] 0x18 '\x18' unsigned char
[0x00000005] 0x00 '\0' unsigned char
[0x00000006] 0x01 '\x1' unsigned char
[0x00000007] 0x01 '\x1' unsigned char

Response Format

All chunk types share a standard response format for the first four fields (Version, CurrentPacket, LastPacket, and PacketLength). Information after the PacketLength field of a packet varies depending on the request type.

Standard Response format

The following table has the part of the response that's the same for all chunk types.

DataTypeComment
Header See Headers.
VersionushortContains the version of SQP to use.
CurrentPacketbyteNot supported. The value should always be 0.
LastPacketbyteNot supported. The value should always be 0.
PacketLengthushortContains the length of the packet after this point.

ServerInfo response format

DataTypeComment
See Standard response format for fields that don't vary between chunk types.
ChunkLengthuintContains the length of the ServerInfo chunk after this point.
CurrentPlayersushortContains the number of players on the server.
MaxPlayersushortContains the maximum number of players the server supports.
ServerNamestringContains the name of the server.
GameTypestringContains the game on the server.
BuildIdstringContains the version number or build ID of the server.
MapstringContains the map the server currently has loaded.
PortushortContains the game port the server has exposed.

The following code snippet has an example of a QueryResponse packet:

[0x00000000] 0x01 '\x1' unsigned char
[0x00000001] 0xc0 'À' unsigned char
[0x00000002] 0x7a 'z' unsigned char
[0x00000003] 0x6c 'l' unsigned char
[0x00000004] 0x3d '=' unsigned char
[0x00000005] 0x00 '\0' unsigned char
[0x00000006] 0x01 '\x1' unsigned char
[0x00000007] 0x00 '\0' unsigned char
[0x00000008] 0x00 '\0' unsigned char
[0x00000009] 0x00 '\0' unsigned char
[0x0000000a] 0x5b '[' unsigned char
[0x0000000b] 0x00 '\0' unsigned char
[0x0000000c] 0x00 '\0' unsigned char
[0x0000000d] 0x00 '\0' unsigned char
[0x0000000e] 0x57 'W' unsigned char
[0x0000000f] 0x00 '\0' unsigned char
[0x00000010] 0x00 '\0' unsigned char
[0x00000011] 0x00 '\0' unsigned char
[0x00000012] 0x10 '\x10' unsigned char
[0x00000013] 0x14 '\x14' unsigned char
[0x00000014] 0x55 'U' unsigned char
[0x00000015] 0x45 'E' unsigned char
[0x00000016] 0x34 '4' unsigned char
[0x00000017] 0x20 ' ' unsigned char
[0x00000018] 0x44 'D' unsigned char
[0x00000019] 0x65 'e' unsigned char
[0x0000001a] 0x64 'd' unsigned char
[0x0000001b] 0x69 'i' unsigned char
[0x0000001c] 0x63 'c' unsigned char
[0x0000001d] 0x61 'a' unsigned char
[0x0000001e] 0x74 't' unsigned char
[0x0000001f] 0x65 'e' unsigned char
[0x00000020] 0x64 'd' unsigned char
[0x00000021] 0x20 ' ' unsigned char
[0x00000022] 0x53 'S' unsigned char
[0x00000023] 0x65 'e' unsigned char
[0x00000024] 0x72 'r' unsigned char
[0x00000025] 0x76 'v' unsigned char
[0x00000026] 0x65 'e' unsigned char
[0x00000027] 0x72 'r' unsigned char
[0x00000028] 0x2e '.' unsigned char
[0x00000029] 0x2f '/' unsigned char
[0x0000002a] 0x53 'S' unsigned char
[0x0000002b] 0x63 'c' unsigned char
[0x0000002c] 0x72 'r' unsigned char
[0x0000002d] 0x69 'i' unsigned char
[0x0000002e] 0x70 'p' unsigned char
[0x0000002f] 0x74 't' unsigned char
[0x00000030] 0x2f '/' unsigned char
[0x00000031] 0x53 'S' unsigned char
[0x00000032] 0x68 'h' unsigned char
[0x00000033] 0x6f 'o' unsigned char
[0x00000034] 0x6f 'o' unsigned char
[0x00000035] 0x74 't' unsigned char
[0x00000036] 0x65 'e' unsigned char
[0x00000037] 0x72 'r' unsigned char
[0x00000038] 0x47 'G' unsigned char
[0x00000039] 0x61 'a' unsigned char
[0x0000003a] 0x6d 'm' unsigned char
[0x0000003b] 0x65 'e' unsigned char
[0x0000003c] 0x2e '.' unsigned char
[0x0000003d] 0x53 'S' unsigned char
[0x0000003e] 0x68 'h' unsigned char
[0x0000003f] 0x6f 'o' unsigned char
[0x00000040] 0x6f 'o' unsigned char
[0x00000041] 0x74 't' unsigned char
[0x00000042] 0x65 'e' unsigned char
[0x00000043] 0x72 'r' unsigned char
[0x00000044] 0x47 'G' unsigned char
[0x00000045] 0x61 'a' unsigned char
[0x00000046] 0x6d 'm' unsigned char
[0x00000047] 0x65 'e' unsigned char
[0x00000048] 0x5f '_' unsigned char
[0x00000049] 0x54 'T' unsigned char
[0x0000004a] 0x65 'e' unsigned char
[0x0000004b] 0x61 'a' unsigned char
[0x0000004c] 0x6d 'm' unsigned char
[0x0000004d] 0x44 'D' unsigned char
[0x0000004e] 0x65 'e' unsigned char
[0x0000004f] 0x61 'a' unsigned char
[0x00000050] 0x74 't' unsigned char
[0x00000051] 0x68 'h' unsigned char
[0x00000052] 0x4d 'M' unsigned char
[0x00000053] 0x61 'a' unsigned char
[0x00000054] 0x74 't' unsigned char
[0x00000055] 0x63 'c' unsigned char
[0x00000056] 0x68 'h' unsigned char
[0x00000057] 0x03 '\x3' unsigned char
[0x00000058] 0x30 '0' unsigned char
[0x00000059] 0x30 '0' unsigned char
[0x0000005a] 0x31 '1' unsigned char
[0x0000005b] 0x08 '\b' unsigned char
[0x0000005c] 0x48 'H' unsigned char
[0x0000005d] 0x69 'i' unsigned char
[0x0000005e] 0x67 'g' unsigned char
[0x0000005f] 0x68 'h' unsigned char
[0x00000060] 0x72 'r' unsigned char
[0x00000061] 0x69 'i' unsigned char
[0x00000062] 0x73 's' unsigned char
[0x00000063] 0x65 'e' unsigned char
[0x00000064] 0x1e '\x1e' unsigned char
[0x00000065] 0x61 'a' unsigned char