User:Pizzahut/msqp.php

From Valve Developer Community
< User:Pizzahut
Revision as of 09:33, 10 December 2010 by Pizzahut (talk | contribs) (This seems to be fixed on Valve's end - getting 130 to 150 servers now.)
Jump to navigation Jump to search

This is a code example for querying a Half-Life master server using the PHP language. For querying more than 231 servers it needs to be extended. The purpose of this program is to get a list of TFC servers, there are only about 150 left at the time of writing so it doesn't check for more.

<?php

/*    Version history

1     Initial release.
2     Added option to retry same server if timeout occurs.
      (This is just a minor update, I should have released it as v1.1.)
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.
*/

// Method 1: Try a different server if one is timing out.
// Method 2: Retry the same server if a timeout occurs.
$method = 1;

$servers = array(
"72.165.61.136:27010",
"68.142.72.250:27010",
"72.165.61.189:27010",
"72.165.61.190:27010",
"69.28.151.162:27010");

$server = "hl1master.steampowered.com";

function master_server_timeout(&$fp, $ip)
{
   $port = 27010;
   $timeout = 1;

   echo "Connecting to master server \"$ip\".\n";

   $fp = fsockopen("udp://$ip", $port, $errno, $errstr, $timeout);
   if (!$fp) exit("Error $errno : $errstr");
   stream_set_timeout($fp, $timeout);

   // region=world, filter: game=Team Fortress Classic
   if (!fwrite($fp, "1\xFF0.0.0.0:0\0\\gamedir\\tfc\0"))
   {
      fclose($fp);
      exit("fwrite error\n");
   }

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

if ($method == 1)
{
   $abort = 1;
   foreach ($servers as $server_address)
   {
      if (!master_server_timeout($fp, $server_address))
      {
         $abort = 0;
         break;
      }
   }
   if ($abort == 1)
      exit("All servers timed out, aborting.\n");
}

if ($method == 2)
{
   for ($i = 1; $i <= 10; $i++)
   {
      if (!master_server_timeout($fp, $server))
         break;
      if ($i == 10)
         exit("Giving up after 10 tries.\n");
      else
         echo "Retrying ($i).\n";
   }
}

$count = 0;
do {
   $a1 = ord(fread($fp,1));
   $info = stream_get_meta_data($fp);
   if ($info['timed_out']) {
      echo "Time out occured.\n";
      break;
   }

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

   if ($a1 != 0) {
      $count++;
      echo "$count $a1.$a2.$a3.$a4:$a5\n";
   }
} while ($a1 != 0);
echo "Retrieved $count servers.\n";

fclose($fp);
?>