aboutsummaryrefslogtreecommitdiff
path: root/lib/MasterServer/UDP/UCCAppletQuery.pm
blob: bd7bb73439d04db798256399018572ace0a4c5e2 (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

package MasterServer::UDP::UCCAppletQuery;

use strict;
use warnings;
use AnyEvent;
use AnyEvent::Handle;
use Exporter 'import';

our @EXPORT = qw| ucc_applet_query_scheduler query_applet |;

################################################################################
## Query other UCC applets periodically to get a list of online servers. 
################################################################################
sub ucc_applet_query_scheduler {
  my $self = shift;
  $self->log("load", "UCC Applet Query Scheduler is loaded.");
  
  my $i = 0;
  return AnyEvent->timer (
    after     => $self->{master_applet_time}[0],
    interval  => $self->{master_applet_time}[1],
    cb        => sub {
      # check if there's a master server entry to be queried. If not, return
      # to zero and go all over again.
      $i = 0 unless $self->{master_applet}[$i];
      return if (!defined $self->{master_applet}[$i]);
      
      # perform the query
      $self->query_applet($self->{master_applet}[$i]);

      #increment counter
      $i++;
    }
  );
}

################################################################################
## 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("applet","[TCP] > start querying $ms->{ip}:$ms->{port} for '$ms->{game}' games");

  # list to store all IPs in.
  my $master_list = "";
  
  # connection handle
  my $handle; 
  $handle = new AnyEvent::Handle(
    connect  => [$ms->{ip} => $ms->{port}],
    timeout  => 5,
    poll     => 'r',
    on_error => sub {$self->log("error", "$! on $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\\/) {
        # skip to part 3: also request the list \list\gamename\ut
        #$handle->push_write("\\list\\\\gamename\\$ms->{game}");
        $handle->push_write("\\list\\");
      }
      
      # part 3b: receive the entire list in multiple steps.
      if ($m =~ m/\\ip\\/) {
        # add buffer to the list
        $master_list .= $m;
      }
    }
  );
}

1;