User:Pizzahut/msqp.php

From Valve Developer Community
< User:Pizzahut
Revision as of 11:29, 11 December 2010 by Pizzahut (talk | contribs) (Added seeding for long server lists (more than 231 servers).)
Jump to navigation Jump to search

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 retry same server if 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.

*/

$master_servers = array("72.165.61.136", "68.142.72.250", "72.165.61.189",
"72.165.61.190", "69.28.151.162");

function query_timeout(&$socket, $seed)
{
   // region=world, filter: game=Half-Life
   if (!fwrite($socket, "1\xFF$seed\0\\gamedir\\valve\0"))
   {
      fclose($socket);
      exit("fwrite error\n");
   }

   $s = bin2hex(fread($socket, 6));
   $info = stream_get_meta_data($socket);
   if ($info['timed_out'])
   {
      echo "Master server \"$seed\" timed out.\n";
      fclose($socket);
   }
   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)
{
   $port = 27010;
   $timeout = 1;

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

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

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

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

$abort = 1;
foreach ($master_servers as $ip)
{
   if (!master_server_timeout($socket, $ip))
   {
      $abort = 0;
      break;
   }
}
if ($abort == 1)
   exit("All master servers timed out, aborting.\n");

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

$count = 0;
do
{
   $new_a1 = ord(fread($socket,1));
   $info = stream_get_meta_data($socket);
   if ($info['timed_out'])
   {
      if (query_timeout($socket, "$a1.$a2.$a3.$a4:$a5"))
         break;
      $a1 = ord(fread($socket,1));
      $info = stream_get_meta_data($socket);
      if ($info['timed_out'])
      {
         echo "Timeout occured.\n";
         break;
      }
      echo "New seed, decreasing count.\n";
      $count--;
   }
   else
      $a1 = $new_a1;

   if ($a1 != 0)
   {
      $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));
      $count++;
      echo "$count $a1.$a2.$a3.$a4:$a5\n";
   }
} while ($a1 != 0);
fclose($socket);
echo "Retrieved $count server addresses.\n";

?>