views:

14

answers:

1

Hello, Trying to decode a UDP message, it is an array of 128 bytes, the first variable length string begins at the 7th byte. What I would like to do is split the array into individual elements and decode each element based on the type(byte,string). The data format/types are defined here: http://developer.valvesoftware.com/wiki/Server_queries#Goldsource_servers_2

Here is the raw data. Receive Buffer: 255 255 255 255 73 48 115 99 52 46 120 32 84 101 115 116 32 83 101 114 118 101 114 91 50 56 49 51 93 0 99 48 97 48 101 0 115 118 101 110 99 111 111 112 5 2 0 83 118 101 110 32 67 111 45 111 112 32 52 46 54 32 111 114 32 108 97 116 101 114 0 70 0 0 12 0 100 119 0 0 49 46 49 46 50 46 49 0 145 145 105 3 44 67 175 180 9 64 1 70 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0

Here is what it looks like as an array of strings split on "0x00". String Response: ????I0sc4.x Test Server[2813] c0a0e svencoop4 Sven Co-op 4.6 or later F ♀ dw 1.1.2.1 ??i♥,C?? @☺F

This works fine up to the fifth element(the "F" after the word "later"). Things get a little garbled after that and I cannot figure out how to select/decode the remaining elements.

# convert to string.
$StringResponse = [Text.Encoding]::ASCII.GetString($ReceiveBuffer)
# make an array of strings.
$SplitString = $StringResponse.split([char][byte]"0x00")
`# store the value of individual elements.
$servername_split = $SplitString[0].split([char]"0")
$Map = $SplitString[1]
$gamedirectory = $SplitString[2]
$gamedescription = $SplitString[3]
$appid = [byte][char]$splitstring[4]

Working with the raw data:
This works to access the first couple of byte elements after the four byte header 255, 255, 255, 255. Then the variable length strings begin.
$type = [char]$ReceiveBuffer[4]
$NetworkProtocolVersion = $ReceiveBuffer[5]

So I cannot do this to access the byte elements near the end of the raw data, unless I know in advance how many bytes are used by the variable length string data.
$numplayers = $ReceiveBuffer[72]
$maxnumplayers = $ReceiveBuffer[73]
$numbots = $ReceiveBuffer[74]
$dedicated = [char]$ReceiveBuffer[75]
$os = [char]$ReceiveBuffer[76]
$passwordreq = $ReceiveBuffer[77]
$secure = $ReceiveBuffer[78]

Console Output:
Type: I
Network Protocol Version: 48
Server Name: sc4.x Test Server[2813]
Map: c0a0e
Game Directory: svencoop4
Game Description: Sven Co-op 4.6 or later
AppID: 70

TIA,

A: 

hey I think I got it figured out.

[code]
# Receive Buffer size varies from server to server.
$ReceiveBuffer = New-Object Byte[] 128

# Info Reply
$BytesReceived = 0
Try
{
$BytesReceived = $UdpSocket.Receivefrom($ReceiveBuffer, [REF]$UdpSocket.LocalEndpoint)
}

# An Exception will be thrown if the server is down or hung.
Catch [Net.Sockets.SocketException]
{
# Set Flag
$Script:NoConnectionTimeOut = $False
}

# Verify and Decode HLDS server response.
If ($BytesReceived -gt 0)
{
# Ignore the four byte header and store the values of the first two bytes.
$type = [char]$ReceiveBuffer[4]
$netversion = $ReceiveBuffer[5]

     # Loop through the byte array and store each type of data.  
     $i = 0  
     $StringNum = 0  
     $FoundAppID = $False  
     foreach ($element in $receivebuffer)  
       {  
          If ($i -gt 5 -and $i -lt 80)
             {
                If ($element -ne 0)
                   {
                      $string = $string + [Text.Encoding]::ASCII.GetString($element)
                   }
                Else
                   {
                      $StringNum++
                      if ($stringnum -eq 1) {      $ServerName = $string }
                      if ($stringnum -eq 2) {         $MapName = $string }
                      if ($stringnum -eq 3) {     $InfoGameDir = $string }
                      if ($stringnum -eq 4) { $GameDescription = $string }
                      $string = ""
                   }
             }
          if ($i -gt 50 -and $element -eq 70 -and $FoundAppID -eq $False)
             {
                if ($element -eq 70)
                   {
                      $FoundAppID = $True
                      $AppID = $element;$arrayIndex = $i
                      $i++;$i++
                      $numplayers =      $ReceiveBuffer[$i]
                      $i++
                      $maxnumplayers =   $ReceiveBuffer[$i]
                      $i++
                      $numbots =         $ReceiveBuffer[$i]
                      $i++
                      $dedicated = [char]$ReceiveBuffer[$i]
                      $i++
                      $os =        [char]$ReceiveBuffer[$i]
                      $i++
                      $Password =        $ReceiveBuffer[$i]
                      $i++
                      $Secure =          $ReceiveBuffer[$i]
                      for ($j = 1; $j -lt 9; $j++)
                         {
                            $i++
                            $GameVersion = $GameVersion + [Text.Encoding]::ASCII.GetString($ReceiveBuffer[$i])
                         }
                      $i++
                      $EDF =             $ReceiveBuffer[$i]
                   }
             }
          $i++
       }

     # Write the server info.
     write-host "`n                    Type: $type"
     write-host "        Protocol Version: $netversion"
     write-host "             Server Name: $ServerName"
     write-host "                     Map: $MapName"
     write-host "          Game Directory: $InfoGameDir"
     write-host "        Game Description: $GameDescription"
     write-host "                   AppID: $AppID, $arrayIndex"
     write-host "       Number of players: $numplayers"
     write-host "         Maximum players: $maxnumplayers"
     write-host "          Number of bots: $numbots"
     write-host "               Dedicated: $dedicated"
     write-host "                      OS: $os"
     write-host "                Password: $Password"
     write-host "                  Secure: $Secure"
     write-host "            Game Version: $GameVersion"
     write-host "                     EDF: $EDF"
     #"Raw Data: $ReceiveBuffer"

[/code]

related questions