forked from premiere/premiere-libtorrent
switched resume data parsing over to use lazy_bdecode. Improves memory allocation performance, especially noticable when heap allocations are expensive. Makes it more practical to run with malloc debug. Changed resume data interface to take a vector as opposed to a parsed structure
This commit is contained in:
parent
6a15c5567b
commit
9c84908bb9
|
@ -253,7 +253,7 @@ add_torrent()
|
|||
sha1_hash info_hash;
|
||||
char const* name;
|
||||
fs::path save_path;
|
||||
entry const* resume_data;
|
||||
std::vector<char>* resume_data;
|
||||
storage_mode_t storage_mode;
|
||||
bool paused;
|
||||
bool auto_managed;
|
||||
|
@ -289,7 +289,8 @@ torrent.
|
|||
|
||||
The optional parameter, ``resume_data`` can be given if up to date fast-resume data
|
||||
is available. The fast-resume data can be acquired from a running torrent by calling
|
||||
`save_resume_data()`_ on `torrent_handle`_. See `fast resume`_.
|
||||
`save_resume_data()`_ on `torrent_handle`_. See `fast resume`_. The ``vector`` that is
|
||||
passed in will be swapped into the running torrent instance with ``std::vector::swap()``.
|
||||
|
||||
The ``storage_mode`` parameter refers to the layout of the storage for this torrent.
|
||||
There are 3 different modes:
|
||||
|
@ -4416,7 +4417,7 @@ this::
|
|||
virtual size_type read(char* buf, int slot, int offset, int size) = 0;
|
||||
virtual void write(const char* buf, int slot, int offset, int size) = 0;
|
||||
virtual bool move_storage(fs::path save_path) = 0;
|
||||
virtual bool verify_resume_data(entry& rd, std::string& error) = 0;
|
||||
virtual bool verify_resume_data(lazy_entry& rd, std::string& error) = 0;
|
||||
virtual void write_resume_data(entry& rd) const = 0;
|
||||
virtual void move_slot(int src_slot, int dst_slot) = 0;
|
||||
virtual void swap_slots(int slot1, int slot2) = 0;
|
||||
|
|
|
@ -66,6 +66,7 @@ POSSIBILITY OF SUCH DAMAGE.
|
|||
#include "libtorrent/ip_filter.hpp"
|
||||
#include "libtorrent/magnet_uri.hpp"
|
||||
#include "libtorrent/bitfield.hpp"
|
||||
#include "libtorrent/file.hpp"
|
||||
|
||||
using boost::bind;
|
||||
|
||||
|
@ -485,19 +486,17 @@ void add_torrent(libtorrent::session& ses
|
|||
|
||||
std::cout << t->name() << "\n";
|
||||
|
||||
entry resume_data;
|
||||
std::stringstream s;
|
||||
s << t->name() << ".fastresume";
|
||||
boost::filesystem::ifstream resume_file(save_path / s.str(), std::ios_base::binary);
|
||||
resume_file.unsetf(std::ios_base::skipws);
|
||||
resume_data = bdecode(
|
||||
std::istream_iterator<char>(resume_file)
|
||||
, std::istream_iterator<char>());
|
||||
|
||||
add_torrent_params p;
|
||||
lazy_entry resume_data;
|
||||
|
||||
std::string filename = (save_path / (t->name() + ".fastresume")).string();
|
||||
|
||||
std::vector<char> buf;
|
||||
if (load_file(filename.c_str(), buf) == 0)
|
||||
p.resume_data = &buf;
|
||||
|
||||
p.ti = t;
|
||||
p.save_path = save_path;
|
||||
p.resume_data = &resume_data;
|
||||
p.storage_mode = compact_mode ? storage_mode_compact : storage_mode_sparse;
|
||||
p.paused = true;
|
||||
p.duplicate_is_error = false;
|
||||
|
|
|
@ -34,7 +34,8 @@ POSSIBILITY OF SUCH DAMAGE.
|
|||
#define TORRENT_FILE_HPP_INCLUDED
|
||||
|
||||
#include <memory>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(push, 1)
|
||||
|
@ -54,10 +55,7 @@ namespace libtorrent
|
|||
{
|
||||
namespace fs = boost::filesystem;
|
||||
|
||||
struct TORRENT_EXPORT file_error: std::runtime_error
|
||||
{
|
||||
file_error(std::string const& msg): std::runtime_error(msg) {}
|
||||
};
|
||||
int load_file(fs::path const& filename, std::vector<char>& v);
|
||||
|
||||
class TORRENT_EXPORT file: public boost::noncopyable
|
||||
{
|
||||
|
|
|
@ -170,7 +170,7 @@ namespace libtorrent
|
|||
return m_size;
|
||||
}
|
||||
|
||||
// end points one byte passed end
|
||||
// end points one byte passed last byte
|
||||
void set_end(char const* end)
|
||||
{
|
||||
TORRENT_ASSERT(end > m_begin);
|
||||
|
|
|
@ -140,7 +140,7 @@ namespace libtorrent
|
|||
sha1_hash info_hash;
|
||||
char const* name;
|
||||
fs::path save_path;
|
||||
entry const* resume_data;
|
||||
std::vector<char>* resume_data;
|
||||
storage_mode_t storage_mode;
|
||||
bool paused;
|
||||
bool auto_managed;
|
||||
|
|
|
@ -133,7 +133,7 @@ namespace libtorrent
|
|||
virtual bool move_storage(fs::path save_path) = 0;
|
||||
|
||||
// verify storage dependent fast resume entries
|
||||
virtual bool verify_resume_data(entry const& rd, std::string& error) = 0;
|
||||
virtual bool verify_resume_data(lazy_entry const& rd, std::string& error) = 0;
|
||||
|
||||
// write storage dependent fast resume entries
|
||||
virtual bool write_resume_data(entry& rd) const = 0;
|
||||
|
@ -212,7 +212,7 @@ namespace libtorrent
|
|||
boost::intrusive_ptr<torrent_info const> info() const { return m_info; }
|
||||
void write_resume_data(entry& rd) const;
|
||||
|
||||
void async_check_fastresume(entry const* resume_data
|
||||
void async_check_fastresume(lazy_entry const* resume_data
|
||||
, boost::function<void(int, disk_io_job const&)> const& handler);
|
||||
|
||||
void async_check_files(boost::function<void(int, disk_io_job const&)> const& handler);
|
||||
|
@ -259,7 +259,7 @@ namespace libtorrent
|
|||
|
||||
fs::path save_path() const;
|
||||
|
||||
bool verify_resume_data(entry const& rd, std::string& error)
|
||||
bool verify_resume_data(lazy_entry const& rd, std::string& error)
|
||||
{ return m_storage->verify_resume_data(rd, error); }
|
||||
|
||||
bool is_allocating() const
|
||||
|
@ -282,7 +282,7 @@ namespace libtorrent
|
|||
// the error message indicates that the fast resume data was rejected
|
||||
// if 'fatal_disk_error' is returned, the error message indicates what
|
||||
// when wrong in the disk access
|
||||
int check_fastresume(entry const& rd, std::string& error);
|
||||
int check_fastresume(lazy_entry const& rd, std::string& error);
|
||||
|
||||
// this function returns true if the checking is complete
|
||||
int check_files(int& current_slot, int& have_piece, std::string& error);
|
||||
|
|
|
@ -107,7 +107,7 @@ namespace libtorrent
|
|||
, int block_size
|
||||
, storage_constructor_type sc
|
||||
, bool paused
|
||||
, entry const* resume_data
|
||||
, std::vector<char>* resume_data
|
||||
, int seq
|
||||
, bool auto_managed);
|
||||
|
||||
|
@ -124,12 +124,14 @@ namespace libtorrent
|
|||
, int block_size
|
||||
, storage_constructor_type sc
|
||||
, bool paused
|
||||
, entry const* resume_data
|
||||
, std::vector<char>* resume_data
|
||||
, int seq
|
||||
, bool auto_managed);
|
||||
|
||||
~torrent();
|
||||
|
||||
void parse_resume_data(std::vector<char>* resume_data);
|
||||
|
||||
// starts the announce timer
|
||||
void start();
|
||||
|
||||
|
@ -564,7 +566,7 @@ namespace libtorrent
|
|||
torrent_handle get_handle();
|
||||
|
||||
void write_resume_data(entry& rd) const;
|
||||
void read_resume_data(entry const& rd);
|
||||
void read_resume_data(lazy_entry const& rd);
|
||||
|
||||
// LOGGING
|
||||
#if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_LOGGING || defined TORRENT_ERROR_LOGGING
|
||||
|
@ -787,7 +789,9 @@ namespace libtorrent
|
|||
// error message
|
||||
std::string m_error;
|
||||
|
||||
entry m_resume_data;
|
||||
// used if there is any resume data
|
||||
std::vector<char> m_resume_data;
|
||||
lazy_entry m_resume_entry;
|
||||
|
||||
// if the torrent is started without metadata, it may
|
||||
// still be given a name until the metadata is received
|
||||
|
|
|
@ -1048,7 +1048,7 @@ namespace libtorrent
|
|||
#ifdef TORRENT_DISK_STATS
|
||||
m_log << log_time() << " check fastresume" << std::endl;
|
||||
#endif
|
||||
entry const* rd = (entry const*)j.buffer;
|
||||
lazy_entry const* rd = (lazy_entry const*)j.buffer;
|
||||
TORRENT_ASSERT(rd != 0);
|
||||
ret = j.storage->check_fastresume(*rd, j.str);
|
||||
break;
|
||||
|
|
17
src/file.cpp
17
src/file.cpp
|
@ -70,6 +70,7 @@ BOOST_STATIC_ASSERT(sizeof(lseek(0, 0, 0)) >= 8);
|
|||
#include "libtorrent/file.hpp"
|
||||
#include <sstream>
|
||||
#include <cstring>
|
||||
#include <vector>
|
||||
|
||||
#ifndef O_BINARY
|
||||
#define O_BINARY 0
|
||||
|
@ -130,9 +131,22 @@ namespace
|
|||
|
||||
namespace libtorrent
|
||||
{
|
||||
|
||||
namespace fs = boost::filesystem;
|
||||
|
||||
int load_file(fs::path const& filename, std::vector<char>& v)
|
||||
{
|
||||
file f;
|
||||
if (!f.open(filename, file::in)) return -1;
|
||||
f.seek(0, file::end);
|
||||
size_type s = f.tell();
|
||||
if (s > 5000000) return -2;
|
||||
v.resize(s);
|
||||
f.seek(0);
|
||||
size_type read = f.read(&v[0], s);
|
||||
if (read != s) return -3;
|
||||
return 0;
|
||||
}
|
||||
|
||||
const file::open_mode file::in(mode_in);
|
||||
const file::open_mode file::out(mode_out);
|
||||
|
||||
|
@ -160,7 +174,6 @@ namespace libtorrent
|
|||
|
||||
bool open(fs::path const& path, int mode)
|
||||
{
|
||||
TORRENT_ASSERT(path.is_complete());
|
||||
close();
|
||||
#if defined(_WIN32) && defined(UNICODE)
|
||||
std::wstring wpath(safe_convert(path.native_file_string()));
|
||||
|
|
|
@ -560,34 +560,32 @@ namespace libtorrent
|
|||
return false;
|
||||
}
|
||||
|
||||
bool verify_resume_data(entry const& rd, std::string& error)
|
||||
bool verify_resume_data(lazy_entry const& rd, std::string& error)
|
||||
{
|
||||
if (rd.type() != entry::dictionary_t)
|
||||
if (rd.type() != lazy_entry::dict_t)
|
||||
{
|
||||
error = "invalid fastresume file";
|
||||
error = "invalid fastresume file (not a dictionary)";
|
||||
return true;
|
||||
}
|
||||
|
||||
std::vector<std::pair<size_type, std::time_t> > file_sizes;
|
||||
entry const* file_sizes_ent = rd.find_key("file sizes");
|
||||
if (file_sizes_ent == 0 || file_sizes_ent->type() != entry::list_t)
|
||||
lazy_entry const* file_sizes_ent = rd.dict_find_list("file sizes");
|
||||
if (file_sizes_ent == 0)
|
||||
{
|
||||
error = "missing or invalid 'file sizes' entry in resume data";
|
||||
return false;
|
||||
}
|
||||
|
||||
entry::list_type const& l = file_sizes_ent->list();
|
||||
|
||||
for (entry::list_type::const_iterator i = l.begin();
|
||||
i != l.end(); ++i)
|
||||
for (int i = 0; i < file_sizes_ent->list_size(); ++i)
|
||||
{
|
||||
if (i->type() != entry::list_t) break;
|
||||
entry::list_type const& pair = i->list();
|
||||
if (pair.size() != 2 || pair.front().type() != entry::int_t
|
||||
|| pair.back().type() != entry::int_t)
|
||||
break;
|
||||
lazy_entry const* e = file_sizes_ent->list_at(i);
|
||||
if (e->type() != lazy_entry::list_t
|
||||
|| e->list_size() != 2
|
||||
|| e->list_at(0)->type() != lazy_entry::int_t
|
||||
|| e->list_at(1)->type() != lazy_entry::int_t)
|
||||
continue;
|
||||
file_sizes.push_back(std::pair<size_type, std::time_t>(
|
||||
pair.front().integer(), pair.back().integer()));
|
||||
e->list_int_value_at(0), std::time_t(e->list_int_value_at(1))));
|
||||
}
|
||||
|
||||
if (file_sizes.empty())
|
||||
|
@ -596,24 +594,30 @@ namespace libtorrent
|
|||
return false;
|
||||
}
|
||||
|
||||
entry const* slots_ent = rd.find_key("slots");
|
||||
if (slots_ent == 0 || slots_ent->type() != entry::list_t)
|
||||
lazy_entry const* slots = rd.dict_find_list("slots");
|
||||
if (slots == 0)
|
||||
{
|
||||
error = "missing or invalid 'slots' entry in resume data";
|
||||
return false;
|
||||
}
|
||||
|
||||
entry::list_type const& slots = slots_ent->list();
|
||||
bool seed = int(slots.size()) == files().num_pieces()
|
||||
&& std::find_if(slots.begin(), slots.end()
|
||||
, boost::bind<bool>(std::less<int>()
|
||||
, boost::bind((size_type const& (entry::*)() const)
|
||||
&entry::integer, _1), 0)) == slots.end();
|
||||
bool seed = false;
|
||||
|
||||
if (int(slots->list_size()) == m_files.num_pieces())
|
||||
{
|
||||
bool seed = true;
|
||||
for (int i = 0; i < slots->list_size(); ++i)
|
||||
{
|
||||
lazy_entry const* e = slots->list_at(i);
|
||||
if (e->list_int_value_at(i, -1) >= 0) continue;
|
||||
seed = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
bool full_allocation_mode = false;
|
||||
entry const* allocation_mode = rd.find_key("allocation");
|
||||
if (allocation_mode && allocation_mode->type() == entry::string_t)
|
||||
full_allocation_mode = allocation_mode->string() == "full";
|
||||
if (rd.dict_find_string_value("allocation") == "full")
|
||||
full_allocation_mode = true;
|
||||
|
||||
if (seed)
|
||||
{
|
||||
|
@ -640,7 +644,6 @@ namespace libtorrent
|
|||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
return match_filesizes(files(), m_save_path, file_sizes
|
||||
|
|
|
@ -257,7 +257,12 @@ namespace libtorrent
|
|||
add_torrent_params p(sc);
|
||||
p.ti = tip;
|
||||
p.save_path = save_path;
|
||||
p.resume_data = &resume_data;
|
||||
std::vector<char> buf;
|
||||
if (resume_data.type() != entry::undefined_t)
|
||||
{
|
||||
bencode(std::back_inserter(buf), resume_data);
|
||||
p.resume_data = &buf;
|
||||
}
|
||||
p.storage_mode = storage_mode;
|
||||
p.paused = paused;
|
||||
return m_impl->add_torrent(p);
|
||||
|
@ -275,7 +280,12 @@ namespace libtorrent
|
|||
add_torrent_params p(sc);
|
||||
p.ti = ti;
|
||||
p.save_path = save_path;
|
||||
p.resume_data = &resume_data;
|
||||
std::vector<char> buf;
|
||||
if (resume_data.type() != entry::undefined_t)
|
||||
{
|
||||
bencode(std::back_inserter(buf), resume_data);
|
||||
p.resume_data = &buf;
|
||||
}
|
||||
p.storage_mode = storage_mode;
|
||||
p.paused = paused;
|
||||
p.userdata = userdata;
|
||||
|
|
132
src/storage.cpp
132
src/storage.cpp
|
@ -422,7 +422,7 @@ namespace libtorrent
|
|||
bool move_slot(int src_slot, int dst_slot);
|
||||
bool swap_slots(int slot1, int slot2);
|
||||
bool swap_slots3(int slot1, int slot2, int slot3);
|
||||
bool verify_resume_data(entry const& rd, std::string& error);
|
||||
bool verify_resume_data(lazy_entry const& rd, std::string& error);
|
||||
bool write_resume_data(entry& rd) const;
|
||||
sha1_hash hash_for_slot(int slot, partial_hash& ph, int piece_size);
|
||||
|
||||
|
@ -685,34 +685,32 @@ namespace libtorrent
|
|||
return false;
|
||||
}
|
||||
|
||||
bool storage::verify_resume_data(entry const& rd, std::string& error)
|
||||
bool storage::verify_resume_data(lazy_entry const& rd, std::string& error)
|
||||
{
|
||||
if (rd.type() != entry::dictionary_t)
|
||||
if (rd.type() != lazy_entry::dict_t)
|
||||
{
|
||||
error = "invalid fastresume file (not a dictionary)";
|
||||
return true;
|
||||
}
|
||||
|
||||
std::vector<std::pair<size_type, std::time_t> > file_sizes;
|
||||
entry const* file_sizes_ent = rd.find_key("file sizes");
|
||||
if (file_sizes_ent == 0 || file_sizes_ent->type() != entry::list_t)
|
||||
lazy_entry const* file_sizes_ent = rd.dict_find_list("file sizes");
|
||||
if (file_sizes_ent == 0)
|
||||
{
|
||||
error = "missing or invalid 'file sizes' entry in resume data";
|
||||
return false;
|
||||
}
|
||||
|
||||
entry::list_type const& l = file_sizes_ent->list();
|
||||
|
||||
for (entry::list_type::const_iterator i = l.begin();
|
||||
i != l.end(); ++i)
|
||||
for (int i = 0; i < file_sizes_ent->list_size(); ++i)
|
||||
{
|
||||
if (i->type() != entry::list_t) break;
|
||||
entry::list_type const& pair = i->list();
|
||||
if (pair.size() != 2 || pair.front().type() != entry::int_t
|
||||
|| pair.back().type() != entry::int_t)
|
||||
break;
|
||||
lazy_entry const* e = file_sizes_ent->list_at(i);
|
||||
if (e->type() != lazy_entry::list_t
|
||||
|| e->list_size() != 2
|
||||
|| e->list_at(0)->type() != lazy_entry::int_t
|
||||
|| e->list_at(1)->type() != lazy_entry::int_t)
|
||||
continue;
|
||||
file_sizes.push_back(std::pair<size_type, std::time_t>(
|
||||
pair.front().integer(), std::time_t(pair.back().integer())));
|
||||
e->list_int_value_at(0), std::time_t(e->list_int_value_at(1))));
|
||||
}
|
||||
|
||||
if (file_sizes.empty())
|
||||
|
@ -721,32 +719,38 @@ namespace libtorrent
|
|||
return false;
|
||||
}
|
||||
|
||||
entry const* slots_ent = rd.find_key("slots");
|
||||
if (slots_ent == 0 || slots_ent->type() != entry::list_t)
|
||||
lazy_entry const* slots = rd.dict_find_list("slots");
|
||||
if (slots == 0)
|
||||
{
|
||||
error = "missing or invalid 'slots' entry in resume data";
|
||||
return false;
|
||||
}
|
||||
|
||||
entry::list_type const& slots = slots_ent->list();
|
||||
bool seed = int(slots.size()) == m_files.num_pieces()
|
||||
&& std::find_if(slots.begin(), slots.end()
|
||||
, boost::bind<bool>(std::less<int>()
|
||||
, boost::bind((size_type const& (entry::*)() const)
|
||||
&entry::integer, _1), 0)) == slots.end();
|
||||
bool seed = false;
|
||||
|
||||
if (int(slots->list_size()) == m_files.num_pieces())
|
||||
{
|
||||
bool seed = true;
|
||||
for (int i = 0; i < slots->list_size(); ++i)
|
||||
{
|
||||
lazy_entry const* e = slots->list_at(i);
|
||||
if (e->list_int_value_at(i, -1) >= 0) continue;
|
||||
seed = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
bool full_allocation_mode = false;
|
||||
entry const* allocation_mode = rd.find_key("allocation");
|
||||
if (allocation_mode && allocation_mode->type() == entry::string_t)
|
||||
full_allocation_mode = allocation_mode->string() == "full";
|
||||
if (rd.dict_find_string_value("allocation") == "full")
|
||||
full_allocation_mode = true;
|
||||
|
||||
if (seed)
|
||||
{
|
||||
if (m_files.num_files() != (int)file_sizes.size())
|
||||
if (files().num_files() != (int)file_sizes.size())
|
||||
{
|
||||
error = "the number of files does not match the torrent (num: "
|
||||
+ boost::lexical_cast<std::string>(file_sizes.size()) + " actual: "
|
||||
+ boost::lexical_cast<std::string>(m_files.num_files()) + ")";
|
||||
+ boost::lexical_cast<std::string>(files().num_files()) + ")";
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -1300,7 +1304,7 @@ namespace libtorrent
|
|||
m_io_thread.add_job(j, handler);
|
||||
}
|
||||
|
||||
void piece_manager::async_check_fastresume(entry const* resume_data
|
||||
void piece_manager::async_check_fastresume(lazy_entry const* resume_data
|
||||
, boost::function<void(int, disk_io_job const&)> const& handler)
|
||||
{
|
||||
TORRENT_ASSERT(resume_data != 0);
|
||||
|
@ -1783,7 +1787,7 @@ namespace libtorrent
|
|||
// isn't return false and the full check
|
||||
// will be run
|
||||
int piece_manager::check_fastresume(
|
||||
entry const& rd, std::string& error)
|
||||
lazy_entry const& rd, std::string& error)
|
||||
{
|
||||
boost::recursive_mutex::scoped_lock lock(m_mutex);
|
||||
|
||||
|
@ -1792,29 +1796,25 @@ namespace libtorrent
|
|||
TORRENT_ASSERT(m_files.piece_length() > 0);
|
||||
|
||||
// if we don't have any resume data, return
|
||||
if (rd.type() == entry::undefined_t) return check_no_fastresume(error);
|
||||
if (rd.type() == lazy_entry::none_t) return check_no_fastresume(error);
|
||||
|
||||
if (rd.type() != entry::dictionary_t)
|
||||
if (rd.type() != lazy_entry::dict_t)
|
||||
{
|
||||
error = "invalid fastresume data (not a bencoded dictionary)";
|
||||
error = "invalid fastresume data (not a dictionary)";
|
||||
return check_no_fastresume(error);
|
||||
}
|
||||
|
||||
int block_size = (std::min)(16 * 1024, m_files.piece_length());
|
||||
entry const* blocks_per_piece_ent = rd.find_key("blocks per piece");
|
||||
if (blocks_per_piece_ent != 0
|
||||
&& blocks_per_piece_ent->type() == entry::int_t
|
||||
&& blocks_per_piece_ent->integer() != m_files.piece_length() / block_size)
|
||||
int blocks_per_piece = rd.dict_find_int_value("blocks per piece", -1);
|
||||
if (blocks_per_piece != -1
|
||||
&& blocks_per_piece != m_files.piece_length() / block_size)
|
||||
{
|
||||
error = "invalid 'blocks per piece' entry";
|
||||
return check_no_fastresume(error);
|
||||
}
|
||||
|
||||
storage_mode_t storage_mode = storage_mode_compact;
|
||||
entry const* allocation = rd.find_key("allocation");
|
||||
if (allocation != 0
|
||||
&& allocation->type() == entry::string_t
|
||||
&& allocation->string() != "compact")
|
||||
if (rd.dict_find_string_value("allocation") != "compact")
|
||||
storage_mode = storage_mode_sparse;
|
||||
|
||||
// assume no piece is out of place (i.e. in a slot
|
||||
|
@ -1823,20 +1823,20 @@ namespace libtorrent
|
|||
|
||||
// if we don't have a piece map, we need the slots
|
||||
// if we're in compact mode, we also need the slots map
|
||||
if (storage_mode == storage_mode_compact || rd.find_key("pieces") == 0)
|
||||
if (storage_mode == storage_mode_compact || rd.dict_find("pieces") == 0)
|
||||
{
|
||||
// read slots map
|
||||
entry const* slots = rd.find_key("slots");
|
||||
if (slots == 0 || slots->type() != entry::list_t)
|
||||
lazy_entry const* slots = rd.dict_find_list("slots");
|
||||
if (slots == 0)
|
||||
{
|
||||
error = "missing slot list";
|
||||
return check_no_fastresume(error);
|
||||
}
|
||||
|
||||
if ((int)slots->list().size() > m_files.num_pieces())
|
||||
if ((int)slots->list_size() > m_files.num_pieces())
|
||||
{
|
||||
error = "file has more slots than torrent (slots: "
|
||||
+ boost::lexical_cast<std::string>(slots->list().size()) + " size: "
|
||||
+ boost::lexical_cast<std::string>(slots->list_size()) + " size: "
|
||||
+ boost::lexical_cast<std::string>(m_files.num_pieces()) + " )";
|
||||
return check_no_fastresume(error);
|
||||
}
|
||||
|
@ -1846,17 +1846,16 @@ namespace libtorrent
|
|||
int num_pieces = int(m_files.num_pieces());
|
||||
m_slot_to_piece.resize(num_pieces, unallocated);
|
||||
m_piece_to_slot.resize(num_pieces, has_no_slot);
|
||||
int slot = 0;
|
||||
for (entry::list_type::const_iterator i = slots->list().begin();
|
||||
i != slots->list().end(); ++i, ++slot)
|
||||
for (int i = 0; i < slots->list_size(); ++i)
|
||||
{
|
||||
if (i->type() != entry::int_t)
|
||||
lazy_entry const* e = slots->list_at(i);
|
||||
if (e->type() != lazy_entry::int_t)
|
||||
{
|
||||
error = "invalid entry type in slot list";
|
||||
return check_no_fastresume(error);
|
||||
}
|
||||
|
||||
int index = int(i->integer());
|
||||
int index = int(e->int_value());
|
||||
if (index >= num_pieces || index < -2)
|
||||
{
|
||||
error = "too high index number in slot map (index: "
|
||||
|
@ -1866,37 +1865,36 @@ namespace libtorrent
|
|||
}
|
||||
if (index >= 0)
|
||||
{
|
||||
m_slot_to_piece[slot] = index;
|
||||
m_piece_to_slot[index] = slot;
|
||||
if (slot != index) out_of_place = true;
|
||||
m_slot_to_piece[i] = index;
|
||||
m_piece_to_slot[index] = i;
|
||||
if (i != index) out_of_place = true;
|
||||
}
|
||||
else if (index == unassigned)
|
||||
{
|
||||
if (m_storage_mode == storage_mode_compact)
|
||||
m_free_slots.push_back(slot);
|
||||
m_free_slots.push_back(i);
|
||||
}
|
||||
else
|
||||
{
|
||||
TORRENT_ASSERT(index == unallocated);
|
||||
if (m_storage_mode == storage_mode_compact)
|
||||
m_unallocated_slots.push_back(slot);
|
||||
m_unallocated_slots.push_back(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
int slot = 0;
|
||||
for (entry::list_type::const_iterator i = slots->list().begin();
|
||||
i != slots->list().end(); ++i, ++slot)
|
||||
for (int i = 0; i < slots->list_size(); ++i)
|
||||
{
|
||||
if (i->type() != entry::int_t)
|
||||
lazy_entry const* e = slots->list_at(i);
|
||||
if (e->type() != lazy_entry::int_t)
|
||||
{
|
||||
error = "invalid entry type in slot list";
|
||||
return check_no_fastresume(error);
|
||||
}
|
||||
|
||||
int index = int(i->integer());
|
||||
if (index != slot && index >= 0)
|
||||
int index = int(e->int_value());
|
||||
if (index != i && index >= 0)
|
||||
{
|
||||
error = "invalid slot index";
|
||||
return check_no_fastresume(error);
|
||||
|
@ -1937,17 +1935,17 @@ namespace libtorrent
|
|||
else if (m_storage_mode == storage_mode_compact)
|
||||
{
|
||||
// read piece map
|
||||
entry const* pieces = rd.find_key("pieces");
|
||||
if (pieces == 0 || pieces->type() != entry::string_t)
|
||||
lazy_entry const* pieces = rd.dict_find("pieces");
|
||||
if (pieces == 0 || pieces->type() != lazy_entry::string_t)
|
||||
{
|
||||
error = "missing pieces entry";
|
||||
return check_no_fastresume(error);
|
||||
}
|
||||
|
||||
if ((int)pieces->string().size() != m_files.num_pieces())
|
||||
if ((int)pieces->string_length() != m_files.num_pieces())
|
||||
{
|
||||
error = "file has more slots than torrent (slots: "
|
||||
+ boost::lexical_cast<std::string>(pieces->string().size()) + " size: "
|
||||
+ boost::lexical_cast<std::string>(pieces->string_length()) + " size: "
|
||||
+ boost::lexical_cast<std::string>(m_files.num_pieces()) + " )";
|
||||
return check_no_fastresume(error);
|
||||
}
|
||||
|
@ -1955,7 +1953,7 @@ namespace libtorrent
|
|||
int num_pieces = int(m_files.num_pieces());
|
||||
m_slot_to_piece.resize(num_pieces, unallocated);
|
||||
m_piece_to_slot.resize(num_pieces, has_no_slot);
|
||||
std::string const& have_pieces = pieces->string();
|
||||
char const* have_pieces = pieces->string_ptr();
|
||||
for (int i = 0; i < num_pieces; ++i)
|
||||
{
|
||||
if (have_pieces[i] & 1)
|
||||
|
|
213
src/torrent.cpp
213
src/torrent.cpp
|
@ -144,7 +144,7 @@ namespace libtorrent
|
|||
, int block_size
|
||||
, storage_constructor_type sc
|
||||
, bool paused
|
||||
, entry const* resume_data
|
||||
, std::vector<char>* resume_data
|
||||
, int seq
|
||||
, bool auto_managed)
|
||||
: m_policy(this)
|
||||
|
@ -203,7 +203,7 @@ namespace libtorrent
|
|||
, m_has_incoming(false)
|
||||
, m_files_checked(false)
|
||||
{
|
||||
if (resume_data) m_resume_data = *resume_data;
|
||||
parse_resume_data(resume_data);
|
||||
}
|
||||
|
||||
torrent::torrent(
|
||||
|
@ -217,7 +217,7 @@ namespace libtorrent
|
|||
, int block_size
|
||||
, storage_constructor_type sc
|
||||
, bool paused
|
||||
, entry const* resume_data
|
||||
, std::vector<char>* resume_data
|
||||
, int seq
|
||||
, bool auto_managed)
|
||||
: m_policy(this)
|
||||
|
@ -274,7 +274,7 @@ namespace libtorrent
|
|||
, m_connections_initialized(false)
|
||||
, m_has_incoming(false)
|
||||
{
|
||||
if (resume_data) m_resume_data = *resume_data;
|
||||
parse_resume_data(resume_data);
|
||||
#ifndef NDEBUG
|
||||
m_files_checked = false;
|
||||
#endif
|
||||
|
@ -289,6 +289,25 @@ namespace libtorrent
|
|||
}
|
||||
}
|
||||
|
||||
void torrent::parse_resume_data(std::vector<char>* resume_data)
|
||||
{
|
||||
if (!resume_data) return;
|
||||
m_resume_data.swap(*resume_data);
|
||||
if (lazy_bdecode(&m_resume_data[0], &m_resume_data[0]
|
||||
+ m_resume_data.size(), m_resume_entry) != 0)
|
||||
{
|
||||
std::vector<char>().swap(m_resume_data);
|
||||
if (m_ses.m_alerts.should_post(alert::warning))
|
||||
{
|
||||
m_ses.m_alerts.post_alert(fastresume_rejected_alert(get_handle(), "parse failed"));
|
||||
#if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_LOGGING || defined TORRENT_ERROR_LOGGING
|
||||
(*m_ses.m_logger) << "fastresume data for "
|
||||
<< torrent_file().name() << " rejected: parse failed\n";
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void torrent::start()
|
||||
{
|
||||
boost::weak_ptr<torrent> self(shared_from_this());
|
||||
|
@ -429,18 +448,17 @@ namespace libtorrent
|
|||
|
||||
m_state = torrent_status::queued_for_checking;
|
||||
|
||||
if (m_resume_data.type() == entry::dictionary_t)
|
||||
if (m_resume_entry.type() == lazy_entry::dict_t)
|
||||
{
|
||||
char const* error = 0;
|
||||
entry const* file_format = m_resume_data.find_key("file-format");
|
||||
if (file_format->string() != "libtorrent resume file")
|
||||
if (m_resume_entry.dict_find_string_value("file-format") != "libtorrent resume file")
|
||||
error = "invalid file format tag";
|
||||
|
||||
entry const* info_hash = m_resume_data.find_key("info-hash");
|
||||
if (!error && (info_hash == 0 || info_hash->type() != entry::string_t))
|
||||
std::string info_hash = m_resume_entry.dict_find_string_value("info-hash");
|
||||
if (!error && info_hash.empty())
|
||||
error = "missing info-hash";
|
||||
|
||||
if (!error && sha1_hash(info_hash->string()) != m_torrent_file->info_hash())
|
||||
if (!error && sha1_hash(info_hash) != m_torrent_file->info_hash())
|
||||
error = "mismatching info-hash";
|
||||
|
||||
if (error && m_ses.m_alerts.should_post(alert::warning))
|
||||
|
@ -453,11 +471,18 @@ namespace libtorrent
|
|||
#endif
|
||||
}
|
||||
|
||||
if (error) m_resume_data = entry();
|
||||
else read_resume_data(m_resume_data);
|
||||
if (error)
|
||||
{
|
||||
std::vector<char>().swap(m_resume_data);
|
||||
m_resume_entry = lazy_entry();
|
||||
}
|
||||
else
|
||||
{
|
||||
read_resume_data(m_resume_entry);
|
||||
}
|
||||
}
|
||||
|
||||
m_storage->async_check_fastresume(&m_resume_data
|
||||
m_storage->async_check_fastresume(&m_resume_entry
|
||||
, bind(&torrent::on_resume_data_checked
|
||||
, shared_from_this(), _1, _2));
|
||||
}
|
||||
|
@ -483,54 +508,41 @@ namespace libtorrent
|
|||
return;
|
||||
}
|
||||
|
||||
// parse out "peers" from the resume data and add them to the peer list
|
||||
entry const* peers_entry = m_resume_data.find_key("peers");
|
||||
if (peers_entry && peers_entry->type() == entry::list_t)
|
||||
if (m_resume_entry.type() == lazy_entry::dict_t)
|
||||
{
|
||||
peer_id id;
|
||||
std::fill(id.begin(), id.end(), 0);
|
||||
entry::list_type const& peer_list = peers_entry->list();
|
||||
|
||||
for (entry::list_type::const_iterator i = peer_list.begin();
|
||||
i != peer_list.end(); ++i)
|
||||
// parse out "peers" from the resume data and add them to the peer list
|
||||
if (lazy_entry const* peers_entry = m_resume_entry.dict_find_list("peers"))
|
||||
{
|
||||
if (i->type() != entry::dictionary_t) continue;
|
||||
entry const* ip = i->find_key("ip");
|
||||
entry const* port = i->find_key("port");
|
||||
if (ip == 0 || port == 0
|
||||
|| ip->type() != entry::string_t
|
||||
|| port->type() != entry::int_t)
|
||||
continue;
|
||||
tcp::endpoint a(
|
||||
address::from_string(ip->string())
|
||||
, (unsigned short)port->integer());
|
||||
m_policy.peer_from_tracker(a, id, peer_info::resume_data, 0);
|
||||
peer_id id(0);
|
||||
|
||||
for (int i = 0; i < peers_entry->list_size(); ++i)
|
||||
{
|
||||
lazy_entry const* e = peers_entry->list_at(i);
|
||||
if (e->type() != lazy_entry::dict_t) continue;
|
||||
std::string ip = e->dict_find_string_value("ip");
|
||||
int port = e->dict_find_int_value("port");
|
||||
if (ip.empty() || port == 0) continue;
|
||||
tcp::endpoint a(address::from_string(ip), (unsigned short)port);
|
||||
m_policy.peer_from_tracker(a, id, peer_info::resume_data, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// parse out "banned_peers" and add them as banned
|
||||
entry const* banned_peers_entry = m_resume_data.find_key("banned_peers");
|
||||
if (banned_peers_entry != 0 && banned_peers_entry->type() == entry::list_t)
|
||||
{
|
||||
peer_id id;
|
||||
std::fill(id.begin(), id.end(), 0);
|
||||
entry::list_type const& peer_list = banned_peers_entry->list();
|
||||
|
||||
for (entry::list_type::const_iterator i = peer_list.begin();
|
||||
i != peer_list.end(); ++i)
|
||||
// parse out "banned_peers" and add them as banned
|
||||
if (lazy_entry const* banned_peers_entry = m_resume_entry.dict_find_list("banned_peers"))
|
||||
{
|
||||
if (i->type() != entry::dictionary_t) continue;
|
||||
entry const* ip = i->find_key("ip");
|
||||
entry const* port = i->find_key("port");
|
||||
if (ip == 0 || port == 0
|
||||
|| ip->type() != entry::string_t
|
||||
|| port->type() != entry::int_t)
|
||||
continue;
|
||||
tcp::endpoint a(
|
||||
address::from_string(ip->string())
|
||||
, (unsigned short)port->integer());
|
||||
policy::peer* p = m_policy.peer_from_tracker(a, id, peer_info::resume_data, 0);
|
||||
if (p) p->banned = true;
|
||||
peer_id id(0);
|
||||
|
||||
for (int i = 0; i < banned_peers_entry->list_size(); ++i)
|
||||
{
|
||||
lazy_entry const* e = banned_peers_entry->list_at(i);
|
||||
if (e->type() != lazy_entry::dict_t) continue;
|
||||
std::string ip = e->dict_find_string_value("ip");
|
||||
int port = e->dict_find_int_value("port");
|
||||
if (ip.empty() || port == 0) continue;
|
||||
tcp::endpoint a(address::from_string(ip), (unsigned short)port);
|
||||
policy::peer* p = m_policy.peer_from_tracker(a, id, peer_info::resume_data, 0);
|
||||
if (p) p->banned = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -551,17 +563,15 @@ namespace libtorrent
|
|||
// there are either no files for this torrent
|
||||
// or the resume_data was accepted
|
||||
|
||||
if (!fastresume_rejected)
|
||||
if (!fastresume_rejected && m_resume_entry.type() == lazy_entry::dict_t)
|
||||
{
|
||||
TORRENT_ASSERT(m_resume_data.type() == entry::dictionary_t);
|
||||
|
||||
// parse have bitmask
|
||||
entry const* pieces = m_resume_data.find_key("pieces");
|
||||
if (pieces && pieces->type() == entry::string_t
|
||||
&& int(pieces->string().length()) == m_torrent_file->num_pieces())
|
||||
lazy_entry const* pieces = m_resume_entry.dict_find("pieces");
|
||||
if (pieces && pieces->type() == lazy_entry::string_t
|
||||
&& int(pieces->string_length()) == m_torrent_file->num_pieces())
|
||||
{
|
||||
std::string const& pieces_str = pieces->string();
|
||||
for (int i = 0, end(pieces_str.size()); i < end; ++i)
|
||||
char const* pieces_str = pieces->string_ptr();
|
||||
for (int i = 0, end(pieces->string_length()); i < end; ++i)
|
||||
{
|
||||
if ((pieces_str[i] & 1) == 0) continue;
|
||||
m_picker->we_have(i);
|
||||
|
@ -572,27 +582,20 @@ namespace libtorrent
|
|||
int num_blocks_per_piece =
|
||||
static_cast<int>(torrent_file().piece_length()) / block_size();
|
||||
|
||||
entry const* unfinished_ent = m_resume_data.find_key("unfinished");
|
||||
if (unfinished_ent != 0 && unfinished_ent->type() == entry::list_t)
|
||||
if (lazy_entry const* unfinished_ent = m_resume_entry.dict_find_list("unfinished"))
|
||||
{
|
||||
entry::list_type const& unfinished = unfinished_ent->list();
|
||||
int index = 0;
|
||||
for (entry::list_type::const_iterator i = unfinished.begin();
|
||||
i != unfinished.end(); ++i, ++index)
|
||||
for (int i = 0; i < unfinished_ent->list_size(); ++i)
|
||||
{
|
||||
if (i->type() != entry::dictionary_t) continue;
|
||||
entry const* piece = i->find_key("piece");
|
||||
if (piece == 0 || piece->type() != entry::int_t) continue;
|
||||
int piece_index = int(piece->integer());
|
||||
if (piece_index < 0 || piece_index >= torrent_file().num_pieces())
|
||||
continue;
|
||||
lazy_entry const* e = unfinished_ent->list_at(i);
|
||||
if (e->type() != lazy_entry::dict_t) continue;
|
||||
int piece = e->dict_find_int_value("piece", -1);
|
||||
if (piece < 0 || piece > torrent_file().num_pieces()) continue;
|
||||
|
||||
if (m_picker->have_piece(piece_index))
|
||||
m_picker->we_dont_have(piece_index);
|
||||
if (m_picker->have_piece(piece))
|
||||
m_picker->we_dont_have(piece);
|
||||
|
||||
entry const* bitmask_ent = i->find_key("bitmask");
|
||||
if (bitmask_ent == 0 || bitmask_ent->type() != entry::string_t) break;
|
||||
std::string const& bitmask = bitmask_ent->string();
|
||||
std::string bitmask = e->dict_find_string_value("bitmask");
|
||||
if (bitmask.empty()) continue;
|
||||
|
||||
const int num_bitmask_bytes = (std::max)(num_blocks_per_piece / 8, 1);
|
||||
if ((int)bitmask.size() != num_bitmask_bytes) continue;
|
||||
|
@ -605,10 +608,10 @@ namespace libtorrent
|
|||
const int bit = j * 8 + k;
|
||||
if (bits & (1 << k))
|
||||
{
|
||||
m_picker->mark_as_finished(piece_block(piece_index, bit), 0);
|
||||
if (m_picker->is_piece_finished(piece_index))
|
||||
async_verify_piece(piece_index, bind(&torrent::piece_finished
|
||||
, shared_from_this(), piece_index, _1));
|
||||
m_picker->mark_as_finished(piece_block(piece, bit), 0);
|
||||
if (m_picker->is_piece_finished(piece))
|
||||
async_verify_piece(piece, bind(&torrent::piece_finished
|
||||
, shared_from_this(), piece, _1));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -649,8 +652,9 @@ namespace libtorrent
|
|||
if (m_auto_managed)
|
||||
set_queue_position((std::numeric_limits<int>::max)());
|
||||
|
||||
m_resume_data = entry();
|
||||
m_storage->async_check_fastresume(&m_resume_data
|
||||
std::vector<char>().swap(m_resume_data);
|
||||
m_resume_entry = lazy_entry();
|
||||
m_storage->async_check_fastresume(&m_resume_entry
|
||||
, bind(&torrent::on_force_recheck
|
||||
, shared_from_this(), _1, _2));
|
||||
}
|
||||
|
@ -2413,31 +2417,14 @@ namespace libtorrent
|
|||
}
|
||||
#endif
|
||||
|
||||
void torrent::read_resume_data(entry const& rd)
|
||||
void torrent::read_resume_data(lazy_entry const& rd)
|
||||
{
|
||||
entry const* e = 0;
|
||||
e = rd.find_key("total_uploaded");
|
||||
m_total_uploaded = (e != 0 && e->type() == entry::int_t)?e->integer():0;
|
||||
e = rd.find_key("total_downloaded");
|
||||
m_total_downloaded = (e != 0 && e->type() == entry::int_t)?e->integer():0;
|
||||
|
||||
e = rd.find_key("active_time");
|
||||
m_active_time = seconds((e != 0 && e->type() == entry::int_t)?e->integer():0);
|
||||
e = rd.find_key("seeding_time");
|
||||
m_seeding_time = seconds((e != 0 && e->type() == entry::int_t)?e->integer():0);
|
||||
|
||||
e = rd.find_key("num_seeds");
|
||||
m_complete = (e != 0 && e->type() == entry::int_t)?e->integer():-1;
|
||||
e = rd.find_key("num_downloaders");
|
||||
m_incomplete = (e != 0 && e->type() == entry::int_t)?e->integer():-1;
|
||||
/*
|
||||
m_total_uploaded = rd.find_int_value("total_uploaded");
|
||||
m_total_downloaded = rd.find_inte_value("total_downloaded");
|
||||
m_active_time = rd.find_int_value("active_time");
|
||||
m_seeding_time = rd.find_int_value("seeding_time");
|
||||
m_complete = rd.find_int_value("num_seeds", -1);
|
||||
m_incomplete = rd.find_int_value("num_downloaders", -1);
|
||||
*/
|
||||
m_total_uploaded = rd.dict_find_int_value("total_uploaded");
|
||||
m_total_downloaded = rd.dict_find_int_value("total_downloaded");
|
||||
m_active_time = seconds(rd.dict_find_int_value("active_time"));
|
||||
m_seeding_time = seconds(rd.dict_find_int_value("seeding_time"));
|
||||
m_complete = rd.dict_find_int_value("num_seeds", -1);
|
||||
m_incomplete = rd.dict_find_int_value("num_downloaders", -1);
|
||||
}
|
||||
|
||||
void torrent::write_resume_data(entry& ret) const
|
||||
|
@ -3332,8 +3319,8 @@ namespace libtorrent
|
|||
{
|
||||
session_impl::mutex_t::scoped_lock l(m_ses.m_mutex);
|
||||
|
||||
TORRENT_ASSERT(m_resume_data.type() == entry::dictionary_t
|
||||
|| m_resume_data.type() == entry::undefined_t);
|
||||
TORRENT_ASSERT(m_resume_entry.type() == lazy_entry::dict_t
|
||||
|| m_resume_entry.type() == lazy_entry::none_t);
|
||||
|
||||
TORRENT_ASSERT(m_bandwidth_queue[0].size() <= m_connections.size());
|
||||
TORRENT_ASSERT(m_bandwidth_queue[1].size() <= m_connections.size());
|
||||
|
|
|
@ -58,6 +58,7 @@ POSSIBILITY OF SUCH DAMAGE.
|
|||
#include "libtorrent/bencode.hpp"
|
||||
#include "libtorrent/hasher.hpp"
|
||||
#include "libtorrent/entry.hpp"
|
||||
#include "libtorrent/file.hpp"
|
||||
|
||||
namespace gr = boost::gregorian;
|
||||
|
||||
|
@ -282,16 +283,13 @@ namespace libtorrent
|
|||
, m_multifile(false)
|
||||
, m_private(false)
|
||||
{
|
||||
size_type s = fs::file_size(fs::path(filename));
|
||||
// don't load torrent files larger than 2 MB
|
||||
if (s > 2000000) return;
|
||||
std::vector<char> buf(s);
|
||||
std::ifstream f(filename, std::ios_base::binary);
|
||||
f.read(&buf[0], s);
|
||||
std::vector<char> buf;
|
||||
int ret = load_file(filename, buf);
|
||||
if (ret < 0) return;
|
||||
|
||||
std::string error;
|
||||
lazy_entry e;
|
||||
lazy_bdecode(&buf[0], &buf[0] + buf.size(), e);
|
||||
std::string error;
|
||||
#ifndef BOOST_NO_EXCEPTIONS
|
||||
if (!parse_torrent_file(e, error))
|
||||
throw invalid_torrent_file();
|
||||
|
|
|
@ -107,7 +107,7 @@ void run_storage_tests(boost::intrusive_ptr<torrent_info> info
|
|||
, test_path, fp, io, default_storage_constructor, storage_mode);
|
||||
boost::mutex lock;
|
||||
|
||||
entry frd;
|
||||
lazy_entry frd;
|
||||
pm->async_check_fastresume(&frd, &on_check_resume_data);
|
||||
ios.reset();
|
||||
ios.run();
|
||||
|
|
Loading…
Reference in New Issue