added support for pieces, verified pieces and piece_priorities in new resume data scheme
This commit is contained in:
parent
a60bbe0a1c
commit
6223057b1e
|
@ -45,6 +45,7 @@ POSSIBILITY OF SUCH DAMAGE.
|
||||||
#include "libtorrent/peer_id.hpp" // sha1_hash
|
#include "libtorrent/peer_id.hpp" // sha1_hash
|
||||||
#include "libtorrent/version.hpp"
|
#include "libtorrent/version.hpp"
|
||||||
#include "libtorrent/socket.hpp" // for tcp::endpoint
|
#include "libtorrent/socket.hpp" // for tcp::endpoint
|
||||||
|
#include "libtorrent/bitfield.hpp"
|
||||||
|
|
||||||
namespace libtorrent
|
namespace libtorrent
|
||||||
{
|
{
|
||||||
|
@ -440,9 +441,33 @@ namespace libtorrent
|
||||||
std::vector<std::string> http_seeds;
|
std::vector<std::string> http_seeds;
|
||||||
std::vector<std::string> url_seeds;
|
std::vector<std::string> url_seeds;
|
||||||
|
|
||||||
|
// peers to add to the torrent, to be tried to be connected to as
|
||||||
|
// bittorrent peers.
|
||||||
std::vector<tcp::endpoint> peers;
|
std::vector<tcp::endpoint> peers;
|
||||||
|
|
||||||
|
// peers banned from this torrent. The will not be connected to
|
||||||
std::vector<tcp::endpoint> banned_peers;
|
std::vector<tcp::endpoint> banned_peers;
|
||||||
|
|
||||||
|
// this is a map of partially downloaded piece. The key is the piece index
|
||||||
|
// and the value is a bitfield where each bit represents a 16 kiB block.
|
||||||
|
// A set bit means we have that block.
|
||||||
|
std::map<int, bitfield> unfinished_pieces;
|
||||||
|
|
||||||
|
// this is a bitfield indicating which pieces we already have of this
|
||||||
|
// torrent.
|
||||||
|
bitfield have_pieces;
|
||||||
|
|
||||||
|
// when in seed_mode, pieces with a set bit in this bitfield have been
|
||||||
|
// verified to be valid. Other pieces will be verified the first time a
|
||||||
|
// peer requests it.
|
||||||
|
bitfield verified_pieces;
|
||||||
|
|
||||||
|
// this sets the priorities for each individual piece in the torrent. Each
|
||||||
|
// element in the vector represent the piece with the same index. If you
|
||||||
|
// set both file- and piece priorities, file priorities will take
|
||||||
|
// precedence.
|
||||||
|
std::vector<boost::uint8_t> piece_priorities;
|
||||||
|
|
||||||
#ifndef TORRENT_NO_DEPRECATE
|
#ifndef TORRENT_NO_DEPRECATE
|
||||||
// The optional parameter, ``resume_data`` can be given if up to date
|
// The optional parameter, ``resume_data`` can be given if up to date
|
||||||
// fast-resume data is available. The fast-resume data can be acquired
|
// fast-resume data is available. The fast-resume data can be acquired
|
||||||
|
|
|
@ -171,6 +171,13 @@ namespace libtorrent
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void swap(bitfield& rhs)
|
||||||
|
{
|
||||||
|
boost::uint32_t* tmp = m_buf;
|
||||||
|
m_buf = rhs.m_buf;
|
||||||
|
rhs.m_buf = tmp;
|
||||||
|
}
|
||||||
|
|
||||||
// count the number of bits in the bitfield that are set to 1.
|
// count the number of bits in the bitfield that are set to 1.
|
||||||
int count() const
|
int count() const
|
||||||
{
|
{
|
||||||
|
|
|
@ -1298,6 +1298,11 @@ namespace libtorrent
|
||||||
// set if there's an error on this torrent
|
// set if there's an error on this torrent
|
||||||
error_code m_error;
|
error_code m_error;
|
||||||
|
|
||||||
|
// used if there is any resume data. Some of the information from the
|
||||||
|
// add_torrent_params struct are needed later in the torrent object's life
|
||||||
|
// cycle, and not in the constructor. So we need to save if away here
|
||||||
|
boost::scoped_ptr<add_torrent_params> m_add_torrent_params;
|
||||||
|
|
||||||
// if the torrent is started without metadata, it may
|
// if the torrent is started without metadata, it may
|
||||||
// still be given a name until the metadata is received
|
// still be given a name until the metadata is received
|
||||||
// once the metadata is received this field will no
|
// once the metadata is received this field will no
|
||||||
|
|
|
@ -240,33 +240,31 @@ namespace libtorrent
|
||||||
TORRENT_ASSERT(false);
|
TORRENT_ASSERT(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
#error add fields to add_torrent_params for these
|
|
||||||
// some sanity checking. Maybe we shouldn't be in seed mode anymore
|
// some sanity checking. Maybe we shouldn't be in seed mode anymore
|
||||||
bdecode_node pieces = rd.dict_find("pieces");
|
if (bdecode_node pieces = rd.dict_find_string("pieces"))
|
||||||
if (pieces && pieces.type() == bdecode_node::string_t
|
|
||||||
&& int(pieces.string_length()) == m_torrent_file->num_pieces())
|
|
||||||
{
|
{
|
||||||
char const* pieces_str = pieces.string_ptr();
|
char const* pieces_str = pieces.string_ptr();
|
||||||
|
ret.have_pieces.resize(pieces.string_length());
|
||||||
|
ret.verified_pieces.resize(pieces.string_length());
|
||||||
for (int i = 0, end(pieces.string_length()); i < end; ++i)
|
for (int i = 0, end(pieces.string_length()); i < end; ++i)
|
||||||
{
|
{
|
||||||
// being in seed mode and missing a piece is not compatible.
|
// being in seed mode and missing a piece is not compatible.
|
||||||
// Leave seed mode if that happens
|
// Leave seed mode if that happens
|
||||||
if ((pieces_str[i] & 1)) continue;
|
if (pieces_str[i] & 1) ret.have_pieces.set_bit(i);
|
||||||
m_seed_mode = false;
|
else ret.have_pieces.clear_bit(i);
|
||||||
break;
|
|
||||||
|
if (pieces_str[i] & 2) ret.verified_pieces.set_bit(i);
|
||||||
|
else ret.verified_pieces.clear_bit(i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bdecode_node piece_priority = rd.dict_find_string("piece_priority");
|
if (bdecode_node piece_priority = rd.dict_find_string("piece_priority"))
|
||||||
if (piece_priority && piece_priority.string_length()
|
|
||||||
== m_torrent_file->num_pieces())
|
|
||||||
{
|
{
|
||||||
char const* p = piece_priority.string_ptr();
|
char const* prio_str = piece_priority.string_ptr();
|
||||||
|
ret.piece_priorities.resize(piece_priority.string_length());
|
||||||
for (int i = 0; i < piece_priority.string_length(); ++i)
|
for (int i = 0; i < piece_priority.string_length(); ++i)
|
||||||
{
|
{
|
||||||
if (p[i] > 0) continue;
|
ret.piece_priorities[i] = prio_str[i];
|
||||||
m_seed_mode = false;
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -278,12 +276,14 @@ namespace libtorrent
|
||||||
ret.peers.push_back(read_v4_endpoint<tcp::endpoint>(ptr));
|
ret.peers.push_back(read_v4_endpoint<tcp::endpoint>(ptr));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if TORRENT_USE_IPV6
|
||||||
if (bdecode_node peers_entry = rd.dict_find_string("peers6"))
|
if (bdecode_node peers_entry = rd.dict_find_string("peers6"))
|
||||||
{
|
{
|
||||||
char const* ptr = peers_entry.string_ptr();
|
char const* ptr = peers_entry.string_ptr();
|
||||||
for (int i = 0; i < peers_entry.string_length(); i += 18)
|
for (int i = 0; i < peers_entry.string_length(); i += 18)
|
||||||
ret.peers.push_back(read_v6_endpoint<tcp::endpoint>(ptr));
|
ret.peers.push_back(read_v6_endpoint<tcp::endpoint>(ptr));
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
if (bdecode_node peers_entry = rd.dict_find_string("banned_peers"))
|
if (bdecode_node peers_entry = rd.dict_find_string("banned_peers"))
|
||||||
{
|
{
|
||||||
|
@ -292,14 +292,31 @@ namespace libtorrent
|
||||||
ret.banned_peers.push_back(read_v4_endpoint<tcp::endpoint>(ptr));
|
ret.banned_peers.push_back(read_v4_endpoint<tcp::endpoint>(ptr));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if TORRENT_USE_IPV6
|
||||||
if (bdecode_node peers_entry = rd.dict_find_string("banned_peers6"))
|
if (bdecode_node peers_entry = rd.dict_find_string("banned_peers6"))
|
||||||
{
|
{
|
||||||
char const* ptr = peers_entry.string_ptr();
|
char const* ptr = peers_entry.string_ptr();
|
||||||
for (int i = 0; i < peers_entry.string_length(); i += 18)
|
for (int i = 0; i < peers_entry.string_length(); i += 18)
|
||||||
ret.banned_peers.push_back(read_v6_endpoint<tcp::endpoint>(ptr));
|
ret.banned_peers.push_back(read_v6_endpoint<tcp::endpoint>(ptr));
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
#error read "unfinished" pieces
|
// parse unfinished pieces
|
||||||
|
if (bdecode_node unfinished_entry = rd.dict_find_list("unfinished"))
|
||||||
|
{
|
||||||
|
for (int i = 0; i < unfinished_entry.list_size(); ++i)
|
||||||
|
{
|
||||||
|
bdecode_node e = unfinished_entry.list_at(i);
|
||||||
|
if (e.type() != bdecode_node::dict_t) continue;
|
||||||
|
int piece = e.dict_find_int_value("piece", -1);
|
||||||
|
if (piece < 0) continue;
|
||||||
|
|
||||||
|
bdecode_node bitmask = e.dict_find_string("bitmask");
|
||||||
|
if (bitmask || bitmask.string_length() == 0) continue;
|
||||||
|
bitfield& bf = ret.unfinished_pieces[piece];
|
||||||
|
bf.assign(bitmask.string_ptr(), bitmask.string_length());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
|
@ -232,6 +232,11 @@ namespace libtorrent
|
||||||
atp.peers.swap(resume_data.peers);
|
atp.peers.swap(resume_data.peers);
|
||||||
atp.banned_peers.swap(resume_data.banned_peers);
|
atp.banned_peers.swap(resume_data.banned_peers);
|
||||||
|
|
||||||
|
atp.unfinished_pieces.swap(resume_data.unfinished_pieces);
|
||||||
|
atp.have_pieces.swap(resume_data.have_pieces);
|
||||||
|
atp.verified_pieces.swap(resume_data.verified_pieces);
|
||||||
|
atp.piece_priorities.swap(resume_data.piece_priorities);
|
||||||
|
|
||||||
if ((atp.flags & add_torrent_params::flag_override_resume_data) == 0)
|
if ((atp.flags & add_torrent_params::flag_override_resume_data) == 0)
|
||||||
{
|
{
|
||||||
atp.download_limit = resume_data.download_limit;
|
atp.download_limit = resume_data.download_limit;
|
||||||
|
|
161
src/torrent.cpp
161
src/torrent.cpp
|
@ -282,6 +282,9 @@ namespace libtorrent
|
||||||
// we cannot log in the constructor, because it relies on shared_from_this
|
// we cannot log in the constructor, because it relies on shared_from_this
|
||||||
// being initialized, which happens after the constructor returns.
|
// being initialized, which happens after the constructor returns.
|
||||||
|
|
||||||
|
// TODO: 3 we could probably get away with just saving a few fields here
|
||||||
|
m_add_torrent_params.reset(new add_torrent_params(p));
|
||||||
|
|
||||||
if (m_pinned)
|
if (m_pinned)
|
||||||
inc_stats_counter(counters::num_pinned_torrents);
|
inc_stats_counter(counters::num_pinned_torrents);
|
||||||
|
|
||||||
|
@ -373,29 +376,6 @@ namespace libtorrent
|
||||||
if (settings().get_bool(settings_pack::prefer_udp_trackers))
|
if (settings().get_bool(settings_pack::prefer_udp_trackers))
|
||||||
prioritize_udp_trackers();
|
prioritize_udp_trackers();
|
||||||
|
|
||||||
// --- PEERS ---
|
|
||||||
|
|
||||||
for (std::vector<tcp::endpoint>::const_iterator i = p.peers.begin()
|
|
||||||
, end(p.peers.end()); i != end; ++i)
|
|
||||||
{
|
|
||||||
add_peer(*i , peer_info::resume_data);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (std::vector<tcp::endpoint>::const_iterator i = p.banned_peers.begin()
|
|
||||||
, end(p.banned_peers.end()); i != end; ++i)
|
|
||||||
{
|
|
||||||
torrent_peer* peer = add_peer(*i, peer_info::resume_data);
|
|
||||||
if (peer) ban_peer(peer);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!p.peers.empty() || !p.banned_peers.empty())
|
|
||||||
update_want_peers();
|
|
||||||
|
|
||||||
#ifndef TORRENT_DISABLE_LOGGING
|
|
||||||
if (m_peer_list && m_peer_list->num_peers() > 0)
|
|
||||||
debug_log("resume added peers (%d)", m_peer_list->num_peers());
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if (m_torrent_file->is_valid())
|
if (m_torrent_file->is_valid())
|
||||||
{
|
{
|
||||||
m_seed_mode = (p.flags & add_torrent_params::flag_seed_mode) != 0;
|
m_seed_mode = (p.flags & add_torrent_params::flag_seed_mode) != 0;
|
||||||
|
@ -1925,26 +1905,17 @@ namespace libtorrent
|
||||||
|
|
||||||
// if we've already loaded file priorities, don't load piece priorities,
|
// if we've already loaded file priorities, don't load piece priorities,
|
||||||
// they will interfere.
|
// they will interfere.
|
||||||
#error we should get the piece priority from add_torrent_params instead
|
if (!m_seed_mode && m_add_torrent_params && m_file_priority.empty())
|
||||||
if (!m_seed_mode && m_resume_data && m_file_priority.empty())
|
|
||||||
{
|
{
|
||||||
bdecode_node piece_priority = m_resume_data->node
|
for (int i = 0; i < int(m_add_torrent_params->piece_priorities.size()); ++i)
|
||||||
.dict_find_string("piece_priority");
|
|
||||||
|
|
||||||
if (piece_priority && piece_priority.string_length()
|
|
||||||
== m_torrent_file->num_pieces())
|
|
||||||
{
|
{
|
||||||
char const* p = piece_priority.string_ptr();
|
int const prio = m_add_torrent_params->piece_priorities[i];
|
||||||
for (int i = 0; i < piece_priority.string_length(); ++i)
|
|
||||||
{
|
|
||||||
int prio = p[i];
|
|
||||||
if (!has_picker() && prio == 4) continue;
|
if (!has_picker() && prio == 4) continue;
|
||||||
need_picker();
|
need_picker();
|
||||||
m_picker->set_piece_priority(i, p[i]);
|
m_picker->set_piece_priority(i, prio);
|
||||||
}
|
}
|
||||||
update_gauge();
|
update_gauge();
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// in case file priorities were passed in via the add_torrent_params
|
// in case file priorities were passed in via the add_torrent_params
|
||||||
// and also in the case of share mode, we need to update the priorities
|
// and also in the case of share mode, we need to update the priorities
|
||||||
|
@ -1958,7 +1929,7 @@ namespace libtorrent
|
||||||
{
|
{
|
||||||
m_have_all = true;
|
m_have_all = true;
|
||||||
m_ses.get_io_service().post(boost::bind(&torrent::files_checked, shared_from_this()));
|
m_ses.get_io_service().post(boost::bind(&torrent::files_checked, shared_from_this()));
|
||||||
m_resume_data.reset();
|
m_add_torrent_params.reset();
|
||||||
update_gauge();
|
update_gauge();
|
||||||
update_state_list();
|
update_state_list();
|
||||||
return;
|
return;
|
||||||
|
@ -2093,6 +2064,7 @@ namespace libtorrent
|
||||||
|
|
||||||
inc_refcount("check_fastresume");
|
inc_refcount("check_fastresume");
|
||||||
// async_check_fastresume will gut links
|
// async_check_fastresume will gut links
|
||||||
|
#error I don't think we need to pass in any resume-data anymore, do we?
|
||||||
m_ses.disk_thread().async_check_fastresume(
|
m_ses.disk_thread().async_check_fastresume(
|
||||||
m_storage.get(), m_resume_data ? &m_resume_data->node : NULL
|
m_storage.get(), m_resume_data ? &m_resume_data->node : NULL
|
||||||
, links, boost::bind(&torrent::on_resume_data_checked
|
, links, boost::bind(&torrent::on_resume_data_checked
|
||||||
|
@ -2316,22 +2288,51 @@ namespace libtorrent
|
||||||
pause();
|
pause();
|
||||||
set_state(torrent_status::checking_files);
|
set_state(torrent_status::checking_files);
|
||||||
if (should_check_files()) start_checking();
|
if (should_check_files()) start_checking();
|
||||||
m_resume_data.reset();
|
m_add_torrent_params.reset();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
state_updated();
|
state_updated();
|
||||||
|
|
||||||
#error instead of keeping m_resume_data as a member of torrent, we'll need an \
|
if (m_add_torrent_params)
|
||||||
add_torrent_params member, to store resume_data until we need it. Unless, \
|
{
|
||||||
we don't support resume data for magnet links and URLs, that resolve later
|
// --- PEERS ---
|
||||||
|
|
||||||
|
for (std::vector<tcp::endpoint>::const_iterator i
|
||||||
|
= m_add_torrent_params->peers.begin()
|
||||||
|
, end(m_add_torrent_params->peers.end()); i != end; ++i)
|
||||||
|
{
|
||||||
|
add_peer(*i , peer_info::resume_data);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (std::vector<tcp::endpoint>::const_iterator i
|
||||||
|
= m_add_torrent_params->banned_peers.begin()
|
||||||
|
, end(m_add_torrent_params->banned_peers.end()); i != end; ++i)
|
||||||
|
{
|
||||||
|
torrent_peer* peer = add_peer(*i, peer_info::resume_data);
|
||||||
|
if (peer) ban_peer(peer);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!m_add_torrent_params->peers.empty()
|
||||||
|
|| !m_add_torrent_params->banned_peers.empty())
|
||||||
|
{
|
||||||
|
update_want_peers();
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifndef TORRENT_DISABLE_LOGGING
|
||||||
|
if (m_peer_list && m_peer_list->num_peers() > 0)
|
||||||
|
debug_log("resume added peers (%d)", m_peer_list->num_peers());
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
// only report this error if the user actually provided resume data
|
// only report this error if the user actually provided resume data
|
||||||
if ((j->error || j->ret != 0) && m_resume_data
|
if ((j->error || j->ret != 0) && m_add_torrent_params
|
||||||
&& m_ses.alerts().should_post<fastresume_rejected_alert>())
|
&& m_ses.alerts().should_post<fastresume_rejected_alert>())
|
||||||
{
|
{
|
||||||
m_ses.alerts().emplace_alert<fastresume_rejected_alert>(get_handle(), j->error.ec
|
m_ses.alerts().emplace_alert<fastresume_rejected_alert>(get_handle()
|
||||||
, resolve_filename(j->error.file), j->error.operation_str());
|
, j->error.ec
|
||||||
|
, resolve_filename(j->error.file)
|
||||||
|
, j->error.operation_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef TORRENT_DISABLE_LOGGING
|
#ifndef TORRENT_DISABLE_LOGGING
|
||||||
|
@ -2355,19 +2356,15 @@ namespace libtorrent
|
||||||
// there are either no files for this torrent
|
// there are either no files for this torrent
|
||||||
// or the resume_data was accepted
|
// or the resume_data was accepted
|
||||||
|
|
||||||
if (!j->error && m_resume_data && m_resume_data->node.type() == bdecode_node::dict_t)
|
if (!j->error && m_add_torrent_params)
|
||||||
{
|
{
|
||||||
// parse have bitmask
|
// --- PIECES ---
|
||||||
#error get this from add_torrent_params
|
|
||||||
bdecode_node pieces = m_resume_data->node.dict_find("pieces");
|
int const num_pieces = (std::min)(m_add_torrent_params->have_pieces.size()
|
||||||
if (pieces && pieces.type() == bdecode_node::string_t
|
, torrent_file().num_pieces());
|
||||||
&& int(pieces.string_length()) == m_torrent_file->num_pieces())
|
for (int i = 0; i < num_pieces; ++i)
|
||||||
{
|
|
||||||
char const* pieces_str = pieces.string_ptr();
|
|
||||||
for (int i = 0, end(pieces.string_length()); i < end; ++i)
|
|
||||||
{
|
|
||||||
if (pieces_str[i] & 1)
|
|
||||||
{
|
{
|
||||||
|
if (m_add_torrent_params->have_pieces[i] == false) continue;
|
||||||
need_picker();
|
need_picker();
|
||||||
m_picker->we_have(i);
|
m_picker->we_have(i);
|
||||||
inc_stats_counter(counters::num_piece_passed);
|
inc_stats_counter(counters::num_piece_passed);
|
||||||
|
@ -2375,23 +2372,29 @@ namespace libtorrent
|
||||||
we_have(i);
|
we_have(i);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_seed_mode && (pieces_str[i] & 2)) m_verified.set_bit(i);
|
if (m_seed_mode)
|
||||||
|
{
|
||||||
|
int const num_pieces2 = (std::min)(m_add_torrent_params->verified_pieces.size()
|
||||||
|
, torrent_file().num_pieces());
|
||||||
|
for (int i = 0; i < num_pieces2; ++i)
|
||||||
|
{
|
||||||
|
if (m_add_torrent_params->verified_pieces[i] == false) continue;
|
||||||
|
m_verified.set_bit(i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// parse unfinished pieces
|
// --- UNFINISHED PIECES ---
|
||||||
int num_blocks_per_piece =
|
|
||||||
|
int const num_blocks_per_piece =
|
||||||
static_cast<int>(torrent_file().piece_length()) / block_size();
|
static_cast<int>(torrent_file().piece_length()) / block_size();
|
||||||
|
|
||||||
#error get this from add_torrent_params
|
for (std::map<int, bitfield>::const_iterator i
|
||||||
if (bdecode_node unfinished_ent
|
= m_add_torrent_params->unfinished_pieces.begin()
|
||||||
= m_resume_data->node.dict_find_list("unfinished"))
|
, end(m_add_torrent_params->unfinished_pieces.end()); i != end; ++i)
|
||||||
{
|
{
|
||||||
for (int i = 0; i < unfinished_ent.list_size(); ++i)
|
int const piece = i->first;
|
||||||
{
|
bitfield const& blocks = i->second;
|
||||||
bdecode_node e = unfinished_ent.list_at(i);
|
|
||||||
if (e.type() != bdecode_node::dict_t) continue;
|
|
||||||
int piece = e.dict_find_int_value("piece", -1);
|
|
||||||
if (piece < 0 || piece > torrent_file().num_pieces()) continue;
|
if (piece < 0 || piece > torrent_file().num_pieces()) continue;
|
||||||
|
|
||||||
// being in seed mode and missing a piece is not compatible.
|
// being in seed mode and missing a piece is not compatible.
|
||||||
|
@ -2404,24 +2407,14 @@ namespace libtorrent
|
||||||
update_gauge();
|
update_gauge();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string bitmask = e.dict_find_string_value("bitmask");
|
|
||||||
if (bitmask.empty()) continue;
|
|
||||||
|
|
||||||
need_picker();
|
need_picker();
|
||||||
|
|
||||||
const int num_bitmask_bytes = (std::max)(num_blocks_per_piece / 8, 1);
|
const int num_bits = (std::min)(num_blocks_per_piece, blocks.size());
|
||||||
if (int(bitmask.size()) != num_bitmask_bytes) continue;
|
for (int k = 0; k < num_bits; ++k)
|
||||||
for (int k = 0; k < num_bitmask_bytes; ++k)
|
|
||||||
{
|
{
|
||||||
const boost::uint8_t bits = boost::uint8_t(bitmask[k]);
|
if (blocks.get_bit(k))
|
||||||
int num_bits = (std::min)(num_blocks_per_piece - k*8, 8);
|
|
||||||
for (int b = 0; b < num_bits; ++b)
|
|
||||||
{
|
{
|
||||||
const int block = k * 8 + b;
|
m_picker->mark_as_finished(piece_block(piece, k), 0);
|
||||||
if (bits & (1 << b))
|
|
||||||
{
|
|
||||||
m_picker->mark_as_finished(piece_block(piece, block), 0);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (m_picker->is_piece_finished(piece))
|
if (m_picker->is_piece_finished(piece))
|
||||||
|
@ -2430,7 +2423,6 @@ namespace libtorrent
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
files_checked();
|
files_checked();
|
||||||
}
|
}
|
||||||
|
@ -2446,7 +2438,7 @@ namespace libtorrent
|
||||||
}
|
}
|
||||||
|
|
||||||
maybe_done_flushing();
|
maybe_done_flushing();
|
||||||
m_resume_data.reset();
|
m_add_torrent_params.reset();
|
||||||
|
|
||||||
// restore m_need_save_resume_data to its state when we entered this
|
// restore m_need_save_resume_data to its state when we entered this
|
||||||
// function.
|
// function.
|
||||||
|
@ -2507,7 +2499,7 @@ namespace libtorrent
|
||||||
if (m_auto_managed && !is_finished())
|
if (m_auto_managed && !is_finished())
|
||||||
set_queue_position((std::numeric_limits<int>::max)());
|
set_queue_position((std::numeric_limits<int>::max)());
|
||||||
|
|
||||||
m_resume_data.reset();
|
m_add_torrent_params.reset();
|
||||||
|
|
||||||
std::vector<std::string> links;
|
std::vector<std::string> links;
|
||||||
inc_refcount("force_recheck");
|
inc_refcount("force_recheck");
|
||||||
|
@ -8552,9 +8544,6 @@ namespace libtorrent
|
||||||
// this fires during disconnecting peers
|
// this fires during disconnecting peers
|
||||||
// if (is_paused()) TORRENT_ASSERT(num_peers() == 0 || m_graceful_pause_mode);
|
// if (is_paused()) TORRENT_ASSERT(num_peers() == 0 || m_graceful_pause_mode);
|
||||||
|
|
||||||
TORRENT_ASSERT(!m_resume_data || m_resume_data->node.type() == bdecode_node::dict_t
|
|
||||||
|| m_resume_data->node.type() == bdecode_node::none_t);
|
|
||||||
|
|
||||||
int seeds = 0;
|
int seeds = 0;
|
||||||
int num_uploads = 0;
|
int num_uploads = 0;
|
||||||
std::map<piece_block, int> num_requests;
|
std::map<piece_block, int> num_requests;
|
||||||
|
|
Loading…
Reference in New Issue