Server Query In Perl
Querying game servers in Perl can be useful if you want to display a server's status on a web site. You can use the following Perl snippet to do it.
Implementation
Created by Mychaeel from scratch. Feel free to use, modify and enhance. Known limitations:
- This script expects the server's response to come as a single UDP datagram. If it doesn't, the sub's output will be truncated. A neater implementation would wait for and concatenate as many packets until the final one (marked by the string
\final\
at the end of it) has been received. - Some enhanced error checking wouldn't hurt.
Code
use Socket; use Sys::Hostname; ############################################################################### # # serverQuery $server, [$port] # # Queries an Unreal Tournament game server and returns a hash containing the # information returned by the server, or a hash just containing an error # description if the query failed. # sub serverQuery ($;$) { my $addressServerHost = shift; my $addressServerPort = shift; $addressServerPort = 7778 unless defined $addressServerPort; my $protocol = getprotobyname 'udp'; my $addressClient = sockaddr_in 0, scalar gethostbyname hostname; socket SERVER, PF_INET, SOCK_DGRAM, $protocol or return (error => 'Unable to create socket'); bind SERVER, $addressClient or return (error => 'Unable to bind address'); my $addressServer = sockaddr_in $addressServerPort, inet_aton $addressServerHost or return (error => 'Server not found'); send SERVER, '\\info\\', 0, $addressServer; my $handleRead = ''; vec($handleRead, fileno SERVER, 1) = 1; select $handleRead, undef, undef, 10.0 or return (error => 'Query timed out'); my $serverInfo; recv SERVER, $serverInfo, 0x1000, 0 or return (error => 'Error receiving information'); close SERVER; $serverInfo =~ s/\\//; $serverInfo =~ s/\\final\\$//; return split /\\/, $serverInfo; }
Usage
The sub serverQuery expects a server address and query port as its arguments and returns a hash containing the key/value pairs of the returned information. Call it as follows:
%serverInfo = serverQuery '66.92.238.12', 7788; print "Results of server query:\n\n"; print map "$_: $serverInfo{$_}\n", keys %serverInfo;
That'll give you output along the following lines:
Results of server query: gametype: CTFGame hostport: 7787 gamever: 436 mapname: CTF-XV8 hostname: [CSHP] Strangelove 2 MotherShip maxplayers: 16 minnetver: 400 wantworldlog: false numplayers: 1 maptitle: XV-8 worldlog: false gamemode: openplaying queryid: 30.1
Interpreting the individual items is up to you.
capt. k. – Dunno if/where you want to add this, but since it wasn't mentioned: you can also use the "\\status\\" query, which returns specifics of current server activity, including timelimit, scorelimit, goalteamscore, and the name/score/team of individual players present on the server. [example]
Mychaeel: Good point; but I guess I'll have to change the script to receive multiple packets (as said above) for a query with a potentially lengthy result like that. Will do, at some point.
El Muerte [TDS]: and you can also combine queries in one request: \basic\\rules\ (note that a request begins and ends with a slash). Also the last query request MUST be a known request or else you won't receive anything. So if you want to get all info from a server, and the server supports team information it wise to do: \teams\\echo\. this was you will always receive \echo\. if a server is online. Also an important thing to think of is NOT to check for the \final\ is the reply. \final\ is not always returned (there are constructions where \final\ won't be returned. The best way to read stuff from a UDP is by polling an asynchrone socket.