added add_piece() to inject data from external sources

This commit is contained in:
Arvid Norberg 2008-12-07 21:04:19 +00:00
parent 3b7e484d6a
commit 14c142d997
7 changed files with 123 additions and 0 deletions

View File

@ -1,4 +1,5 @@
* added add_piece() function to inject data from external sources
* add_tracker() function added to torrent_handle
* if there is no working tracker, current_tracker is the
tracker that is currently being tried

View File

@ -1717,6 +1717,9 @@ Its declaration looks like this::
void rename_file(int index, boost::filesystem::wpath) 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;
bool operator==(torrent_handle const&) const;
@ -1868,6 +1871,27 @@ get_storage_impl()
Returns the storage implementation for this torrent. This depends on the
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()
------------------

View File

@ -169,6 +169,11 @@ namespace libtorrent
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_interface* get_storage()
{

View File

@ -314,6 +314,9 @@ namespace libtorrent
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_peer_info(std::vector<peer_info>& v) const;
torrent_status status() const;

View File

@ -370,6 +370,71 @@ namespace libtorrent
if (!m_connections.empty())
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)
{

View File

@ -535,6 +535,12 @@ namespace libtorrent
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
{
INVARIANT_CHECK;

View File

@ -49,11 +49,28 @@ void test_running_torrent(boost::intrusive_ptr<torrent_info> info, size_type fil
TEST_CHECK(st.total_wanted == file_size);
std::cout << "total_wanted_done: " << st.total_wanted_done << " : 0" << std::endl;
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()
{
{
remove("test_torrent_dir2/tmp1");
remove("test_torrent_dir2/tmp2");
remove("test_torrent_dir2/tmp3");
file_storage fs;
size_type file_size = 1 * 1024 * 1024 * 1024;
fs.add_file("test_torrent_dir2/tmp1", file_size);
@ -69,6 +86,7 @@ int test_main()
// calculate the hash for all pieces
sha1_hash ph = hasher(&piece[0], piece.size()).final();
int num = t.num_pieces();
TEST_CHECK(t.num_pieces() > 0);
for (int i = 0; i < num; ++i)
t.set_hash(i, ph);
@ -76,6 +94,7 @@ int test_main()
std::back_insert_iterator<std::vector<char> > out(tmp);
bencode(out, t.generate());
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);
}