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
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
|
package MasterServer::TCP::Syncer;
use strict;
use warnings;
use AnyEvent;
use AnyEvent::Handle;
use Exporter 'import';
our @EXPORT = qw| synchronize
process_applet
process_syncer |;
################################################################################
## Synchronize with UCC Applets (Epic Megagames, Inc.) or other 333networks
## based masterservers.
################################################################################
sub synchronize {
my ($self, $ms, $type) = @_;
my $ipbuflist = "";
# connection handle
my $handle; $handle = new AnyEvent::Handle(
connect => [$ms->{ip} => $ms->{hostport}],
timeout => $self->{timeout_time},
poll => 'r',
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 = "";
# part 1: receive \basic\\secure\$key
if ($m =~ m/\\basic\\\\secure\\/) {
# use provided gamename for applet or 333networks for syncer
my $gamename = "";
$gamename = $ms->{gamename} if ($type eq "applet");
$gamename = "333networks" if ($type eq "333nwm");
# processess received data and respond to challenge
my $rx = $self->data2hashref($m);
my $validate = $self->validate_string(
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\\";}
# push the request to remote host
$handle->push_write($request);
}
# 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 received from the UCC applet masterserver and
## move new addresses to the pending list.
################################################################################
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
# 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);
# use transactions for large numbers of ip/ports
$self->{dbh}->begin_work;
# iterate through the gamenames and addresses
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+)/ ) {
# 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
# 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("syncer", "found $tot ($new new) addresses at $ms->{ip},$ms->{hostport} (333nwm)");
}
1;
|