forked from premiere/premiere-libtorrent
removed checker thread
This commit is contained in:
parent
1a0f8d5cd5
commit
f53cfa7eeb
|
@ -94,73 +94,6 @@ namespace libtorrent
|
||||||
{
|
{
|
||||||
struct session_impl;
|
struct session_impl;
|
||||||
|
|
||||||
// this data is shared between the main thread and the
|
|
||||||
// thread that initialize pieces
|
|
||||||
struct piece_checker_data
|
|
||||||
{
|
|
||||||
piece_checker_data()
|
|
||||||
: processing(false), progress(0.f), abort(false) {}
|
|
||||||
|
|
||||||
boost::shared_ptr<torrent> torrent_ptr;
|
|
||||||
fs::path save_path;
|
|
||||||
|
|
||||||
sha1_hash info_hash;
|
|
||||||
|
|
||||||
void parse_resume_data(
|
|
||||||
const entry& rd
|
|
||||||
, const torrent_info& info
|
|
||||||
, std::string& error);
|
|
||||||
|
|
||||||
std::vector<int> piece_map;
|
|
||||||
std::vector<piece_picker::downloading_piece> unfinished_pieces;
|
|
||||||
std::vector<piece_picker::block_info> block_info;
|
|
||||||
std::vector<tcp::endpoint> peers;
|
|
||||||
std::vector<tcp::endpoint> banned_peers;
|
|
||||||
entry resume_data;
|
|
||||||
|
|
||||||
// this is true if this torrent is being processed (checked)
|
|
||||||
// if it is not being processed, then it can be removed from
|
|
||||||
// the queue without problems, otherwise the abort flag has
|
|
||||||
// to be set.
|
|
||||||
bool processing;
|
|
||||||
|
|
||||||
// is filled in by storage::initialize_pieces()
|
|
||||||
// and represents the progress. It should be a
|
|
||||||
// value in the range [0, 1]
|
|
||||||
float progress;
|
|
||||||
|
|
||||||
// abort defaults to false and is typically
|
|
||||||
// filled in by torrent_handle when the user
|
|
||||||
// aborts the torrent
|
|
||||||
bool abort;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct checker_impl: boost::noncopyable
|
|
||||||
{
|
|
||||||
checker_impl(session_impl& s): m_ses(s), m_abort(false) {}
|
|
||||||
void operator()();
|
|
||||||
piece_checker_data* find_torrent(const sha1_hash& info_hash);
|
|
||||||
void remove_torrent(sha1_hash const& info_hash, int options);
|
|
||||||
|
|
||||||
#ifndef NDEBUG
|
|
||||||
void check_invariant() const;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// when the files has been checked
|
|
||||||
// the torrent is added to the session
|
|
||||||
session_impl& m_ses;
|
|
||||||
|
|
||||||
mutable boost::mutex m_mutex;
|
|
||||||
boost::condition m_cond;
|
|
||||||
|
|
||||||
// a list of all torrents that are currently in queue
|
|
||||||
// or checking their files
|
|
||||||
std::deque<boost::shared_ptr<piece_checker_data> > m_torrents;
|
|
||||||
std::deque<boost::shared_ptr<piece_checker_data> > m_processing;
|
|
||||||
|
|
||||||
bool m_abort;
|
|
||||||
};
|
|
||||||
|
|
||||||
#if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_LOGGING || defined TORRENT_ERROR_LOGGING
|
#if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_LOGGING || defined TORRENT_ERROR_LOGGING
|
||||||
struct tracker_logger;
|
struct tracker_logger;
|
||||||
#endif
|
#endif
|
||||||
|
@ -284,6 +217,9 @@ namespace libtorrent
|
||||||
|
|
||||||
std::vector<torrent_handle> get_torrents();
|
std::vector<torrent_handle> get_torrents();
|
||||||
|
|
||||||
|
void check_torrent(boost::shared_ptr<torrent> const& t);
|
||||||
|
void done_checking(boost::shared_ptr<torrent> const& t);
|
||||||
|
|
||||||
void set_severity_level(alert::severity_t s);
|
void set_severity_level(alert::severity_t s);
|
||||||
std::auto_ptr<alert> pop_alert();
|
std::auto_ptr<alert> pop_alert();
|
||||||
|
|
||||||
|
@ -435,6 +371,7 @@ namespace libtorrent
|
||||||
|
|
||||||
tracker_manager m_tracker_manager;
|
tracker_manager m_tracker_manager;
|
||||||
torrent_map m_torrents;
|
torrent_map m_torrents;
|
||||||
|
std::list<boost::shared_ptr<torrent> > m_queued_for_checking;
|
||||||
|
|
||||||
// this maps sockets to their peer_connection
|
// this maps sockets to their peer_connection
|
||||||
// object. It is the complete list of all connected
|
// object. It is the complete list of all connected
|
||||||
|
@ -625,16 +562,8 @@ namespace libtorrent
|
||||||
extension_list_t m_extensions;
|
extension_list_t m_extensions;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// data shared between the main thread
|
|
||||||
// and the checker thread
|
|
||||||
checker_impl m_checker_impl;
|
|
||||||
|
|
||||||
// the main working thread
|
// the main working thread
|
||||||
boost::scoped_ptr<boost::thread> m_thread;
|
boost::scoped_ptr<boost::thread> m_thread;
|
||||||
|
|
||||||
// the thread that calls initialize_pieces()
|
|
||||||
// on all torrents before they start downloading
|
|
||||||
boost::scoped_ptr<boost::thread> m_checker_thread;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_LOGGING || defined TORRENT_ERROR_LOGGING
|
#if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_LOGGING || defined TORRENT_ERROR_LOGGING
|
||||||
|
|
|
@ -77,6 +77,8 @@ namespace libtorrent
|
||||||
, move_storage
|
, move_storage
|
||||||
, release_files
|
, release_files
|
||||||
, delete_files
|
, delete_files
|
||||||
|
, check_fastresume
|
||||||
|
, check_files
|
||||||
};
|
};
|
||||||
|
|
||||||
action_t action;
|
action_t action;
|
||||||
|
@ -154,10 +156,6 @@ namespace libtorrent
|
||||||
, boost::function<void(int, disk_io_job const&)> const& f
|
, boost::function<void(int, disk_io_job const&)> const& f
|
||||||
= boost::function<void(int, disk_io_job const&)>());
|
= boost::function<void(int, disk_io_job const&)>());
|
||||||
|
|
||||||
#ifndef NDEBUG
|
|
||||||
disk_io_job find_job(boost::intrusive_ptr<piece_manager> s
|
|
||||||
, int action, int piece) const;
|
|
||||||
#endif
|
|
||||||
// keep track of the number of bytes in the job queue
|
// keep track of the number of bytes in the job queue
|
||||||
// at any given time. i.e. the sum of all buffer_size.
|
// at any given time. i.e. the sum of all buffer_size.
|
||||||
// this is used to slow down the download global download
|
// this is used to slow down the download global download
|
||||||
|
@ -268,9 +266,6 @@ namespace libtorrent
|
||||||
// number of bytes per block. The BitTorrent
|
// number of bytes per block. The BitTorrent
|
||||||
// protocol defines the block size to 16 KiB.
|
// protocol defines the block size to 16 KiB.
|
||||||
int m_block_size;
|
int m_block_size;
|
||||||
#ifndef NDEBUG
|
|
||||||
disk_io_job m_current;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef TORRENT_DISK_STATS
|
#ifdef TORRENT_DISK_STATS
|
||||||
std::ofstream m_log;
|
std::ofstream m_log;
|
||||||
|
|
|
@ -138,10 +138,7 @@ namespace libtorrent
|
||||||
|
|
||||||
// the vector tells which pieces we already have
|
// the vector tells which pieces we already have
|
||||||
// and which we don't have.
|
// and which we don't have.
|
||||||
void files_checked(
|
void init(std::vector<bool> const& pieces);
|
||||||
std::vector<bool> const& pieces
|
|
||||||
, std::vector<downloading_piece> const& unfinished
|
|
||||||
, std::vector<int>& verify_pieces);
|
|
||||||
|
|
||||||
// increases the peer count for the given piece
|
// increases the peer count for the given piece
|
||||||
// (is used when a HAVE message is received)
|
// (is used when a HAVE message is received)
|
||||||
|
|
|
@ -119,12 +119,12 @@ namespace libtorrent
|
||||||
// if allocate_files is true.
|
// if allocate_files is true.
|
||||||
// allocate_files is true if allocation mode
|
// allocate_files is true if allocation mode
|
||||||
// is set to full and sparse files are supported
|
// is set to full and sparse files are supported
|
||||||
|
// false return value indicates an error
|
||||||
virtual bool initialize(bool allocate_files) = 0;
|
virtual bool initialize(bool allocate_files) = 0;
|
||||||
|
|
||||||
// negative return value indicates an error
|
// negative return value indicates an error
|
||||||
virtual size_type read(char* buf, int slot, int offset, int size) = 0;
|
virtual size_type read(char* buf, int slot, int offset, int size) = 0;
|
||||||
|
|
||||||
// may throw file_error if storage for slot hasn't been allocated
|
|
||||||
// negative return value indicates an error
|
// negative return value indicates an error
|
||||||
virtual size_type write(const char* buf, int slot, int offset, int size) = 0;
|
virtual size_type write(const char* buf, int slot, int offset, int size) = 0;
|
||||||
|
|
||||||
|
@ -194,47 +194,22 @@ namespace libtorrent
|
||||||
, fs::path const& path
|
, fs::path const& path
|
||||||
, file_pool& fp
|
, file_pool& fp
|
||||||
, disk_io_thread& io
|
, disk_io_thread& io
|
||||||
, storage_constructor_type sc);
|
, storage_constructor_type sc
|
||||||
|
, storage_mode_t sm);
|
||||||
|
|
||||||
~piece_manager();
|
~piece_manager();
|
||||||
|
|
||||||
torrent_info const* info() const { return m_info.get(); }
|
torrent_info const* info() const { return m_info.get(); }
|
||||||
|
|
||||||
bool check_fastresume(aux::piece_checker_data& d
|
|
||||||
, std::vector<bool>& pieces, int& num_pieces, storage_mode_t storage_mode
|
|
||||||
, std::string& error_msg);
|
|
||||||
std::pair<bool, float> check_files(std::vector<bool>& pieces
|
|
||||||
, int& num_pieces, boost::recursive_mutex& mutex, bool& error);
|
|
||||||
|
|
||||||
// frees a buffer that was returned from a read operation
|
// frees a buffer that was returned from a read operation
|
||||||
void free_buffer(char* buf);
|
void free_buffer(char* buf);
|
||||||
|
|
||||||
void write_resume_data(entry& rd) const
|
void write_resume_data(entry& rd, std::vector<bool> const& have) const;
|
||||||
{ m_storage->write_resume_data(rd); }
|
|
||||||
|
|
||||||
bool verify_resume_data(entry const& rd, std::string& error)
|
void async_check_fastresume(entry const* resume_data
|
||||||
{
|
, boost::function<void(int, disk_io_job const&)> const& handler);
|
||||||
#ifndef NDEBUG
|
|
||||||
m_resume_data_verified = true;
|
|
||||||
#endif
|
|
||||||
return m_storage->verify_resume_data(rd, error);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool is_allocating() const
|
void async_check_files(boost::function<void(int, disk_io_job const&)> const& handler);
|
||||||
{ return m_state == state_expand_pieces; }
|
|
||||||
|
|
||||||
void mark_failed(int index);
|
|
||||||
|
|
||||||
std::string const& error() const { return m_storage->error(); }
|
|
||||||
void clear_error() { m_storage->clear_error(); }
|
|
||||||
|
|
||||||
unsigned long piece_crc(
|
|
||||||
int slot_index
|
|
||||||
, int block_size
|
|
||||||
, piece_picker::block_info const* bi);
|
|
||||||
|
|
||||||
int slot_for(int piece) const;
|
|
||||||
int piece_for(int slot) const;
|
|
||||||
|
|
||||||
void async_read(
|
void async_read(
|
||||||
peer_request const& r
|
peer_request const& r
|
||||||
|
@ -249,8 +224,6 @@ namespace libtorrent
|
||||||
|
|
||||||
void async_hash(int piece, boost::function<void(int, disk_io_job const&)> const& f);
|
void async_hash(int piece, boost::function<void(int, disk_io_job const&)> const& f);
|
||||||
|
|
||||||
fs::path save_path() const;
|
|
||||||
|
|
||||||
void async_release_files(
|
void async_release_files(
|
||||||
boost::function<void(int, disk_io_job const&)> const& handler
|
boost::function<void(int, disk_io_job const&)> const& handler
|
||||||
= boost::function<void(int, disk_io_job const&)>());
|
= boost::function<void(int, disk_io_job const&)>());
|
||||||
|
@ -262,12 +235,44 @@ namespace libtorrent
|
||||||
void async_move_storage(fs::path const& p
|
void async_move_storage(fs::path const& p
|
||||||
, boost::function<void(int, disk_io_job const&)> const& handler);
|
, boost::function<void(int, disk_io_job const&)> const& handler);
|
||||||
|
|
||||||
// fills the vector that maps all allocated
|
enum return_t
|
||||||
// slots to the piece that is stored (or
|
{
|
||||||
// partially stored) there. -2 is the index
|
// return values from check_fastresume and check_files
|
||||||
// of unassigned pieces and -1 is unallocated
|
no_error = 0,
|
||||||
void export_piece_map(std::vector<int>& pieces
|
need_full_check = -1,
|
||||||
, std::vector<bool> const& have) const;
|
fatal_disk_error = -2,
|
||||||
|
};
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
fs::path save_path() const;
|
||||||
|
|
||||||
|
bool verify_resume_data(entry const& rd, std::string& error)
|
||||||
|
{ return m_storage->verify_resume_data(rd, error); }
|
||||||
|
|
||||||
|
bool is_allocating() const
|
||||||
|
{ return m_state == state_expand_pieces; }
|
||||||
|
|
||||||
|
void mark_failed(int index);
|
||||||
|
|
||||||
|
std::string const& error() const { return m_storage->error(); }
|
||||||
|
void clear_error() { m_storage->clear_error(); }
|
||||||
|
|
||||||
|
int slot_for(int piece) const;
|
||||||
|
int piece_for(int slot) const;
|
||||||
|
|
||||||
|
// helper functions for check_dastresume
|
||||||
|
int check_no_fastresume(std::string& error);
|
||||||
|
int check_init_storage(std::string& error);
|
||||||
|
|
||||||
|
// if error is set and return value is 'no_error' or 'need_full_check'
|
||||||
|
// 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);
|
||||||
|
|
||||||
|
// this function returns true if the checking is complete
|
||||||
|
int check_files(int& current_slot, int& have_piece, std::string& error);
|
||||||
|
|
||||||
bool compact_allocation() const
|
bool compact_allocation() const
|
||||||
{ return m_storage_mode == storage_mode_compact; }
|
{ return m_storage_mode == storage_mode_compact; }
|
||||||
|
@ -276,18 +281,8 @@ namespace libtorrent
|
||||||
std::string name() const { return m_info->name(); }
|
std::string name() const { return m_info->name(); }
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
private:
|
|
||||||
|
|
||||||
bool allocate_slots(int num_slots, bool abort_on_disk = false);
|
bool allocate_slots(int num_slots, bool abort_on_disk = false);
|
||||||
|
|
||||||
int identify_data(
|
|
||||||
const std::vector<char>& piece_data
|
|
||||||
, int current_slot
|
|
||||||
, std::vector<bool>& have_pieces
|
|
||||||
, int& num_pieces
|
|
||||||
, const std::multimap<sha1_hash, int>& hash_to_piece
|
|
||||||
, boost::recursive_mutex& mutex);
|
|
||||||
|
|
||||||
size_type read_impl(
|
size_type read_impl(
|
||||||
char* buf
|
char* buf
|
||||||
, int piece_index
|
, int piece_index
|
||||||
|
@ -300,8 +295,10 @@ namespace libtorrent
|
||||||
, int offset
|
, int offset
|
||||||
, int size);
|
, int size);
|
||||||
|
|
||||||
bool check_one_piece(std::vector<bool>& pieces, int& num_pieces
|
bool check_one_piece(int& have_piece);
|
||||||
, boost::recursive_mutex& mutex);
|
int identify_data(
|
||||||
|
const std::vector<char>& piece_data
|
||||||
|
, int current_slot);
|
||||||
|
|
||||||
void switch_to_full_mode();
|
void switch_to_full_mode();
|
||||||
sha1_hash hash_for_piece_impl(int piece);
|
sha1_hash hash_for_piece_impl(int piece);
|
||||||
|
@ -357,8 +354,6 @@ namespace libtorrent
|
||||||
state_none,
|
state_none,
|
||||||
// the file checking is complete
|
// the file checking is complete
|
||||||
state_finished,
|
state_finished,
|
||||||
// creating the directories
|
|
||||||
state_create_files,
|
|
||||||
// checking the files
|
// checking the files
|
||||||
state_full_check,
|
state_full_check,
|
||||||
// move pieces to their final position
|
// move pieces to their final position
|
||||||
|
@ -403,9 +398,6 @@ namespace libtorrent
|
||||||
// the piece_manager destructs. This is because
|
// the piece_manager destructs. This is because
|
||||||
// the torrent_info object is owned by the torrent.
|
// the torrent_info object is owned by the torrent.
|
||||||
boost::shared_ptr<void> m_torrent;
|
boost::shared_ptr<void> m_torrent;
|
||||||
#ifndef NDEBUG
|
|
||||||
bool m_resume_data_verified;
|
|
||||||
#endif
|
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -98,20 +98,19 @@ namespace libtorrent
|
||||||
|
|
||||||
torrent(
|
torrent(
|
||||||
aux::session_impl& ses
|
aux::session_impl& ses
|
||||||
, aux::checker_impl& checker
|
|
||||||
, boost::intrusive_ptr<torrent_info> tf
|
, boost::intrusive_ptr<torrent_info> tf
|
||||||
, fs::path const& save_path
|
, fs::path const& save_path
|
||||||
, tcp::endpoint const& net_interface
|
, tcp::endpoint const& net_interface
|
||||||
, storage_mode_t m_storage_mode
|
, storage_mode_t m_storage_mode
|
||||||
, int block_size
|
, int block_size
|
||||||
, storage_constructor_type sc
|
, storage_constructor_type sc
|
||||||
, bool paused);
|
, bool paused
|
||||||
|
, entry const& resume_data);
|
||||||
|
|
||||||
// used with metadata-less torrents
|
// used with metadata-less torrents
|
||||||
// (the metadata is downloaded from the peers)
|
// (the metadata is downloaded from the peers)
|
||||||
torrent(
|
torrent(
|
||||||
aux::session_impl& ses
|
aux::session_impl& ses
|
||||||
, aux::checker_impl& checker
|
|
||||||
, char const* tracker_url
|
, char const* tracker_url
|
||||||
, sha1_hash const& info_hash
|
, sha1_hash const& info_hash
|
||||||
, char const* name
|
, char const* name
|
||||||
|
@ -120,7 +119,8 @@ namespace libtorrent
|
||||||
, storage_mode_t m_storage_mode
|
, storage_mode_t m_storage_mode
|
||||||
, int block_size
|
, int block_size
|
||||||
, storage_constructor_type sc
|
, storage_constructor_type sc
|
||||||
, bool paused);
|
, bool paused
|
||||||
|
, entry const& resume_data);
|
||||||
|
|
||||||
~torrent();
|
~torrent();
|
||||||
|
|
||||||
|
@ -142,6 +142,12 @@ namespace libtorrent
|
||||||
// it will initialize the storage and the piece-picker
|
// it will initialize the storage and the piece-picker
|
||||||
void init();
|
void init();
|
||||||
|
|
||||||
|
void on_resume_data_checked(int ret, disk_io_job const& j);
|
||||||
|
void on_piece_checked(int ret, disk_io_job const& j);
|
||||||
|
void files_checked();
|
||||||
|
void start_checking();
|
||||||
|
|
||||||
|
storage_mode_t storage_mode() const { return m_storage_mode; }
|
||||||
// this will flag the torrent as aborted. The main
|
// this will flag the torrent as aborted. The main
|
||||||
// loop in session_impl will check for this state
|
// loop in session_impl will check for this state
|
||||||
// on all torrents once every second, and take
|
// on all torrents once every second, and take
|
||||||
|
@ -149,19 +155,12 @@ namespace libtorrent
|
||||||
void abort();
|
void abort();
|
||||||
bool is_aborted() const { return m_abort; }
|
bool is_aborted() const { return m_abort; }
|
||||||
|
|
||||||
// returns true if this torrent is being allocated
|
|
||||||
// by the checker thread.
|
|
||||||
bool is_allocating() const;
|
|
||||||
|
|
||||||
session_settings const& settings() const;
|
session_settings const& settings() const;
|
||||||
|
|
||||||
aux::session_impl& session() { return m_ses; }
|
aux::session_impl& session() { return m_ses; }
|
||||||
|
|
||||||
void set_sequential_download(bool sd);
|
void set_sequential_download(bool sd);
|
||||||
|
|
||||||
bool verify_resume_data(entry const& rd, std::string& error)
|
|
||||||
{ TORRENT_ASSERT(m_storage); return m_storage->verify_resume_data(rd, error); }
|
|
||||||
|
|
||||||
void second_tick(stat& accumulator, float tick_interval);
|
void second_tick(stat& accumulator, float tick_interval);
|
||||||
|
|
||||||
// debug purpose only
|
// debug purpose only
|
||||||
|
@ -169,11 +168,6 @@ namespace libtorrent
|
||||||
|
|
||||||
std::string name() const;
|
std::string name() const;
|
||||||
|
|
||||||
bool check_fastresume(aux::piece_checker_data&);
|
|
||||||
std::pair<bool, float> check_files(bool& error);
|
|
||||||
void files_checked(std::vector<piece_picker::downloading_piece> const&
|
|
||||||
unfinished_pieces);
|
|
||||||
|
|
||||||
stat statistics() const { return m_stat; }
|
stat statistics() const { return m_stat; }
|
||||||
size_type bytes_left() const;
|
size_type bytes_left() const;
|
||||||
boost::tuples::tuple<size_type, size_type> bytes_done() const;
|
boost::tuples::tuple<size_type, size_type> bytes_done() const;
|
||||||
|
@ -705,7 +699,6 @@ namespace libtorrent
|
||||||
// a back reference to the session
|
// a back reference to the session
|
||||||
// this torrent belongs to.
|
// this torrent belongs to.
|
||||||
aux::session_impl& m_ses;
|
aux::session_impl& m_ses;
|
||||||
aux::checker_impl& m_checker;
|
|
||||||
|
|
||||||
boost::scoped_ptr<piece_picker> m_picker;
|
boost::scoped_ptr<piece_picker> m_picker;
|
||||||
|
|
||||||
|
@ -768,6 +761,12 @@ namespace libtorrent
|
||||||
// determines the storage state for this torrent.
|
// determines the storage state for this torrent.
|
||||||
storage_mode_t m_storage_mode;
|
storage_mode_t m_storage_mode;
|
||||||
|
|
||||||
|
// the state of this torrent (queued, checking, downloading)
|
||||||
|
torrent_status::state_t m_state;
|
||||||
|
float m_progress;
|
||||||
|
|
||||||
|
entry m_resume_data;
|
||||||
|
|
||||||
// defaults to 16 kiB, but can be set by the user
|
// defaults to 16 kiB, but can be set by the user
|
||||||
// when creating the torrent
|
// when creating the torrent
|
||||||
const int m_default_block_size;
|
const int m_default_block_size;
|
||||||
|
|
|
@ -278,7 +278,7 @@ namespace libtorrent
|
||||||
friend struct aux::session_impl;
|
friend struct aux::session_impl;
|
||||||
friend class torrent;
|
friend class torrent;
|
||||||
|
|
||||||
torrent_handle(): m_ses(0), m_chk(0), m_info_hash(0) {}
|
torrent_handle(): m_ses(0), m_info_hash(0) {}
|
||||||
|
|
||||||
void get_peer_info(std::vector<peer_info>& v) const;
|
void get_peer_info(std::vector<peer_info>& v) const;
|
||||||
bool send_chat_message(tcp::endpoint ip, std::string message) const;
|
bool send_chat_message(tcp::endpoint ip, std::string message) const;
|
||||||
|
@ -418,15 +418,12 @@ namespace libtorrent
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
torrent_handle(aux::session_impl* s,
|
torrent_handle(aux::session_impl* s
|
||||||
aux::checker_impl* c,
|
, const sha1_hash& h)
|
||||||
const sha1_hash& h)
|
|
||||||
: m_ses(s)
|
: m_ses(s)
|
||||||
, m_chk(c)
|
|
||||||
, m_info_hash(h)
|
, m_info_hash(h)
|
||||||
{
|
{
|
||||||
TORRENT_ASSERT(m_ses != 0);
|
TORRENT_ASSERT(m_ses != 0);
|
||||||
TORRENT_ASSERT(m_chk != 0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef NDEBUG
|
#ifndef NDEBUG
|
||||||
|
@ -434,7 +431,6 @@ namespace libtorrent
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
aux::session_impl* m_ses;
|
aux::session_impl* m_ses;
|
||||||
aux::checker_impl* m_chk;
|
|
||||||
sha1_hash m_info_hash;
|
sha1_hash m_info_hash;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
|
@ -73,31 +73,6 @@ namespace libtorrent
|
||||||
TORRENT_ASSERT(m_abort == true);
|
TORRENT_ASSERT(m_abort == true);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef NDEBUG
|
|
||||||
disk_io_job disk_io_thread::find_job(boost::intrusive_ptr<piece_manager> s
|
|
||||||
, int action, int piece) const
|
|
||||||
{
|
|
||||||
mutex_t::scoped_lock l(m_mutex);
|
|
||||||
for (std::list<disk_io_job>::const_iterator i = m_jobs.begin();
|
|
||||||
i != m_jobs.end(); ++i)
|
|
||||||
{
|
|
||||||
if (i->storage != s)
|
|
||||||
continue;
|
|
||||||
if ((i->action == action || action == -1) && i->piece == piece)
|
|
||||||
return *i;
|
|
||||||
}
|
|
||||||
if ((m_current.action == action || action == -1)
|
|
||||||
&& m_current.piece == piece)
|
|
||||||
return m_current;
|
|
||||||
|
|
||||||
disk_io_job ret;
|
|
||||||
ret.action = (disk_io_job::action_t)-1;
|
|
||||||
ret.piece = -1;
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
void disk_io_thread::join()
|
void disk_io_thread::join()
|
||||||
{
|
{
|
||||||
mutex_t::scoped_lock l(m_mutex);
|
mutex_t::scoped_lock l(m_mutex);
|
||||||
|
@ -735,19 +710,14 @@ namespace libtorrent
|
||||||
m_log << log_time() << " idle" << std::endl;
|
m_log << log_time() << " idle" << std::endl;
|
||||||
#endif
|
#endif
|
||||||
mutex_t::scoped_lock l(m_mutex);
|
mutex_t::scoped_lock l(m_mutex);
|
||||||
#ifndef NDEBUG
|
|
||||||
m_current.action = (disk_io_job::action_t)-1;
|
|
||||||
m_current.piece = -1;
|
|
||||||
#endif
|
|
||||||
while (m_jobs.empty() && !m_abort)
|
while (m_jobs.empty() && !m_abort)
|
||||||
m_signal.wait(l);
|
m_signal.wait(l);
|
||||||
if (m_abort && m_jobs.empty()) return;
|
if (m_abort && m_jobs.empty()) return;
|
||||||
|
|
||||||
boost::function<void(int, disk_io_job const&)> handler;
|
boost::function<void(int, disk_io_job const&)> handler;
|
||||||
handler.swap(m_jobs.front().callback);
|
handler.swap(m_jobs.front().callback);
|
||||||
#ifndef NDEBUG
|
|
||||||
m_current = m_jobs.front();
|
|
||||||
#endif
|
|
||||||
disk_io_job j = m_jobs.front();
|
disk_io_job j = m_jobs.front();
|
||||||
m_jobs.pop_front();
|
m_jobs.pop_front();
|
||||||
m_queue_buffer_size -= j.buffer_size;
|
m_queue_buffer_size -= j.buffer_size;
|
||||||
|
@ -876,8 +846,8 @@ namespace libtorrent
|
||||||
j.storage->clear_error();
|
j.storage->clear_error();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
j.str.resize(20);
|
ret = (j.storage->info()->hash_for_piece(j.piece) == h)?0:-1;
|
||||||
std::memcpy(&j.str[0], &h[0], 20);
|
if (ret == -1) j.storage->mark_failed(j.piece);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case disk_io_job::move_storage:
|
case disk_io_job::move_storage:
|
||||||
|
@ -950,6 +920,47 @@ namespace libtorrent
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case disk_io_job::check_fastresume:
|
||||||
|
{
|
||||||
|
#ifdef TORRENT_DISK_STATS
|
||||||
|
m_log << log_time() << " check fastresume" << std::endl;
|
||||||
|
#endif
|
||||||
|
entry const* rd = (entry const*)j.buffer;
|
||||||
|
TORRENT_ASSERT(rd != 0);
|
||||||
|
ret = j.storage->check_fastresume(*rd, j.str);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case disk_io_job::check_files:
|
||||||
|
{
|
||||||
|
#ifdef TORRENT_DISK_STATS
|
||||||
|
m_log << log_time() << " check files" << std::endl;
|
||||||
|
#endif
|
||||||
|
int piece_size = j.storage->info()->piece_length();
|
||||||
|
for (int processed = 0; processed < 4 * 1024 * 1024; processed += piece_size)
|
||||||
|
{
|
||||||
|
ret = j.storage->check_files(j.piece, j.offset, j.str);
|
||||||
|
|
||||||
|
#ifndef BOOST_NO_EXCEPTIONS
|
||||||
|
try {
|
||||||
|
#endif
|
||||||
|
TORRENT_ASSERT(handler);
|
||||||
|
if (handler && ret == piece_manager::need_full_check)
|
||||||
|
m_ios.post(bind(handler, ret, j));
|
||||||
|
#ifndef BOOST_NO_EXCEPTIONS
|
||||||
|
} catch (std::exception&) {}
|
||||||
|
#endif
|
||||||
|
if (ret != piece_manager::need_full_check) break;
|
||||||
|
}
|
||||||
|
// if the check is not done, add it at the end of the job queue
|
||||||
|
if (ret == piece_manager::need_full_check)
|
||||||
|
{
|
||||||
|
mutex_t::scoped_lock l(m_mutex);
|
||||||
|
m_jobs.push_back(j);
|
||||||
|
m_jobs.back().callback.swap(handler);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#ifndef BOOST_NO_EXCEPTIONS
|
#ifndef BOOST_NO_EXCEPTIONS
|
||||||
|
@ -973,12 +984,6 @@ namespace libtorrent
|
||||||
#ifndef BOOST_NO_EXCEPTIONS
|
#ifndef BOOST_NO_EXCEPTIONS
|
||||||
} catch (std::exception&) {}
|
} catch (std::exception&) {}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
#ifndef NDEBUG
|
|
||||||
m_current.storage = 0;
|
|
||||||
m_current.callback.clear();
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
TORRENT_ASSERT(false);
|
TORRENT_ASSERT(false);
|
||||||
}
|
}
|
||||||
|
|
|
@ -122,10 +122,7 @@ namespace libtorrent
|
||||||
}
|
}
|
||||||
|
|
||||||
// pieces is a bitmask with the pieces we have
|
// pieces is a bitmask with the pieces we have
|
||||||
void piece_picker::files_checked(
|
void piece_picker::init(std::vector<bool> const& pieces)
|
||||||
std::vector<bool> const& pieces
|
|
||||||
, std::vector<downloading_piece> const& unfinished
|
|
||||||
, std::vector<int>& verify_pieces)
|
|
||||||
{
|
{
|
||||||
TORRENT_PIECE_PICKER_INVARIANT_CHECK;
|
TORRENT_PIECE_PICKER_INVARIANT_CHECK;
|
||||||
#ifndef NDEBUG
|
#ifndef NDEBUG
|
||||||
|
@ -153,25 +150,6 @@ namespace libtorrent
|
||||||
p.index = 0;
|
p.index = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// if we have fast resume info
|
|
||||||
// use it
|
|
||||||
if (!unfinished.empty())
|
|
||||||
{
|
|
||||||
for (std::vector<downloading_piece>::const_iterator i
|
|
||||||
= unfinished.begin(); i != unfinished.end(); ++i)
|
|
||||||
{
|
|
||||||
for (int j = 0; j < m_blocks_per_piece; ++j)
|
|
||||||
{
|
|
||||||
if (i->info[j].state == block_info::state_finished)
|
|
||||||
mark_as_finished(piece_block(i->index, j), 0);
|
|
||||||
}
|
|
||||||
if (is_piece_finished(i->index))
|
|
||||||
{
|
|
||||||
verify_pieces.push_back(i->index);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void piece_picker::piece_info(int index, piece_picker::downloading_piece& st) const
|
void piece_picker::piece_info(int index, piece_picker::downloading_piece& st) const
|
||||||
|
|
|
@ -116,362 +116,8 @@ namespace detail
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
} namespace aux {
|
}
|
||||||
// This is the checker thread
|
namespace aux {
|
||||||
// it is looping in an infinite loop
|
|
||||||
// until the session is aborted. It will
|
|
||||||
// normally just block in a wait() call,
|
|
||||||
// waiting for a signal from session that
|
|
||||||
// there's a new torrent to check.
|
|
||||||
|
|
||||||
void checker_impl::operator()()
|
|
||||||
{
|
|
||||||
eh_initializer();
|
|
||||||
// if we're currently performing a full file check,
|
|
||||||
// this is the torrent being processed
|
|
||||||
boost::shared_ptr<piece_checker_data> processing;
|
|
||||||
boost::shared_ptr<piece_checker_data> t;
|
|
||||||
for (;;)
|
|
||||||
{
|
|
||||||
// temporary torrent used while checking fastresume data
|
|
||||||
t.reset();
|
|
||||||
{
|
|
||||||
boost::mutex::scoped_lock l(m_mutex);
|
|
||||||
|
|
||||||
INVARIANT_CHECK;
|
|
||||||
|
|
||||||
// if the job queue is empty and
|
|
||||||
// we shouldn't abort
|
|
||||||
// wait for a signal
|
|
||||||
while (m_torrents.empty() && !m_abort && !processing)
|
|
||||||
m_cond.wait(l);
|
|
||||||
|
|
||||||
if (m_abort)
|
|
||||||
{
|
|
||||||
// no lock is needed here, because the main thread
|
|
||||||
// has already been shut down by now
|
|
||||||
processing.reset();
|
|
||||||
t.reset();
|
|
||||||
std::for_each(m_torrents.begin(), m_torrents.end()
|
|
||||||
, boost::bind(&torrent::abort
|
|
||||||
, boost::bind(&shared_ptr<torrent>::get
|
|
||||||
, boost::bind(&piece_checker_data::torrent_ptr, _1))));
|
|
||||||
m_torrents.clear();
|
|
||||||
std::for_each(m_processing.begin(), m_processing.end()
|
|
||||||
, boost::bind(&torrent::abort
|
|
||||||
, boost::bind(&shared_ptr<torrent>::get
|
|
||||||
, boost::bind(&piece_checker_data::torrent_ptr, _1))));
|
|
||||||
m_processing.clear();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!m_torrents.empty())
|
|
||||||
{
|
|
||||||
t = m_torrents.front();
|
|
||||||
if (t->abort)
|
|
||||||
{
|
|
||||||
// make sure the locking order is
|
|
||||||
// consistent to avoid dead locks
|
|
||||||
// we need to lock the session because closing
|
|
||||||
// torrents assume to have access to it
|
|
||||||
l.unlock();
|
|
||||||
session_impl::mutex_t::scoped_lock l2(m_ses.m_mutex);
|
|
||||||
l.lock();
|
|
||||||
|
|
||||||
t->torrent_ptr->abort();
|
|
||||||
m_torrents.pop_front();
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (t)
|
|
||||||
{
|
|
||||||
std::string error_msg;
|
|
||||||
t->parse_resume_data(t->resume_data, t->torrent_ptr->torrent_file()
|
|
||||||
, error_msg);
|
|
||||||
|
|
||||||
// lock the session to add the new torrent
|
|
||||||
session_impl::mutex_t::scoped_lock l(m_ses.m_mutex);
|
|
||||||
|
|
||||||
if (!error_msg.empty() && m_ses.m_alerts.should_post(alert::warning))
|
|
||||||
{
|
|
||||||
m_ses.m_alerts.post_alert(fastresume_rejected_alert(
|
|
||||||
t->torrent_ptr->get_handle()
|
|
||||||
, error_msg));
|
|
||||||
#if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING)
|
|
||||||
(*m_ses.m_logger) << "fastresume data for "
|
|
||||||
<< t->torrent_ptr->torrent_file().name() << " rejected: "
|
|
||||||
<< error_msg << "\n";
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
mutex::scoped_lock l2(m_mutex);
|
|
||||||
|
|
||||||
if (m_torrents.empty() || m_torrents.front() != t)
|
|
||||||
{
|
|
||||||
// this means the torrent was removed right after it was
|
|
||||||
// added. Abort the checking.
|
|
||||||
t.reset();
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// clear the resume data now that it has been used
|
|
||||||
// (the fast resume data is now parsed and stored in t)
|
|
||||||
t->resume_data = entry();
|
|
||||||
bool up_to_date = t->torrent_ptr->check_fastresume(*t);
|
|
||||||
|
|
||||||
if (up_to_date)
|
|
||||||
{
|
|
||||||
INVARIANT_CHECK;
|
|
||||||
|
|
||||||
TORRENT_ASSERT(!m_torrents.empty());
|
|
||||||
TORRENT_ASSERT(m_torrents.front() == t);
|
|
||||||
|
|
||||||
t->torrent_ptr->files_checked(t->unfinished_pieces);
|
|
||||||
m_torrents.pop_front();
|
|
||||||
|
|
||||||
// we cannot add the torrent if the session is aborted.
|
|
||||||
if (!m_ses.is_aborted())
|
|
||||||
{
|
|
||||||
m_ses.m_torrents.insert(std::make_pair(t->info_hash, t->torrent_ptr));
|
|
||||||
if (m_ses.m_alerts.should_post(alert::info))
|
|
||||||
{
|
|
||||||
m_ses.m_alerts.post_alert(torrent_checked_alert(
|
|
||||||
processing->torrent_ptr->get_handle()
|
|
||||||
, "torrent finished checking"));
|
|
||||||
}
|
|
||||||
if (t->torrent_ptr->is_seed() && m_ses.m_alerts.should_post(alert::info))
|
|
||||||
{
|
|
||||||
m_ses.m_alerts.post_alert(torrent_finished_alert(
|
|
||||||
t->torrent_ptr->get_handle()
|
|
||||||
, "torrent is complete"));
|
|
||||||
}
|
|
||||||
|
|
||||||
peer_id id;
|
|
||||||
std::fill(id.begin(), id.end(), 0);
|
|
||||||
for (std::vector<tcp::endpoint>::const_iterator i = t->peers.begin();
|
|
||||||
i != t->peers.end(); ++i)
|
|
||||||
{
|
|
||||||
t->torrent_ptr->get_policy().peer_from_tracker(*i, id
|
|
||||||
, peer_info::resume_data, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (std::vector<tcp::endpoint>::const_iterator i = t->banned_peers.begin();
|
|
||||||
i != t->banned_peers.end(); ++i)
|
|
||||||
{
|
|
||||||
policy::peer* p = t->torrent_ptr->get_policy().peer_from_tracker(*i, id
|
|
||||||
, peer_info::resume_data, 0);
|
|
||||||
if (p) p->banned = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
t->torrent_ptr->abort();
|
|
||||||
}
|
|
||||||
t.reset();
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
l.unlock();
|
|
||||||
|
|
||||||
// move the torrent from
|
|
||||||
// m_torrents to m_processing
|
|
||||||
TORRENT_ASSERT(m_torrents.front() == t);
|
|
||||||
|
|
||||||
m_torrents.pop_front();
|
|
||||||
m_processing.push_back(t);
|
|
||||||
if (!processing)
|
|
||||||
{
|
|
||||||
processing = t;
|
|
||||||
processing->processing = true;
|
|
||||||
t.reset();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!processing) continue;
|
|
||||||
|
|
||||||
TORRENT_ASSERT(processing);
|
|
||||||
|
|
||||||
bool finished = false;
|
|
||||||
bool error = false;
|
|
||||||
float progress = 0.f;
|
|
||||||
boost::tie(finished, progress) = processing->torrent_ptr->check_files(error);
|
|
||||||
|
|
||||||
if (error)
|
|
||||||
{
|
|
||||||
// This will happen if the storage fails to initialize
|
|
||||||
session_impl::mutex_t::scoped_lock l(m_ses.m_mutex);
|
|
||||||
mutex::scoped_lock l2(m_mutex);
|
|
||||||
|
|
||||||
if (!m_processing.empty()
|
|
||||||
&& m_processing.front() == processing)
|
|
||||||
m_processing.pop_front();
|
|
||||||
processing.reset();
|
|
||||||
if (!m_processing.empty())
|
|
||||||
{
|
|
||||||
processing = m_processing.front();
|
|
||||||
processing->processing = true;
|
|
||||||
}
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
mutex::scoped_lock l2(m_mutex);
|
|
||||||
|
|
||||||
INVARIANT_CHECK;
|
|
||||||
|
|
||||||
processing->progress = progress;
|
|
||||||
if (processing->abort)
|
|
||||||
{
|
|
||||||
TORRENT_ASSERT(!m_processing.empty());
|
|
||||||
TORRENT_ASSERT(m_processing.front() == processing);
|
|
||||||
m_processing.pop_front();
|
|
||||||
|
|
||||||
// make sure the lock order is correct
|
|
||||||
l2.unlock();
|
|
||||||
session_impl::mutex_t::scoped_lock l(m_ses.m_mutex);
|
|
||||||
l2.lock();
|
|
||||||
processing->torrent_ptr->abort();
|
|
||||||
|
|
||||||
processing.reset();
|
|
||||||
if (!m_processing.empty())
|
|
||||||
{
|
|
||||||
processing = m_processing.front();
|
|
||||||
processing->processing = true;
|
|
||||||
}
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (finished)
|
|
||||||
{
|
|
||||||
// lock the session to add the new torrent
|
|
||||||
session_impl::mutex_t::scoped_lock l(m_ses.m_mutex);
|
|
||||||
mutex::scoped_lock l2(m_mutex);
|
|
||||||
|
|
||||||
INVARIANT_CHECK;
|
|
||||||
|
|
||||||
TORRENT_ASSERT(!m_processing.empty());
|
|
||||||
TORRENT_ASSERT(m_processing.front() == processing);
|
|
||||||
|
|
||||||
// TODO: factor out the adding of torrents to the session
|
|
||||||
// and to the checker thread to avoid duplicating the
|
|
||||||
// check for abortion.
|
|
||||||
if (!m_ses.is_aborted())
|
|
||||||
{
|
|
||||||
processing->torrent_ptr->files_checked(processing->unfinished_pieces);
|
|
||||||
m_ses.m_torrents.insert(std::make_pair(
|
|
||||||
processing->info_hash, processing->torrent_ptr));
|
|
||||||
if (m_ses.m_alerts.should_post(alert::info))
|
|
||||||
{
|
|
||||||
m_ses.m_alerts.post_alert(torrent_checked_alert(
|
|
||||||
processing->torrent_ptr->get_handle()
|
|
||||||
, "torrent finished checking"));
|
|
||||||
}
|
|
||||||
if (processing->torrent_ptr->is_seed()
|
|
||||||
&& m_ses.m_alerts.should_post(alert::info))
|
|
||||||
{
|
|
||||||
m_ses.m_alerts.post_alert(torrent_finished_alert(
|
|
||||||
processing->torrent_ptr->get_handle()
|
|
||||||
, "torrent is complete"));
|
|
||||||
}
|
|
||||||
|
|
||||||
peer_id id;
|
|
||||||
std::fill(id.begin(), id.end(), 0);
|
|
||||||
for (std::vector<tcp::endpoint>::const_iterator i = processing->peers.begin();
|
|
||||||
i != processing->peers.end(); ++i)
|
|
||||||
{
|
|
||||||
processing->torrent_ptr->get_policy().peer_from_tracker(*i, id
|
|
||||||
, peer_info::resume_data, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (std::vector<tcp::endpoint>::const_iterator i = processing->banned_peers.begin();
|
|
||||||
i != processing->banned_peers.end(); ++i)
|
|
||||||
{
|
|
||||||
policy::peer* p = processing->torrent_ptr->get_policy().peer_from_tracker(*i, id
|
|
||||||
, peer_info::resume_data, 0);
|
|
||||||
if (p) p->banned = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
processing->torrent_ptr->abort();
|
|
||||||
}
|
|
||||||
processing.reset();
|
|
||||||
m_processing.pop_front();
|
|
||||||
if (!m_processing.empty())
|
|
||||||
{
|
|
||||||
processing = m_processing.front();
|
|
||||||
processing->processing = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
aux::piece_checker_data* checker_impl::find_torrent(sha1_hash const& info_hash)
|
|
||||||
{
|
|
||||||
INVARIANT_CHECK;
|
|
||||||
for (std::deque<boost::shared_ptr<piece_checker_data> >::iterator i
|
|
||||||
= m_torrents.begin(); i != m_torrents.end(); ++i)
|
|
||||||
{
|
|
||||||
if ((*i)->info_hash == info_hash) return i->get();
|
|
||||||
}
|
|
||||||
for (std::deque<boost::shared_ptr<piece_checker_data> >::iterator i
|
|
||||||
= m_processing.begin(); i != m_processing.end(); ++i)
|
|
||||||
{
|
|
||||||
if ((*i)->info_hash == info_hash) return i->get();
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void checker_impl::remove_torrent(sha1_hash const& info_hash, int options)
|
|
||||||
{
|
|
||||||
INVARIANT_CHECK;
|
|
||||||
for (std::deque<boost::shared_ptr<piece_checker_data> >::iterator i
|
|
||||||
= m_torrents.begin(); i != m_torrents.end(); ++i)
|
|
||||||
{
|
|
||||||
if ((*i)->info_hash == info_hash)
|
|
||||||
{
|
|
||||||
TORRENT_ASSERT((*i)->processing == false);
|
|
||||||
if (options & session::delete_files)
|
|
||||||
(*i)->torrent_ptr->delete_files();
|
|
||||||
m_torrents.erase(i);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for (std::deque<boost::shared_ptr<piece_checker_data> >::iterator i
|
|
||||||
= m_processing.begin(); i != m_processing.end(); ++i)
|
|
||||||
{
|
|
||||||
if ((*i)->info_hash == info_hash)
|
|
||||||
{
|
|
||||||
TORRENT_ASSERT((*i)->processing == false);
|
|
||||||
if (options & session::delete_files)
|
|
||||||
(*i)->torrent_ptr->delete_files();
|
|
||||||
m_processing.erase(i);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
TORRENT_ASSERT(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifndef NDEBUG
|
|
||||||
void checker_impl::check_invariant() const
|
|
||||||
{
|
|
||||||
for (std::deque<boost::shared_ptr<piece_checker_data> >::const_iterator i
|
|
||||||
= m_torrents.begin(); i != m_torrents.end(); ++i)
|
|
||||||
{
|
|
||||||
TORRENT_ASSERT(*i);
|
|
||||||
TORRENT_ASSERT((*i)->torrent_ptr);
|
|
||||||
}
|
|
||||||
for (std::deque<boost::shared_ptr<piece_checker_data> >::const_iterator i
|
|
||||||
= m_processing.begin(); i != m_processing.end(); ++i)
|
|
||||||
{
|
|
||||||
TORRENT_ASSERT(*i);
|
|
||||||
TORRENT_ASSERT((*i)->torrent_ptr);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
struct seed_random_generator
|
struct seed_random_generator
|
||||||
{
|
{
|
||||||
|
@ -524,7 +170,6 @@ namespace detail
|
||||||
#if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_LOGGING || defined TORRENT_ERROR_LOGGING
|
#if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_LOGGING || defined TORRENT_ERROR_LOGGING
|
||||||
, m_logpath(logpath)
|
, m_logpath(logpath)
|
||||||
#endif
|
#endif
|
||||||
, m_checker_impl(*this)
|
|
||||||
{
|
{
|
||||||
#ifdef WIN32
|
#ifdef WIN32
|
||||||
// windows XP has a limit on the number of
|
// windows XP has a limit on the number of
|
||||||
|
@ -596,7 +241,6 @@ namespace detail
|
||||||
bind(&session_impl::second_tick, this, _1));
|
bind(&session_impl::second_tick, this, _1));
|
||||||
|
|
||||||
m_thread.reset(new boost::thread(boost::ref(*this)));
|
m_thread.reset(new boost::thread(boost::ref(*this)));
|
||||||
m_checker_thread.reset(new boost::thread(boost::ref(m_checker_impl)));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef TORRENT_DISABLE_EXTENSIONS
|
#ifndef TORRENT_DISABLE_EXTENSIONS
|
||||||
|
@ -711,10 +355,6 @@ namespace detail
|
||||||
|
|
||||||
m_download_channel.close();
|
m_download_channel.close();
|
||||||
m_upload_channel.close();
|
m_upload_channel.close();
|
||||||
|
|
||||||
mutex::scoped_lock l2(m_checker_impl.m_mutex);
|
|
||||||
// abort the checker thread
|
|
||||||
m_checker_impl.m_abort = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void session_impl::set_port_filter(port_filter const& f)
|
void session_impl::set_port_filter(port_filter const& f)
|
||||||
|
@ -1077,25 +717,6 @@ namespace detail
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
|
||||||
namespace
|
|
||||||
{
|
|
||||||
struct compare_peer_ptr
|
|
||||||
{
|
|
||||||
bool operator()(peer_connection const* lhs
|
|
||||||
, intrusive_ptr<peer_connection const> const& rhs)
|
|
||||||
{
|
|
||||||
return lhs < rhs.get();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool operator()(intrusive_ptr<peer_connection const> const& lhs
|
|
||||||
, peer_connection const* rhs)
|
|
||||||
{
|
|
||||||
return lhs.get() < rhs;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
void session_impl::close_connection(peer_connection const* p
|
void session_impl::close_connection(peer_connection const* p
|
||||||
, char const* message)
|
, char const* message)
|
||||||
{
|
{
|
||||||
|
@ -1647,40 +1268,21 @@ namespace detail
|
||||||
std::vector<torrent_handle> session_impl::get_torrents()
|
std::vector<torrent_handle> session_impl::get_torrents()
|
||||||
{
|
{
|
||||||
mutex_t::scoped_lock l(m_mutex);
|
mutex_t::scoped_lock l(m_mutex);
|
||||||
mutex::scoped_lock l2(m_checker_impl.m_mutex);
|
|
||||||
std::vector<torrent_handle> ret;
|
std::vector<torrent_handle> ret;
|
||||||
for (std::deque<boost::shared_ptr<aux::piece_checker_data> >::iterator i
|
|
||||||
= m_checker_impl.m_torrents.begin()
|
|
||||||
, end(m_checker_impl.m_torrents.end()); i != end; ++i)
|
|
||||||
{
|
|
||||||
if ((*i)->abort) continue;
|
|
||||||
ret.push_back(torrent_handle(this, &m_checker_impl
|
|
||||||
, (*i)->info_hash));
|
|
||||||
}
|
|
||||||
|
|
||||||
for (std::deque<boost::shared_ptr<aux::piece_checker_data> >::iterator i
|
|
||||||
= m_checker_impl.m_processing.begin()
|
|
||||||
, end(m_checker_impl.m_processing.end()); i != end; ++i)
|
|
||||||
{
|
|
||||||
if ((*i)->abort) continue;
|
|
||||||
ret.push_back(torrent_handle(this, &m_checker_impl
|
|
||||||
, (*i)->info_hash));
|
|
||||||
}
|
|
||||||
|
|
||||||
for (session_impl::torrent_map::iterator i
|
for (session_impl::torrent_map::iterator i
|
||||||
= m_torrents.begin(), end(m_torrents.end());
|
= m_torrents.begin(), end(m_torrents.end());
|
||||||
i != end; ++i)
|
i != end; ++i)
|
||||||
{
|
{
|
||||||
if (i->second->is_aborted()) continue;
|
if (i->second->is_aborted()) continue;
|
||||||
ret.push_back(torrent_handle(this, &m_checker_impl
|
ret.push_back(torrent_handle(this, i->first));
|
||||||
, i->first));
|
|
||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
torrent_handle session_impl::find_torrent_handle(sha1_hash const& info_hash)
|
torrent_handle session_impl::find_torrent_handle(sha1_hash const& info_hash)
|
||||||
{
|
{
|
||||||
return torrent_handle(this, &m_checker_impl, info_hash);
|
return torrent_handle(this, info_hash);
|
||||||
}
|
}
|
||||||
|
|
||||||
torrent_handle session_impl::add_torrent(
|
torrent_handle session_impl::add_torrent(
|
||||||
|
@ -1699,7 +1301,6 @@ namespace detail
|
||||||
|
|
||||||
// lock the session and the checker thread (the order is important!)
|
// lock the session and the checker thread (the order is important!)
|
||||||
mutex_t::scoped_lock l(m_mutex);
|
mutex_t::scoped_lock l(m_mutex);
|
||||||
mutex::scoped_lock l2(m_checker_impl.m_mutex);
|
|
||||||
|
|
||||||
// INVARIANT_CHECK;
|
// INVARIANT_CHECK;
|
||||||
|
|
||||||
|
@ -1710,17 +1311,13 @@ namespace detail
|
||||||
if (!find_torrent(ti->info_hash()).expired())
|
if (!find_torrent(ti->info_hash()).expired())
|
||||||
throw duplicate_torrent();
|
throw duplicate_torrent();
|
||||||
|
|
||||||
// is the torrent currently being checked?
|
|
||||||
if (m_checker_impl.find_torrent(ti->info_hash()))
|
|
||||||
throw duplicate_torrent();
|
|
||||||
|
|
||||||
// create the torrent and the data associated with
|
// create the torrent and the data associated with
|
||||||
// the checker thread and store it before starting
|
// the checker thread and store it before starting
|
||||||
// the thread
|
// the thread
|
||||||
boost::shared_ptr<torrent> torrent_ptr(
|
boost::shared_ptr<torrent> torrent_ptr(
|
||||||
new torrent(*this, m_checker_impl, ti, save_path
|
new torrent(*this, ti, save_path
|
||||||
, m_listen_interface, storage_mode, 16 * 1024
|
, m_listen_interface, storage_mode, 16 * 1024
|
||||||
, sc, paused));
|
, sc, paused, resume_data));
|
||||||
torrent_ptr->start();
|
torrent_ptr->start();
|
||||||
|
|
||||||
#ifndef TORRENT_DISABLE_EXTENSIONS
|
#ifndef TORRENT_DISABLE_EXTENSIONS
|
||||||
|
@ -1732,13 +1329,6 @@ namespace detail
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
boost::shared_ptr<aux::piece_checker_data> d(
|
|
||||||
new aux::piece_checker_data);
|
|
||||||
d->torrent_ptr = torrent_ptr;
|
|
||||||
d->save_path = save_path;
|
|
||||||
d->info_hash = ti->info_hash();
|
|
||||||
d->resume_data = resume_data;
|
|
||||||
|
|
||||||
#ifndef TORRENT_DISABLE_DHT
|
#ifndef TORRENT_DISABLE_DHT
|
||||||
if (m_dht)
|
if (m_dht)
|
||||||
{
|
{
|
||||||
|
@ -1750,13 +1340,23 @@ namespace detail
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// add the torrent to the queue to be checked
|
m_torrents.insert(std::make_pair(ti->info_hash(), torrent_ptr));
|
||||||
m_checker_impl.m_torrents.push_back(d);
|
|
||||||
// and notify the thread that it got another
|
|
||||||
// job in its queue
|
|
||||||
m_checker_impl.m_cond.notify_one();
|
|
||||||
|
|
||||||
return torrent_handle(this, &m_checker_impl, ti->info_hash());
|
return torrent_handle(this, ti->info_hash());
|
||||||
|
}
|
||||||
|
|
||||||
|
void session_impl::check_torrent(boost::shared_ptr<torrent> const& t)
|
||||||
|
{
|
||||||
|
if (m_queued_for_checking.empty()) t->start_checking();
|
||||||
|
m_queued_for_checking.push_back(t);
|
||||||
|
}
|
||||||
|
|
||||||
|
void session_impl::done_checking(boost::shared_ptr<torrent> const& t)
|
||||||
|
{
|
||||||
|
TORRENT_ASSERT(m_queued_for_checking.front() == t);
|
||||||
|
m_queued_for_checking.pop_front();
|
||||||
|
if (!m_queued_for_checking.empty())
|
||||||
|
m_queued_for_checking.front()->start_checking();
|
||||||
}
|
}
|
||||||
|
|
||||||
torrent_handle session_impl::add_torrent(
|
torrent_handle session_impl::add_torrent(
|
||||||
|
@ -1764,7 +1364,7 @@ namespace detail
|
||||||
, sha1_hash const& info_hash
|
, sha1_hash const& info_hash
|
||||||
, char const* name
|
, char const* name
|
||||||
, fs::path const& save_path
|
, fs::path const& save_path
|
||||||
, entry const&
|
, entry const& resume_data
|
||||||
, storage_mode_t storage_mode
|
, storage_mode_t storage_mode
|
||||||
, storage_constructor_type sc
|
, storage_constructor_type sc
|
||||||
, bool paused
|
, bool paused
|
||||||
|
@ -1773,14 +1373,6 @@ namespace detail
|
||||||
|
|
||||||
// TODO: support resume data in this case
|
// TODO: support resume data in this case
|
||||||
TORRENT_ASSERT(!save_path.empty());
|
TORRENT_ASSERT(!save_path.empty());
|
||||||
{
|
|
||||||
// lock the checker_thread
|
|
||||||
mutex::scoped_lock l(m_checker_impl.m_mutex);
|
|
||||||
|
|
||||||
// is the torrent currently being checked?
|
|
||||||
if (m_checker_impl.find_torrent(info_hash))
|
|
||||||
throw duplicate_torrent();
|
|
||||||
}
|
|
||||||
|
|
||||||
// lock the session
|
// lock the session
|
||||||
session_impl::mutex_t::scoped_lock l(m_mutex);
|
session_impl::mutex_t::scoped_lock l(m_mutex);
|
||||||
|
@ -1789,7 +1381,11 @@ namespace detail
|
||||||
|
|
||||||
// is the torrent already active?
|
// is the torrent already active?
|
||||||
if (!find_torrent(info_hash).expired())
|
if (!find_torrent(info_hash).expired())
|
||||||
|
#ifndef BOOST_NO_EXCEPTIONS
|
||||||
throw duplicate_torrent();
|
throw duplicate_torrent();
|
||||||
|
#else
|
||||||
|
return torrent_handle();
|
||||||
|
#endif
|
||||||
|
|
||||||
// you cannot add new torrents to a session that is closing down
|
// you cannot add new torrents to a session that is closing down
|
||||||
TORRENT_ASSERT(!is_aborted());
|
TORRENT_ASSERT(!is_aborted());
|
||||||
|
@ -1798,9 +1394,9 @@ namespace detail
|
||||||
// the checker thread and store it before starting
|
// the checker thread and store it before starting
|
||||||
// the thread
|
// the thread
|
||||||
boost::shared_ptr<torrent> torrent_ptr(
|
boost::shared_ptr<torrent> torrent_ptr(
|
||||||
new torrent(*this, m_checker_impl, tracker_url, info_hash, name
|
new torrent(*this, tracker_url, info_hash, name
|
||||||
, save_path, m_listen_interface, storage_mode, 16 * 1024
|
, save_path, m_listen_interface, storage_mode, 16 * 1024
|
||||||
, sc, paused));
|
, sc, paused, resume_data));
|
||||||
torrent_ptr->start();
|
torrent_ptr->start();
|
||||||
|
|
||||||
#ifndef TORRENT_DISABLE_EXTENSIONS
|
#ifndef TORRENT_DISABLE_EXTENSIONS
|
||||||
|
@ -1812,16 +1408,14 @@ namespace detail
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
m_torrents.insert(
|
m_torrents.insert(std::make_pair(info_hash, torrent_ptr));
|
||||||
std::make_pair(info_hash, torrent_ptr)).first;
|
|
||||||
|
|
||||||
return torrent_handle(this, &m_checker_impl, info_hash);
|
return torrent_handle(this, info_hash);
|
||||||
}
|
}
|
||||||
|
|
||||||
void session_impl::remove_torrent(const torrent_handle& h, int options)
|
void session_impl::remove_torrent(const torrent_handle& h, int options)
|
||||||
{
|
{
|
||||||
if (h.m_ses != this) return;
|
if (h.m_ses != this) return;
|
||||||
TORRENT_ASSERT(h.m_chk == &m_checker_impl || h.m_chk == 0);
|
|
||||||
TORRENT_ASSERT(h.m_ses != 0);
|
TORRENT_ASSERT(h.m_ses != 0);
|
||||||
|
|
||||||
mutex_t::scoped_lock l(m_mutex);
|
mutex_t::scoped_lock l(m_mutex);
|
||||||
|
@ -1871,19 +1465,6 @@ namespace detail
|
||||||
TORRENT_ASSERT(m_torrents.find(i_hash) == m_torrents.end());
|
TORRENT_ASSERT(m_torrents.find(i_hash) == m_torrents.end());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (h.m_chk)
|
|
||||||
{
|
|
||||||
mutex::scoped_lock l(m_checker_impl.m_mutex);
|
|
||||||
|
|
||||||
aux::piece_checker_data* d = m_checker_impl.find_torrent(h.m_info_hash);
|
|
||||||
if (d != 0)
|
|
||||||
{
|
|
||||||
if (d->processing) d->abort = true;
|
|
||||||
else m_checker_impl.remove_torrent(h.m_info_hash, options);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool session_impl::listen_on(
|
bool session_impl::listen_on(
|
||||||
|
@ -2182,31 +1763,6 @@ namespace detail
|
||||||
|
|
||||||
TORRENT_ASSERT(m_torrents.empty());
|
TORRENT_ASSERT(m_torrents.empty());
|
||||||
|
|
||||||
// it's important that the main thread is closed completely before
|
|
||||||
// the checker thread is terminated. Because all the connections
|
|
||||||
// have to be closed and removed from the torrents before they
|
|
||||||
// can be destructed. (because the weak pointers in the
|
|
||||||
// peer_connections will be invalidated when the torrents are
|
|
||||||
// destructed and then the invariant will be broken).
|
|
||||||
|
|
||||||
{
|
|
||||||
mutex::scoped_lock l(m_checker_impl.m_mutex);
|
|
||||||
// abort the checker thread
|
|
||||||
m_checker_impl.m_abort = true;
|
|
||||||
|
|
||||||
// abort the currently checking torrent
|
|
||||||
if (!m_checker_impl.m_torrents.empty())
|
|
||||||
{
|
|
||||||
m_checker_impl.m_torrents.front()->abort = true;
|
|
||||||
}
|
|
||||||
m_checker_impl.m_cond.notify_one();
|
|
||||||
}
|
|
||||||
|
|
||||||
#if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING)
|
|
||||||
(*m_logger) << time_now_string() << " waiting for checker thread\n";
|
|
||||||
#endif
|
|
||||||
m_checker_thread->join();
|
|
||||||
|
|
||||||
#if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING)
|
#if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING)
|
||||||
(*m_logger) << time_now_string() << " waiting for disk io thread\n";
|
(*m_logger) << time_now_string() << " waiting for disk io thread\n";
|
||||||
#endif
|
#endif
|
||||||
|
@ -2476,210 +2032,5 @@ namespace detail
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
void piece_checker_data::parse_resume_data(
|
|
||||||
const entry& resume_data
|
|
||||||
, const torrent_info& info
|
|
||||||
, std::string& error)
|
|
||||||
{
|
|
||||||
// if we don't have any resume data, return
|
|
||||||
if (resume_data.type() == entry::undefined_t) return;
|
|
||||||
|
|
||||||
entry rd = resume_data;
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
if (rd["file-format"].string() != "libtorrent resume file")
|
|
||||||
{
|
|
||||||
error = "missing file format tag";
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (rd["file-version"].integer() > 1)
|
|
||||||
{
|
|
||||||
error = "incompatible file version "
|
|
||||||
+ boost::lexical_cast<std::string>(rd["file-version"].integer());
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// verify info_hash
|
|
||||||
sha1_hash hash = rd["info-hash"].string();
|
|
||||||
if (hash != info.info_hash())
|
|
||||||
{
|
|
||||||
error = "mismatching info-hash: " + boost::lexical_cast<std::string>(hash);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// the peers
|
|
||||||
|
|
||||||
if (entry* peers_entry = rd.find_key("peers"))
|
|
||||||
{
|
|
||||||
entry::list_type& peer_list = peers_entry->list();
|
|
||||||
|
|
||||||
std::vector<tcp::endpoint> tmp_peers;
|
|
||||||
tmp_peers.reserve(peer_list.size());
|
|
||||||
for (entry::list_type::iterator i = peer_list.begin();
|
|
||||||
i != peer_list.end(); ++i)
|
|
||||||
{
|
|
||||||
tcp::endpoint a(
|
|
||||||
address::from_string((*i)["ip"].string())
|
|
||||||
, (unsigned short)(*i)["port"].integer());
|
|
||||||
tmp_peers.push_back(a);
|
|
||||||
}
|
|
||||||
|
|
||||||
peers.swap(tmp_peers);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (entry* banned_peers_entry = rd.find_key("banned_peers"))
|
|
||||||
{
|
|
||||||
entry::list_type& peer_list = banned_peers_entry->list();
|
|
||||||
|
|
||||||
std::vector<tcp::endpoint> tmp_peers;
|
|
||||||
tmp_peers.reserve(peer_list.size());
|
|
||||||
for (entry::list_type::iterator i = peer_list.begin();
|
|
||||||
i != peer_list.end(); ++i)
|
|
||||||
{
|
|
||||||
tcp::endpoint a(
|
|
||||||
address::from_string((*i)["ip"].string())
|
|
||||||
, (unsigned short)(*i)["port"].integer());
|
|
||||||
tmp_peers.push_back(a);
|
|
||||||
}
|
|
||||||
|
|
||||||
banned_peers.swap(tmp_peers);
|
|
||||||
}
|
|
||||||
|
|
||||||
// read piece map
|
|
||||||
const entry::list_type& slots = rd["slots"].list();
|
|
||||||
if ((int)slots.size() > info.num_pieces())
|
|
||||||
{
|
|
||||||
error = "file has more slots than torrent (slots: "
|
|
||||||
+ boost::lexical_cast<std::string>(slots.size()) + " size: "
|
|
||||||
+ boost::lexical_cast<std::string>(info.num_pieces()) + " )";
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<int> tmp_pieces;
|
|
||||||
tmp_pieces.reserve(slots.size());
|
|
||||||
for (entry::list_type::const_iterator i = slots.begin();
|
|
||||||
i != slots.end(); ++i)
|
|
||||||
{
|
|
||||||
int index = (int)i->integer();
|
|
||||||
if (index >= info.num_pieces() || index < -2)
|
|
||||||
{
|
|
||||||
error = "too high index number in slot map (index: "
|
|
||||||
+ boost::lexical_cast<std::string>(index) + " size: "
|
|
||||||
+ boost::lexical_cast<std::string>(info.num_pieces()) + ")";
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
tmp_pieces.push_back(index);
|
|
||||||
}
|
|
||||||
|
|
||||||
// only bother to check the partial pieces if we have the same block size
|
|
||||||
// as in the fast resume data. If the blocksize has changed, then throw
|
|
||||||
// away all partial pieces.
|
|
||||||
std::vector<piece_picker::downloading_piece> tmp_unfinished;
|
|
||||||
int num_blocks_per_piece = (int)rd["blocks per piece"].integer();
|
|
||||||
if (num_blocks_per_piece == info.piece_length() / torrent_ptr->block_size())
|
|
||||||
{
|
|
||||||
// the unfinished pieces
|
|
||||||
|
|
||||||
entry::list_type& unfinished = rd["unfinished"].list();
|
|
||||||
int unfinished_size = int(unfinished.size());
|
|
||||||
block_info.resize(num_blocks_per_piece * unfinished_size);
|
|
||||||
tmp_unfinished.reserve(unfinished_size);
|
|
||||||
int index = 0;
|
|
||||||
for (entry::list_type::iterator i = unfinished.begin();
|
|
||||||
i != unfinished.end(); ++i, ++index)
|
|
||||||
{
|
|
||||||
piece_picker::downloading_piece p;
|
|
||||||
p.info = &block_info[index * num_blocks_per_piece];
|
|
||||||
p.index = (int)(*i)["piece"].integer();
|
|
||||||
if (p.index < 0 || p.index >= info.num_pieces())
|
|
||||||
{
|
|
||||||
error = "invalid piece index in unfinished piece list (index: "
|
|
||||||
+ boost::lexical_cast<std::string>(p.index) + " size: "
|
|
||||||
+ boost::lexical_cast<std::string>(info.num_pieces()) + ")";
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const std::string& bitmask = (*i)["bitmask"].string();
|
|
||||||
|
|
||||||
const int num_bitmask_bytes = (std::max)(num_blocks_per_piece / 8, 1);
|
|
||||||
if ((int)bitmask.size() != num_bitmask_bytes)
|
|
||||||
{
|
|
||||||
error = "invalid size of bitmask (" + boost::lexical_cast<std::string>(bitmask.size()) + ")";
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
for (int j = 0; j < num_bitmask_bytes; ++j)
|
|
||||||
{
|
|
||||||
unsigned char bits = bitmask[j];
|
|
||||||
int num_bits = (std::min)(num_blocks_per_piece - j*8, 8);
|
|
||||||
for (int k = 0; k < num_bits; ++k)
|
|
||||||
{
|
|
||||||
const int bit = j * 8 + k;
|
|
||||||
if (bits & (1 << k))
|
|
||||||
{
|
|
||||||
p.info[bit].state = piece_picker::block_info::state_finished;
|
|
||||||
++p.finished;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (p.finished == 0) continue;
|
|
||||||
|
|
||||||
std::vector<int>::iterator slot_iter
|
|
||||||
= std::find(tmp_pieces.begin(), tmp_pieces.end(), p.index);
|
|
||||||
if (slot_iter == tmp_pieces.end())
|
|
||||||
{
|
|
||||||
// this piece is marked as unfinished
|
|
||||||
// but doesn't have any storage
|
|
||||||
error = "piece " + boost::lexical_cast<std::string>(p.index) + " is "
|
|
||||||
"marked as unfinished, but doesn't have any storage";
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
TORRENT_ASSERT(*slot_iter == p.index);
|
|
||||||
int slot_index = static_cast<int>(slot_iter - tmp_pieces.begin());
|
|
||||||
const entry* ad = i->find_key("adler32");
|
|
||||||
|
|
||||||
if (ad && ad->type() == entry::int_t)
|
|
||||||
{
|
|
||||||
unsigned long adler
|
|
||||||
= torrent_ptr->filesystem().piece_crc(
|
|
||||||
slot_index
|
|
||||||
, torrent_ptr->block_size()
|
|
||||||
, p.info);
|
|
||||||
|
|
||||||
// crc's didn't match, don't use the resume data
|
|
||||||
if (ad->integer() != entry::integer_type(adler))
|
|
||||||
{
|
|
||||||
error = "checksum mismatch on piece "
|
|
||||||
+ boost::lexical_cast<std::string>(p.index);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
tmp_unfinished.push_back(p);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!torrent_ptr->verify_resume_data(rd, error))
|
|
||||||
return;
|
|
||||||
|
|
||||||
piece_map.swap(tmp_pieces);
|
|
||||||
unfinished_pieces.swap(tmp_unfinished);
|
|
||||||
}
|
|
||||||
catch (invalid_encoding&)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
catch (type_error&)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
catch (file_error&)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}}
|
}}
|
||||||
|
|
||||||
|
|
583
src/storage.cpp
583
src/storage.cpp
|
@ -462,7 +462,12 @@ namespace libtorrent
|
||||||
#endif
|
#endif
|
||||||
file(m_save_path / file_iter->path, file::out);
|
file(m_save_path / file_iter->path, file::out);
|
||||||
#ifndef BOOST_NO_EXCEPTIONS
|
#ifndef BOOST_NO_EXCEPTIONS
|
||||||
} catch (std::exception&) {}
|
}
|
||||||
|
catch (std::exception& e)
|
||||||
|
{
|
||||||
|
m_error = e.what();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -480,7 +485,12 @@ namespace libtorrent
|
||||||
f->set_size(file_iter->size);
|
f->set_size(file_iter->size);
|
||||||
}
|
}
|
||||||
#ifndef BOOST_NO_EXCEPTIONS
|
#ifndef BOOST_NO_EXCEPTIONS
|
||||||
} catch (std::exception&) {}
|
}
|
||||||
|
catch (std::exception& e)
|
||||||
|
{
|
||||||
|
m_error = e.what();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
// close files that were opened in write mode
|
// close files that were opened in write mode
|
||||||
|
@ -1094,9 +1104,10 @@ namespace libtorrent
|
||||||
, fs::path const& save_path
|
, fs::path const& save_path
|
||||||
, file_pool& fp
|
, file_pool& fp
|
||||||
, disk_io_thread& io
|
, disk_io_thread& io
|
||||||
, storage_constructor_type sc)
|
, storage_constructor_type sc
|
||||||
|
, storage_mode_t sm)
|
||||||
: m_storage(sc(ti, save_path, fp))
|
: m_storage(sc(ti, save_path, fp))
|
||||||
, m_storage_mode(storage_mode_sparse)
|
, m_storage_mode(sm)
|
||||||
, m_info(ti)
|
, m_info(ti)
|
||||||
, m_save_path(complete(save_path))
|
, m_save_path(complete(save_path))
|
||||||
, m_state(state_none)
|
, m_state(state_none)
|
||||||
|
@ -1107,9 +1118,6 @@ namespace libtorrent
|
||||||
, m_io_thread(io)
|
, m_io_thread(io)
|
||||||
, m_torrent(torrent)
|
, m_torrent(torrent)
|
||||||
{
|
{
|
||||||
#ifndef NDEBUG
|
|
||||||
m_resume_data_verified = false;
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
piece_manager::~piece_manager()
|
piece_manager::~piece_manager()
|
||||||
|
@ -1149,6 +1157,26 @@ namespace libtorrent
|
||||||
m_io_thread.add_job(j, handler);
|
m_io_thread.add_job(j, handler);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void piece_manager::async_check_fastresume(entry const* resume_data
|
||||||
|
, boost::function<void(int, disk_io_job const&)> const& handler)
|
||||||
|
{
|
||||||
|
TORRENT_ASSERT(resume_data != 0);
|
||||||
|
disk_io_job j;
|
||||||
|
j.storage = this;
|
||||||
|
j.action = disk_io_job::check_fastresume;
|
||||||
|
j.buffer = (char*)resume_data;
|
||||||
|
m_io_thread.add_job(j, handler);
|
||||||
|
}
|
||||||
|
|
||||||
|
void piece_manager::async_check_files(
|
||||||
|
boost::function<void(int, disk_io_job const&)> const& handler)
|
||||||
|
{
|
||||||
|
disk_io_job j;
|
||||||
|
j.storage = this;
|
||||||
|
j.action = disk_io_job::check_files;
|
||||||
|
m_io_thread.add_job(j, handler);
|
||||||
|
}
|
||||||
|
|
||||||
void piece_manager::async_read(
|
void piece_manager::async_read(
|
||||||
peer_request const& r
|
peer_request const& r
|
||||||
, boost::function<void(int, disk_io_job const&)> const& handler
|
, boost::function<void(int, disk_io_job const&)> const& handler
|
||||||
|
@ -1238,45 +1266,44 @@ namespace libtorrent
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void piece_manager::export_piece_map(
|
void piece_manager::write_resume_data(entry& rd
|
||||||
std::vector<int>& p, std::vector<bool> const& have) const
|
, std::vector<bool> const& have) const
|
||||||
{
|
{
|
||||||
boost::recursive_mutex::scoped_lock lock(m_mutex);
|
boost::recursive_mutex::scoped_lock lock(m_mutex);
|
||||||
|
|
||||||
INVARIANT_CHECK;
|
INVARIANT_CHECK;
|
||||||
|
|
||||||
|
m_storage->write_resume_data(rd);
|
||||||
|
|
||||||
|
entry::list_type& slots = rd["slots"].list();
|
||||||
if (m_storage_mode == storage_mode_compact)
|
if (m_storage_mode == storage_mode_compact)
|
||||||
{
|
{
|
||||||
p.clear();
|
slots.clear();
|
||||||
p.reserve(m_info->num_pieces());
|
|
||||||
std::vector<int>::const_reverse_iterator last;
|
std::vector<int>::const_reverse_iterator last;
|
||||||
for (last = m_slot_to_piece.rbegin();
|
for (last = m_slot_to_piece.rbegin();
|
||||||
last != m_slot_to_piece.rend(); ++last)
|
last != m_slot_to_piece.rend(); ++last)
|
||||||
{
|
{
|
||||||
if (*last != unallocated && have[*last]) break;
|
if (*last != unallocated) break;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (std::vector<int>::const_iterator i =
|
for (std::vector<int>::const_iterator i =
|
||||||
m_slot_to_piece.begin();
|
m_slot_to_piece.begin();
|
||||||
i != last.base(); ++i)
|
i != last.base(); ++i)
|
||||||
{
|
{
|
||||||
p.push_back((*i >= 0 && have[*i]) ? *i : unassigned);
|
slots.push_back((*i >= 0) ? *i : unassigned);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
p.reserve(m_info->num_pieces());
|
|
||||||
for (int i = 0; i < m_info->num_pieces(); ++i)
|
for (int i = 0; i < m_info->num_pieces(); ++i)
|
||||||
{
|
{
|
||||||
p.push_back(have[i] ? i : unassigned);
|
slots.push_back(have[i] ? i : unassigned);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void piece_manager::mark_failed(int piece_index)
|
void piece_manager::mark_failed(int piece_index)
|
||||||
{
|
{
|
||||||
boost::recursive_mutex::scoped_lock lock(m_mutex);
|
|
||||||
|
|
||||||
INVARIANT_CHECK;
|
INVARIANT_CHECK;
|
||||||
|
|
||||||
if (m_storage_mode != storage_mode_compact) return;
|
if (m_storage_mode != storage_mode_compact) return;
|
||||||
|
@ -1290,43 +1317,6 @@ namespace libtorrent
|
||||||
m_free_slots.push_back(slot_index);
|
m_free_slots.push_back(slot_index);
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned long piece_manager::piece_crc(
|
|
||||||
int slot_index
|
|
||||||
, int block_size
|
|
||||||
, piece_picker::block_info const* bi)
|
|
||||||
{
|
|
||||||
TORRENT_ASSERT(slot_index >= 0);
|
|
||||||
TORRENT_ASSERT(slot_index < m_info->num_pieces());
|
|
||||||
TORRENT_ASSERT(block_size > 0);
|
|
||||||
|
|
||||||
adler32_crc crc;
|
|
||||||
std::vector<char> buf(block_size);
|
|
||||||
int num_blocks = static_cast<int>(m_info->piece_size(slot_index)) / block_size;
|
|
||||||
int last_block_size = static_cast<int>(m_info->piece_size(slot_index)) % block_size;
|
|
||||||
if (last_block_size == 0) last_block_size = block_size;
|
|
||||||
|
|
||||||
for (int i = 0; i < num_blocks-1; ++i)
|
|
||||||
{
|
|
||||||
if (bi[i].state != piece_picker::block_info::state_finished) continue;
|
|
||||||
m_storage->read(
|
|
||||||
&buf[0]
|
|
||||||
, slot_index
|
|
||||||
, i * block_size
|
|
||||||
, block_size);
|
|
||||||
crc.update(&buf[0], block_size);
|
|
||||||
}
|
|
||||||
if (num_blocks > 0 && bi[num_blocks - 1].state == piece_picker::block_info::state_finished)
|
|
||||||
{
|
|
||||||
m_storage->read(
|
|
||||||
&buf[0]
|
|
||||||
, slot_index
|
|
||||||
, block_size * (num_blocks - 1)
|
|
||||||
, last_block_size);
|
|
||||||
crc.update(&buf[0], last_block_size);
|
|
||||||
}
|
|
||||||
return crc.final();
|
|
||||||
}
|
|
||||||
|
|
||||||
size_type piece_manager::read_impl(
|
size_type piece_manager::read_impl(
|
||||||
char* buf
|
char* buf
|
||||||
, int piece_index
|
, int piece_index
|
||||||
|
@ -1382,16 +1372,10 @@ namespace libtorrent
|
||||||
|
|
||||||
int piece_manager::identify_data(
|
int piece_manager::identify_data(
|
||||||
const std::vector<char>& piece_data
|
const std::vector<char>& piece_data
|
||||||
, int current_slot
|
, int current_slot)
|
||||||
, std::vector<bool>& have_pieces
|
|
||||||
, int& num_pieces
|
|
||||||
, const std::multimap<sha1_hash, int>& hash_to_piece
|
|
||||||
, boost::recursive_mutex& mutex)
|
|
||||||
{
|
{
|
||||||
// INVARIANT_CHECK;
|
// INVARIANT_CHECK;
|
||||||
|
|
||||||
TORRENT_ASSERT((int)have_pieces.size() == m_info->num_pieces());
|
|
||||||
|
|
||||||
const int piece_size = static_cast<int>(m_info->piece_length());
|
const int piece_size = static_cast<int>(m_info->piece_length());
|
||||||
const int last_piece_size = static_cast<int>(m_info->piece_size(
|
const int last_piece_size = static_cast<int>(m_info->piece_size(
|
||||||
m_info->num_pieces() - 1));
|
m_info->num_pieces() - 1));
|
||||||
|
@ -1421,8 +1405,8 @@ namespace libtorrent
|
||||||
map_iter end2;
|
map_iter end2;
|
||||||
|
|
||||||
// makes the lookups for the small digest and the large digest
|
// makes the lookups for the small digest and the large digest
|
||||||
boost::tie(begin1, end1) = hash_to_piece.equal_range(small_hash);
|
boost::tie(begin1, end1) = m_hash_to_piece.equal_range(small_hash);
|
||||||
boost::tie(begin2, end2) = hash_to_piece.equal_range(large_hash);
|
boost::tie(begin2, end2) = m_hash_to_piece.equal_range(large_hash);
|
||||||
|
|
||||||
// copy all potential piece indices into this vector
|
// copy all potential piece indices into this vector
|
||||||
std::vector<int> matching_pieces;
|
std::vector<int> matching_pieces;
|
||||||
|
@ -1448,15 +1432,11 @@ namespace libtorrent
|
||||||
// we will assume that the piece is in the right place
|
// we will assume that the piece is in the right place
|
||||||
const int piece_index = current_slot;
|
const int piece_index = current_slot;
|
||||||
|
|
||||||
// lock because we're writing to have_pieces
|
int other_slot = m_piece_to_slot[piece_index];
|
||||||
boost::recursive_mutex::scoped_lock l(mutex);
|
if (other_slot >= 0)
|
||||||
|
|
||||||
if (have_pieces[piece_index])
|
|
||||||
{
|
{
|
||||||
// we have already found a piece with
|
// we have already found a piece with
|
||||||
// this index.
|
// this index.
|
||||||
int other_slot = m_piece_to_slot[piece_index];
|
|
||||||
TORRENT_ASSERT(other_slot >= 0);
|
|
||||||
|
|
||||||
// take one of the other matching pieces
|
// take one of the other matching pieces
|
||||||
// that hasn't already been assigned
|
// that hasn't already been assigned
|
||||||
|
@ -1464,18 +1444,15 @@ namespace libtorrent
|
||||||
for (std::vector<int>::iterator i = matching_pieces.begin();
|
for (std::vector<int>::iterator i = matching_pieces.begin();
|
||||||
i != matching_pieces.end(); ++i)
|
i != matching_pieces.end(); ++i)
|
||||||
{
|
{
|
||||||
if (have_pieces[*i] || *i == piece_index) continue;
|
if (m_piece_to_slot[*i] >= 0 || *i == piece_index) continue;
|
||||||
other_piece = *i;
|
other_piece = *i;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (other_piece >= 0)
|
if (other_piece >= 0)
|
||||||
{
|
{
|
||||||
// replace the old slot with 'other_piece'
|
// replace the old slot with 'other_piece'
|
||||||
TORRENT_ASSERT(have_pieces[other_piece] == false);
|
|
||||||
have_pieces[other_piece] = true;
|
|
||||||
m_slot_to_piece[other_slot] = other_piece;
|
m_slot_to_piece[other_slot] = other_piece;
|
||||||
m_piece_to_slot[other_piece] = other_slot;
|
m_piece_to_slot[other_piece] = other_slot;
|
||||||
++num_pieces;
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -1491,19 +1468,9 @@ namespace libtorrent
|
||||||
TORRENT_ASSERT(m_piece_to_slot[piece_index] != current_slot);
|
TORRENT_ASSERT(m_piece_to_slot[piece_index] != current_slot);
|
||||||
TORRENT_ASSERT(m_piece_to_slot[piece_index] >= 0);
|
TORRENT_ASSERT(m_piece_to_slot[piece_index] >= 0);
|
||||||
m_piece_to_slot[piece_index] = has_no_slot;
|
m_piece_to_slot[piece_index] = has_no_slot;
|
||||||
#ifndef NDEBUG
|
|
||||||
// to make the assert happy, a few lines down
|
|
||||||
have_pieces[piece_index] = false;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
++num_pieces;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TORRENT_ASSERT(have_pieces[piece_index] == false);
|
|
||||||
TORRENT_ASSERT(m_piece_to_slot[piece_index] == has_no_slot);
|
TORRENT_ASSERT(m_piece_to_slot[piece_index] == has_no_slot);
|
||||||
have_pieces[piece_index] = true;
|
|
||||||
|
|
||||||
return piece_index;
|
return piece_index;
|
||||||
}
|
}
|
||||||
|
@ -1514,21 +1481,14 @@ namespace libtorrent
|
||||||
for (std::vector<int>::iterator i = matching_pieces.begin();
|
for (std::vector<int>::iterator i = matching_pieces.begin();
|
||||||
i != matching_pieces.end(); ++i)
|
i != matching_pieces.end(); ++i)
|
||||||
{
|
{
|
||||||
if (have_pieces[*i]) continue;
|
if (m_piece_to_slot[*i] >= 0) continue;
|
||||||
free_piece = *i;
|
free_piece = *i;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (free_piece >= 0)
|
if (free_piece >= 0)
|
||||||
{
|
{
|
||||||
// lock because we're writing to have_pieces
|
|
||||||
boost::recursive_mutex::scoped_lock l(mutex);
|
|
||||||
|
|
||||||
TORRENT_ASSERT(have_pieces[free_piece] == false);
|
|
||||||
TORRENT_ASSERT(m_piece_to_slot[free_piece] == has_no_slot);
|
TORRENT_ASSERT(m_piece_to_slot[free_piece] == has_no_slot);
|
||||||
have_pieces[free_piece] = true;
|
|
||||||
++num_pieces;
|
|
||||||
|
|
||||||
return free_piece;
|
return free_piece;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -1538,15 +1498,92 @@ namespace libtorrent
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int piece_manager::check_no_fastresume(std::string& error)
|
||||||
|
{
|
||||||
|
torrent_info::file_iterator i = m_info->begin_files(true);
|
||||||
|
torrent_info::file_iterator end = m_info->end_files(true);
|
||||||
|
|
||||||
|
for (; i != end; ++i)
|
||||||
|
{
|
||||||
|
bool file_exists = false;
|
||||||
|
fs::path f = m_save_path / i->path;
|
||||||
|
#ifndef BOOST_NO_EXCEPTIONS
|
||||||
|
try
|
||||||
|
{
|
||||||
|
#endif
|
||||||
|
#if defined(_WIN32) && defined(UNICODE) && BOOST_VERSION < 103400
|
||||||
|
file_exists = exists_win(f);
|
||||||
|
#elif defined(_WIN32) && defined(UNICODE)
|
||||||
|
fs::wpath wf = safe_convert(f.string());
|
||||||
|
file_exists = exists(wf);
|
||||||
|
#else
|
||||||
|
file_exists = exists(f);
|
||||||
|
#endif
|
||||||
|
#ifndef BOOST_NO_EXCEPTIONS
|
||||||
|
}
|
||||||
|
catch (std::exception& e)
|
||||||
|
{
|
||||||
|
error = f.string();
|
||||||
|
error += ": ";
|
||||||
|
error += e.what();
|
||||||
|
return fatal_disk_error;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
if (file_exists && i->size > 0)
|
||||||
|
{
|
||||||
|
m_state = state_full_check;
|
||||||
|
m_piece_to_slot.clear();
|
||||||
|
m_piece_to_slot.resize(m_info->num_pieces(), has_no_slot);
|
||||||
|
m_slot_to_piece.clear();
|
||||||
|
m_slot_to_piece.resize(m_info->num_pieces(), unallocated);
|
||||||
|
return need_full_check;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_storage_mode == storage_mode_compact)
|
||||||
|
{
|
||||||
|
// in compact mode without checking, we need to
|
||||||
|
// populate the unallocated list
|
||||||
|
TORRENT_ASSERT(m_unallocated_slots.empty());
|
||||||
|
for (int i = 0, end(m_info->num_pieces()); i < end; ++i)
|
||||||
|
m_unallocated_slots.push_back(i);
|
||||||
|
m_piece_to_slot.resize(m_info->num_pieces(), has_no_slot);
|
||||||
|
m_slot_to_piece.resize(m_info->num_pieces(), unallocated);
|
||||||
|
}
|
||||||
|
|
||||||
|
return check_init_storage(error);
|
||||||
|
}
|
||||||
|
|
||||||
|
int piece_manager::check_init_storage(std::string& error)
|
||||||
|
{
|
||||||
|
if (m_storage->initialize(m_storage_mode == storage_mode_allocate))
|
||||||
|
{
|
||||||
|
error = m_storage->error();
|
||||||
|
m_storage->clear_error();
|
||||||
|
return fatal_disk_error;
|
||||||
|
}
|
||||||
|
m_state = state_finished;
|
||||||
|
buffer().swap(m_scratch_buffer);
|
||||||
|
buffer().swap(m_scratch_buffer2);
|
||||||
|
if (m_storage_mode != storage_mode_compact)
|
||||||
|
{
|
||||||
|
// if no piece is out of place
|
||||||
|
// since we're in full allocation mode, we can
|
||||||
|
// forget the piece allocation tables
|
||||||
|
std::vector<int>().swap(m_piece_to_slot);
|
||||||
|
std::vector<int>().swap(m_slot_to_piece);
|
||||||
|
std::vector<int>().swap(m_free_slots);
|
||||||
|
std::vector<int>().swap(m_unallocated_slots);
|
||||||
|
}
|
||||||
|
return no_error;
|
||||||
|
}
|
||||||
|
|
||||||
// check if the fastresume data is up to date
|
// check if the fastresume data is up to date
|
||||||
// if it is, use it and return true. If it
|
// if it is, use it and return true. If it
|
||||||
// isn't return false and the full check
|
// isn't return false and the full check
|
||||||
// will be run
|
// will be run
|
||||||
bool piece_manager::check_fastresume(
|
int piece_manager::check_fastresume(
|
||||||
aux::piece_checker_data& data
|
entry const& rd, std::string& error)
|
||||||
, std::vector<bool>& pieces
|
|
||||||
, int& num_pieces, storage_mode_t storage_mode
|
|
||||||
, std::string& error_msg)
|
|
||||||
{
|
{
|
||||||
boost::recursive_mutex::scoped_lock lock(m_mutex);
|
boost::recursive_mutex::scoped_lock lock(m_mutex);
|
||||||
|
|
||||||
|
@ -1554,7 +1591,144 @@ namespace libtorrent
|
||||||
|
|
||||||
TORRENT_ASSERT(m_info->piece_length() > 0);
|
TORRENT_ASSERT(m_info->piece_length() > 0);
|
||||||
|
|
||||||
m_storage_mode = storage_mode;
|
// if we don't have any resume data, return
|
||||||
|
if (rd.type() == entry::undefined_t) return check_no_fastresume(error);
|
||||||
|
|
||||||
|
if (rd.type() != entry::dictionary_t)
|
||||||
|
{
|
||||||
|
error = "invalid fastresume data (not a bencoded dictionary)";
|
||||||
|
return check_no_fastresume(error);
|
||||||
|
}
|
||||||
|
|
||||||
|
entry const* file_format = rd.find_key("file-format");
|
||||||
|
|
||||||
|
if (file_format == 0 || file_format->type() != entry::string_t)
|
||||||
|
{
|
||||||
|
error = "missing file format tag";
|
||||||
|
return check_no_fastresume(error);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (file_format->string() != "libtorrent resume file")
|
||||||
|
{
|
||||||
|
error = "invalid file format tag";
|
||||||
|
return check_no_fastresume(error);
|
||||||
|
}
|
||||||
|
|
||||||
|
entry const* info_hash = rd.find_key("info-hash");
|
||||||
|
if (info_hash == 0 || info_hash->type() != entry::string_t)
|
||||||
|
{
|
||||||
|
error = "missing info-hash";
|
||||||
|
return check_no_fastresume(error);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sha1_hash(info_hash->string()) != m_info->info_hash())
|
||||||
|
{
|
||||||
|
error = "mismatching info-hash";
|
||||||
|
return check_no_fastresume(error);
|
||||||
|
}
|
||||||
|
|
||||||
|
int block_size = (std::min)(16 * 1024, m_info->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_info->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")
|
||||||
|
storage_mode = storage_mode_sparse;
|
||||||
|
|
||||||
|
// read piece map
|
||||||
|
entry const* slots = rd.find_key("slots");
|
||||||
|
if (slots == 0 || slots->type() != entry::list_t)
|
||||||
|
{
|
||||||
|
error = "missing slot list";
|
||||||
|
return check_no_fastresume(error);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((int)slots->list().size() > m_info->num_pieces())
|
||||||
|
{
|
||||||
|
error = "file has more slots than torrent (slots: "
|
||||||
|
+ boost::lexical_cast<std::string>(slots->list().size()) + " size: "
|
||||||
|
+ boost::lexical_cast<std::string>(m_info->num_pieces()) + " )";
|
||||||
|
return check_no_fastresume(error);
|
||||||
|
}
|
||||||
|
|
||||||
|
// assume no piece is out of place (i.e. in a slot
|
||||||
|
// other than the one it should be in)
|
||||||
|
bool out_of_place = false;
|
||||||
|
|
||||||
|
if (storage_mode == storage_mode_compact)
|
||||||
|
{
|
||||||
|
int num_pieces = int(m_info->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)
|
||||||
|
{
|
||||||
|
if (i->type() != entry::int_t)
|
||||||
|
{
|
||||||
|
error = "invalid entry type in slot list";
|
||||||
|
return check_no_fastresume(error);
|
||||||
|
}
|
||||||
|
|
||||||
|
int index = int(i->integer());
|
||||||
|
if (index >= num_pieces || index < -2)
|
||||||
|
{
|
||||||
|
error = "too high index number in slot map (index: "
|
||||||
|
+ boost::lexical_cast<std::string>(index) + " size: "
|
||||||
|
+ boost::lexical_cast<std::string>(num_pieces) + ")";
|
||||||
|
return check_no_fastresume(error);
|
||||||
|
}
|
||||||
|
if (index >= 0)
|
||||||
|
{
|
||||||
|
m_slot_to_piece[slot] = index;
|
||||||
|
m_piece_to_slot[index] = slot;
|
||||||
|
if (slot != index) out_of_place = true;
|
||||||
|
}
|
||||||
|
else if (index == unassigned)
|
||||||
|
{
|
||||||
|
if (m_storage_mode == storage_mode_compact)
|
||||||
|
m_free_slots.push_back(slot);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
TORRENT_ASSERT(index == unallocated);
|
||||||
|
if (m_storage_mode == storage_mode_compact)
|
||||||
|
m_unallocated_slots.push_back(slot);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
int slot = 0;
|
||||||
|
for (entry::list_type::const_iterator i = slots->list().begin();
|
||||||
|
i != slots->list().end(); ++i, ++slot)
|
||||||
|
{
|
||||||
|
if (i->type() != entry::int_t)
|
||||||
|
{
|
||||||
|
error = "invalid entry type in slot list";
|
||||||
|
return check_no_fastresume(error);
|
||||||
|
}
|
||||||
|
|
||||||
|
int index = int(i->integer());
|
||||||
|
if (index != slot)
|
||||||
|
{
|
||||||
|
error = "invalid slot index";
|
||||||
|
return check_no_fastresume(error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!m_storage->verify_resume_data(rd, error))
|
||||||
|
return check_no_fastresume(error);
|
||||||
|
|
||||||
// This will corrupt the storage
|
// This will corrupt the storage
|
||||||
// use while debugging to find
|
// use while debugging to find
|
||||||
|
@ -1562,123 +1736,44 @@ namespace libtorrent
|
||||||
// by check_pieces.
|
// by check_pieces.
|
||||||
// m_storage->shuffle();
|
// m_storage->shuffle();
|
||||||
|
|
||||||
m_piece_to_slot.resize(m_info->num_pieces(), has_no_slot);
|
if (m_storage_mode == storage_mode_compact)
|
||||||
m_slot_to_piece.resize(m_info->num_pieces(), unallocated);
|
|
||||||
TORRENT_ASSERT(m_free_slots.empty());
|
|
||||||
TORRENT_ASSERT(m_unallocated_slots.empty());
|
|
||||||
|
|
||||||
// assume no piece is out of place (i.e. in a slot
|
|
||||||
// other than the one it should be in)
|
|
||||||
bool out_of_place = false;
|
|
||||||
|
|
||||||
pieces.clear();
|
|
||||||
pieces.resize(m_info->num_pieces(), false);
|
|
||||||
num_pieces = 0;
|
|
||||||
|
|
||||||
// if we have fast-resume info
|
|
||||||
// use it instead of doing the actual checking
|
|
||||||
if (!data.piece_map.empty()
|
|
||||||
&& int(data.piece_map.size()) <= m_info->num_pieces())
|
|
||||||
{
|
{
|
||||||
TORRENT_ASSERT(m_resume_data_verified);
|
if (m_unallocated_slots.empty()) switch_to_full_mode();
|
||||||
for (int i = 0; i < (int)data.piece_map.size(); ++i)
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
TORRENT_ASSERT(m_free_slots.empty());
|
||||||
|
TORRENT_ASSERT(m_unallocated_slots.empty());
|
||||||
|
|
||||||
|
if (out_of_place)
|
||||||
{
|
{
|
||||||
m_slot_to_piece[i] = data.piece_map[i];
|
// in this case we're in full allocation mode, but
|
||||||
if (data.piece_map[i] >= 0)
|
// we're resuming a compact allocated storage
|
||||||
{
|
m_state = state_expand_pieces;
|
||||||
if (data.piece_map[i] != i) out_of_place = true;
|
m_current_slot = 0;
|
||||||
m_piece_to_slot[data.piece_map[i]] = i;
|
error = "pieces needs to be reordered";
|
||||||
int found_piece = data.piece_map[i];
|
return need_full_check;
|
||||||
|
|
||||||
// if the piece is not in the unfinished list
|
|
||||||
// we have all of it
|
|
||||||
if (std::find_if(
|
|
||||||
data.unfinished_pieces.begin()
|
|
||||||
, data.unfinished_pieces.end()
|
|
||||||
, piece_picker::has_index(found_piece))
|
|
||||||
== data.unfinished_pieces.end())
|
|
||||||
{
|
|
||||||
++num_pieces;
|
|
||||||
pieces[found_piece] = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (data.piece_map[i] == unassigned)
|
|
||||||
{
|
|
||||||
if (m_storage_mode == storage_mode_compact)
|
|
||||||
m_free_slots.push_back(i);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
TORRENT_ASSERT(data.piece_map[i] == unallocated);
|
|
||||||
if (m_storage_mode == storage_mode_compact)
|
|
||||||
m_unallocated_slots.push_back(i);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_storage_mode == storage_mode_compact)
|
|
||||||
{
|
|
||||||
m_unallocated_slots.reserve(int(m_info->num_pieces() - data.piece_map.size()));
|
|
||||||
for (int i = (int)data.piece_map.size(); i < (int)m_info->num_pieces(); ++i)
|
|
||||||
{
|
|
||||||
m_unallocated_slots.push_back(i);
|
|
||||||
}
|
|
||||||
if (m_unallocated_slots.empty())
|
|
||||||
{
|
|
||||||
switch_to_full_mode();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (!out_of_place)
|
|
||||||
{
|
|
||||||
// if no piece is out of place
|
|
||||||
// since we're in full allocation mode, we can
|
|
||||||
// forget the piece allocation tables
|
|
||||||
|
|
||||||
std::vector<int>().swap(m_piece_to_slot);
|
|
||||||
std::vector<int>().swap(m_slot_to_piece);
|
|
||||||
m_state = state_create_files;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// in this case we're in full allocation mode, but
|
|
||||||
// we're resuming a compact allocated storage
|
|
||||||
m_state = state_expand_pieces;
|
|
||||||
m_current_slot = 0;
|
|
||||||
error_msg = "pieces needs to be reordered";
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
m_state = state_create_files;
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
m_state = state_full_check;
|
return check_init_storage(error);
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
state chart:
|
state chart:
|
||||||
|
|
||||||
check_fastresume()
|
check_fastresume() ----------+
|
||||||
|
|
|
||||||
| |
|
| | |
|
||||||
| v
|
| v v
|
||||||
| +------------+ +---------------+
|
| +------------+ +---------------+
|
||||||
| | full_check |-->| expand_pieses |
|
| | full_check |-->| expand_pieses |
|
||||||
| +------------+ +---------------+
|
| +------------+ +---------------+
|
||||||
| | |
|
| | |
|
||||||
| v |
|
| v |
|
||||||
| +--------------+ |
|
| +--------------+ |
|
||||||
+->| create_files | <------+
|
+->| finished | <------+
|
||||||
+--------------+
|
+--------------+
|
||||||
|
|
|
||||||
v
|
|
||||||
+----------+
|
|
||||||
| finished |
|
|
||||||
+----------+
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
@ -1688,23 +1783,12 @@ namespace libtorrent
|
||||||
// the second return value is the progress the
|
// the second return value is the progress the
|
||||||
// file check is at. 0 is nothing done, and 1
|
// file check is at. 0 is nothing done, and 1
|
||||||
// is finished
|
// is finished
|
||||||
std::pair<bool, float> piece_manager::check_files(
|
int piece_manager::check_files(int& current_slot, int& have_piece, std::string& error)
|
||||||
std::vector<bool>& pieces, int& num_pieces, boost::recursive_mutex& mutex
|
|
||||||
, bool& error)
|
|
||||||
{
|
{
|
||||||
#ifndef NDEBUG
|
TORRENT_ASSERT(int(m_piece_to_slot.size()) == m_info->num_pieces());
|
||||||
boost::recursive_mutex::scoped_lock l_(mutex);
|
|
||||||
TORRENT_ASSERT(num_pieces == std::count(pieces.begin(), pieces.end(), true));
|
|
||||||
l_.unlock();
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if (m_state == state_create_files)
|
|
||||||
{
|
|
||||||
m_storage->initialize(m_storage_mode == storage_mode_allocate);
|
|
||||||
m_state = state_finished;
|
|
||||||
return std::make_pair(true, 1.f);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
current_slot = m_current_slot;
|
||||||
|
have_piece = -1;
|
||||||
if (m_state == state_expand_pieces)
|
if (m_state == state_expand_pieces)
|
||||||
{
|
{
|
||||||
INVARIANT_CHECK;
|
INVARIANT_CHECK;
|
||||||
|
@ -1724,8 +1808,9 @@ namespace libtorrent
|
||||||
if (m_storage->read(&m_scratch_buffer2[0], piece, 0, piece_size)
|
if (m_storage->read(&m_scratch_buffer2[0], piece, 0, piece_size)
|
||||||
!= piece_size)
|
!= piece_size)
|
||||||
{
|
{
|
||||||
error = true;
|
error = m_storage->error();
|
||||||
return std::make_pair(true, (float)m_current_slot / m_info->num_pieces());
|
m_storage->clear_error();
|
||||||
|
return fatal_disk_error;
|
||||||
}
|
}
|
||||||
m_scratch_piece = other_piece;
|
m_scratch_piece = other_piece;
|
||||||
m_piece_to_slot[other_piece] = unassigned;
|
m_piece_to_slot[other_piece] = unassigned;
|
||||||
|
@ -1736,8 +1821,9 @@ namespace libtorrent
|
||||||
int piece_size = m_info->piece_size(piece);
|
int piece_size = m_info->piece_size(piece);
|
||||||
if (m_storage->write(&m_scratch_buffer[0], piece, 0, piece_size) != piece_size)
|
if (m_storage->write(&m_scratch_buffer[0], piece, 0, piece_size) != piece_size)
|
||||||
{
|
{
|
||||||
error = true;
|
error = m_storage->error();
|
||||||
return std::make_pair(true, (float)m_current_slot / m_info->num_pieces());
|
m_storage->clear_error();
|
||||||
|
return fatal_disk_error;
|
||||||
}
|
}
|
||||||
m_piece_to_slot[piece] = piece;
|
m_piece_to_slot[piece] = piece;
|
||||||
m_slot_to_piece[piece] = piece;
|
m_slot_to_piece[piece] = piece;
|
||||||
|
@ -1745,7 +1831,7 @@ namespace libtorrent
|
||||||
if (other_piece >= 0)
|
if (other_piece >= 0)
|
||||||
m_scratch_buffer.swap(m_scratch_buffer2);
|
m_scratch_buffer.swap(m_scratch_buffer2);
|
||||||
|
|
||||||
return std::make_pair(false, (float)m_current_slot / m_info->num_pieces());
|
return need_full_check;
|
||||||
}
|
}
|
||||||
|
|
||||||
while (m_current_slot < m_info->num_pieces()
|
while (m_current_slot < m_info->num_pieces()
|
||||||
|
@ -1757,15 +1843,7 @@ namespace libtorrent
|
||||||
|
|
||||||
if (m_current_slot == m_info->num_pieces())
|
if (m_current_slot == m_info->num_pieces())
|
||||||
{
|
{
|
||||||
m_state = state_create_files;
|
return check_init_storage(error);
|
||||||
buffer().swap(m_scratch_buffer);
|
|
||||||
buffer().swap(m_scratch_buffer2);
|
|
||||||
if (m_storage_mode != storage_mode_compact)
|
|
||||||
{
|
|
||||||
std::vector<int>().swap(m_piece_to_slot);
|
|
||||||
std::vector<int>().swap(m_slot_to_piece);
|
|
||||||
}
|
|
||||||
return std::make_pair(false, 1.f);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int piece = m_slot_to_piece[m_current_slot];
|
int piece = m_slot_to_piece[m_current_slot];
|
||||||
|
@ -1782,8 +1860,9 @@ namespace libtorrent
|
||||||
int piece_size = m_info->piece_size(other_piece);
|
int piece_size = m_info->piece_size(other_piece);
|
||||||
if (m_storage->read(&m_scratch_buffer[0], piece, 0, piece_size) != piece_size)
|
if (m_storage->read(&m_scratch_buffer[0], piece, 0, piece_size) != piece_size)
|
||||||
{
|
{
|
||||||
error = true;
|
error = m_storage->error();
|
||||||
return std::make_pair(false, (float)m_current_slot / m_info->num_pieces());
|
m_storage->clear_error();
|
||||||
|
return fatal_disk_error;
|
||||||
}
|
}
|
||||||
m_scratch_piece = other_piece;
|
m_scratch_piece = other_piece;
|
||||||
m_piece_to_slot[other_piece] = unassigned;
|
m_piece_to_slot[other_piece] = unassigned;
|
||||||
|
@ -1796,12 +1875,12 @@ namespace libtorrent
|
||||||
m_slot_to_piece[m_current_slot] = unassigned;
|
m_slot_to_piece[m_current_slot] = unassigned;
|
||||||
m_slot_to_piece[piece] = piece;
|
m_slot_to_piece[piece] = piece;
|
||||||
|
|
||||||
return std::make_pair(false, (float)m_current_slot / m_info->num_pieces());
|
return need_full_check;
|
||||||
}
|
}
|
||||||
|
|
||||||
TORRENT_ASSERT(m_state == state_full_check);
|
TORRENT_ASSERT(m_state == state_full_check);
|
||||||
|
|
||||||
bool skip = check_one_piece(pieces, num_pieces, mutex);
|
bool skip = check_one_piece(have_piece);
|
||||||
|
|
||||||
if (skip)
|
if (skip)
|
||||||
{
|
{
|
||||||
|
@ -1837,6 +1916,7 @@ namespace libtorrent
|
||||||
}
|
}
|
||||||
|
|
||||||
++m_current_slot;
|
++m_current_slot;
|
||||||
|
current_slot = m_current_slot;
|
||||||
|
|
||||||
if (m_current_slot >= m_info->num_pieces())
|
if (m_current_slot >= m_info->num_pieces())
|
||||||
{
|
{
|
||||||
|
@ -1856,8 +1936,7 @@ namespace libtorrent
|
||||||
|
|
||||||
std::vector<int>().swap(m_piece_to_slot);
|
std::vector<int>().swap(m_piece_to_slot);
|
||||||
std::vector<int>().swap(m_slot_to_piece);
|
std::vector<int>().swap(m_slot_to_piece);
|
||||||
m_state = state_create_files;
|
return check_init_storage(error);
|
||||||
return std::make_pair(false, 1.f);
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -1865,47 +1944,37 @@ namespace libtorrent
|
||||||
// we're resuming a compact allocated storage
|
// we're resuming a compact allocated storage
|
||||||
m_state = state_expand_pieces;
|
m_state = state_expand_pieces;
|
||||||
m_current_slot = 0;
|
m_current_slot = 0;
|
||||||
return std::make_pair(false, 0.f);
|
current_slot = m_current_slot;
|
||||||
|
return need_full_check;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (m_unallocated_slots.empty())
|
else if (m_unallocated_slots.empty())
|
||||||
{
|
{
|
||||||
switch_to_full_mode();
|
switch_to_full_mode();
|
||||||
}
|
}
|
||||||
m_state = state_create_files;
|
return check_init_storage(error);
|
||||||
|
|
||||||
#ifndef NDEBUG
|
|
||||||
boost::recursive_mutex::scoped_lock l(mutex);
|
|
||||||
TORRENT_ASSERT(num_pieces == std::count(pieces.begin(), pieces.end(), true));
|
|
||||||
#endif
|
|
||||||
return std::make_pair(false, 1.f);
|
|
||||||
}
|
}
|
||||||
|
return need_full_check;
|
||||||
TORRENT_ASSERT(num_pieces == std::count(pieces.begin(), pieces.end(), true));
|
|
||||||
|
|
||||||
return std::make_pair(false, (float)m_current_slot / m_info->num_pieces());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool piece_manager::check_one_piece(std::vector<bool>& pieces, int& num_pieces
|
bool piece_manager::check_one_piece(int& have_piece)
|
||||||
, boost::recursive_mutex& mutex)
|
|
||||||
{
|
{
|
||||||
// ------------------------
|
// ------------------------
|
||||||
// DO THE FULL CHECK
|
// DO THE FULL CHECK
|
||||||
// ------------------------
|
// ------------------------
|
||||||
|
|
||||||
|
TORRENT_ASSERT(int(m_piece_to_slot.size()) == m_info->num_pieces());
|
||||||
|
TORRENT_ASSERT(int(m_slot_to_piece.size()) == m_info->num_pieces());
|
||||||
|
TORRENT_ASSERT(have_piece == -1);
|
||||||
|
|
||||||
// initialization for the full check
|
// initialization for the full check
|
||||||
if (m_hash_to_piece.empty())
|
if (m_hash_to_piece.empty())
|
||||||
{
|
{
|
||||||
for (int i = 0; i < m_info->num_pieces(); ++i)
|
for (int i = 0; i < m_info->num_pieces(); ++i)
|
||||||
{
|
|
||||||
m_hash_to_piece.insert(std::make_pair(m_info->hash_for_piece(i), i));
|
m_hash_to_piece.insert(std::make_pair(m_info->hash_for_piece(i), i));
|
||||||
}
|
|
||||||
boost::recursive_mutex::scoped_lock l(mutex);
|
|
||||||
std::fill(pieces.begin(), pieces.end(), false);
|
|
||||||
num_pieces = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
m_piece_data.resize(m_info->piece_length());
|
m_piece_data.resize(int(m_info->piece_length()));
|
||||||
int piece_size = m_info->piece_size(m_current_slot);
|
int piece_size = m_info->piece_size(m_current_slot);
|
||||||
int num_read = m_storage->read(&m_piece_data[0]
|
int num_read = m_storage->read(&m_piece_data[0]
|
||||||
, m_current_slot, 0, piece_size);
|
, m_current_slot, 0, piece_size);
|
||||||
|
@ -1914,14 +1983,14 @@ namespace libtorrent
|
||||||
if (num_read != piece_size)
|
if (num_read != piece_size)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
int piece_index = identify_data(m_piece_data, m_current_slot
|
int piece_index = identify_data(m_piece_data, m_current_slot);
|
||||||
, pieces, num_pieces, m_hash_to_piece, mutex);
|
|
||||||
|
if (piece_index >= 0) have_piece = piece_index;
|
||||||
|
|
||||||
if (piece_index != m_current_slot
|
if (piece_index != m_current_slot
|
||||||
&& piece_index >= 0)
|
&& piece_index >= 0)
|
||||||
m_out_of_place = true;
|
m_out_of_place = true;
|
||||||
|
|
||||||
TORRENT_ASSERT(num_pieces == std::count(pieces.begin(), pieces.end(), true));
|
|
||||||
TORRENT_ASSERT(piece_index == unassigned || piece_index >= 0);
|
TORRENT_ASSERT(piece_index == unassigned || piece_index >= 0);
|
||||||
|
|
||||||
const bool this_should_move = piece_index >= 0 && m_slot_to_piece[piece_index] != unallocated;
|
const bool this_should_move = piece_index >= 0 && m_slot_to_piece[piece_index] != unallocated;
|
||||||
|
@ -2148,7 +2217,7 @@ namespace libtorrent
|
||||||
|
|
||||||
if (m_storage_mode != storage_mode_compact) return piece_index;
|
if (m_storage_mode != storage_mode_compact) return piece_index;
|
||||||
|
|
||||||
// INVARIANT_CHECK;
|
INVARIANT_CHECK;
|
||||||
|
|
||||||
TORRENT_ASSERT(piece_index >= 0);
|
TORRENT_ASSERT(piece_index >= 0);
|
||||||
TORRENT_ASSERT(piece_index < (int)m_piece_to_slot.size());
|
TORRENT_ASSERT(piece_index < (int)m_piece_to_slot.size());
|
||||||
|
@ -2263,7 +2332,7 @@ namespace libtorrent
|
||||||
boost::recursive_mutex::scoped_lock lock(m_mutex);
|
boost::recursive_mutex::scoped_lock lock(m_mutex);
|
||||||
TORRENT_ASSERT(num_slots > 0);
|
TORRENT_ASSERT(num_slots > 0);
|
||||||
|
|
||||||
// INVARIANT_CHECK;
|
INVARIANT_CHECK;
|
||||||
|
|
||||||
TORRENT_ASSERT(!m_unallocated_slots.empty());
|
TORRENT_ASSERT(!m_unallocated_slots.empty());
|
||||||
TORRENT_ASSERT(m_storage_mode == storage_mode_compact);
|
TORRENT_ASSERT(m_storage_mode == storage_mode_compact);
|
||||||
|
|
375
src/torrent.cpp
375
src/torrent.cpp
|
@ -150,14 +150,14 @@ namespace libtorrent
|
||||||
|
|
||||||
torrent::torrent(
|
torrent::torrent(
|
||||||
session_impl& ses
|
session_impl& ses
|
||||||
, aux::checker_impl& checker
|
|
||||||
, boost::intrusive_ptr<torrent_info> tf
|
, boost::intrusive_ptr<torrent_info> tf
|
||||||
, fs::path const& save_path
|
, fs::path const& save_path
|
||||||
, tcp::endpoint const& net_interface
|
, tcp::endpoint const& net_interface
|
||||||
, storage_mode_t storage_mode
|
, storage_mode_t storage_mode
|
||||||
, int block_size
|
, int block_size
|
||||||
, storage_constructor_type sc
|
, storage_constructor_type sc
|
||||||
, bool paused)
|
, bool paused
|
||||||
|
, entry const& resume_data)
|
||||||
: m_torrent_file(tf)
|
: m_torrent_file(tf)
|
||||||
, m_abort(false)
|
, m_abort(false)
|
||||||
, m_paused(paused)
|
, m_paused(paused)
|
||||||
|
@ -179,7 +179,6 @@ namespace libtorrent
|
||||||
, m_last_dht_announce(time_now() - minutes(15))
|
, m_last_dht_announce(time_now() - minutes(15))
|
||||||
#endif
|
#endif
|
||||||
, m_ses(ses)
|
, m_ses(ses)
|
||||||
, m_checker(checker)
|
|
||||||
, m_picker(0)
|
, m_picker(0)
|
||||||
, m_trackers(m_torrent_file->trackers())
|
, m_trackers(m_torrent_file->trackers())
|
||||||
, m_last_working_tracker(-1)
|
, m_last_working_tracker(-1)
|
||||||
|
@ -195,6 +194,9 @@ namespace libtorrent
|
||||||
, m_net_interface(net_interface.address(), 0)
|
, m_net_interface(net_interface.address(), 0)
|
||||||
, m_save_path(complete(save_path))
|
, m_save_path(complete(save_path))
|
||||||
, m_storage_mode(storage_mode)
|
, m_storage_mode(storage_mode)
|
||||||
|
, m_state(torrent_status::queued_for_checking)
|
||||||
|
, m_progress(0.f)
|
||||||
|
, m_resume_data(resume_data)
|
||||||
, m_default_block_size(block_size)
|
, m_default_block_size(block_size)
|
||||||
, m_connections_initialized(true)
|
, m_connections_initialized(true)
|
||||||
, m_settings(ses.settings())
|
, m_settings(ses.settings())
|
||||||
|
@ -211,7 +213,6 @@ namespace libtorrent
|
||||||
|
|
||||||
torrent::torrent(
|
torrent::torrent(
|
||||||
session_impl& ses
|
session_impl& ses
|
||||||
, aux::checker_impl& checker
|
|
||||||
, char const* tracker_url
|
, char const* tracker_url
|
||||||
, sha1_hash const& info_hash
|
, sha1_hash const& info_hash
|
||||||
, char const* name
|
, char const* name
|
||||||
|
@ -220,7 +221,8 @@ namespace libtorrent
|
||||||
, storage_mode_t storage_mode
|
, storage_mode_t storage_mode
|
||||||
, int block_size
|
, int block_size
|
||||||
, storage_constructor_type sc
|
, storage_constructor_type sc
|
||||||
, bool paused)
|
, bool paused
|
||||||
|
, entry const& resume_data)
|
||||||
: m_torrent_file(new torrent_info(info_hash))
|
: m_torrent_file(new torrent_info(info_hash))
|
||||||
, m_abort(false)
|
, m_abort(false)
|
||||||
, m_paused(paused)
|
, m_paused(paused)
|
||||||
|
@ -242,7 +244,6 @@ namespace libtorrent
|
||||||
, m_last_dht_announce(time_now() - minutes(15))
|
, m_last_dht_announce(time_now() - minutes(15))
|
||||||
#endif
|
#endif
|
||||||
, m_ses(ses)
|
, m_ses(ses)
|
||||||
, m_checker(checker)
|
|
||||||
, m_picker(0)
|
, m_picker(0)
|
||||||
, m_last_working_tracker(-1)
|
, m_last_working_tracker(-1)
|
||||||
, m_currently_trying_tracker(0)
|
, m_currently_trying_tracker(0)
|
||||||
|
@ -257,6 +258,9 @@ namespace libtorrent
|
||||||
, m_net_interface(net_interface.address(), 0)
|
, m_net_interface(net_interface.address(), 0)
|
||||||
, m_save_path(complete(save_path))
|
, m_save_path(complete(save_path))
|
||||||
, m_storage_mode(storage_mode)
|
, m_storage_mode(storage_mode)
|
||||||
|
, m_state(torrent_status::queued_for_checking)
|
||||||
|
, m_progress(0.f)
|
||||||
|
, m_resume_data(resume_data)
|
||||||
, m_default_block_size(block_size)
|
, m_default_block_size(block_size)
|
||||||
, m_connections_initialized(false)
|
, m_connections_initialized(false)
|
||||||
, m_settings(ses.settings())
|
, m_settings(ses.settings())
|
||||||
|
@ -399,7 +403,8 @@ namespace libtorrent
|
||||||
// the shared_from_this() will create an intentional
|
// the shared_from_this() will create an intentional
|
||||||
// cycle of ownership, se the hpp file for description.
|
// cycle of ownership, se the hpp file for description.
|
||||||
m_owning_storage = new piece_manager(shared_from_this(), m_torrent_file
|
m_owning_storage = new piece_manager(shared_from_this(), m_torrent_file
|
||||||
, m_save_path, m_ses.m_files, m_ses.m_disk_thread, m_storage_constructor);
|
, m_save_path, m_ses.m_files, m_ses.m_disk_thread, m_storage_constructor
|
||||||
|
, m_storage_mode);
|
||||||
m_storage = m_owning_storage.get();
|
m_storage = m_owning_storage.get();
|
||||||
m_block_size = calculate_block_size(*m_torrent_file, m_default_block_size);
|
m_block_size = calculate_block_size(*m_torrent_file, m_default_block_size);
|
||||||
m_picker.reset(new piece_picker(
|
m_picker.reset(new piece_picker(
|
||||||
|
@ -409,6 +414,233 @@ namespace libtorrent
|
||||||
std::vector<std::string> const& url_seeds = m_torrent_file->url_seeds();
|
std::vector<std::string> const& url_seeds = m_torrent_file->url_seeds();
|
||||||
std::copy(url_seeds.begin(), url_seeds.end(), std::inserter(m_web_seeds
|
std::copy(url_seeds.begin(), url_seeds.end(), std::inserter(m_web_seeds
|
||||||
, m_web_seeds.begin()));
|
, m_web_seeds.begin()));
|
||||||
|
|
||||||
|
m_state = torrent_status::queued_for_checking;
|
||||||
|
|
||||||
|
m_storage->async_check_fastresume(&m_resume_data
|
||||||
|
, bind(&torrent::on_resume_data_checked
|
||||||
|
, shared_from_this(), _1, _2));
|
||||||
|
}
|
||||||
|
|
||||||
|
void torrent::on_resume_data_checked(int ret, disk_io_job const& j)
|
||||||
|
{
|
||||||
|
session_impl::mutex_t::scoped_lock l(m_ses.m_mutex);
|
||||||
|
|
||||||
|
if (ret == piece_manager::fatal_disk_error)
|
||||||
|
{
|
||||||
|
if (m_ses.m_alerts.should_post(alert::fatal))
|
||||||
|
{
|
||||||
|
m_ses.m_alerts.post_alert(file_error_alert(get_handle(), j.str));
|
||||||
|
#if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_LOGGING || defined TORRENT_ERROR_LOGGING
|
||||||
|
(*m_ses.m_logger) << time_now_string() << ": fatal disk error ["
|
||||||
|
" error: " << j.str <<
|
||||||
|
" torrent: " << torrent_file().name() <<
|
||||||
|
" ]\n";
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
std::fill(m_have_pieces.begin(), m_have_pieces.end(), false);
|
||||||
|
m_num_pieces = 0;
|
||||||
|
pause();
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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)
|
||||||
|
{
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool fastresume_rejected = !j.str.empty();
|
||||||
|
|
||||||
|
if (fastresume_rejected && m_ses.m_alerts.should_post(alert::warning))
|
||||||
|
{
|
||||||
|
m_ses.m_alerts.post_alert(fastresume_rejected_alert(get_handle(), j.str));
|
||||||
|
#if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_LOGGING || defined TORRENT_ERROR_LOGGING
|
||||||
|
(*m_ses.m_logger) << "fastresume data for "
|
||||||
|
<< torrent_file().name() << " rejected: "
|
||||||
|
<< j.str << "\n";
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ret == 0)
|
||||||
|
{
|
||||||
|
// there are either no files for this torrent
|
||||||
|
// or the resume_data was accepted
|
||||||
|
|
||||||
|
m_num_pieces = 0;
|
||||||
|
std::fill(m_have_pieces.begin(), m_have_pieces.end(), false);
|
||||||
|
if (!fastresume_rejected)
|
||||||
|
{
|
||||||
|
// parse slots
|
||||||
|
entry const* slots_ent = m_resume_data.find_key("slots");
|
||||||
|
if (slots_ent != 0 && slots_ent->type() == entry::list_t)
|
||||||
|
{
|
||||||
|
entry::list_type const& slots = slots_ent->list();
|
||||||
|
|
||||||
|
for (entry::list_type::const_iterator i = slots.begin();
|
||||||
|
i != slots.end(); ++i)
|
||||||
|
{
|
||||||
|
if (i->type() != entry::int_t) continue;
|
||||||
|
int piece_index = int(i->integer());
|
||||||
|
if (piece_index < 0 || piece_index >= torrent_file().num_pieces())
|
||||||
|
continue;
|
||||||
|
m_have_pieces[piece_index] = true;
|
||||||
|
++m_num_pieces;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// parse unfinished pieces
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
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;
|
||||||
|
|
||||||
|
// if this assert is hit, the resume data file was corrupt
|
||||||
|
TORRENT_ASSERT(m_have_pieces[piece_index]);
|
||||||
|
m_have_pieces[piece_index] = false;
|
||||||
|
--m_num_pieces;
|
||||||
|
|
||||||
|
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();
|
||||||
|
|
||||||
|
const int num_bitmask_bytes = (std::max)(num_blocks_per_piece / 8, 1);
|
||||||
|
if ((int)bitmask.size() != num_bitmask_bytes) continue;
|
||||||
|
for (int j = 0; j < num_bitmask_bytes; ++j)
|
||||||
|
{
|
||||||
|
unsigned char bits = bitmask[j];
|
||||||
|
int num_bits = (std::min)(num_blocks_per_piece - j*8, 8);
|
||||||
|
for (int k = 0; k < num_bits; ++k)
|
||||||
|
{
|
||||||
|
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));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
files_checked();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// either the fastresume data was rejected or there are
|
||||||
|
// some files
|
||||||
|
m_ses.check_torrent(shared_from_this());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void torrent::start_checking()
|
||||||
|
{
|
||||||
|
m_state = torrent_status::checking_files;
|
||||||
|
|
||||||
|
m_storage->async_check_files(bind(
|
||||||
|
&torrent::on_piece_checked
|
||||||
|
, shared_from_this(), _1, _2));
|
||||||
|
}
|
||||||
|
|
||||||
|
void torrent::on_piece_checked(int ret, disk_io_job const& j)
|
||||||
|
{
|
||||||
|
session_impl::mutex_t::scoped_lock l(m_ses.m_mutex);
|
||||||
|
|
||||||
|
if (ret == piece_manager::fatal_disk_error)
|
||||||
|
{
|
||||||
|
if (m_ses.m_alerts.should_post(alert::fatal))
|
||||||
|
{
|
||||||
|
m_ses.m_alerts.post_alert(file_error_alert(get_handle(), j.str));
|
||||||
|
#if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_LOGGING || defined TORRENT_ERROR_LOGGING
|
||||||
|
(*m_ses.m_logger) << time_now_string() << ": fatal disk error ["
|
||||||
|
" error: " << j.str <<
|
||||||
|
" torrent: " << torrent_file().name() <<
|
||||||
|
" ]\n";
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
std::fill(m_have_pieces.begin(), m_have_pieces.end(), false);
|
||||||
|
m_num_pieces = 0;
|
||||||
|
pause();
|
||||||
|
m_ses.done_checking(shared_from_this());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_progress = j.piece / float(torrent_file().num_pieces());
|
||||||
|
|
||||||
|
if (j.offset >= 0 && !m_have_pieces[j.offset])
|
||||||
|
{
|
||||||
|
m_have_pieces[j.offset] = true;
|
||||||
|
++m_num_pieces;
|
||||||
|
}
|
||||||
|
|
||||||
|
// we're not done checking yet
|
||||||
|
// this handler will be called repeatedly until
|
||||||
|
// we're done, or encounter a failure
|
||||||
|
if (ret == piece_manager::need_full_check) return;
|
||||||
|
|
||||||
|
m_ses.done_checking(shared_from_this());
|
||||||
|
files_checked();
|
||||||
}
|
}
|
||||||
|
|
||||||
void torrent::use_interface(const char* net_interface)
|
void torrent::use_interface(const char* net_interface)
|
||||||
|
@ -1102,7 +1334,6 @@ namespace libtorrent
|
||||||
// that has sent the least number of pieces
|
// that has sent the least number of pieces
|
||||||
m_picker->restore_piece(index);
|
m_picker->restore_piece(index);
|
||||||
TORRENT_ASSERT(m_storage);
|
TORRENT_ASSERT(m_storage);
|
||||||
m_storage->mark_failed(index);
|
|
||||||
|
|
||||||
TORRENT_ASSERT(m_have_pieces[index] == false);
|
TORRENT_ASSERT(m_have_pieces[index] == false);
|
||||||
|
|
||||||
|
@ -2151,31 +2382,14 @@ namespace libtorrent
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
init();
|
|
||||||
|
|
||||||
boost::mutex::scoped_lock(m_checker.m_mutex);
|
|
||||||
|
|
||||||
boost::shared_ptr<aux::piece_checker_data> d(
|
|
||||||
new aux::piece_checker_data);
|
|
||||||
d->torrent_ptr = shared_from_this();
|
|
||||||
d->save_path = m_save_path;
|
|
||||||
d->info_hash = m_torrent_file->info_hash();
|
|
||||||
// add the torrent to the queue to be checked
|
|
||||||
m_checker.m_torrents.push_back(d);
|
|
||||||
typedef session_impl::torrent_map torrent_map;
|
|
||||||
torrent_map::iterator i = m_ses.m_torrents.find(
|
|
||||||
m_torrent_file->info_hash());
|
|
||||||
TORRENT_ASSERT(i != m_ses.m_torrents.end());
|
|
||||||
m_ses.m_torrents.erase(i);
|
|
||||||
// and notify the thread that it got another
|
|
||||||
// job in its queue
|
|
||||||
m_checker.m_cond.notify_one();
|
|
||||||
|
|
||||||
if (m_ses.m_alerts.should_post(alert::info))
|
if (m_ses.m_alerts.should_post(alert::info))
|
||||||
{
|
{
|
||||||
m_ses.m_alerts.post_alert(metadata_received_alert(
|
m_ses.m_alerts.post_alert(metadata_received_alert(
|
||||||
get_handle(), "metadata successfully received from swarm"));
|
get_handle(), "metadata successfully received from swarm"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
init();
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2186,6 +2400,13 @@ namespace libtorrent
|
||||||
TORRENT_ASSERT(p != 0);
|
TORRENT_ASSERT(p != 0);
|
||||||
TORRENT_ASSERT(!p->is_local());
|
TORRENT_ASSERT(!p->is_local());
|
||||||
|
|
||||||
|
if (m_state == torrent_status::queued_for_checking
|
||||||
|
|| m_state == torrent_status::checking_files)
|
||||||
|
{
|
||||||
|
p->disconnect("torrent is not ready to accept peers");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (m_ses.m_connections.find(p) == m_ses.m_connections.end())
|
if (m_ses.m_connections.find(p) == m_ses.m_connections.end())
|
||||||
{
|
{
|
||||||
p->disconnect("peer is not properly constructed");
|
p->disconnect("peer is not properly constructed");
|
||||||
|
@ -2246,7 +2467,9 @@ namespace libtorrent
|
||||||
{
|
{
|
||||||
return int(m_connections.size()) < m_max_connections
|
return int(m_connections.size()) < m_max_connections
|
||||||
&& m_ses.m_half_open.free_slots()
|
&& m_ses.m_half_open.free_slots()
|
||||||
&& !m_paused;
|
&& !m_paused
|
||||||
|
&& m_state != torrent_status::checking_files
|
||||||
|
&& m_state != torrent_status::queued_for_checking;
|
||||||
}
|
}
|
||||||
|
|
||||||
void torrent::disconnect_all()
|
void torrent::disconnect_all()
|
||||||
|
@ -2380,6 +2603,8 @@ namespace libtorrent
|
||||||
, "torrent has finished downloading"));
|
, "torrent has finished downloading"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
m_state = torrent_status::finished;
|
||||||
|
|
||||||
// disconnect all seeds
|
// disconnect all seeds
|
||||||
// TODO: should disconnect all peers that have the pieces we have
|
// TODO: should disconnect all peers that have the pieces we have
|
||||||
// not just seeds
|
// not just seeds
|
||||||
|
@ -2414,6 +2639,7 @@ namespace libtorrent
|
||||||
// make the next tracker request
|
// make the next tracker request
|
||||||
// be a completed-event
|
// be a completed-event
|
||||||
m_event = tracker_request::completed;
|
m_event = tracker_request::completed;
|
||||||
|
m_state = torrent_status::seeding;
|
||||||
force_tracker_request();
|
force_tracker_request();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2478,10 +2704,10 @@ namespace libtorrent
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool torrent::check_fastresume(aux::piece_checker_data& data)
|
/*
|
||||||
|
void torrent::check_fastresume()
|
||||||
{
|
{
|
||||||
INVARIANT_CHECK;
|
INVARIANT_CHECK;
|
||||||
|
|
||||||
TORRENT_ASSERT(valid_metadata());
|
TORRENT_ASSERT(valid_metadata());
|
||||||
bool done = true;
|
bool done = true;
|
||||||
try
|
try
|
||||||
|
@ -2492,16 +2718,6 @@ namespace libtorrent
|
||||||
done = m_storage->check_fastresume(data, m_have_pieces, m_num_pieces
|
done = m_storage->check_fastresume(data, m_have_pieces, m_num_pieces
|
||||||
, m_storage_mode, error_msg);
|
, m_storage_mode, error_msg);
|
||||||
|
|
||||||
if (!error_msg.empty() && m_ses.m_alerts.should_post(alert::warning))
|
|
||||||
{
|
|
||||||
m_ses.m_alerts.post_alert(fastresume_rejected_alert(
|
|
||||||
get_handle(), error_msg));
|
|
||||||
#if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_LOGGING || defined TORRENT_ERROR_LOGGING
|
|
||||||
(*m_ses.m_logger) << "fastresume data for "
|
|
||||||
<< torrent_file().name() << " rejected: "
|
|
||||||
<< error_msg << "\n";
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
catch (std::exception& e)
|
catch (std::exception& e)
|
||||||
{
|
{
|
||||||
|
@ -2551,30 +2767,21 @@ namespace libtorrent
|
||||||
|
|
||||||
return progress;
|
return progress;
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
void torrent::files_checked(std::vector<piece_picker::downloading_piece> const&
|
void torrent::files_checked()
|
||||||
unfinished_pieces)
|
|
||||||
{
|
{
|
||||||
session_impl::mutex_t::scoped_lock l(m_ses.m_mutex);
|
session_impl::mutex_t::scoped_lock l(m_ses.m_mutex);
|
||||||
|
|
||||||
TORRENT_ASSERT(m_torrent_file->is_valid());
|
TORRENT_ASSERT(m_torrent_file->is_valid());
|
||||||
INVARIANT_CHECK;
|
INVARIANT_CHECK;
|
||||||
|
|
||||||
|
m_state = torrent_status::connecting_to_tracker;
|
||||||
|
|
||||||
if (!is_seed())
|
if (!is_seed())
|
||||||
{
|
{
|
||||||
// this is filled in with pieces that needs to be checked
|
m_picker->init(m_have_pieces);
|
||||||
// against its hashes.
|
|
||||||
std::vector<int> verify_pieces;
|
|
||||||
m_picker->files_checked(m_have_pieces, unfinished_pieces, verify_pieces);
|
|
||||||
if (m_sequential_download)
|
if (m_sequential_download)
|
||||||
picker().sequential_download(m_sequential_download);
|
picker().sequential_download(m_sequential_download);
|
||||||
while (!verify_pieces.empty())
|
|
||||||
{
|
|
||||||
int piece = verify_pieces.back();
|
|
||||||
verify_pieces.pop_back();
|
|
||||||
async_verify_piece(piece, bind(&torrent::piece_finished
|
|
||||||
, shared_from_this(), piece, _1));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef TORRENT_DISABLE_EXTENSIONS
|
#ifndef TORRENT_DISABLE_EXTENSIONS
|
||||||
|
@ -2593,6 +2800,7 @@ namespace libtorrent
|
||||||
|
|
||||||
if (is_seed())
|
if (is_seed())
|
||||||
{
|
{
|
||||||
|
m_state = torrent_status::seeding;
|
||||||
m_picker.reset();
|
m_picker.reset();
|
||||||
if (m_ses.settings().free_torrent_hashes)
|
if (m_ses.settings().free_torrent_hashes)
|
||||||
m_torrent_file->seed_free();
|
m_torrent_file->seed_free();
|
||||||
|
@ -2634,10 +2842,7 @@ namespace libtorrent
|
||||||
|
|
||||||
fs::path torrent::save_path() const
|
fs::path torrent::save_path() const
|
||||||
{
|
{
|
||||||
if (m_owning_storage.get())
|
return m_save_path;
|
||||||
return m_owning_storage->save_path();
|
|
||||||
else
|
|
||||||
return m_save_path;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void torrent::move_storage(fs::path const& save_path)
|
void torrent::move_storage(fs::path const& save_path)
|
||||||
|
@ -2674,7 +2879,7 @@ namespace libtorrent
|
||||||
|
|
||||||
torrent_handle torrent::get_handle() const
|
torrent_handle torrent::get_handle() const
|
||||||
{
|
{
|
||||||
return torrent_handle(&m_ses, &m_checker, m_torrent_file->info_hash());
|
return torrent_handle(&m_ses, m_torrent_file->info_hash());
|
||||||
}
|
}
|
||||||
|
|
||||||
session_settings const& torrent::settings() const
|
session_settings const& torrent::settings() const
|
||||||
|
@ -2779,17 +2984,6 @@ namespace libtorrent
|
||||||
complete = false;
|
complete = false;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
// this is no longer valid since the completion event
|
|
||||||
// may be queued in the io service
|
|
||||||
/*
|
|
||||||
if (complete && m_files_checked)
|
|
||||||
{
|
|
||||||
disk_io_job ret = m_ses.m_disk_thread.find_job(
|
|
||||||
m_owning_storage, -1, i->index);
|
|
||||||
TORRENT_ASSERT(ret.action == disk_io_job::hash || ret.action == disk_io_job::write);
|
|
||||||
TORRENT_ASSERT(ret.piece == i->index);
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3100,9 +3294,8 @@ namespace libtorrent
|
||||||
void torrent::on_piece_verified(int ret, disk_io_job const& j
|
void torrent::on_piece_verified(int ret, disk_io_job const& j
|
||||||
, boost::function<void(bool)> f)
|
, boost::function<void(bool)> f)
|
||||||
{
|
{
|
||||||
sha1_hash h(j.str);
|
|
||||||
session_impl::mutex_t::scoped_lock l(m_ses.m_mutex);
|
session_impl::mutex_t::scoped_lock l(m_ses.m_mutex);
|
||||||
f(m_torrent_file->hash_for_piece(j.piece) == h);
|
f(ret == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
const tcp::endpoint& torrent::current_tracker() const
|
const tcp::endpoint& torrent::current_tracker() const
|
||||||
|
@ -3110,9 +3303,6 @@ namespace libtorrent
|
||||||
return m_tracker_address;
|
return m_tracker_address;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool torrent::is_allocating() const
|
|
||||||
{ return m_owning_storage.get() && m_owning_storage->is_allocating(); }
|
|
||||||
|
|
||||||
void torrent::file_progress(std::vector<float>& fp) const
|
void torrent::file_progress(std::vector<float>& fp) const
|
||||||
{
|
{
|
||||||
TORRENT_ASSERT(valid_metadata());
|
TORRENT_ASSERT(valid_metadata());
|
||||||
|
@ -3217,6 +3407,8 @@ namespace libtorrent
|
||||||
st.connections_limit = m_max_connections;
|
st.connections_limit = m_max_connections;
|
||||||
// if we don't have any metadata, stop here
|
// if we don't have any metadata, stop here
|
||||||
|
|
||||||
|
st.state = m_state;
|
||||||
|
|
||||||
if (!valid_metadata())
|
if (!valid_metadata())
|
||||||
{
|
{
|
||||||
if (m_got_tracker_response == false)
|
if (m_got_tracker_response == false)
|
||||||
|
@ -3224,14 +3416,8 @@ namespace libtorrent
|
||||||
else
|
else
|
||||||
st.state = torrent_status::downloading_metadata;
|
st.state = torrent_status::downloading_metadata;
|
||||||
|
|
||||||
// TODO: add a progress member to the torrent that will be used in this case
|
st.progress = m_progress;
|
||||||
// and that may be set by a plugin
|
|
||||||
// if (m_metadata_size == 0) st.progress = 0.f;
|
|
||||||
// else st.progress = (std::min)(1.f, m_metadata_progress / (float)m_metadata_size);
|
|
||||||
st.progress = 0.f;
|
|
||||||
|
|
||||||
st.block_size = 0;
|
st.block_size = 0;
|
||||||
|
|
||||||
return st;
|
return st;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3258,31 +3444,14 @@ namespace libtorrent
|
||||||
|
|
||||||
TORRENT_ASSERT(st.total_wanted >= st.total_wanted_done);
|
TORRENT_ASSERT(st.total_wanted >= st.total_wanted_done);
|
||||||
|
|
||||||
if (st.total_wanted == 0) st.progress = 1.f;
|
if (m_state == torrent_status::checking_files)
|
||||||
|
st.progress = m_progress;
|
||||||
|
else if (st.total_wanted == 0) st.progress = 1.f;
|
||||||
else st.progress = st.total_wanted_done
|
else st.progress = st.total_wanted_done
|
||||||
/ static_cast<double>(st.total_wanted);
|
/ static_cast<double>(st.total_wanted);
|
||||||
|
|
||||||
st.pieces = &m_have_pieces;
|
st.pieces = &m_have_pieces;
|
||||||
st.num_pieces = m_num_pieces;
|
st.num_pieces = m_num_pieces;
|
||||||
|
|
||||||
if (m_got_tracker_response == false)
|
|
||||||
{
|
|
||||||
st.state = torrent_status::connecting_to_tracker;
|
|
||||||
}
|
|
||||||
else if (is_seed())
|
|
||||||
{
|
|
||||||
TORRENT_ASSERT(st.total_done == m_torrent_file->total_size());
|
|
||||||
st.state = torrent_status::seeding;
|
|
||||||
}
|
|
||||||
else if (st.total_wanted_done == st.total_wanted)
|
|
||||||
{
|
|
||||||
st.state = torrent_status::finished;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
st.state = torrent_status::downloading;
|
|
||||||
}
|
|
||||||
|
|
||||||
st.num_seeds = num_seeds();
|
st.num_seeds = num_seeds();
|
||||||
if (m_picker.get())
|
if (m_picker.get())
|
||||||
st.distributed_copies = m_picker->distributed_copies();
|
st.distributed_copies = m_picker->distributed_copies();
|
||||||
|
|
|
@ -82,58 +82,46 @@ using libtorrent::aux::session_impl;
|
||||||
|
|
||||||
#define TORRENT_FORWARD(call) \
|
#define TORRENT_FORWARD(call) \
|
||||||
if (m_ses == 0) return; \
|
if (m_ses == 0) return; \
|
||||||
TORRENT_ASSERT(m_chk); \
|
|
||||||
session_impl::mutex_t::scoped_lock l1(m_ses->m_mutex); \
|
session_impl::mutex_t::scoped_lock l1(m_ses->m_mutex); \
|
||||||
mutex::scoped_lock l2(m_chk->m_mutex); \
|
boost::shared_ptr<torrent> t = m_ses->find_torrent(m_info_hash).lock(); \
|
||||||
torrent* t = find_torrent(m_ses, m_chk, m_info_hash); \
|
if (!t) return; \
|
||||||
if (t == 0) return; \
|
|
||||||
t->call
|
t->call
|
||||||
|
|
||||||
#define TORRENT_FORWARD_RETURN(call, def) \
|
#define TORRENT_FORWARD_RETURN(call, def) \
|
||||||
if (m_ses == 0) return def; \
|
if (m_ses == 0) return def; \
|
||||||
TORRENT_ASSERT(m_chk); \
|
|
||||||
session_impl::mutex_t::scoped_lock l1(m_ses->m_mutex); \
|
session_impl::mutex_t::scoped_lock l1(m_ses->m_mutex); \
|
||||||
mutex::scoped_lock l2(m_chk->m_mutex); \
|
boost::shared_ptr<torrent> t = m_ses->find_torrent(m_info_hash).lock(); \
|
||||||
torrent* t = find_torrent(m_ses, m_chk, m_info_hash); \
|
if (!t) return def; \
|
||||||
if (t == 0) return def; \
|
|
||||||
return t->call
|
return t->call
|
||||||
|
|
||||||
#define TORRENT_FORWARD_RETURN2(call, def) \
|
#define TORRENT_FORWARD_RETURN2(call, def) \
|
||||||
if (m_ses == 0) return def; \
|
if (m_ses == 0) return def; \
|
||||||
TORRENT_ASSERT(m_chk); \
|
|
||||||
session_impl::mutex_t::scoped_lock l1(m_ses->m_mutex); \
|
session_impl::mutex_t::scoped_lock l1(m_ses->m_mutex); \
|
||||||
mutex::scoped_lock l2(m_chk->m_mutex); \
|
boost::shared_ptr<torrent> t = m_ses->find_torrent(m_info_hash).lock(); \
|
||||||
torrent* t = find_torrent(m_ses, m_chk, m_info_hash); \
|
if (!t) return def; \
|
||||||
if (t == 0) return def; \
|
|
||||||
t->call
|
t->call
|
||||||
|
|
||||||
#else
|
#else
|
||||||
|
|
||||||
#define TORRENT_FORWARD(call) \
|
#define TORRENT_FORWARD(call) \
|
||||||
if (m_ses == 0) throw_invalid_handle(); \
|
if (m_ses == 0) throw_invalid_handle(); \
|
||||||
TORRENT_ASSERT(m_chk); \
|
|
||||||
session_impl::mutex_t::scoped_lock l1(m_ses->m_mutex); \
|
session_impl::mutex_t::scoped_lock l1(m_ses->m_mutex); \
|
||||||
mutex::scoped_lock l2(m_chk->m_mutex); \
|
boost::shared_ptr<torrent> t = m_ses->find_torrent(m_info_hash).lock(); \
|
||||||
torrent* t = find_torrent(m_ses, m_chk, m_info_hash); \
|
if (!t) throw_invalid_handle(); \
|
||||||
if (t == 0) throw_invalid_handle(); \
|
|
||||||
t->call
|
t->call
|
||||||
|
|
||||||
#define TORRENT_FORWARD_RETURN(call, def) \
|
#define TORRENT_FORWARD_RETURN(call, def) \
|
||||||
if (m_ses == 0) throw_invalid_handle(); \
|
if (m_ses == 0) throw_invalid_handle(); \
|
||||||
TORRENT_ASSERT(m_chk); \
|
|
||||||
session_impl::mutex_t::scoped_lock l1(m_ses->m_mutex); \
|
session_impl::mutex_t::scoped_lock l1(m_ses->m_mutex); \
|
||||||
mutex::scoped_lock l2(m_chk->m_mutex); \
|
boost::shared_ptr<torrent> t = m_ses->find_torrent(m_info_hash).lock(); \
|
||||||
torrent* t = find_torrent(m_ses, m_chk, m_info_hash); \
|
if (!t) return def; \
|
||||||
if (t == 0) return def; \
|
|
||||||
return t->call
|
return t->call
|
||||||
|
|
||||||
#define TORRENT_FORWARD_RETURN2(call, def) \
|
#define TORRENT_FORWARD_RETURN2(call, def) \
|
||||||
if (m_ses == 0) throw_invalid_handle(); \
|
if (m_ses == 0) throw_invalid_handle(); \
|
||||||
TORRENT_ASSERT(m_chk); \
|
|
||||||
session_impl::mutex_t::scoped_lock l1(m_ses->m_mutex); \
|
session_impl::mutex_t::scoped_lock l1(m_ses->m_mutex); \
|
||||||
mutex::scoped_lock l2(m_chk->m_mutex); \
|
boost::shared_ptr<torrent> t = m_ses->find_torrent(m_info_hash).lock(); \
|
||||||
torrent* t = find_torrent(m_ses, m_chk, m_info_hash); \
|
if (!t) return def; \
|
||||||
if (t == 0) return def; \
|
|
||||||
t->call
|
t->call
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -150,26 +138,12 @@ namespace libtorrent
|
||||||
throw invalid_handle();
|
throw invalid_handle();
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
torrent* find_torrent(
|
|
||||||
session_impl* ses
|
|
||||||
, aux::checker_impl* chk
|
|
||||||
, sha1_hash const& hash)
|
|
||||||
{
|
|
||||||
aux::piece_checker_data* d = chk->find_torrent(hash);
|
|
||||||
if (d != 0) return d->torrent_ptr.get();
|
|
||||||
|
|
||||||
boost::shared_ptr<torrent> t = ses->find_torrent(hash).lock();
|
|
||||||
if (t) return t.get();
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef NDEBUG
|
#ifndef NDEBUG
|
||||||
|
|
||||||
void torrent_handle::check_invariant() const
|
void torrent_handle::check_invariant() const
|
||||||
{
|
{
|
||||||
TORRENT_ASSERT((m_ses == 0 && m_chk == 0) || (m_ses != 0 && m_chk != 0));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -302,30 +276,8 @@ namespace libtorrent
|
||||||
#else
|
#else
|
||||||
throw_invalid_handle();
|
throw_invalid_handle();
|
||||||
#endif
|
#endif
|
||||||
TORRENT_ASSERT(m_chk);
|
|
||||||
|
|
||||||
session_impl::mutex_t::scoped_lock l(m_ses->m_mutex);
|
session_impl::mutex_t::scoped_lock l(m_ses->m_mutex);
|
||||||
mutex::scoped_lock l2(m_chk->m_mutex);
|
|
||||||
|
|
||||||
aux::piece_checker_data* d = m_chk->find_torrent(m_info_hash);
|
|
||||||
if (d != 0)
|
|
||||||
{
|
|
||||||
torrent_status st = d->torrent_ptr->status();
|
|
||||||
|
|
||||||
if (d->processing)
|
|
||||||
{
|
|
||||||
if (d->torrent_ptr->is_allocating())
|
|
||||||
st.state = torrent_status::allocating;
|
|
||||||
else
|
|
||||||
st.state = torrent_status::checking_files;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
st.state = torrent_status::queued_for_checking;
|
|
||||||
st.progress = d->progress;
|
|
||||||
st.paused = d->torrent_ptr->is_paused();
|
|
||||||
return st;
|
|
||||||
}
|
|
||||||
|
|
||||||
boost::shared_ptr<torrent> t = m_ses->find_torrent(m_info_hash).lock();
|
boost::shared_ptr<torrent> t = m_ses->find_torrent(m_info_hash).lock();
|
||||||
if (t) return t->status();
|
if (t) return t->status();
|
||||||
|
|
||||||
|
@ -464,11 +416,9 @@ namespace libtorrent
|
||||||
#else
|
#else
|
||||||
if (m_ses == 0) throw_invalid_handle();
|
if (m_ses == 0) throw_invalid_handle();
|
||||||
#endif
|
#endif
|
||||||
TORRENT_ASSERT(m_chk);
|
|
||||||
session_impl::mutex_t::scoped_lock l1(m_ses->m_mutex);
|
session_impl::mutex_t::scoped_lock l1(m_ses->m_mutex);
|
||||||
mutex::scoped_lock l2(m_chk->m_mutex);
|
boost::shared_ptr<torrent> t = m_ses->find_torrent(m_info_hash).lock();
|
||||||
torrent* t = find_torrent(m_ses, m_chk, m_info_hash);
|
if (!t || !t->valid_metadata())
|
||||||
if (t == 0 || !t->valid_metadata())
|
|
||||||
#ifdef BOOST_NO_EXCEPTIONS
|
#ifdef BOOST_NO_EXCEPTIONS
|
||||||
return empty;
|
return empty;
|
||||||
#else
|
#else
|
||||||
|
@ -481,10 +431,8 @@ namespace libtorrent
|
||||||
{
|
{
|
||||||
INVARIANT_CHECK;
|
INVARIANT_CHECK;
|
||||||
if (m_ses == 0) return false;
|
if (m_ses == 0) return false;
|
||||||
TORRENT_ASSERT(m_chk);
|
|
||||||
session_impl::mutex_t::scoped_lock l1(m_ses->m_mutex);
|
session_impl::mutex_t::scoped_lock l1(m_ses->m_mutex);
|
||||||
mutex::scoped_lock l2(m_chk->m_mutex);
|
boost::shared_ptr<torrent> t = m_ses->find_torrent(m_info_hash).lock();
|
||||||
torrent* t = find_torrent(m_ses, m_chk, m_info_hash);
|
|
||||||
return t;
|
return t;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -498,12 +446,8 @@ namespace libtorrent
|
||||||
#else
|
#else
|
||||||
throw_invalid_handle();
|
throw_invalid_handle();
|
||||||
#endif
|
#endif
|
||||||
TORRENT_ASSERT(m_chk);
|
|
||||||
|
|
||||||
session_impl::mutex_t::scoped_lock l(m_ses->m_mutex);
|
session_impl::mutex_t::scoped_lock l(m_ses->m_mutex);
|
||||||
mutex::scoped_lock l2(m_chk->m_mutex);
|
boost::shared_ptr<torrent> t = m_ses->find_torrent(m_info_hash).lock();
|
||||||
|
|
||||||
torrent* t = find_torrent(m_ses, m_chk, m_info_hash);
|
|
||||||
if (!t || !t->valid_metadata())
|
if (!t || !t->valid_metadata())
|
||||||
#ifdef BOOST_NO_EXCEPTIONS
|
#ifdef BOOST_NO_EXCEPTIONS
|
||||||
return entry();
|
return entry();
|
||||||
|
@ -518,7 +462,9 @@ namespace libtorrent
|
||||||
ret["file-format"] = "libtorrent resume file";
|
ret["file-format"] = "libtorrent resume file";
|
||||||
ret["file-version"] = 1;
|
ret["file-version"] = 1;
|
||||||
|
|
||||||
ret["allocation"] = t->filesystem().compact_allocation()?"compact":"full";
|
storage_mode_t sm = t->storage_mode();
|
||||||
|
ret["allocation"] = sm == storage_mode_sparse?"sparse"
|
||||||
|
:sm == storage_mode_allocate?"full":"compact";
|
||||||
|
|
||||||
const sha1_hash& info_hash = t->torrent_file().info_hash();
|
const sha1_hash& info_hash = t->torrent_file().info_hash();
|
||||||
ret["info-hash"] = std::string((char*)info_hash.begin(), (char*)info_hash.end());
|
ret["info-hash"] = std::string((char*)info_hash.begin(), (char*)info_hash.end());
|
||||||
|
@ -569,25 +515,13 @@ namespace libtorrent
|
||||||
TORRENT_ASSERT(bits == 8 || j == num_bitmask_bytes - 1);
|
TORRENT_ASSERT(bits == 8 || j == num_bitmask_bytes - 1);
|
||||||
}
|
}
|
||||||
piece_struct["bitmask"] = bitmask;
|
piece_struct["bitmask"] = bitmask;
|
||||||
/*
|
|
||||||
TORRENT_ASSERT(t->filesystem().slot_for(i->index) >= 0);
|
|
||||||
unsigned long adler
|
|
||||||
= t->filesystem().piece_crc(
|
|
||||||
t->filesystem().slot_for(i->index)
|
|
||||||
, t->block_size()
|
|
||||||
, i->info);
|
|
||||||
|
|
||||||
piece_struct["adler32"] = adler;
|
|
||||||
*/
|
|
||||||
// push the struct onto the unfinished-piece list
|
// push the struct onto the unfinished-piece list
|
||||||
up.push_back(piece_struct);
|
up.push_back(piece_struct);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<int> piece_index;
|
std::vector<int> piece_index;
|
||||||
t->filesystem().export_piece_map(piece_index, have_pieces);
|
t->filesystem().write_resume_data(ret, have_pieces);
|
||||||
entry::list_type& slots = ret["slots"].list();
|
|
||||||
std::copy(piece_index.begin(), piece_index.end(), std::back_inserter(slots));
|
|
||||||
|
|
||||||
// write local peers
|
// write local peers
|
||||||
|
|
||||||
|
@ -632,8 +566,6 @@ namespace libtorrent
|
||||||
peer_list.push_back(peer);
|
peer_list.push_back(peer);
|
||||||
}
|
}
|
||||||
|
|
||||||
t->filesystem().write_resume_data(ret);
|
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -654,27 +586,16 @@ namespace libtorrent
|
||||||
#else
|
#else
|
||||||
throw_invalid_handle();
|
throw_invalid_handle();
|
||||||
#endif
|
#endif
|
||||||
TORRENT_ASSERT(m_chk);
|
|
||||||
|
|
||||||
session_impl::mutex_t::scoped_lock l(m_ses->m_mutex);
|
session_impl::mutex_t::scoped_lock l(m_ses->m_mutex);
|
||||||
boost::shared_ptr<torrent> t = m_ses->find_torrent(m_info_hash).lock();
|
boost::shared_ptr<torrent> t = m_ses->find_torrent(m_info_hash).lock();
|
||||||
|
|
||||||
if (!t)
|
if (!t)
|
||||||
{
|
{
|
||||||
// the torrent is being checked. Add the peer to its
|
|
||||||
// peer list. The entries in there will be connected
|
|
||||||
// once the checking is complete.
|
|
||||||
mutex::scoped_lock l2(m_chk->m_mutex);
|
|
||||||
|
|
||||||
aux::piece_checker_data* d = m_chk->find_torrent(m_info_hash);
|
|
||||||
if (d == 0)
|
|
||||||
#ifdef BOOST_NO_EXCEPTIONS
|
#ifdef BOOST_NO_EXCEPTIONS
|
||||||
return;
|
|
||||||
#else
|
|
||||||
throw_invalid_handle();
|
|
||||||
#endif
|
|
||||||
d->peers.push_back(adr);
|
|
||||||
return;
|
return;
|
||||||
|
#else
|
||||||
|
throw_invalid_handle();
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
peer_id id;
|
peer_id id;
|
||||||
|
|
Loading…
Reference in New Issue