From 8ed949c4d5c4d61ab8863c9569735827d90e255e Mon Sep 17 00:00:00 2001 From: Arvid Norberg Date: Wed, 14 May 2008 05:29:42 +0000 Subject: [PATCH] factored out torrent creation functionality from torrent_info into create_torrent. Modified torrent_info to use lazy_bdecoder for increased performance --- Jamfile | 1 + docs/manual.rst | 104 +---- examples/dump_torrent.cpp | 31 +- include/Makefile.am | 1 + include/libtorrent/create_torrent.hpp | 140 ++++++ include/libtorrent/torrent.hpp | 2 +- include/libtorrent/torrent_info.hpp | 102 ++--- src/Makefile.am | 3 +- src/create_torrent.cpp | 303 +++++++++++++ src/metadata_transfer.cpp | 57 ++- src/session.cpp | 2 - src/torrent.cpp | 7 +- src/torrent_info.cpp | 609 +++++++------------------- src/ut_metadata.cpp | 46 +- test/setup_transfer.cpp | 23 +- test/test_fast_extension.cpp | 4 +- test/test_storage.cpp | 98 +++-- test/test_web_seed.cpp | 41 +- 18 files changed, 847 insertions(+), 727 deletions(-) create mode 100644 include/libtorrent/create_torrent.hpp create mode 100644 src/create_torrent.cpp diff --git a/Jamfile b/Jamfile index 12a493170..f4604eef5 100755 --- a/Jamfile +++ b/Jamfile @@ -257,6 +257,7 @@ SOURCES = alert assert connection_queue + create_torrent disk_buffer_holder entry lazy_bdecode diff --git a/docs/manual.rst b/docs/manual.rst index 372715846..bfe284227 100644 --- a/docs/manual.rst +++ b/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::const_iterator file_iterator; typedef std::vector::const_reverse_iterator @@ -1122,7 +1115,6 @@ The ``torrent_info`` has the following synopsis:: std::vector const& trackers() const; bool priv() const; - void set_priv(bool v); std::vector 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 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 const& node); + boost::shared_array 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 diff --git a/examples/dump_torrent.cpp b/examples/dump_torrent.cpp index d41909490..8e040ac44 100644 --- a/examples/dump_torrent.cpp +++ b/examples/dump_torrent.cpp @@ -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 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(in), std::istream_iterator()); + + int size = file_size(argv[1]); + if (size > 10 * 1000000) + { + std::cerr << "file too big (" << size << "), aborting\n"; + return 1; + } + std::vector 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) diff --git a/include/Makefile.am b/include/Makefile.am index 44bc5b732..9ebcf2723 100644 --- a/include/Makefile.am +++ b/include/Makefile.am @@ -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 \ diff --git a/include/libtorrent/create_torrent.hpp b/include/libtorrent/create_torrent.hpp new file mode 100644 index 000000000..c97174d4c --- /dev/null +++ b/include/libtorrent/create_torrent.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 +#include +#include + +#ifdef _MSC_VER +#pragma warning(push, 1) +#endif + +#include +#include +#include + +#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 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 announce_entry; + std::vector m_urls; + + std::vector m_url_seeds; + + std::vector 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 file_entry; + // the list of files that this torrent consists of + std::vector m_files; + + // dht nodes to add to the routing table/bootstrap from + typedef std::vector > 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 + diff --git a/include/libtorrent/torrent.hpp b/include/libtorrent/torrent.hpp index b30d6050e..cda543feb 100755 --- a/include/libtorrent/torrent.hpp +++ b/include/libtorrent/torrent.hpp @@ -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; } diff --git a/include/libtorrent/torrent_info.hpp b/include/libtorrent/torrent_info.hpp index 83873c17f..8941db194 100755 --- a/include/libtorrent/torrent_info.hpp +++ b/include/libtorrent/torrent_info.hpp @@ -45,12 +45,14 @@ POSSIBILITY OF SUCH DAMAGE. #include #include #include +#include #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 const& map); @@ -132,10 +127,9 @@ namespace libtorrent , bool storage = false) const; std::vector 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::const_iterator file_iterator; typedef std::vector::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& trackers() const { return m_urls; } + std::vector 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 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 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 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 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 m_piece_hash; - // the list of files that this torrent consists of std::vector 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 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; }; } diff --git a/src/Makefile.am b/src/Makefile.am index bcbfc7eb2..568198fc2 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -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 \ diff --git a/src/create_torrent.cpp b/src/create_torrent.cpp new file mode 100644 index 000000000..8d408fe2c --- /dev/null +++ b/src/create_torrent.cpp @@ -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 +#include +#include + +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::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::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::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::const_iterator i = m_piece_hash.begin(); + i != m_piece_hash.end(); ++i) + { + p.append((char*)i->begin(), (char*)i->end()); + } + + std::vector 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( + (m_total_size + m_piece_length - 1) / m_piece_length); + int old_num_pieces = static_cast(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 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; + } +} + diff --git a/src/metadata_transfer.cpp b/src/metadata_transfer.cpp index f5dcab181..8938cfb7b 100644 --- a/src/metadata_transfer.cpp +++ b/src/metadata_transfer.cpp @@ -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 new_connection( peer_connection* pc); - std::vector 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 m_metadata; + mutable boost::shared_array 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 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 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); } diff --git a/src/session.cpp b/src/session.cpp index f6ee4a2bb..bfceb7024 100755 --- a/src/session.cpp +++ b/src/session.cpp @@ -253,7 +253,6 @@ namespace libtorrent , bool paused , storage_constructor_type sc) { - TORRENT_ASSERT(!ti.m_half_metadata); boost::intrusive_ptr 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; diff --git a/src/torrent.cpp b/src/torrent.cpp index 2844d1317..c1bacf534 100755 --- a/src/torrent.cpp +++ b/src/torrent.cpp @@ -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) diff --git a/src/torrent_info.cpp b/src/torrent_info.cpp index c6e2e0e8c..60558b1b1 100755 --- a/src/torrent_info.cpp +++ b/src/torrent_info.cpp @@ -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& target + bool extract_files(lazy_entry const& list, std::vector& 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 tmp; + std::back_insert_iterator > 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 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( - (m_total_size + m_piece_length - 1) / m_piece_length); - int old_num_pieces = static_cast(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 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 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((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((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 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( - (m_total_size + m_piece_length - 1) / m_piece_length); - int old_num_pieces = static_cast(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::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::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::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::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 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().swap(m_url_seeds); - nodes_t().swap(m_nodes); - std::vector().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 const& node) - { - m_nodes.push_back(node); - } - bool torrent_info::remap_files(std::vector const& map) { size_type offset = 0; diff --git a/src/ut_metadata.cpp b/src/ut_metadata.cpp index 4cefcdc7c..f92fa88d4 100644 --- a/src/ut_metadata.cpp +++ b/src/ut_metadata.cpp @@ -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 new_connection( peer_connection* pc); - std::vector 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::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 m_metadata; + mutable boost::shared_array 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]; diff --git a/test/setup_transfer.cpp b/test/setup_transfer.cpp index a59f8637b..f68508f45 100644 --- a/test/setup_transfer.cpp +++ b/test/setup_transfer.cpp @@ -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 create_torrent(std::ostream* file) using namespace boost::filesystem; - boost::intrusive_ptr 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 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 create_torrent(std::ostream* file) } } - return t; + std::vector tmp; + std::back_insert_iterator > out(tmp); + bencode(out, t.generate()); + return boost::intrusive_ptr(new torrent_info(&tmp[0], tmp.size())); } boost::tuple @@ -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 t = create_torrent(&file); + boost::intrusive_ptr t = ::create_torrent(&file); file.close(); if (clear_files) { diff --git a/test/test_fast_extension.cpp b/test/test_fast_extension.cpp index 8e23592ee..cf1855884 100644 --- a/test/test_fast_extension.cpp +++ b/test/test_fast_extension.cpp @@ -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 t = create_torrent(); + boost::intrusive_ptr 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 t = create_torrent(); + boost::intrusive_ptr 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"); diff --git a/test/test_storage.cpp b/test/test_storage.cpp index adeb5f792..e2e72d1f4 100644 --- a/test/test_storage.cpp +++ b/test/test_storage.cpp @@ -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 #include @@ -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 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 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 none; TEST_CHECK(exists(test_path / "temp_storage")); @@ -140,19 +136,19 @@ void run_storage_tests(boost::intrusive_ptr info void test_remove(path const& test_path) { - boost::intrusive_ptr 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 info(new torrent_info(t.generate())); file_pool fp; boost::scoped_ptr s( @@ -173,14 +169,23 @@ void run_test(path const& test_path) { std::cerr << "\n=== " << test_path.string() << " ===\n" << std::endl; - boost::intrusive_ptr 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 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 t = create_torrent(&file); + boost::intrusive_ptr t = ::create_torrent(&file); file.close(); TEST_CHECK(exists("tmp1/temporary")); diff --git a/test/test_web_seed.cpp b/test/test_web_seed.cpp index 11b7103cf..0e3b6b8ca 100644 --- a/test/test_web_seed.cpp +++ b/test/test_web_seed.cpp @@ -3,6 +3,7 @@ #include "libtorrent/file_pool.hpp" #include "libtorrent/storage.hpp" #include "libtorrent/bencode.hpp" +#include "libtorrent/create_torrent.hpp" #include #include #include @@ -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_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 empty; th.replace_trackers(empty); @@ -89,8 +87,8 @@ int test_main() using namespace libtorrent; using namespace boost::filesystem; - boost::intrusive_ptr 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 buf(t.piece_length()); + file_pool fp; + boost::intrusive_ptr torrent_file(new torrent_info(t.generate())); boost::scoped_ptr s(default_storage_constructor( torrent_file, ".", fp)); - // calculate the hash for all pieces - int num = torrent_file->num_pieces(); - std::vector 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");