File: metaserver.pl.in

package info (click to toggle)
crossfire 1.71.0%2Bdfsg1-2
  • links: PTS
  • area: main
  • in suites: buster
  • size: 28,076 kB
  • sloc: ansic: 85,126; sh: 11,978; perl: 2,659; lex: 2,044; makefile: 1,271
file content (170 lines) | stat: -rwxr-xr-x 5,496 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
#!/usr/bin/perl
# $Id$

# Copyright 2000 by Mark Wedel.
# This script follows the same license as crossfire (GPL).

use Socket;
use English;

# We periodically generate a nice HTML file that people can't put their
# web browser at.  This is the location of that file.
$HTML_FILE="/var/apache/htdocs/metaserver.html";

# Cache file to keep data we ahve collected.  This is used so that if
# the metaserver program crashes/dies, it still has some old data.
# You may want to set this to a location that will survive across system
# reboots.
$CACHE_FILE="/var/tmp/meta_xfire.cache";

# We remove a server after $REMOVE_SERVER number of seconds of no updates.
# 600 is 10 minutes - if we haven't gotten an update that fast, the server
# is almost certainly gone/not available.  This reduces congestion when
# someone on a dhcp connection keeps running a server and it fills
# up a bunch of the slots.
$REMOVE_SERVER=600;

# UPDATE_SYNC determines how often we update the HTML_FILE and CACHE_FILE.
$UPDATE_SYNC=300;

# IP_INTERVAL is how often (in seconds) same IP can request metaserver
# info.  This is to prevent DOS attacks.

$IP_INTERVAL=5;

# For gathering some anonymous statistics. You probably want to use
# MRTG/RRDTOOL for generating statistics from the file.
# -- Heikki Hokkanen, 2005-03-26
my $STATS_FILE="/var/tmp/meta_xfire.stats";
my $stats_updatehits = 0; # COUNTER
my $stats_requesthits = 0; # COUNTER
my $stats_totalplayers = 0; # GAUGE
my $stats_totalservers = 0; # GAUGE

socket(SOCKET, PF_INET, SOCK_DGRAM, getprotobyname("udp")) ||
	die("$0: can not open udp socket: $OS_ERROR\n");
bind(SOCKET, sockaddr_in(13326, INADDR_ANY)) ||
	die("$0: Can not bind to socket: $OS_ERROR\n");

# Socket1 is used for incoming requests - if we get a connection on this,
# we dump out our data to that socket in an easily parsible form.
socket(SOCKET1, PF_INET, SOCK_STREAM, getprotobyname("tcp")) ||
	die("$0: can not open tcp socket: $OS_ERROR\n");

# errors on this not that critical
setsockopt(SOCKET1, SOL_SOCKET, SO_REUSEADDR, 1);

bind(SOCKET1, sockaddr_in(13326, INADDR_ANY)) ||
	die("$0: Can not bind to socket: $OS_ERROR\n");
listen(SOCKET1, 10) ||
	die("$0: Can not listen on socket: $OS_ERROR\n");

vec($rin, fileno(SOCKET), 1)=1;
vec($rin, fileno(SOCKET1), 1)=1;

if (open(CACHE,"<$CACHE_FILE")) {
    while (<CACHE>) {
	chomp;
	($ip, $rest) = split /\|/, $_, 2;
	$data{$ip} = $_;
    }
}
close(CACHE);

$last_sync=time;

while (1) {
    $nfound=select($rout=$rin, undef, undef, 60);
    $cur_time=time;
    if ($nfound) {
	if (vec($rout, fileno(SOCKET),1)) {
	    $ipaddr = recv(SOCKET, $data, 256, 0) ||
		print STDERR "$0: error on recv call: $OS_ERROR\n";
	    ($port, $ip) = sockaddr_in($ipaddr);
	    $host = inet_ntoa $ip;
	    ($name, $rest) = split /\|/, $data;
	    if ($name ne "put.your.hostname.here") {
		$data{$host} = "$host|$cur_time|$data";
		$stats_updatehits++;
	    }
	}
	if (vec($rout, fileno(SOCKET1),1)) {
	    # This is overly basic - if there are enough servers
	    # where the output won't fit in the outgoing socket,
	    # this will block.  However, if we fork, we open
	    # ourselves up to someone intentionally designing something
	    # that causes these to block, and then have us fork a huge
	    # number of process potentially filling up our proc table.
	    if ($ipaddr=accept NEWSOCKET, SOCKET1) {
		($port, $ip ) = sockaddr_in( $ipaddr );
		$dq = join('.',unpack('C4', $ip));
		if ($ip_times{$dq} > time) {
		    close(NEWSOCKET);
 		} else {
		    $ip_times{$dq} = time + $IP_INTERVAL;
		    foreach $i (keys %data) {
		        # Report idle time to client, and not last update
		    	# as we received in seconds since epoch.
			($ip, $time, $rest) = split /\|/, $data{$i}, 3;
		    	$newtime = $cur_time - $time;
		    	print NEWSOCKET "$ip|$newtime|$rest\n";
		    }
		    close(NEWSOCKET);
		    $stats_requesthits++;
		}
	    }
	}
    }

    # Need to generate some files.  This is also where we remove outdated
    # hosts.
    if ($last_sync+$UPDATE_SYNC < $cur_time) {
	$last_sync = $cur_time;
	open(CACHE,">$CACHE_FILE");
	open(HTML,">$HTML_FILE");

	print HTML
'<title>Crossfire Server List</title>
<h1 align=center>Crossfire Server List</h1><p>
<table border=1 align=center cellpadding=5>
<tr>
<th>IP Address</th><th>Last Update Date/Time</th><th>Last Update Minutes Elapsed</th>
<th>Hostname</th><th>Number of Players</th><th>Version</th><th>Comment</th>
</tr>
';

	$stats_totalplayers = 0;
	$stats_totalservers = 0;
	foreach $i (keys %data) {
		$stats_totalservers++;
	    ($ip, $time, @rest) = split /\|/, $data{$i};
	    if ($time+$REMOVE_SERVER<$cur_time) {
		delete $data{$i};
	    } else {
		print CACHE "$data{$i}\n";
		$elapsed = int(($cur_time - $time)/60);
		$gmtime = gmtime($time);
		print HTML "<tr><td>$i</td><td>$gmtime</td><td>$elapsed</td>";
		print HTML "<td>$rest[0]</td><td>$rest[1]</td><td>$rest[2]</td><td>$rest[3]</td></tr>\n";
		$stats_totalplayers += int($rest[2]);
	    }
	}
	$gmtime = gmtime($cur_time);
	print HTML "
</table><p>
The server name is reported by the server, while the ip address is determined by
the incoming data packet.  These values may not resolve to the same thing in the
case of multi homed hosts or multi ip hosts.<p>

All times are in GMT.<p>

<font size=-2>Last Updated: $gmtime<font size=+2><p>";
	close(HTML);
	close(CACHE);

	open(STATS,">$STATS_FILE");
	print STATS "$stats_updatehits:$stats_requesthits:$stats_totalservers:$stats_totalplayers\n";
	close(STATS);

    }
}