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
|
package MasterServer::UDP::UDPTicker;
use strict;
use warnings;
use AnyEvent::Handle::UDP;
use Exporter 'import';
our @EXPORT = qw| udp_ticker |;
################################################################################
## When addresses are provided from secondary sources (master applets,
## synchronization or manual addition, they are queried by this udp_ticker.
## When they validate (which also implies correct router settings) they are
## added to the masterserver list.
##
## Some servers do not support the secure-challenge or do not respond to
## queries directly. By retrieving the server information we are able to
## make exceptions on a case to case basis.
##
## Other than previous MS-Perl versions, unresponsive servers are no longer
## checked. When servers become fail to report in after 2 hours, they remain
## are considered offline and will remain archived. This server can become
## active again by uplinking to one of the affiliated masterservers.
################################################################################
sub udp_ticker {
my $self = shift;
# queue: start time, server id, counter, time limit
my %p = (start => time, id => 0, c => 0, limit => 900); # pending: 15m
my %u = (start => time, id => 0, c => 0, limit => 300); # updater: 5m
# tick through pending list and server list
my $server_info = AnyEvent->timer (
after => 120, # grace time receiving beacons -- MUST be the last
# function to start as it controls the first_run parameter
interval => 0.2, # ~5 servers/second
cb => sub {
# reset counters if minimum time before reset passed + list processed
if ($self->{firstrun}) {
if ($p{c} && time - $p{start} > $p{limit}) { # pending reset
%p = (%p, start => time, id => 0, c => 0); }
if ($u{c} && time - $u{start} > $u{limit}) { # updater reset
%u = (%u, start => time, id => 0, c => 0); }
}
# Check pending addresses
if ( my $n = $self->get_pending(next_id => $p{id}, limit => 1)->[0] ) {
$p{id} = $n->{id}; # next id will be >$n
# assign BeaconChecker to query the server for validate, status
$self->query_udp_server(
ip => $n->{ip},
port => $n->{heartbeat},
need_validate => 1,
);
return;
}
$p{c}++; # all pending addresses were processed
# Update server status
if ( my $n = $self->get_server(
next_id => $u{id},
updated => 7200, # count >2h as unresponsive
limit => 1
)->[0] ) {
$u{id} = $n->{id}; # next id will be >$n
# assign BeaconChecker to query the server for status (no validate)
$self->query_udp_server(
ip => $n->{ip},
port => $n->{port},
);
return;
}
$u{c}++; # all servers were processed
# first run complete?
if ($self->{firstrun}) {
# done. no other actions required
return;
} else {
# notify about first run being completed and reset
my $t = time-$self->{firstruntime};
my $t_readable = ($t > 60) ? (int($t/60). " minutes ". ($t%60). " seconds") : ($t. " seconds");
$self->log("info", "first run completed after $t_readable");
delete $self->{firstruntime};
$self->{firstrun} = 1;
}
# Run complete. Count down until the minimum time has elapsed and handle
# new server entries as they are added to the list.
}
);
# allow object to exist beyond this scope. Objects have ambitions too.
$self->log("info", "UDP ticker is loaded");
return $server_info;
}
1;
|