AnyEvent-BitTorrent
view release on metacpan or search on metacpan
lib/AnyEvent/BitTorrent.pm view on Meta::CPAN
($_->[0] != $index)
|| ($_->[1] != $offset)
|| ($_->[2] != $length)
} @{$s->peers->{$h}{local_requests}}
];
$s->peers->{$h}{timeout}
= AE::timer(30, 0, sub { $s->_del_peer($h) });
}
elsif ($packet->{type} == $ALLOWED_FAST) {
push @{$s->peers->{$h}{local_allowed}}, $packet->{payload};
}
else {
# use Data::Dump qw[pp];
# die 'Unhandled packet: ' . pp $packet;
}
last
if 5 > length($h->rbuf // ''); # Min size for protocol
}
}
sub _send_bitfield {
my ($s, $h) = @_;
if (vec($s->peers->{$h}{reserved}, 7, 1) & 0x04) {
if ($s->seed) {
return $s->_send_encrypted($h, build_haveall());
}
elsif ($s->bitfield() !~ m[[^\0]]) {
return $s->_send_encrypted($h, build_havenone());
}
}
# XXX - If it's cheaper to send HAVE packets than a full BITFIELD, do it
$s->_send_encrypted($h, build_bitfield($s->bitfield));
}
sub _broadcast {
my ($s, $data, $qualifier) = @_;
$qualifier //= sub {1};
$s->_send_encrypted($_->{handle}, $data)
for grep { $qualifier->() } values %{$s->peers};
}
sub _consider_peer { # Figure out whether or not we find a peer interesting
my ($s, $p) = @_;
return if $s->state ne 'active';
return if $s->complete;
my $relevence = $p->{bitfield} & $s->wanted;
my $interesting
= (
index(substr(unpack('b*', $relevence), 0, $s->piece_count + 1), 1, 0)
!= -1) ? 1 : 0;
if ($interesting) {
if (!$p->{local_interested}) {
$p->{local_interested} = 1;
$s->_send_encrypted($p->{handle}, build_interested());
}
}
else {
if ($p->{local_interested}) {
$p->{local_interested} = 0;
$s->_send_encrypted($p->{handle}, build_not_interested());
}
}
}
has working_pieces => (is => 'ro',
lazy => 1,
isa => HashRef,
init_arg => undef,
default => sub { {} }
);
sub _file_to_range {
my ($s, $file) = @_;
my $start = 0;
for (0 .. $file - 1) {
$start += $s->files->[$_]->{length};
}
my $end = $start + $s->files->[$file]->{length};
$start = $start / $s->piece_length;
$end = $end / $s->piece_length;
(int($start) .. int $end + ($end != int($end) ? 0 : +1));
}
sub _request_pieces {
my ($s, $p) = @_;
return if $s->state ne 'active';
weaken $p unless isweak $p;
$p // return;
$p->{handle} // return;
my @indexes;
if (scalar keys %{$s->working_pieces} < 10) { # XXX - Max working pieces
for my $findex (0 .. $#{$s->files}) {
for my $index ($s->_file_to_range($findex)) {
next
if !(vec($p->{bitfield}, $index, 1)
&& !vec($s->bitfield, $index, 1));
push @indexes,
map {$index} 1 .. $s->{files}[$findex]{priority};
}
}
}
else {
@indexes = keys %{$s->working_pieces};
}
return if !@indexes;
my $index = $indexes[rand @indexes]; # XXX - Weighted random/Rarest first
my $piece_size
= $index == $s->piece_count ?
$s->size % $s->piece_length
: $s->piece_length;
my $block_count = $piece_size / $block_size;
my @offsets = map { $_ * $block_size }
0 .. $block_count - ((int($block_count) == $block_count) ? 1 : 0);
$s->working_pieces->{$index} //= {map { $_ => {} } @offsets};
my @unrequested = sort { $a <=> $b }
grep { # XXX - If there are no unrequested blocks, pick a new index
(!ref $s->working_pieces->{$index}{$_})
|| ( (!defined $s->working_pieces->{$index}{$_}[4])
&& (!defined $s->working_pieces->{$index}{$_}[3]))
} @offsets;
my @unfilled_local_requests
( run in 0.880 second using v1.01-cache-2.11-cpan-cdf2f3d4e48 )