forked from premiere/premiere-libtorrent
factored out torrent creation functionality from torrent_info into create_torrent. Modified torrent_info to use lazy_bdecoder for increased performance
This commit is contained in:
parent
a954240aa9
commit
8ed949c4d5
1
Jamfile
1
Jamfile
|
@ -257,6 +257,7 @@ SOURCES =
|
|||
alert
|
||||
assert
|
||||
connection_queue
|
||||
create_torrent
|
||||
disk_buffer_holder
|
||||
entry
|
||||
lazy_bdecode
|
||||
|
|
104
docs/manual.rst
104
docs/manual.rst
|
@ -1091,14 +1091,7 @@ The ``torrent_info`` has the following synopsis::
|
|||
torrent_info(entry const& torrent_file);
|
||||
torrent_info(char const* filename);
|
||||
|
||||
entry create_torrent() const;
|
||||
void set_comment(char const* str);
|
||||
void set_piece_size(int size);
|
||||
void set_creator(char const* str);
|
||||
void set_hash(int index, sha1_hash const& h);
|
||||
void add_tracker(std::string const& url, int tier = 0);
|
||||
void add_file(boost::filesystem::path file, size_type size);
|
||||
void add_url_seed(std::string const& url);
|
||||
|
||||
typedef std::vector<file_entry>::const_iterator file_iterator;
|
||||
typedef std::vector<file_entry>::const_reverse_iterator
|
||||
|
@ -1122,7 +1115,6 @@ The ``torrent_info`` has the following synopsis::
|
|||
std::vector<announce_entry> const& trackers() const;
|
||||
|
||||
bool priv() const;
|
||||
void set_priv(bool v);
|
||||
|
||||
std::vector<std::string> const& url_seeds() const;
|
||||
|
||||
|
@ -1144,6 +1136,10 @@ The ``torrent_info`` has the following synopsis::
|
|||
|
||||
int piece_size(unsigned int index) const;
|
||||
sha1_hash const& hash_for_piece(unsigned int index) const;
|
||||
char const* hash_for_piece_ptr(unsigned int index) const;
|
||||
|
||||
boost::shared_array<char> metadata() const;
|
||||
int metadata_size() const;
|
||||
};
|
||||
|
||||
torrent_info()
|
||||
|
@ -1178,66 +1174,16 @@ the constructor, for convenience. This might not be the most suitable for applic
|
|||
want to be able to report detailed errors on what might go wrong.
|
||||
|
||||
|
||||
set_comment() set_piece_size() set_creator() set_hash() add_tracker() add_file()
|
||||
--------------------------------------------------------------------------------
|
||||
add_tracker()
|
||||
-------------
|
||||
|
||||
::
|
||||
|
||||
void set_comment(char const* str);
|
||||
void set_piece_size(int size);
|
||||
void set_creator(char const* str);
|
||||
void set_hash(int index, sha1_hash const& h);
|
||||
void add_tracker(std::string const& url, int tier = 0);
|
||||
void add_file(boost::filesystem::path file, size_type size);
|
||||
|
||||
These files are used when creating a torrent file. ``set_comment()`` will simply set
|
||||
the comment that belongs to this torrent. The comment can be retrieved with the
|
||||
``comment()`` member. The string should be UTF-8 encoded.
|
||||
|
||||
``set_piece_size()`` will set the size of each piece in this torrent. The piece size must
|
||||
be an even multiple of 2. i.e. usually something like 256 kiB, 512 kiB, 1024 kiB etc. The
|
||||
size is given in number of bytes.
|
||||
|
||||
``set_creator()`` is an optional attribute that can be used to identify your application
|
||||
that was used to create the torrent file. The string should be UTF-8 encoded.
|
||||
|
||||
``set_hash()`` writes the hash for the piece with the given piece-index. You have to call
|
||||
this function for every piece in the torrent. Usually the hasher_ is used to calculate
|
||||
the sha1-hash for a piece.
|
||||
|
||||
``add_tracker()`` adds a tracker to the announce-list. The ``tier`` determines the order in
|
||||
which the trackers are to be tried. For more information see `trackers()`_.
|
||||
|
||||
``add_file()`` adds a file to the torrent. The order in which you add files will determine
|
||||
the order in which they are placed in the torrent file. You have to add at least one file
|
||||
to the torrent. The ``path`` you give has to be a relative path from the root directory
|
||||
of the torrent. The ``size`` is given in bytes.
|
||||
|
||||
When you have added all the files and hashes to your torrent, you can generate an ``entry``
|
||||
which then can be encoded as a .torrent file. You do this by calling `create_torrent()`_.
|
||||
|
||||
For a complete example of how to create a torrent from a file structure, see make_torrent_.
|
||||
|
||||
|
||||
create_torrent()
|
||||
----------------
|
||||
|
||||
::
|
||||
|
||||
entry create_torrent();
|
||||
|
||||
Returns an ``entry`` representing the bencoded tree of data that makes up a .torrent file.
|
||||
You can save this data as a torrent file with bencode() (see `bdecode() bencode()`_), for a
|
||||
complete example, see make_torrent_.
|
||||
|
||||
.. _make_torrent: examples.html#make_torrent
|
||||
|
||||
This function is not const because it will also set the info-hash of the ``torrent_info``
|
||||
object.
|
||||
|
||||
Note that a torrent file must include at least one file, and it must have at
|
||||
least one tracker url or at least one DHT node.
|
||||
|
||||
|
||||
remap_files()
|
||||
-------------
|
||||
|
@ -1425,18 +1371,6 @@ remapped, they may differ. For more info, see `remap_files()`_.
|
|||
See `HTTP seeding`_ for more information.
|
||||
|
||||
|
||||
print()
|
||||
-------
|
||||
|
||||
::
|
||||
|
||||
void print(std::ostream& os) const;
|
||||
|
||||
The ``print()`` function is there for debug purposes only. It will print the info from
|
||||
the torrent file to the given outstream. This function has been deprecated and will
|
||||
be removed from future releases.
|
||||
|
||||
|
||||
trackers()
|
||||
----------
|
||||
|
||||
|
@ -1479,17 +1413,21 @@ be the same as ``piece_length()`` except in the case of the last piece, which ma
|
|||
be smaller.
|
||||
|
||||
|
||||
hash_for_piece() info_hash()
|
||||
----------------------------
|
||||
hash_for_piece() hash_for_piece_ptr() info_hash()
|
||||
-------------------------------------------------
|
||||
|
||||
::
|
||||
|
||||
size_type piece_size(unsigned int index) const;
|
||||
sha1_hash const& hash_for_piece(unsigned int index) const;
|
||||
char const* hash_for_piece_ptr(unsigned int index) const;
|
||||
|
||||
``hash_for_piece()`` takes a piece-index and returns the 20-bytes sha1-hash for that
|
||||
piece and ``info_hash()`` returns the 20-bytes sha1-hash for the info-section of the
|
||||
torrent file. For more information on the ``sha1_hash``, see the big_number_ class.
|
||||
``hash_for_piece_ptr()`` returns a pointer to the 20 byte sha1 digest for the piece.
|
||||
Note that the string is not null-terminated.
|
||||
|
||||
``info_hash()`` will only return a valid hash if the torrent_info was read from a
|
||||
``.torrent`` file or if an ``entry`` was created from it (through ``create_torrent``).
|
||||
|
||||
|
@ -1518,19 +1456,16 @@ it will return an empty string.
|
|||
__ http://www.boost.org/doc/html/date_time/posix_time.html#date_time.posix_time.ptime_class
|
||||
|
||||
|
||||
priv() set_priv()
|
||||
-----------------
|
||||
priv()
|
||||
------
|
||||
|
||||
::
|
||||
|
||||
bool priv() const;
|
||||
void set_priv(bool v);
|
||||
|
||||
``priv()`` returns true if this torrent is private. i.e., it should not be
|
||||
distributed on the trackerless network (the kademlia DHT).
|
||||
|
||||
``set_priv()`` sets or clears the private flag on this torrent.
|
||||
|
||||
|
||||
nodes()
|
||||
-------
|
||||
|
@ -1543,15 +1478,16 @@ If this torrent contains any DHT nodes, they are put in this vector in their ori
|
|||
form (host name and port number).
|
||||
|
||||
|
||||
add_node()
|
||||
----------
|
||||
metadata() metadata_size()
|
||||
--------------------------
|
||||
|
||||
::
|
||||
|
||||
void add_node(std::pair<std::string, int> const& node);
|
||||
boost::shared_array<char> metadata() const;
|
||||
int metadata_size() const;
|
||||
|
||||
This is used when creating torrent. Use this to add a known DHT node. It may
|
||||
be used, by the client, to bootstrap into the DHT network.
|
||||
``metadata()`` returns a the raw info section of the torrent file. The size
|
||||
of the metadata is returned by ``metadata_size()``.
|
||||
|
||||
|
||||
torrent_handle
|
||||
|
|
|
@ -38,11 +38,14 @@ POSSIBILITY OF SUCH DAMAGE.
|
|||
#include "libtorrent/entry.hpp"
|
||||
#include "libtorrent/bencode.hpp"
|
||||
#include "libtorrent/torrent_info.hpp"
|
||||
#include "libtorrent/lazy_entry.hpp"
|
||||
#include <boost/filesystem/operations.hpp>
|
||||
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
using namespace libtorrent;
|
||||
using namespace boost::filesystem;
|
||||
|
||||
if (argc != 2)
|
||||
{
|
||||
|
@ -57,15 +60,29 @@ int main(int argc, char* argv[])
|
|||
try
|
||||
{
|
||||
#endif
|
||||
std::ifstream in(argv[1], std::ios_base::binary);
|
||||
in.unsetf(std::ios_base::skipws);
|
||||
entry e = bdecode(std::istream_iterator<char>(in), std::istream_iterator<char>());
|
||||
|
||||
int size = file_size(argv[1]);
|
||||
if (size > 10 * 1000000)
|
||||
{
|
||||
std::cerr << "file too big (" << size << "), aborting\n";
|
||||
return 1;
|
||||
}
|
||||
std::vector<char> buf(size);
|
||||
std::ifstream(argv[1], std::ios_base::binary).read(&buf[0], size);
|
||||
lazy_entry e;
|
||||
int ret = lazy_bdecode(&buf[0], &buf[0] + buf.size(), e);
|
||||
|
||||
if (ret != 0)
|
||||
{
|
||||
std::cerr << "invalid bencoding: " << ret << std::endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
std::cout << "\n\n----- raw info -----\n\n";
|
||||
e.print(std::cout);
|
||||
|
||||
torrent_info t(e);
|
||||
std::cout << e << std::endl;
|
||||
|
||||
torrent_info t(e);
|
||||
|
||||
// print info about torrent
|
||||
std::cout << "\n\n----- torrent file info -----\n\n";
|
||||
std::cout << "nodes:\n";
|
||||
|
@ -99,7 +116,7 @@ int main(int argc, char* argv[])
|
|||
<< " " << i->path.string() << "[ " << first << ", "
|
||||
<< last << " ]\n";
|
||||
}
|
||||
|
||||
|
||||
#ifndef BOOST_NO_EXCEPTIONS
|
||||
}
|
||||
catch (std::exception& e)
|
||||
|
|
|
@ -8,6 +8,7 @@ libtorrent/bencode.hpp \
|
|||
libtorrent/broadcast_socket.hpp \
|
||||
libtorrent/buffer.hpp \
|
||||
libtorrent/connection_queue.hpp \
|
||||
libtorrent/create_torrent.hpp \
|
||||
libtorrent/config.hpp \
|
||||
libtorrent/debug.hpp \
|
||||
libtorrent/disk_buffer_holder.hpp \
|
||||
|
|
|
@ -0,0 +1,140 @@
|
|||
/*
|
||||
|
||||
Copyright (c) 2008, Arvid Norberg
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in
|
||||
the documentation and/or other materials provided with the distribution.
|
||||
* Neither the name of the author nor the names of its
|
||||
contributors may be used to endorse or promote products derived
|
||||
from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef TORRENT_CREATE_TORRENT_HPP_INCLUDED
|
||||
#define TORRENT_CREATE_TORRENT_HPP_INCLUDED
|
||||
|
||||
#include "libtorrent/bencode.hpp"
|
||||
#include "libtorrent/peer_id.hpp"
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(push, 1)
|
||||
#endif
|
||||
|
||||
#include <boost/filesystem/path.hpp>
|
||||
#include <boost/optional.hpp>
|
||||
#include <boost/date_time/posix_time/posix_time.hpp>
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
|
||||
namespace libtorrent
|
||||
{
|
||||
namespace fs = boost::filesystem;
|
||||
namespace pt = boost::posix_time;
|
||||
|
||||
struct create_torrent
|
||||
{
|
||||
create_torrent();
|
||||
entry generate() const;
|
||||
|
||||
void set_comment(char const* str);
|
||||
void set_creator(char const* str);
|
||||
void set_piece_size(int size);
|
||||
void set_hash(int index, sha1_hash const& h);
|
||||
void add_file(fs::path file, size_type size);
|
||||
void add_url_seed(std::string const& url);
|
||||
void add_node(std::pair<std::string, int> const& node);
|
||||
void add_tracker(std::string const& url, int tier = 0);
|
||||
|
||||
int num_pieces() const { return m_num_pieces; }
|
||||
int piece_length() const { return m_piece_length; }
|
||||
int piece_size(int i) const;
|
||||
|
||||
private:
|
||||
|
||||
// the urls to the trackers
|
||||
typedef std::pair<std::string, int> announce_entry;
|
||||
std::vector<announce_entry> m_urls;
|
||||
|
||||
std::vector<std::string> m_url_seeds;
|
||||
|
||||
std::vector<sha1_hash> m_piece_hash;
|
||||
|
||||
// the length of one piece
|
||||
// if this is 0, the torrent_info is
|
||||
// in an uninitialized state
|
||||
int m_piece_length;
|
||||
|
||||
typedef std::pair<fs::path, size_type> file_entry;
|
||||
// the list of files that this torrent consists of
|
||||
std::vector<file_entry> m_files;
|
||||
|
||||
// dht nodes to add to the routing table/bootstrap from
|
||||
typedef std::vector<std::pair<std::string, int> > nodes_t;
|
||||
nodes_t m_nodes;
|
||||
|
||||
// the sum of all filesizes
|
||||
size_type m_total_size;
|
||||
|
||||
// the number of pieces in the torrent
|
||||
int m_num_pieces;
|
||||
|
||||
// the hash that identifies this torrent
|
||||
// is mutable because it's calculated
|
||||
// lazily
|
||||
mutable sha1_hash m_info_hash;
|
||||
|
||||
std::string m_name;
|
||||
|
||||
// if a creation date is found in the torrent file
|
||||
// this will be set to that, otherwise it'll be
|
||||
// 1970, Jan 1
|
||||
pt::ptime m_creation_date;
|
||||
|
||||
// if a comment is found in the torrent file
|
||||
// this will be set to that comment
|
||||
std::string m_comment;
|
||||
|
||||
// an optional string naming the software used
|
||||
// to create the torrent file
|
||||
std::string m_created_by;
|
||||
|
||||
// this is used when creating a torrent. If there's
|
||||
// only one file there are cases where it's impossible
|
||||
// to know if it should be written as a multifile torrent
|
||||
// or not. e.g. test/test there's one file and one directory
|
||||
// and they have the same name.
|
||||
bool m_multifile;
|
||||
|
||||
// this is true if the torrent is private. i.e., is should not
|
||||
// be announced on the dht
|
||||
bool m_private;
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
@ -570,7 +570,7 @@ namespace libtorrent
|
|||
// to the checker thread for initial checking
|
||||
// of the storage.
|
||||
// a return value of false indicates an error
|
||||
bool set_metadata(entry const& metadata, std::string& error);
|
||||
bool set_metadata(lazy_entry const& metadata, std::string& error);
|
||||
|
||||
int sequence_number() const { return m_sequence_number; }
|
||||
|
||||
|
|
|
@ -45,12 +45,14 @@ POSSIBILITY OF SUCH DAMAGE.
|
|||
#include <boost/optional.hpp>
|
||||
#include <boost/filesystem/path.hpp>
|
||||
#include <boost/shared_ptr.hpp>
|
||||
#include <boost/shared_array.hpp>
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
|
||||
#include "libtorrent/entry.hpp"
|
||||
#include "libtorrent/lazy_entry.hpp"
|
||||
#include "libtorrent/socket.hpp"
|
||||
#include "libtorrent/peer_id.hpp"
|
||||
#include "libtorrent/size_type.hpp"
|
||||
|
@ -110,19 +112,12 @@ namespace libtorrent
|
|||
|
||||
torrent_info();
|
||||
torrent_info(sha1_hash const& info_hash);
|
||||
torrent_info(entry const& torrent_file);
|
||||
torrent_info(lazy_entry const& torrent_file);
|
||||
torrent_info(char const* buffer, int size);
|
||||
torrent_info(char const* filename);
|
||||
~torrent_info();
|
||||
|
||||
entry create_torrent() const;
|
||||
entry create_info_metadata() const;
|
||||
void set_comment(char const* str);
|
||||
void set_creator(char const* str);
|
||||
void set_piece_size(int size);
|
||||
void set_hash(int index, sha1_hash const& h);
|
||||
void add_tracker(std::string const& url, int tier = 0);
|
||||
void add_file(fs::path file, size_type size);
|
||||
void add_url_seed(std::string const& url);
|
||||
|
||||
bool remap_files(std::vector<file_entry> const& map);
|
||||
|
||||
|
@ -132,10 +127,9 @@ namespace libtorrent
|
|||
, bool storage = false) const;
|
||||
|
||||
std::vector<std::string> const& url_seeds() const
|
||||
{
|
||||
TORRENT_ASSERT(!m_half_metadata);
|
||||
return m_url_seeds;
|
||||
}
|
||||
{ return m_url_seeds; }
|
||||
void torrent_info::add_url_seed(std::string const& url)
|
||||
{ m_url_seeds.push_back(url); }
|
||||
|
||||
typedef std::vector<file_entry>::const_iterator file_iterator;
|
||||
typedef std::vector<file_entry>::const_reverse_iterator reverse_file_iterator;
|
||||
|
@ -177,12 +171,12 @@ namespace libtorrent
|
|||
{
|
||||
TORRENT_ASSERT(m_piece_length > 0);
|
||||
if (!storage || m_remapped_files.empty())
|
||||
return (int)m_files.size();
|
||||
return int(m_files.size());
|
||||
else
|
||||
return (int)m_remapped_files.size();
|
||||
return int(m_remapped_files.size());
|
||||
}
|
||||
|
||||
const file_entry& file_at(int index, bool storage = false) const
|
||||
file_entry const& file_at(int index, bool storage = false) const
|
||||
{
|
||||
if (!storage || m_remapped_files.empty())
|
||||
{
|
||||
|
@ -196,7 +190,7 @@ namespace libtorrent
|
|||
}
|
||||
}
|
||||
|
||||
const std::vector<announce_entry>& trackers() const { return m_urls; }
|
||||
std::vector<announce_entry> const& trackers() const { return m_urls; }
|
||||
|
||||
size_type total_size() const { TORRENT_ASSERT(m_piece_length > 0); return m_total_size; }
|
||||
int piece_length() const { TORRENT_ASSERT(m_piece_length > 0); return m_piece_length; }
|
||||
|
@ -205,25 +199,30 @@ namespace libtorrent
|
|||
const std::string& name() const { TORRENT_ASSERT(m_piece_length > 0); return m_name; }
|
||||
|
||||
// ------- start deprecation -------
|
||||
// this functionaily will be removed in a future version
|
||||
// these functions will be removed in a future version
|
||||
torrent_info(entry const& torrent_file) TORRENT_DEPRECATED;
|
||||
void print(std::ostream& os) const TORRENT_DEPRECATED;
|
||||
// ------- end deprecation -------
|
||||
|
||||
bool is_valid() const { return m_piece_length > 0; }
|
||||
|
||||
bool priv() const { return m_private; }
|
||||
void set_priv(bool v) { m_private = v; }
|
||||
|
||||
void convert_file_names();
|
||||
|
||||
int piece_size(int index) const;
|
||||
|
||||
const sha1_hash& hash_for_piece(int index) const
|
||||
sha1_hash hash_for_piece(int index) const
|
||||
{
|
||||
return sha1_hash(hash_for_piece_ptr(index));
|
||||
}
|
||||
|
||||
char const* hash_for_piece_ptr(int index) const
|
||||
{
|
||||
TORRENT_ASSERT(index >= 0);
|
||||
TORRENT_ASSERT(index < (int)m_piece_hash.size());
|
||||
TORRENT_ASSERT(!m_half_metadata);
|
||||
return m_piece_hash[index];
|
||||
TORRENT_ASSERT(index < m_num_pieces);
|
||||
TORRENT_ASSERT(m_piece_hashes);
|
||||
TORRENT_ASSERT(m_piece_hashes >= m_info_section.get());
|
||||
TORRENT_ASSERT(m_piece_hashes < m_info_section.get() + m_info_section_size);
|
||||
return &m_piece_hashes[index*20];
|
||||
}
|
||||
|
||||
boost::optional<pt::ptime> creation_date() const;
|
||||
|
@ -239,26 +238,29 @@ namespace libtorrent
|
|||
|
||||
nodes_t const& nodes() const
|
||||
{
|
||||
TORRENT_ASSERT(!m_half_metadata);
|
||||
return m_nodes;
|
||||
}
|
||||
|
||||
void add_node(std::pair<std::string, int> const& node);
|
||||
bool parse_info_section(lazy_entry const& e, std::string& error);
|
||||
|
||||
bool parse_info_section(entry const& e, std::string& error);
|
||||
|
||||
entry const* extra(char const* key) const
|
||||
{ return m_extra_info.find_key(key); }
|
||||
|
||||
// frees parts of the metadata that isn't
|
||||
// used by seeds
|
||||
void seed_free();
|
||||
lazy_entry const* info(char const* key) const
|
||||
{
|
||||
if (m_info_dict.type() == lazy_entry::none_t)
|
||||
lazy_bdecode(m_info_section.get(), m_info_section.get()
|
||||
+ m_info_section_size, m_info_dict);
|
||||
return m_info_dict.dict_find(key);
|
||||
}
|
||||
|
||||
void swap(torrent_info& ti);
|
||||
|
||||
boost::shared_array<char> metadata() const
|
||||
{ return m_info_section; }
|
||||
|
||||
int metadata_size() const { return m_info_section_size; }
|
||||
|
||||
private:
|
||||
|
||||
bool read_torrent_info(const entry& libtorrent, std::string& error);
|
||||
bool parse_torrent_file(lazy_entry const& libtorrent, std::string& error);
|
||||
|
||||
// the urls to the trackers
|
||||
std::vector<announce_entry> m_urls;
|
||||
|
@ -270,9 +272,6 @@ namespace libtorrent
|
|||
// in an uninitialized state
|
||||
int m_piece_length;
|
||||
|
||||
// the sha-1 hashes of each piece
|
||||
std::vector<sha1_hash> m_piece_hash;
|
||||
|
||||
// the list of files that this torrent consists of
|
||||
std::vector<file_entry> m_files;
|
||||
|
||||
|
@ -294,7 +293,7 @@ namespace libtorrent
|
|||
// the hash that identifies this torrent
|
||||
// is mutable because it's calculated
|
||||
// lazily
|
||||
mutable sha1_hash m_info_hash;
|
||||
sha1_hash m_info_hash;
|
||||
|
||||
std::string m_name;
|
||||
|
||||
|
@ -322,18 +321,19 @@ namespace libtorrent
|
|||
// be announced on the dht
|
||||
bool m_private;
|
||||
|
||||
// contains any non-parsed entries from the info-section
|
||||
// these are kept in order to be able to accurately
|
||||
// reproduce the info-section when sending the metadata
|
||||
// to peers.
|
||||
entry m_extra_info;
|
||||
// this is a copy of the info section from the torrent.
|
||||
// it use maintained in this flat format in order to
|
||||
// make it available through the metadata extension
|
||||
boost::shared_array<char> m_info_section;
|
||||
int m_info_section_size;
|
||||
|
||||
#ifndef NDEBUG
|
||||
public:
|
||||
// this is set to true when seed_free() is called
|
||||
bool m_half_metadata;
|
||||
private:
|
||||
#endif
|
||||
// this is a pointer into the m_info_section buffer
|
||||
// pointing to the first byte of the first sha-1 hash
|
||||
char const* m_piece_hashes;
|
||||
|
||||
// the info section parsed. points into m_info_section
|
||||
// parsed lazily
|
||||
mutable lazy_entry m_info_dict;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -23,7 +23,7 @@ alert.cpp identify_client.cpp ip_filter.cpp file.cpp metadata_transfer.cpp \
|
|||
logger.cpp file_pool.cpp ut_pex.cpp lsd.cpp upnp.cpp instantiate_connection.cpp \
|
||||
socks5_stream.cpp socks4_stream.cpp http_stream.cpp connection_queue.cpp \
|
||||
disk_io_thread.cpp ut_metadata.cpp magnet_uri.cpp udp_socket.cpp smart_ban.cpp \
|
||||
http_parser.cpp gzip.cpp disk_buffer_holder.cpp GeoIP.c $(kademlia_sources)
|
||||
http_parser.cpp gzip.cpp disk_buffer_holder.cpp create_torrent.cpp GeoIP.c $(kademlia_sources)
|
||||
|
||||
noinst_HEADERS = \
|
||||
$(top_srcdir)/include/libtorrent/alert.hpp \
|
||||
|
@ -37,6 +37,7 @@ $(top_srcdir)/include/libtorrent/bencode.hpp \
|
|||
$(top_srcdir)/include/libtorrent/broadcast_socket.hpp \
|
||||
$(top_srcdir)/include/libtorrent/buffer.hpp \
|
||||
$(top_srcdir)/include/libtorrent/connection_queue.hpp \
|
||||
$(top_srcdir)/include/libtorrent/create_torrent.hpp \
|
||||
$(top_srcdir)/include/libtorrent/debug.hpp \
|
||||
$(top_srcdir)/include/libtorrent/disk_io_thread.hpp \
|
||||
$(top_srcdir)/include/libtorrent/entry.hpp \
|
||||
|
|
|
@ -0,0 +1,303 @@
|
|||
/*
|
||||
|
||||
Copyright (c) 2008, Arvid Norberg
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in
|
||||
the documentation and/or other materials provided with the distribution.
|
||||
* Neither the name of the author nor the names of its
|
||||
contributors may be used to endorse or promote products derived
|
||||
from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
#include "libtorrent/create_torrent.hpp"
|
||||
#include "libtorrent/hasher.hpp"
|
||||
|
||||
#include <boost/date_time/posix_time/posix_time.hpp>
|
||||
#include <boost/date_time/gregorian/gregorian.hpp>
|
||||
#include <boost/bind.hpp>
|
||||
|
||||
namespace gr = boost::gregorian;
|
||||
|
||||
namespace libtorrent
|
||||
{
|
||||
create_torrent::create_torrent()
|
||||
: m_piece_length(0)
|
||||
, m_total_size(0)
|
||||
, m_num_pieces(0)
|
||||
, m_info_hash()
|
||||
, m_name()
|
||||
, m_creation_date(pt::second_clock::universal_time())
|
||||
, m_multifile(false)
|
||||
, m_private(false)
|
||||
{}
|
||||
|
||||
entry create_torrent::generate() const
|
||||
{
|
||||
TORRENT_ASSERT(m_piece_length > 0);
|
||||
|
||||
if (m_files.empty())
|
||||
{
|
||||
// TODO: throw something here
|
||||
// throw
|
||||
return entry();
|
||||
}
|
||||
|
||||
entry dict;
|
||||
|
||||
if (!m_urls.empty()) dict["announce"] = m_urls.front().first;
|
||||
|
||||
if (!m_nodes.empty())
|
||||
{
|
||||
entry& nodes = dict["nodes"];
|
||||
entry::list_type& nodes_list = nodes.list();
|
||||
for (nodes_t::const_iterator i = m_nodes.begin()
|
||||
, end(m_nodes.end()); i != end; ++i)
|
||||
{
|
||||
entry::list_type node;
|
||||
node.push_back(entry(i->first));
|
||||
node.push_back(entry(i->second));
|
||||
nodes_list.push_back(entry(node));
|
||||
}
|
||||
}
|
||||
|
||||
if (m_urls.size() > 1)
|
||||
{
|
||||
entry trackers(entry::list_t);
|
||||
entry tier(entry::list_t);
|
||||
int current_tier = m_urls.front().second;
|
||||
for (std::vector<announce_entry>::const_iterator i = m_urls.begin();
|
||||
i != m_urls.end(); ++i)
|
||||
{
|
||||
if (i->second != current_tier)
|
||||
{
|
||||
current_tier = i->second;
|
||||
trackers.list().push_back(tier);
|
||||
tier.list().clear();
|
||||
}
|
||||
tier.list().push_back(entry(i->first));
|
||||
}
|
||||
trackers.list().push_back(tier);
|
||||
dict["announce-list"] = trackers;
|
||||
}
|
||||
|
||||
if (!m_comment.empty())
|
||||
dict["comment"] = m_comment;
|
||||
|
||||
dict["creation date"] =
|
||||
(m_creation_date - pt::ptime(gr::date(1970, gr::Jan, 1))).total_seconds();
|
||||
|
||||
if (!m_created_by.empty())
|
||||
dict["created by"] = m_created_by;
|
||||
|
||||
if (!m_url_seeds.empty())
|
||||
{
|
||||
if (m_url_seeds.size() == 1)
|
||||
{
|
||||
dict["url-list"] = m_url_seeds.front();
|
||||
}
|
||||
else
|
||||
{
|
||||
entry& list = dict["url-list"];
|
||||
for (std::vector<std::string>::const_iterator i
|
||||
= m_url_seeds.begin(); i != m_url_seeds.end(); ++i)
|
||||
{
|
||||
list.list().push_back(entry(*i));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
entry& info = dict["info"];
|
||||
|
||||
info["name"] = m_name;
|
||||
|
||||
|
||||
if (m_private) info["private"] = 1;
|
||||
|
||||
if (!m_multifile)
|
||||
{
|
||||
info["length"] = m_files.front().second;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!info.find_key("files"))
|
||||
{
|
||||
entry& files = info["files"];
|
||||
|
||||
for (std::vector<file_entry>::const_iterator i = m_files.begin();
|
||||
i != m_files.end(); ++i)
|
||||
{
|
||||
files.list().push_back(entry());
|
||||
entry& file_e = files.list().back();
|
||||
file_e["length"] = i->second;
|
||||
entry& path_e = file_e["path"];
|
||||
|
||||
TORRENT_ASSERT(i->first.has_branch_path());
|
||||
TORRENT_ASSERT(*i->first.begin() == m_name);
|
||||
|
||||
for (fs::path::iterator j = boost::next(i->first.begin());
|
||||
j != i->first.end(); ++j)
|
||||
{
|
||||
path_e.list().push_back(entry(*j));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
info["piece length"] = m_piece_length;
|
||||
entry& pieces = info["pieces"];
|
||||
|
||||
std::string& p = pieces.string();
|
||||
|
||||
for (std::vector<sha1_hash>::const_iterator i = m_piece_hash.begin();
|
||||
i != m_piece_hash.end(); ++i)
|
||||
{
|
||||
p.append((char*)i->begin(), (char*)i->end());
|
||||
}
|
||||
|
||||
std::vector<char> buf;
|
||||
bencode(std::back_inserter(buf), info);
|
||||
m_info_hash = hasher(&buf[0], buf.size()).final();
|
||||
|
||||
return dict;
|
||||
|
||||
}
|
||||
|
||||
int create_torrent::piece_size(int index) const
|
||||
{
|
||||
TORRENT_ASSERT(index >= 0 && index < num_pieces());
|
||||
if (index == num_pieces()-1)
|
||||
{
|
||||
int size = int(m_total_size
|
||||
- (num_pieces() - 1) * piece_length());
|
||||
TORRENT_ASSERT(size > 0);
|
||||
TORRENT_ASSERT(size <= piece_length());
|
||||
return int(size);
|
||||
}
|
||||
else
|
||||
return piece_length();
|
||||
}
|
||||
|
||||
void create_torrent::add_tracker(std::string const& url, int tier)
|
||||
{
|
||||
m_urls.push_back(announce_entry(url, tier));
|
||||
|
||||
using boost::bind;
|
||||
std::sort(m_urls.begin(), m_urls.end()
|
||||
, bind(&announce_entry::second, _1) < bind(&announce_entry::second, _2));
|
||||
}
|
||||
|
||||
void create_torrent::set_piece_size(int size)
|
||||
{
|
||||
// make sure the size is an even power of 2
|
||||
#ifndef NDEBUG
|
||||
for (int i = 0; i < 32; ++i)
|
||||
{
|
||||
if (size & (1 << i))
|
||||
{
|
||||
TORRENT_ASSERT((size & ~(1 << i)) == 0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
m_piece_length = size;
|
||||
|
||||
m_num_pieces = static_cast<int>(
|
||||
(m_total_size + m_piece_length - 1) / m_piece_length);
|
||||
int old_num_pieces = static_cast<int>(m_piece_hash.size());
|
||||
|
||||
m_piece_hash.resize(m_num_pieces);
|
||||
for (int i = old_num_pieces; i < m_num_pieces; ++i)
|
||||
{
|
||||
m_piece_hash[i].clear();
|
||||
}
|
||||
}
|
||||
|
||||
void create_torrent::set_hash(int index, sha1_hash const& h)
|
||||
{
|
||||
TORRENT_ASSERT(index >= 0);
|
||||
TORRENT_ASSERT(index < (int)m_piece_hash.size());
|
||||
m_piece_hash[index] = h;
|
||||
}
|
||||
|
||||
void create_torrent::add_file(fs::path file, size_type size)
|
||||
{
|
||||
// TORRENT_ASSERT(file.begin() != file.end());
|
||||
|
||||
if (!file.has_branch_path())
|
||||
{
|
||||
// you have already added at least one file with a
|
||||
// path to the file (branch_path), which means that
|
||||
// all the other files need to be in the same top
|
||||
// directory as the first file.
|
||||
TORRENT_ASSERT(m_files.empty());
|
||||
TORRENT_ASSERT(!m_multifile);
|
||||
m_name = file.string();
|
||||
}
|
||||
else
|
||||
{
|
||||
#ifndef NDEBUG
|
||||
if (!m_files.empty())
|
||||
TORRENT_ASSERT(m_name == *file.begin());
|
||||
#endif
|
||||
m_multifile = true;
|
||||
m_name = *file.begin();
|
||||
}
|
||||
|
||||
m_files.push_back(file_entry(file, size));
|
||||
|
||||
m_total_size += size;
|
||||
|
||||
if (m_piece_length == 0)
|
||||
m_piece_length = 256 * 1024;
|
||||
|
||||
m_num_pieces = int((m_total_size + m_piece_length - 1) / m_piece_length);
|
||||
int old_num_pieces = int(m_piece_hash.size());
|
||||
|
||||
m_piece_hash.resize(m_num_pieces);
|
||||
if (m_num_pieces > old_num_pieces)
|
||||
std::for_each(m_piece_hash.begin() + old_num_pieces
|
||||
, m_piece_hash.end(), boost::bind(&sha1_hash::clear, _1));
|
||||
}
|
||||
|
||||
void create_torrent::add_node(std::pair<std::string, int> const& node)
|
||||
{
|
||||
m_nodes.push_back(node);
|
||||
}
|
||||
|
||||
void create_torrent::add_url_seed(std::string const& url)
|
||||
{
|
||||
m_url_seeds.push_back(url);
|
||||
}
|
||||
|
||||
void create_torrent::set_comment(char const* str)
|
||||
{
|
||||
m_comment = str;
|
||||
}
|
||||
|
||||
void create_torrent::set_creator(char const* str)
|
||||
{
|
||||
m_created_by = str;
|
||||
}
|
||||
}
|
||||
|
|
@ -55,6 +55,7 @@ POSSIBILITY OF SUCH DAMAGE.
|
|||
#include "libtorrent/extensions.hpp"
|
||||
#include "libtorrent/extensions/metadata_transfer.hpp"
|
||||
#include "libtorrent/alert_types.hpp"
|
||||
#include "libtorrent/buffer.hpp"
|
||||
|
||||
namespace libtorrent { namespace
|
||||
{
|
||||
|
@ -107,40 +108,37 @@ namespace libtorrent { namespace
|
|||
|
||||
virtual void on_files_checked()
|
||||
{
|
||||
// if the torrent is a seed, copy the metadata from
|
||||
// the torrent before it is deallocated
|
||||
if (m_torrent.is_seed())
|
||||
metadata();
|
||||
// if the torrent is a seed, make a reference to
|
||||
// the metadata from the torrent before it is deallocated
|
||||
if (m_torrent.is_seed()) metadata();
|
||||
}
|
||||
|
||||
virtual boost::shared_ptr<peer_plugin> new_connection(
|
||||
peer_connection* pc);
|
||||
|
||||
std::vector<char> const& metadata() const
|
||||
buffer::const_interval metadata() const
|
||||
{
|
||||
if (m_metadata.empty())
|
||||
if (!m_metadata)
|
||||
{
|
||||
bencode(std::back_inserter(m_metadata)
|
||||
, m_torrent.torrent_file().create_info_metadata());
|
||||
|
||||
TORRENT_ASSERT(hasher(&m_metadata[0], m_metadata.size()).final()
|
||||
m_metadata = m_torrent.torrent_file().metadata();
|
||||
m_metadata_size = m_torrent.torrent_file().metadata_size();
|
||||
TORRENT_ASSERT(hasher(m_metadata.get(), m_metadata_size).final()
|
||||
== m_torrent.torrent_file().info_hash());
|
||||
}
|
||||
TORRENT_ASSERT(!m_metadata.empty());
|
||||
return m_metadata;
|
||||
return buffer::const_interval(m_metadata.get(), m_metadata.get()
|
||||
+ m_metadata_size);
|
||||
}
|
||||
|
||||
bool received_metadata(char const* buf, int size, int offset, int total_size)
|
||||
{
|
||||
if (m_torrent.valid_metadata()) return false;
|
||||
|
||||
if ((int)m_metadata.size() < total_size)
|
||||
m_metadata.resize(total_size);
|
||||
|
||||
std::copy(
|
||||
buf
|
||||
, buf + size
|
||||
, &m_metadata[offset]);
|
||||
if (!m_metadata || m_metadata_size < total_size)
|
||||
{
|
||||
m_metadata.reset(new char[total_size]);
|
||||
m_metadata_size = total_size;
|
||||
}
|
||||
std::copy(buf, buf + size, &m_metadata[offset]);
|
||||
|
||||
if (m_have_metadata.empty())
|
||||
m_have_metadata.resize(256, false);
|
||||
|
@ -163,7 +161,7 @@ namespace libtorrent { namespace
|
|||
if (!have_all) return false;
|
||||
|
||||
hasher h;
|
||||
h.update(&m_metadata[0], (int)m_metadata.size());
|
||||
h.update(&m_metadata[0], m_metadata_size);
|
||||
sha1_hash info_hash = h.final();
|
||||
|
||||
if (info_hash != m_torrent.torrent_file().info_hash())
|
||||
|
@ -184,9 +182,10 @@ namespace libtorrent { namespace
|
|||
return false;
|
||||
}
|
||||
|
||||
entry metadata = bdecode(m_metadata.begin(), m_metadata.end());
|
||||
lazy_entry e;
|
||||
lazy_bdecode(m_metadata.get(), m_metadata.get() + m_metadata_size, e);
|
||||
std::string error;
|
||||
if (!m_torrent.set_metadata(metadata, error))
|
||||
if (!m_torrent.set_metadata(e, error))
|
||||
{
|
||||
// this means the metadata is correct, since we
|
||||
// verified it against the info-hash, but we
|
||||
|
@ -240,10 +239,10 @@ namespace libtorrent { namespace
|
|||
// the metadata file while downloading it from
|
||||
// peers, and while sending it.
|
||||
// it is mutable because it's generated lazily
|
||||
mutable std::vector<char> m_metadata;
|
||||
mutable boost::shared_array<char> m_metadata;
|
||||
|
||||
int m_metadata_progress;
|
||||
int m_metadata_size;
|
||||
mutable int m_metadata_size;
|
||||
|
||||
// this is a bitfield of size 256, each bit represents
|
||||
// a piece of the metadata. It is set to one if we
|
||||
|
@ -333,7 +332,7 @@ namespace libtorrent { namespace
|
|||
if (m_torrent.valid_metadata() && !m_torrent.torrent_file().priv())
|
||||
{
|
||||
std::pair<int, int> offset
|
||||
= req_to_offset(req, (int)m_tp.metadata().size());
|
||||
= req_to_offset(req, (int)m_tp.metadata().left());
|
||||
|
||||
buffer::interval i = m_pc.allocate_send_buffer(15 + offset.second);
|
||||
|
||||
|
@ -343,11 +342,11 @@ namespace libtorrent { namespace
|
|||
detail::write_uint8(m_message_index, i.begin);
|
||||
// means 'data packet'
|
||||
detail::write_uint8(1, i.begin);
|
||||
detail::write_uint32((int)m_tp.metadata().size(), i.begin);
|
||||
detail::write_uint32((int)m_tp.metadata().left(), i.begin);
|
||||
detail::write_uint32(offset.first, i.begin);
|
||||
std::vector<char> const& metadata = m_tp.metadata();
|
||||
std::copy(metadata.begin() + offset.first
|
||||
, metadata.begin() + offset.first + offset.second, i.begin);
|
||||
char const* metadata = m_tp.metadata().begin;
|
||||
std::copy(metadata + offset.first
|
||||
, metadata + offset.first + offset.second, i.begin);
|
||||
i.begin += offset.second;
|
||||
TORRENT_ASSERT(i.begin == i.end);
|
||||
}
|
||||
|
|
|
@ -253,7 +253,6 @@ namespace libtorrent
|
|||
, bool paused
|
||||
, storage_constructor_type sc)
|
||||
{
|
||||
TORRENT_ASSERT(!ti.m_half_metadata);
|
||||
boost::intrusive_ptr<torrent_info> tip(new torrent_info(ti));
|
||||
add_torrent_params p(sc);
|
||||
p.ti = tip;
|
||||
|
@ -273,7 +272,6 @@ namespace libtorrent
|
|||
, storage_constructor_type sc
|
||||
, void* userdata)
|
||||
{
|
||||
TORRENT_ASSERT(!ti->m_half_metadata);
|
||||
add_torrent_params p(sc);
|
||||
p.ti = ti;
|
||||
p.save_path = save_path;
|
||||
|
|
|
@ -1498,9 +1498,8 @@ namespace libtorrent
|
|||
#endif
|
||||
if (is_seed())
|
||||
{
|
||||
m_state = torrent_status::seeding;
|
||||
m_picker.reset();
|
||||
if (m_ses.settings().free_torrent_hashes)
|
||||
m_torrent_file->seed_free();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2608,7 +2607,7 @@ namespace libtorrent
|
|||
return true;
|
||||
}
|
||||
|
||||
bool torrent::set_metadata(entry const& metadata, std::string& error)
|
||||
bool torrent::set_metadata(lazy_entry const& metadata, std::string& error)
|
||||
{
|
||||
INVARIANT_CHECK;
|
||||
|
||||
|
@ -3042,8 +3041,6 @@ namespace libtorrent
|
|||
{
|
||||
m_state = torrent_status::seeding;
|
||||
m_picker.reset();
|
||||
if (m_ses.settings().free_torrent_hashes)
|
||||
m_torrent_file->seed_free();
|
||||
}
|
||||
|
||||
if (!m_connections_initialized)
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
|
||||
Copyright (c) 2003, Arvid Norberg
|
||||
Copyright (c) 2008, Arvid Norberg
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
|
@ -160,13 +160,13 @@ namespace
|
|||
}
|
||||
}
|
||||
|
||||
bool extract_single_file(entry const& dict, file_entry& target
|
||||
bool extract_single_file(lazy_entry const& dict, file_entry& target
|
||||
, std::string const& root_dir)
|
||||
{
|
||||
entry const* length = dict.find_key("length");
|
||||
if (length == 0 || length->type() != entry::int_t)
|
||||
lazy_entry const* length = dict.dict_find("length");
|
||||
if (length == 0 || length->type() != lazy_entry::int_t)
|
||||
return false;
|
||||
target.size = length->integer();
|
||||
target.size = length->int_value();
|
||||
target.path = root_dir;
|
||||
target.file_base = 0;
|
||||
|
||||
|
@ -174,27 +174,19 @@ namespace
|
|||
// because if it exists, it is more
|
||||
// likely to be correctly encoded
|
||||
|
||||
const entry::list_type* list = 0;
|
||||
entry const* p8 = dict.find_key("path.utf-8");
|
||||
if (p8 != 0 && p8->type() == entry::list_t)
|
||||
{
|
||||
list = &p8->list();
|
||||
}
|
||||
else
|
||||
{
|
||||
entry const* p = dict.find_key("path");
|
||||
if (p == 0 || p->type() != entry::list_t)
|
||||
return false;
|
||||
list = &p->list();
|
||||
}
|
||||
lazy_entry const* p = dict.dict_find("path.utf-8");
|
||||
if (p == 0 || p->type() != lazy_entry::list_t)
|
||||
p = dict.dict_find("path");
|
||||
if (p == 0 || p->type() != lazy_entry::list_t)
|
||||
return false;
|
||||
|
||||
for (entry::list_type::const_iterator i = list->begin();
|
||||
i != list->end(); ++i)
|
||||
for (int i = 0, end(p->list_size()); i < end; ++i)
|
||||
{
|
||||
if (i->type() != entry::string_t)
|
||||
if (p->list_at(i)->type() != lazy_entry::string_t)
|
||||
return false;
|
||||
if (i->string() != "..")
|
||||
target.path /= i->string();
|
||||
std::string path_element = p->list_at(i)->string_value();
|
||||
if (path_element != "..")
|
||||
target.path /= path_element;
|
||||
}
|
||||
verify_encoding(target);
|
||||
if (target.path.is_complete())
|
||||
|
@ -202,14 +194,15 @@ namespace
|
|||
return true;
|
||||
}
|
||||
|
||||
bool extract_files(const entry::list_type& list, std::vector<file_entry>& target
|
||||
bool extract_files(lazy_entry const& list, std::vector<file_entry>& target
|
||||
, std::string const& root_dir)
|
||||
{
|
||||
size_type offset = 0;
|
||||
for (entry::list_type::const_iterator i = list.begin(); i != list.end(); ++i)
|
||||
if (list.type() != lazy_entry::list_t) return false;
|
||||
for (int i = 0, end(list.list_size()); i < end; ++i)
|
||||
{
|
||||
target.push_back(file_entry());
|
||||
if (!extract_single_file(*i, target.back(), root_dir))
|
||||
if (!extract_single_file(*list.list_at(i), target.back(), root_dir))
|
||||
return false;
|
||||
target.back().offset = offset;
|
||||
offset += target.back().size;
|
||||
|
@ -232,25 +225,65 @@ namespace libtorrent
|
|||
{
|
||||
|
||||
// standard constructor that parses a torrent file
|
||||
torrent_info::torrent_info(const entry& torrent_file)
|
||||
torrent_info::torrent_info(entry const& torrent_file)
|
||||
: m_num_pieces(0)
|
||||
, m_creation_date(pt::ptime(pt::not_a_date_time))
|
||||
, m_multifile(false)
|
||||
, m_private(false)
|
||||
, m_extra_info(entry::dictionary_t)
|
||||
#ifndef NDEBUG
|
||||
, m_half_metadata(false)
|
||||
, m_info_section_size(0)
|
||||
, m_piece_hashes(0)
|
||||
{
|
||||
std::vector<char> tmp;
|
||||
std::back_insert_iterator<std::vector<char> > out(tmp);
|
||||
bencode(out, torrent_file);
|
||||
|
||||
lazy_entry e;
|
||||
lazy_bdecode(&tmp[0], &tmp[0] + tmp.size(), e);
|
||||
std::string error;
|
||||
#ifndef BOOST_NO_EXCEPTIONS
|
||||
if (!parse_torrent_file(e, error))
|
||||
throw invalid_torrent_file();
|
||||
#else
|
||||
read_torrent_info(e, error);
|
||||
#endif
|
||||
}
|
||||
|
||||
torrent_info::torrent_info(lazy_entry const& torrent_file)
|
||||
: m_num_pieces(0)
|
||||
, m_creation_date(pt::ptime(pt::not_a_date_time))
|
||||
, m_multifile(false)
|
||||
, m_private(false)
|
||||
, m_info_section_size(0)
|
||||
, m_piece_hashes(0)
|
||||
{
|
||||
std::string error;
|
||||
#ifndef BOOST_NO_EXCEPTIONS
|
||||
if (!read_torrent_info(torrent_file, error))
|
||||
if (!parse_torrent_file(torrent_file, error))
|
||||
throw invalid_torrent_file();
|
||||
#else
|
||||
read_torrent_info(torrent_file, error);
|
||||
#endif
|
||||
}
|
||||
|
||||
torrent_info::torrent_info(char const* buffer, int size)
|
||||
: m_num_pieces(0)
|
||||
, m_creation_date(pt::ptime(pt::not_a_date_time))
|
||||
, m_multifile(false)
|
||||
, m_private(false)
|
||||
, m_info_section_size(0)
|
||||
, m_piece_hashes(0)
|
||||
{
|
||||
std::string error;
|
||||
lazy_entry e;
|
||||
lazy_bdecode(buffer, buffer + size, e);
|
||||
#ifndef BOOST_NO_EXCEPTIONS
|
||||
if (!parse_torrent_file(e, error))
|
||||
throw invalid_torrent_file();
|
||||
#else
|
||||
read_torrent_info(e, error);
|
||||
#endif
|
||||
}
|
||||
|
||||
// constructor used for creating new torrents
|
||||
// will not contain any hashes, comments, creation date
|
||||
// just the necessary to use it with piece manager
|
||||
|
@ -264,10 +297,8 @@ namespace libtorrent
|
|||
, m_creation_date(pt::second_clock::universal_time())
|
||||
, m_multifile(false)
|
||||
, m_private(false)
|
||||
, m_extra_info(entry::dictionary_t)
|
||||
#ifndef NDEBUG
|
||||
, m_half_metadata(false)
|
||||
#endif
|
||||
, m_info_section_size(0)
|
||||
, m_piece_hashes(0)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -280,10 +311,8 @@ namespace libtorrent
|
|||
, m_creation_date(pt::second_clock::universal_time())
|
||||
, m_multifile(false)
|
||||
, m_private(false)
|
||||
, m_extra_info(entry::dictionary_t)
|
||||
#ifndef NDEBUG
|
||||
, m_half_metadata(false)
|
||||
#endif
|
||||
, m_info_section_size(0)
|
||||
, m_piece_hashes(0)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -292,10 +321,6 @@ namespace libtorrent
|
|||
, m_creation_date(pt::ptime(pt::not_a_date_time))
|
||||
, m_multifile(false)
|
||||
, m_private(false)
|
||||
, m_extra_info(entry::dictionary_t)
|
||||
#ifndef NDEBUG
|
||||
, m_half_metadata(false)
|
||||
#endif
|
||||
{
|
||||
size_type s = fs::file_size(fs::path(filename));
|
||||
// don't load torrent files larger than 2 MB
|
||||
|
@ -303,15 +328,12 @@ namespace libtorrent
|
|||
std::vector<char> buf(s);
|
||||
std::ifstream f(filename);
|
||||
f.read(&buf[0], s);
|
||||
/*
|
||||
lazy_entry e;
|
||||
int ret = lazy_bdecode(&buf[0], &buf[0] + buf.size(), e);
|
||||
if (ret != 0) return;
|
||||
*/
|
||||
entry e = bdecode(&buf[0], &buf[0] + buf.size());
|
||||
|
||||
std::string error;
|
||||
lazy_entry e;
|
||||
lazy_bdecode(&buf[0], &buf[0] + buf.size(), e);
|
||||
#ifndef BOOST_NO_EXCEPTIONS
|
||||
if (!read_torrent_info(e, error))
|
||||
if (!parse_torrent_file(e, error))
|
||||
throw invalid_torrent_file();
|
||||
#else
|
||||
read_torrent_info(e, error);
|
||||
|
@ -326,9 +348,8 @@ namespace libtorrent
|
|||
using std::swap;
|
||||
m_urls.swap(ti.m_urls);
|
||||
m_url_seeds.swap(ti.m_url_seeds);
|
||||
swap(m_piece_length, ti.m_piece_length);
|
||||
m_piece_hash.swap(ti.m_piece_hash);
|
||||
m_files.swap(ti.m_files);
|
||||
m_files.swap(ti.m_remapped_files);
|
||||
m_nodes.swap(ti.m_nodes);
|
||||
swap(m_num_pieces, ti.m_num_pieces);
|
||||
swap(m_info_hash, ti.m_info_hash);
|
||||
|
@ -338,83 +359,51 @@ namespace libtorrent
|
|||
m_created_by.swap(ti.m_created_by);
|
||||
swap(m_multifile, ti.m_multifile);
|
||||
swap(m_private, ti.m_private);
|
||||
m_extra_info.swap(ti.m_extra_info);
|
||||
#ifndef NDEBUG
|
||||
swap(m_half_metadata, ti.m_half_metadata);
|
||||
#endif
|
||||
swap(m_info_section, ti.m_info_section);
|
||||
swap(m_info_section_size, ti.m_info_section_size);
|
||||
swap(m_piece_hashes, ti.m_piece_hashes);
|
||||
swap(m_info_dict, ti.m_info_dict);
|
||||
}
|
||||
|
||||
void torrent_info::set_piece_size(int size)
|
||||
bool torrent_info::parse_info_section(lazy_entry const& info, std::string& error)
|
||||
{
|
||||
// make sure the size is an even power of 2
|
||||
#ifndef NDEBUG
|
||||
for (int i = 0; i < 32; ++i)
|
||||
{
|
||||
if (size & (1 << i))
|
||||
{
|
||||
TORRENT_ASSERT((size & ~(1 << i)) == 0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
TORRENT_ASSERT(!m_half_metadata);
|
||||
m_piece_length = size;
|
||||
|
||||
m_num_pieces = static_cast<int>(
|
||||
(m_total_size + m_piece_length - 1) / m_piece_length);
|
||||
int old_num_pieces = static_cast<int>(m_piece_hash.size());
|
||||
|
||||
m_piece_hash.resize(m_num_pieces);
|
||||
for (int i = old_num_pieces; i < m_num_pieces; ++i)
|
||||
{
|
||||
m_piece_hash[i].clear();
|
||||
}
|
||||
}
|
||||
|
||||
bool torrent_info::parse_info_section(entry const& info, std::string& error)
|
||||
{
|
||||
if (info.type() != entry::dictionary_t)
|
||||
if (info.type() != lazy_entry::dict_t)
|
||||
{
|
||||
error = "'info' entry is not a dictionary";
|
||||
return false;
|
||||
}
|
||||
|
||||
// encode the info-field in order to calculate it's sha1-hash
|
||||
std::vector<char> buf;
|
||||
bencode(std::back_inserter(buf), info);
|
||||
// hash the info-field to calculate info-hash
|
||||
hasher h;
|
||||
h.update(&buf[0], (int)buf.size());
|
||||
std::pair<char const*, int> section = info.data_section();
|
||||
h.update(section.first, section.second);
|
||||
m_info_hash = h.final();
|
||||
|
||||
// copy the info section
|
||||
m_info_section_size = section.second;
|
||||
m_info_section.reset(new char[m_info_section_size]);
|
||||
memcpy(m_info_section.get(), section.first, m_info_section_size);
|
||||
TORRENT_ASSERT(section.first[0] == 'd');
|
||||
TORRENT_ASSERT(section.first[m_info_section_size-1] == 'e');
|
||||
|
||||
// extract piece length
|
||||
entry const* piece_length = info.find_key("piece length");
|
||||
if (piece_length == 0 || piece_length->type() != entry::int_t)
|
||||
m_piece_length = info.dict_find_int_value("piece length", -1);
|
||||
if (m_piece_length <= 0)
|
||||
{
|
||||
error = "invalid or missing 'piece length' entry in torrent file";
|
||||
return false;
|
||||
}
|
||||
m_piece_length = int(piece_length->integer());
|
||||
if (m_piece_length <= 0)
|
||||
|
||||
// extract file name (or the directory name if it's a multifile libtorrent)
|
||||
m_name = info.dict_find_string_value("name.utf-8");
|
||||
if (m_name.empty()) m_name = info.dict_find_string_value("name");
|
||||
|
||||
if (m_name.empty())
|
||||
{
|
||||
error = "invalid torrent. piece length <= 0";
|
||||
error = "invalid name in torrent file";
|
||||
return false;
|
||||
}
|
||||
|
||||
// extract file name (or the directory name if it's a multifile libtorrent)
|
||||
entry const* e = info.find_key("name.utf-8");
|
||||
if (e && e->type() == entry::string_t)
|
||||
{ m_name = e->string(); }
|
||||
else
|
||||
{
|
||||
entry const* e = info.find_key("name");
|
||||
if (e == 0 || e->type() != entry::string_t)
|
||||
{
|
||||
error = "invalid name in torrent file";
|
||||
return false;
|
||||
}
|
||||
m_name = e->string();
|
||||
}
|
||||
|
||||
fs::path tmp = m_name;
|
||||
if (tmp.is_complete())
|
||||
{
|
||||
|
@ -433,32 +422,31 @@ namespace libtorrent
|
|||
}
|
||||
if (m_name == ".." || m_name == ".")
|
||||
{
|
||||
|
||||
error = "invalid 'name' of torrent (possible exploit attempt)";
|
||||
return false;
|
||||
}
|
||||
|
||||
// extract file list
|
||||
entry const* i = info.find_key("files");
|
||||
lazy_entry const* i = info.dict_find_list("files");
|
||||
if (i == 0)
|
||||
{
|
||||
entry const* length = info.find_key("length");
|
||||
if (length == 0 || length->type() != entry::int_t)
|
||||
{
|
||||
error = "invalid length of torrent";
|
||||
return false;
|
||||
}
|
||||
// if there's no list of files, there has to be a length
|
||||
// field.
|
||||
file_entry e;
|
||||
e.path = m_name;
|
||||
e.offset = 0;
|
||||
e.size = length->integer();
|
||||
e.size = info.dict_find_int_value("length", -1);
|
||||
if (e.size < 0)
|
||||
{
|
||||
error = "invalid length of torrent";
|
||||
return false;
|
||||
}
|
||||
m_files.push_back(e);
|
||||
m_multifile = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!extract_files(i->list(), m_files, m_name))
|
||||
if (!extract_files(*i, m_files, m_name))
|
||||
{
|
||||
error = "failed to parse files from torrent file";
|
||||
return false;
|
||||
|
@ -475,84 +463,51 @@ namespace libtorrent
|
|||
// we want this division to round upwards, that's why we have the
|
||||
// extra addition
|
||||
|
||||
entry const* pieces_ent = info.find_key("pieces");
|
||||
if (pieces_ent == 0 || pieces_ent->type() != entry::string_t)
|
||||
m_num_pieces = static_cast<int>((m_total_size + m_piece_length - 1) / m_piece_length);
|
||||
|
||||
lazy_entry const* pieces = info.dict_find("pieces");
|
||||
if (pieces == 0 || pieces->type() != lazy_entry::string_t)
|
||||
{
|
||||
error = "invalid or missing 'pieces' entry in torrent file";
|
||||
return false;
|
||||
}
|
||||
|
||||
m_num_pieces = static_cast<int>((m_total_size + m_piece_length - 1) / m_piece_length);
|
||||
m_piece_hash.resize(m_num_pieces);
|
||||
const std::string& hash_string = pieces_ent->string();
|
||||
|
||||
if ((int)hash_string.length() != m_num_pieces * 20)
|
||||
if (pieces->string_length() != m_num_pieces * 20)
|
||||
{
|
||||
error = "incorrect number of piece hashes in torrent file";
|
||||
return false;
|
||||
}
|
||||
|
||||
for (int i = 0; i < m_num_pieces; ++i)
|
||||
std::copy(
|
||||
hash_string.begin() + i*20
|
||||
, hash_string.begin() + (i+1)*20
|
||||
, m_piece_hash[i].begin());
|
||||
m_piece_hashes = m_info_section.get() + (pieces->string_ptr() - section.first);
|
||||
TORRENT_ASSERT(m_piece_hashes >= m_info_section.get());
|
||||
TORRENT_ASSERT(m_piece_hashes < m_info_section.get() + m_info_section_size);
|
||||
|
||||
for (entry::dictionary_type::const_iterator i = info.dict().begin()
|
||||
, end(info.dict().end()); i != end; ++i)
|
||||
{
|
||||
if (i->first == "pieces"
|
||||
|| i->first == "piece length"
|
||||
|| i->first == "length")
|
||||
continue;
|
||||
m_extra_info[i->first] = i->second;
|
||||
}
|
||||
|
||||
if (entry const* priv = info.find_key("private"))
|
||||
{
|
||||
if (priv->type() != entry::int_t
|
||||
|| priv->integer() != 0)
|
||||
{
|
||||
// this key exists and it's not 0.
|
||||
// consider the torrent private
|
||||
m_private = true;
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef NDEBUG
|
||||
std::vector<char> info_section_buf;
|
||||
entry gen_info_section = create_info_metadata();
|
||||
bencode(std::back_inserter(info_section_buf), gen_info_section);
|
||||
TORRENT_ASSERT(hasher(&info_section_buf[0], info_section_buf.size()).final()
|
||||
== m_info_hash);
|
||||
#endif
|
||||
m_private = info.dict_find_int_value("private", 0);
|
||||
return true;
|
||||
}
|
||||
|
||||
// extracts information from a libtorrent file and fills in the structures in
|
||||
// the torrent object
|
||||
bool torrent_info::read_torrent_info(const entry& torrent_file, std::string& error)
|
||||
bool torrent_info::parse_torrent_file(lazy_entry const& torrent_file, std::string& error)
|
||||
{
|
||||
if (torrent_file.type() != entry::dictionary_t)
|
||||
if (torrent_file.type() != lazy_entry::dict_t)
|
||||
{
|
||||
error = "torrent file is not a dictionary";
|
||||
return false;
|
||||
}
|
||||
|
||||
// extract the url of the tracker
|
||||
entry const* i = torrent_file.find_key("announce-list");
|
||||
if (i && i->type() == entry::list_t)
|
||||
lazy_entry const* i = torrent_file.dict_find_list("announce-list");
|
||||
if (i)
|
||||
{
|
||||
const entry::list_type& l = i->list();
|
||||
for (entry::list_type::const_iterator j = l.begin(); j != l.end(); ++j)
|
||||
m_urls.reserve(i->list_size());
|
||||
for (int j = 0, end(i->list_size()); j < end; ++j)
|
||||
{
|
||||
if (j->type() != entry::list_t) break;
|
||||
const entry::list_type& ll = j->list();
|
||||
for (entry::list_type::const_iterator k = ll.begin(); k != ll.end(); ++k)
|
||||
lazy_entry const* tier = i->list_at(j);
|
||||
if (tier->type() != lazy_entry::list_t) break;
|
||||
for (int k = 0, end(tier->list_size()); k < end; ++k)
|
||||
{
|
||||
if (k->type() != entry::string_t) break;
|
||||
announce_entry e(k->string());
|
||||
e.tier = (int)std::distance(l.begin(), j);
|
||||
announce_entry e(tier->list_string_value_at(k));
|
||||
if (e.url.empty()) continue;
|
||||
e.tier = j;
|
||||
m_urls.push_back(e);
|
||||
}
|
||||
}
|
||||
|
@ -573,71 +528,62 @@ namespace libtorrent
|
|||
std::random_shuffle(start, stop);
|
||||
}
|
||||
|
||||
entry const* announce = torrent_file.find_key("announce");
|
||||
if (m_urls.empty() && announce && announce->type() == entry::string_t)
|
||||
|
||||
if (m_urls.empty())
|
||||
{
|
||||
m_urls.push_back(announce_entry(announce->string()));
|
||||
announce_entry e(torrent_file.dict_find_string_value("announce"));
|
||||
if (!e.url.empty()) m_urls.push_back(e);
|
||||
}
|
||||
|
||||
entry const* nodes = torrent_file.find_key("nodes");
|
||||
if (nodes && nodes->type() == entry::list_t)
|
||||
lazy_entry const* nodes = torrent_file.dict_find_list("nodes");
|
||||
if (nodes)
|
||||
{
|
||||
entry::list_type const& list = nodes->list();
|
||||
for (entry::list_type::const_iterator i(list.begin())
|
||||
, end(list.end()); i != end; ++i)
|
||||
for (int i = 0, end(nodes->list_size()); i < end; ++i)
|
||||
{
|
||||
if (i->type() != entry::list_t) continue;
|
||||
entry::list_type const& l = i->list();
|
||||
entry::list_type::const_iterator iter = l.begin();
|
||||
if (l.size() < 1) continue;
|
||||
if (iter->type() != entry::string_t) continue;
|
||||
std::string const& hostname = iter->string();
|
||||
++iter;
|
||||
int port = 6881;
|
||||
if (iter->type() != entry::int_t) continue;
|
||||
if (l.end() != iter) port = int(iter->integer());
|
||||
m_nodes.push_back(std::make_pair(hostname, port));
|
||||
lazy_entry const* n = nodes->list_at(i);
|
||||
if (n->type() != lazy_entry::list_t
|
||||
|| n->list_size() < 2
|
||||
|| n->list_at(0)->type() != lazy_entry::string_t
|
||||
|| n->list_at(1)->type() != lazy_entry::int_t)
|
||||
continue;
|
||||
m_nodes.push_back(std::make_pair(
|
||||
n->list_at(0)->string_value()
|
||||
, int(n->list_at(1)->int_value())));
|
||||
}
|
||||
}
|
||||
|
||||
// extract creation date
|
||||
entry const* creation_date = torrent_file.find_key("creation date");
|
||||
if (creation_date && creation_date->type() == entry::int_t)
|
||||
size_type cd = torrent_file.dict_find_int_value("creation date", -1);
|
||||
if (cd >= 0)
|
||||
{
|
||||
m_creation_date = pt::ptime(gr::date(1970, gr::Jan, 1))
|
||||
+ pt::seconds(long(creation_date->integer()));
|
||||
+ pt::seconds(long(cd));
|
||||
}
|
||||
|
||||
// if there are any url-seeds, extract them
|
||||
entry const* url_seeds = torrent_file.find_key("url-list");
|
||||
if (url_seeds && url_seeds->type() == entry::string_t)
|
||||
lazy_entry const* url_seeds = torrent_file.dict_find("url-list");
|
||||
if (url_seeds && url_seeds->type() == lazy_entry::string_t)
|
||||
{
|
||||
m_url_seeds.push_back(url_seeds->string());
|
||||
m_url_seeds.push_back(url_seeds->string_value());
|
||||
}
|
||||
else if (url_seeds && url_seeds->type() == entry::list_t)
|
||||
else if (url_seeds && url_seeds->type() == lazy_entry::list_t)
|
||||
{
|
||||
entry::list_type const& l = url_seeds->list();
|
||||
for (entry::list_type::const_iterator i = l.begin();
|
||||
i != l.end(); ++i)
|
||||
for (int i = 0, end(url_seeds->list_size()); i < end; ++i)
|
||||
{
|
||||
if (i->type() != entry::string_t) continue;
|
||||
m_url_seeds.push_back(i->string());
|
||||
lazy_entry const* url = url_seeds->list_at(i);
|
||||
if (url->type() != lazy_entry::string_t) continue;
|
||||
m_url_seeds.push_back(url->string_value());
|
||||
}
|
||||
}
|
||||
|
||||
// extract comment
|
||||
if (entry const* e = torrent_file.find_key("comment.utf-8"))
|
||||
{ m_comment = e->string(); }
|
||||
else if (entry const* e = torrent_file.find_key("comment"))
|
||||
{ m_comment = e->string(); }
|
||||
m_comment = torrent_file.dict_find_string_value("comment.utf-8");
|
||||
if (m_comment.empty()) m_comment = torrent_file.dict_find_string_value("comment");
|
||||
|
||||
if (entry const* e = torrent_file.find_key("created by.utf-8"))
|
||||
{ m_created_by = e->string(); }
|
||||
else if (entry const* e = torrent_file.find_key("created by"))
|
||||
{ m_created_by = e->string(); }
|
||||
m_comment = torrent_file.dict_find_string_value("created by.utf-8");
|
||||
if (m_comment.empty()) m_comment = torrent_file.dict_find_string_value("created by");
|
||||
|
||||
entry const* info = torrent_file.find_key("info");
|
||||
if (info == 0 || info->type() != entry::dictionary_t)
|
||||
lazy_entry const* info = torrent_file.dict_find_dict("info");
|
||||
if (info == 0)
|
||||
{
|
||||
error = "missing or invalid 'info' section in torrent file";
|
||||
return false;
|
||||
|
@ -666,234 +612,6 @@ namespace libtorrent
|
|||
, bind(&announce_entry::tier, _1), bind(&announce_entry::tier, _2)));
|
||||
}
|
||||
|
||||
void torrent_info::add_file(fs::path file, size_type size)
|
||||
{
|
||||
// TORRENT_ASSERT(file.begin() != file.end());
|
||||
|
||||
if (!file.has_branch_path())
|
||||
{
|
||||
// you have already added at least one file with a
|
||||
// path to the file (branch_path), which means that
|
||||
// all the other files need to be in the same top
|
||||
// directory as the first file.
|
||||
TORRENT_ASSERT(m_files.empty());
|
||||
TORRENT_ASSERT(!m_multifile);
|
||||
m_name = file.string();
|
||||
}
|
||||
else
|
||||
{
|
||||
#ifndef NDEBUG
|
||||
if (!m_files.empty())
|
||||
TORRENT_ASSERT(m_name == *file.begin());
|
||||
#endif
|
||||
m_multifile = true;
|
||||
m_name = *file.begin();
|
||||
}
|
||||
|
||||
file_entry e;
|
||||
e.path = file;
|
||||
e.size = size;
|
||||
e.offset = m_files.empty() ? 0 : m_files.back().offset
|
||||
+ m_files.back().size;
|
||||
m_files.push_back(e);
|
||||
|
||||
m_total_size += size;
|
||||
|
||||
if (m_piece_length == 0)
|
||||
m_piece_length = 256 * 1024;
|
||||
|
||||
m_num_pieces = static_cast<int>(
|
||||
(m_total_size + m_piece_length - 1) / m_piece_length);
|
||||
int old_num_pieces = static_cast<int>(m_piece_hash.size());
|
||||
|
||||
m_piece_hash.resize(m_num_pieces);
|
||||
if (m_num_pieces > old_num_pieces)
|
||||
std::for_each(m_piece_hash.begin() + old_num_pieces
|
||||
, m_piece_hash.end(), boost::bind(&sha1_hash::clear, _1));
|
||||
}
|
||||
|
||||
void torrent_info::add_url_seed(std::string const& url)
|
||||
{
|
||||
m_url_seeds.push_back(url);
|
||||
}
|
||||
|
||||
void torrent_info::set_comment(char const* str)
|
||||
{
|
||||
m_comment = str;
|
||||
}
|
||||
|
||||
void torrent_info::set_creator(char const* str)
|
||||
{
|
||||
m_created_by = str;
|
||||
}
|
||||
|
||||
entry torrent_info::create_info_metadata() const
|
||||
{
|
||||
// you have to add files to the torrent first
|
||||
TORRENT_ASSERT(!m_files.empty());
|
||||
|
||||
entry info(m_extra_info);
|
||||
|
||||
if (!info.find_key("name"))
|
||||
info["name"] = m_name;
|
||||
|
||||
if (m_private) info["private"] = 1;
|
||||
|
||||
if (!m_multifile)
|
||||
{
|
||||
info["length"] = m_files.front().size;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!info.find_key("files"))
|
||||
{
|
||||
entry& files = info["files"];
|
||||
|
||||
for (std::vector<file_entry>::const_iterator i = m_files.begin();
|
||||
i != m_files.end(); ++i)
|
||||
{
|
||||
files.list().push_back(entry());
|
||||
entry& file_e = files.list().back();
|
||||
file_e["length"] = i->size;
|
||||
entry& path_e = file_e["path"];
|
||||
|
||||
fs::path const* file_path;
|
||||
if (i->orig_path) file_path = &(*i->orig_path);
|
||||
else file_path = &i->path;
|
||||
TORRENT_ASSERT(file_path->has_branch_path());
|
||||
TORRENT_ASSERT(*file_path->begin() == m_name);
|
||||
|
||||
for (fs::path::iterator j = boost::next(file_path->begin());
|
||||
j != file_path->end(); ++j)
|
||||
{
|
||||
path_e.list().push_back(entry(*j));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
info["piece length"] = piece_length();
|
||||
entry& pieces = info["pieces"];
|
||||
|
||||
std::string& p = pieces.string();
|
||||
|
||||
for (std::vector<sha1_hash>::const_iterator i = m_piece_hash.begin();
|
||||
i != m_piece_hash.end(); ++i)
|
||||
{
|
||||
p.append((char*)i->begin(), (char*)i->end());
|
||||
}
|
||||
|
||||
return info;
|
||||
}
|
||||
|
||||
entry torrent_info::create_torrent() const
|
||||
{
|
||||
TORRENT_ASSERT(m_piece_length > 0);
|
||||
|
||||
if (m_files.empty())
|
||||
{
|
||||
// TODO: throw something here
|
||||
// throw
|
||||
return entry();
|
||||
}
|
||||
|
||||
entry dict;
|
||||
|
||||
if (!m_urls.empty())
|
||||
dict["announce"] = m_urls.front().url;
|
||||
|
||||
if (!m_nodes.empty())
|
||||
{
|
||||
entry& nodes = dict["nodes"];
|
||||
entry::list_type& nodes_list = nodes.list();
|
||||
for (nodes_t::const_iterator i = m_nodes.begin()
|
||||
, end(m_nodes.end()); i != end; ++i)
|
||||
{
|
||||
entry::list_type node;
|
||||
node.push_back(entry(i->first));
|
||||
node.push_back(entry(i->second));
|
||||
nodes_list.push_back(entry(node));
|
||||
}
|
||||
}
|
||||
|
||||
if (m_urls.size() > 1)
|
||||
{
|
||||
entry trackers(entry::list_t);
|
||||
entry tier(entry::list_t);
|
||||
int current_tier = m_urls.front().tier;
|
||||
for (std::vector<announce_entry>::const_iterator i = m_urls.begin();
|
||||
i != m_urls.end(); ++i)
|
||||
{
|
||||
if (i->tier != current_tier)
|
||||
{
|
||||
current_tier = i->tier;
|
||||
trackers.list().push_back(tier);
|
||||
tier.list().clear();
|
||||
}
|
||||
tier.list().push_back(entry(i->url));
|
||||
}
|
||||
trackers.list().push_back(tier);
|
||||
dict["announce-list"] = trackers;
|
||||
}
|
||||
|
||||
if (!m_comment.empty())
|
||||
dict["comment"] = m_comment;
|
||||
|
||||
dict["creation date"] =
|
||||
(m_creation_date - pt::ptime(gr::date(1970, gr::Jan, 1))).total_seconds();
|
||||
|
||||
if (!m_created_by.empty())
|
||||
dict["created by"] = m_created_by;
|
||||
|
||||
if (!m_url_seeds.empty())
|
||||
{
|
||||
if (m_url_seeds.size() == 1)
|
||||
{
|
||||
dict["url-list"] = m_url_seeds.front();
|
||||
}
|
||||
else
|
||||
{
|
||||
entry& list = dict["url-list"];
|
||||
for (std::vector<std::string>::const_iterator i
|
||||
= m_url_seeds.begin(); i != m_url_seeds.end(); ++i)
|
||||
{
|
||||
list.list().push_back(entry(*i));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dict["info"] = create_info_metadata();
|
||||
|
||||
entry const& info_section = dict["info"];
|
||||
std::vector<char> buf;
|
||||
bencode(std::back_inserter(buf), info_section);
|
||||
m_info_hash = hasher(&buf[0], buf.size()).final();
|
||||
|
||||
return dict;
|
||||
}
|
||||
|
||||
void torrent_info::set_hash(int index, const sha1_hash& h)
|
||||
{
|
||||
TORRENT_ASSERT(index >= 0);
|
||||
TORRENT_ASSERT(index < (int)m_piece_hash.size());
|
||||
m_piece_hash[index] = h;
|
||||
}
|
||||
|
||||
void torrent_info::convert_file_names()
|
||||
{
|
||||
TORRENT_ASSERT(false);
|
||||
}
|
||||
|
||||
void torrent_info::seed_free()
|
||||
{
|
||||
std::vector<std::string>().swap(m_url_seeds);
|
||||
nodes_t().swap(m_nodes);
|
||||
std::vector<sha1_hash>().swap(m_piece_hash);
|
||||
#ifndef NDEBUG
|
||||
m_half_metadata = true;
|
||||
#endif
|
||||
}
|
||||
|
||||
// ------- start deprecation -------
|
||||
|
||||
void torrent_info::print(std::ostream& os) const
|
||||
|
@ -933,11 +651,6 @@ namespace libtorrent
|
|||
return piece_length();
|
||||
}
|
||||
|
||||
void torrent_info::add_node(std::pair<std::string, int> const& node)
|
||||
{
|
||||
m_nodes.push_back(node);
|
||||
}
|
||||
|
||||
bool torrent_info::remap_files(std::vector<file_entry> const& map)
|
||||
{
|
||||
size_type offset = 0;
|
||||
|
|
|
@ -54,7 +54,7 @@ POSSIBILITY OF SUCH DAMAGE.
|
|||
#include "libtorrent/bencode.hpp"
|
||||
#include "libtorrent/torrent.hpp"
|
||||
#include "libtorrent/extensions.hpp"
|
||||
#include "libtorrent/extensions/metadata_transfer.hpp"
|
||||
#include "libtorrent/extensions/ut_metadata.hpp"
|
||||
#include "libtorrent/alert_types.hpp"
|
||||
#ifdef TORRENT_STATS
|
||||
#include "libtorrent/aux_/session_impl.hpp"
|
||||
|
@ -89,39 +89,38 @@ namespace libtorrent { namespace
|
|||
virtual boost::shared_ptr<peer_plugin> new_connection(
|
||||
peer_connection* pc);
|
||||
|
||||
std::vector<char> const& metadata() const
|
||||
buffer::const_interval metadata() const
|
||||
{
|
||||
TORRENT_ASSERT(m_torrent.valid_metadata());
|
||||
|
||||
if (m_metadata.empty())
|
||||
if (!m_metadata)
|
||||
{
|
||||
bencode(std::back_inserter(m_metadata)
|
||||
, m_torrent.torrent_file().create_info_metadata());
|
||||
|
||||
TORRENT_ASSERT(hasher(&m_metadata[0], m_metadata.size()).final()
|
||||
m_metadata = m_torrent.torrent_file().metadata();
|
||||
m_metadata_size = m_torrent.torrent_file().metadata_size();
|
||||
TORRENT_ASSERT(hasher(m_metadata.get(), m_metadata_size).final()
|
||||
== m_torrent.torrent_file().info_hash());
|
||||
}
|
||||
TORRENT_ASSERT(!m_metadata.empty());
|
||||
return m_metadata;
|
||||
return buffer::const_interval(m_metadata.get(), m_metadata.get()
|
||||
+ m_metadata_size);
|
||||
}
|
||||
|
||||
bool received_metadata(char const* buf, int size, int piece, int total_size)
|
||||
{
|
||||
if (m_torrent.valid_metadata()) return false;
|
||||
|
||||
if (m_metadata.empty())
|
||||
if (!m_metadata)
|
||||
{
|
||||
// verify the total_size
|
||||
if (total_size <= 0 || total_size > 500 * 1024) return false;
|
||||
|
||||
m_metadata.resize(total_size);
|
||||
m_metadata.reset(new char[total_size]);
|
||||
m_requested_metadata.resize(div_round_up(total_size, 16 * 1024), 0);
|
||||
m_metadata_size = total_size;
|
||||
}
|
||||
|
||||
if (piece < 0 || piece >= int(m_requested_metadata.size()))
|
||||
return false;
|
||||
|
||||
TORRENT_ASSERT(piece * 16 * 1024 + size <= int(m_metadata.size()));
|
||||
TORRENT_ASSERT(piece * 16 * 1024 + size <= m_metadata_size);
|
||||
std::memcpy(&m_metadata[piece * 16 * 1024], buf, size);
|
||||
// mark this piece has 'have'
|
||||
m_requested_metadata[piece] = (std::numeric_limits<int>::max)();
|
||||
|
@ -133,7 +132,7 @@ namespace libtorrent { namespace
|
|||
if (!have_all) return false;
|
||||
|
||||
hasher h;
|
||||
h.update(&m_metadata[0], (int)m_metadata.size());
|
||||
h.update(&m_metadata[0], m_metadata_size);
|
||||
sha1_hash info_hash = h.final();
|
||||
|
||||
if (info_hash != m_torrent.torrent_file().info_hash())
|
||||
|
@ -149,7 +148,8 @@ namespace libtorrent { namespace
|
|||
return false;
|
||||
}
|
||||
|
||||
entry metadata = bdecode(m_metadata.begin(), m_metadata.end());
|
||||
lazy_entry metadata;
|
||||
int ret = lazy_bdecode(m_metadata.get(), m_metadata.get() + m_metadata_size, metadata);
|
||||
std::string error;
|
||||
if (!m_torrent.set_metadata(metadata, error))
|
||||
{
|
||||
|
@ -191,7 +191,7 @@ namespace libtorrent { namespace
|
|||
{
|
||||
if (m_metadata_size > 0 || size <= 0 || size > 500 * 1024) return;
|
||||
m_metadata_size = size;
|
||||
m_metadata.resize(size);
|
||||
m_metadata.reset(new char[size]);
|
||||
m_requested_metadata.resize(div_round_up(size, 16 * 1024), 0);
|
||||
}
|
||||
|
||||
|
@ -202,10 +202,10 @@ namespace libtorrent { namespace
|
|||
// the metadata file while downloading it from
|
||||
// peers, and while sending it.
|
||||
// it is mutable because it's generated lazily
|
||||
mutable std::vector<char> m_metadata;
|
||||
mutable boost::shared_array<char> m_metadata;
|
||||
|
||||
int m_metadata_progress;
|
||||
int m_metadata_size;
|
||||
mutable int m_metadata_size;
|
||||
|
||||
// this vector keeps track of how many times each meatdata
|
||||
// block has been requested
|
||||
|
@ -231,7 +231,7 @@ namespace libtorrent { namespace
|
|||
entry& messages = h["m"];
|
||||
messages["ut_metadata"] = 15;
|
||||
if (m_torrent.valid_metadata())
|
||||
h["metadata_size"] = m_tp.metadata().size();
|
||||
h["metadata_size"] = m_tp.metadata().left();
|
||||
}
|
||||
|
||||
// called when the extension handshake from the other end is received
|
||||
|
@ -273,14 +273,14 @@ namespace libtorrent { namespace
|
|||
if (type == 1)
|
||||
{
|
||||
TORRENT_ASSERT(m_pc.associated_torrent().lock()->valid_metadata());
|
||||
e["total_size"] = m_tp.metadata().size();
|
||||
e["total_size"] = m_tp.metadata().left();
|
||||
int offset = piece * 16 * 1024;
|
||||
metadata = &m_tp.metadata()[0] + offset;
|
||||
metadata = m_tp.metadata().begin + offset;
|
||||
metadata_piece_size = (std::min)(
|
||||
int(m_tp.metadata().size() - offset), 16 * 1024);
|
||||
int(m_tp.metadata().left() - offset), 16 * 1024);
|
||||
TORRENT_ASSERT(metadata_piece_size > 0);
|
||||
TORRENT_ASSERT(offset >= 0);
|
||||
TORRENT_ASSERT(offset + metadata_piece_size <= int(m_tp.metadata().size()));
|
||||
TORRENT_ASSERT(offset + metadata_piece_size <= int(m_tp.metadata().left()));
|
||||
}
|
||||
|
||||
char msg[200];
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
#include "test.hpp"
|
||||
#include "libtorrent/assert.hpp"
|
||||
#include "libtorrent/alert_types.hpp"
|
||||
#include "libtorrent/create_torrent.hpp"
|
||||
|
||||
using boost::filesystem::remove_all;
|
||||
using boost::filesystem::create_directory;
|
||||
|
@ -102,7 +103,7 @@ void start_web_server(int port, bool ssl)
|
|||
<< (ssl?"https":"http") << "://127.0.0.1:" << port << "/infinite_redirect\")\n"
|
||||
"$HTTP[\"url\"] == \"/test_file.gz\" {\n"
|
||||
" setenv.add-response-header = ( \"Content-Encoding\" => \"gzip\" )\n"
|
||||
" mimetype.assign = ()\n"
|
||||
"# mimetype.assign = ()\n"
|
||||
"}\n";
|
||||
// this requires lighttpd to be built with ssl support.
|
||||
// The port distribution for mac is not built with ssl
|
||||
|
@ -168,22 +169,21 @@ boost::intrusive_ptr<torrent_info> create_torrent(std::ostream* file)
|
|||
|
||||
using namespace boost::filesystem;
|
||||
|
||||
boost::intrusive_ptr<torrent_info> t(new torrent_info);
|
||||
libtorrent::create_torrent t;
|
||||
int total_size = 2 * 1024 * 1024;
|
||||
t->add_file(path("temporary"), total_size);
|
||||
t->set_piece_size(16 * 1024);
|
||||
t->add_tracker(tracker_url);
|
||||
t.add_file(path("temporary"), total_size);
|
||||
t.set_piece_size(16 * 1024);
|
||||
t.add_tracker(tracker_url);
|
||||
|
||||
std::vector<char> piece(16 * 1024);
|
||||
for (int i = 0; i < int(piece.size()); ++i)
|
||||
piece[i] = (i % 26) + 'A';
|
||||
|
||||
// calculate the hash for all pieces
|
||||
int num = t->num_pieces();
|
||||
int num = t.num_pieces();
|
||||
sha1_hash ph = hasher(&piece[0], piece.size()).final();
|
||||
for (int i = 0; i < num; ++i)
|
||||
t->set_hash(i, ph);
|
||||
t->create_torrent();
|
||||
t.set_hash(i, ph);
|
||||
|
||||
if (file)
|
||||
{
|
||||
|
@ -194,7 +194,10 @@ boost::intrusive_ptr<torrent_info> create_torrent(std::ostream* file)
|
|||
}
|
||||
}
|
||||
|
||||
return t;
|
||||
std::vector<char> tmp;
|
||||
std::back_insert_iterator<std::vector<char> > out(tmp);
|
||||
bencode(out, t.generate());
|
||||
return boost::intrusive_ptr<torrent_info>(new torrent_info(&tmp[0], tmp.size()));
|
||||
}
|
||||
|
||||
boost::tuple<torrent_handle, torrent_handle, torrent_handle>
|
||||
|
@ -214,7 +217,7 @@ setup_transfer(session* ses1, session* ses2, session* ses3
|
|||
|
||||
create_directory("./tmp1" + suffix);
|
||||
std::ofstream file(("./tmp1" + suffix + "/temporary").c_str());
|
||||
boost::intrusive_ptr<torrent_info> t = create_torrent(&file);
|
||||
boost::intrusive_ptr<torrent_info> t = ::create_torrent(&file);
|
||||
file.close();
|
||||
if (clear_files)
|
||||
{
|
||||
|
|
|
@ -127,7 +127,7 @@ void do_handshake(stream_socket& s, sha1_hash const& ih, char* buffer)
|
|||
// rejected aren't requested again
|
||||
void test_reject_fast()
|
||||
{
|
||||
boost::intrusive_ptr<torrent_info> t = create_torrent();
|
||||
boost::intrusive_ptr<torrent_info> t = ::create_torrent();
|
||||
sha1_hash ih = t->info_hash();
|
||||
session ses1(fingerprint("LT", 0, 1, 0, 0), std::make_pair(48900, 49000));
|
||||
ses1.add_torrent(t, "./tmp1");
|
||||
|
@ -190,7 +190,7 @@ void test_reject_fast()
|
|||
|
||||
void test_respect_suggest()
|
||||
{
|
||||
boost::intrusive_ptr<torrent_info> t = create_torrent();
|
||||
boost::intrusive_ptr<torrent_info> t = ::create_torrent();
|
||||
sha1_hash ih = t->info_hash();
|
||||
session ses1(fingerprint("LT", 0, 1, 0, 0), std::make_pair(48900, 49000));
|
||||
ses1.add_torrent(t, "./tmp1");
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
#include "libtorrent/session.hpp"
|
||||
#include "libtorrent/alert_types.hpp"
|
||||
#include "libtorrent/aux_/session_impl.hpp"
|
||||
#include "libtorrent/create_torrent.hpp"
|
||||
|
||||
#include <boost/utility.hpp>
|
||||
#include <boost/filesystem/operations.hpp>
|
||||
|
@ -18,6 +19,20 @@ using namespace boost::filesystem;
|
|||
|
||||
const int piece_size = 16;
|
||||
|
||||
const int half = piece_size / 2;
|
||||
|
||||
char piece0[piece_size] =
|
||||
{ 6, 6, 6, 6, 6, 6, 6, 6
|
||||
, 9, 9, 9, 9, 9, 9, 9, 9};
|
||||
|
||||
char piece1[piece_size] =
|
||||
{ 0, 0, 0, 0, 0, 0, 0, 0
|
||||
, 1, 1, 1, 1, 1, 1, 1, 1};
|
||||
|
||||
char piece2[piece_size] =
|
||||
{ 0, 0, 1, 0, 0, 0, 0, 0
|
||||
, 1, 1, 1, 1, 1, 1, 1, 1};
|
||||
|
||||
void on_read_piece(int ret, disk_io_job const& j, char const* data, int size)
|
||||
{
|
||||
std::cerr << "on_read_piece piece: " << j.piece << std::endl;
|
||||
|
@ -39,26 +54,6 @@ void run_storage_tests(boost::intrusive_ptr<torrent_info> info
|
|||
, path const& test_path
|
||||
, libtorrent::storage_mode_t storage_mode)
|
||||
{
|
||||
const int half = piece_size / 2;
|
||||
|
||||
char piece0[piece_size] =
|
||||
{ 6, 6, 6, 6, 6, 6, 6, 6
|
||||
, 9, 9, 9, 9, 9, 9, 9, 9};
|
||||
|
||||
char piece1[piece_size] =
|
||||
{ 0, 0, 0, 0, 0, 0, 0, 0
|
||||
, 1, 1, 1, 1, 1, 1, 1, 1};
|
||||
|
||||
char piece2[piece_size] =
|
||||
{ 0, 0, 1, 0, 0, 0, 0, 0
|
||||
, 1, 1, 1, 1, 1, 1, 1, 1};
|
||||
|
||||
info->set_hash(0, hasher(piece0, piece_size).final());
|
||||
info->set_hash(1, hasher(piece1, piece_size).final());
|
||||
info->set_hash(2, hasher(piece2, piece_size).final());
|
||||
|
||||
info->create_torrent();
|
||||
|
||||
create_directory(test_path / "temp_storage");
|
||||
|
||||
int num_pieces = (1 + 612 + 17 + piece_size - 1) / piece_size;
|
||||
|
@ -105,10 +100,11 @@ void run_storage_tests(boost::intrusive_ptr<torrent_info> info
|
|||
|
||||
entry frd;
|
||||
pm->async_check_fastresume(&frd, &on_check_resume_data);
|
||||
test_sleep(2000);
|
||||
ios.run();
|
||||
|
||||
pm->async_check_files(&on_check_files);
|
||||
test_sleep(2000);
|
||||
for (int i = 0; i < 4; ++i)
|
||||
ios.run_one();
|
||||
|
||||
boost::function<void(int, disk_io_job const&)> none;
|
||||
TEST_CHECK(exists(test_path / "temp_storage"));
|
||||
|
@ -140,19 +136,19 @@ void run_storage_tests(boost::intrusive_ptr<torrent_info> info
|
|||
|
||||
void test_remove(path const& test_path)
|
||||
{
|
||||
boost::intrusive_ptr<torrent_info> info(new torrent_info());
|
||||
info->set_piece_size(4);
|
||||
info->add_file("temp_storage/test1.tmp", 8);
|
||||
info->add_file("temp_storage/folder1/test2.tmp", 8);
|
||||
info->add_file("temp_storage/folder2/test3.tmp", 0);
|
||||
info->add_file("temp_storage/_folder3/test4.tmp", 0);
|
||||
info->add_file("temp_storage/_folder3/subfolder/test5.tmp", 8);
|
||||
libtorrent::create_torrent t;
|
||||
t.set_piece_size(4);
|
||||
t.add_file("temp_storage/test1.tmp", 8);
|
||||
t.add_file("temp_storage/folder1/test2.tmp", 8);
|
||||
t.add_file("temp_storage/folder2/test3.tmp", 0);
|
||||
t.add_file("temp_storage/_folder3/test4.tmp", 0);
|
||||
t.add_file("temp_storage/_folder3/subfolder/test5.tmp", 8);
|
||||
|
||||
char buf[4] = {0, 0, 0, 0};
|
||||
sha1_hash h = hasher(buf, 4).final();
|
||||
for (int i = 0; i < 6; ++i) info->set_hash(i, h);
|
||||
for (int i = 0; i < 6; ++i) t.set_hash(i, h);
|
||||
|
||||
info->create_torrent();
|
||||
boost::intrusive_ptr<torrent_info> info(new torrent_info(t.generate()));
|
||||
|
||||
file_pool fp;
|
||||
boost::scoped_ptr<storage_interface> s(
|
||||
|
@ -173,14 +169,23 @@ void run_test(path const& test_path)
|
|||
{
|
||||
std::cerr << "\n=== " << test_path.string() << " ===\n" << std::endl;
|
||||
|
||||
boost::intrusive_ptr<torrent_info> info(new torrent_info());
|
||||
info->set_piece_size(piece_size);
|
||||
info->add_file("temp_storage/test1.tmp", 17);
|
||||
info->add_file("temp_storage/test2.tmp", 612);
|
||||
info->add_file("temp_storage/test3.tmp", 0);
|
||||
info->add_file("temp_storage/test4.tmp", 0);
|
||||
info->add_file("temp_storage/test5.tmp", 1);
|
||||
boost::intrusive_ptr<torrent_info> info;
|
||||
|
||||
{
|
||||
libtorrent::create_torrent t;
|
||||
t.set_piece_size(piece_size);
|
||||
t.add_file("temp_storage/test1.tmp", 17);
|
||||
t.add_file("temp_storage/test2.tmp", 612);
|
||||
t.add_file("temp_storage/test3.tmp", 0);
|
||||
t.add_file("temp_storage/test4.tmp", 0);
|
||||
t.add_file("temp_storage/test5.tmp", 1);
|
||||
|
||||
t.set_hash(0, hasher(piece0, piece_size).final());
|
||||
t.set_hash(1, hasher(piece1, piece_size).final());
|
||||
t.set_hash(2, hasher(piece2, piece_size).final());
|
||||
|
||||
|
||||
info = new torrent_info(t.generate());
|
||||
std::cerr << "=== test 1 ===" << std::endl;
|
||||
|
||||
run_storage_tests(info, test_path, storage_mode_compact);
|
||||
|
@ -193,6 +198,7 @@ void run_test(path const& test_path)
|
|||
TEST_CHECK(exists(test_path / "temp_storage/test3.tmp"));
|
||||
TEST_CHECK(exists(test_path / "temp_storage/test4.tmp"));
|
||||
remove_all(test_path / "temp_storage");
|
||||
}
|
||||
|
||||
// ==============================================
|
||||
|
||||
|
@ -221,10 +227,15 @@ void run_test(path const& test_path)
|
|||
remove_all(test_path / "temp_storage");
|
||||
|
||||
// ==============================================
|
||||
|
||||
info = new torrent_info();
|
||||
info->set_piece_size(piece_size);
|
||||
info->add_file("temp_storage/test1.tmp", 17 + 612 + 1);
|
||||
|
||||
{
|
||||
libtorrent::create_torrent t;
|
||||
t.set_piece_size(piece_size);
|
||||
t.add_file("temp_storage/test1.tmp", 17 + 612 + 1);
|
||||
t.set_hash(0, hasher(piece0, piece_size).final());
|
||||
t.set_hash(1, hasher(piece1, piece_size).final());
|
||||
t.set_hash(2, hasher(piece2, piece_size).final());
|
||||
info = new torrent_info(t.generate());
|
||||
|
||||
std::cerr << "=== test 3 ===" << std::endl;
|
||||
|
||||
|
@ -233,6 +244,7 @@ void run_test(path const& test_path)
|
|||
// 48 = piece_size * 3
|
||||
TEST_CHECK(file_size(test_path / "temp_storage" / "test1.tmp") == 48);
|
||||
remove_all(test_path / "temp_storage");
|
||||
}
|
||||
|
||||
// ==============================================
|
||||
|
||||
|
@ -258,7 +270,7 @@ void test_fastresume()
|
|||
std::cout << "=== test fastresume ===" << std::endl;
|
||||
create_directory("tmp1");
|
||||
std::ofstream file("tmp1/temporary");
|
||||
boost::intrusive_ptr<torrent_info> t = create_torrent(&file);
|
||||
boost::intrusive_ptr<torrent_info> t = ::create_torrent(&file);
|
||||
file.close();
|
||||
TEST_CHECK(exists("tmp1/temporary"));
|
||||
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
#include "libtorrent/file_pool.hpp"
|
||||
#include "libtorrent/storage.hpp"
|
||||
#include "libtorrent/bencode.hpp"
|
||||
#include "libtorrent/create_torrent.hpp"
|
||||
#include <boost/thread.hpp>
|
||||
#include <boost/tuple/tuple.hpp>
|
||||
#include <boost/filesystem/operations.hpp>
|
||||
|
@ -14,10 +15,7 @@
|
|||
using namespace boost::filesystem;
|
||||
using namespace libtorrent;
|
||||
|
||||
void add_files(
|
||||
torrent_info& t
|
||||
, path const& p
|
||||
, path const& l)
|
||||
void add_files(libtorrent::create_torrent& t, path const& p, path const& l)
|
||||
{
|
||||
if (l.leaf()[0] == '.') return;
|
||||
path f(p / l);
|
||||
|
@ -34,7 +32,7 @@ void add_files(
|
|||
}
|
||||
|
||||
// proxy: 0=none, 1=socks4, 2=socks5, 3=socks5_pw 4=http 5=http_pw
|
||||
void test_transfer(torrent_info torrent_file, int proxy)
|
||||
void test_transfer(boost::intrusive_ptr<torrent_info> torrent_file, int proxy)
|
||||
{
|
||||
using namespace libtorrent;
|
||||
|
||||
|
@ -59,7 +57,7 @@ void test_transfer(torrent_info torrent_file, int proxy)
|
|||
ses.set_web_seed_proxy(ps);
|
||||
}
|
||||
|
||||
torrent_handle th = ses.add_torrent(torrent_file, "./tmp1");
|
||||
torrent_handle th = ses.add_torrent(*torrent_file, "./tmp1");
|
||||
|
||||
std::vector<announce_entry> empty;
|
||||
th.replace_trackers(empty);
|
||||
|
@ -89,8 +87,8 @@ int test_main()
|
|||
using namespace libtorrent;
|
||||
using namespace boost::filesystem;
|
||||
|
||||
boost::intrusive_ptr<torrent_info> torrent_file(new torrent_info);
|
||||
torrent_file->add_url_seed("http://127.0.0.1:8000/");
|
||||
libtorrent::create_torrent t;
|
||||
t.add_url_seed("http://127.0.0.1:8000/");
|
||||
|
||||
create_directory("test_torrent");
|
||||
char random_data[300000];
|
||||
|
@ -104,31 +102,32 @@ int test_main()
|
|||
std::ofstream("./test_torrent/test6").write(random_data, 300000);
|
||||
std::ofstream("./test_torrent/test7").write(random_data, 300000);
|
||||
|
||||
add_files(*torrent_file, complete("."), "test_torrent");
|
||||
add_files(t, complete("."), "test_torrent");
|
||||
|
||||
start_web_server(8000);
|
||||
|
||||
// calculate the hash for all pieces
|
||||
int num = t.num_pieces();
|
||||
std::vector<char> buf(t.piece_length());
|
||||
|
||||
file_pool fp;
|
||||
boost::intrusive_ptr<torrent_info> torrent_file(new torrent_info(t.generate()));
|
||||
boost::scoped_ptr<storage_interface> s(default_storage_constructor(
|
||||
torrent_file, ".", fp));
|
||||
// calculate the hash for all pieces
|
||||
int num = torrent_file->num_pieces();
|
||||
std::vector<char> buf(torrent_file->piece_length());
|
||||
|
||||
for (int i = 0; i < num; ++i)
|
||||
{
|
||||
s->read(&buf[0], i, 0, torrent_file->piece_size(i));
|
||||
hasher h(&buf[0], torrent_file->piece_size(i));
|
||||
torrent_file->set_hash(i, h.final());
|
||||
s->read(&buf[0], i, 0, t.piece_size(i));
|
||||
hasher h(&buf[0], t.piece_size(i));
|
||||
t.set_hash(i, h.final());
|
||||
}
|
||||
|
||||
// to calculate the info_hash
|
||||
entry te = torrent_file->create_torrent();
|
||||
|
||||
entry e = t.generate();
|
||||
torrent_file = new torrent_info(e);
|
||||
s.reset(default_storage_constructor(torrent_file, ".", fp));
|
||||
|
||||
for (int i = 0; i < 6; ++i)
|
||||
test_transfer(*torrent_file, i);
|
||||
|
||||
|
||||
test_transfer(torrent_file, i);
|
||||
|
||||
stop_web_server(8000);
|
||||
remove_all("./test_torrent");
|
||||
|
|
Loading…
Reference in New Issue