diff options
| author | Darkelarious <darkelarious@333networks.com> | 2015-05-19 22:00:40 +0200 |
|---|---|---|
| committer | Darkelarious <darkelarious@333networks.com> | 2015-05-19 22:00:40 +0200 |
| commit | 2c7d62f38944f61e7eafea155c6128521d16aed9 (patch) | |
| tree | bd473e6fb9dbbf8e0fdc67b87f0a4ac251fada7b /lib/MasterServer/TCP/Handler.pm | |
| parent | 534626943a0a5e251e5465376f3de3fb71b25e91 (diff) | |
| download | MasterServer-Perl-2c7d62f38944f61e7eafea155c6128521d16aed9.tar.gz MasterServer-Perl-2c7d62f38944f61e7eafea155c6128521d16aed9.zip | |
Beta with support for Pg and SQLite
Diffstat (limited to 'lib/MasterServer/TCP/Handler.pm')
| -rwxr-xr-x | lib/MasterServer/TCP/Handler.pm | 280 |
1 files changed, 280 insertions, 0 deletions
diff --git a/lib/MasterServer/TCP/Handler.pm b/lib/MasterServer/TCP/Handler.pm new file mode 100755 index 0000000..bf6beb9 --- /dev/null +++ b/lib/MasterServer/TCP/Handler.pm @@ -0,0 +1,280 @@ + +package MasterServer::TCP::Handler; + +use strict; +use warnings; +use AnyEvent::Socket; +use AnyEvent::Handle; +use Exporter 'import'; + +our @EXPORT = qw| read_tcp_handle + handle_validate + handle_about + handle_list + handle_sync |; + +################################################################################ +## wait for incoming TCP connections from game clients and other masterservers. +## respond with secure/validate, contact info and/or server lists. +## allow other masterservers to synchronize +################################################################################ +sub read_tcp_handle { + my ($self, $h, $a, $p, $secure, $c) = @_; + + # clear the buffer + my $m = $c->rbuf; + $c->rbuf = ""; + + # did the client validate already? + my $val = $self->{browser_clients}->{$h}[1]; + + # in case of errors, save the original message + my $rxbuf = $m; + + # allow multiple blocks to add to the response string + my $response = ""; + + # replace empty values for the string "undef" and replace line endings from netcatters + # parse the received data and extrapolate all the query commands found + my %r = (); + $m =~ s/\\\\/\\undef\\/; + $m =~ s/\n//; + $m =~ s/\\([^\\]+)\\([^\\]+)/$r{$1}=$2/eg; + + # secure/validate challenge + # part 2: receive \gamename\ut\location\0\validate\$validate\final\ + $val = $self->handle_validate(\%r, $h, $secure, $a, $p) + if (exists $r{validate} && !$val); + + # about query + $response .= $self->handle_about($r{about}, $a, $p) if (exists $r{about}); + + # return address list + # part 3: wait for the requested action: \list\gamename\ut\ + $self->handle_list($val, \%r, $c, $a, $p) if (exists $r{list} && exists $r{gamename}); + + # Sync request from another 333networks-based masterserver. Respond with list + # of requested games (or all games). + $self->handle_sync($val, \%r, $c, $a, $p) if (exists $r{sync}); + + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + # improper syntax/protocol -- no valid commands found + # respond with an error. + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + if ($m =~ m/!(about|sync|validate|list)/) { + + # error message to client + $c->push_write("\\echo\\333networks did not understand your request. ". + "Contact us via 333networks.com\\final\\"); + + # and log it + $self->log("error","invalid request from Browser $a:$p with unknown message \"$rxbuf\"", $self->{log_settings}->{handler_error}); + } # end if weird query + else { + $c->push_write($response . "\\final\\") if ($response ne ""); + } + +} + + +################################################################################ +## The master server opens the connection with the \secure\ challenge. The +## client should respond with basic information about itself and the +## \validate\ response. In this code block we verify the challenge/response. +################################################################################ +sub handle_validate { + my ($self, $r, $h, $secure, $a, $p) = @_; + + # auth var init + my $val = 0; + + # pass or fail the secure challenge + if (exists $r->{gamename} && exists $self->{game}->{$r->{gamename}}) { + # game exists and we have the key to verify the response + $val = $self->validated_request($r->{gamename}, $secure, $r->{enctype}, $r->{validate}); + + # update for future queries + $self->{browser_clients}->{$h}[1] = $val; + } + elsif (exists $r->{gamename}) { + # log + $self->log("support", "received unknown gamename request \"$r->{gamename}\" from $a:$p"); + } + + # log + $self->log("secure","$a:$p validated with $val for $r->{gamename}, $secure, $r->{validate}"); + + # return auth status + return $val; +} + + +################################################################################ +## \about\ query. +## Can contain the values "contact", "build", "Address" or "support", where +## - contact: return contact information; see config.pl +## - build: build info, also version.pm +## - address: address and ports +## - support: return a list of games currently in the database +## - undef: all of the above +## +## NOTE: client does not need to validate to be allowed to perform this +## query. +################################################################################ +sub handle_about { + my ($self, $about, $a, $p) = @_; + my $response = ""; + + # + # contact info + # + if ($about =~ /^contact$/i or $about =~ /^undef$/i) { + $response .= "\\about\\$self->{contact_details}"; + + # log/print + $self->log("about","communicating to $a:$p my contact information."); + } + + # + # build info + # + if ($about =~ /^build$/i or $about =~ /^undef$/i) { + + $response .= "\\build\\$self->{build_type} $self->{build_version} written " + . "by $self->{build_author}, released $self->{build_date}"; + + # log/print + $self->log("about","telling $a:$p my build info."); + } + + # + # address info + # + if ($about =~ /^address$/i or $about =~ /^undef$/i) { + + $response .= "\\address\\$self->{masterserver_address}" + . "\\listen_port\\$self->{listen_port}" + . "\\beacon_port\\$self->{beacon_port}"; + + # log/print + $self->log("about","telling $a:$p my address/config info."); + } + + # + # support info + # + if ($about =~ /^support$/i or $about =~ /^undef$/i) { + + # string games in database + my $sg = $self->get_gamenames(); + my $sgs = ""; + for (@{$sg}) { + $sgs .= " " if (length $sgs > 0); + $sgs .= $_->[0]; + } + + # print response + $response .= "\\support\\$sgs"; + + #log/print + $self->log("about","telling $a:$p which games are supported."); + } + + # return response string + return $response; +} + +################################################################################ +## At this point, the client should be validated and ready to request with +## the \secure\ command and is allowed to ask for the list. +## The \list\ cmd is NOT compatible with combined queries +## (like \about\contact\list\) +################################################################################ +sub handle_list { + my ($self, $val, $r, $c, $a, $p) = @_; + + # confirm validation + if ($val && exists $r->{gamename}) { + + # prepare the list + my $data = ""; + + # determine the return format + if ($self->{hex_format} =~ m/$r->{gamename}/i or $r->{gamename} =~ /^cmp$/i) { + # return addresses as byte format (ip=ABCD port=EF) + $data .= $self->compile_list_cmp($r->{gamename}); + } + else { + # return addresses as regular \ip\127.0.0.1:7777\ format + $data .= $self->compile_list($r->{gamename}); + } + + # finalize response string + $data .= "\\final\\"; + + # immediately send to client + $c->push_write($data); + + # log successful (debug) + $self->log("list","$a:$p successfully retrieved the list for $r->{gamename}."); + + # clean and close the connection + $self->clean_tcp_handle($c); + } + + # proper syntax/protocol, but incorrect validation. Therefore respond with + # an 'empty' list, returning only \final\. + else { + # return error/empty list + $c->push_write("\\echo\\333networks failed to validate your request. Use the correct authorization cipher!\\final\\"); + + # log it too + $self->log("error","browser $a:$p failed validation for $r->{gamename}"); + + # clean and close the connection + $self->clean_tcp_handle($c); + } +} + +################################################################################ +## Respond to \sync\ requests from other 333networks-based masterservers. After +## validation, sync behaves in much the same way as \list\, +################################################################################ +sub handle_sync { + my ($self, $val, $r, $c, $a, $p) = @_; + + # alternate part 3: wait for the requested action: \sync\(all|list of games) + $self->log("tcp","Sync request from $a:$p found"); + + if ($val && exists $r->{sync}) { + + # compile list of addresses + my $data = $self->compile_sync($r->{sync}); + $data .= "\\final\\"; + + # send to remote client + $c->push_write($data); + + # log successful (debug) + $self->log("sync","$a:$p successfully synced."); + + # clean and close the connection + $self->clean_tcp_handle($c); + + } + # proper syntax/protocol, but incorrect validation. Therefore respond with + # an 'empty' list, returning only \final\. + else { + + # return error/empty list + $c->push_write("\\echo\\333networks failed to validate your request. Use a proper authorization key!\\final\\"); + + # log it too + $self->log("error","$a:$p failed synchronization."); + + # clean and close the connection + $self->clean_tcp_handle($c); + } +} + +1; |
