| line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
|
1
|
23
|
|
|
23
|
|
233096
|
use v5.40; |
|
|
23
|
|
|
|
|
89
|
|
|
2
|
23
|
|
|
23
|
|
191
|
use feature 'class', 'try'; |
|
|
23
|
|
|
|
|
66
|
|
|
|
23
|
|
|
|
|
3210
|
|
|
3
|
23
|
|
|
23
|
|
1299
|
no warnings 'experimental::class', 'experimental::try'; |
|
|
23
|
|
|
|
|
58
|
|
|
|
23
|
|
|
|
|
3796
|
|
|
4
|
23
|
|
|
23
|
|
11755
|
class Net::BitTorrent::Protocol::BEP10 v2.0.0 : isa(Net::BitTorrent::Protocol::BEP52) { |
|
|
23
|
|
|
|
|
75
|
|
|
|
23
|
|
|
|
|
1288
|
|
|
5
|
23
|
|
|
23
|
|
2023
|
use Net::BitTorrent::Protocol::BEP03::Bencode qw[bencode bdecode]; |
|
|
23
|
|
|
|
|
84
|
|
|
|
23
|
|
|
|
|
6726
|
|
|
6
|
|
|
|
|
|
|
field $local_extensions : param : reader = {}; |
|
7
|
|
|
|
|
|
|
field $remote_extensions : reader = {}; |
|
8
|
|
|
|
|
|
|
field $remote_version : reader = undef; |
|
9
|
|
|
|
|
|
|
field $remote_ip : reader = undef; |
|
10
|
|
|
|
|
|
|
field $metadata_size : param : reader = 0; |
|
11
|
|
|
|
|
|
|
field $remote_extensions_received : reader = 0; |
|
12
|
|
|
|
|
|
|
|
|
13
|
|
|
|
|
|
|
# Message ID for extended messages |
|
14
|
23
|
|
|
23
|
|
203
|
use constant EXTENDED => 20; |
|
|
23
|
|
|
|
|
44
|
|
|
|
23
|
|
|
|
|
36934
|
|
|
15
|
|
|
|
|
|
|
|
|
16
|
|
|
|
|
|
|
method send_ext_handshake () { |
|
17
|
|
|
|
|
|
|
my $data = { m => $local_extensions, v => 'Net::BitTorrent ' . ( $Net::BitTorrent::VERSION // $Net::BitTorrent::Protocol::BEP10::VERSION ) }; |
|
18
|
|
|
|
|
|
|
$data->{metadata_size} = $metadata_size if $metadata_size > 0; |
|
19
|
|
|
|
|
|
|
my $payload = bencode($data); |
|
20
|
|
|
|
|
|
|
$self->send_message( EXTENDED, pack( 'C a*', 0, $payload ) ); |
|
21
|
|
|
|
|
|
|
} |
|
22
|
|
|
|
|
|
|
|
|
23
|
|
|
|
|
|
|
method send_ext_message ( $name, $payload ) { |
|
24
|
|
|
|
|
|
|
my $id = $remote_extensions->{$name}; |
|
25
|
|
|
|
|
|
|
if ( !defined $id ) { |
|
26
|
|
|
|
|
|
|
$self->_emit( log => "Remote does not support extension: $name", level => 'fatal' ); |
|
27
|
|
|
|
|
|
|
return; |
|
28
|
|
|
|
|
|
|
} |
|
29
|
|
|
|
|
|
|
$self->send_message( EXTENDED, pack( 'C a*', $id, $payload ) ); |
|
30
|
|
|
|
|
|
|
} |
|
31
|
|
|
|
|
|
|
|
|
32
|
|
|
|
|
|
|
method _handle_message ( $id, $payload ) { |
|
33
|
|
|
|
|
|
|
if ( $id == EXTENDED ) { |
|
34
|
|
|
|
|
|
|
return if length($payload) < 1; |
|
35
|
|
|
|
|
|
|
my $ext_id = unpack( 'C', substr( $payload, 0, 1, '' ) ); |
|
36
|
|
|
|
|
|
|
if ( $ext_id == 0 ) { |
|
37
|
|
|
|
|
|
|
$self->_handle_ext_handshake($payload); |
|
38
|
|
|
|
|
|
|
} |
|
39
|
|
|
|
|
|
|
else { |
|
40
|
|
|
|
|
|
|
my $name = $self->_lookup_local_extension($ext_id); |
|
41
|
|
|
|
|
|
|
if ($name) { |
|
42
|
|
|
|
|
|
|
$self->_emit( extended_message => $name, $payload ); |
|
43
|
|
|
|
|
|
|
} |
|
44
|
|
|
|
|
|
|
else { |
|
45
|
|
|
|
|
|
|
$self->_emit( log => " [DEBUG] Received unknown extended message ID: $ext_id\n", level => 'debug' ) if $self->debug; |
|
46
|
|
|
|
|
|
|
} |
|
47
|
|
|
|
|
|
|
} |
|
48
|
|
|
|
|
|
|
} |
|
49
|
|
|
|
|
|
|
else { |
|
50
|
|
|
|
|
|
|
$self->SUPER::_handle_message( $id, $payload ); |
|
51
|
|
|
|
|
|
|
} |
|
52
|
|
|
|
|
|
|
} |
|
53
|
|
|
|
|
|
|
|
|
54
|
|
|
|
|
|
|
method _handle_ext_handshake ($payload) { |
|
55
|
|
|
|
|
|
|
my $data; |
|
56
|
|
|
|
|
|
|
try { |
|
57
|
|
|
|
|
|
|
my @res = bdecode( $payload, 1 ); |
|
58
|
|
|
|
|
|
|
if ( @res > 2 ) { # Dictionary returned as key-value list + leftover |
|
59
|
|
|
|
|
|
|
pop @res; # Discard leftover |
|
60
|
|
|
|
|
|
|
$data = {@res}; |
|
61
|
|
|
|
|
|
|
} |
|
62
|
|
|
|
|
|
|
else { |
|
63
|
|
|
|
|
|
|
$data = $res[0]; |
|
64
|
|
|
|
|
|
|
} |
|
65
|
|
|
|
|
|
|
} |
|
66
|
|
|
|
|
|
|
catch ($e) { |
|
67
|
|
|
|
|
|
|
$self->_emit( log => " [ERROR] Malformed extended handshake: $e\n", level => 'error' ); |
|
68
|
|
|
|
|
|
|
return; |
|
69
|
|
|
|
|
|
|
} |
|
70
|
|
|
|
|
|
|
if ( ref $data ne 'HASH' ) { |
|
71
|
|
|
|
|
|
|
$self->_emit( log => " [ERROR] Malformed extended handshake: data is not a hash\n", level => 'error' ); |
|
72
|
|
|
|
|
|
|
return; |
|
73
|
|
|
|
|
|
|
} |
|
74
|
|
|
|
|
|
|
$remote_extensions = $data->{m} || {}; |
|
75
|
|
|
|
|
|
|
if ( $self->debug ) { |
|
76
|
|
|
|
|
|
|
$self->_emit( |
|
77
|
|
|
|
|
|
|
log => " [DEBUG] Remote extensions: " . join( ", ", map {"$_=$remote_extensions->{$_}"} keys %$remote_extensions ) . "\n", |
|
78
|
|
|
|
|
|
|
level => 'debug' |
|
79
|
|
|
|
|
|
|
); |
|
80
|
|
|
|
|
|
|
} |
|
81
|
|
|
|
|
|
|
$remote_version = $data->{v} if exists $data->{v}; |
|
82
|
|
|
|
|
|
|
$remote_ip = $data->{yourip} if exists $data->{yourip}; |
|
83
|
|
|
|
|
|
|
$metadata_size = $data->{metadata_size} if exists $data->{metadata_size}; |
|
84
|
|
|
|
|
|
|
$remote_extensions_received = 1; |
|
85
|
|
|
|
|
|
|
$self->_emit( ext_handshake => $data ); |
|
86
|
|
|
|
|
|
|
} |
|
87
|
|
|
|
|
|
|
|
|
88
|
|
|
|
|
|
|
method _lookup_local_extension ($id) { |
|
89
|
|
|
|
|
|
|
for my $name ( keys %$local_extensions ) { |
|
90
|
|
|
|
|
|
|
return $name if $local_extensions->{$name} == $id; |
|
91
|
|
|
|
|
|
|
} |
|
92
|
|
|
|
|
|
|
return undef; |
|
93
|
|
|
|
|
|
|
} |
|
94
|
|
|
|
|
|
|
|
|
95
|
|
|
|
|
|
|
method _lookup_remote_extension ($id) { |
|
96
|
|
|
|
|
|
|
for my $name ( keys %$remote_extensions ) { |
|
97
|
|
|
|
|
|
|
return $name if $remote_extensions->{$name} == $id; |
|
98
|
|
|
|
|
|
|
} |
|
99
|
|
|
|
|
|
|
return undef; |
|
100
|
|
|
|
|
|
|
} |
|
101
|
|
|
|
|
|
|
} 1; |