File Coverage

blib/lib/Net/SRCDS/Queries.pm
Criterion Covered Total %
statement 54 85 63.5
branch 2 10 20.0
condition 2 7 28.5
subroutine 17 20 85.0
pod 8 8 100.0
total 83 130 63.8


line stmt bran cond sub pod time code
1             package Net::SRCDS::Queries;
2              
3 3     3   107913 use warnings;
  3         8  
  3         104  
4 3     3   14 use strict;
  3         10  
  3         83  
5 3     3   2414 use version; our $VERSION = qv('0.0.3');
  3         6670  
  3         15  
6 3     3   247 use Carp qw(croak);
  3         6  
  3         221  
7 3     3   1749 use IO::Socket::INET;
  3         52075  
  3         27  
8 3     3   4445 use IO::Select;
  3         5045  
  3         147  
9 3     3   19 use base qw(Net::SRCDS::Queries::Parser);
  3         7  
  3         2086  
10              
11             # implemented queries
12             # see http://developer.valvesoftware.com/wiki/Source_Server_Queries
13             # for all queries.
14             #
15 3     3   20 use constant GETCHALLENGE => "\xFF\xFF\xFF\xFF\x57";
  3         13  
  3         157  
16 3     3   15 use constant A2S_INFO => "\xFF\xFF\xFF\xFFTSource Engine Query\0";
  3         4  
  3         138  
17 3     3   14 use constant A2S_PLAYER => "\xFF\xFF\xFF\xFF\x55";
  3         5  
  3         135  
18 3     3   14 use constant A2S_RULES => "\xFF\xFF\xFF\xFF\x56";
  3         5  
  3         109  
19 3     3   19 use constant MAX_SOCKBUF => 65535;
  3         5  
  3         2464  
20              
21             sub new {
22 2     2 1 326 my( $class, %args ) = @_;
23              
24 2 50       19 my $socket = IO::Socket::INET->new(
25             Proto => 'udp',
26             Blocking => 0,
27             ) or croak "cannot bind socket : $!";
28 2         485 my $select = IO::Select->new($socket);
29 2   50     175 my $self = {
      50        
30             socket => $socket,
31             select => $select,
32             servers => [],
33             timeout => $args{timeout} || 3,
34             encoding => $args{encoding} || undef,
35             };
36 2 50       16 $self->{float_order} =
37             unpack( 'H*', pack( 'f', 1.05 ) ) eq '6666863f' ? 0 : 1;
38 2         28 bless $self, $class;
39             }
40              
41             sub add_server {
42 0     0 1 0 my( $self, $addr, $port ) = @_;
43 0         0 push @{ $self->{servers} }, { addr => $addr, port => $port };
  0         0  
44             }
45              
46             sub get_all {
47 0     0 1 0 my($self) = @_;
48 0         0 my $select = $self->{select};
49 0         0 my $timeout = $self->{timeout};
50 0         0 for my $s ( @{ $self->{servers} } ) {
  0         0  
51 0         0 my $dest = sockaddr_in $s->{port}, inet_aton $s->{addr};
52 0         0 $self->send_a2s_info($dest);
53 0         0 $self->send_challenge($dest);
54             }
55 0         0 my $finished = {};
56 0         0 LOOP: while (1) {
57 0         0 my @ready = $select->can_read($timeout);
58 0         0 for my $fh (@ready) {
59 0         0 my $sender = $fh->recv( my $buf, MAX_SOCKBUF );
60 0         0 my( $port, $addr ) = sockaddr_in $sender;
61 0         0 my $server = sprintf "%s:%s", inet_ntoa($addr), $port;
62 0         0 my $result = $self->parse_packet( $buf, $server, $sender );
63 0         0 my $sr = $self->{results}->{$server};
64 0 0 0     0 if ( exists $sr->{player} and exists $sr->{rules} ) {
65 0         0 $finished->{$server}++;
66             }
67             last LOOP
68 0 0       0 if scalar keys %{$finished} >= scalar @{ $self->{servers} };
  0         0  
  0         0  
69             }
70             # exit loop when you get nothing
71 0 0       0 unless (@ready) {
72 0         0 warn "no ready\n";
73 0         0 last LOOP;
74             }
75             }
76 0         0 return $self->{results};
77             }
78              
79             sub send_challenge {
80 1     1 1 1128 my( $self, $dest ) = @_;
81 1         3 my $socket = $self->{socket};
82 1         6 $socket->send( GETCHALLENGE, 0, $dest );
83             }
84              
85             sub send_a2s_info {
86 1     1 1 703 my( $self, $dest ) = @_;
87 1         9 my $socket = $self->{socket};
88 1         12 $socket->send( A2S_INFO, 0, $dest );
89             }
90              
91             sub send_a2s_player {
92 1     1 1 805 my( $self, $dest, $cnum ) = @_;
93 1         3 my $socket = $self->{socket};
94 1         7 $socket->send( A2S_PLAYER . $cnum, 0, $dest );
95             }
96              
97             sub send_a2s_rules {
98 1     1 1 2671 my( $self, $dest, $cnum ) = @_;
99 1         4 my $socket = $self->{socket};
100 1         6 $socket->send( A2S_RULES . $cnum, 0, $dest );
101             }
102              
103             sub get_result {
104 0     0 1   my($self) = @_;
105 0           return $self->{results};
106             }
107              
108             1;
109             __END__