added add_piece() to inject data from external sources
This commit is contained in:
parent
3b7e484d6a
commit
14c142d997
|
@ -1,4 +1,5 @@
|
||||||
|
|
||||||
|
* added add_piece() function to inject data from external sources
|
||||||
* add_tracker() function added to torrent_handle
|
* add_tracker() function added to torrent_handle
|
||||||
* if there is no working tracker, current_tracker is the
|
* if there is no working tracker, current_tracker is the
|
||||||
tracker that is currently being tried
|
tracker that is currently being tried
|
||||||
|
|
|
@ -1717,6 +1717,9 @@ Its declaration looks like this::
|
||||||
void rename_file(int index, boost::filesystem::wpath) const;
|
void rename_file(int index, boost::filesystem::wpath) const;
|
||||||
storage_interface* get_storage_impl() const;
|
storage_interface* get_storage_impl() const;
|
||||||
|
|
||||||
|
enum flags_t { overwrite_existing = 1 };
|
||||||
|
void add_piece(int piece, char const* data, int flags = 0) const;
|
||||||
|
|
||||||
sha1_hash info_hash() const;
|
sha1_hash info_hash() const;
|
||||||
|
|
||||||
bool operator==(torrent_handle const&) const;
|
bool operator==(torrent_handle const&) const;
|
||||||
|
@ -1868,6 +1871,27 @@ get_storage_impl()
|
||||||
Returns the storage implementation for this torrent. This depends on the
|
Returns the storage implementation for this torrent. This depends on the
|
||||||
storage contructor function that was passed to ``session::add_torrent``.
|
storage contructor function that was passed to ``session::add_torrent``.
|
||||||
|
|
||||||
|
add_piece()
|
||||||
|
-----------
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
enum flags_t { overwrite_existing = 1 };
|
||||||
|
void add_piece(int piece, char const* data, int flags = 0) const;
|
||||||
|
|
||||||
|
This function will write ``data`` to the storage as piece ``piece``, as if it had
|
||||||
|
been downloaded from a peer. ``data`` is expected to point to a buffer of as many
|
||||||
|
bytes as the size of the specified piece. The data in the buffer is copied and
|
||||||
|
passed on to the disk IO thread to be written at a later point.
|
||||||
|
|
||||||
|
By default, data that's already been downloaded is not overwritten by this buffer. If
|
||||||
|
you trust this data to be correct (and pass the piece hash check) you may pass the
|
||||||
|
``overwrite_existing`` flag. This will instruct libtorrent to overwrite any data that
|
||||||
|
may already have been downloaded with this data.
|
||||||
|
|
||||||
|
Since the data is written asynchronously, you may know that is passed or failed the
|
||||||
|
hash check by waiting for ``piece_finished_alert`` or ``has_failed_alert``.
|
||||||
|
|
||||||
force_reannounce()
|
force_reannounce()
|
||||||
------------------
|
------------------
|
||||||
|
|
||||||
|
|
|
@ -169,6 +169,11 @@ namespace libtorrent
|
||||||
|
|
||||||
int seed_rank(session_settings const& s) const;
|
int seed_rank(session_settings const& s) const;
|
||||||
|
|
||||||
|
enum flags_t { overwrite_existing = 1 };
|
||||||
|
void add_piece(int piece, char const* data, int flags = 0);
|
||||||
|
void on_disk_write_complete(int ret, disk_io_job const& j
|
||||||
|
, peer_request p);
|
||||||
|
|
||||||
storage_mode_t storage_mode() const { return m_storage_mode; }
|
storage_mode_t storage_mode() const { return m_storage_mode; }
|
||||||
storage_interface* get_storage()
|
storage_interface* get_storage()
|
||||||
{
|
{
|
||||||
|
|
|
@ -314,6 +314,9 @@ namespace libtorrent
|
||||||
|
|
||||||
torrent_handle() {}
|
torrent_handle() {}
|
||||||
|
|
||||||
|
enum flags_t { overwrite_existing = 1 };
|
||||||
|
void add_piece(int piece, char const* data, int flags = 0) const;
|
||||||
|
|
||||||
void get_full_peer_list(std::vector<peer_list_entry>& v) const;
|
void get_full_peer_list(std::vector<peer_list_entry>& v) const;
|
||||||
void get_peer_info(std::vector<peer_info>& v) const;
|
void get_peer_info(std::vector<peer_info>& v) const;
|
||||||
torrent_status status() const;
|
torrent_status status() const;
|
||||||
|
|
|
@ -370,6 +370,71 @@ namespace libtorrent
|
||||||
if (!m_connections.empty())
|
if (!m_connections.empty())
|
||||||
disconnect_all();
|
disconnect_all();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void torrent::add_piece(int piece, char const* data, int flags)
|
||||||
|
{
|
||||||
|
TORRENT_ASSERT(piece >= 0 && piece < m_torrent_file->num_pieces());
|
||||||
|
int piece_size = m_torrent_file->piece_size(piece);
|
||||||
|
int blocks_in_piece = (piece_size + m_block_size - 1) / m_block_size;
|
||||||
|
|
||||||
|
peer_request p;
|
||||||
|
p.piece = piece;
|
||||||
|
p.start = 0;
|
||||||
|
picker().inc_refcount(piece);
|
||||||
|
for (int i = 0; i < blocks_in_piece; ++i, p.start += m_block_size)
|
||||||
|
{
|
||||||
|
if (picker().is_finished(piece_block(piece, i))
|
||||||
|
&& (flags & torrent::overwrite_existing) == 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
p.length = (std::min)(piece_size - p.start, m_block_size);
|
||||||
|
char* buffer = m_ses.allocate_disk_buffer();
|
||||||
|
// out of memory
|
||||||
|
if (buffer == 0) return;
|
||||||
|
disk_buffer_holder holder(m_ses, buffer);
|
||||||
|
std::memcpy(buffer, data + p.start, p.length);
|
||||||
|
filesystem().async_write(p, holder, bind(&torrent::on_disk_write_complete
|
||||||
|
, shared_from_this(), _1, _2, p));
|
||||||
|
piece_block block(piece, i);
|
||||||
|
picker().mark_as_downloading(block, 0, piece_picker::fast);
|
||||||
|
picker().mark_as_writing(block, 0);
|
||||||
|
}
|
||||||
|
picker().dec_refcount(piece);
|
||||||
|
}
|
||||||
|
|
||||||
|
void torrent::on_disk_write_complete(int ret, disk_io_job const& j
|
||||||
|
, peer_request p)
|
||||||
|
{
|
||||||
|
session_impl::mutex_t::scoped_lock l(m_ses.m_mutex);
|
||||||
|
|
||||||
|
INVARIANT_CHECK;
|
||||||
|
|
||||||
|
if (m_abort)
|
||||||
|
{
|
||||||
|
piece_block block_finished(p.piece, p.start / m_block_size);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
piece_block block_finished(p.piece, p.start / m_block_size);
|
||||||
|
|
||||||
|
if (ret == -1)
|
||||||
|
{
|
||||||
|
if (has_picker()) picker().write_failed(block_finished);
|
||||||
|
if (alerts().should_post<file_error_alert>())
|
||||||
|
alerts().post_alert(file_error_alert(j.error_file, get_handle(), j.str));
|
||||||
|
set_error(j.str);
|
||||||
|
pause();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
picker().mark_as_finished(block_finished, 0);
|
||||||
|
|
||||||
|
// did we just finish the piece?
|
||||||
|
if (picker().is_piece_finished(p.piece))
|
||||||
|
{
|
||||||
|
async_verify_piece(p.piece, bind(&torrent::piece_finished, shared_from_this()
|
||||||
|
, p.piece, _1));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
peer_request torrent::to_req(piece_block const& p)
|
peer_request torrent::to_req(piece_block const& p)
|
||||||
{
|
{
|
||||||
|
|
|
@ -535,6 +535,12 @@ namespace libtorrent
|
||||||
TORRENT_FORWARD(add_tracker(url));
|
TORRENT_FORWARD(add_tracker(url));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void torrent_handle::add_piece(int piece, char const* data, int flags) const
|
||||||
|
{
|
||||||
|
INVARIANT_CHECK;
|
||||||
|
TORRENT_FORWARD(add_piece(piece, data, flags));
|
||||||
|
}
|
||||||
|
|
||||||
storage_interface* torrent_handle::get_storage_impl() const
|
storage_interface* torrent_handle::get_storage_impl() const
|
||||||
{
|
{
|
||||||
INVARIANT_CHECK;
|
INVARIANT_CHECK;
|
||||||
|
|
|
@ -49,11 +49,28 @@ void test_running_torrent(boost::intrusive_ptr<torrent_info> info, size_type fil
|
||||||
TEST_CHECK(st.total_wanted == file_size);
|
TEST_CHECK(st.total_wanted == file_size);
|
||||||
std::cout << "total_wanted_done: " << st.total_wanted_done << " : 0" << std::endl;
|
std::cout << "total_wanted_done: " << st.total_wanted_done << " : 0" << std::endl;
|
||||||
TEST_CHECK(st.total_wanted_done == 0);
|
TEST_CHECK(st.total_wanted_done == 0);
|
||||||
|
|
||||||
|
if (info->num_pieces() > 0)
|
||||||
|
{
|
||||||
|
h.piece_priority(0, 1);
|
||||||
|
st = h.status();
|
||||||
|
TEST_CHECK(st.pieces[0] == false);
|
||||||
|
std::vector<char> piece(info->piece_length());
|
||||||
|
for (int i = 0; i < int(piece.size()); ++i)
|
||||||
|
piece[i] = (i % 26) + 'A';
|
||||||
|
h.add_piece(0, &piece[0]);
|
||||||
|
test_sleep(10000);
|
||||||
|
st = h.status();
|
||||||
|
TEST_CHECK(st.pieces[0] == true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int test_main()
|
int test_main()
|
||||||
{
|
{
|
||||||
{
|
{
|
||||||
|
remove("test_torrent_dir2/tmp1");
|
||||||
|
remove("test_torrent_dir2/tmp2");
|
||||||
|
remove("test_torrent_dir2/tmp3");
|
||||||
file_storage fs;
|
file_storage fs;
|
||||||
size_type file_size = 1 * 1024 * 1024 * 1024;
|
size_type file_size = 1 * 1024 * 1024 * 1024;
|
||||||
fs.add_file("test_torrent_dir2/tmp1", file_size);
|
fs.add_file("test_torrent_dir2/tmp1", file_size);
|
||||||
|
@ -69,6 +86,7 @@ int test_main()
|
||||||
// calculate the hash for all pieces
|
// calculate the hash for all pieces
|
||||||
sha1_hash ph = hasher(&piece[0], piece.size()).final();
|
sha1_hash ph = hasher(&piece[0], piece.size()).final();
|
||||||
int num = t.num_pieces();
|
int num = t.num_pieces();
|
||||||
|
TEST_CHECK(t.num_pieces() > 0);
|
||||||
for (int i = 0; i < num; ++i)
|
for (int i = 0; i < num; ++i)
|
||||||
t.set_hash(i, ph);
|
t.set_hash(i, ph);
|
||||||
|
|
||||||
|
@ -76,6 +94,7 @@ int test_main()
|
||||||
std::back_insert_iterator<std::vector<char> > out(tmp);
|
std::back_insert_iterator<std::vector<char> > out(tmp);
|
||||||
bencode(out, t.generate());
|
bencode(out, t.generate());
|
||||||
boost::intrusive_ptr<torrent_info> info(new torrent_info(&tmp[0], tmp.size()));
|
boost::intrusive_ptr<torrent_info> info(new torrent_info(&tmp[0], tmp.size()));
|
||||||
|
TEST_CHECK(info->num_pieces() > 0);
|
||||||
|
|
||||||
test_running_torrent(info, file_size);
|
test_running_torrent(info, file_size);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue