Master Server Query Protocol

From Valve Developer Community
Revision as of 20:58, 21 November 2010 by Pizzahut (talk | contribs) (Client to master server: Code example)

Jump to: navigation, search

Client to master server

Send the following UDP query to a master server to get a list of Source host servers.

Format

Type Field Value
Byte Message Type 0x31 - the character "1"
Byte Region Code See below
String Zero IP:Port See below
String Zero Filter See below

Region codes

The region of the world that you wish to find servers in.

Byte Description
0x00 US East coast
0x01 US West coast
0x02 South America
0x03 Europe
0x04 Asia
0x05 Australia
0x06 Middle East
0x07 Africa
0xFF Rest of the world

IP:Port

The first IP:Port you should send is "0.0.0.0:0"

From then on, IP:Port becomes the last IP:Port received in the master servers reply. This allows steam to then grab another list of more servers.

Terminate this with 0x00

Note that whenever you open a new socket (and thus get a new random client port), the Master Server will always send you the first batch of IPs even if you pass a valid game server IP. Do not close your socket between packets.

Filter

Allows you to restrict the results to servers running a certain game, map, etc.

Send an empty string (0x00) to receive a list of all types of servers.

Insert \ in between filter parameters

\type\d
Servers running dedicated
\secure\1
Servers using anti-cheat technology (VAC, but potentially others as well)
\gamedir\[mod]
Servers running the specified modification (ex. cstrike)
\map\[map]
Servers running the specified map (ex. cs_italy)
\linux\1
Servers running on a Linux platform
\empty\1
Servers that are not empty
\full\1
Servers that are not full
\proxy\1
Servers that are spectator proxies
\napp\[appid]
Servers that are NOT running game [appid] (This was introduced to block Left 4 Dead games from the Steam Server Browser)
\noplayers\1
Servers that are empty
\white\1
Servers that are whitelisted

Sample query

To get all servers everywhere:

0000   31 FF 30 2E 30 2E 30 2E    1.0.0.0.
0008   30 3A 30 00 00             0:0..

This is the default Steam Server Browser query to the Source Master Server. It uses the napp filter to filter out Left 4 Dead games (which are meant to be joined using the matchmaking feature).

31 ff 30 2e 30 2e 30 2e 30 3a 30 00 5c 6e 61 70  1.0.0.0.0:0.\nap
70 5c 35 30 30 00                                p\500.

Master servers

Current master servers are:

GoldSrc
hl1master.steampowered.com:27010 (numeric IP may change) [1]
Source
hl2master.steampowered.com:27011 (numeric IP may change)
Rag Doll Kung Fu
67.132.200.140:27012
Red Orchestra
Unknown - same as Source?
SiN 1 Multiplayer
69.28.151.162:27010

If you can, get your application to check the file Steam\config\MasterServer2.vdf to get the latest list of master servers.

Reply format

The reply always starts with FF FF FF FF 66 0A.

The format is then a series of these server address blocks:

Type Data
Byte First octet of IP address
Byte Second octet of IP address
Byte Third octet of IP address
Byte Fourth octet of IP address
Unsigned Short Port number - usually 27015 (69 87) - this is network ordered, which is unlike every other Steam protocol.

Some of the servers may be unreachable, so query each server directly to find out. Note also that this list is not exhaustive, so if you're looking for a particular type of server make sure that you specify a filter with the query, rather than filtering client side.

Parsing packet

To get each octet you must convert the hex pairs into int32. When the packet is received by your UDP client, the hex values will be converted into their integer values. For example hex "ff" will be converted into "255" in a byte array. We don't want that 255 because the addresses that we are receiving are made up of 6 pairs. 4 pairs are for the octets and the remaining two are combined together to create the port.

An example code for parsing the packet:


        Public Function browser_ConnectMaster(Byval ipStartSeed As String, Byval allFilters As String, Byval regionCode As String) As Byte()
            Dim ip As String = browser_ToString(UnicodeEncoding.ASCII.GetBytes(ipStartSeed))
            Dim filter As String = browser_ToString(UnicodeEncoding.ASCII.GetBytes(allFilters))
            hexString = "31" & regionCode & ip & "00" & filter & "00"
            byteArray = browser_GetBytes(hexString, discarded)
            Public WithEvents udpClientM1, udpClient As New Sockets.UdpClient
            Dim receivedBytes As Byte() = New Byte() {}
            Dim pret As Integer
            Public RemoteIpEndPoint As New System.Net.IPEndPoint(System.Net.IPAddress.Any, 0)
            udpClientM1.Connect("72.165.61.136", 27010) ' Main Server
            RemoteIpEndPoint = udpClientM1.Client.RemoteEndPoint
            pret = udpClientM1.Send(byteArray, byteArray.Length)
            receivedBytes = udpClientM1.Receive(RemoteIpEndPoint)
            Dim retrievedServers() As String = browser_ToStringOriginal(receivedBytes).Split(" ")
            Return retrievedServers
        End Function

        Public Shared Function browser_ToStringOriginal(ByVal bytes As Byte()) As String
            Dim hexString As String = ""
            For i As Integer = 0 To bytes.Length - 1
                Dim newByteStr As String = Convert.ToString(bytes(i), 16)
                If newByteStr.Length < 2 Then ' Hex pair must always have two chars
                    hexString += "0" & newByteStr & " "
                Else               
                    hexString += newByteStr & " "
                End If
            Next
            Return hexString
        End Function

        Public Shared Function browser_ToString(ByVal bytes As Byte()) As String
            Dim hexString As String = ""
            For i As Integer = 0 To bytes.Length - 1
                hexString += bytes(i).ToString("X2")
            Next
            Return hexString
        End Function

        Public Shared Function browser_GetBytes(ByVal hexString As String, ByRef discarded As Integer) As Byte()
            discarded = 0
            Dim newString As String = ""
            Dim c As Char
            ' remove all none A-F, 0-9, characters
            For i As Integer = 0 To hexString.Length - 1
                c = hexString(i)
                If IsHexDigit(c) Then
                    newString += c
                Else
                    discarded += 1
                End If
            Next
            ' if odd number of characters, discard last character
            If newString.Length Mod 2 <> 0 Then
                discarded += 1
                newString = newString.Substring(0, newString.Length - 1)
            End If

            Dim byteLength As Integer = newString.Length / 2
            Dim bytes As Byte() = New Byte(byteLength - 1) {}
            Dim hex As String
            Dim j As Integer = 0
            For i As Integer = 0 To bytes.Length - 1
                hex = New [String](New [Char]() {newString(j), newString(j + 1)})
                bytes(i) = HexToByte(hex)
                j = j + 2
            Next
            Return bytes
        End Function

The above code will do the following: Connect to the master server, send a UDP query with specific variables (region code, start seed, filters), receive packet into byte array, convert byte array in hex array.

Now that we have converted the byte array into a hex array, we must convert each hex pair into its int32 equivalent.

    Dim serverList As New Hashtable()

    Private Sub browser_ParsePacket(Byval packet As String())
        Dim countPrimary, countSecondary As Integer
        Dim address, portBuilder, lastAddress As String

        Try
            For Each hexPair As String In packet
                If Not hexPair = Nothing Then
                    countPrimary += 1
                    If countPrimary > 6 Then
                        If countSecondary <= 2 Then ' Get first 3 octets
                            address = address & Convert.ToInt32(hexPair, 16) & "."
                        ElseIf countSecondary = 3 Then ' Fourth octet must have a trailing :
                            address = address & Convert.ToInt32(hexPair, 16)
                        ElseIf countSecondary > 3 Then ' Get last two hex pairs to form the port
                            portBuilder = portBuilder & hexPair
                        End If
                        If countSecondary = 5 Then ' Convert the combined hex pairs into an integer
                            portBuilder = Convert.ToInt32(portBuilder, 16)
                        End If
                        countSecondary += 1
                    End If
                    If countSecondary = 6 Then
                        lastAddress = address & ":" & portBuilder
                        serverList.Add(serverList.Count + 1, address & ":" & portBuilder)
                        countSecondary = 0
                        portBuilder = 0
                        address = String.Empty
                    End If
                End If
            Next
        Catch ex As Exception
            MsgBox(ex.Message)
        End Try

        If Not lastAddress = "0.0.0.0:0" Then
            browser_ConnectMaster(lastAddress, "\napp\500", "00")
            Exit Sub
        Else
            For Each item As DictionaryEntry In serverList
                    browser_HostConnect(item.Value)
            Next
        End If
    End Sub

This above code will go through each and every hex pair in the array. Ever 6 pairs (12 characters) is another IP address. It will add the found IP address to hashtable which can again be put through a loop to extract the addresses to connect and query later on.

(Code written by Erix920, your welcome devs :))

End of IP address list

The full requested IP list may not fit in 1 x packet. Subsequent packets must be requested by using the last received IP address and Port as the 'seed' in the next request.

The end of the IP list is indicated by a received IP address of 0.0.0.0 Port:0.

Code example

Game server to master server

Join

Shortly after a game server has been initialized, it picks two master servers to "join." In order for clients to see a particular game server when they click on the "Internet" tab, the game server must be present in the Steam master servers' records.

The game server sends each master server "q" (71).

The master servers each respond by sending FF FF FF FF 73 0A followed by a (relatively) unique 4-byte "challenge" number. If you send the master servers an invalid challenge, you will get another challenge as a response.

Challenge response

After receiving the challenge packet, the game server then sends its challenge information in the following format:

Goldsource

 002a                                 30 0a 5c 70 72 6f            0.\pro
 0030   74 6f 63 6f 6c 5c 34 37 5c 63 68 61 6c 6c 65 6e  tocol\47\challen
 0040   67 65 5c 31 33 33 39 38 39 35 37 30 32 5c 70 6c  ge\1339895702\pl
 0050   61 79 65 72 73 5c 30 5c 6d 61 78 5c 32 5c 62 6f  ayers\0\max\2\bo
 0060   74 73 5c 30 5c 67 61 6d 65 64 69 72 5c 63 73 74  ts\0\gamedir\cst
 0070   72 69 6b 65 5c 6d 61 70 5c 64 65 5f 64 75 73 74  rike\map\de_dust
 0080   5c 74 79 70 65 5c 64 5c 70 61 73 73 77 6f 72 64  \type\d\password
 0090   5c 30 5c 6f 73 5c 6c 5c 73 65 63 75 72 65 5c 30  \0\os\l\secure\0
 00a0   5c 6c 61 6e 5c 30 5c 76 65 72 73 69 6f 6e 5c 31  \lan\0\version\1
 00b0   2e 31 2e 32 2e 35 2f 53 74 64 69 6f 5c 72 65 67  .1.2.5/Stdio\reg
 00c0   69 6f 6e 5c 32 35 35 5c 70 72 6f 64 75 63 74 5c  ion\255\product\
 00d0   63 73 74 72 69 6b 65 0a                          cstrike.

The challenge number is simply the challenge sent by the master server converted to an int.

Source

 002a                                 30 0a 5c 70 72 6f            0.\pro
 0030   74 6f 63 6f 6c 5c 37 5c 63 68 61 6c 6c 65 6e 67  tocol\7\challeng
 0040   65 5c 31 33 33 39 36 31 38 32 33 5c 70 6c 61 79  e\133961823\play
 0050   65 72 73 5c 30 5c 6d 61 78 5c 32 5c 62 6f 74 73  ers\0\max\2\bots
 0060   5c 30 5c 67 61 6d 65 64 69 72 5c 63 73 74 72 69  \0\gamedir\cstri
 0070   6b 65 5c 6d 61 70 5c 64 65 5f 64 75 73 74 5c 70  ke\map\de_dust\p
 0080   61 73 73 77 6f 72 64 5c 30 5c 6f 73 5c 6c 5c 6c  assword\0\os\l\l
 0090   61 6e 5c 30 5c 72 65 67 69 6f 6e 5c 32 35 35 5c  an\0\region\255\
 00a0   74 79 70 65 5c 64 5c 73 65 63 75 72 65 5c 30 5c  type\d\secure\0\
 00b0   76 65 72 73 69 6f 6e 5c 31 2e 30 2e 30 2e 32 38  version\1.0.0.28
 00c0   5c 70 72 6f 64 75 63 74 5c 63 73 74 72 69 6b 65  \product\cstrike
 00d0   0a                                               .

The challenge number is simply the challenge sent by the master server converted to an int.

Orangebox

0000   30 0a 5c 70 72 6f 74 6f 63 6f 6c 5c 37 5c 63 68  0.\protocol\7\ch
0010   61 6c 6c 65 6e 67 65 5c 31 39 35 39 36 38 37 33  allenge\19596873
0020   39 39 5c 70 6c 61 79 65 72 73 5c 31 5c 6d 61 78  99\players\1\max
0030   5c 34 5c 62 6f 74 73 5c 30 5c 67 61 6d 65 64 69  \4\bots\0\gamedi
0040   72 5c 74 66 5c 6d 61 70 5c 61 72 65 6e 61 5f 62  r\tf\map\arena_b
0050   61 64 6c 61 6e 64 73 5c 70 61 73 73 77 6f 72 64  adlands\password
0060   5c 30 5c 6f 73 5c 77 5c 6c 61 6e 5c 31 5c 72 65  \0\os\w\lan\1\re
0070   67 69 6f 6e 5c 2d 31 5c 67 61 6d 65 74 79 70 65  gion\-1\gametype
0080   5c 61 72 65 6e 61 5c 74 79 70 65 5c 6c 5c 73 65  \arena\type\l\se
0090   63 75 72 65 5c 30 5c 76 65 72 73 69 6f 6e 5c 31  cure\0\version\1
00a0   2e 30 2e 34 2e 33 5c 70 72 6f 64 75 63 74 5c 74  .0.4.3\product\t
00b0   66 0a                                            f.

The challenge number is simply the challenge sent by the master server converted to an int.

Differences

The field order is a bit different with Source than with Goldsource.

Goldsource protocol challenge players max bots gamedir map type password os secure lan version region product
Source protocol challenge players max bots gamedir map password os lan region type secure version product

Heartbeat

A "heartbeat" occurs every five minutes in order to let the master servers know that a game server is still "alive". The game server simply goes through the process of "joining" the master server list again.

Quit

Goldsource
The game server sends the master server 62 0A to signal that the game server has shut down.
Source
The game server sends the master server 62 0A 00 to signal that the game server has shut down.

See also