I'm developing an application that detects Source-based games running on the LAN. Following up on the specifications provided by Valve, I have it narrowed down to exactly what I want: making a UDP connection on port 27015, sending an A2S_INFO
query (0xFFFFFFFF followed by "TSource Engine Query") and parsing the binary reply.
This is the code I'm working with:
Dim sIP As String = "192.168.0.154"
Dim nPort As Integer = 27015
Dim connectionMessage As String = "ÿÿÿÿTSource Engine Query" & Chr(0)
Dim endPoint As New IPEndPoint(IPAddress.Parse(sIP), nPort)
Dim client As Socket = New Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp)
client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReceiveTimeout, 6000)
client.SendTo(Encoding.ASCII.GetBytes(connectionMessage), endPoint)
Console.WriteLine("Message sent to " & sIP & ":" & nPort & vbCrLf & connectionMessage)
Dim sBuffer(1400) As Byte
Try
client.ReceiveFrom(sBuffer, endPoint)
MsgBox(System.Text.Encoding.Unicode.GetString(sBuffer))
Catch ex As SocketException
MsgBox("Failed to receive response on " & sIP & ":" & nPort & ":" & vbCrLf & ex.Message)
End Try
I keep getting SocketError.TimedOut
exceptions, informing me:
Failed to receive response on 192.168.0.154:27015: A connection attempt failed because the connected party did not properly respond after a period of time, or established connection failed because connected host has failed to respond
I'm fairly certain this is very close to the answer, because the following very simple PHP version works like a charm:
$ip = "192.168.0.154";
$port = 27015;
$fp = fsockopen("udp://".$ip,$port, $errno, $errstr);
socket_set_timeout($fp, 6);
$prefix = "\xff\xff\xff\xff";
$command = "TSource Engine Query";
$msg = "$prefix$command";
fputs($fp, $msg, strlen($msg));
$response = "";
do {
$response .= fgets($fp, 16);
$status = socket_get_status($fp);
} while ($status['unread_bytes']);
fclose ($fp);
echo $response;
This provides me with a reply in accordance with the specifications.
I'm close, but something's amiss with my VB.NET code. What am I doing wrong?
The solution
The encoding type is not valid for transmitting binary data. I replaced the following:
Encoding.ASCII.GetBytes(connectionMessage)
with:
System.Text.Encoding.[Default].GetBytes(connectionMessage)
And it was instantly solved.
A more robust solution, suggested by "pub", might be to specify the code page (although I haven't tested this):
Encoding.GetEncoding("iso-8859-1").GetBytes(connectionMessage)