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
|
package MasterServer::TCP::BrowserHost;
use strict;
use warnings;
use AnyEvent::Socket;
use AnyEvent::Handle;
use Exporter 'import';
our @EXPORT = qw| browser_host |;
# keep handle alive and store authentication info
my %conn = ();
################################################################################
## wait for incoming TCP connections from game clients and other masterservers.
## 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, $addr, $port) = @_;
my $auth = 0;
# prepare a secure/validate challenge
my $secure = $self->secure_string();
# handle for client connection
my $client; $client = AnyEvent::Handle->new(
fh => $fh,
poll => 'r',
timeout => $self->{timeout_time},
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\
$client->push_write("\\basic\\\\secure\\$secure\\final\\");
# 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}");
return $browser;
}
################################################################################
## clean handles on timeouts, completed requests and/or errors
################################################################################
sub drop_handle {
my $c = shift;
delete $conn{$c};
$c->destroy();
}
1;
|