User:Pizzahut/msqp.php: Difference between revisions
Jump to navigation
Jump to search
m (Handling timeout of seeds (retrying).) |
m (Timeout turned out to be too short.) |
||
| Line 20: | Line 20: | ||
- Bug fix: Don't close socket twice. | - Bug fix: Don't close socket twice. | ||
2.3 - Retry queries on timeout if the first query was successful. | 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. | |||
*/ | */ | ||
$master_servers = array("68.142.72.250", "69.28.151.162", "72.165.61.190", | $master_servers = array("68.142.72.250", "69.28.151.162", "72.165.61.190", | ||
"72.165.61.189"); | "72.165.61.189"); | ||
define("TIMEOUT", 2.0); | |||
define("WORLD", "\xFF"); | |||
define("PORT", 27010); | |||
function query_timeout(&$socket, $seed) | function query_timeout(&$socket, $seed) | ||
{ | { | ||
echo "Sending query to master server.\n"; | echo "Sending query to master server.\n"; | ||
stream_set_timeout($socket, | stream_set_timeout($socket, TIMEOUT); | ||
if (!fwrite($socket, "1 | $region = WORLD; | ||
if (!fwrite($socket, "1$region$seed\0\\gamedir\\cstrike\0")) | |||
{ | { | ||
fclose($socket); | fclose($socket); | ||
| Line 36: | Line 43: | ||
} | } | ||
echo "Reading response header | echo "Reading response header.\n"; | ||
stream_set_timeout($socket, | stream_set_timeout($socket, TIMEOUT); | ||
$s = bin2hex(fread($socket, 6)); | $s = bin2hex(fread($socket, 6)); | ||
$info = stream_get_meta_data($socket); | $info = stream_get_meta_data($socket); | ||
| Line 58: | Line 65: | ||
function master_server_timeout(&$socket, $ip) | function master_server_timeout(&$socket, $ip) | ||
{ | { | ||
echo "Connecting to master server \"$ip\".\n"; | echo "Connecting to master server \"$ip:".PORT."\".\n"; | ||
$socket = fsockopen("udp://$ip", | $socket = fsockopen("udp://$ip", PORT, $errno, $errstr, TIMEOUT); | ||
if (!$socket) | if (!$socket) | ||
exit("Error $errno : $errstr \n"); | exit("Error $errno : $errstr \n"); | ||
| Line 89: | Line 96: | ||
do | do | ||
{ | { | ||
stream_set_timeout($socket, | stream_set_timeout($socket, TIMEOUT); | ||
$a1 = ord(fread($socket,1)); | $a1 = ord(fread($socket,1)); | ||
$info = stream_get_meta_data($socket); | $info = stream_get_meta_data($socket); | ||
if ($info['timed_out']) | 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); | |||
stream_set_timeout($socket, | |||
$a1 = ord(fread($socket,1)); | $a1 = ord(fread($socket,1)); | ||
$info = stream_get_meta_data($socket); | $info = stream_get_meta_data($socket); | ||
| Line 116: | Line 116: | ||
else | else | ||
$check_for_duplicate = 0; | $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 ($a1 != 0) | ||
{ | { | ||
if (($check_for_duplicate==0)||($a1!=$old_a1)||($a2!=$old_a2)|| | if (($check_for_duplicate==0)||($a1!=$old_a1)||($a2!=$old_a2)|| | ||
($a3!=$old_a3)||($a4!=$old_a4)||($a5!=$old_a5)) | ($a3!=$old_a3)||($a4!=$old_a4)||($a5!=$old_a5)) | ||
Revision as of 19:22, 11 December 2010
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.
*/
$master_servers = array("68.142.72.250", "69.28.151.162", "72.165.61.190",
"72.165.61.189");
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\\cstrike\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 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;
}
else
fclose($socket);
}
if ($abort == 1)
exit("All master servers timed out, aborting.\n");
// 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";
?>