How to query Unreal Tournament Server within ASP page

I wanted to have a web page for checking if anyone was playing on my Unreal Tournament Server. No IIS/ASP script was readily available, so I wrote one myself.  The server is queried with GameSpy UDP protocol, so naturally I tried to find a free Sockets COM component to do the dirty work for me. Yeah, there HAS been one available (GSSockets), years ago, and naturally it was nowhere to be found.

.NET to the rescue. I have .NET framework installed on my server, so I decided to use the System.Net.Sockets class. System.Net class is utilized for grabbing the reply from the server.

Quick and really dirty one-page solution to my problem is presented below. Use and modify at your own risk. Copy and save to an .aspx page, and it should work. Remember to change the server name and port if needed.

You can of course use this script in your own IIS to monitor someone else's UT server if you want - there is no need for the script to sit on the same server where UT is running. And with a little creative modifying, you could run this from command prompt or create a Win32 app.

Oh, and by the way, you might want to fix the latest UT99 version (4.36) which has a known UDP query bug - the mutators are sometimes not returned when querying the server status. Fix is available here.

<%@ page language="VB" %>
<%@ Import Namespace="System.Net.Sockets" %>
<%@ Import Namespace="System.Net" %>

<meta http-equiv="refresh" content="120">
<meta http-equiv="Content-Type" content="text/html; charset=windows-1252">
<title>Unreal Tournament Status</title>
body	{font-family: Verdana, Arial, Sans-serif; font-size: 9pt}
td           { text-align: left; vertical-align: top; font-size: 9pt}


' Randomize local port to maximize success on error 
' (if local port is reserved, the script will fail)

Dim LocalPort As System.Int32 = 6500+Int(Rnd*100)

' Create the UDP component
Dim udpClient As New UdpClient(LocalPort)
	' The UT server name goes here.
	Dim RemoteHost = ""
		' Connect to the server
		udpClient.Connect(RemoteHost, 7778)
		' Sends a message to the host to which you have connected.	
		Dim sendBytes As [Byte]() = Encoding.ASCII.GetBytes("\status\\echo\")
		udpClient.Send(sendBytes, sendBytes.Length)
      	' Create the listener
		Dim RemoteIpEndPoint As New IPEndPoint(IPAddress.Any, 0)

		' UdpClient.Receive blocks until a message is received from a remote host.
		Dim receiveBytes As [Byte]() = udpClient.Receive(RemoteIPEndPoint)
		Dim returnData As String = Encoding.ASCII.GetString(receiveBytes)

		' Save the returned data to a variable
		Dim Ret = returnData.ToString()
		' Rip the returned string for all kinds of interesting information
		' Convert the numplayers to a Integer - we will be using this 
		' value later when iterating the player list. Everything else
		' will be used as a string.
		Dim numplayers =  (CInt(GetParameter("numplayers", Ret)))
		Dim hostname = GetParameter("hostname",Ret)
		Dim hostport = GetParameter("hostport", Ret)
		Dim gamever = GetParameter("gamever", Ret)
		Dim maptitle = GetParameter("maptitle", Ret)
		Dim mapname = GetParameter("mapname", Ret)
		Dim gametype = GetParameter("gametype", Ret)
		Dim mutators = GetParameter("mutators", Ret)

		' If time limit is zero, there is no time limit.
		Dim timelimit = CStr(GetParameter("timelimit", Ret))
		If timelimit = "0" Then timelimit = "unlimited" else timelimit = timelimit & " min"

		' If frag limit is zero, there is no frag limit.
		Dim fraglimit = CStr(GetParameter("fraglimit", Ret))
		If fraglimit ="0" Then fraglimit = "unlimited"

		' Same goes for the number of maximum players.
		Dim maxplayers = CStr(GetParameter("maxplayers", Ret))
		if maxplayers="0" Then maxplayers = "unlimited"
		' Blend some HTML and variables we got.
		<table style="border-style: solid; border-width: 0"  cellpadding="3" width="99%" id="table1">	
			<td colspan="2" align="left" valign="top">
			<b>Server name: <% = hostname %></b><br>
			<span style="font-size: 8pt">
			game version <% = gamever %>, running on <% = RemoteHost %>, using port <% = hostport %>
			<td nowrap="nowrap" align="left" valign="top">Players:</td>
			<td align="left" valign="top"><% = numplayers %></td>
			<td nowrap="nowrap" align="left" valign="top">Current map:</td>
			<td align="left" valign="top"><% = maptitle %> (<% = mapname %>)</td>
			<td nowrap="nowrap" align="left" valign="top">Game mode:</td>
			<td align="left" valign="top"><% = gametype %> </td>
			<td nowrap="nowrap" align="left" valign="top">Mutators in use:</td>
			<td align="left" valign="top"><% =mutators %></td>
			<td nowrap="nowrap" align="left" valign="top">Game limits:</td>
			<td align="left" valign="top">Timelimit: <% = timelimit %> - Frag Limit: 
			<% = fraglimit %> - Max Players: <% = maxplayers%> </td>
			<td colspan="2" align="left" valign="top"><b>Players on server:</b></td>

		' Let's iterate the player list. Players and their individual values are appended with 
		' underscore and a player number - player_0, player_1, ping_0, frags_0 and so on.
		If numplayers > 0 Then
			Dim N ' The player name
			Dim PN, FN, PPN ' Player Number, Frags, Ping time
			Dim Alt = 0 ' Alternate row colors
			Dim Color ' Row color

			For N = 0 to numplayers -1 ' Zero based
				' Create strings for ripping the information from server response
				PN = "player_" & N
				FN = "frags_" & N
				PPN = "ping_" & N
				If Alt = 0 Then 
					Alt = 1
					Color = "#EEEEEEE"
					Alt = 0
					Color = "#CCCCCC"
				End If
					<td align="left" valign="top" bgcolor="<% = Color %>"><b>
					<% Response.Write (GetParameter(PN, Ret)) %>
					<td align="left" valign="top" bgcolor="<% = Color %>">
					<% Response.Write ("frags: " & GetParameter(FN, Ret) & ", 
					ping time: " & GetParameter(PPN,Ret)) %>
			<tr><td colspan = "2">No-one is currently logged on server.</td></tr>
		End If 
		<tr><td colspan ="2" align="right">
		<span style="font-size: 7pt">Last update at <% =Now %>

	Catch ex As Exception
		Response.Write ("<h2> The server is not available.</H2>")
	End Try

Catch ex0 as Exception
	Response.Write ("<h2> The UDP Connection component failed - local port is propably reserved.</h2>")
End Try
' Function for ripping values from server response. The values are returned in one string,
' separated by backslash. Basically we locate the position of the value name, and split 
' the rest of the string to an array by backslashes. The first index (0) will be empty, 
' the second index (1) will be the name we were looking for, and the third (2) the value 
' we wanted. Then we just forget the rest of the array. And of course we hope like hell 
' that there are no unwanted backslashes in any of the values we got. :)
<script runat="server" language="vb">

Public Function GetParameter (Param, RetString)
Dim X = Instr(RetString, "\" + Param + "\")
If X > 0 Then
 Dim Y = Split(Mid(RetString,X),"\")
 GetParameter = Y(2)
End If
End Function