diff options
| author | Darkelarious <darkelarious@333networks.com> | 2017-07-06 12:21:45 +0200 |
|---|---|---|
| committer | Darkelarious <darkelarious@333networks.com> | 2017-07-06 12:21:45 +0200 |
| commit | e0d727670cbeda0db0812c5c9efc503d75f8d0a4 (patch) | |
| tree | 3c4a5c2aa2b065e5458ea30e86c30ed30f7bac8d /lib/MasterServer/UDP/UpLink.pm | |
| parent | 34a2c7390ea9662d33258d384e72fff1912343ff (diff) | |
| download | MasterServer-Perl-e0d727670cbeda0db0812c5c9efc503d75f8d0a4.tar.gz MasterServer-Perl-e0d727670cbeda0db0812c5c9efc503d75f8d0a4.zip | |
Support for \status\ query, deprecated \about\ query
Diffstat (limited to 'lib/MasterServer/UDP/UpLink.pm')
| -rwxr-xr-x | lib/MasterServer/UDP/UpLink.pm | 140 |
1 files changed, 85 insertions, 55 deletions
diff --git a/lib/MasterServer/UDP/UpLink.pm b/lib/MasterServer/UDP/UpLink.pm index 63cbefb..01e806e 100755 --- a/lib/MasterServer/UDP/UpLink.pm +++ b/lib/MasterServer/UDP/UpLink.pm @@ -9,8 +9,11 @@ use Exporter 'import'; our @EXPORT = qw| send_heartbeats do_uplink - process_uplink_response - process_udp_secure |; + process_udp_secure + handle_status_query |; + +# for compliance, query ID +my $query_id = 0; ################################################################################ ## Broadcast heartbeats to other masterservers @@ -57,7 +60,11 @@ sub do_uplink { timeout => $self->{timeout_time}, on_timeout => sub {$udp_client->destroy()}, on_error => sub {$udp_client->destroy()}, - on_recv => sub {$self->process_uplink_response(@_)}, + on_recv => sub { + my ($self, $buf, $udp, $pa) = @_; + $self->handle_status_query($udp, $pa, $buf) + if ($buf =~ m/secure/); + }, ); # Send heardbeat @@ -65,78 +72,101 @@ sub do_uplink { } ################################################################################ -## Process requests received after uplinking -## +## Respond to status-like queries. Supported queries are basic, info, rules, +## players, status. +## Note: this replaces the \about\ query in the TCP handler! ################################################################################ -sub process_uplink_response { - # $self, beacon address, handle, packed client address - my ($self, $b, $udp, $pa) = @_; - - # unpack ip from packed client address - my ($port, $iaddr) = sockaddr_in($pa); - my $peer_addr = inet_ntoa($iaddr); - - # assume fraud/crash attempt if response too long - if (length $b > 64) { - # log - $self->log("attack","length exceeded in uplink response: $peer_addr:$port sent $b"); - - # truncate and try to continue - $b = substr $b, 0, 64; - } - - # check if this is a secure challenge - $self->process_udp_secure($udp, $pa, $b, $peer_addr) - if ($b =~ m/\\secure\\/); -} +sub handle_status_query { + my ($self, $udp, $pa, $buf) = @_; - -################################################################################ -## Process the received secure query and respond with the correct response -## TODO: expand queries with support for info, rules, players, status, etc -################################################################################ -sub process_udp_secure { - # $self, handle, packed address, udp data, peer ip address, $port - my ($self, $udp, $pa, $buf, $peer_addr) = @_; - - # received secure in $buf: \basic\\secure\wookie + # hotfix for one-word queries + $buf .= "\\dummy\\"; my %r; - + $buf = encode('UTF-8', $buf); - $buf =~ s/\\\\/\\undef\\/; $buf =~ s/\n//; + $buf =~ s/\\\\/\\undef\\/g; # where to add the +? seperate perl script! $buf =~ s/\\([^\\]+)\\([^\\]+)/$r{$1}=$2/eg; # response string my $response = ""; - # compile basic string + # for compliance, query ids between 0-99 + $query_id = ($query_id >= 99) ? 1 : ++$query_id; + my $sub_id = 1; - # provide basic information if asked for - if (defined $r{basic} || defined $r{status} || defined $r{info}) { + # get database info to present game stats as players, where num_total > 0 + my $maxgames = $self->check_cipher_count(); + my $gameinfo = $self->get_game_props( + num_gt => 1, + sort => "num_total", + reverse => 1 + ); - # format: \gamename\ut\gamever\348\minnetver\348\location\0\final\\queryid\16.1 + # secure challenge + if (defined $r{secure}) { + $response .= "\\validate\\" + . $self->validate_string( + gamename => "333networks", + enctype => 0, + secure => $r{secure} + ); + } + + # basic query + if (defined $r{basic} || defined $r{status}) { $response .= "\\gamename\\333networks" . "\\gamever\\$self->{short_version}" . "\\location\\0" - . "\\hostname\\$self->{masterserver_hostname}" - . "\\hostport\\$self->{listen_port}"; + . "\\queryid\\$query_id.".$sub_id++; + } + + # info query + if (defined $r{info} || defined $r{status}) { + $response .= "\\hostname\\$self->{masterserver_hostname}" + . "\\hostport\\$self->{listen_port}" + . "\\gametype\\MasterServer" + . "\\numplayers\\". scalar @{$gameinfo} + . "\\maxplayers\\$maxgames" + . "\\gamemode\\openplaying" + . "\\queryid\\$query_id.".$sub_id++; + } + + # rules query + if (defined $r{rules} || defined $r{status}) { + $response .= "\\mutators\\333networks synchronization, master applet synchronization" + . "\\AdminName\\$self->{masterserver_name}" + . "\\AdminEMail\\$self->{masterserver_contact}" + . "\\queryid\\$query_id.".$sub_id++; } - # TODO: add queryid -- not because it's useful, but because protocol compliant + # players query + if (defined $r{players} || defined $r{status}) { + # list game stats as if they were players, with game description as + # player_$, gamename as skin_$, total servers as frags_$ and number of + # direct uplinks as deaths_$ + my $c = 0; - # support for secure/validate - if (defined $r{secure}) { - # generate response - - $response .= "\\validate\\" - . $self->validate_string(gamename => "333networks", - enctype => 0, - secure => $r{secure}); + foreach my $p (@{$gameinfo}) { + $c++; # count players + $response .= "\\player_$c\\$p->{description}" + . "\\skin_$c\\$p->{gamename}" + . "\\frags_$c\\$p->{num_total}" + . "\\deaths_$c\\$p->{num_uplink}"; + } + $response .= "\\queryid\\$query_id.".$sub_id++; } - # send the response - $udp->push_send("$response\\final\\", $pa); + # close query with final tag + $response .= "\\final\\"; + + # split the response in chunks of 512 bytes and send + while (length $response > 512) { + my $chunk = substr $response, 0, 512, ''; + $udp->push_send($chunk, $pa); + } + # last <512 chunk + $udp->push_send($response, $pa); } 1; |
