## ## Orginal code by: ## Luigi Auriemma ## ## ## LICENSE: ## This program is free software; you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation; either version 2 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this program; if not, write to the Free Software ## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ## ## http://www.gnu.org/licenses/gpl.txt ## ## NOTE: ## Please include our copyrights and a link to this source file ## to your website! Thank you. ################################################################################# class GameSpy { var $Host; var $Port; var $Sock; function GameSpy($Host = "master.gamespy.com", $Port = 28900) { /* --Constructor-- $Host: GameSpy-Master IP $Port: GameSpy-Master Port */ $this->Host = $Host; $this->Port = $Port; } function GetServers($Gamename, $Handoff, $Filter = "") { /* This function will return the Serverlist for $Gamename in an Array. $Gamename: (http://motd.gamespy.com/software/services/index.aspx) $Handoff: (http://motd.gamespy.com/software/services/index.aspx?mode=full&services=$Gamename) If the Handoff is >= 13 chars, it will be sized to an 6-char Handoff $Filter: The GS-Filter Example: Array ( [0] => Array ( [ip] => 69.44.61.202 [port] => 23000 ) [1] => Array ( [ip] => 195.140.135.250 [port] => 23000 ) ... ) */ // Try to connect to the GameSpy-Master: $this->Sock = @fsockopen("tcp://$this->Host", $this->Port, &$errno, &$errstr, 6); @stream_set_timeout($this->Sock, 6); if(!$this->Sock) { // Error while connecting return false; // :-( } else { $this->Connected = true; } // Receive the Secure-Key: $SecureKey = substr(fgets($this->Sock, 256), -7, 6); // Create the Validate-Key: $ValidateKey = $this->__MakeValidate($SecureKey, $Handoff); // Send the packet $Packet = "\\gamename\\$Gamename\\enctype\\0\\validate\\$ValidateKey\\final\\" . "\\queryid\\1.1\\list\\cmp\\gamename\\$Gamename\\where\\$Filter\\final\\"; fwrite($this->Sock, $Packet); // Receive the (compressed) Serverlist: $Data = ""; do { $Data .= fgets($this->Sock, 2048); $Buffer = socket_get_status($this->Sock); } while($Buffer["unread_bytes"] > 0); fclose($this->Sock); // Close socket return $this->__ParseCompressedIPs($Data); // Return the parsed Serverlist } function __ParseCompressedIPs($Data) { /* Parse the 6-Byte-IP packet and return the Serverlist-Array $Data: Compressed IPs received from the Server */ $UnComp = array(); $i = 0; $c = 0; // Remove the "\final\": $Data = str_replace("\\final\\", "", $Data); while($i <= strlen($Data) - 6) { // IP $UnComp[$c]["ip"] = ord($Data{$i++}).".".ord($Data{$i++}).".".ord($Data{$i++}).".".ord($Data{$i++}); // Port $UnComp[$c++]["port"] = (ord($Data{$i++}) * 256) + ord($Data{$i++}); } return $UnComp; } function __MakeValidate($SecureKey, $Handoff) { /* MakeValidate creates a Validate-Key for you :D $SecureKey: The Secure-Key received from the GS Master $Handoff: See GetServers() */ $Temp = array(0, 0, 0, 0, $Handoff); // Array for some temporary Variables $Table = array(); for($i = 0; $i <= 255; $i++) { $Table[$i] = $i; // Fill the buffer } // Check the Handoff-Length: if(strlen($Handoff) >= 13) { $Handoff = ""; // Invalid Handoff! -> Need 6-char Handoff for($i = 2; $i <= 13; $i += 2) { $Handoff .= $Temp[4]{$i}; } } // Add the length of the Keys to the array: $Length = array(strlen($Handoff), strlen($SecureKey)); for($i = 0; $i <= 255; $i++) { // Scramble the Table with the Handoff: $Temp[0] = ($Temp[0] + $Table[$i] + ord($Handoff{$i % $Length[0]})) & 255; $Temp[1] = $Table[$Temp[0]]; // Update the buffer: $Table[$Temp[0]] = $Table[$i]; $Table[$i] = $Temp[1]; } $Temp[0] = 0; $Key = array(); // Scramble the SecureKey with the Table: for($i = 0; $i < $Length[1]; $i++) { // Add the next char to the Array $Key[$i] = ord($SecureKey{$i}); $Temp[0] = ($Temp[0] + $Key[$i] + 1) & 255; $Temp[1] = $Table[$Temp[0]]; $Temp[2] = ($Temp[2] + $Temp[1]) & 255; $Temp[3] = $Table[$Temp[2]]; $Table[$Temp[2]] = $Temp[1]; $Table[$Temp[0]] = $Temp[3]; // XOR the Key with the Buffer: $Key[$i] ^= $Table[($Temp[1] + $Temp[3]) & 255]; } $Length[1] /= 3; $i = 0; $ValidateKey = ""; // Create the ValidateKey: while($Length[1]--) { $Temp[1] = $Key[$i++]; $Temp[3] = $Key[$i++]; $ValidateKey .= $this->__AddChar($Temp[1] >> 2); $ValidateKey .= $this->__AddChar((($Temp[1] & 3) << 4) | ($Temp[3] >> 4)); $Temp[1] = $Key[$i++]; $ValidateKey .= $this->__AddChar((($Temp[3] & 15) << 2) | ($Temp[1] >> 6)); $ValidateKey .= $this->__AddChar($Temp[1] & 63); } return $ValidateKey; } function __AddChar($Number) { // Return a new char if($Number < 26) { return chr($Number + 65); } elseif($Number < 52) { return chr($Number + 71); } elseif($Number < 62) { return chr($Number - 4); } elseif($Number == 62) { return "+"; } elseif($Number == 63) { return "/"; } } } ?>