ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/utils/metaserver.pl.in
Revision: 1.1.1.1 (vendor branch)
Committed: Fri Feb 3 07:14:50 2006 UTC (18 years, 3 months ago) by root
Branch: UPSTREAM, MAIN
CVS Tags: LAST_C_VERSION, rel-2_82, rel-2_81, rel-2_80, UPSTREAM_2006_03_15, rel-3_1, rel-3_0, rel-2_6, rel-2_7, rel-2_4, rel-2_5, rel-2_2, rel-2_3, rel-2_0, rel-2_1, rel-2_72, rel-2_73, rel-2_71, rel-2_76, rel-2_77, rel-2_74, rel-2_75, rel-2_54, rel-2_55, rel-2_56, rel-2_79, rel-2_52, rel-2_53, rel-2_32, UPSTREAM_2006_02_22, rel-2_90, rel-2_92, rel-2_93, rel-2_78, rel-2_61, UPSTREAM_2006_02_03, difficulty_fix_merge_060810_2300, rel-2_43, rel-2_42, rel-2_41, HEAD
Branch point for: difficulty_fix
Changes since 1.1: +0 -0 lines
Log Message:
initial import

File Contents

# Content
1 #!/usr/bin/perl
2 # $Id: metaserver.pl.in,v 1.3 2005/07/08 23:48:59 mwedel Exp $
3
4 # Copyright 2000 by Mark Wedel.
5 # This script follows the same license as crossfire (GPL).
6
7 use Socket;
8 use English;
9
10 # We periodically generate a nice HTML file that people can't put their
11 # web browser at. This is the location of that file.
12 $HTML_FILE="/var/apache/htdocs/metaserver.html";
13
14 # Cache file to keep data we ahve collected. This is used so that if
15 # the metaserver program crashes/dies, it still has some old data.
16 # You may want to set this to a location that will survive across system
17 # reboots.
18 $CACHE_FILE="/var/tmp/meta_xfire.cache";
19
20 # We remove a server after $REMOVE_SERVER number of seconds of no updates.
21 # 600 is 10 minutes - if we haven't gotten an update that fast, the server
22 # is almost certainly gone/not available. This reduces congestion when
23 # someone on a dhcp connection keeps running a server and it fills
24 # up a bunch of the slots.
25 $REMOVE_SERVER=600;
26
27 # UPDATE_SYNC determines how often we update the HTML_FILE and CACHE_FILE.
28 $UPDATE_SYNC=300;
29
30 # IP_INTERVAL is how often (in seconds) same IP can request metaserver
31 # info. This is to prevent DOS attacks.
32
33 $IP_INTERVAL=5;
34
35 # For gathering some anonymous statistics. You probably want to use
36 # MRTG/RRDTOOL for generating statistics from the file.
37 # -- Heikki Hokkanen, 2005-03-26
38 my $STATS_FILE="/var/tmp/meta_xfire.stats";
39 my $stats_updatehits = 0; # COUNTER
40 my $stats_requesthits = 0; # COUNTER
41 my $stats_totalplayers = 0; # GAUGE
42 my $stats_totalservers = 0; # GAUGE
43
44 socket(SOCKET, PF_INET, SOCK_DGRAM, getprotobyname("udp")) ||
45 die("$0: can not open udp socket: $OS_ERROR\n");
46 bind(SOCKET, sockaddr_in(13326, INADDR_ANY)) ||
47 die("$0: Can not bind to socket: $OS_ERROR\n");
48
49 # Socket1 is used for incoming requests - if we get a connection on this,
50 # we dump out our data to that socket in an easily parsible form.
51 socket(SOCKET1, PF_INET, SOCK_STREAM, getprotobyname("tcp")) ||
52 die("$0: can not open tcp socket: $OS_ERROR\n");
53
54 # errors on this not that critical
55 setsockopt(SOCKET1, SOL_SOCKET, SO_REUSEADDR, 1);
56
57 bind(SOCKET1, sockaddr_in(13326, INADDR_ANY)) ||
58 die("$0: Can not bind to socket: $OS_ERROR\n");
59 listen(SOCKET1, 10) ||
60 die("$0: Can not listen on socket: $OS_ERROR\n");
61
62 vec($rin, fileno(SOCKET), 1)=1;
63 vec($rin, fileno(SOCKET1), 1)=1;
64
65 if (open(CACHE,"<$CACHE_FILE")) {
66 while (<CACHE>) {
67 chomp;
68 ($ip, $rest) = split /\|/, $_, 2;
69 $data{$ip} = $_;
70 }
71 }
72 close(CACHE);
73
74 $last_sync=time;
75
76 while (1) {
77 $nfound=select($rout=$rin, undef, undef, 60);
78 $cur_time=time;
79 if ($nfound) {
80 if (vec($rout, fileno(SOCKET),1)) {
81 $ipaddr = recv(SOCKET, $data, 256, 0) ||
82 print STDERR "$0: error on recv call: $OS_ERROR\n";
83 ($port, $ip) = sockaddr_in($ipaddr);
84 $host = inet_ntoa $ip;
85 ($name, $rest) = split /\|/, $data;
86 if ($name ne "put.your.hostname.here") {
87 $data{$host} = "$host|$cur_time|$data";
88 $stats_updatehits++;
89 }
90 }
91 if (vec($rout, fileno(SOCKET1),1)) {
92 # This is overly basic - if there are enough servers
93 # where the output won't fit in the outgoing socket,
94 # this will block. However, if we fork, we open
95 # ourselves up to someone intentionally designing something
96 # that causes these to block, and then have us fork a huge
97 # number of process potentially filling up our proc table.
98 if ($ipaddr=accept NEWSOCKET, SOCKET1) {
99 ($port, $ip ) = sockaddr_in( $ipaddr );
100 $dq = join('.',unpack('C4', $ip));
101 if ($ip_times{$dq} > time) {
102 close(NEWSOCKET);
103 } else {
104 $ip_times{$dq} = time + $IP_INTERVAL;
105 foreach $i (keys %data) {
106 # Report idle time to client, and not last update
107 # as we received in seconds since epoch.
108 ($ip, $time, $rest) = split /\|/, $data{$i}, 3;
109 $newtime = $cur_time - $time;
110 print NEWSOCKET "$ip|$newtime|$rest\n";
111 }
112 close(NEWSOCKET);
113 $stats_requesthits++;
114 }
115 }
116 }
117 }
118
119 # Need to generate some files. This is also where we remove outdated
120 # hosts.
121 if ($last_sync+$UPDATE_SYNC < $cur_time) {
122 $last_sync = $cur_time;
123 open(CACHE,">$CACHE_FILE");
124 open(HTML,">$HTML_FILE");
125
126 print HTML
127 '<title>Crossfire Server List</title>
128 <h1 align=center>Crossfire Server List</h1><p>
129 <table border=1 align=center cellpadding=5>
130 <tr>
131 <th>IP Address</th><th>Last Update Date/Time</th><th>Last Update Minutes Elapsed</th>
132 <th>Hostname</th><th>Number of Players</th><th>Version</th><th>Comment</th>
133 </tr>
134 ';
135
136 $stats_totalplayers = 0;
137 $stats_totalservers = 0;
138 foreach $i (keys %data) {
139 $stats_totalservers++;
140 ($ip, $time, @rest) = split /\|/, $data{$i};
141 if ($time+$REMOVE_SERVER<$cur_time) {
142 delete $data{$i};
143 } else {
144 print CACHE "$data{$i}\n";
145 $elapsed = int(($cur_time - $time)/60);
146 $gmtime = gmtime($time);
147 print HTML "<tr><td>$i</td><td>$gmtime</td><td>$elapsed</td>";
148 print HTML "<td>$rest[0]</td><td>$rest[1]</td><td>$rest[2]</td><td>$rest[3]</td></tr>\n";
149 $stats_totalplayers += int($rest[2]);
150 }
151 }
152 $gmtime = gmtime($cur_time);
153 print HTML "
154 </table><p>
155 The server name is reported by the server, while the ip address is determined by
156 the incoming data packet. These values may not resolve to the same thing in the
157 case of multi homed hosts or multi ip hosts.<p>
158
159 All times are in GMT.<p>
160
161 <font size=-2>Last Updated: $gmtime<font size=+2><p>";
162 close(HTML);
163 close(CACHE);
164
165 open(STATS,">$STATS_FILE");
166 print STATS "$stats_updatehits:$stats_requesthits:$stats_totalservers:$stats_totalplayers\n";
167 close(STATS);
168
169 }
170 }