File Coverage

blib/lib/BZFlag/Info.pm
Criterion Covered Total %
statement 15 214 7.0
branch 0 60 0.0
condition n/a
subroutine 5 11 45.4
pod 4 6 66.6
total 24 291 8.2


line stmt bran cond sub pod time code
1             package BZFlag::Info;
2              
3 1     1   5399 use 5.006001;
  1         3  
  1         31  
4 1     1   5 use strict;
  1         1  
  1         23  
5 1     1   4 use warnings;
  1         9  
  1         26  
6              
7 1     1   6245 use LWP::UserAgent;
  1         57583  
  1         39  
8 1     1   1325 use Socket;
  1         6398  
  1         2542  
9              
10             our $VERSION = '1.9.2';
11              
12             sub new {
13 0     0 1   my $self = { };
14 0           bless $self, "BZFlag::Info";
15 0           return $self;
16             }
17              
18             sub serverlist(%) {
19 0     0 1   my $self = shift;
20            
21 0           my %options;
22 0           while (my @option = splice(@_, 0, 2)) {
23 0           $options{$option[0]} = $option[1];
24             }
25            
26 0           my $proxy = $options{Proxy};
27 0           my $response;
28 0           my $ua = new LWP::UserAgent;
29 0 0         $ua->proxy('http', $proxy) if defined($proxy);
30            
31 0           $ua->timeout(10);
32            
33 0 0         my $req = HTTP::Request->new('GET', ($options{Server} ? $options{Server} : $self->listserver));
34 0           my $res = $ua->request($req);
35 0           my $totalServers = 0;
36 0           my $totalPlayers = 0;
37 0           for my $line (split("\n",$res->content)) {
38 0           my ($serverport, $version, $flags, $ip, $description) = split(" ",$line,5);
39            
40 0           my @fields = ('style','maxShots','shakeWins','shakeTimeout','maxPlayerScore',
41             'maxTeamScore','maxTime','maxPlayers','rogueSize','rogueMax','redSize',
42             'redMax','greenSize','greenMax','blueSize','blueMax','purpleSize',
43             'purpleMax','observerSize','observerMax'
44             );
45              
46 0           my @info = unpack("(A4)7 (A2)13", $flags);
47              
48 0           my $counter = 0;
49 0           my %info;
50              
51 0           foreach (@fields) {
52 0           $info{$_} = oct('0x'.$info[$counter]);
53 0           $counter++;
54             }
55            
56 0           my $playerSize = $info{rogueSize} + $info{redSize} + $info{greenSize}
57             + $info{blueSize} + $info{purpleSize} + $info{observerSize};
58            
59 0 0         unless ($serverport =~ m/.*:\d+/) {
60 0           $serverport = "$serverport:5154";
61             }
62            
63 0           $response->{servers}->{$serverport}->{version} = $version;
64 0           $response->{servers}->{$serverport}->{ip} = $ip;
65 0           $response->{servers}->{$serverport}->{description} = $description;
66            
67 0           $response->{servers}->{$serverport}->{numplayers} = $playerSize;
68 0           $response->{servers}->{$serverport}->{roguesize} = $info{rogueSize};
69 0           $response->{servers}->{$serverport}->{redsize} = $info{redSize};
70 0           $response->{servers}->{$serverport}->{greensize} = $info{greenSize};
71 0           $response->{servers}->{$serverport}->{bluesize} = $info{blueSize};
72 0           $response->{servers}->{$serverport}->{purplesize} = $info{purpleSize};
73 0           $response->{servers}->{$serverport}->{observersize} = $info{observerSize};
74              
75 0           $response->{servers}->{$serverport}->{serverconfig}->{style} = $self->parsestyle($info{style});
76 0           $response->{servers}->{$serverport}->{serverconfig}->{maxshots} = $info{maxShots};
77 0           $response->{servers}->{$serverport}->{serverconfig}->{shakewins} = $info{shakeWins};
78 0           $response->{servers}->{$serverport}->{serverconfig}->{shaketimeout} = $info{shakeTimeout} / 10;
79 0           $response->{servers}->{$serverport}->{serverconfig}->{maxplayerscore} = $info{maxPlayerScore};
80 0           $response->{servers}->{$serverport}->{serverconfig}->{maxteamscore} = $info{maxTeamScore};
81 0           $response->{servers}->{$serverport}->{serverconfig}->{maxtime} = $info{maxTime};
82 0           $response->{servers}->{$serverport}->{serverconfig}->{maxplayers} = $info{maxPlayers};
83 0           $response->{servers}->{$serverport}->{serverconfig}->{roguemax} = $info{rogueMax};
84 0           $response->{servers}->{$serverport}->{serverconfig}->{redmax} = $info{redMax};
85 0           $response->{servers}->{$serverport}->{serverconfig}->{greenmax} = $info{greenMax};
86 0           $response->{servers}->{$serverport}->{serverconfig}->{bluemax} = $info{blueMax};
87 0           $response->{servers}->{$serverport}->{serverconfig}->{purplemax} = $info{purpleMax};
88 0           $response->{servers}->{$serverport}->{serverconfig}->{observermax} = $info{observerMax};
89              
90 0           $totalServers += 1;
91 0           $totalPlayers += $playerSize;
92             }
93 0           $response->{totalservers} = $totalServers;
94 0           $response->{totalplayers} = $totalPlayers;
95              
96 0           return ($response);
97              
98             }
99              
100             sub queryserver(%) {
101 0     0 1   my $self = shift;
102              
103 0           my %options;
104 0           while (my @option = splice(@_, 0, 2)) {
105 0           $options{$option[0]} = $option[1];
106             }
107              
108 0           my $hostandport = $options{Server};
109 0           my $timeout = $options{Timeout};
110              
111 0           my @teamName = ("X", "R", "G", "B", "P", "O", "H");
112             # my @teamName = ("X", "R", "G", "B", "P");
113 0           my ($message, $server);
114 0           my $response;
115 0           my ($servername, $port) = split(/:/, $hostandport);
116 0 0         $port = 5154 unless $port;
117            
118             # socket define
119 0           my $sockaddr = 'S n a4 x8';
120            
121             # port to port number
122 0           my ($name,$aliases,$proto) = getprotobyname('tcp');
123 0 0         ($name,$aliases,$port) = getservbyname($port,'tcp') unless $port =~ /^\d+$/;
124            
125             # get server address
126 0           my ($type,$len,$serveraddr);
127 0           ($name,$aliases,$type,$len,$serveraddr) = gethostbyname($servername);
128 0           $server = pack($sockaddr, AF_INET, $port, $serveraddr);
129            
130             # connect
131 0 0         unless (socket(S, AF_INET, SOCK_STREAM, $proto)) {
132 0           $self->{error} = 'errSocketError';
133 0           return undef;
134             }
135              
136 0 0         unless (connect(S, $server)) {
137 0           $self->{error} = "errCouldNotConnect: $servername:$port";
138 0           return undef;
139             }
140            
141             # don't buffer
142 0           select(S); $| = 1; select(STDOUT);
  0            
  0            
143            
144             # get hello
145 0           my $buffer;
146 0 0         unless (read(S, $buffer, 9) == 9) {
147 0           $self->{error} = 'errReadError';
148 0           return undef;
149             }
150              
151             # parse reply
152 0           my ($magic, $version, $id) = unpack("a4 a4 C1", $buffer);
153            
154             # quit if version isn't valid
155 0 0         if ($magic ne "BZFS") {
156 0           $self->{error} = 'errNotABzflagServer';
157 0           return undef;
158             }
159              
160             # try incompatible for 1.7, etc.
161 0 0         if ($version != '1910') {
162 0           $self->{error} = 'errIncompatibleVersion';
163 0           return undef;
164             }
165            
166             # send game request
167 0           print S pack("n2", 0, 0x7167);
168            
169             # get reply
170 0 0         unless (read(S, $buffer, 40) == 40) {
171 0           $self->{error} = 'errServerReadError';
172 0           return undef;
173             }
174              
175 0           my ($infolen,$infocode,$style,$maxPlayers,$maxShots,
176             $rogueSize,$redSize,$greenSize,$blueSize,$purpleSize,
177             $rogueMax,$redMax,$greenMax,$blueMax,$purpleMax,
178             $shakeWins,$shakeTimeout,
179             $maxPlayerScore,$maxTeamScore,$maxTime) = unpack("n20", $buffer);
180              
181 0 0         unless ($infocode == 0x7167) {
182 0           $self->{error} = 'errBadServerData';
183 0           return undef;
184             }
185              
186 0           $response->{serverconfig}->{style} = $self->parsestyle($style);
187              
188 0           $response->{serverconfig}->{maxplayers} = $maxPlayers;
189 0           $response->{serverconfig}->{maxshots} = $maxShots;
190 0           $response->{serverconfig}->{roguemax} = $rogueMax;
191 0           $response->{serverconfig}->{redmax} = $redMax;
192 0           $response->{serverconfig}->{greenmax} = $greenMax;
193 0           $response->{serverconfig}->{bluemax} = $blueMax;
194 0           $response->{serverconfig}->{purplemax} = $purpleMax;
195 0           $response->{serverconfig}->{shakewins} = $shakeWins;
196 0           $response->{serverconfig}->{shaketimeout} = $shakeTimeout;
197 0           $response->{serverconfig}->{maxplayerscore} = $maxPlayerScore;
198 0           $response->{serverconfig}->{maxteamscore} = $maxTeamScore;
199 0           $response->{serverconfig}->{maxtime} = $maxTime;
200              
201             # send players request
202 0           print S pack("n2", 0, 0x7170);
203            
204             # get number of teams and players we'll be receiving
205 0 0         unless (read(S, $buffer, 8) == 8) {
206 0           $self->{error} = 'errCountReadError';
207 0           return undef;
208             }
209              
210 0           my ($countlen,$countcode,$numTeams,$numPlayers) = unpack("n4", $buffer);
211 0 0         unless ($countcode == 0x7170) {
212 0           $self->{error} = 'errBadCountData';
213 0           return undef;
214             }
215              
216 0           $response->{numplayers} = $numPlayers;
217              
218 0 0         unless (read(S, $buffer, 5) == 5) {
219 0           $self->{error} = 'errCountReadError';
220 0           return undef;
221             }
222              
223 0           my ($countlen2, $countcode2, $numTeams2) = unpack("n2 C", $buffer);
224 0 0         unless ($countcode2 == 0x7475) {
225 0           $self->{error} = 'errBadCountData';
226 0           return undef;
227             }
228              
229 0           $response->{numteams} = $numTeams2;
230              
231             # get the teams
232 0           for (1..$numTeams2) {
233 0 0         unless (read(S, $buffer, 8) == 8) {
234 0           $self->{error} = 'errTeamReadError';
235 0           return undef;
236             }
237              
238 0           my ($team, $size, $wins, $losses) = unpack("n4", $buffer);
239              
240 0           my $score = $wins - $losses;
241              
242 0           $response->{teams}->{$teamName[$team]}->{size} = $size;
243 0           $response->{teams}->{$teamName[$team]}->{score} = $score;
244 0           $response->{teams}->{$teamName[$team]}->{wins} = $wins;
245 0           $response->{teams}->{$teamName[$team]}->{losses} = $losses;
246            
247             }
248            
249             # get the players
250 0           for (1..$numPlayers) {
251 0 0         next unless (read(S, $buffer, 175) == 175);
252 0           my ($len, $code, $pID, $type, $team, $wins, $losses, $tks, $callsign, $email) =
253             unpack("n2 C n5 A32 A128", $buffer);
254              
255 0 0         unless ($code == 0x6170) {
256 0           $self->{error} = 'errBadPlayerData';
257 0           return undef;
258             }
259              
260 0           my $score = $wins - $losses;
261              
262 0           $response->{players}->{$callsign}->{team} = $teamName[$team];
263 0           $response->{players}->{$callsign}->{email} = $email;
264 0           $response->{players}->{$callsign}->{score} = $score;
265 0           $response->{players}->{$callsign}->{wins} = $wins;
266 0           $response->{players}->{$callsign}->{losses} = $losses;
267 0           $response->{players}->{$callsign}->{tks} = $tks;
268 0           $response->{players}->{$callsign}->{pID} = $pID;
269              
270             }
271 0 0         if ($numPlayers <= 1) {
272 0           $self->{error} = 'errNoPlayers';
273 0           return undef;
274             }
275            
276             # close socket
277 0           close(S);
278            
279 0           return $response;
280              
281             }
282              
283             sub parsestyle ($) {
284 0     0 1   my $self = shift;
285 0           my $style = shift;
286              
287 0           my $response;
288              
289 0 0         if ($style & 0x0001) {
290 0           $response->{ctf} = 1;
291             } else {
292 0           $response->{ctf} = 0;
293             }
294            
295 0 0         if ($style & 0x0002) {
296 0           $response->{superflags} = 1;
297             } else {
298 0           $response->{superflags} = 0;
299             }
300            
301 0 0         if ($style & 0x0004) {
302 0           $response->{rogues} = 1;
303             } else {
304 0           $response->{rogues} = 0;
305             }
306            
307 0 0         if ($style & 0x0008) {
308 0           $response->{jumping} = 1;
309             } else {
310 0           $response->{jumping} = 0;
311             }
312            
313 0 0         if ($style & 0x0010) {
314 0           $response->{inertia} = 1;
315             } else {
316 0           $response->{inertia} = 0;
317             }
318            
319 0 0         if ($style & 0x0020) {
320 0           $response->{ricochet} = 1;
321             } else {
322 0           $response->{ricochet} = 0;
323             }
324            
325 0 0         if ($style & 0x0040) {
326 0           $response->{shakable} = 1;
327             } else {
328 0           $response->{shakable} = 0;
329             }
330            
331 0 0         if ($style & 0x0080) {
332 0           $response->{antidoteflags} = 1;
333             } else {
334 0           $response->{antidoteflags} = 0;
335             }
336            
337 0 0         if ($style & 0x0100) {
338 0           $response->{timesync} = 1;
339             } else {
340 0           $response->{timesync} = 0;
341             }
342            
343 0 0         if ($style & 0x0200) {
344 0           $response->{rabbitchase} = 1;
345             } else {
346 0           $response->{rabbitchase} = 0;
347             }
348              
349 0           return $response;
350             }
351              
352             sub geterror {
353 0     0 0   my $self = shift;
354 0           return $self->{error};
355             }
356              
357             sub listserver {
358 0     0 0   my $self = shift;
359 0           return "http://list.bzflag.bz/db/";
360             }
361              
362             1;
363              
364             __END__