aboutsummaryrefslogtreecommitdiff
path: root/lib/MasterServer/TCP
diff options
context:
space:
mode:
Diffstat (limited to 'lib/MasterServer/TCP')
-rwxr-xr-xlib/MasterServer/TCP/BrowserHost.pm78
-rwxr-xr-xlib/MasterServer/TCP/Handler.pm211
-rwxr-xr-xlib/MasterServer/TCP/ListCompiler.pm133
-rwxr-xr-xlib/MasterServer/TCP/Syncer.pm226
-rwxr-xr-xlib/MasterServer/TCP/UCCAppletQuery.pm72
5 files changed, 213 insertions, 507 deletions
diff --git a/lib/MasterServer/TCP/BrowserHost.pm b/lib/MasterServer/TCP/BrowserHost.pm
index c53ae42..316a135 100755
--- a/lib/MasterServer/TCP/BrowserHost.pm
+++ b/lib/MasterServer/TCP/BrowserHost.pm
@@ -5,59 +5,89 @@ use warnings;
use AnyEvent::Socket;
use AnyEvent::Handle;
use Exporter 'import';
+our @EXPORT = qw| browser_host |;
-our @EXPORT = qw| browser_host clean_tcp_handle|;
+# keep handle alive and store authentication info
+my %conn = ();
################################################################################
## wait for incoming TCP connections from game clients and other masterservers.
-## respond with secure/validate, contact info and/or server lists.
+## respond with secure/validate and/or server lists.
## allow other masterservers to synchronize
################################################################################
sub browser_host {
my $self = shift;
my $browser = tcp_server undef, $self->{listen_port}, sub {
- my ($fh, $a, $p) = @_;
-
- # validated? yes = 1 no = 0
+ my ($fh, $addr, $port) = @_;
my $auth = 0;
- # debug -- new connection opened
- #$self->log("tcp","New connection from $a:$p");
-
- # prep a challenge
+ # prepare a secure/validate challenge
my $secure = $self->secure_string();
-
- # handle received data
- my $h; $h = AnyEvent::Handle->new(
+
+ # handle for client connection
+ my $client; $client = AnyEvent::Handle->new(
fh => $fh,
poll => 'r',
timeout => $self->{timeout_time},
- on_eof => sub {$self->log("tcp","eof on $a:$p" ); $self->clean_tcp_handle(@_)},
- on_error => sub {$self->error($!, "browser $a:$p"); $self->clean_tcp_handle(@_)},
- on_read => sub {$self->read_tcp_handle($h, $a, $p, $secure, @_)},
+ on_eof => sub {drop_handle($client);},
+ on_error => sub {drop_handle($client);$self->error($!, "client $addr:$port");},
+ on_read => sub {
+ # receive data
+ my $rx = $self->data2hashref($client->rbuf);$client->rbuf = "";
+
+ # Support echo: log, but don't respond (or recursive echo abuse)
+ $self->log("echo","msg $addr:$port: $rx->{echo}") if $rx->{echo};
+
+ # first check for validation info
+ if ($rx->{validate} && $rx->{gamename}) {
+ $auth = $self->auth_browser(
+ gamename => $rx->{gamename},
+ secure => $secure,
+ enctype => $rx->{enctype},
+ validate => $rx->{validate},
+ );
+ $conn{$client}[1] = $auth;
+ $self->log("secure", "client $addr:$port failed validation $rx->{gamename}") unless $auth;}
+
+ # list request with valid gamename / challenge
+ if ($auth && $rx->{gamename} && exists $rx->{list}) {
+ $client->push_write($self->generate_list($rx->{gamename}, $rx->{list})."\\final\\");
+ $self->log("list","$addr:$port retrieved the list for $rx->{gamename}");
+ drop_handle($client)}
+
+ # sync request with valid gamename / challenge
+ if ($auth && $rx->{sync}) {
+ $client->push_write($self->generate_sync($rx->{sync})."\\final\\");
+ $self->log("syncer","$addr:$port synchronized $rx->{sync}");
+ drop_handle($client)}
+
+ # request without valid gamename and/or authentication
+ if (!$auth && ($rx->{sync} || exists $rx->{list}) ) {
+ $client->push_write("\\echo\\You failed to authenticate. See 333networks.com for more info.\\final\\");
+ $self->log("warning","$addr:$port failed to authenticate before requesting a list/sync");
+ drop_handle($client);}
+ },
);
# part 1: send \basic\\secure\$key\
- $h->push_write("\\basic\\\\secure\\$secure\\final\\");
+ $client->push_write("\\basic\\\\secure\\$secure\\final\\");
- # keep handle alive longer and store authentication info
- $self->{browser_clients}->{$h} = [$h, $auth];
- return;
+ # keep handle alive and store authentication info
+ $conn{$client} = [$client, $auth];
};
# startup of TCP server complete
- $self->log("info", "Listening for TCP connections on port $self->{listen_port}.");
+ $self->log("info", "listening for TCP connections on port $self->{listen_port}");
return $browser;
}
################################################################################
## clean handles on timeouts, completed requests and/or errors
################################################################################
-sub clean_tcp_handle{
- my ($self, $c) = @_;
- # clean and close the connection
- delete ($self->{browser_clients}->{$c});
+sub drop_handle {
+ my $c = shift;
+ delete $conn{$c};
$c->destroy();
}
diff --git a/lib/MasterServer/TCP/Handler.pm b/lib/MasterServer/TCP/Handler.pm
deleted file mode 100755
index eb0094d..0000000
--- a/lib/MasterServer/TCP/Handler.pm
+++ /dev/null
@@ -1,211 +0,0 @@
-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_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, log the original message
- my $rxbuf = $m;
- #$self->log("debug","$a:$p sent $rxbuf");
-
- # 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/\\$/\\undef\\/;
- $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);
-
- # 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});
-
- #
- # Support echo: doesn't do anything but print to log if not suppressed.
- $self->log("echo","($a:$p): $r{echo}") if $r{echo};
-
- # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
- # improper syntax/protocol -- no valid commands found
- # respond with an error.
- # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
- if ("sync validate list" =~ m/\Q$response\E/i) {
-
- # 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\".");
- } # 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} && $self->get_game_props(gamename => $r->{gamename})) {
-
- # game exists and we have the key to verify the response
- $val = $self->compare_challenge(
- gamename => $r->{gamename},
- secure => $secure,
- enctype => $r->{enctype},
- validate => $r->{validate},
- ignore => $self->{ignore_browser_key},
- );
-
- # 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 (debug)
- #$self->log("secure","$a:$p validated with $val for $r->{gamename}, $secure, $r->{validate}");
-
- # return auth status
- return $val;
-}
-
-################################################################################
-## At this point, the client should be validated and ready to request with
-## the \secure\ command and is allowed to ask for the 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 ($r->{list} =~ /^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
- $self->log("list","$a:$p successfully retrieved the list for $r->{gamename}.");
-
- # clean and close the connection
- #$self->log("tcp","closing $a:$p");
- $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->log("tcp","closing $a:$p");
- $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)\sender\domainname
- $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-tx","$a:$p successfully synced.");
-
- # clean and close the connection
- #$self->log("tcp","closing $a:$p");
- $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->log("tcp","closing $a:$p");
- $self->clean_tcp_handle($c);
- }
-}
-
-1;
diff --git a/lib/MasterServer/TCP/ListCompiler.pm b/lib/MasterServer/TCP/ListCompiler.pm
index c035008..edced5e 100755
--- a/lib/MasterServer/TCP/ListCompiler.pm
+++ b/lib/MasterServer/TCP/ListCompiler.pm
@@ -3,120 +3,75 @@ package MasterServer::TCP::ListCompiler;
use strict;
use warnings;
use Exporter 'import';
-
-our @EXPORT = qw| compile_list compile_list_cmp compile_sync |;
+our @EXPORT = qw| generate_list generate_sync compile_sync |;
################################################################################
## compile the list of \ip\ip:port\ addresses and parse them into the
-## plaintext return string.
+## plaintext or compressed address string.
################################################################################
-sub compile_list {
- my ($self, $gamename) = @_;
+sub generate_list {
+ # gamename and \list\(|cmp)
+ my ($self, $gamename, $cmp) = @_;
# get the list from database
my $serverlist = $self->get_server(
- updated => 3600,
- gamename => $gamename,
- );
-
- # prepare empty return string
- my $response_string = "";
-
- # add address as regular \ip\127.0.0.1:7777\ format
- for (@{$serverlist}){
-
- # append \ip\ip:port to string
- $response_string .= "\\ip\\$_->{ip}:$_->{port}";
- }
+ updated => 3600,
+ gamename => $gamename,
+ );
- # return the string with data
- return $response_string;
-}
-
-################################################################################
-## compile the list of binary ip:port addresses and parse them into the
-## ABCDE return string.
-################################################################################
-sub compile_list_cmp {
- my ($self, $gamename) = @_;
-
- # get the list from database
- my $serverlist = $self->get_server(
- updated => 3600,
- gamename => $gamename,
- );
-
- # prepare empty return string
- my $response_string = "";
-
- # compile a return string
- for (@{$serverlist}){
-
- # convert ip address to ABCDEF mode
- my ($A, $B, $C, $D) = ($_->{ip} =~ /(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})/);
- my ($E, $F) = ($_->{port} >> 8, $_->{port} & 0xFF);
-
- # print as chr string of 6 bytes long
- my $bin = ""; $bin .= (chr $A) . (chr $B) . (chr $C) . (chr $D) . (chr $E) . (chr $F);
-
- # append to list of addresses
- $response_string .= $bin;
+ my $list = "";
+ # which format?
+ if ($cmp eq "cmp") {
+ # compressed format (ABCDEF format)
+ for (@{$serverlist}) {
+ my ($A, $B, $C, $D) = ($_->{ip} =~ /(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})/);
+ my ($E, $F) = ($_->{port} >> 8, $_->{port} & 0xFF);
+ my $bin = ""; $bin .= (chr $A) . (chr $B) . (chr $C) . (chr $D) . (chr $E) . (chr $F);
+ $list .= $bin;}
}
-
- # return the string with data
- return $response_string;
+ else {
+ # normal format (regular \ip\127.0.0.1:7777\ format)
+ for (@{$serverlist}) {
+ $list .= "\\ip\\$_->{ip}:$_->{port}";}
+ }
+
+ # list ready
+ return $list;
}
-
################################################################################
-## compile a list of all requested games --or-- if not specified, a list of
-## all games
+## compile a list of addresses for all available or requested games.
+## opts: all | list of games
################################################################################
-sub compile_sync {
+sub generate_sync {
my ($self, $sync) = @_;
-
- # prepare empty return string
- my $response_string = "";
- my @games;
-
- # client requests to sync all games
+ my $list = "";
+ my %games = ();
+
+ # prepare list of games
+ my $avail = $self->get_gamenames();
if ($sync eq "all") {
- # get array of gamenames from db
- my $sg = $self->get_gamenames();
- for (@{$sg}) {push @games, $_->[0];}
- }
- # only selected games
+ # if "all" is requested, check which games we have available
+ $games{$_->[0]} = 1 for (@{$avail}); }
else {
- # split request into array
- @games = split " ", $sync;
- }
+ # otherwise, see which of the requested addresses match our db
+ for (@{$avail}) {$games{$_->[0]} = 1 if ($sync =~ m/$_->[0]/i); } }
- # only get unique values from array
- my %games = map { $_ => 1 } @games;
-
# get the list for every requested gamename
- for my $g (keys %games) {
-
- # $g is now a gamename -- check if it's supported. Else ignore.
- if ($self->get_game_props(gamename => $g)) {
+ for my $gamename (keys %games) {
# get list from database
- my $list = $self->get_server(
- updated => 7200,
- gamename => $g,
- );
+ my $listref = $self->get_server(gamename => $gamename, updated => 3600);
# add all games to string separated by spaces
- my $gamestring = "";
- foreach $_ (@{$list}) {$gamestring .= "$_->{ip}:$_->{port} ";}
+ my $addresses = "";
+ foreach (@{$listref}) {$addresses .= "$_->{ip}:$_->{port} ";}
# if it contains at least one entry, add the list to the response list
- $response_string .= "\\$g\\$gamestring" if (length $gamestring >= 7);
- }
+ $list .= "\\$gamename\\$addresses" if (length $addresses >= 7);
}
-
- # return \gamename\addresses\gamename2\addresses2 list
- return $response_string;
+ # list ready
+ return $list;
}
1;
diff --git a/lib/MasterServer/TCP/Syncer.pm b/lib/MasterServer/TCP/Syncer.pm
index d890f00..cf7ee5b 100755
--- a/lib/MasterServer/TCP/Syncer.pm
+++ b/lib/MasterServer/TCP/Syncer.pm
@@ -5,152 +5,156 @@ use warnings;
use AnyEvent;
use AnyEvent::Handle;
use Exporter 'import';
-
-our @EXPORT = qw| sync_with_master
- process_sync_list |;
+our @EXPORT = qw| synchronize
+ process_applet
+ process_syncer |;
################################################################################
-## Sends synchronization request to another 333networks based master server and
-## receives the list of games.
+## Synchronize with UCC Applets (Epic Megagames, Inc.) or other 333networks
+## based masterservers.
################################################################################
-sub sync_with_master {
- my ($self, $ms) = @_;
-
- # announce
- $self->log("tcp", "Attempting to synchronize with $ms->{ip}");
+sub synchronize {
+ my ($self, $ms, $type) = @_;
+ my $ipbuflist = "";
- # list to store all IPs in.
- my $sync_list = "";
-
# connection handle
- my $handle;
- $handle = new AnyEvent::Handle(
+ my $handle; $handle = new AnyEvent::Handle(
connect => [$ms->{ip} => $ms->{hostport}],
timeout => $self->{timeout_time},
poll => 'r',
- on_error => sub {$self->error($!, "$ms->{ip}:$ms->{hostport}"); $handle->destroy;},
- on_eof => sub {$self->process_sync_list($sync_list, $ms); $handle->destroy;},
+ on_error => sub {$handle->destroy; $self->error($!, "$ms->{ip}:$ms->{hostport}");},
+ on_eof => sub {
+ $handle->destroy;
+ if ($type eq "applet") {$self->process_applet($ipbuflist, $ms);}
+ if ($type eq "333nwm") {$self->process_syncer($ipbuflist, $ms);}
+ },
on_read => sub {
-
# receive and clear buffer
my $m = $_[0]->rbuf;
$_[0]->rbuf = "";
- # remove string terminator: sometimes trailing slashes, line endings or
- # string terminators are added or forgotten by sender, so \secure\abcdef
- # is actually \secure\abcdef{\0}
- chop $m if $m =~ m/secure/;
-
# part 1: receive \basic\\secure\$key
- if ($m =~ m/basic\\\\secure/) {
+ if ($m =~ m/\\basic\\\\secure\\/) {
- # hash $m into %r
- my %r = ();
- $m =~ s/\\\\/\\undef\\/;
- $m =~ s/\n//;
- $m =~ s/\\([^\\]+)\\([^\\]+)/$r{$1}=$2/eg;
+ # use provided gamename for applet or 333networks for syncer
+ my $gamename = "";
+ $gamename = $ms->{gamename} if ($type eq "applet");
+ $gamename = "333networks" if ($type eq "333nwm");
- # respond to the validate challenge
+ # processess received data and respond to challenge
+ my $rx = $self->data2hashref($m);
my $validate = $self->validate_string(
- gamename => "333networks",
- secure => $r{secure},
- enctype => $r{enctype}
- );
+ gamename => $gamename,
+ enctype => $rx->{enctype},
+ secure => $rx->{secure}
+ );
+
+ # send challenge response
+ $handle->push_write("\\gamename\\$gamename\\location\\0\\validate\\$validate\\final\\");
+
+ # part 3a: also request the list \list\\gamename\ut
+ my $request = "";
+ if ($type eq "applet") {
+ $request = "\\list\\\\gamename\\$ms->{gamename}\\final\\";}
+ # part 3b: request the list \sync\[gamenames] consisting of space-seperated game names or "all"
+ if ($type eq "333nwm") {
+ $request = "\\sync\\".($self->{sync_games}[0] == 0 ? "all" : $self->{sync_games}[1] )."\\final\\";}
- # part 2: send \gamename\ut\location\0\validate\$validate\final\
- $handle->push_write("\\gamename\\333networks\\location\\0\\validate\\$validate\\final\\");
-
- # part 3: request the list \sync\gamenames consisting of space-seperated game names or "all"
- # compatibility note: old queries use "new", instead treat them as "all".
- my $request = "\\sync\\"
- . (($self->{sync_games}[0] == 0) ? ("all") : $self->{sync_games}[1])
- . "\\final\\";
-
# push the request to remote host
$handle->push_write($request);
-
- # clean up $m for future receivings
- $m = "";
-
- } # end secure
+ }
- # part 4: receive the entire list in multiple steps
- $sync_list .= $m;
- },
+ # part 4: receive the entire list in multiple steps.
+ # continue receiving data and adding to the buffer
+ else {$ipbuflist .= $m;}
+ }
);
}
################################################################################
-## Process the list of addresses that was received after querying the UCC applet
-## and store them in the pending list.
+## Process the list of addresses received from the UCC applet masterserver and
+## move new addresses to the pending list.
################################################################################
-sub process_sync_list {
- my ($self, $m, $ms) = @_;
-
- # replace empty values for the string "undef" and replace line endings from netcatters
- # parse hash {gamename => list of ips seperated by space}
- my %r = ();
- $m =~ s/\\\\/\\undef\\/;
- $m =~ s/\n//;
- $m =~ s/\\([^\\]+)\\([^\\]+)/$r{$1}=$2/eg;
+sub process_applet {
+ my ($self, $buf, $ms) = @_;
+ my $new = 0; my $tot = 0;
+
+ # database types such as SQLite are slow, therefore use transactions.
+ $self->{dbh}->begin_work;
+
+ # parse $buf into an array of [ip, port]
+ foreach my $l (split /\\/, $buf) {
+
+ # search for \ip\255.255.255.255:7778\ and capture ip and port
+ if (my ($address,$port) = $l =~ /([\.\w]+):(\d+)/ ) {
+ # check if address entry is valid
+ if ($self->valid_address($address,$port)) {
+
+ # add server and count new/total addresses
+ $new += $self->insert_pending(ip => $address, port => $port);
+ $tot++;
+ }
+ # invalid address, log
+ else {$self->log("error", "invalid address found at $ms->{ip}:$ms->{hostport} > $l (applet)");}
+ }
+ } # end foreach
- # counter
- my $c = 0;
+ # complete transaction
+ $self->{dbh}->commit;
+
+ # update time if successful applet query
+ $self->update_master_applet(ip => $ms->{ip}, port => $ms->{hostport}, gamename => $ms->{gamename} )
+ if ($tot > 0);
+
+ # print findings
+ $self->log("syncer","found $tot ($new new) addresses at $ms->{ip},$ms->{hostport} for $ms->{gamename} (applet)");
+}
+
+################################################################################
+## Process the list of addresses received from the 333networks masterserver and
+## move new addresses to the pending list.
+################################################################################
+sub process_syncer {
+ my ($self, $buf, $ms) = @_;
+ my $new = 0; my $tot = 0;
+
+ # extract to hash: gamename => ( address list )
+ my $rx = $self->data2hashref($buf);
- if (exists $r{echo}) {
- # remote address says...
- $self->log("echo", "$ms->{ip} replied: $r{echo}");
- }
+ # use transactions for large numbers of ip/ports
+ $self->{dbh}->begin_work;
# iterate through the gamenames and addresses
- while ( my ($gn,$addr) = each %r) {
-
- # process all games wether we have a cipher for them.
- if (defined $gn) {
-
- # some database types, such as SQLite, are slow - therefore use transactions.
- $self->{dbh}->begin_work;
-
- # l(ocations, \label\ip:port\) split up in a(ddress) and p(ort)
- foreach my $l (split(/ /, $addr)) {
-
- # search for \255.255.255.255:7778\, contains ':'
- if ($l =~ /:/) {
- my ($a,$p) = $l =~ /(.*):(.*)/;
-
- # check if address entry is valid
- if ($self->valid_address($a,$p)) {
- # count number of valid addresses
- $c++;
-
- # add server
- $self->syncer_add($a, $p, $gn, $self->secure_string());
-
- # print address (debug)
- # $self->log("add", "syncer added $gn\t$a\t$p");
- }
- else {
- # invalid address, log
- $self->log("error", "invalid address found while syncing at $ms->{ip}: $l!");
- }
-
- } # endif ($l =~ /:/)
- } # end for / /
-
- # end transaction, commit
- $self->{dbh}->commit;
+ while ( my ($gamename,$addresslist) = each %{$rx}) {
+
+ # parse $buf into an array of [ip, port]
+ foreach my $l (split / /, $addresslist) {
+
+ # search for \ip\255.255.255.255:7778\ and capture ip and port
+ if (my ($address,$port) = $l =~ /([\.\w]+):(\d+)/ ) {
- } # end defined $gn
+ # check if address entry is valid
+ if ($self->valid_address($address,$port)) {
+ # add server and count new/total addresses
+ $new += $self->insert_pending(ip => $address, port => $port);
+ $tot++;
+
+ }
+ # invalid address, log
+ else {$self->log("error", "invalid address found at $ms->{ip}:$ms->{hostport} > $l (333nwm)");}
+ }
+ } # end foreach
} # end while
- # update this sync master in the gamelist with lastseen time
- $self->update_server_list(
- ip => $ms->{ip},
- port => $ms->{port},
- ) if ($c > 0);
+ # complete transaction
+ $self->{dbh}->commit;
+
+ # update time if successful sync master query
+ $self->update_server(ip => $ms->{ip}, hostport => $ms->{hostport})
+ if ($tot > 0);
# end message
- $self->log("sync-rx", "received $c addresses after syncing from $ms->{ip}:$ms->{hostport}");
+ $self->log("syncer", "found $tot ($new new) addresses at $ms->{ip},$ms->{hostport} (333nwm)");
}
1;
diff --git a/lib/MasterServer/TCP/UCCAppletQuery.pm b/lib/MasterServer/TCP/UCCAppletQuery.pm
deleted file mode 100755
index 2c32de9..0000000
--- a/lib/MasterServer/TCP/UCCAppletQuery.pm
+++ /dev/null
@@ -1,72 +0,0 @@
-package MasterServer::TCP::UCCAppletQuery;
-
-use strict;
-use warnings;
-use AnyEvent;
-use AnyEvent::Handle;
-use Exporter 'import';
-
-our @EXPORT = qw| query_applet |;
-
-################################################################################
-## The UCC Applet (Epic Megagames, Inc.) functions as a master server for one
-## single game. However, it does not always follow the defined protocol.
-## This module connects with UCC masterserver applets to receive the list.
-################################################################################
-sub query_applet {
- my ($self, $ms) = @_;
-
- # be nice to notify
- $self->log("tcp","start querying $ms->{ip}:$ms->{port} for '$ms->{gamename}' games");
-
- # list to store all IPs in.
- my $master_list = "";
-
- # connection handle
- my $handle;
- $handle = new AnyEvent::Handle(
- connect => [$ms->{ip} => $ms->{port}],
- timeout => $self->{timeout_time},
- poll => 'r',
- on_error => sub {$self->error($!, "$ms->{ip}:$ms->{port}"); $handle->destroy;},
- on_eof => sub {$self->process_ucc_applet_query($master_list, $ms); $handle->destroy;},
- on_read => sub {
-
- # receive and clear buffer
- my $m = $_[0]->rbuf;
- $_[0]->rbuf = "";
-
- # remove string terminator
- chop $m if $m =~ m/secure/;
-
- # part 1: receive \basic\\secure\$key
- if ($m =~ m/\\basic\\\\secure\\/) {
-
- # received data
- my %r;
- $m =~ s/\\([^\\]+)\\([^\\]+)/$r{$1}=$2/eg;
-
- # respond to challenge
- my $validate = $self->validate_string(gamename => $ms->{gamename},
- enctype => $r{enctype}||0,
- secure => $r{secure});
-
- # send response
- $handle->push_write("\\gamename\\$ms->{gamename}\\location\\0\\validate\\$validate\\final\\");
-
- # part 3: also request the list \list\gamename\ut -- skipped in UCC applets
- $handle->push_write("\\list\\\\gamename\\$ms->{gamename}\\final\\");
-
- }
-
- # part 3b: receive the entire list in multiple steps.
- # $m contains \ip\ or part of that string
- else {
- # add buffer to the list
- $master_list .= $m;
- }
- }
- );
-}
-
-1;