aboutsummaryrefslogtreecommitdiff
path: root/lib/MasterServer/TCP/BrowserHost.pm
blob: 316a13569c9745621cbd42923a6f537b240f9fc0 (plain)
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;