File Coverage

blib/lib/Net/BitTorrent/Util.pm
Criterion Covered Total %
statement 79 79 100.0
branch 46 48 95.8
condition 14 15 93.3
subroutine 11 11 100.0
pod 4 4 100.0
total 154 157 98.0


line stmt bran cond sub pod time code
1             #!/usr/bin/perl -w
2             package Net::BitTorrent::Util;
3             {
4 13     13   736619 use strict;
  13         42  
  13         750  
5 13     13   72 use warnings;
  13         24  
  13         453  
6 13     13   69 use Carp qw[carp];
  13         25  
  13         770  
7 13     13   66 use List::Util qw[min max shuffle sum];
  13         20  
  13         1245  
8 13     13   70 use version qw[qv];
  13         24  
  13         133  
9             our $VERSION_BASE = 50; our $UNSTABLE_RELEASE = 0; our $VERSION = sprintf(($UNSTABLE_RELEASE ? q[%.3f_%03d] : q[%.3f]), (version->new(($VERSION_BASE))->numify / 1000), $UNSTABLE_RELEASE);
10 13     13   1724 use vars qw[@EXPORT_OK %EXPORT_TAGS];
  13         26  
  13         749  
11 13     13   69 use Exporter qw[];
  13         46  
  13         15159  
12             *import = *import = *Exporter::import;
13             @EXPORT_OK = qw[bencode bdecode compact uncompact];
14             %EXPORT_TAGS = (all => [@EXPORT_OK],
15             bencode => [qw[bencode bdecode]],
16             compact => [qw[compact uncompact]],
17             );
18              
19             sub bencode {
20 5129     5129 1 120752 my ($ref) = @_;
21 5129 100       9936 $ref = defined $ref ? $ref : q[];
22 5129 100       17202 if (not ref $ref) {
    100          
    100          
23 4221 100 66     70842 return ( (defined $ref and $ref =~ m[^[-+]?\d+$])
24             ? (q[i] . $ref . q[e])
25             : (length($ref) . q[:] . $ref)
26             );
27             }
28             elsif (ref $ref eq q[ARRAY]) {
29 209         325 return join(q[], q[l], (map { bencode($_) } @{$ref}), q[e]);
  320         1008  
  209         894  
30             }
31             elsif (ref $ref eq q[HASH]) {
32             return
33 2213         4865 join(q[], q[d],
34 697         4554 (map { bencode($_) . bencode($ref->{$_}) }
35 697         1090 sort keys %{$ref}
36             ),
37             q[e]
38             );
39             }
40 2         10 return q[];
41             }
42              
43             sub bdecode {
44 10675     10675 1 18762 my ($string) = @_;
45 10675 100       24155 return if not defined $string;
46 10674         16091 my ($return, $leftover);
47 10674 100 100     83070 if ( $string =~ m[^([1-9]\d*):]s
    100          
    100          
    100          
48             or $string =~ m[^(0+):]s)
49 8605         16868 { my $size = $1;
50 8605 100       28246 $return = q[] if $1 =~ m[^0+$];
51 8605         116893 $string =~ s|^$size:||s;
52 8605         23535 while ($size) {
53 8598         28749 my $this_time = min($size, 32766);
54 8598         142853 $string =~ s|^(.{$this_time})||s;
55 8598 100       30522 return if not $1;
56 8597         15260 $return .= $1;
57 8597         56186 $size = max(0, ($size - $this_time));
58             }
59 8604 100       49771 return wantarray ? ($return, $string) : $return; # byte string
60             }
61             elsif ($string =~ s|^i([-+]?\d+)e||s) { # integer
62 407 100       2421 return wantarray ? (int($1), $string) : int($1);
63             }
64             elsif ($string =~ s|^l(.*)||s) { # list
65 246         970 $leftover = $1;
66 246   100     4986 while ($leftover and $leftover !~ s|^e||s) {
67 367         854 (my ($piece), $leftover) = bdecode($leftover);
68 367         2899 push @$return, $piece;
69             }
70 246 100       1730 return wantarray ? (\@$return, $leftover) : \@$return;
71             }
72             elsif ($string =~ s|^d(.*)||s) { # dictionary
73 1405         3764 $leftover = $1;
74 1405   100     8111 while ($leftover and $leftover !~ s|^e||s) {
75 4804         6187 my ($key, $value);
76 4804         11196 ($key, $leftover) = bdecode($leftover);
77 4804 50       16695 ($value, $leftover) = bdecode($leftover) if $leftover;
78 4804 50       50411 $return->{$key} = $value if defined $key;
79             }
80 1405 100       7813 return wantarray ? (\%$return, $leftover) : \%$return;
81             }
82 11         71 return;
83             }
84              
85             sub compact {
86 206     206 1 739 my (@peers) = @_;
87 206 100       745 if (not @peers) {return}
  62         350  
88 144         471 my $return;
89             my %seen;
90 144   100     2505 PEER: for my $peer (grep(defined && !$seen{$_}++, @peers)) {
91 455 100       1000 next if not $peer;
92 454         1485 my ($ip, $port) = split(q[:], $peer, 2);
93 454 100       4036 if ($peer
    100          
94             !~ m[^(?:(?:(?:25[0-5]|2[0-4][0-9]|[0-1]?[0-9]{1,2})[.]?){4}):\d+$]
95             )
96 5         742 { carp q[Invalid IP address: ] . $peer;
97             }
98             elsif ($port > 2**16) {
99 1         97 carp q[Port number beyond ephemeral range: ] . $peer;
100             }
101             else {
102 448         4447 $return .= pack q[C4n],
103             ($ip =~ m[^([\d]+)\.([\d]+)\.([\d]+)\.([\d]+)$]),
104             int $port;
105             }
106             }
107 144         1031 return $return;
108             }
109              
110             sub uncompact {
111 198     198 1 2196 my $string = shift;
112 198 100       872 if (not defined $string) { return; }
  14         54  
113 184         324 my %peers;
114 184         1303 while ($string =~ m|(....)(..)|g) {
115             $peers{
116 574         6020 sprintf(q[%d.%d.%d.%d:%d],
117             unpack(q[C4], $1),
118             unpack(q[n], $2))
119             }++;
120             }
121 184 100       4052 return (shuffle(%peers ? keys %peers : ()));
122             }
123             1;
124             }
125              
126             =pod
127              
128             =head1 NAME
129              
130             Net::BitTorrent::Util - BitTorrent Related Utility Functions
131              
132             =head1 Importing From Net::BitTorrent::Util
133              
134             By default, nothing is exported.
135              
136             You may import any of the following or use one or more of these tags:
137              
138             =over 2
139              
140             =item C<:all>
141              
142             Everything is imported into your namespace.
143              
144             =item C<:bencode>
145              
146             You get the two Bencode-related functions: L
147             and L. For more on Bencoding, see the
148             BitTorrent Protocol documentation.
149              
150             =item C<:compact>
151              
152             Imports the tracker response-related functions
153             L and L.
154              
155             =back
156              
157             =head1 Functions
158              
159             =over 4
160              
161             =item C
162              
163             Expects a single value (basic scalar, array reference, or hash
164             reference) and returns a single string.
165              
166             Bencoding is the BitTorrent protocol's basic serialization and
167             data organization format. The specification supports integers,
168             lists (arrays), dictionaries (hashes), and byte strings.
169              
170             =item C
171              
172             Expects a bencoded string. The return value depends on the type of
173             data contained in the string.
174              
175             =item C
176              
177             Compacts a list of IPv4:port strings into a single string.
178              
179             A compact peer is 6 bytes; the first four bytes are the host (in network
180             byte order), the last two bytes are the port (again, in network byte
181             order).
182              
183             =item C
184              
185             Inflates a compacted string of peers and returns a list of IPv4:port
186             strings.
187              
188             =back
189              
190             =head1 See Also
191              
192             =over
193              
194             =item The BitTorrent Protocol Specification
195              
196             http://bittorrent.org/beps/bep_0003.html#the-connectivity-is-as-follows
197              
198             =item BEP 32: Tracker Returns Compact Peer Lists
199              
200             http://bittorrent.org/beps/bep_0023.html
201              
202             =item Other Bencode related modules:
203              
204             =over
205              
206             =item L
207              
208             =item L
209              
210             =item L
211              
212             =back
213              
214             =back
215              
216             =head1 Author
217              
218             Sanko Robinson - http://sankorobinson.com/
219              
220             CPAN ID: SANKO
221              
222             =head1 License and Legal
223              
224             Copyright (C) 2008-2009 by Sanko Robinson Esanko@cpan.orgE
225              
226             This program is free software; you can redistribute it and/or modify
227             it under the terms of The Artistic License 2.0. See the F
228             file included with this distribution or
229             http://www.perlfoundation.org/artistic_license_2_0. For
230             clarification, see http://www.perlfoundation.org/artistic_2_0_notes.
231              
232             When separated from the distribution, all POD documentation is covered
233             by the Creative Commons Attribution-Share Alike 3.0 License. See
234             http://creativecommons.org/licenses/by-sa/3.0/us/legalcode. For
235             clarification, see http://creativecommons.org/licenses/by-sa/3.0/us/.
236              
237             Neither this module nor the L is affiliated with
238             BitTorrent, Inc.
239              
240             =for svn $Id: Util.pm 07f0c35 2010-04-02 18:31:29Z sanko@cpan.org $
241              
242             =cut