improve support for merkle tree torrent creation
This commit is contained in:
parent
fbd7d49d7e
commit
7817229f5d
|
@ -87,6 +87,7 @@
|
|||
incoming connection
|
||||
* added more detailed instrumentation of the disk I/O thread
|
||||
|
||||
* improve support for merkle tree torrent creation
|
||||
* exposed comparison operators on torrent_handle to python
|
||||
* exposed alert error_codes to python
|
||||
* fixed bug in announce_entry::next_announce_in and min_announce_in
|
||||
|
|
|
@ -341,6 +341,9 @@ merkle
|
|||
The benefit is that the resulting torrent file will be much smaller and
|
||||
not grow with more pieces. When this option is specified, it is
|
||||
recommended to have a fairly small piece size, say 64 kiB.
|
||||
When creating merkle torrents, the full hash tree is also generated
|
||||
and should be saved off separately. It is accessed through the
|
||||
``merkle_tree()`` function.
|
||||
|
||||
modification_time
|
||||
This will include the file modification time as part of the torrent.
|
||||
|
@ -488,3 +491,19 @@ set_priv() priv()
|
|||
|
||||
Sets and queries the private flag of the torrent.
|
||||
|
||||
merkle_tree()
|
||||
-------------
|
||||
|
||||
::
|
||||
|
||||
std::vector<sha1_hash> const& merkle_tree() const;
|
||||
|
||||
This function returns the merkle hash tree, if the torrent was created as a merkle
|
||||
torrent. The tree is created by ``generate()`` and won't be valid until that function
|
||||
has been called. When creating a merkle tree torrent, the actual tree itself has to
|
||||
be saved off separately and fed into libtorrent the first time you start seeding it,
|
||||
through the ``torrent_info::set_merkle_tree()`` function. From that point onwards, the
|
||||
tree will be saved in the resume data.
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -1666,6 +1666,9 @@ The ``torrent_info`` has the following synopsis::
|
|||
sha1_hash const& hash_for_piece(unsigned int index) const;
|
||||
char const* hash_for_piece_ptr(unsigned int index) const;
|
||||
|
||||
std::vector<sha1_hash> const& merkle_tree() const;
|
||||
void set_merkle_tree(std::vector<sha1_hash>& h);
|
||||
|
||||
boost::shared_array<char> metadata() const;
|
||||
int metadata_size() const;
|
||||
};
|
||||
|
@ -2079,6 +2082,23 @@ torrent file. For more information on the ``sha1_hash``, see the big_number_ cla
|
|||
``hash_for_piece_ptr()`` returns a pointer to the 20 byte sha1 digest for the piece.
|
||||
Note that the string is not null-terminated.
|
||||
|
||||
merkle_tree() set_merkle_tree()
|
||||
-------------------------------
|
||||
|
||||
::
|
||||
|
||||
std::vector<sha1_hash> const& merkle_tree() const;
|
||||
void set_merkle_tree(std::vector<sha1_hash>& h);
|
||||
|
||||
``merkle_tree()`` returns a reference to the merkle tree for this torrent, if any.
|
||||
|
||||
``set_merkle_tree()`` moves the passed in merkle tree into the torrent_info object.
|
||||
i.e. ``h`` will not be identical after the call. You need to set the merkle tree for
|
||||
a torrent that you've just created (as a merkle torrent). The merkle tree is retrieved
|
||||
from the ``create_torrent::merkle_tree()`` function, and need to be saved separately
|
||||
from the torrent file itself. Once it's added to libtorrent, the merkle tree will be
|
||||
persisted in the resume data.
|
||||
|
||||
|
||||
name() comment() creation_date() creator()
|
||||
------------------------------------------
|
||||
|
|
|
@ -64,8 +64,10 @@ void print_usage()
|
|||
"Generates a torrent file from the specified file\n"
|
||||
"or directory and writes it to standard out\n\n"
|
||||
"OPTIONS:\n"
|
||||
"-m generate a merkle hash tree torrent.\n"
|
||||
"-m file generate a merkle hash tree torrent.\n"
|
||||
" merkle torrents require client support\n"
|
||||
" the resulting full merkle tree is written to\n"
|
||||
" the specified file\n"
|
||||
"-f include sha-1 file hashes in the torrent\n"
|
||||
" this helps supporting mixing sources from\n"
|
||||
" other networks\n"
|
||||
|
@ -109,6 +111,7 @@ int main(int argc, char* argv[])
|
|||
int flags = 0;
|
||||
|
||||
std::string outfile;
|
||||
std::string merklefile;
|
||||
#ifdef TORRENT_WINDOWS
|
||||
// don't ever write binary data to the console on windows
|
||||
// it will just be interpreted as text and corrupted
|
||||
|
@ -143,6 +146,8 @@ int main(int argc, char* argv[])
|
|||
piece_size = atoi(argv[i]);
|
||||
break;
|
||||
case 'm':
|
||||
++i;
|
||||
merklefile = argv[i];
|
||||
flags |= create_torrent::merkle;
|
||||
break;
|
||||
case 'o':
|
||||
|
@ -204,6 +209,18 @@ int main(int argc, char* argv[])
|
|||
if (output != stdout)
|
||||
fclose(output);
|
||||
|
||||
if (!merklefile.empty())
|
||||
{
|
||||
output = fopen(merklefile.c_str(), "wb+");
|
||||
int ret = fwrite(&t.merkle_tree()[0], 1, t.merkle_tree().size(), output);
|
||||
if (ret != t.merkle_tree().size())
|
||||
{
|
||||
fprintf(stderr, "failed to write %s: (%d) %s\n"
|
||||
, merklefile.c_str(), errno, strerror(errno));
|
||||
}
|
||||
fclose(output);
|
||||
}
|
||||
|
||||
#ifndef BOOST_NO_EXCEPTIONS
|
||||
}
|
||||
catch (std::exception& e)
|
||||
|
|
|
@ -97,6 +97,7 @@ namespace libtorrent
|
|||
bool priv() const { return m_private; }
|
||||
|
||||
bool should_add_file_hashes() const { return m_calculate_file_hashes; }
|
||||
std::vector<sha1_hash> const& merkle_tree() const { return m_merkle_tree; }
|
||||
|
||||
private:
|
||||
|
||||
|
@ -117,6 +118,11 @@ namespace libtorrent
|
|||
|
||||
std::vector<sha1_hash> m_filehashes;
|
||||
|
||||
// if we're generating a merkle torrent, this is the
|
||||
// merkle tree we got. This should be saved in fast-resume
|
||||
// in order to start seeding the torrent
|
||||
mutable std::vector<sha1_hash> m_merkle_tree;
|
||||
|
||||
// dht nodes to add to the routing table/bootstrap from
|
||||
typedef std::vector<std::pair<std::string, int> > nodes_t;
|
||||
nodes_t m_nodes;
|
||||
|
|
|
@ -387,18 +387,16 @@ namespace libtorrent
|
|||
info["piece length"] = m_files.piece_length();
|
||||
if (m_merkle_torrent)
|
||||
{
|
||||
std::vector<sha1_hash> merkle_tree;
|
||||
|
||||
int num_leafs = merkle_num_leafs(m_files.num_pieces());
|
||||
int num_nodes = merkle_num_nodes(num_leafs);
|
||||
int first_leaf = num_nodes - num_leafs;
|
||||
merkle_tree.resize(num_nodes);
|
||||
m_merkle_tree.resize(num_nodes);
|
||||
int num_pieces = m_piece_hash.size();
|
||||
for (int i = 0; i < num_pieces; ++i)
|
||||
merkle_tree[first_leaf + i] = m_piece_hash[i];
|
||||
m_merkle_tree[first_leaf + i] = m_piece_hash[i];
|
||||
sha1_hash filler(0);
|
||||
for (int i = num_pieces; i < num_leafs; ++i)
|
||||
merkle_tree[first_leaf + i] = filler;
|
||||
m_merkle_tree[first_leaf + i] = filler;
|
||||
|
||||
// now that we have initialized all leaves, build
|
||||
// each level bottom-up
|
||||
|
@ -410,16 +408,16 @@ namespace libtorrent
|
|||
for (int i = level_start; i < level_start + level_size; i += 2, ++parent)
|
||||
{
|
||||
hasher h;
|
||||
h.update((char const*)&merkle_tree[i][0], 20);
|
||||
h.update((char const*)&merkle_tree[i+1][0], 20);
|
||||
merkle_tree[parent] = h.final();
|
||||
h.update((char const*)&m_merkle_tree[i][0], 20);
|
||||
h.update((char const*)&m_merkle_tree[i+1][0], 20);
|
||||
m_merkle_tree[parent] = h.final();
|
||||
}
|
||||
level_start = merkle_get_parent(level_start);
|
||||
level_size /= 2;
|
||||
}
|
||||
TORRENT_ASSERT(level_size == 1);
|
||||
std::string& p = info["root hash"].string();
|
||||
p.assign((char const*)&merkle_tree[0][0], 20);
|
||||
p.assign((char const*)&m_merkle_tree[0][0], 20);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
Loading…
Reference in New Issue