File Coverage

blib/lib/Net/BitTorrent/Protocol/BEP55.pm
Criterion Covered Total %
statement 20 20 100.0
branch n/a
condition n/a
subroutine 7 7 100.0
pod n/a
total 27 27 100.0


line stmt bran cond sub pod time code
1 20     20   273 use v5.40;
  20         75  
2 20     20   134 use feature 'class', 'try';
  20         45  
  20         2833  
3 20     20   228 no warnings 'experimental::class', 'experimental::try';
  20         48  
  20         2348  
4 20     20   10387 class Net::BitTorrent::Protocol::BEP55 v2.0.0 : isa(Net::BitTorrent::Protocol::BEP11) {
  20         68  
  20         1417  
5 20     20   144 use Net::BitTorrent::Protocol::BEP03::Bencode qw[bencode bdecode];
  20         38  
  20         1256  
6 20     20   128 use Net::BitTorrent::Protocol::BEP23;
  20         37  
  20         581  
7              
8             # BEP 55 Message IDs (internal to ut_holepunch)
9 20     20   113 use constant { HP_RENDEZVOUS => 0, HP_CONNECT => 1, HP_ERROR => 2, };
  20         44  
  20         18204  
10             ADJUST {
11             $self->on(
12             extended_message => sub ( $self, $name, $payload ) {
13             return unless $name eq 'ut_holepunch';
14             my $type = unpack( 'C', substr( $payload, 0, 1, '' ) );
15             my $dict;
16             try {
17             my @res = bdecode( $payload, 1 );
18             if ( @res > 2 ) {
19             pop @res; # Discard leftover
20             $dict = {@res};
21             }
22             else {
23             $dict = $res[0];
24             }
25             }
26             catch ($e) {
27             $self->_emit( log => " [ERROR] Malformed ut_holepunch message: $e\n", level => 'error' );
28             return;
29             }
30             if ( ref $dict ne 'HASH' ) {
31             $self->_emit( log => " [ERROR] Malformed ut_holepunch message: dict is not a hash\n", level => 'error' );
32             return;
33             }
34             if ( $type == HP_RENDEZVOUS ) {
35             $self->_emit( hp_rendezvous => $dict->{id} );
36             }
37             elsif ( $type == HP_CONNECT ) {
38             $self->_emit( hp_connect => $dict->{addr}, $dict->{port} );
39             }
40             elsif ( $type == HP_ERROR ) {
41             $self->_emit( hp_error => $dict->{e} );
42             }
43             }
44             );
45             }
46              
47             method send_hp_rendezvous ($target_id) {
48             return unless exists $self->remote_extensions->{ut_holepunch};
49             my $payload = bencode( { id => $target_id, } );
50             $self->send_ext_message( 'ut_holepunch', pack( 'C a*', HP_RENDEZVOUS, $payload ) );
51             }
52              
53             method send_hp_connect ( $ip, $port ) {
54             return unless exists $self->remote_extensions->{ut_holepunch};
55             my $payload = bencode( { addr => $ip, port => $port, } );
56             $self->send_ext_message( 'ut_holepunch', pack( 'C a*', HP_CONNECT, $payload ) );
57             }
58              
59             method send_hp_error ($err_code) {
60             return unless exists $self->remote_extensions->{ut_holepunch};
61             my $payload = bencode( { e => $err_code, } );
62             $self->send_ext_message( 'ut_holepunch', pack( 'C a*', HP_ERROR, $payload ) );
63             }
64             } 1;