#!/usr/bin/perl -w ## $Id: eqstat,v 2.4 2001/09/03 07:09:48 baldio Exp $ ## eqstat --- display EverQuest server status ## by Baldio Holyfield , Level 70 Cleric on Veeshan ## usage: eqstat [server1, server2, ...] ## example1: eqstat Veeshan ## example2: eqstat vee ayona fenn que xev drinal require 5.003; use strict; use sigtrap; use IO::Socket; use constant MAXBYTES => scalar 4096; use FileHandle; my ($querydata, $namedata, $statusdata, $bannerdata); ## binary data to/from status server my ($banner, $servercnt, @server_name, $players, $zones); ## retrieve from data reply my ($cgi_mode, $socket, $buf1, $buf2, $i, $total, $pattern); ## internal use my ($xml_mode, $scantime); ## for xml_mode ## display EverQuest Server Protocol ## while () { print; } exit 0; ## You probably need to modify HTML format sample (see bottom) --- this is a very simple case! $cgi_mode = 1 if ($ENV{'GATEWAY_INTERFACE'}); ## default variables $i = 0; $total = 0; $pattern = join("\|", @ARGV); ## xml_mode $xml_mode = 0; $scantime = localtime(time); ## ----- main start ----- ## create socket -> send and receive data -> close socket &create_socket; &request_server_names; &request_server_status; &request_banner_data; &close_socket; ## retrieve data &retrieve_servers; &retrieve_server_name; &retrieve_banner; ## display data if ($cgi_mode) { STDOUT->autoflush(1); STDOUT->format_top_name("HTML_TOP"); STDOUT->format_name("HTML"); print "Content-Type: text/html; charset=iso-8859-1\r\n\r\n"; } if ($xml_mode) { STDOUT->format_top_name("XML_TOP"); STDOUT->format_name("XML"); STDOUT->format_lines_per_page("4096"); } if ($namedata && $statusdata) { &print_chat_server_status; &print_server_status; STDOUT->format_name("STDOUT_FOOT"); STDOUT->format_name("HTML_FOOT") if ($cgi_mode); STDOUT->format_name("XML_FOOT") if ($xml_mode); write; } else { die "Could not retrieve status: $!\n"; } ## ----- main end ----- sub create_socket { ## create UDP socket to status.everquest.com:24252 (default) $socket = IO::Socket::INET->new(PeerAddr => "status.everquest.com", PeerPort => 24252, Type => SOCK_DGRAM, Proto => "udp"); die "Could not create socket: $!\n" unless ($socket); } sub request_server_names { $querydata = pack("N", 0xffff0100); until ($namedata) { $socket->send($querydata) || die "Client send(names): $!\n"; eval { local $SIG{ALRM} = sub { die "No response from server(names)\n" }; alarm 2; $socket->recv($namedata, MAXBYTES); alarm 0; }; } } sub request_server_status { $querydata = pack("N", 0xffff0500); until ($statusdata) { $socket->send($querydata) || die "Client send(status): $!\n"; eval { local $SIG{ALRM} = sub { die "No response from server(status)\n" }; alarm 2; $socket->recv($statusdata, MAXBYTES); alarm 0; }; } } sub request_banner_data { $querydata = pack("N", 0xffff0900); until ($bannerdata) { $socket->send($querydata) || die "Client send(banner): $!\n"; eval { local $SIG{ALRM} = sub { die "No response from server(banner)\n" }; alarm 2; $socket->recv($bannerdata, MAXBYTES); alarm 0; }; } } sub close_socket { $socket->close(); } sub retrieve_servers { ## retrieve how many servers exist $servercnt = ord(substr($statusdata, 7, 1)) if ($statusdata); } sub retrieve_server_name { ## retrieve server name list -> set them into array @server_name @server_name = split(pack("x"), substr($namedata, 6)) if ($namedata); } sub retrieve_banner { ## retrieve banner message on chat server $banner = substr($bannerdata, 4) if ($bannerdata); chop $banner; } sub print_chat_server_status { $buf1 = ord(substr($statusdata, 5, 1)) * 256; $buf2 = ord(substr($statusdata, 6, 1)); $zones = "N/A"; $players = $buf1 + $buf2; if ($players != 1) { $players = "DOWN"; } else { $total++; $players = "UP"; } write; } sub print_server_status { for ($i = 1; $i <= $servercnt; $i++) { $buf1 = ord(substr($statusdata, $i * 4 + 4, 1)) * 256; $buf2 = ord(substr($statusdata, $i * 4 + 5, 1)); $zones = ord(substr($statusdata, $i * 4 + 7, 1)); $players = $buf1 + $buf2; if ($players != 1) { $players = "DOWN"; } else { $total++; $players = "UP"; } if ($#ARGV < 0) { write; } else { write if ($server_name[$i] =~ /$pattern/io); } } } format STDOUT_TOP = Server Name Status Zones ------------------ ---- --- . format STDOUT = @<<<<<<<<<<<<<<<<< @>>> @>> $server_name[$i], $players, $zones . format STDOUT_FOOT = ------------------------------- @< Servers UP on EverQuest $total @* $banner . #################################### # XML format sample (for xml_mode) # #################################### format XML_TOP = $scantime . format XML = @<<<<<<<<<<<<<<<<< $server_name[$i] @>>> $players @>> $zones . format XML_FOOT = @< $total @* $banner . ##################################### # HTML format sample (for cgi_mode) # ##################################### format HTML_TOP = EverQuest Server Status . format HTML = $server_name[$i], $players, $zones . format HTML_FOOT =
Server NameStatusZones
@<<<<<<<<<<<<<<<<< @>>> @>>
@< Servers UP on EverQuest: $total @* $banner
. __END__ EverQuest STATUS SERVER: Host : status.everquest.com Port : 24252 Protocol : UDP COMMANDS: Request Server Names : 0xFFFF0100 : Request a list of all server names Request Status Data : 0xFFFF0500 : Request player zone status information for all servers Request Chat Banner : 0xFFFF0900 : Request the banner set in the Chat Server REPLIES: Request Server Names Reply: BYTE 1 to BYTE 4 : Command Code (0xFFFF0100) BYTE 5 : Total number of server names BYTE 6 : Total number of zones in each server BYTE 7+ : Name Data Stream The rest of the data is each name of each server separated by a null (0x00) character The number of names returned is equal to the total number of server names count provided in BYTE 5 Request Status Data Reply: BYTE 1 to BYTE 4 : Command Code (0xFFFF0500) BYTE 5 : Total Number of Chat Servers (currently 1) BYTE 6 to BYTE 7 : Server Status of Chat Server (-1 = DOWN and 1 = UP) BYTE 8 : Total Number of World Servers BYTE 9+ : World Server Data (Size = 4 Bytes * Total Number of World Servers) (World Server Data Block) BYTE 1 to BYTE 2 : Status of World Server (-1 = DOWN and 1 = UP) BYTE 3 : Total number of zones in this world (currently 101) BYTE 4 : Total number of zones currently up Request Chat Banner: BYTE 1 to BYTE 4 : Command Code (0xFFFF0900) BYTE 5+ : The banner string, null terminated