View difference between Paste ID: 7CMNPBT2 and D2mjg9Nb
SHOW: | | - or go back to the newest paste.
1
<?php
2
3
/*
4
5
Version history
6
7
1     - Initial release.
8
2     - Added option to use the official domain name instead of IPs and retry if
9
        a timeout occurs.
10
2.1   - Added more master servers.
11
2.1.1 - Fixed a bug, program didn't terminate if all master servers time out.
12
2.1.2 - Removed a now redundant variable.
13
2.2   - Seeding for long server lists.
14
      - Removed the domain name because it's often better to try different
15
        servers.
16
2.2.1 - Bug fix: Timeout showed wrong master server IP.
17
      - Bug fix: Check whether the new seed starts with a duplicate or not.
18
      - Bug fix: Don't close socket twice.
19
2.3   - Retry queries on timeout if the first query was successful.
20
2.3.1 - Reading the whole address again if it starts with a zero.
21
      - Increased timeout to avoid a communication issue.
22
      - Removed maximum number of timeouts for testing.
23
2.4   - Again using hl1master.steampowered.com because IPs change often.
24
      - Endless retries because this server often times out.
25
2.5   - Trying following ports on timeout or if the response wasn't correct.
26
2.5.3 - Cosmetic changes (defines, variable name).
27
2.5.4 - Code optimisation.
28
2.6   - Repeat until list isn't empty.
29
*/
30
31
// Currently uses ports 27011-27013 and 27015.
32
$master_servers = array("hl2master.steampowered.com");
33
34
define("MIN_PORT", 27011); // Range of port numbers which the master servers
35
define("MAX_PORT", 27015); // potentially use.
36
define("FILTER", '\gamedir\tfc'); // game = Team Fortress Classic
37
define("REGION", "\xFF"); // region = world
38
define("TIMEOUT", 2.0); // 2s timeout
39
40
function query_timeout($socket, $seed)
41
{
42
   echo "Sending query to master server.\n";
43
   stream_set_timeout($socket, TIMEOUT);
44
   if (!fwrite($socket, "1".REGION."$seed\0".FILTER."\0"))
45
   {
46
      fclose($socket);
47
      exit("fwrite error\n");
48
   }
49
50
   echo "Reading response header.\n";
51
   stream_set_timeout($socket, TIMEOUT);
52
   $s = bin2hex(fread($socket, 6));
53
   $info = stream_get_meta_data($socket);
54
   if ($info['timed_out'])
55
      echo "Master server timed out.\n";
56
   else
57
   {
58
      if ($s !== "ffffffff660a")
59
      {
60
         fclose($socket);
61
         if ($s == "")
62
            echo "Expected ff ff ff ff 66 0a (hex) but got nothing.\n";
63
         else
64
            echo "Expected ff ff ff ff 66 0a (hex) but got $s.\n";
65
         return True;
66
      }
67
   }
68
   return $info['timed_out'];
69
}
70
71
// Connect to master server, return timeout info.
72
// The socket is passed as reference and thus returned as well.
73
74
function master_server_timeout(&$socket, $ip)
75
{
76
   $port = MIN_PORT;
77
   do {
78
      echo "Connecting to master server \"$ip:$port\".\n";
79
      $socket = fsockopen("udp://$ip", $port, $errno, $errstr, TIMEOUT);
80
      if (!$socket) exit("Error $errno : $errstr \n");
81
      $timeout = query_timeout($socket, "0.0.0.0:0");
82
      $port = $port + 1;
83
   } while ($timeout && ($port <= MAX_PORT));
84
   return $timeout;
85
}
86
87
// Read list with server addresses (IP:port).
88
89
function list_not_empty($socket)
90
	{
91
	$count = 0;
92
	$old_a1 = 0; $old_a2 = 0; $old_a3 = 0; $old_a4 = 0; $old_a5 = 0;
93
	$max_timeouts = 6;
94
	do
95
	{
96
	   stream_set_timeout($socket, TIMEOUT);
97
	   $a1 = ord(fread($socket,1));
98
	   $info = stream_get_meta_data($socket);
99
	   if ($info['timed_out'])
100
	   {
101
		  $seed = "$old_a1.$old_a2.$old_a3.$old_a4:$old_a5";
102
		  echo "Seed: $seed\n";
103
		  while (query_timeout($socket, $seed));
104
		  stream_set_timeout($socket, TIMEOUT);
105
		  $a1 = ord(fread($socket,1));
106
		  $info = stream_get_meta_data($socket);
107
		  if ($info['timed_out'])
108
		  {
109
			 echo "Timeout occured.\n";
110
			 break;
111
		  }
112
		  $check_for_duplicate = 1;
113
	   }
114
	   else
115
		  $check_for_duplicate = 0;
116
117
	   // Let's always read the rest of the address (even if it starts with 0) in
118
	   // order to empty the master server's write buffer. This may avoid subsequent
119
	   // problems, but I'm paranoid here.
120
	   $a2 = ord(fread($socket,1));
121
	   $a3 = ord(fread($socket,1));
122
	   $a4 = ord(fread($socket,1));
123
	   $a5 = ord(fread($socket,1))*256 + ord(fread($socket,1));
124
125
	   if ($a1 != 0)
126
	   {
127
		  if (($check_for_duplicate==0)||($a1!=$old_a1)||($a2!=$old_a2)||
128
		  ($a3!=$old_a3)||($a4!=$old_a4)||($a5!=$old_a5))
129
		  {
130
			 $count++;
131
			 echo "$count $a1.$a2.$a3.$a4:$a5\n";
132
		  }
133
		  $old_a1 = $a1; $old_a2 = $a2; $old_a3 = $a3; $old_a4 = $a4; $old_a5 = $a5;
134
	   }
135
	} while ($a1 != 0);
136
	fclose($socket);
137
138
	if ($count != 0) echo "Retrieved $count server addresses.\n";
139
	return ($count != 0);
140
}
141
142
// Try all master servers until we find one that isn't timing out.
143
144
foreach ($master_servers as $ip)
145
	if ($timeout=master_server_timeout($socket, $ip))
146
		fclose($socket);
147
	else
148
		if (list_not_empty($socket)) break;
149
150
?>
151