diff options
| author | Darkelarious <darkelarious@333networks.com> | 2016-11-19 20:56:04 +0100 |
|---|---|---|
| committer | Darkelarious <darkelarious@333networks.com> | 2016-11-19 20:56:04 +0100 |
| commit | c3f8d65a4fb1f5674557ee67cf7f74369df86ad1 (patch) | |
| tree | 92aab2a394bda28da0ed7c7c75e633fdf386fc71 /lib/MasterServer/UDP/UDPTicker.pm | |
| parent | 1de3da4b8027508a91144639455c934fd6ccb9b7 (diff) | |
| download | MasterServer-Perl-c3f8d65a4fb1f5674557ee67cf7f74369df86ad1.tar.gz MasterServer-Perl-c3f8d65a4fb1f5674557ee67cf7f74369df86ad1.zip | |
Massive improvements on efficiency, robustness, security, reliability and more
Diffstat (limited to 'lib/MasterServer/UDP/UDPTicker.pm')
| -rwxr-xr-x | lib/MasterServer/UDP/UDPTicker.pm | 298 |
1 files changed, 298 insertions, 0 deletions
diff --git a/lib/MasterServer/UDP/UDPTicker.pm b/lib/MasterServer/UDP/UDPTicker.pm new file mode 100755 index 0000000..5a34a8f --- /dev/null +++ b/lib/MasterServer/UDP/UDPTicker.pm @@ -0,0 +1,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; |
