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
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
|
package MasterServer::UDP::UDPTicker;
use strict;
use warnings;
use AnyEvent::Handle::UDP;
use Exporter 'import';
our @EXPORT = qw| udp_ticker |;
################################################################################
## When addresses are stored in the 'pending' list, they are supposed to be
## queried immediately with the secure/validate challenge to testify that
## the server is genuine and alive.
##
## Some servers do not support the secure-challenge on the Uplink port. These
## servers are verified with a secure-challenge on their heartbeat ports,
## which are designed to respond to secure queries, as well as status queries.
##
## Addresses collected by other scripts, whether from the UCC applet or manual
## input via the website, are added to the pending list. It is more
## important to verify pending beacons and new server addresses, than to
## update the status of existing addresses. Therefore, pending addresses are
## prioritized.
##
## Another function required for 333networks is the "server info" part of the
## site. UT servers are queried and stored in the database. This is the lowest
## priority for the masterserver and is therefore performed last.
##
################################################################################
sub udp_ticker {
my $self = shift;
# inform that we are running
$self->log("info", "UDP Ticker is loaded.");
# queue -- which address is next in line?
my %reset = (start => time, id => 0);
my %pending = (%reset, c => 0, limit => 900); # 900s ~ 15m
my %updater = (%reset, c => 0, limit => 1800); # 1800s ~ 30m
my %ut_serv = (%reset, c => 0, limit => 300); # 300s ~ 5m
my %oldserv = (%reset, c => 0, limit => 86400); # 86400s ~ 24h
my $debug_counter = 0;
# go through all servers that need querying
my $server_info = AnyEvent->timer (
after => 75, # first give beacons a chance to uplink
interval => 0.2, # 5 addresses per second is fast enough
cb => sub {
# after the first full run was completed, reset the counters when loop time expires
if (defined $self->{firstrun}) {
# reset timer
%reset = (start => time, id => 0, c => 0);
#
# it can happen that a run takes more than the allowed time
# in that case, allow more time
#
# pending
if (time - $pending{start} > $pending{limit}) {
if ($pending{c} > 0) {
# done within defined time, reset
%pending = (%pending, %reset);
}
}
# ut servers
if (time - $ut_serv{start} > $ut_serv{limit}) {
if ($ut_serv{c} > 0) {
# done within defined time, reset
%ut_serv = (%ut_serv, %reset)
}
}
# updater
if (time - $updater{start} > $updater{limit}) {
if ($updater{c} > 0) {
# done within defined time, reset
%updater = (%updater, %reset);
}
}
# old servers
if (time - $oldserv{start} > $oldserv{limit}) {
if ($oldserv{c} > 0) {
%oldserv = (%oldserv, %reset);
}
}
#
# else { print "Making overtime!" }
=pod
# FIXME remove this if above works
# debug: detect premature resets
if (time - $pending{start} > $pending{limit}) {
if ($pending{c} == 0) {
print "Premature pending reset\n" ;
}
else{$pending{c} = 0;}
}
if (time - $updater{start} > $updater{limit}) {
if ($updater{c} == 0) {
print "Premature updater reset\n" ;
}
else{$updater{c} = 0;}
}
if (time - $ut_serv{start} > $ut_serv{limit}) {
if ($ut_serv{c} == 0) {
print "Premature ut_serv reset\n" ;
}
else{$ut_serv{c} = 0;}
}
if (time - $oldserv{start} > $oldserv{limit}) {
if ($oldserv{c} == 0) {
print "Premature oldserv reset\n" ;
}
else{$oldserv{c} = 0;}
}
# are we making overtime on any of the counters yet?
%pending = (%pending, %reset) if (time - $pending{start} > $pending{limit});
%updater = (%updater, %reset) if (time - $updater{start} > $updater{limit});
%ut_serv = (%ut_serv, %reset) if (time - $ut_serv{start} > $ut_serv{limit});
%oldserv = (%oldserv, %reset) if (time - $oldserv{start} > $oldserv{limit});
=cut
}
#
# Check pending beacons
#
# pending beacons/servers (15 seconds grace time)
my $n = $self->get_pending(
next_id => $pending{id},
added => 15,
sort => "id",
limit => 1
)->[0] if $self->{beacon_checker_enabled};
# if next pending server/address exists:
if ( $n ) {
# next pending id will be > $n
$pending{id} = $n->{id};
# query the server using the heartbeat port provided in the beacon/manual add
$self->query_udp_server(
$n->{id},
$n->{ip},
$n->{heartbeat},
$n->{secure}, # secure string necessary!
1, # request secure challenge
);
# our work is done for this cycle.
return;
}
# pending are done and is allowed to reset at a later stadium
$pending{c}++;
#
# Query Unreal Tournament 99 (demo) servers for serverstats
#
# next server in line
$n = $self->get_server(
next_id => $ut_serv{id},
updated => 3600,
gamename => "ut",
sort => "id",
limit => 1,
)->[0] if $self->{utserver_query_enabled};
# if next server/address exists:
if ( $n ) {
#next pending id will be > $n
$ut_serv{id} = $n->{id};
# query the server (no secure string)
$self->query_udp_server(
$n->{id},
$n->{ip},
$n->{port},
"", # no secure string necessary
2, # request full status info
);
# our work is done for this cycle.
return;
}
# ut servers are done and is allowed to reset at a later stadium
$ut_serv{c}++;
#
# update existing servers (both ut/non-ut)
#
# next server in line
$n = $self->get_server(
next_id => $updater{id},
updated => 7200,
sort => "id",
limit => 1,
)->[0] if $self->{beacon_checker_enabled};
# if next server/address exists:
if ( $n ) {
#next pending id will be > $n
$updater{id} = $n->{id};
# query the server (no secure string)
$self->query_udp_server(
$n->{id},
$n->{ip},
$n->{port},
"", # no secure string necessary
0, # request info
);
# our work is done for this cycle.
return;
}
# updating servers is done and is allowed to reset at a later stadium
$updater{c}++;
#
# Query servers older than 2 hours
#
# next server in line
$n = $self->get_server(
next_id => $oldserv{id},
before => 7200,
sort => "id",
limit => 1,
)->[0] if $self->{beacon_checker_enabled};
# if next server/address exists:
if ( $n ) {
#next old server id will be > $n
$oldserv{id} = $n->{id};
# query the server (no secure string)
$self->query_udp_server(
$n->{id},
$n->{ip},
$n->{port},
"", # no secure string necessary
0, # request info
);
# our work is done for this cycle.
return;
}
# old servers are done and is allowed to reset at a later stadium
$oldserv{c}++;
# and notify about first run being completed
if (!defined $self->{firstrun}) {
# inform that first run is completed
my $t = time-$self->{firstruntime};
my $t_readable = ($t > 60) ? (($t/60). ":". ($t%60). "minutes") : ($t. "seconds");
$self->log("info", "First run completed after $t_readable.");
$self->{firstrun} = 0;
# reset all counters and follow procedure
%reset = (start => time, id => 0, c => 0);
%pending = (%pending, %reset);
%updater = (%updater, %reset);
%ut_serv = (%ut_serv, %reset);
%oldserv = (%oldserv, %reset);
}
# At this point, we are out of server entries. From here on, just count
# down until the cycle is complete and handle new entries while they are
# added to the list.
}
);
# return the timer object to keep it alive outside of this scope
return $server_info;
}
1;
|