User:Pizzahut/msqp.php: Difference between revisions

From Valve Developer Community
Jump to navigation Jump to search
(Adding more servers because the official one keeps timing out.)
(Added hint where to get the master server IPs.)
Line 27: Line 27:
*/
*/


$master_servers = array("hl1master.steampowered.com", "69.28.140.247", "69.28.158.131", "72.165.61.149");
// Check "Steam\config\MasterServer2.vdf" for the currently used master servers.
$master_servers = array("hl1master.steampowered.com", "69.28.140.247", "69.28.158.131",
"72.165.61.149");


define("TIMEOUT", 2.0);
define("TIMEOUT", 2.0);

Revision as of 17:41, 19 November 2011

This is a code example for querying a Half-Life master server using the PHP language.

<?php

/*

Version history

1     - Initial release.
2     - Added option to use the official domain name instead of IPs and retry if
        a timeout occurs.
2.1   - Added more master servers.
2.1.1 - Fixed a bug, program didn't terminate if all master servers time out.
2.1.2 - Removed a now redundant variable.
2.2   - Seeding for long server lists.
      - Removed the domain name because it's often better to try different
        servers.
2.2.1 - Bug fix: Timeout showed wrong master server IP.
      - Bug fix: Check whether the new seed starts with a duplicate or not.
      - Bug fix: Don't close socket twice.
2.3   - Retry queries on timeout if the first query was successful.
2.3.1 - Reading the whole address again if it starts with a zero.
      - Increased timeout to avoid a communication issue.
      - Removed maximum number of timeouts for testing.
2.4   - Again using hl1master.steampowered.com because IPs change often.
      - Endless retries because this server often times out.
*/

// Check "Steam\config\MasterServer2.vdf" for the currently used master servers.
$master_servers = array("hl1master.steampowered.com", "69.28.140.247", "69.28.158.131",
"72.165.61.149");

define("TIMEOUT", 2.0);
define("WORLD", "\xFF");
define("PORT", 27010);

function query_timeout(&$socket, $seed)
{
   echo "Sending query to master server.\n";
   stream_set_timeout($socket, TIMEOUT);
   $region = WORLD;
   if (!fwrite($socket, "1$region$seed\0\\gamedir\\tfc\0"))
   {
      fclose($socket);
      exit("fwrite error\n");
   }

   echo "Reading response header.\n";
   stream_set_timeout($socket, TIMEOUT);
   $s = bin2hex(fread($socket, 6));
   $info = stream_get_meta_data($socket);
   if ($info['timed_out'])
      echo "Master server timed out.\n";
   else
   {
      if ($s !== "ffffffff660a")
      {
         fclose($socket);
         exit("Expected ff ff ff ff 66 0a (hex) but got $s.");
      }
   }
   return $info['timed_out'];
}

// Connect to master server, return timeout info.
// The socket is passed as reference and thus returned as well.

function master_server_timeout(&$socket, $ip)
{
   echo "Connecting to master server \"$ip:".PORT."\".\n";
   $socket = fsockopen("udp://$ip", PORT, $errno, $errstr, TIMEOUT);
   if (!$socket)
      exit("Error $errno : $errstr \n");

   return query_timeout($socket, "0.0.0.0:0");
}

// Try all master servers until we find one that isn't timing out.

do {
   $abort = 1;
   foreach ($master_servers as $ip)
   {
      if (!master_server_timeout($socket, $ip))
      {
         $abort = 0;
         break;
      }
      else
         fclose($socket);
   }
} while ($abort == 1);

// Read list with server addresses (IP:port).

$count = 0;
$old_a1 = 0; $old_a2 = 0; $old_a3 = 0; $old_a4 = 0; $old_a5 = 0;
$max_timeouts = 6;
do
{
   stream_set_timeout($socket, TIMEOUT);
   $a1 = ord(fread($socket,1));
   $info = stream_get_meta_data($socket);
   if ($info['timed_out'])
   {
      $seed = "$old_a1.$old_a2.$old_a3.$old_a4:$old_a5";
      echo "Seed: $seed\n";
      while (query_timeout($socket, $seed));
      stream_set_timeout($socket, TIMEOUT);
      $a1 = ord(fread($socket,1));
      $info = stream_get_meta_data($socket);
      if ($info['timed_out'])
      {
         echo "Timeout occured.\n";
         break;
      }
      $check_for_duplicate = 1;
   }
   else
      $check_for_duplicate = 0;

   // Let's always read the rest of the address (even if it starts with 0) in
   // order to empty the master server's write buffer. This may avoid subsequent
   // problems, but I'm paranoid here.
   $a2 = ord(fread($socket,1));
   $a3 = ord(fread($socket,1));
   $a4 = ord(fread($socket,1));
   $a5 = ord(fread($socket,1))*256 + ord(fread($socket,1));

   if ($a1 != 0)
   {
      if (($check_for_duplicate==0)||($a1!=$old_a1)||($a2!=$old_a2)||
      ($a3!=$old_a3)||($a4!=$old_a4)||($a5!=$old_a5))
      {
         $count++;
         echo "$count $a1.$a2.$a3.$a4:$a5\n";
      }
      $old_a1 = $a1; $old_a2 = $a2; $old_a3 = $a3; $old_a4 = $a4; $old_a5 = $a5;
   }
} while ($a1 != 0);
fclose($socket);
echo "Retrieved $count server addresses.\n";

?>