diff --git a/CMakeLists.txt b/CMakeLists.txt index c993d8221..37befa0ca 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -13,6 +13,7 @@ set(sources bandwidth_limit bandwidth_manager bandwidth_queue_entry + bdecode block_cache bloom_filter chained_buffer diff --git a/ChangeLog b/ChangeLog index 5c71ae0f6..ec94b2b57 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,4 @@ + * replaced lazy_bdecode with a new bdecoder that's a lot more efficient * deprecate time functions, expose typedefs of boost::chrono in the libtorrent namespace instead * deprecate file_base feature in file_storage/torrent_info diff --git a/Jamfile b/Jamfile index fa1cf8e6a..e347272a2 100755 --- a/Jamfile +++ b/Jamfile @@ -529,6 +529,7 @@ SOURCES = bandwidth_limit bandwidth_manager bandwidth_queue_entry + bdecode block_cache bloom_filter chained_buffer diff --git a/bindings/python/src/error_code.cpp b/bindings/python/src/error_code.cpp index 466f9b7ba..101baa59e 100644 --- a/bindings/python/src/error_code.cpp +++ b/bindings/python/src/error_code.cpp @@ -32,7 +32,7 @@ POSSIBILITY OF SUCH DAMAGE. #include #include -#include +#include #include #include diff --git a/bindings/python/src/session.cpp b/bindings/python/src/session.cpp index 2a8a8460c..b33b73663 100644 --- a/bindings/python/src/session.cpp +++ b/bindings/python/src/session.cpp @@ -12,7 +12,7 @@ #include #include #include -#include +#include #include #include // for settings_map() @@ -486,9 +486,9 @@ namespace std::vector buf; bencode(std::back_inserter(buf), st); - lazy_entry e; + bdecode_node e; error_code ec; - lazy_bdecode(&buf[0], &buf[0] + buf.size(), e, ec); + bdecode(&buf[0], &buf[0] + buf.size(), e, ec); TORRENT_ASSERT(!ec); ses.load_state(e); } diff --git a/docs/gen_reference_doc.py b/docs/gen_reference_doc.py index 036c7be97..0c7072465 100644 --- a/docs/gen_reference_doc.py +++ b/docs/gen_reference_doc.py @@ -82,6 +82,7 @@ category_mapping = { 'alert_types.hpp': 'Alerts', 'bencode.hpp': 'Bencoding', 'lazy_entry.hpp': 'Bencoding', + 'bdecode.hpp': 'Bdecoding', 'entry.hpp': 'Bencoding', 'time.hpp': 'Time', 'escape_string.hpp': 'String', diff --git a/docs/makefile b/docs/makefile index 7293b14dd..093049601 100644 --- a/docs/makefile +++ b/docs/makefile @@ -85,8 +85,8 @@ $(REFERENCE_TARGETS:=.rst):gen_reference_doc.py ../include/libtorrent/*.hpp ../i rst2pdf $? -o $@ --stylesheets stylesheet %.html:%.rst - rst2html-2.6.py --template=template.txt --stylesheet-path=style.css --link-stylesheet --no-toc-backlinks $? > $@ - rst2html-2.6.py --template=template2.txt --stylesheet-path=style.css --link-stylesheet --no-toc-backlinks $? > $(WEB_PATH)/$@ + rst2html-3.4.py --template=template.txt --stylesheet-path=style.css --link-stylesheet --no-toc-backlinks $? > $@ + rst2html-3.4.py --template=template2.txt --stylesheet-path=style.css --link-stylesheet --no-toc-backlinks $? > $(WEB_PATH)/$@ %.png:%.dot dot -Tpng $? >$@ diff --git a/examples/client_test.cpp b/examples/client_test.cpp index f227099d0..3e043cfbe 100644 --- a/examples/client_test.cpp +++ b/examples/client_test.cpp @@ -64,7 +64,7 @@ POSSIBILITY OF SUCH DAMAGE. #include "libtorrent/magnet_uri.hpp" #include "libtorrent/bitfield.hpp" #include "libtorrent/peer_info.hpp" -#include "libtorrent/lazy_entry.hpp" +#include "libtorrent/bdecode.hpp" #include "libtorrent/add_torrent_params.hpp" #include "libtorrent/time.hpp" #include "libtorrent/create_torrent.hpp" @@ -697,7 +697,6 @@ void add_torrent(libtorrent::session& ses if (seed_mode) p.flags |= add_torrent_params::flag_seed_mode; if (disable_storage) p.storage = disabled_storage_constructor; if (share_mode) p.flags |= add_torrent_params::flag_share_mode; - lazy_entry resume_data; std::string filename = path_append(save_path, path_append(".resume" , leaf_path(torrent) + ".resume")); @@ -1324,8 +1323,8 @@ int main(int argc, char* argv[]) error_code ec; if (load_file(".ses_state", in, ec) == 0) { - lazy_entry e; - if (lazy_bdecode(&in[0], &in[0] + in.size(), e, ec) == 0) + bdecode_node e; + if (bdecode(&in[0], &in[0] + in.size(), e, ec) == 0) ses.load_state(e); } diff --git a/examples/dump_torrent.cpp b/examples/dump_torrent.cpp index 0f9a2fa03..7d2b6f27a 100644 --- a/examples/dump_torrent.cpp +++ b/examples/dump_torrent.cpp @@ -33,10 +33,11 @@ POSSIBILITY OF SUCH DAMAGE. #include "libtorrent/entry.hpp" #include "libtorrent/bencode.hpp" #include "libtorrent/torrent_info.hpp" -#include "libtorrent/lazy_entry.hpp" +#include "libtorrent/bdecode.hpp" #include "libtorrent/magnet_uri.hpp" -int load_file(std::string const& filename, std::vector& v, libtorrent::error_code& ec, int limit = 8000000) +int load_file(std::string const& filename, std::vector& v + , libtorrent::error_code& ec, int limit = 8000000) { ec.clear(); FILE* f = fopen(filename.c_str(), "rb"); @@ -127,11 +128,11 @@ int main(int argc, char* argv[]) fprintf(stderr, "failed to load file: %s\n", ec.message().c_str()); return 1; } - lazy_entry e; + bdecode_node e; int pos = -1; printf("decoding. recursion limit: %d total item count limit: %d\n" , depth_limit, item_limit); - ret = lazy_bdecode(&buf[0], &buf[0] + buf.size(), e, ec, &pos + ret = bdecode(&buf[0], &buf[0] + buf.size(), e, ec, &pos , depth_limit, item_limit); printf("\n\n----- raw info -----\n\n%s\n", print_entry(e).c_str()); diff --git a/examples/rss_reader.cpp b/examples/rss_reader.cpp index 2b6ab9aad..85dc60af1 100644 --- a/examples/rss_reader.cpp +++ b/examples/rss_reader.cpp @@ -179,8 +179,8 @@ int main(int argc, char* argv[]) error_code ec; if (load_file(".ses_state", in, ec) == 0) { - lazy_entry e; - if (lazy_bdecode(&in[0], &in[0] + in.size(), e, ec) == 0) + bdecode_node e; + if (bdecode(&in[0], &in[0] + in.size(), e, ec) == 0) ses.load_state(e); } diff --git a/include/libtorrent/Makefile.am b/include/libtorrent/Makefile.am index 8b7512983..77c08fecc 100644 --- a/include/libtorrent/Makefile.am +++ b/include/libtorrent/Makefile.am @@ -16,6 +16,7 @@ nobase_include_HEADERS = \ bandwidth_socket.hpp \ bandwidth_queue_entry.hpp \ bencode.hpp \ + bdecode.hpp \ bitfield.hpp \ block_cache.hpp \ bloom_filter.hpp \ diff --git a/include/libtorrent/aux_/session_impl.hpp b/include/libtorrent/aux_/session_impl.hpp index 2b7db3941..3eb3cc3a3 100644 --- a/include/libtorrent/aux_/session_impl.hpp +++ b/include/libtorrent/aux_/session_impl.hpp @@ -492,7 +492,7 @@ namespace libtorrent void announce_lsd(sha1_hash const& ih, int port, bool broadcast = false); void save_state(entry* e, boost::uint32_t flags) const; - void load_state(lazy_entry const* e); + void load_state(bdecode_node const* e); bool has_connection(peer_connection* p) const; void insert_peer(boost::shared_ptr const& c); diff --git a/include/libtorrent/bdecode.hpp b/include/libtorrent/bdecode.hpp new file mode 100644 index 000000000..f05269556 --- /dev/null +++ b/include/libtorrent/bdecode.hpp @@ -0,0 +1,409 @@ +/* + +Copyright (c) 2015, 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 +#include +#include +#include +#include "libtorrent/assert.hpp" + +#ifndef TORRENT_BDECODE_HPP +#define TORRENT_BDECODE_HPP + +/* + +This is an efficient bdecoder. It decodes into a flat memory buffer of tokens. + +Each token has an offset into the bencoded buffer where the token came from +and a next pointer, which is a relative number of tokens to skip forward to +get to the logical next item in a container. + +strings and ints offset pointers point to the first character of the length +prefix or the 'i' character. This is to maintain uniformity with other types +and to allow easily calculating the span of a node by subtracting its offset +by the offset of the next node. + +example layout: + +{ + "a": { "b": 1, "c": "abcd" }, + "d": 3 +} + + /---------------------------------------------------------------------------------------\ + | | + | | + | /--------------------------------------------\ | + | | | | + | | | | + | /-----\ | /----\ /----\ /----\ /----\ | /----\ /----\ | + | next | | | | | | | | | | | | | | | | | + | pointers | v | | v | v | v | v v | v | v v ++-+-----+----+--+----+--+----+--+----+--+----+--+----+--+-------+----+--+----+--+------+ X +| dict | str | dict | str | int | str | str | end | str | int | end | +| | | | | | | | | | | | +| | | | | | | | | | | | ++-+-----+-+-----+-+-----+-+-----+-+-----+-+-----+-+-----+-+-----+-+-----+-+-----+-+----+ + | offset| | | | | | | | | | + | | | | | | | | | | | + |/------/ | | | | | | | | | + || /-----------/ | | | | | | | | + || |/------------------/ | | | | | | | + || || /-----------------------/ | | | | | | + || || | /----------------------------/ | | | | | + || || | | /---------------------------------/ | | | | + || || | | | /-----------------------------------/ | | | + || || | | | |/------------------------------------------/ | | + || || | | | || /-----------------------------------------------/ | + || || | | | || | /----------------------------------------------------/ + || || | | | || | | + vv vv v v v vv v v +``d1:ad1:bi1e1:c4:abcde1:di3ee`` + +*/ + +namespace libtorrent { + +TORRENT_EXPORT boost::system::error_category& get_bdecode_category(); + +namespace bdecode_errors +{ + // libtorrent uses boost.system's ``error_code`` class to represent + // errors. libtorrent has its own error category get_bdecode_category() + // whith the error codes defined by error_code_enum. + enum error_code_enum + { + // Not an error + no_error = 0, + // expected string in bencoded string + expected_digit, + // expected colon in bencoded string + expected_colon, + // unexpected end of file in bencoded string + unexpected_eof, + // expected value (list, dict, int or string) in bencoded string + expected_value, + // bencoded recursion depth limit exceeded + depth_exceeded, + // bencoded item count limit exceeded + limit_exceeded, + // integer overflow + overflow, + + // the number of error codes + error_code_max + }; + + // hidden + TORRENT_EXPORT boost::system::error_code make_error_code(error_code_enum e); +} +} // namespace libtorrent + +namespace boost { namespace system { + + template<> struct is_error_code_enum + { static const bool value = true; }; + + template<> struct is_error_condition_enum + { static const bool value = true; }; +} } + +namespace libtorrent { + + typedef boost::system::error_code error_code; + +TORRENT_EXTRA_EXPORT char const* parse_int(char const* start + , char const* end, char delimiter, boost::int64_t& val + , bdecode_errors::error_code_enum& ec); + +namespace detail +{ +// internal +struct bdecode_token +{ + // the node with type 'end' is a logical node, pointing to the end + // of the bencoded buffer. + enum type_t + { none, dict, list, string, integer, end }; + + enum limits_t + { + max_offset = (1 << 29) - 1, + max_next_item = (1 << 29) - 1, + max_header = (1 << 3) - 1, + }; + + bdecode_token(boost::uint32_t off, bdecode_token::type_t t) + : offset(off) + , type(t) + , next_item(0) + , header(0) + { + TORRENT_ASSERT(off <= max_offset); + TORRENT_ASSERT(t >= 0 && t <= end); + } + + bdecode_token(boost::uint32_t off, boost::uint32_t next + , bdecode_token::type_t t, boost::uint8_t header_size = 0) + : offset(off) + , type(t) + , next_item(next) + , header(type == string ? header_size - 2 : 0) + { + TORRENT_ASSERT(type != string || header_size >= 2); + TORRENT_ASSERT(off <= max_offset); + TORRENT_ASSERT(next <= max_next_item); + TORRENT_ASSERT(header_size < 8); + TORRENT_ASSERT(t >= 0 && t <= end); + } + + int start_offset() const { TORRENT_ASSERT(type == string); return header + 2; } + + // offset into the bdecoded buffer where this node is + boost::uint32_t offset:29; + + // one of type_t enums + boost::uint32_t type:3; + + // if this node is a member of a list, 'next_item' is the number of nodes + // to jump forward in th node array to get to the next item in the list. + // if it's a key in a dictionary, it's the number of step forwards to get + // to its corresponding value. If it's a value in a dictionary, it's the + // number of steps to the next key, or to the end node. + // this is the _relative_ offset to the next node + boost::uint32_t next_item:29; + + // this is the number of bytes to skip forward from the offset to get to the + // first character of the string, if this is a string. This field is not + // used for other types. Essentially this is the length of the length prefix + // and the colon. Since a string always has at least one character of length + // prefix and always a colon, those 2 characters are implied. + boost::uint32_t header:3; +}; +} + +// a ``bdecode_node`` is used to traverse and hold the tree structure defined +// by bencoded data after it has been parse by bdecode(). +// +// There are primarily two kinds of bdecode_nodes. The ones that own the tree +// structure, and defines its lifetime, and nodes that are child nodes in the +// tree, pointing back into the root's tree. +// +// The ``bdecode_node`` passed in to ``bdecode()`` becomes the one owning the +// tree structure. Make sure not to destruct that object for as long as you +// use any of its child nodes. Also, keep in mind that the buffer originally +// parsed also must remain valid while using it. (see switch_underlying_buffer()). +// +// Copying an owning node will create a copy of the whole tree, but will still +// point into the same parsed bencoded buffer as the first one. + +// Sometimes it's important to get a non-owning reference to the root node ( +// to be able to copy it as a reference for instance). For that, use the +// non_owninig() member function. +// +// There are 5 different types of nodes, see type_t. +struct TORRENT_EXPORT bdecode_node +{ + friend int bdecode(char const* start, char const* end, bdecode_node& ret + , error_code& ec, int* error_pos, int depth_limit, int token_limit); + + // creates a default constructed node, it will have the type ``none_t``. + bdecode_node(); + + // For owning nodes, the copy will create a copy of the tree, but the + // underlying buffer remains the same. + bdecode_node(bdecode_node const&); + bdecode_node& operator=(bdecode_node const&); + + // the dypes of bdecoded nodes + enum type_t + { + // uninitialized or default constructed. This is also used + // to indicate that a node was not found in some cases. + none_t, + // a dictionary node. The ``dict_find_`` functions are valid. + dict_t, + // a list node. The ``list_`` functions are valid. + list_t, + // a string node, the ``string_`` functions are valid. + string_t, + // an integer node. The ``int_`` functions are valid. + int_t + }; + + // the type of this node. See type_t. + type_t type() const; + + // returns true if type() != none_t. + operator bool() const; + + // return a non-owning reference to this node. This is useful to refer to + // the root node without copying it in assignments. + bdecode_node non_owning() const; + + // returns the buffer and length of the section in the original bencoded + // buffer where this node is defined. For a dictionary for instance, this + // starts with ``d`` and ends with ``e``, and has all the content of the + // dictionary in between. + std::pair data_section() const; + + // functions with the ``list_`` prefix operate on lists. These functions are + // only valid if ``type()`` == ``list_t``. ``list_at()`` returns the item + // in the list at index ``i``. ``i`` may not be greater than or equal to the + // size of the list. ``size()`` returns the size of the list. + bdecode_node list_at(int i) const; + std::string list_string_value_at(int i + , char const* default_val = ""); + boost::int64_t list_int_value_at(int i + , boost::int64_t default_val = 0); + int list_size() const; + + // functions with the ``dict_`` prefix operates on dictionaries. Theu are + // only valid if ``type()`` == ``dict_t``. In case a key you're looking up + // contains a 0 byte, you cannot use the null-terminated string overloads, + // but have to use ``std::string`` instead. ``dict_find_list`` will return + // a valid ``bdecode_node`` if the key is found _and_ it is a list. Otherwise + // it will return a default-constructed bdecode_node. + bdecode_node dict_find(std::string key) const; + bdecode_node dict_find(char const* key) const; + std::pair dict_at(int i) const; + bdecode_node dict_find_dict(std::string key) const; + bdecode_node dict_find_dict(char const* key) const; + bdecode_node dict_find_list(char const* key) const; + bdecode_node dict_find_string(char const* key) const; + bdecode_node dict_find_int(char const* key) const; + std::string dict_find_string_value(char const* key + , char const* default_value = "") const; + boost::int64_t dict_find_int_value(char const* key + , boost::int64_t default_val = 0) const; + int dict_size() const; + + // this function is only valid if ``type()`` == ``int_t``. It returns the + // value of the integer. + boost::int64_t int_value() const; + + // these functions are only valid if ``type()`` == ``string_t``. They return + // the string values. Note that ``string_ptr()`` is _not_ null-terminated. + // ``string_length()`` returns the number of bytes in the string. + std::string string_value() const; + char const* string_ptr() const; + int string_length() const; + + // resets the ``bdecoded_node`` to a default constructed state. If this is + // an owning node, the tree is freed and all child nodes are invalidated. + void clear(); + + // Swap contents. + void swap(bdecode_node& n); + + // pre-allocate memory for the specified numbers of tokens. This is + // useful if you know approximately how many tokens are in the file + // you are about to parse. Doing so will save realloc operations + // while parsing. You should only call this on the root node, before + // passing it in to bdecode(). + void reserve(int tokens); + + // this buffer MUST be identical to the one originally parsed. + // This operation is only defined on owning root nodes, i.e. the one + // passed in to decode(). + void switch_underlying_buffer(char const* buf); + +private: + bdecode_node(detail::bdecode_token const* tokens, char const* buf + , int len, int idx); + + // if this is the root node, that owns all the tokens, they live in this + // vector. If this is a sub-node, this field is not used, instead the + // m_root_tokens pointer points to the root node's token. + std::vector m_tokens; + + // this points to the root nodes token vector + // for the root node, this points to its own m_tokens member + detail::bdecode_token const* m_root_tokens; + + // this points to the original buffer that was parsed + char const* m_buffer; + int m_buffer_size; + + // this is the index into m_root_tokens that this node refers to + // for the root node, it's 0. -1 means uninitialized. + int m_token_idx; + + // this is a cache of the last element index looked up. This only applies + // to lists and dictionaries. If the next lookup is at m_last_index or + // greater, we can start iterating the tokens at m_last_token. + mutable int m_last_index; + mutable int m_last_token; + + // the number of elements in this list or dict (computed on the first + // call to dict_size() or list_size()) + mutable int m_size; +}; + +// print the bencoded structure in a human-readable format to a string +// that's returned. +TORRENT_EXPORT std::string print_entry(bdecode_node const& e + , bool single_line = false, int indent = 0); + +// This function decodes/parses bdecoded data (for example a .torrent file). +// The data structure is returned in the ``ret`` argument. +// the buffer to parse is specified by the ``start`` of the buffer as well as +// the ``end``, i.e. one byte past the end. If the buffer fails to parse, the +// function returns a non-zero value and fills in ``ec`` with the error code. +// The optional argument ``error_pos``, if set to non-null, will be set to the byte +// offset into the buffer where the parse failure occurred. +// +// ``depth_limit`` specifies the max number of nested lists or dictionaries are +// allowed in the data structure. (This affects the stack usage of the +// function, be careful not to set it too high). +// +// ``token_limit`` is the max number of tokens allowed to be parsed from the +// buffer. This is simply a sanity check to not have unbounded memory usage. +// +// The resulting ``bdecode_node`` is an *owning* node. That means it will +// be holding the whole parsed tree. When iterating lists and dictionaries, +// those ``bdecode_node``s will simply have references to the root or owning +// ``bdecode_node``. If the root node is destructed, all other nodes that +// refer to anything in that tree become invalid. +// +// However, the underlying buffer passed in to this function (``start``, ``end``) +// must also remain valid while the bdecoded tree is used. The parsed tree +// produced by this function does not copy any data out of the buffer, but +// simply produces references back into it. +TORRENT_EXPORT int bdecode(char const* start, char const* end, bdecode_node& ret + , error_code& ec, int* error_pos = 0, int depth_limit = 100 + , int token_limit = 1000000); + +} + +#endif // TORRENT_BDECODE_HPP + diff --git a/include/libtorrent/bencode.hpp b/include/libtorrent/bencode.hpp index af2a3c66e..f5fc92f67 100644 --- a/include/libtorrent/bencode.hpp +++ b/include/libtorrent/bencode.hpp @@ -51,7 +51,7 @@ POSSIBILITY OF SUCH DAMAGE. // // There are two mechanims to *decode* bencoded buffers in libtorrent. // -// The most flexible one is bdecode(), which returns a structure +// The most flexible one is `bdecode() bencode()`_, which returns a structure // represented by entry. When a buffer is decoded with this function, // it can be discarded. The entry does not contain any references back // to it. This means that bdecode() actually copies all the data out @@ -59,16 +59,16 @@ POSSIBILITY OF SUCH DAMAGE. // function potentially expensive, if you're parsing large amounts // of data. // -// Another consideration is that bdecode() is a recursive parser. +// Another consideration is that `bdecode() bencode()`_ is a recursive parser. // For this reason, in order to avoid DoS attacks by triggering // a stack overflow, there is a recursion limit. This limit is // a sanity check to make sure it doesn't run the risk of // busting the stack. // -// The second mechanism is lazy_bdecode(), which returns a -// bencoded structure represented by lazy_entry. This function +// The second mechanism is bdecode(), which returns a +// bencoded structure represented by bdecode_node. This function // builds a tree that points back into the original buffer. -// The returned lazy_entry will not be valid once the buffer +// The returned bdecode_node will not be valid once the buffer // it was parsed out of is discarded. // // Not only is this function more efficient because of less @@ -391,9 +391,10 @@ namespace libtorrent } } - // These functions will encode data to bencoded_ or decode bencoded_ data. + // These functions will encode data to bencoded or decode bencoded data. // - // If possible, lazy_bdecode() should be preferred over ``bdecode()``. + // If possible, bdecode() and bdecode_node should be preferred over this + // function. // // The entry_ class is the internal representation of the bencoded data // and it can be used to retrieve information, an entry_ can also be build by diff --git a/include/libtorrent/cpuid.hpp b/include/libtorrent/cpuid.hpp index a4174e56a..ee41214f1 100644 --- a/include/libtorrent/cpuid.hpp +++ b/include/libtorrent/cpuid.hpp @@ -43,6 +43,7 @@ POSSIBILITY OF SUCH DAMAGE. namespace libtorrent { + // internal inline void cpuid(unsigned int info[4], int type) { #if TORRENT_HAS_SSE && defined _MSC_VER diff --git a/include/libtorrent/disk_interface.hpp b/include/libtorrent/disk_interface.hpp index 5738392b4..26fdb302f 100644 --- a/include/libtorrent/disk_interface.hpp +++ b/include/libtorrent/disk_interface.hpp @@ -36,7 +36,7 @@ POSSIBILITY OF SUCH DAMAGE. #include #include -#include "libtorrent/lazy_entry.hpp" +#include "libtorrent/bdecode.hpp" #include @@ -66,7 +66,7 @@ namespace libtorrent , boost::function const& handler = boost::function()) = 0; virtual void async_check_fastresume(piece_manager* storage - , lazy_entry const* resume_data + , bdecode_node const* resume_data , boost::function const& handler) = 0; #ifndef TORRENT_NO_DEPRECATE virtual void async_finalize_file(piece_manager*, int file diff --git a/include/libtorrent/disk_io_thread.hpp b/include/libtorrent/disk_io_thread.hpp index d733f26f3..f0000ad25 100644 --- a/include/libtorrent/disk_io_thread.hpp +++ b/include/libtorrent/disk_io_thread.hpp @@ -307,7 +307,7 @@ namespace libtorrent void async_delete_files(piece_manager* storage , boost::function const& handler); void async_check_fastresume(piece_manager* storage - , lazy_entry const* resume_data + , bdecode_node const* resume_data , boost::function const& handler); void async_save_resume_data(piece_manager* storage , boost::function const& handler); diff --git a/include/libtorrent/entry.hpp b/include/libtorrent/entry.hpp index 8e71f56aa..3386abdf5 100644 --- a/include/libtorrent/entry.hpp +++ b/include/libtorrent/entry.hpp @@ -76,7 +76,10 @@ POSSIBILITY OF SUCH DAMAGE. namespace libtorrent { +#ifndef TORRENT_NO_DEPRECATE struct lazy_entry; +#endif + struct bdecode_node; // thrown by any accessor function of entry if the accessor // function requires a type different than the actual type @@ -142,7 +145,10 @@ namespace libtorrent // copies the structure of the right hand side into this // entry. +#ifndef TORRENT_NO_DEPRECATE void operator=(lazy_entry const&); +#endif + void operator=(bdecode_node const&); void operator=(entry const&); void operator=(dictionary_type const&); void operator=(string_type const&); diff --git a/include/libtorrent/extensions.hpp b/include/libtorrent/extensions.hpp index 574a22831..45dc29926 100644 --- a/include/libtorrent/extensions.hpp +++ b/include/libtorrent/extensions.hpp @@ -191,7 +191,7 @@ namespace libtorrent struct peer_request; class peer_connection; class entry; - struct lazy_entry; + struct bdecode_node; struct disk_buffer_holder; struct bitfield; class alert; @@ -248,7 +248,7 @@ namespace libtorrent virtual void save_state(entry&) const {} // called when loading settings state - virtual void load_state(lazy_entry const&) {} + virtual void load_state(bdecode_node const&) {} }; // Torrent plugins are associated with a single torrent and have a number @@ -387,7 +387,7 @@ namespace libtorrent // supported by this peer. It will result in this peer_plugin // being removed from the peer_connection and destructed. // this is not called for web seeds - virtual bool on_extension_handshake(lazy_entry const&) { return true; } + virtual bool on_extension_handshake(bdecode_node const&) { return true; } // returning true from any of the message handlers // indicates that the plugin has handeled the message. diff --git a/include/libtorrent/kademlia/dht_tracker.hpp b/include/libtorrent/kademlia/dht_tracker.hpp index 91b89a86e..d63a0a951 100644 --- a/include/libtorrent/kademlia/dht_tracker.hpp +++ b/include/libtorrent/kademlia/dht_tracker.hpp @@ -56,7 +56,6 @@ POSSIBILITY OF SUCH DAMAGE. namespace libtorrent { namespace aux { struct session_impl; } - struct lazy_entry; struct counters; #ifndef TORRENT_NO_DEPRECATE struct session_status; @@ -139,6 +138,11 @@ namespace libtorrent { namespace dht virtual bool send_packet(libtorrent::entry& e, udp::endpoint const& addr , int send_flags); + // this is the bdecode_node DHT messages are parsed into. It's a member + // in order to avoid having to deallocate and re-allocate it for every + // message. + bdecode_node m_msg; + counters& m_counters; node_impl m_dht; rate_limited_udp_socket& m_sock; diff --git a/include/libtorrent/kademlia/get_item.hpp b/include/libtorrent/kademlia/get_item.hpp index ee547a2c7..1433504d6 100644 --- a/include/libtorrent/kademlia/get_item.hpp +++ b/include/libtorrent/kademlia/get_item.hpp @@ -45,7 +45,7 @@ class get_item : public find_data public: typedef boost::function data_callback; - void got_data(lazy_entry const* v, + void got_data(bdecode_node const& v, char const* pk, boost::uint64_t seq, char const* sig); diff --git a/include/libtorrent/kademlia/item.hpp b/include/libtorrent/kademlia/item.hpp index 350c7e466..767d34aa7 100644 --- a/include/libtorrent/kademlia/item.hpp +++ b/include/libtorrent/kademlia/item.hpp @@ -34,7 +34,7 @@ POSSIBILITY OF SUCH DAMAGE. #define LIBTORRENT_ITEM_HPP #include -#include +#include #include #include #include @@ -91,7 +91,7 @@ public: item(entry const& v , std::pair salt , boost::uint64_t seq, char const* pk, char const* sk); - item(lazy_entry const* v) { assign(v); } + item(bdecode_node const& v) { assign(v); } void assign(entry const& v) { @@ -100,12 +100,12 @@ public: } void assign(entry const& v, std::pair salt , boost::uint64_t seq, char const* pk, char const* sk); - void assign(lazy_entry const* v) + void assign(bdecode_node const& v) { assign(v, std::pair(static_cast(NULL) , 0), 0, NULL, NULL); } - bool assign(lazy_entry const* v, std::pair salt + bool assign(bdecode_node const& v, std::pair salt , boost::uint64_t seq, char const* pk, char const* sig); void assign(entry const& v, std::string salt, boost::uint64_t seq , char const* pk, char const* sig); diff --git a/include/libtorrent/kademlia/msg.hpp b/include/libtorrent/kademlia/msg.hpp index e9dc6e1c1..9c0d67fc5 100644 --- a/include/libtorrent/kademlia/msg.hpp +++ b/include/libtorrent/kademlia/msg.hpp @@ -51,9 +51,9 @@ typedef std::vector peers_t; struct msg { - msg(lazy_entry const& m, udp::endpoint const& ep): message(m), addr(ep) {} + msg(bdecode_node const& m, udp::endpoint const& ep): message(m), addr(ep) {} // the message - lazy_entry const& message; + bdecode_node const& message; // the address of the process sending or receiving // the message. diff --git a/include/libtorrent/kademlia/node.hpp b/include/libtorrent/kademlia/node.hpp index de8e6b274..b73ad889f 100644 --- a/include/libtorrent/kademlia/node.hpp +++ b/include/libtorrent/kademlia/node.hpp @@ -99,8 +99,8 @@ struct key_desc_t }; }; -bool TORRENT_EXTRA_EXPORT verify_message(lazy_entry const* msg, key_desc_t const desc[] - , lazy_entry const* ret[], int size , char* error, int error_size); +bool TORRENT_EXTRA_EXPORT verify_message(bdecode_node const& msg, key_desc_t const desc[] + , bdecode_node ret[], int size , char* error, int error_size); // this is the entry for every peer // the timestamp is there to make it possible diff --git a/include/libtorrent/lazy_entry.hpp b/include/libtorrent/lazy_entry.hpp index ecef15916..e6414a129 100644 --- a/include/libtorrent/lazy_entry.hpp +++ b/include/libtorrent/lazy_entry.hpp @@ -33,6 +33,8 @@ POSSIBILITY OF SUCH DAMAGE. #ifndef TORRENT_LAZY_ENTRY_HPP_INCLUDED #define TORRENT_LAZY_ENTRY_HPP_INCLUDED +#ifndef TORRENT_NO_DEPRECATE + #include #include #include @@ -41,6 +43,7 @@ POSSIBILITY OF SUCH DAMAGE. #include "libtorrent/config.hpp" #include "libtorrent/assert.hpp" #include "libtorrent/error_code.hpp" +#include "libtorrent/bdecode.hpp" // for error codes namespace libtorrent { @@ -50,9 +53,8 @@ namespace libtorrent // // .. _bencoded: http://wiki.theory.org/index.php/BitTorrentSpecification // - // Whenever possible, ``lazy_bdecode()`` should be preferred over ``bdecode()``. - // It is more efficient and more secure. It supports having constraints on the - // amount of memory is consumed by the parser. + // The lazy bdecoder and lazy_entry has been deprecated in favour of + // bdecode_node and its corresponding bdecode() function. // // *lazy* refers to the fact that it doesn't copy any actual data out of the // bencoded buffer. It builds a tree of ``lazy_entry`` which has pointers into @@ -79,9 +81,10 @@ namespace libtorrent // in case the function fails. ``error_pos`` is an optional pointer to an int, // which will be set to the byte offset into the buffer where an error occurred, // in case the function fails. + TORRENT_DEPRECATED_PREFIX TORRENT_EXPORT int lazy_bdecode(char const* start, char const* end , lazy_entry& ret, error_code& ec, int* error_pos = 0 - , int depth_limit = 1000, int item_limit = 1000000); + , int depth_limit = 1000, int item_limit = 1000000) TORRENT_DEPRECATED; #ifndef TORRENT_NO_DEPRECATE // for backwards compatibility, does not report error code @@ -392,63 +395,21 @@ namespace libtorrent lazy_entry val; }; - // print the bencoded structure in a human-readable format to a stting + // print the bencoded structure in a human-readable format to a string // that's returned. + TORRENT_DEPRECATED_PREFIX TORRENT_EXPORT std::string print_entry(lazy_entry const& e - , bool single_line = false, int indent = 0); - - // get the ``error_category`` for bdecode errors - TORRENT_EXPORT boost::system::error_category& get_bdecode_category(); - - namespace bdecode_errors - { - // libtorrent uses boost.system's ``error_code`` class to represent errors. libtorrent has - // its own error category get_bdecode_category() whith the error codes defined by error_code_enum. - enum error_code_enum - { - // Not an error - no_error = 0, - // expected string in bencoded string - expected_string, - // expected colon in bencoded string - expected_colon, - // unexpected end of file in bencoded string - unexpected_eof, - // expected value (list, dict, int or string) in bencoded string - expected_value, - // bencoded recursion depth limit exceeded - depth_exceeded, - // bencoded item count limit exceeded - limit_exceeded, - // integer overflow - overflow, - - // the number of error codes - error_code_max - }; - - // hidden - TORRENT_EXPORT boost::system::error_code make_error_code(error_code_enum e); - } + , bool single_line = false, int indent = 0) TORRENT_DEPRECATED; + // defined in bdecode.cpp + TORRENT_DEPRECATED_PREFIX TORRENT_EXTRA_EXPORT char const* parse_int(char const* start , char const* end, char delimiter, boost::int64_t& val - , bdecode_errors::error_code_enum& ec); + , bdecode_errors::error_code_enum& ec) TORRENT_DEPRECATED; } -#if BOOST_VERSION >= 103500 - -namespace boost { namespace system { - - template<> struct is_error_code_enum - { static const bool value = true; }; - - template<> struct is_error_condition_enum - { static const bool value = true; }; -} } - -#endif +#endif // TORRENT_NO_DEPRECATE #endif diff --git a/include/libtorrent/rss.hpp b/include/libtorrent/rss.hpp index 9893d43c2..4fd1e6bfe 100644 --- a/include/libtorrent/rss.hpp +++ b/include/libtorrent/rss.hpp @@ -229,7 +229,7 @@ namespace libtorrent int next_update(time_t now) const; - void load_state(lazy_entry const& rd); + void load_state(bdecode_node const& rd); void save_state(entry& rd) const; // private: diff --git a/include/libtorrent/session.hpp b/include/libtorrent/session.hpp index cad44856d..2b5d868ba 100644 --- a/include/libtorrent/session.hpp +++ b/include/libtorrent/session.hpp @@ -311,14 +311,14 @@ namespace libtorrent // to the ``entry`` that's passed in, which needs to either not be // initialized, or initialized as a dictionary. // - // ``load_state`` expects a lazy_entry which can be built from a bencoded - // buffer with lazy_bdecode(). + // ``load_state`` expects a bdecode_node which can be built from a bencoded + // buffer with bdecode(). // // The ``flags`` arguments passed in to ``save_state`` can be used to // filter which parts of the session state to save. By default, all state // is saved (except for the individual torrents). see save_state_flags_t void save_state(entry& e, boost::uint32_t flags = 0xffffffff) const; - void load_state(lazy_entry const& e); + void load_state(bdecode_node const& e); // .. note:: // these calls are potentially expensive and won't scale well with @@ -735,6 +735,9 @@ namespace libtorrent void load_state(entry const& ses_state) TORRENT_DEPRECATED; TORRENT_DEPRECATED_PREFIX entry state() const TORRENT_DEPRECATED; + // deprecated in 1.1 + TORRENT_DEPRECATED_PREFIX + void load_state(lazy_entry const& ses_state) TORRENT_DEPRECATED; #endif // TORRENT_NO_DEPRECATE // Sets a filter that will be used to reject and accept incoming as well diff --git a/include/libtorrent/settings_pack.hpp b/include/libtorrent/settings_pack.hpp index 2fb3e6546..f1568b079 100644 --- a/include/libtorrent/settings_pack.hpp +++ b/include/libtorrent/settings_pack.hpp @@ -51,9 +51,9 @@ namespace libtorrent namespace aux { struct session_impl; struct session_settings; } struct settings_pack; - struct lazy_entry; + struct bdecode_node; - TORRENT_EXTRA_EXPORT settings_pack* load_pack_from_dict(lazy_entry const* settings); + TORRENT_EXTRA_EXPORT settings_pack* load_pack_from_dict(bdecode_node const& settings); TORRENT_EXTRA_EXPORT void save_settings_to_dict(aux::session_settings const& s, entry::dictionary_type& sett); TORRENT_EXTRA_EXPORT void apply_pack(settings_pack const* pack, aux::session_settings& sett, aux::session_impl* ses = 0); diff --git a/include/libtorrent/socket_io.hpp b/include/libtorrent/socket_io.hpp index 3faaf3b94..dff58c7da 100644 --- a/include/libtorrent/socket_io.hpp +++ b/include/libtorrent/socket_io.hpp @@ -37,7 +37,7 @@ POSSIBILITY OF SUCH DAMAGE. #include "libtorrent/address.hpp" #include "libtorrent/io.hpp" #include "libtorrent/error_code.hpp" -#include "libtorrent/lazy_entry.hpp" +#include "libtorrent/bdecode.hpp" #include "libtorrent/bencode.hpp" #include "libtorrent/peer_id.hpp" // for sha1_hash #include @@ -123,20 +123,21 @@ namespace libtorrent #endif template - void read_endpoint_list(libtorrent::lazy_entry const* n, std::vector& epl) + void read_endpoint_list(libtorrent::bdecode_node const& n + , std::vector& epl) { using namespace libtorrent; - if (n->type() != lazy_entry::list_t) return; - for (int i = 0; i < n->list_size(); ++i) + if (n.type() != bdecode_node::list_t) return; + for (int i = 0; i < n.list_size(); ++i) { - lazy_entry const* e = n->list_at(i); - if (e->type() != lazy_entry::string_t) return; - if (e->string_length() < 6) continue; - char const* in = e->string_ptr(); - if (e->string_length() == 6) + bdecode_node e = n.list_at(i); + if (e.type() != bdecode_node::string_t) return; + if (e.string_length() < 6) continue; + char const* in = e.string_ptr(); + if (e.string_length() == 6) epl.push_back(read_v4_endpoint(in)); #if TORRENT_USE_IPV6 - else if (e->string_length() == 18) + else if (e.string_length() == 18) epl.push_back(read_v6_endpoint(in)); #endif } diff --git a/include/libtorrent/storage.hpp b/include/libtorrent/storage.hpp index 9d648c44e..75840b288 100644 --- a/include/libtorrent/storage.hpp +++ b/include/libtorrent/storage.hpp @@ -66,7 +66,7 @@ POSSIBILITY OF SUCH DAMAGE. #include "libtorrent/file_pool.hpp" // pool_file_status #include "libtorrent/part_file.hpp" #include "libtorrent/stat_cache.hpp" -#include "libtorrent/lazy_entry.hpp" +#include "libtorrent/bdecode.hpp" #include "libtorrent/bitfield.hpp" #include "libtorrent/performance_counters.hpp" @@ -115,7 +115,7 @@ POSSIBILITY OF SUCH DAMAGE. // virtual bool rename_file(int file, std::string const& new_name) // { assert(false); return false; } // virtual bool move_storage(std::string const& save_path) { return false; } -// virtual bool verify_resume_data(lazy_entry const& rd, storage_error& error) { return false; } +// virtual bool verify_resume_data(bdecode_node const& rd, storage_error& error) { return false; } // virtual bool write_resume_data(entry& rd) const { return false; } // virtual boost::int64_t physical_offset(int slot, int offset) // { return slot * m_files.piece_length() + offset; }; @@ -307,7 +307,7 @@ namespace libtorrent // This function should verify the resume data ``rd`` with the files // on disk. If the resume data seems to be up-to-date, return true. If // not, set ``error`` to a description of what mismatched and return false. - virtual bool verify_resume_data(lazy_entry const& rd, storage_error& ec) = 0; + virtual bool verify_resume_data(bdecode_node const& rd, storage_error& ec) = 0; // This function should fill in resume data, the current state of the // storage, in ``rd``. The default storage adds file timestamps and @@ -423,7 +423,7 @@ namespace libtorrent void initialize(storage_error& ec); int move_storage(std::string const& save_path, int flags, storage_error& ec); int sparse_end(int start) const; - bool verify_resume_data(lazy_entry const& rd, storage_error& error); + bool verify_resume_data(bdecode_node const& rd, storage_error& error); void write_resume_data(entry& rd, storage_error& ec) const; bool tick(); @@ -519,7 +519,7 @@ namespace libtorrent int writev(file::iovec_t const* bufs, int num_bufs, int piece , int offset, int flags, storage_error& ec); - bool verify_resume_data(lazy_entry const&, storage_error&) { return false; } + bool verify_resume_data(bdecode_node const&, storage_error&) { return false; } void write_resume_data(entry&, storage_error&) const {} int m_piece_size; @@ -541,7 +541,7 @@ namespace libtorrent , storage_error&) {} virtual int move_storage(std::string const& /* save_path */ , int /* flags */, storage_error&) { return 0; } - virtual bool verify_resume_data(lazy_entry const& /* rd */, storage_error&) + virtual bool verify_resume_data(bdecode_node const& /* rd */, storage_error&) { return false; } virtual void write_resume_data(entry&, storage_error&) const {} virtual void release_files(storage_error&) {} @@ -674,7 +674,7 @@ namespace libtorrent // the error message indicates that the fast resume data was rejected // if 'fatal_disk_error' is returned, the error message indicates what // when wrong in the disk access - int check_fastresume(lazy_entry const& rd, storage_error& error); + int check_fastresume(bdecode_node const& rd, storage_error& error); // helper functions for check_fastresume int check_no_fastresume(storage_error& error); diff --git a/include/libtorrent/torrent.hpp b/include/libtorrent/torrent.hpp index 4229f5962..e4fea76ac 100644 --- a/include/libtorrent/torrent.hpp +++ b/include/libtorrent/torrent.hpp @@ -116,7 +116,7 @@ namespace libtorrent struct resume_data_t { std::vector buf; - lazy_entry entry; + bdecode_node node; }; struct time_critical_piece @@ -1019,7 +1019,7 @@ namespace libtorrent torrent_handle get_handle(); void write_resume_data(entry& rd) const; - void read_resume_data(lazy_entry const& rd); + void read_resume_data(bdecode_node const& rd); void seen_complete() { m_last_seen_complete = time(0); } int time_since_complete() const { return int(time(0) - m_last_seen_complete); } diff --git a/include/libtorrent/torrent_info.hpp b/include/libtorrent/torrent_info.hpp index a41887e5f..2db9db7e8 100644 --- a/include/libtorrent/torrent_info.hpp +++ b/include/libtorrent/torrent_info.hpp @@ -49,7 +49,7 @@ POSSIBILITY OF SUCH DAMAGE. #include "libtorrent/config.hpp" #include "libtorrent/entry.hpp" -#include "libtorrent/lazy_entry.hpp" +#include "libtorrent/bdecode.hpp" #include "libtorrent/peer_id.hpp" #include "libtorrent/time.hpp" #include "libtorrent/assert.hpp" @@ -280,10 +280,10 @@ namespace libtorrent // metadata will be created by libtorrent as soon as it has been // downloaded from the swarm. // - // The constructor that takes a lazy_entry will create a torrent_info + // The constructor that takes a bdecode_node will create a torrent_info // object from the information found in the given torrent_file. The - // lazy_entry represents a tree node in an bencoded file. To load an - // ordinary .torrent file into a lazy_entry, use lazy_bdecode(). + // bdecode_node represents a tree node in an bencoded file. To load an + // ordinary .torrent file into a bdecode_node, use bdecode(). // // The version that takes a buffer pointer and a size will decode it as a // .torrent file and initialize the torrent_info object for you. @@ -306,7 +306,7 @@ namespace libtorrent // // The ``flags`` argument is currently unused. #ifndef BOOST_NO_EXCEPTIONS - torrent_info(lazy_entry const& torrent_file, int flags = 0); + torrent_info(bdecode_node const& torrent_file, int flags = 0); torrent_info(char const* buffer, int size, int flags = 0); torrent_info(std::string const& filename, int flags = 0); #ifndef TORRENT_NO_DEPRECATE @@ -317,18 +317,24 @@ namespace libtorrent torrent_info(std::wstring const& filename, int flags = 0) TORRENT_DEPRECATED; #endif // TORRENT_USE_WSTRING #endif // TORRENT_NO_DEPRECATE -#endif +#endif // BOOST_NO_EXCEPTIONS torrent_info(torrent_info const& t); torrent_info(sha1_hash const& info_hash, int flags = 0); - torrent_info(lazy_entry const& torrent_file, error_code& ec, int flags = 0); + torrent_info(bdecode_node const& torrent_file, error_code& ec, int flags = 0); torrent_info(char const* buffer, int size, error_code& ec, int flags = 0); torrent_info(std::string const& filename, error_code& ec, int flags = 0); #ifndef TORRENT_NO_DEPRECATE + TORRENT_DEPRECATED_PREFIX + torrent_info(lazy_entry const& torrent_file, int flags = 0) TORRENT_DEPRECATED; + TORRENT_DEPRECATED_PREFIX + torrent_info(lazy_entry const& torrent_file, error_code& ec + , int flags = 0) TORRENT_DEPRECATED; #if TORRENT_USE_WSTRING // all wstring APIs are deprecated since 0.16.11 instead, use the wchar // -> utf8 conversion functions and pass in utf8 strings TORRENT_DEPRECATED_PREFIX - torrent_info(std::wstring const& filename, error_code& ec, int flags = 0) TORRENT_DEPRECATED; + torrent_info(std::wstring const& filename, error_code& ec + , int flags = 0) TORRENT_DEPRECATED; #endif // TORRENT_USE_WSTRING #endif // TORRENT_NO_DEPRECATE @@ -413,6 +419,11 @@ namespace libtorrent std::vector url_seeds() const TORRENT_DEPRECATED; TORRENT_DEPRECATED_PREFIX std::vector http_seeds() const TORRENT_DEPRECATED; + + // deprecated in 1.1 + TORRENT_DEPRECATED_PREFIX + bool parse_info_section(lazy_entry const& e, error_code& ec + , int flags) TORRENT_DEPRECATED; #endif // TORRENT_NO_DEPRECATE // ``web_seeds()`` returns all url seeds and http seeds in the torrent. @@ -629,23 +640,23 @@ namespace libtorrent // populates the torrent_info by providing just the info-dict buffer. // This is used when loading a torrent from a magnet link for instance, - // where we only have the info-dict. The lazy_entry ``e`` points to a + // where we only have the info-dict. The bdecode_node ``e`` points to a // parsed info-dictionary. ``ec`` returns an error code if something // fails (typically if the info dictionary is malformed). ``flags`` are // currently unused. - bool parse_info_section(lazy_entry const& e, error_code& ec, int flags); + bool parse_info_section(bdecode_node const& e, error_code& ec, int flags); // This function looks up keys from the info-dictionary of the loaded // torrent file. It can be used to access extension values put in the // .torrent file. If the specified key cannot be found, it returns NULL. - lazy_entry const* info(char const* key) const + bdecode_node info(char const* key) const { - if (m_info_dict.type() == lazy_entry::none_t) + if (m_info_dict.type() == bdecode_node::none_t) { error_code ec; - lazy_bdecode(m_info_section.get(), m_info_section.get() + bdecode(m_info_section.get(), m_info_section.get() + m_info_section_size, m_info_dict, ec); - if (ec) return NULL; + if (ec) return bdecode_node(); } return m_info_dict.dict_find(key); } @@ -670,7 +681,7 @@ namespace libtorrent // __ http://bittorrent.org/beps/bep_0030.html bool is_merkle_torrent() const { return !m_merkle_tree.empty(); } - bool parse_torrent_file(lazy_entry const& libtorrent, error_code& ec, int flags); + bool parse_torrent_file(bdecode_node const& libtorrent, error_code& ec, int flags); // if we're logging member offsets, we need access to them private: @@ -726,7 +737,7 @@ namespace libtorrent // the info section parsed. points into m_info_section // parsed lazily - mutable lazy_entry m_info_dict; + mutable bdecode_node m_info_dict; // if a creation date is found in the torrent file // this will be set to that, otherwise it'll be diff --git a/src/Makefile.am b/src/Makefile.am index b9184123c..7642d01c6 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -43,6 +43,7 @@ libtorrent_rasterbar_la_SOURCES = \ bandwidth_limit.cpp \ bandwidth_manager.cpp \ bandwidth_queue_entry.cpp \ + bdecode.cpp \ bloom_filter.cpp \ broadcast_socket.cpp \ block_cache.cpp \ diff --git a/src/bdecode.cpp b/src/bdecode.cpp new file mode 100644 index 000000000..6e45eefac --- /dev/null +++ b/src/bdecode.cpp @@ -0,0 +1,1081 @@ +/* + +Copyright (c) 2015, 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/bdecode.hpp" +#include "libtorrent/alloca.hpp" +#include +#include +#include // for memset + +#ifndef BOOST_SYSTEM_NOEXCEPT +#define BOOST_SYSTEM_NOEXCEPT throw() +#endif + +namespace libtorrent +{ + using detail::bdecode_token; + + namespace + { + bool numeric(char c) { return c >= '0' && c <= '9'; } + + // finds the end of an integer and verifies that it looks valid this does + // not detect all overflows, just the ones that are an order of magnitued + // beyond. Exact overflow checking is done when the integer value is queried + // from a bdecode_node. + char const* check_integer(char const* start, char const* end + , bdecode_errors::error_code_enum& e) + { + if (start == end) + { + e = bdecode_errors::unexpected_eof; + return start; + } + + if (*start == '-') + { + ++start; + if (start == end) + { + e = bdecode_errors::unexpected_eof; + return start; + } + } + + int digits = 0; + do + { + if (!numeric(*start)) + { + e = bdecode_errors::expected_digit; + break; + } + ++start; + ++digits; + + if (start == end) + { + e = bdecode_errors::unexpected_eof; + break; + } + } + while (*start != 'e'); + + if (digits > 20) + { + e = bdecode_errors::overflow; + } + + return start; + } + + struct stack_frame + { + stack_frame(int t): token(t), state(0) {} + // this is an index into m_tokens + boost::uint32_t token:31; + // this is used for doctionaries to indicate whether we're + // reading a key or a vale. 0 means key 1 is value + boost::uint32_t state:1; + }; + + // str1 is null-terminated + // str2 is not, str2 is len2 chars + bool string_equal(char const* str1, char const* str2, int len2) + { + while (len2 > 0) + { + if (*str1 != *str2) return false; + if (*str1 == 0) return false; + ++str1; + ++str2; + --len2; + } + return *str1 == 0; + } + + } // anonymous namespace + + + // fills in 'val' with what the string between start and the + // first occurance of the delimiter is interpreted as an int. + // return the pointer to the delimiter, or 0 if there is a + // parse error. val should be initialized to zero + char const* parse_int(char const* start, char const* end, char delimiter + , boost::int64_t& val, bdecode_errors::error_code_enum& ec) + { + while (start < end && *start != delimiter) + { + if (!numeric(*start)) + { + ec = bdecode_errors::expected_digit; + return start; + } + if (val > (std::numeric_limits::max)() / 10) + { + ec = bdecode_errors::overflow; + return start; + } + val *= 10; + int digit = *start - '0'; + if (val > (std::numeric_limits::max)() - digit) + { + ec = bdecode_errors::overflow; + return start; + } + val += digit; + ++start; + } + if (*start != delimiter) + ec = bdecode_errors::expected_colon; + return start; + } + + + struct bdecode_error_category : boost::system::error_category + { + virtual const char* name() const BOOST_SYSTEM_NOEXCEPT; + virtual std::string message(int ev) const BOOST_SYSTEM_NOEXCEPT; + virtual boost::system::error_condition default_error_condition( + int ev) const BOOST_SYSTEM_NOEXCEPT + { return boost::system::error_condition(ev, *this); } + }; + + const char* bdecode_error_category::name() const BOOST_SYSTEM_NOEXCEPT + { + return "bdecode error"; + } + + std::string bdecode_error_category::message(int ev) const BOOST_SYSTEM_NOEXCEPT + { + static char const* msgs[] = + { + "no error", + "expected digit in bencoded string", + "expected colon in bencoded string", + "unexpected end of file in bencoded string", + "expected value (list, dict, int or string) in bencoded string", + "bencoded nesting depth exceeded", + "bencoded item count limit exceeded", + "integer overflow", + }; + if (ev < 0 || ev >= int(sizeof(msgs)/sizeof(msgs[0]))) + return "Unknown error"; + return msgs[ev]; + } + + boost::system::error_category& get_bdecode_category() + { + static bdecode_error_category bdecode_category; + return bdecode_category; + } + + namespace bdecode_errors + { + boost::system::error_code make_error_code(error_code_enum e) + { + return boost::system::error_code(e, get_bdecode_category()); + } + } + + + bdecode_node::bdecode_node() + : m_root_tokens(0) + , m_buffer(NULL) + , m_buffer_size(0) + , m_token_idx(-1) + , m_last_index(-1) + , m_last_token(-1) + , m_size(-1) + {} + + bdecode_node::bdecode_node(bdecode_node const& n) + : m_tokens(n.m_tokens) + , m_root_tokens(n.m_root_tokens) + , m_buffer(n.m_buffer) + , m_buffer_size(n.m_buffer_size) + , m_token_idx(n.m_token_idx) + , m_last_index(n.m_last_index) + , m_last_token(n.m_last_token) + , m_size(n.m_size) + { + (*this) = n; + } + + bdecode_node& bdecode_node::operator=(bdecode_node const& n) + { + m_tokens = n.m_tokens; + m_root_tokens = n.m_root_tokens; + m_buffer = n.m_buffer; + m_buffer_size = n.m_buffer_size; + m_token_idx = n.m_token_idx; + m_last_index = n.m_last_index; + m_last_token = n.m_last_token; + m_size = n.m_size; + if (!m_tokens.empty()) + { + // if this is a root, make the token pointer + // point to our storage + m_root_tokens = &m_tokens[0]; + } + return *this; + } + + bdecode_node::bdecode_node(bdecode_token const* tokens, char const* buf + , int len, int idx) + : m_root_tokens(tokens) + , m_buffer(buf) + , m_buffer_size(len) + , m_token_idx(idx) + , m_last_index(-1) + , m_last_token(-1) + , m_size(-1) + { + TORRENT_ASSERT(tokens != NULL); + TORRENT_ASSERT(idx >= 0); + } + + bdecode_node bdecode_node::non_owning() const + { + // if we're not a root, just return a copy of ourself + if (m_tokens.empty()) return *this; + + // otherwise, return a reference to this node, but without + // being an owning root node + return bdecode_node(&m_tokens[0], m_buffer, m_buffer_size, m_token_idx); + } + + void bdecode_node::clear() + { + m_tokens.clear(); + m_root_tokens = NULL; + m_token_idx = -1; + m_size = -1; + m_last_index = -1; + m_last_token = -1; + } + + void bdecode_node::switch_underlying_buffer(char const* buf) + { + TORRENT_ASSERT(!m_tokens.empty()); + if (m_tokens.empty()) return; + + m_buffer = buf; + } + + bdecode_node::type_t bdecode_node::type() const + { + if (m_token_idx == -1) return none_t; + return (bdecode_node::type_t)m_root_tokens[m_token_idx].type; + } + + bdecode_node::operator bool() const + { return m_token_idx != -1; } + + std::pair bdecode_node::data_section() const + { + if (m_token_idx == -1) return std::make_pair(m_buffer, 0); + + TORRENT_ASSERT(m_token_idx != -1); + bdecode_token const& t = m_root_tokens[m_token_idx]; + bdecode_token const& next = m_root_tokens[m_token_idx + t.next_item]; + return std::make_pair(m_buffer + t.offset, next.offset - t.offset); + } + + bdecode_node bdecode_node::list_at(int i) const + { + TORRENT_ASSERT(type() == list_t); + TORRENT_ASSERT(i >= 0); + + // make sure this is a list. + bdecode_token const* tokens = m_root_tokens; + + // this is the first item + int token = m_token_idx + 1; + int item = 0; + + // do we have a lookup cached? + if (m_last_index <= i && m_last_index != -1) + { + token = m_last_token; + item = m_last_index; + } + + while (item < i) + { + token += tokens[token].next_item; + ++item; + + // index 'i' out of range + TORRENT_ASSERT(tokens[token].type != bdecode_token::end); + } + + m_last_token = token; + m_last_index = i; + + return bdecode_node(tokens, m_buffer, m_buffer_size, token); + } + + std::string bdecode_node::list_string_value_at(int i + , char const* default_val) + { + bdecode_node n = list_at(i); + if (n.type() != bdecode_node::string_t) return default_val; + return n.string_value(); + } + + boost::int64_t bdecode_node::list_int_value_at(int i + , boost::int64_t default_val) + { + bdecode_node n = list_at(i); + if (n.type() != bdecode_node::int_t) return default_val; + return n.int_value(); + } + + int bdecode_node::list_size() const + { + TORRENT_ASSERT(type() == list_t); + + if (m_size != -1) return m_size; + + // make sure this is a list. + bdecode_token const* tokens = m_root_tokens; + TORRENT_ASSERT(tokens[m_token_idx].type == bdecode_token::list); + + // this is the first item + int token = m_token_idx + 1; + int ret = 0; + + // do we have a lookup cached? + if (m_last_index != -1) + { + token = m_last_token; + ret = m_last_index; + } + while (tokens[token].type != bdecode_token::end) + { + token += tokens[token].next_item; + ++ret; + } + + m_size = ret; + + return ret; + } + + std::pair bdecode_node::dict_at(int i) const + { + TORRENT_ASSERT(type() == dict_t); + TORRENT_ASSERT(m_token_idx != -1); + + bdecode_token const* tokens = m_root_tokens; + TORRENT_ASSERT(tokens[m_token_idx].type == bdecode_token::dict); + + int token = m_token_idx + 1; + int item = 0; + + // do we have a lookup cached? + if (m_last_index <= i && m_last_index != -1) + { + token = m_last_token; + item = m_last_index; + } + + while (item < i) + { + TORRENT_ASSERT(tokens[token].type == bdecode_token::string); + + // skip the key + token += tokens[token].next_item; + TORRENT_ASSERT(tokens[token].type != bdecode_token::end); + + // skip the value + token += tokens[token].next_item; + + ++item; + + // index 'i' out of range + TORRENT_ASSERT(tokens[token].type != bdecode_token::end); + } + + // there's no point in caching the first item + if (i > 0) + { + m_last_token = token; + m_last_index = i; + } + + int value_token = token + tokens[token].next_item; + TORRENT_ASSERT(tokens[token].type != bdecode_token::end); + + return std::make_pair( + bdecode_node(tokens, m_buffer, m_buffer_size, token).string_value() + , bdecode_node(tokens, m_buffer, m_buffer_size, value_token)); + } + + int bdecode_node::dict_size() const + { + TORRENT_ASSERT(type() == dict_t); + TORRENT_ASSERT(m_token_idx != -1); + + if (m_size != -1) return m_size; + + bdecode_token const* tokens = m_root_tokens; + TORRENT_ASSERT(tokens[m_token_idx].type == bdecode_token::dict); + + // this is the first item + int token = m_token_idx + 1; + int ret = 0; + + if (m_last_index != -1) + { + ret = m_last_index * 2; + token = m_last_token; + } + + while (tokens[token].type != bdecode_token::end) + { + token += tokens[token].next_item; + ++ret; + } + + // a dictionary must contain full key-value pairs. which means + // the number of entries is divisible by 2 + TORRENT_ASSERT((ret % 2) == 0); + + // each item is one key and one value, so divide by 2 + ret /= 2; + + m_size = ret; + + return ret; + } + + bdecode_node bdecode_node::dict_find(std::string key) const + { + TORRENT_ASSERT(type() == dict_t); + + bdecode_token const* tokens = m_root_tokens; + + // this is the first item + int token = m_token_idx + 1; + + while (tokens[token].type != bdecode_token::end) + { + bdecode_token const& t = tokens[token]; + TORRENT_ASSERT(t.type == bdecode_token::string); + int size = m_root_tokens[token + 1].offset - t.offset - t.start_offset(); + if (int(key.size()) == size + && std::equal(key.c_str(), key.c_str() + size, m_buffer + + t.offset + t.start_offset())) + { + // skip key + token += t.next_item; + TORRENT_ASSERT(tokens[token].type != bdecode_token::end); + + return bdecode_node(tokens, m_buffer, m_buffer_size, token); + } + + // skip key + token += t.next_item; + TORRENT_ASSERT(tokens[token].type != bdecode_token::end); + + // skip value + token += tokens[token].next_item; + } + + return bdecode_node(); + } + + bdecode_node bdecode_node::dict_find_list(char const* key) const + { + bdecode_node ret = dict_find(key); + if (ret.type() == bdecode_node::list_t) + return ret; + return bdecode_node(); + } + + bdecode_node bdecode_node::dict_find_dict(std::string key) const + { + bdecode_node ret = dict_find(key); + if (ret.type() == bdecode_node::dict_t) + return ret; + return bdecode_node(); + } + + bdecode_node bdecode_node::dict_find_dict(char const* key) const + { + bdecode_node ret = dict_find(key); + if (ret.type() == bdecode_node::dict_t) + return ret; + return bdecode_node(); + } + + bdecode_node bdecode_node::dict_find_string(char const* key) const + { + bdecode_node ret = dict_find(key); + if (ret.type() == bdecode_node::string_t) + return ret; + return bdecode_node(); + } + + bdecode_node bdecode_node::dict_find_int(char const* key) const + { + bdecode_node ret = dict_find(key); + if (ret.type() == bdecode_node::int_t) + return ret; + return bdecode_node(); + } + + + bdecode_node bdecode_node::dict_find(char const* key) const + { + TORRENT_ASSERT(type() == dict_t); + + bdecode_token const* tokens = m_root_tokens; + + // this is the first item + int token = m_token_idx + 1; + + while (tokens[token].type != bdecode_token::end) + { + bdecode_token const& t = tokens[token]; + TORRENT_ASSERT(t.type == bdecode_token::string); + int size = m_root_tokens[token + 1].offset - t.offset - t.start_offset(); + if (string_equal(key, m_buffer + t.offset + t.start_offset(), size)) + { + // skip key + token += t.next_item; + TORRENT_ASSERT(tokens[token].type != bdecode_token::end); + + return bdecode_node(tokens, m_buffer, m_buffer_size, token); + } + + // skip key + token += t.next_item; + TORRENT_ASSERT(tokens[token].type != bdecode_token::end); + + // skip value + token += tokens[token].next_item; + } + + return bdecode_node(); + } + + std::string bdecode_node::dict_find_string_value(char const* key + , char const* default_value) const + { + bdecode_node n = dict_find(key); + if (n.type() != bdecode_node::string_t) return default_value; + return n.string_value(); + } + + boost::int64_t bdecode_node::dict_find_int_value(char const* key + , boost::int64_t default_val) const + { + bdecode_node n = dict_find(key); + if (n.type() != bdecode_node::int_t) return default_val; + return n.int_value(); + } + + boost::int64_t bdecode_node::int_value() const + { + TORRENT_ASSERT(type() == int_t); + bdecode_token const& t = m_root_tokens[m_token_idx]; + int size = m_root_tokens[m_token_idx + 1].offset - t.offset; + TORRENT_ASSERT(t.type == bdecode_token::integer); + + // +1 is to skip the 'i' + char const* ptr = m_buffer + t.offset + 1; + boost::int64_t val = 0; + bool negative = false; + if (*ptr == '-') negative = true; + bdecode_errors::error_code_enum ec = bdecode_errors::no_error; + parse_int(ptr + negative + , ptr + size, 'e', val, ec); + if (ec) return 0; + if (negative) val = -val; + return val; + } + + std::string bdecode_node::string_value() const + { + TORRENT_ASSERT(type() == string_t); + bdecode_token const& t = m_root_tokens[m_token_idx]; + int size = m_root_tokens[m_token_idx + 1].offset - t.offset - t.start_offset(); + TORRENT_ASSERT(t.type == bdecode_token::string); + + return std::string(m_buffer + t.offset + t.start_offset(), size); + } + + char const* bdecode_node::string_ptr() const + { + TORRENT_ASSERT(type() == string_t); + bdecode_token const& t = m_root_tokens[m_token_idx]; + TORRENT_ASSERT(t.type == bdecode_token::string); + return m_buffer + t.offset + t.start_offset(); + } + + int bdecode_node::string_length() const + { + TORRENT_ASSERT(type() == string_t); + bdecode_token const& t = m_root_tokens[m_token_idx]; + TORRENT_ASSERT(t.type == bdecode_token::string); + return m_root_tokens[m_token_idx + 1].offset - t.offset - t.start_offset(); + } + + void bdecode_node::reserve(int tokens) + { m_tokens.reserve(tokens); } + + void bdecode_node::swap(bdecode_node& n) + { +/* + bool lhs_is_root = (m_root_tokens == &m_tokens); + bool rhs_is_root = (n.m_root_tokens == &n.m_tokens); + + // swap is only defined between non-root nodes + // and between root-nodes. They may not be mixed! + // note that when swapping root nodes, all bdecode_node + // entries that exist in those subtrees are invalidated! + TORRENT_ASSERT(lhs_is_root == rhs_is_root); + + // if both are roots, m_root_tokens always point to + // its own vector, and should not get swapped (the + // underlying vectors are swapped already) + if (!lhs_is_root && !rhs_is_root) + { + // if neither is a root, we just swap the pointers + // to the token vectors, switching their roots + std::swap(m_root_tokens, n.m_root_tokens); + } +*/ + m_tokens.swap(n.m_tokens); + std::swap(m_root_tokens, n.m_root_tokens); + std::swap(m_buffer, n.m_buffer); + std::swap(m_buffer_size, n.m_buffer_size); + std::swap(m_token_idx, n.m_token_idx); + std::swap(m_last_index, n.m_last_index); + std::swap(m_last_token, n.m_last_token); + std::swap(m_size, n.m_size); + } + +#define TORRENT_FAIL_BDECODE(code) do { \ + ec = make_error_code(code); \ + if (error_pos) *error_pos = start - orig_start; \ + goto done; \ + } while (false) + + int bdecode(char const* start, char const* end, bdecode_node& ret + , error_code& ec, int* error_pos, int depth_limit, int token_limit) + { + ec.clear(); + ret.clear(); + + if (end - start > bdecode_token::max_offset) + { + if (error_pos) *error_pos = 0; + ec = make_error_code(bdecode_errors::limit_exceeded); + return -1; + } + + // this is the stack of bdecode_token indices, into m_tokens. + // sp is the stack pointer, as index into the array, stack + int sp = 0; + stack_frame* stack = TORRENT_ALLOCA(stack_frame, depth_limit); + + char const* const orig_start = start; + if (start == end) return 0; + + while (start <= end) + { + if (start >= end) TORRENT_FAIL_BDECODE(bdecode_errors::unexpected_eof); + + if (sp >= depth_limit) + TORRENT_FAIL_BDECODE(bdecode_errors::depth_exceeded); + + --token_limit; + if (token_limit < 0) + TORRENT_FAIL_BDECODE(bdecode_errors::limit_exceeded); + + // look for a new token + const char t = *start; + + const int current_frame = sp; + + // if we're currently parsing a dictionary, assert that + // every other node is a string. + if (current_frame > 0 + && ret.m_tokens[stack[current_frame-1].token].type == bdecode_token::dict) + { + if (stack[current_frame-1].state == 0) + { + // the current parent is a dict and we are parsing a key. + // only allow a digit (for a string) or 'e' to terminate + if (!numeric(t) && t != 'e') + TORRENT_FAIL_BDECODE(bdecode_errors::expected_digit); + } + } + + switch (t) + { + case 'd': + stack[sp++] = ret.m_tokens.size(); + // we push it into the stack so that we know where to fill + // in the next_node field once we pop this node off the stack. + // i.e. get to the node following the dictionary in the buffer + ret.m_tokens.push_back(bdecode_token(start - orig_start + , bdecode_token::dict)); + ++start; + break; + case 'l': + stack[sp++] = ret.m_tokens.size(); + // we push it into the stack so that we know where to fill + // in the next_node field once we pop this node off the stack. + // i.e. get to the node following the list in the buffer + ret.m_tokens.push_back(bdecode_token(start - orig_start + , bdecode_token::list)); + ++start; + break; + case 'i': + { + char const* int_start = start; + bdecode_errors::error_code_enum e = bdecode_errors::no_error; + // +1 here to point to the first digit, rather than 'i' + start = check_integer(start + 1, end, e); + if (e) + { + // in order to gracefully terminate the tree, + // make sure the end of the previous token is set correctly + if (error_pos) *error_pos = start - orig_start; + error_pos = NULL; + start = int_start; + TORRENT_FAIL_BDECODE(e); + } + ret.m_tokens.push_back(bdecode_token(int_start - orig_start + , 1, bdecode_token::integer, 1)); + TORRENT_ASSERT(*start == 'e'); + + // skip 'e' + ++start; + break; + } + case 'e': + { + // this is the end of a list or dict + if (sp == 0) + TORRENT_FAIL_BDECODE(bdecode_errors::unexpected_eof); + + if (sp > 0 + && ret.m_tokens[stack[sp-1].token].type == bdecode_token::dict + && stack[sp-1].state == 1) + { + // this means we're parsing a dictionary and about to parse a + // value associated with a key. Instad, we got a termination + TORRENT_FAIL_BDECODE(bdecode_errors::expected_value); + } + + // insert the end-of-sequence token + ret.m_tokens.push_back(bdecode_token(start - orig_start, 1 + , bdecode_token::end)); + + // and back-patch the start of this sequence with the offset + // to the next token we'll insert + int top = stack[sp-1].token; + // subtract the token's own index, since this is a relative + // offset + if (ret.m_tokens.size() - top > bdecode_token::max_next_item) + TORRENT_FAIL_BDECODE(bdecode_errors::limit_exceeded); + + ret.m_tokens[top].next_item = ret.m_tokens.size() - top; + + // and pop it from the stack. + --sp; + ++start; + break; + } + default: + { + // this is the case for strings. The start character is any + // numeric digit + if (!numeric(t)) + TORRENT_FAIL_BDECODE(bdecode_errors::expected_value); + + boost::int64_t len = t - '0'; + char const* str_start = start; + ++start; + bdecode_errors::error_code_enum e = bdecode_errors::no_error; + start = parse_int(start, end, ':', len, e); + if (e) + TORRENT_FAIL_BDECODE(e); + if (start + len + 1 > end) + TORRENT_FAIL_BDECODE(bdecode_errors::unexpected_eof); + if (len < 0) + TORRENT_FAIL_BDECODE(bdecode_errors::overflow); + + // skip ':' + ++start; + if (start >= end) TORRENT_FAIL_BDECODE(bdecode_errors::unexpected_eof); + + // the bdecode_token only has 8 bits to keep the header size + // in. If it overflows, fail! + if (start - str_start - 2 > detail::bdecode_token::max_header) + TORRENT_FAIL_BDECODE(bdecode_errors::limit_exceeded); + + ret.m_tokens.push_back(bdecode_token(str_start - orig_start + , 1, bdecode_token::string, start - str_start)); + start += len; + break; + } + } + + if (current_frame > 0 + && ret.m_tokens[stack[current_frame-1].token].type == bdecode_token::dict) + { + // the next item we parse is the opposite + stack[current_frame-1].state = ~stack[current_frame-1].state; + } + + // this terminates the top level node, we're done! + if (sp == 0) break; + } + +done: + + // if parse failed, sp will be greater than 1 + // unwind the stack by inserting terminator to make whatever we have + // so far valid + while (sp > 0) { + TORRENT_ASSERT(ec); + --sp; + + // we may need to insert a dummy token to properly terminate the tree, + // in case we just parsed a key to a dict and failed in the value + if (ret.m_tokens[stack[sp].token].type == bdecode_token::dict + && stack[sp].state == 1) + { + // insert an empty dictionary as the value + ret.m_tokens.push_back(bdecode_token(start - orig_start + , 2, bdecode_token::dict)); + ret.m_tokens.push_back(bdecode_token(start - orig_start + , bdecode_token::end)); + } + + int top = stack[sp].token; + TORRENT_ASSERT(ret.m_tokens.size() - top <= bdecode_token::max_next_item); + ret.m_tokens[top].next_item = ret.m_tokens.size() - top; + ret.m_tokens.push_back(bdecode_token(start - orig_start, 1, bdecode_token::end)); + } + + ret.m_tokens.push_back(bdecode_token(start - orig_start, 0 + , bdecode_token::end)); + + ret.m_token_idx = 0; + ret.m_buffer = orig_start; + ret.m_buffer_size = start - orig_start; + ret.m_root_tokens = &ret.m_tokens[0]; + + return ec ? -1 : 0; + } + + namespace { + + int line_longer_than(bdecode_node const& e, int limit) + { + int line_len = 0; + switch (e.type()) + { + case bdecode_node::list_t: + line_len += 4; + if (line_len > limit) return -1; + for (int i = 0; i < e.list_size(); ++i) + { + int ret = line_longer_than(e.list_at(i), limit - line_len); + if (ret == -1) return -1; + line_len += ret + 2; + } + break; + case bdecode_node::dict_t: + line_len += 4; + if (line_len > limit) return -1; + for (int i = 0; i < e.dict_size(); ++i) + { + line_len += 4 + e.dict_at(i).first.size(); + if (line_len > limit) return -1; + int ret = line_longer_than(e.dict_at(i).second, limit - line_len); + if (ret == -1) return -1; + line_len += ret + 1; + } + break; + case bdecode_node::string_t: + line_len += 3 + e.string_length(); + break; + case bdecode_node::int_t: + { + boost::int64_t val = e.int_value(); + while (val > 0) + { + ++line_len; + val /= 10; + } + line_len += 2; + } + break; + case bdecode_node::none_t: + line_len += 4; + break; + } + + if (line_len > limit) return -1; + return line_len; + } + + void escape_string(std::string& ret, char const* str, int len) + { + for (int i = 0; i < len; ++i) + { + if (str[i] >= 32 && str[i] < 127) + { + ret += str[i]; + } + else + { + char tmp[5]; + snprintf(tmp, sizeof(tmp), "\\x%02x", (unsigned char)str[i]); + ret += tmp; + } + } + } + + void print_string(std::string& ret, char const* str, int len, bool single_line) + { + bool printable = true; + for (int i = 0; i < len; ++i) + { + char c = str[i]; + if (c >= 32 && c < 127) continue; + printable = false; + break; + } + ret += "'"; + if (printable) + { + if (single_line && len > 30) + { + ret.append(str, 14); + ret += "..."; + ret.append(str + len-14, 14); + } + else + ret.append(str, len); + ret += "'"; + return; + } + if (single_line && len > 20) + { + escape_string(ret, str, 9); + ret += "..."; + escape_string(ret, str + len - 9, 9); + } + else + { + escape_string(ret, str, len); + } + ret += "'"; + } + +} + + std::string print_entry(bdecode_node const& e + , bool single_line, int indent) + { + char indent_str[200]; + using std::memset; + memset(indent_str, ' ', 200); + indent_str[0] = ','; + indent_str[1] = '\n'; + indent_str[199] = 0; + if (indent < 197 && indent >= 0) indent_str[indent+2] = 0; + std::string ret; + switch (e.type()) + { + case bdecode_node::none_t: return "none"; + case bdecode_node::int_t: + { + char str[100]; + snprintf(str, sizeof(str), "%" PRId64, e.int_value()); + return str; + } + case bdecode_node::string_t: + { + print_string(ret, e.string_ptr(), e.string_length(), single_line); + return ret; + } + case bdecode_node::list_t: + { + ret += '['; + bool one_liner = line_longer_than(e, 200) != -1 || single_line; + + if (!one_liner) ret += indent_str + 1; + for (int i = 0; i < e.list_size(); ++i) + { + if (i == 0 && one_liner) ret += " "; + ret += print_entry(e.list_at(i), single_line, indent + 2); + if (i < e.list_size() - 1) ret += (one_liner?", ":indent_str); + else ret += (one_liner?" ":indent_str+1); + } + ret += "]"; + return ret; + } + case bdecode_node::dict_t: + { + ret += "{"; + bool one_liner = line_longer_than(e, 200) != -1 || single_line; + + if (!one_liner) ret += indent_str+1; + for (int i = 0; i < e.dict_size(); ++i) + { + if (i == 0 && one_liner) ret += " "; + std::pair ent = e.dict_at(i); + print_string(ret, ent.first.c_str(), ent.first.size(), true); + ret += ": "; + ret += print_entry(ent.second, single_line, indent + 2); + if (i < e.dict_size() - 1) ret += (one_liner?", ":indent_str); + else ret += (one_liner?" ":indent_str+1); + } + ret += "}"; + return ret; + } + } + return ret; + } +} + diff --git a/src/bt_peer_connection.cpp b/src/bt_peer_connection.cpp index dba479a5b..fb86ffa43 100644 --- a/src/bt_peer_connection.cpp +++ b/src/bt_peer_connection.cpp @@ -1263,9 +1263,9 @@ namespace libtorrent #ifdef TORRENT_LOGGING peer_log("<== HASHPIECE [ piece: %d list: %d ]", p.piece, list_size); #endif - lazy_entry hash_list; + bdecode_node hash_list; error_code ec; - if (lazy_bdecode(recv_buffer.begin + 13, recv_buffer.begin+ 13 + list_size + if (bdecode(recv_buffer.begin + 13, recv_buffer.begin+ 13 + list_size , hash_list, ec) != 0) { disconnect(errors::invalid_hash_piece, op_bittorrent, 2); @@ -1274,7 +1274,7 @@ namespace libtorrent // the list has this format: // [ [node-index, hash], [node-index, hash], ... ] - if (hash_list.type() != lazy_entry::list_t) + if (hash_list.type() != bdecode_node::list_t) { disconnect(errors::invalid_hash_list, op_bittorrent, 2); return; @@ -1283,15 +1283,15 @@ namespace libtorrent std::map nodes; for (int i = 0; i < hash_list.list_size(); ++i) { - lazy_entry const* e = hash_list.list_at(i); - if (e->type() != lazy_entry::list_t - || e->list_size() != 2 - || e->list_at(0)->type() != lazy_entry::int_t - || e->list_at(1)->type() != lazy_entry::string_t - || e->list_at(1)->string_length() != 20) continue; + bdecode_node e = hash_list.list_at(i); + if (e.type() != bdecode_node::list_t + || e.list_size() != 2 + || e.list_at(0).type() != bdecode_node::int_t + || e.list_at(1).type() != bdecode_node::string_t + || e.list_at(1).string_length() != 20) continue; - nodes.insert(std::make_pair(int(e->list_int_value_at(0)) - , sha1_hash(e->list_at(1)->string_ptr()))); + nodes.insert(std::make_pair(int(e.list_int_value_at(0)) + , sha1_hash(e.list_at(1).string_ptr()))); } if (!nodes.empty() && !t->add_merkle_nodes(nodes, p.piece)) { @@ -1783,11 +1783,11 @@ namespace libtorrent buffer::const_interval recv_buffer = m_recv_buffer.get(); - lazy_entry root; + bdecode_node root; error_code ec; int pos; - int ret = lazy_bdecode(recv_buffer.begin + 2, recv_buffer.end, root, ec, &pos); - if (ret != 0 || ec || root.type() != lazy_entry::dict_t) + int ret = bdecode(recv_buffer.begin + 2, recv_buffer.end, root, ec, &pos); + if (ret != 0 || ec || root.type() != bdecode_node::dict_t) { #ifdef TORRENT_LOGGING peer_log("*** invalid extended handshake: %s pos: %d" @@ -1813,11 +1813,11 @@ namespace libtorrent if (is_disconnecting()) return; // upload_only - if (lazy_entry const* m = root.dict_find_dict("m")) + if (bdecode_node m = root.dict_find_dict("m")) { - m_upload_only_id = boost::uint8_t(m->dict_find_int_value("upload_only", 0)); - m_holepunch_id = boost::uint8_t(m->dict_find_int_value("ut_holepunch", 0)); - m_dont_have_id = boost::uint8_t(m->dict_find_int_value("lt_donthave", 0)); + m_upload_only_id = boost::uint8_t(m.dict_find_int_value("upload_only", 0)); + m_holepunch_id = boost::uint8_t(m.dict_find_int_value("ut_holepunch", 0)); + m_dont_have_id = boost::uint8_t(m.dict_find_int_value("lt_donthave", 0)); } // there is supposed to be a remote listen port diff --git a/src/disk_io_thread.cpp b/src/disk_io_thread.cpp index be46e7445..83a8c327c 100644 --- a/src/disk_io_thread.cpp +++ b/src/disk_io_thread.cpp @@ -1902,7 +1902,7 @@ namespace libtorrent } void disk_io_thread::async_check_fastresume(piece_manager* storage - , lazy_entry const* resume_data + , bdecode_node const* resume_data , boost::function const& handler) { #ifdef TORRENT_DEBUG @@ -2603,8 +2603,8 @@ namespace libtorrent // if this assert fails, something's wrong with the fence logic TORRENT_ASSERT(j->storage->num_outstanding_jobs() == 1); - lazy_entry const* rd = (lazy_entry const*)j->buffer; - lazy_entry tmp; + bdecode_node const* rd = (bdecode_node const*)j->buffer; + bdecode_node tmp; if (rd == NULL) rd = &tmp; return j->storage->check_fastresume(*rd, j->error); diff --git a/src/entry.cpp b/src/entry.cpp index 93a7a3027..d7402c942 100644 --- a/src/entry.cpp +++ b/src/entry.cpp @@ -38,7 +38,10 @@ POSSIBILITY OF SUCH DAMAGE. #include "libtorrent/entry.hpp" #include "libtorrent/config.hpp" #include "libtorrent/escape_string.hpp" +#ifndef TORRENT_NO_DEPRECATE #include "libtorrent/lazy_entry.hpp" +#endif +#include "libtorrent/bdecode.hpp" #include "libtorrent/escape_string.hpp" #if defined(_MSC_VER) @@ -314,6 +317,44 @@ namespace libtorrent m_type = int_t; } + // convert a bdecode_node into an old skool entry + void entry::operator=(bdecode_node const& e) + { + switch (e.type()) + { + case bdecode_node::string_t: + this->string() = e.string_value(); + break; + case bdecode_node::int_t: + this->integer() = e.int_value(); + break; + case bdecode_node::dict_t: + { + dictionary_type& d = this->dict(); + for (int i = 0; i < e.dict_size(); ++i) + { + std::pair elem = e.dict_at(i); + d[elem.first] = elem.second; + } + break; + } + case bdecode_node::list_t: + { + list_type& l = this->list(); + for (int i = 0; i < e.list_size(); ++i) + { + l.push_back(entry()); + l.back() = e.list_at(i); + } + break; + } + case bdecode_node::none_t: + destruct(); + break; + } + } + +#ifndef TORRENT_NO_DEPRECATE // convert a lazy_entry into an old skool entry void entry::operator=(lazy_entry const& e) { @@ -350,6 +391,7 @@ namespace libtorrent break; } } +#endif void entry::operator=(dictionary_type const& v) { diff --git a/src/http_tracker_connection.cpp b/src/http_tracker_connection.cpp index 70684a7ec..2e594f90b 100644 --- a/src/http_tracker_connection.cpp +++ b/src/http_tracker_connection.cpp @@ -377,18 +377,18 @@ namespace libtorrent close(); } - bool extract_peer_info(lazy_entry const& info, peer_entry& ret, error_code& ec) + bool extract_peer_info(bdecode_node const& info, peer_entry& ret, error_code& ec) { // extract peer id (if any) - if (info.type() != lazy_entry::dict_t) + if (info.type() != bdecode_node::dict_t) { ec.assign(errors::invalid_peer_dict, get_libtorrent_category()); return false; } - lazy_entry const* i = info.dict_find_string("peer id"); - if (i != 0 && i->string_length() == 20) + bdecode_node i = info.dict_find_string("peer id"); + if (i && i.string_length() == 20) { - std::copy(i->string_ptr(), i->string_ptr()+20, ret.pid.begin()); + std::copy(i.string_ptr(), i.string_ptr()+20, ret.pid.begin()); } else { @@ -403,7 +403,7 @@ namespace libtorrent ec.assign(errors::invalid_tracker_response, get_libtorrent_category()); return false; } - ret.hostname = i->string_value(); + ret.hostname = i.string_value(); // extract port i = info.dict_find_int("port"); @@ -412,7 +412,7 @@ namespace libtorrent ec.assign(errors::invalid_tracker_response, get_libtorrent_category()); return false; } - ret.port = (unsigned short)i->int_value(); + ret.port = (unsigned short)i.int_value(); return true; } @@ -422,12 +422,12 @@ namespace libtorrent { tracker_response resp; - lazy_entry e; - int res = lazy_bdecode(data, data + size, e, ec); + bdecode_node e; + int res = bdecode(data, data + size, e, ec); if (ec) return resp; - if (res != 0 || e.type() != lazy_entry::dict_t) + if (res != 0 || e.type() != bdecode_node::dict_t) { ec.assign(errors::invalid_tracker_response, get_libtorrent_category()); return resp; @@ -441,45 +441,45 @@ namespace libtorrent resp.interval = interval; resp.min_interval = min_interval; - lazy_entry const* tracker_id = e.dict_find_string("tracker id"); + bdecode_node tracker_id = e.dict_find_string("tracker id"); if (tracker_id) - resp.trackerid = tracker_id->string_value(); + resp.trackerid = tracker_id.string_value(); // parse the response - lazy_entry const* failure = e.dict_find_string("failure reason"); + bdecode_node failure = e.dict_find_string("failure reason"); if (failure) { - resp.failure_reason = failure->string_value(); + resp.failure_reason = failure.string_value(); ec.assign(errors::tracker_failure, get_libtorrent_category()); return resp; } - lazy_entry const* warning = e.dict_find_string("warning message"); + bdecode_node warning = e.dict_find_string("warning message"); if (warning) - resp.warning_message = warning->string_value(); + resp.warning_message = warning.string_value(); if (scrape_request) { - lazy_entry const* files = e.dict_find_dict("files"); - if (files == 0) + bdecode_node files = e.dict_find_dict("files"); + if (!files) { ec.assign(errors::invalid_files_entry, get_libtorrent_category()); return resp; } - lazy_entry const* scrape_data = files->dict_find_dict( + bdecode_node scrape_data = files.dict_find_dict( scrape_ih.to_string()); - if (scrape_data == 0) + if (!scrape_data) { ec.assign(errors::invalid_hash_entry, get_libtorrent_category()); return resp; } - resp.complete = int(scrape_data->dict_find_int_value("complete", -1)); - resp.incomplete = int(scrape_data->dict_find_int_value("incomplete", -1)); - resp.downloaded = int(scrape_data->dict_find_int_value("downloaded", -1)); - resp.downloaders = int(scrape_data->dict_find_int_value("downloaders", -1)); + resp.complete = int(scrape_data.dict_find_int_value("complete", -1)); + resp.incomplete = int(scrape_data.dict_find_int_value("incomplete", -1)); + resp.downloaded = int(scrape_data.dict_find_int_value("downloaded", -1)); + resp.downloaders = int(scrape_data.dict_find_int_value("downloaders", -1)); return resp; } @@ -489,11 +489,11 @@ namespace libtorrent resp.incomplete = int(e.dict_find_int_value("incomplete", -1)); resp.downloaded = int(e.dict_find_int_value("downloaded", -1)); - lazy_entry const* peers_ent = e.dict_find("peers"); - if (peers_ent && peers_ent->type() == lazy_entry::string_t) + bdecode_node peers_ent = e.dict_find("peers"); + if (peers_ent && peers_ent.type() == bdecode_node::string_t) { - char const* peers = peers_ent->string_ptr(); - int len = peers_ent->string_length(); + char const* peers = peers_ent.string_ptr(); + int len = peers_ent.string_length(); resp.peers4.reserve(len / 6); for (int i = 0; i < len; i += 6) { @@ -506,15 +506,15 @@ namespace libtorrent resp.peers4.push_back(p); } } - else if (peers_ent && peers_ent->type() == lazy_entry::list_t) + else if (peers_ent && peers_ent.type() == bdecode_node::list_t) { - int len = peers_ent->list_size(); + int len = peers_ent.list_size(); resp.peers.reserve(len); error_code parse_error; for (int i = 0; i < len; ++i) { peer_entry p; - if (!extract_peer_info(*peers_ent->list_at(i), p, parse_error)) + if (!extract_peer_info(peers_ent.list_at(i), p, parse_error)) continue; resp.peers.push_back(p); } @@ -528,15 +528,15 @@ namespace libtorrent } else { - peers_ent = 0; + peers_ent.clear(); } #if TORRENT_USE_IPV6 - lazy_entry const* ipv6_peers = e.dict_find_string("peers6"); + bdecode_node ipv6_peers = e.dict_find_string("peers6"); if (ipv6_peers) { - char const* peers = ipv6_peers->string_ptr(); - int len = ipv6_peers->string_length(); + char const* peers = ipv6_peers.string_ptr(); + int len = ipv6_peers.string_length(); resp.peers6.reserve(len / 18); for (int i = 0; i < len; i += 18) { @@ -550,10 +550,10 @@ namespace libtorrent } else { - ipv6_peers = 0; + ipv6_peers.clear(); } #else - lazy_entry const* ipv6_peers = 0; + bdecode_node ipv6_peers = 0; #endif /* // if we didn't receive any peers. We don't care if we're stopping anyway @@ -564,14 +564,14 @@ namespace libtorrent return resp; } */ - lazy_entry const* ip_ent = e.dict_find_string("external ip"); + bdecode_node ip_ent = e.dict_find_string("external ip"); if (ip_ent) { - char const* p = ip_ent->string_ptr(); - if (ip_ent->string_length() == int(address_v4::bytes_type().size())) + char const* p = ip_ent.string_ptr(); + if (ip_ent.string_length() == int(address_v4::bytes_type().size())) resp.external_ip = detail::read_v4_address(p); #if TORRENT_USE_IPV6 - else if (ip_ent->string_length() == int(address_v6::bytes_type().size())) + else if (ip_ent.string_length() == int(address_v6::bytes_type().size())) resp.external_ip = detail::read_v6_address(p); #endif } diff --git a/src/kademlia/dht_tracker.cpp b/src/kademlia/dht_tracker.cpp index 8ef1897e9..0def32230 100644 --- a/src/kademlia/dht_tracker.cpp +++ b/src/kademlia/dht_tracker.cpp @@ -72,9 +72,9 @@ namespace libtorrent { namespace dht void incoming_error(entry& e, char const* msg); #ifdef TORRENT_DHT_VERBOSE_LOGGING - std::string parse_dht_client(lazy_entry const& e) + std::string parse_dht_client(bdecode_node const& e) { - lazy_entry const* ver = e.dict_find_string("v"); + bdecode_node ver = e.dict_find_string("v"); if (!ver) return "generic"; std::string const& client = ver->string_value(); if (client.size() < 2) @@ -116,12 +116,12 @@ namespace libtorrent { namespace dht TORRENT_DEFINE_LOG(dht_tracker) #endif - node_id extract_node_id(lazy_entry const* e) + node_id extract_node_id(bdecode_node e) { - if (e == 0 || e->type() != lazy_entry::dict_t) return (node_id::min)(); - lazy_entry const* nid = e->dict_find_string("node-id"); - if (nid == 0 || nid->string_length() != 20) return (node_id::min)(); - return node_id(node_id(nid->string_ptr())); + if (!e || e.type() != bdecode_node::dict_t) return (node_id::min)(); + bdecode_node nid = e.dict_find_string("node-id"); + if (!nid || nid.string_length() != 20) return (node_id::min)(); + return node_id(node_id(nid.string_ptr())); } node_id extract_node_id(entry const* e) @@ -135,7 +135,8 @@ namespace libtorrent { namespace dht // class that puts the networking and the kademlia node in a single // unit and connecting them together. - dht_tracker::dht_tracker(libtorrent::aux::session_impl& ses, rate_limited_udp_socket& sock + dht_tracker::dht_tracker(libtorrent::aux::session_impl& ses + , rate_limited_udp_socket& sock , dht_settings const& settings, counters& cnt, entry const* state) : m_counters(cnt) , m_dht(&ses, this, settings, extract_node_id(state) @@ -391,10 +392,9 @@ namespace libtorrent { namespace dht TORRENT_ASSERT(size > 0); - lazy_entry e; int pos; error_code err; - int ret = lazy_bdecode(buf, buf + size, e, err, &pos, 10, 500); + int ret = bdecode(buf, buf + size, m_msg, err, &pos, 10, 500); if (ret != 0) { #ifdef TORRENT_DHT_VERBOSE_LOGGING @@ -404,9 +404,7 @@ namespace libtorrent { namespace dht return false; } - libtorrent::dht::msg m(e, ep); - - if (e.type() != lazy_entry::dict_t) + if (m_msg.type() != bdecode_node::dict_t) { #ifdef TORRENT_DHT_VERBOSE_LOGGING TORRENT_LOG(dht_tracker) << "<== " << ep << " ERROR: not a dictionary: " @@ -420,6 +418,7 @@ namespace libtorrent { namespace dht return false; } + libtorrent::dht::msg m(m_msg, ep); m_dht.incoming(m); return true; } @@ -503,8 +502,8 @@ namespace libtorrent { namespace dht #ifdef TORRENT_DHT_VERBOSE_LOGGING std::stringstream log_line; - lazy_entry print; - int ret = lazy_bdecode(&m_send_buf[0], &m_send_buf[0] + m_send_buf.size(), print, ec); + bdecode_node print; + int ret = bdecode(&m_send_buf[0], &m_send_buf[0] + m_send_buf.size(), print, ec); TORRENT_ASSERT(ret == 0); log_line << print_entry(print, true); #endif diff --git a/src/kademlia/find_data.cpp b/src/kademlia/find_data.cpp index 0106bc92c..d8ffb544b 100644 --- a/src/kademlia/find_data.cpp +++ b/src/kademlia/find_data.cpp @@ -54,7 +54,7 @@ using detail::read_v6_endpoint; void find_data_observer::reply(msg const& m) { - lazy_entry const* r = m.message.dict_find_dict("r"); + bdecode_node r = m.message.dict_find_dict("r"); if (!r) { #ifdef TORRENT_DHT_VERBOSE_LOGGING @@ -63,19 +63,19 @@ void find_data_observer::reply(msg const& m) return; } - lazy_entry const* id = r->dict_find_string("id"); - if (!id || id->string_length() != 20) + bdecode_node id = r.dict_find_string("id"); + if (!id || id.string_length() != 20) { #ifdef TORRENT_DHT_VERBOSE_LOGGING TORRENT_LOG(traversal) << "[" << m_algorithm.get() << "] invalid id in response"; #endif return; } - lazy_entry const* token = r->dict_find_string("token"); + bdecode_node token = r.dict_find_string("token"); if (token) { static_cast(m_algorithm.get())->got_write_token( - node_id(id->string_ptr()), token->string_value()); + node_id(id.string_ptr()), token.string_value()); } traversal_observer::reply(m); diff --git a/src/kademlia/get_item.cpp b/src/kademlia/get_item.cpp index c31ede630..24b05a075 100644 --- a/src/kademlia/get_item.cpp +++ b/src/kademlia/get_item.cpp @@ -42,7 +42,7 @@ POSSIBILITY OF SUCH DAMAGE. namespace libtorrent { namespace dht { -void get_item::got_data(lazy_entry const* v, +void get_item::got_data(bdecode_node const& v, char const* pk, boost::uint64_t seq, char const* sig) @@ -55,7 +55,7 @@ void get_item::got_data(lazy_entry const* v, if (pk) incoming_target = item_target_id(salt, pk); else - incoming_target = item_target_id(v->data_section()); + incoming_target = item_target_id(v.data_section()); if (incoming_target != m_target) return; @@ -248,7 +248,7 @@ void get_item_observer::reply(msg const& m) char const* sig = NULL; boost::uint64_t seq = 0; - lazy_entry const* r = m.message.dict_find_dict("r"); + bdecode_node r = m.message.dict_find_dict("r"); if (!r) { #ifdef TORRENT_DHT_VERBOSE_LOGGING @@ -257,21 +257,21 @@ void get_item_observer::reply(msg const& m) return; } - lazy_entry const* k = r->dict_find_string("k"); - if (k && k->string_length() == item_pk_len) - pk = k->string_ptr(); + bdecode_node k = r.dict_find_string("k"); + if (k && k.string_length() == item_pk_len) + pk = k.string_ptr(); - lazy_entry const* s = r->dict_find_string("sig"); - if (s && s->string_length() == item_sig_len) - sig = s->string_ptr(); + bdecode_node s = r.dict_find_string("sig"); + if (s && s.string_length() == item_sig_len) + sig = s.string_ptr(); - lazy_entry const* q = r->dict_find_int("seq"); + bdecode_node q = r.dict_find_int("seq"); if (q) - seq = q->int_value(); + seq = q.int_value(); else if (pk && sig) return; - lazy_entry const* v = r->dict_find("v"); + bdecode_node v = r.dict_find("v"); if (v) { static_cast(m_algorithm.get())->got_data(v, pk, seq, sig); diff --git a/src/kademlia/get_peers.cpp b/src/kademlia/get_peers.cpp index 922ca7466..e5f848a78 100644 --- a/src/kademlia/get_peers.cpp +++ b/src/kademlia/get_peers.cpp @@ -47,7 +47,7 @@ using detail::read_v6_endpoint; void get_peers_observer::reply(msg const& m) { - lazy_entry const* r = m.message.dict_find_dict("r"); + bdecode_node r = m.message.dict_find_dict("r"); if (!r) { #ifdef TORRENT_DHT_VERBOSE_LOGGING @@ -57,27 +57,27 @@ void get_peers_observer::reply(msg const& m) } // look for peers - lazy_entry const* n = r->dict_find_list("values"); + bdecode_node n = r.dict_find_list("values"); if (n) { std::vector peer_list; - if (n->list_size() == 1 && n->list_at(0)->type() == lazy_entry::string_t) + if (n.list_size() == 1 && n.list_at(0).type() == bdecode_node::string_t) { // assume it's mainline format - char const* peers = n->list_at(0)->string_ptr(); - char const* end = peers + n->list_at(0)->string_length(); + char const* peers = n.list_at(0).string_ptr(); + char const* end = peers + n.list_at(0).string_length(); #ifdef TORRENT_DHT_VERBOSE_LOGGING - lazy_entry const* id = r->dict_find_string("id"); - if (id && id->string_length() == 20) + bdecode_node id = r.dict_find_string("id"); + if (id && id.string_length() == 20) { TORRENT_LOG(traversal) << "[" << m_algorithm.get() << "] PEERS" - << " invoke-count: " << m_algorithm->invoke_count() - << " branch-factor: " << m_algorithm->branch_factor() + << " invoke-count: " << m_algorithm.invoke_count() + << " branch-factor: " << m_algorithm.branch_factor() << " addr: " << m.addr - << " id: " << node_id(id->string_ptr()) - << " distance: " << distance_exp(m_algorithm->target(), node_id(id->string_ptr())) + << " id: " << node_id(id.string_ptr()) + << " distance: " << distance_exp(m_algorithm.target(), node_id(id.string_ptr())) << " p: " << ((end - peers) / 6); } #endif @@ -89,17 +89,17 @@ void get_peers_observer::reply(msg const& m) // assume it's uTorrent/libtorrent format read_endpoint_list(n, peer_list); #ifdef TORRENT_DHT_VERBOSE_LOGGING - lazy_entry const* id = r->dict_find_string("id"); - if (id && id->string_length() == 20) + bdecode_node id = r.dict_find_string("id"); + if (id && id.string_length() == 20) { TORRENT_LOG(traversal) << "[" << m_algorithm.get() << "] PEERS" << " invoke-count: " << m_algorithm->invoke_count() << " branch-factor: " << m_algorithm->branch_factor() << " addr: " << m.addr - << " id: " << node_id(id->string_ptr()) + << " id: " << node_id(id.string_ptr()) << " distance: " << distance_exp(m_algorithm->target(), node_id(id->string_ptr())) - << " p: " << n->list_size(); + << " p: " << n.list_size(); } #endif } @@ -295,7 +295,7 @@ void obfuscated_get_peers::done() void obfuscated_get_peers_observer::reply(msg const& m) { - lazy_entry const* r = m.message.dict_find_dict("r"); + bdecode_node r = m.message.dict_find_dict("r"); if (!r) { #ifdef TORRENT_DHT_VERBOSE_LOGGING @@ -305,8 +305,8 @@ void obfuscated_get_peers_observer::reply(msg const& m) return; } - lazy_entry const* id = r->dict_find_string("id"); - if (!id || id->string_length() != 20) + bdecode_node id = r.dict_find_string("id"); + if (!id || id.string_length() != 20) { #ifdef TORRENT_DHT_VERBOSE_LOGGING TORRENT_LOG(traversal) << "[" << m_algorithm.get() diff --git a/src/kademlia/item.cpp b/src/kademlia/item.cpp index d58600887..c401ce12d 100644 --- a/src/kademlia/item.cpp +++ b/src/kademlia/item.cpp @@ -36,7 +36,7 @@ POSSIBILITY OF SUCH DAMAGE. #include #ifdef TORRENT_DEBUG -#include "libtorrent/lazy_entry.hpp" +#include "libtorrent/bdecode.hpp" #endif #ifdef TORRENT_USE_VALGRIND @@ -54,9 +54,9 @@ namespace { // v must be valid bencoding! #ifdef TORRENT_DEBUG - lazy_entry e; + bdecode_node e; error_code ec; - TORRENT_ASSERT(lazy_bdecode(v.first, v.first + v.second, e, ec) == 0); + TORRENT_ASSERT(bdecode(v.first, v.first + v.second, e, ec) == 0); #endif char* ptr = out; @@ -185,14 +185,14 @@ void item::assign(entry const& v, std::pair salt m_mutable = false; } -bool item::assign(lazy_entry const* v +bool item::assign(bdecode_node const& v , std::pair salt , boost::uint64_t seq, char const* pk, char const* sig) { - TORRENT_ASSERT(v->data_section().second <= 1000); + TORRENT_ASSERT(v.data_section().second <= 1000); if (pk && sig) { - if (!verify_mutable_item(v->data_section(), salt, seq, pk, sig)) + if (!verify_mutable_item(v.data_section(), salt, seq, pk, sig)) return false; memcpy(m_pk.c_array(), pk, item_pk_len); memcpy(m_sig.c_array(), sig, item_sig_len); @@ -206,7 +206,7 @@ bool item::assign(lazy_entry const* v else m_mutable = false; - m_value = *v; + m_value = v; return true; } diff --git a/src/kademlia/node.cpp b/src/kademlia/node.cpp index e55d7ba46..1cca97e28 100644 --- a/src/kademlia/node.cpp +++ b/src/kademlia/node.cpp @@ -221,44 +221,44 @@ void node_impl::unreachable(udp::endpoint const& ep) void node_impl::incoming(msg const& m) { // is this a reply? - lazy_entry const* y_ent = m.message.dict_find_string("y"); - if (!y_ent || y_ent->string_length() == 0) + bdecode_node y_ent = m.message.dict_find_string("y"); + if (!y_ent || y_ent.string_length() == 0) { // don't respond to this obviously broken messages. We don't // want to open up a magnification opportunity // entry e; // incoming_error(e, "missing 'y' entry"); -// m_sock->send_packet(e, m.addr, 0); +// m_sock.send_packet(e, m.addr, 0); return; } - char y = *(y_ent->string_ptr()); + char y = *(y_ent.string_ptr()); - lazy_entry const* ext_ip = m.message.dict_find_string("ip"); + bdecode_node ext_ip = m.message.dict_find_string("ip"); // backwards compatibility - if (ext_ip == NULL) + if (!ext_ip) { - lazy_entry const* r = m.message.dict_find_dict("r"); + bdecode_node r = m.message.dict_find_dict("r"); if (r) - ext_ip = r->dict_find_string("ip"); + ext_ip = r.dict_find_string("ip"); } #if TORRENT_USE_IPV6 - if (ext_ip && ext_ip->string_length() >= 16) + if (ext_ip && ext_ip.string_length() >= 16) { // this node claims we use the wrong node-ID! address_v6::bytes_type b; - memcpy(&b[0], ext_ip->string_ptr(), 16); + memcpy(&b[0], ext_ip.string_ptr(), 16); if (m_observer) m_observer->set_external_address(address_v6(b) , m.addr.address()); } else #endif - if (ext_ip && ext_ip->string_length() >= 4) + if (ext_ip && ext_ip.string_length() >= 4) { address_v4::bytes_type b; - memcpy(&b[0], ext_ip->string_ptr(), 4); + memcpy(&b[0], ext_ip.string_ptr(), 4); if (m_observer) m_observer->set_external_address(address_v4(b) , m.addr.address()); @@ -283,10 +283,10 @@ void node_impl::incoming(msg const& m) case 'e': { #ifdef TORRENT_DHT_VERBOSE_LOGGING - lazy_entry const* err = m.message.dict_find_list("e"); - if (err && err->list_size() >= 2) + bdecode_node err = m.message.dict_find_list("e"); + if (err && err.list_size() >= 2) { - TORRENT_LOG(node) << "INCOMING ERROR: " << err->list_string_value_at(1); + TORRENT_LOG(node) << "INCOMING ERROR: " << err.list_string_value_at(1); } #endif node_id id; @@ -419,7 +419,7 @@ struct ping_observer : observer { flags |= flag_done; - lazy_entry const* r = m.message.dict_find_dict("r"); + bdecode_node r = m.message.dict_find_dict("r"); if (!r) { #ifdef TORRENT_DHT_VERBOSE_LOGGING @@ -430,11 +430,11 @@ struct ping_observer : observer } // look for nodes - lazy_entry const* n = r->dict_find_string("nodes"); + bdecode_node n = r.dict_find_string("nodes"); if (n) { - char const* nodes = n->string_ptr(); - char const* end = nodes + n->string_length(); + char const* nodes = n.string_ptr(); + char const* end = nodes + n.string_length(); while (end - nodes >= 26) { @@ -674,18 +674,23 @@ using detail::write_nodes_entry; // verifies that a message has all the required // entries and returns them in ret -bool verify_message(lazy_entry const* msg, key_desc_t const desc[], lazy_entry const* ret[] - , int size , char* error, int error_size) +bool verify_message(bdecode_node const& message, key_desc_t const desc[] + , bdecode_node ret[], int size , char* error, int error_size) { + // get a non-root bdecode_node that still + // points to the root. message should not be copied + bdecode_node msg = message.non_owning(); + // clear the return buffer - memset(ret, 0, sizeof(ret[0]) * size); + for (int i = 0; i < size; ++i) + ret[i].clear(); // when parsing child nodes, this is the stack - // of lazy_entry pointers to return to - lazy_entry const* stack[5]; + // of bdecode_nodes to return to + bdecode_node stack[5]; int stack_ptr = -1; - if (msg->type() != lazy_entry::dict_t) + if (msg.type() != bdecode_node::dict_t) { snprintf(error, error_size, "not a dictionary"); return false; @@ -698,9 +703,10 @@ bool verify_message(lazy_entry const* msg, key_desc_t const desc[], lazy_entry c // fprintf(stderr, "looking for %s in %s\n", k.name, print_entry(*msg).c_str()); - ret[i] = msg->dict_find(k.name); + ret[i] = msg.dict_find(k.name); // none_t means any type - if (ret[i] && ret[i]->type() != k.type && k.type != lazy_entry::none_t) ret[i] = 0; + if (ret[i] && ret[i].type() != k.type && k.type != bdecode_node::none_t) + ret[i].clear(); if (ret[i] == 0 && (k.flags & key_desc_t::optional) == 0) { // the key was not found, and it's not an optional key @@ -710,18 +716,18 @@ bool verify_message(lazy_entry const* msg, key_desc_t const desc[], lazy_entry c if (k.size > 0 && ret[i] - && k.type == lazy_entry::string_t) + && k.type == bdecode_node::string_t) { bool invalid = false; if (k.flags & key_desc_t::size_divisible) - invalid = (ret[i]->string_length() % k.size) != 0; + invalid = (ret[i].string_length() % k.size) != 0; else - invalid = ret[i]->string_length() != k.size; + invalid = ret[i].string_length() != k.size; if (invalid) { // the string was not of the required size - ret[i] = 0; + ret[i].clear(); if ((k.flags & key_desc_t::optional) == 0) { snprintf(error, error_size, "invalid value for '%s'", k.name); @@ -731,7 +737,7 @@ bool verify_message(lazy_entry const* msg, key_desc_t const desc[], lazy_entry c } if (k.flags & key_desc_t::parse_children) { - TORRENT_ASSERT(k.type == lazy_entry::dict_t); + TORRENT_ASSERT(k.type == bdecode_node::dict_t); if (ret[i]) { @@ -805,15 +811,16 @@ void node_impl::incoming_request(msg const& m, entry& e) e["t"] = m.message.dict_find_string_value("t"); key_desc_t top_desc[] = { - {"q", lazy_entry::string_t, 0, 0}, - {"ro", lazy_entry::int_t, 0, key_desc_t::optional}, - {"a", lazy_entry::dict_t, 0, key_desc_t::parse_children}, - {"id", lazy_entry::string_t, 20, key_desc_t::last_child}, + {"q", bdecode_node::string_t, 0, 0}, + {"ro", bdecode_node::int_t, 0, key_desc_t::optional}, + {"a", bdecode_node::dict_t, 0, key_desc_t::parse_children}, + {"id", bdecode_node::string_t, 20, key_desc_t::last_child}, }; - lazy_entry const* top_level[4]; + bdecode_node top_level[4]; char error_string[200]; - if (!verify_message(&m.message, top_desc, top_level, 4, error_string, sizeof(error_string))) + if (!verify_message(m.message, top_desc, top_level, 4, error_string + , sizeof(error_string))) { incoming_error(e, error_string); return; @@ -821,11 +828,12 @@ void node_impl::incoming_request(msg const& m, entry& e) e["ip"] = endpoint_to_bytes(m.addr); - char const* query = top_level[0]->string_cstr(); + char const* query = top_level[0].string_ptr(); + int query_len = top_level[0].string_length(); - lazy_entry const* arg_ent = top_level[2]; - bool read_only = top_level[1] && top_level[1]->int_value() != 0; - node_id id(top_level[3]->string_ptr()); + bdecode_node arg_ent = top_level[2]; + bool read_only = top_level[1] && top_level[1].int_value() != 0; + node_id id(top_level[3].string_ptr()); // if this nodes ID doesn't match its IP, tell it what // its IP is with an error @@ -845,21 +853,21 @@ void node_impl::incoming_request(msg const& m, entry& e) // mirror back the other node's external port reply["p"] = m.addr.port(); - if (strcmp(query, "ping") == 0) + if (query_len == 4 && memcmp(query, "ping", 4) == 0) { m_counters.inc_stats_counter(counters::dht_ping_in); // we already have 't' and 'id' in the response // no more left to add } - else if (strcmp(query, "get_peers") == 0) + else if (query_len == 9 && memcmp(query, "get_peers", 9) == 0) { key_desc_t msg_desc[] = { - {"info_hash", lazy_entry::string_t, 20, 0}, - {"noseed", lazy_entry::int_t, 0, key_desc_t::optional}, - {"scrape", lazy_entry::int_t, 0, key_desc_t::optional}, + {"info_hash", bdecode_node::string_t, 20, 0}, + {"noseed", bdecode_node::int_t, 0, key_desc_t::optional}, + {"scrape", bdecode_node::int_t, 0, key_desc_t::optional}, }; - lazy_entry const* msg_keys[3]; + bdecode_node msg_keys[3]; if (!verify_message(arg_ent, msg_desc, msg_keys, 3, error_string , sizeof(error_string))) { @@ -868,11 +876,11 @@ void node_impl::incoming_request(msg const& m, entry& e) return; } - reply["token"] = generate_token(m.addr, msg_keys[0]->string_ptr()); + reply["token"] = generate_token(m.addr, msg_keys[0].string_ptr()); m_counters.inc_stats_counter(counters::dht_get_peers_in); - sha1_hash info_hash(msg_keys[0]->string_ptr()); + sha1_hash info_hash(msg_keys[0].string_ptr()); nodes_t n; // always return nodes as well as peers m_table.find_node(info_hash, n, 0); @@ -880,8 +888,8 @@ void node_impl::incoming_request(msg const& m, entry& e) bool noseed = false; bool scrape = false; - if (msg_keys[1] && msg_keys[1]->int_value() != 0) noseed = true; - if (msg_keys[2] && msg_keys[2]->int_value() != 0) scrape = true; + if (msg_keys[1] && msg_keys[1].int_value() != 0) noseed = true; + if (msg_keys[2] && msg_keys[2].int_value() != 0) scrape = true; lookup_peers(info_hash, reply, noseed, scrape); #ifdef TORRENT_DHT_VERBOSE_LOGGING if (reply.find_key("values")) @@ -890,13 +898,13 @@ void node_impl::incoming_request(msg const& m, entry& e) } #endif } - else if (strcmp(query, "find_node") == 0) + else if (query_len == 9 && memcmp(query, "find_node", 9) == 0) { key_desc_t msg_desc[] = { - {"target", lazy_entry::string_t, 20, 0}, + {"target", bdecode_node::string_t, 20, 0}, }; - lazy_entry const* msg_keys[1]; + bdecode_node msg_keys[1]; if (!verify_message(arg_ent, msg_desc, msg_keys, 1, error_string, sizeof(error_string))) { incoming_error(e, error_string); @@ -904,25 +912,25 @@ void node_impl::incoming_request(msg const& m, entry& e) } m_counters.inc_stats_counter(counters::dht_find_node_in); - sha1_hash target(msg_keys[0]->string_ptr()); + sha1_hash target(msg_keys[0].string_ptr()); // TODO: 2 find_node should write directly to the response entry nodes_t n; m_table.find_node(target, n, 0); write_nodes_entry(reply, n); } - else if (strcmp(query, "announce_peer") == 0) + else if (query_len == 13 && memcmp(query, "announce_peer", 13) == 0) { key_desc_t msg_desc[] = { - {"info_hash", lazy_entry::string_t, 20, 0}, - {"port", lazy_entry::int_t, 0, 0}, - {"token", lazy_entry::string_t, 0, 0}, - {"n", lazy_entry::string_t, 0, key_desc_t::optional}, - {"seed", lazy_entry::int_t, 0, key_desc_t::optional}, - {"implied_port", lazy_entry::int_t, 0, key_desc_t::optional}, + {"info_hash", bdecode_node::string_t, 20, 0}, + {"port", bdecode_node::int_t, 0, 0}, + {"token", bdecode_node::string_t, 0, 0}, + {"n", bdecode_node::string_t, 0, key_desc_t::optional}, + {"seed", bdecode_node::int_t, 0, key_desc_t::optional}, + {"implied_port", bdecode_node::int_t, 0, key_desc_t::optional}, }; - lazy_entry const* msg_keys[6]; + bdecode_node msg_keys[6]; if (!verify_message(arg_ent, msg_desc, msg_keys, 6, error_string, sizeof(error_string))) { m_counters.inc_stats_counter(counters::dht_invalid_announce); @@ -930,11 +938,11 @@ void node_impl::incoming_request(msg const& m, entry& e) return; } - int port = int(msg_keys[1]->int_value()); + int port = int(msg_keys[1].int_value()); // is the announcer asking to ignore the explicit // listen port and instead use the source port of the packet? - if (msg_keys[5] && msg_keys[5]->int_value() != 0) + if (msg_keys[5] && msg_keys[5].int_value() != 0) port = m.addr.port(); if (port < 0 || port >= 65536) @@ -944,7 +952,7 @@ void node_impl::incoming_request(msg const& m, entry& e) return; } - sha1_hash info_hash(msg_keys[0]->string_ptr()); + sha1_hash info_hash(msg_keys[0].string_ptr()); if (m_post_alert) { @@ -952,7 +960,7 @@ void node_impl::incoming_request(msg const& m, entry& e) if (!m_post_alert->post_alert(a)) delete a; } - if (!verify_token(msg_keys[2]->string_value(), msg_keys[0]->string_ptr(), m.addr)) + if (!verify_token(msg_keys[2].string_value(), msg_keys[0].string_ptr(), m.addr)) { m_counters.inc_stats_counter(counters::dht_invalid_announce); incoming_error(e, "invalid token"); @@ -1001,7 +1009,7 @@ void node_impl::incoming_request(msg const& m, entry& e) // for this torrent. Store it. if (msg_keys[3] && v->name.empty()) { - std::string name = msg_keys[3]->string_value(); + std::string name = msg_keys[3].string_value(); if (name.size() > 50) name.resize(50); v->name = name; } @@ -1009,28 +1017,28 @@ void node_impl::incoming_request(msg const& m, entry& e) peer_entry peer; peer.addr = tcp::endpoint(m.addr.address(), port); peer.added = aux::time_now(); - peer.seed = msg_keys[4] && msg_keys[4]->int_value(); + peer.seed = msg_keys[4] && msg_keys[4].int_value(); std::set::iterator i = v->peers.find(peer); if (i != v->peers.end()) v->peers.erase(i++); v->peers.insert(i, peer); } - else if (strcmp(query, "put") == 0) + else if (query_len == 3 && memcmp(query, "put", 3) == 0) { // the first 2 entries are for both mutable and // immutable puts const static key_desc_t msg_desc[] = { - {"token", lazy_entry::string_t, 0, 0}, - {"v", lazy_entry::none_t, 0, 0}, - {"seq", lazy_entry::int_t, 0, key_desc_t::optional}, + {"token", bdecode_node::string_t, 0, 0}, + {"v", bdecode_node::none_t, 0, 0}, + {"seq", bdecode_node::int_t, 0, key_desc_t::optional}, // public key - {"k", lazy_entry::string_t, item_pk_len, key_desc_t::optional}, - {"sig", lazy_entry::string_t, item_sig_len, key_desc_t::optional}, - {"cas", lazy_entry::int_t, 0, key_desc_t::optional}, - {"salt", lazy_entry::string_t, 0, key_desc_t::optional}, + {"k", bdecode_node::string_t, item_pk_len, key_desc_t::optional}, + {"sig", bdecode_node::string_t, item_sig_len, key_desc_t::optional}, + {"cas", bdecode_node::int_t, 0, key_desc_t::optional}, + {"salt", bdecode_node::string_t, 0, key_desc_t::optional}, }; // attempt to parse the message - lazy_entry const* msg_keys[7]; + bdecode_node msg_keys[7]; if (!verify_message(arg_ent, msg_desc, msg_keys, 7, error_string, sizeof(error_string))) { m_counters.inc_stats_counter(counters::dht_invalid_put); @@ -1045,14 +1053,14 @@ void node_impl::incoming_request(msg const& m, entry& e) // public key (only set if it's a mutable put) char const* pk = NULL; - if (msg_keys[3]) pk = msg_keys[3]->string_ptr(); + if (msg_keys[3]) pk = msg_keys[3].string_ptr(); // signature (only set if it's a mutable put) char const* sig = NULL; - if (msg_keys[4]) sig = msg_keys[4]->string_ptr(); + if (msg_keys[4]) sig = msg_keys[4].string_ptr(); // pointer and length to the whole entry - std::pair buf = msg_keys[1]->data_section(); + std::pair buf = msg_keys[1].data_section(); if (buf.second > 1000 || buf.second <= 0) { m_counters.inc_stats_counter(counters::dht_invalid_put); @@ -1063,7 +1071,7 @@ void node_impl::incoming_request(msg const& m, entry& e) std::pair salt(static_cast(NULL), 0); if (msg_keys[6]) salt = std::pair( - msg_keys[6]->string_ptr(), msg_keys[6]->string_length()); + msg_keys[6].string_ptr(), msg_keys[6].string_length()); if (salt.second > 64) { m_counters.inc_stats_counter(counters::dht_invalid_put); @@ -1085,7 +1093,7 @@ void node_impl::incoming_request(msg const& m, entry& e) // verify the write-token. tokens are only valid to write to // specific target hashes. it must match the one we got a "get" for - if (!verify_token(msg_keys[0]->string_value(), (char const*)&target[0], m.addr)) + if (!verify_token(msg_keys[0].string_value(), (char const*)&target[0], m.addr)) { m_counters.inc_stats_counter(counters::dht_invalid_put); incoming_error(e, "invalid token"); @@ -1133,12 +1141,12 @@ void node_impl::incoming_request(msg const& m, entry& e) // mutable put, we must verify the signature #ifdef TORRENT_USE_VALGRIND - VALGRIND_CHECK_MEM_IS_DEFINED(msg_keys[4]->string_ptr(), item_sig_len); + VALGRIND_CHECK_MEM_IS_DEFINED(msg_keys[4].string_ptr(), item_sig_len); VALGRIND_CHECK_MEM_IS_DEFINED(pk, item_pk_len); #endif // msg_keys[4] is the signature, msg_keys[3] is the public key if (!verify_mutable_item(buf, salt - , msg_keys[2]->int_value(), pk, sig)) + , msg_keys[2].int_value(), pk, sig)) { m_counters.inc_stats_counter(counters::dht_invalid_put); incoming_error(e, "invalid signature", 206); @@ -1167,7 +1175,7 @@ void node_impl::incoming_request(msg const& m, entry& e) dht_mutable_item to_add; to_add.value = (char*)malloc(buf.second); to_add.size = buf.second; - to_add.seq = msg_keys[2]->int_value(); + to_add.seq = msg_keys[2].int_value(); to_add.salt = NULL; to_add.salt_size = 0; if (salt.second > 0) @@ -1177,7 +1185,7 @@ void node_impl::incoming_request(msg const& m, entry& e) memcpy(to_add.salt, salt.first, salt.second); } memcpy(to_add.sig, sig, sizeof(to_add.sig)); - TORRENT_ASSERT(sizeof(to_add.sig) == msg_keys[4]->string_length()); + TORRENT_ASSERT(sizeof(to_add.sig) == msg_keys[4].string_length()); memcpy(to_add.value, buf.first, buf.second); memcpy(&to_add.key, pk, sizeof(to_add.key)); @@ -1197,21 +1205,21 @@ void node_impl::incoming_request(msg const& m, entry& e) // number matches the expected value before replacing it // this is critical for avoiding race conditions when multiple // writers are accessing the same slot - if (msg_keys[5] && item->seq != msg_keys[5]->int_value()) + if (msg_keys[5] && item->seq != msg_keys[5].int_value()) { m_counters.inc_stats_counter(counters::dht_invalid_put); incoming_error(e, "CAS mismatch", 301); return; } - if (item->seq > boost::uint64_t(msg_keys[2]->int_value())) + if (item->seq > boost::uint64_t(msg_keys[2].int_value())) { m_counters.inc_stats_counter(counters::dht_invalid_put); incoming_error(e, "old sequence number", 302); return; } - if (item->seq < boost::uint64_t(msg_keys[2]->int_value())) + if (item->seq < boost::uint64_t(msg_keys[2].int_value())) { if (item->size != buf.second) { @@ -1219,9 +1227,9 @@ void node_impl::incoming_request(msg const& m, entry& e) item->value = (char*)malloc(buf.second); item->size = buf.second; } - item->seq = msg_keys[2]->int_value(); - memcpy(item->sig, msg_keys[4]->string_ptr(), sizeof(item->sig)); - TORRENT_ASSERT(sizeof(item->sig) == msg_keys[4]->string_length()); + item->seq = msg_keys[2].int_value(); + memcpy(item->sig, msg_keys[4].string_ptr(), sizeof(item->sig)); + TORRENT_ASSERT(sizeof(item->sig) == msg_keys[4].string_length()); memcpy(item->value, buf.first, buf.second); } } @@ -1242,17 +1250,17 @@ void node_impl::incoming_request(msg const& m, entry& e) ++f->num_announcers; } } - else if (strcmp(query, "get") == 0) + else if (query_len == 3 && memcmp(query, "get", 3) == 0) { key_desc_t msg_desc[] = { - {"seq", lazy_entry::int_t, 0, key_desc_t::optional}, - {"target", lazy_entry::string_t, 20, 0}, + {"seq", bdecode_node::int_t, 0, key_desc_t::optional}, + {"target", bdecode_node::string_t, 20, 0}, }; // k is not used for now // attempt to parse the message - lazy_entry const* msg_keys[2]; + bdecode_node msg_keys[2]; if (!verify_message(arg_ent, msg_desc, msg_keys, 2, error_string , sizeof(error_string))) { @@ -1262,13 +1270,13 @@ void node_impl::incoming_request(msg const& m, entry& e) } m_counters.inc_stats_counter(counters::dht_get_in); - sha1_hash target(msg_keys[1]->string_ptr()); + sha1_hash target(msg_keys[1].string_ptr()); // fprintf(stderr, "%s GET target: %s\n" // , msg_keys[1] ? "mutable":"immutable" // , to_hex(target.to_string()).c_str()); - reply["token"] = generate_token(m.addr, msg_keys[1]->string_ptr()); + reply["token"] = generate_token(m.addr, msg_keys[1].string_ptr()); nodes_t n; // always return nodes as well as peers @@ -1294,7 +1302,7 @@ void node_impl::incoming_request(msg const& m, entry& e) { dht_mutable_item const& f = i->second; reply["seq"] = f.seq; - if (!msg_keys[0] || boost::uint64_t(msg_keys[0]->int_value()) < f.seq) + if (!msg_keys[0] || boost::uint64_t(msg_keys[0].int_value()) < f.seq) { reply["v"] = bdecode(f.value, f.value + f.size); reply["sig"] = std::string(f.sig, f.sig + sizeof(f.sig)); @@ -1308,18 +1316,18 @@ void node_impl::incoming_request(msg const& m, entry& e) // if we don't recognize the message but there's a // 'target' or 'info_hash' in the arguments, treat it // as find_node to be future compatible - lazy_entry const* target_ent = arg_ent->dict_find_string("target"); - if (target_ent == 0 || target_ent->string_length() != 20) + bdecode_node target_ent = arg_ent.dict_find_string("target"); + if (!target_ent || target_ent.string_length() != 20) { - target_ent = arg_ent->dict_find_string("info_hash"); - if (target_ent == 0 || target_ent->string_length() != 20) + target_ent = arg_ent.dict_find_string("info_hash"); + if (!target_ent || target_ent.string_length() != 20) { incoming_error(e, "unknown message"); return; } } - sha1_hash target(target_ent->string_ptr()); + sha1_hash target(target_ent.string_ptr()); nodes_t n; // always return nodes as well as peers m_table.find_node(target, n, 0); diff --git a/src/kademlia/rpc_manager.cpp b/src/kademlia/rpc_manager.cpp index e6ece84b9..00120c2bf 100644 --- a/src/kademlia/rpc_manager.cpp +++ b/src/kademlia/rpc_manager.cpp @@ -324,13 +324,13 @@ bool rpc_manager::incoming(msg const& m, node_id* id, libtorrent::dht_settings c << std::endl; #endif - lazy_entry const* ret_ent = m.message.dict_find_dict("r"); - if (ret_ent == 0) + bdecode_node ret_ent = m.message.dict_find_dict("r"); + if (!ret_ent) { // it may be an error ret_ent = m.message.dict_find("e"); o->timeout(); - if (ret_ent == NULL) + if (!ret_ent) { entry e; incoming_error(e, "missing 'r' key"); @@ -339,8 +339,8 @@ bool rpc_manager::incoming(msg const& m, node_id* id, libtorrent::dht_settings c return false; } - lazy_entry const* node_id_ent = ret_ent->dict_find_string("id"); - if (node_id_ent == 0 || node_id_ent->string_length() != 20) + bdecode_node node_id_ent = ret_ent.dict_find_string("id"); + if (!node_id_ent || node_id_ent.string_length() != 20) { o->timeout(); entry e; @@ -349,7 +349,7 @@ bool rpc_manager::incoming(msg const& m, node_id* id, libtorrent::dht_settings c return false; } - node_id nid = node_id(node_id_ent->string_ptr()); + node_id nid = node_id(node_id_ent.string_ptr()); if (settings.enforce_node_id && !verify_id(nid, m.addr.address())) { o->timeout(); diff --git a/src/kademlia/traversal_algorithm.cpp b/src/kademlia/traversal_algorithm.cpp index 0168ee860..eb977e44c 100644 --- a/src/kademlia/traversal_algorithm.cpp +++ b/src/kademlia/traversal_algorithm.cpp @@ -521,7 +521,7 @@ void traversal_algorithm::status(dht_lookup& l) void traversal_observer::reply(msg const& m) { - lazy_entry const* r = m.message.dict_find_dict("r"); + bdecode_node r = m.message.dict_find_dict("r"); if (!r) { #ifdef TORRENT_DHT_VERBOSE_LOGGING @@ -532,20 +532,20 @@ void traversal_observer::reply(msg const& m) } #ifdef TORRENT_DHT_VERBOSE_LOGGING - lazy_entry const* nid = r->dict_find_string("id"); + bdecode_node nid = r.dict_find_string("id"); TORRENT_LOG(traversal) << "[" << m_algorithm.get() << "] " - "RESPONSE id: " << to_hex(nid->string_value()) - << " invoke-count: " << m_algorithm->invoke_count() + "RESPONSE id: " << to_hex(nid.string_value()) + << " invoke-count: " << m_algorithm.invoke_count() << " addr: " << m.addr - << " type: " << m_algorithm->name() + << " type: " << m_algorithm.name() ; #endif // look for nodes - lazy_entry const* n = r->dict_find_string("nodes"); + bdecode_node n = r.dict_find_string("nodes"); if (n) { - char const* nodes = n->string_ptr(); - char const* end = nodes + n->string_length(); + char const* nodes = n.string_ptr(); + char const* end = nodes + n.string_length(); while (end - nodes >= 26) { @@ -556,8 +556,8 @@ void traversal_observer::reply(msg const& m) } } - lazy_entry const* id = r->dict_find_string("id"); - if (!id || id->string_length() != 20) + bdecode_node id = r.dict_find_string("id"); + if (!id || id.string_length() != 20) { #ifdef TORRENT_DHT_VERBOSE_LOGGING TORRENT_LOG(traversal) << "[" << m_algorithm.get() << "] invalid id in response"; @@ -567,7 +567,7 @@ void traversal_observer::reply(msg const& m) // in case we didn't know the id of this peer when we sent the message to // it. For instance if it's a bootstrap node. - set_id(node_id(id->string_ptr())); + set_id(node_id(id.string_ptr())); } void traversal_algorithm::abort() diff --git a/src/lazy_bdecode.cpp b/src/lazy_bdecode.cpp index 27e9f7137..9961966bf 100644 --- a/src/lazy_bdecode.cpp +++ b/src/lazy_bdecode.cpp @@ -30,8 +30,11 @@ POSSIBILITY OF SUCH DAMAGE. */ +#ifndef TORRENT_NO_DEPRECATE + #include "libtorrent/config.hpp" #include "libtorrent/lazy_entry.hpp" +#include "libtorrent/bdecode.hpp" // for error codes #include #include // for numeric_limits @@ -70,40 +73,6 @@ namespace libtorrent namespace { bool numeric(char c) { return c >= '0' && c <= '9'; } } - // fills in 'val' with what the string between start and the - // first occurance of the delimiter is interpreted as an int. - // return the pointer to the delimiter, or 0 if there is a - // parse error. val should be initialized to zero - char const* parse_int(char const* start, char const* end, char delimiter - , boost::int64_t& val, bdecode_errors::error_code_enum& ec) - { - while (start < end && *start != delimiter) - { - if (!numeric(*start)) - { - ec = bdecode_errors::expected_string; - return start; - } - if (val > (std::numeric_limits::max)() / 10) - { - ec = bdecode_errors::overflow; - return start; - } - val *= 10; - int digit = *start - '0'; - if (val > (std::numeric_limits::max)() - digit) - { - ec = bdecode_errors::overflow; - return start; - } - val += digit; - ++start; - } - if (*start != delimiter) - ec = bdecode_errors::expected_colon; - return start; - } - char const* find_char(char const* start, char const* end, char delimiter) { while (start < end && *start != delimiter) ++start; @@ -153,7 +122,7 @@ namespace libtorrent stack.pop_back(); continue; } - if (!numeric(t)) TORRENT_FAIL_BDECODE(bdecode_errors::expected_string); + if (!numeric(t)) TORRENT_FAIL_BDECODE(bdecode_errors::expected_digit); boost::int64_t len = t - '0'; bdecode_errors::error_code_enum e = bdecode_errors::no_error; start = parse_int(start, end, ':', len, e); @@ -382,7 +351,8 @@ namespace libtorrent return e; } - boost::int64_t lazy_entry::dict_find_int_value(char const* name, boost::int64_t default_val) const + boost::int64_t lazy_entry::dict_find_int_value(char const* name + , boost::int64_t default_val) const { lazy_entry const* e = dict_find(name); if (e == 0 || e->type() != lazy_entry::int_t) return default_val; @@ -672,50 +642,7 @@ namespace libtorrent } return ret; } - - struct bdecode_error_category : boost::system::error_category - { - virtual const char* name() const BOOST_SYSTEM_NOEXCEPT; - virtual std::string message(int ev) const BOOST_SYSTEM_NOEXCEPT; - virtual boost::system::error_condition default_error_condition(int ev) const BOOST_SYSTEM_NOEXCEPT - { return boost::system::error_condition(ev, *this); } - }; - - const char* bdecode_error_category::name() const BOOST_SYSTEM_NOEXCEPT - { - return "bdecode error"; - } - - std::string bdecode_error_category::message(int ev) const BOOST_SYSTEM_NOEXCEPT - { - static char const* msgs[] = - { - "no error", - "expected string in bencoded string", - "expected colon in bencoded string", - "unexpected end of file in bencoded string", - "expected value (list, dict, int or string) in bencoded string", - "bencoded nesting depth exceeded", - "bencoded item count limit exceeded", - "integer overflow", - }; - if (ev < 0 || ev >= int(sizeof(msgs)/sizeof(msgs[0]))) - return "Unknown error"; - return msgs[ev]; - } - - boost::system::error_category& get_bdecode_category() - { - static bdecode_error_category bdecode_category; - return bdecode_category; - } - - namespace bdecode_errors - { - boost::system::error_code make_error_code(error_code_enum e) - { - return boost::system::error_code(e, get_bdecode_category()); - } - } }; +#endif // TORRENT_NO_DEPRECATE + diff --git a/src/lt_trackers.cpp b/src/lt_trackers.cpp index 654e7002d..8ede025c2 100644 --- a/src/lt_trackers.cpp +++ b/src/lt_trackers.cpp @@ -167,14 +167,14 @@ namespace libtorrent { namespace } // called when the extension handshake from the other end is received - virtual bool on_extension_handshake(lazy_entry const& h) + virtual bool on_extension_handshake(bdecode_node const& h) { m_message_index = 0; - if (h.type() != lazy_entry::dict_t) return false; - lazy_entry const* messages = h.dict_find("m"); - if (!messages || messages->type() != lazy_entry::dict_t) return false; + if (h.type() != bdecode_node::dict_t) return false; + bdecode_node messages = h.dict_find("m"); + if (!messages || messages.type() != bdecode_node::dict_t) return false; - int index = int(messages->dict_find_int_value("lt_tex", -1)); + int index = int(messages.dict_find_int_value("lt_tex", -1)); if (index == -1) return false; m_message_index = index; @@ -196,16 +196,16 @@ namespace libtorrent { namespace if (m_message_index == 0) return false; if (!m_pc.packet_finished()) return true; - lazy_entry msg; + bdecode_node msg; error_code ec; - int ret = lazy_bdecode(body.begin, body.end, msg, ec); - if (ret != 0 || msg.type() != lazy_entry::dict_t) + int ret = bdecode(body.begin, body.end, msg, ec); + if (ret != 0 || msg.type() != bdecode_node::dict_t) { m_pc.disconnect(errors::invalid_lt_tracker_message, op_bittorrent, 2); return true; } - lazy_entry const* added = msg.dict_find_list("added"); + bdecode_node added = msg.dict_find_list("added"); // invalid tex message if (added == 0) @@ -231,9 +231,9 @@ namespace libtorrent { namespace "added: "; #endif - for (int i = 0; i < added->list_size(); ++i) + for (int i = 0; i < added.list_size(); ++i) { - announce_entry e(added->list_string_value_at(i)); + announce_entry e(added.list_string_value_at(i)); if (e.url.empty()) continue; // ignore urls with binary data in them diff --git a/src/metadata_transfer.cpp b/src/metadata_transfer.cpp index 4b1e86fc9..11f5d5fe9 100644 --- a/src/metadata_transfer.cpp +++ b/src/metadata_transfer.cpp @@ -277,14 +277,14 @@ namespace libtorrent { namespace } // called when the extension handshake from the other end is received - virtual bool on_extension_handshake(lazy_entry const& h) + virtual bool on_extension_handshake(bdecode_node const& h) { m_message_index = 0; - if (h.type() != lazy_entry::dict_t) return false; - lazy_entry const* messages = h.dict_find("m"); - if (!messages || messages->type() != lazy_entry::dict_t) return false; + if (h.type() != bdecode_node::dict_t) return false; + bdecode_node messages = h.dict_find("m"); + if (!messages || messages.type() != bdecode_node::dict_t) return false; - int index = int(messages->dict_find_int_value("LT_metadata", -1)); + int index = int(messages.dict_find_int_value("LT_metadata", -1)); if (index == -1) return false; m_message_index = index; return true; diff --git a/src/rss.cpp b/src/rss.cpp index 9be239873..e252251dd 100644 --- a/src/rss.cpp +++ b/src/rss.cpp @@ -398,31 +398,31 @@ void feed::on_feed(error_code const& ec m_ses.update_rss_feeds(); } -void feed::load_state(lazy_entry const& rd) +void feed::load_state(bdecode_node const& rd) { m_title = rd.dict_find_string_value("m_title"); m_description = rd.dict_find_string_value("m_description"); m_last_attempt = rd.dict_find_int_value("m_last_attempt"); m_last_update = rd.dict_find_int_value("m_last_update"); - lazy_entry const* e = rd.dict_find_list("items"); + bdecode_node e = rd.dict_find_list("items"); if (e) { - m_items.reserve(e->list_size()); - for (int i = 0; i < e->list_size(); ++i) + m_items.reserve(e.list_size()); + for (int i = 0; i < e.list_size(); ++i) { - lazy_entry const* entry = e->list_at(i); - if (entry->type() != lazy_entry::dict_t) continue; + bdecode_node entry = e.list_at(i); + if (entry.type() != bdecode_node::dict_t) continue; m_items.push_back(feed_item()); feed_item& item = m_items.back(); - item.url = entry->dict_find_string_value("url"); - item.uuid = entry->dict_find_string_value("uuid"); - item.title = entry->dict_find_string_value("title"); - item.description = entry->dict_find_string_value("description"); - item.comment = entry->dict_find_string_value("comment"); - item.category = entry->dict_find_string_value("category"); - item.size = entry->dict_find_int_value("size"); + item.url = entry.dict_find_string_value("url"); + item.uuid = entry.dict_find_string_value("uuid"); + item.title = entry.dict_find_string_value("title"); + item.description = entry.dict_find_string_value("description"); + item.comment = entry.dict_find_string_value("comment"); + item.category = entry.dict_find_string_value("category"); + item.size = entry.dict_find_int_value("size"); // don't load duplicates if (m_urls.find(item.url) != m_urls.end()) @@ -442,27 +442,27 @@ void feed::load_state(lazy_entry const& rd) e = rd.dict_find_dict("add_params"); if (e) { - m_settings.add_args.save_path = e->dict_find_string_value("save_path"); - m_settings.add_args.flags = e->dict_find_int_value("flags"); + m_settings.add_args.save_path = e.dict_find_string_value("save_path"); + m_settings.add_args.flags = e.dict_find_int_value("flags"); } e = rd.dict_find_list("history"); if (e) { - for (int i = 0; i < e->list_size(); ++i) + for (int i = 0; i < e.list_size(); ++i) { - if (e->list_at(i)->type() != lazy_entry::list_t) continue; + if (e.list_at(i).type() != bdecode_node::list_t) continue; - lazy_entry const* item = e->list_at(i); + bdecode_node item = e.list_at(i); - if (item->list_size() != 2 - || item->list_at(0)->type() != lazy_entry::string_t - || item->list_at(1)->type() != lazy_entry::int_t) + if (item.list_size() != 2 + || item.list_at(0).type() != bdecode_node::string_t + || item.list_at(1).type() != bdecode_node::int_t) continue; m_added.insert(std::pair( - item->list_at(0)->string_value() - , item->list_at(1)->int_value())); + item.list_at(0).string_value() + , item.list_at(1).int_value())); } } } diff --git a/src/session.cpp b/src/session.cpp index 42d470613..bb510eeeb 100644 --- a/src/session.cpp +++ b/src/session.cpp @@ -433,7 +433,7 @@ namespace libtorrent TORRENT_SYNC_CALL2(save_state, &e, flags); } - void session::load_state(lazy_entry const& e) + void session::load_state(bdecode_node const& e) { // this needs to be synchronized since the lifespan // of e is tied to the caller @@ -494,12 +494,30 @@ namespace libtorrent if (ses_state.type() == entry::undefined_t) return; std::vector buf; bencode(std::back_inserter(buf), ses_state); - lazy_entry e; + bdecode_node e; error_code ec; #if defined TORRENT_DEBUG || TORRENT_RELEASE_ASSERTS || !defined BOOST_NO_EXCEPTIONS int ret = #endif - lazy_bdecode(&buf[0], &buf[0] + buf.size(), e, ec); + bdecode(&buf[0], &buf[0] + buf.size(), e, ec); + + TORRENT_ASSERT(ret == 0); +#ifndef BOOST_NO_EXCEPTIONS + if (ret != 0) throw libtorrent_exception(ec); +#endif + TORRENT_SYNC_CALL1(load_state, &e); + } + + void session::load_state(lazy_entry const& ses_state) + { + if (ses_state.type() == lazy_entry::none_t) return; + std::pair buf = ses_state.data_section(); + bdecode_node e; + error_code ec; +#if defined TORRENT_DEBUG || TORRENT_RELEASE_ASSERTS || !defined BOOST_NO_EXCEPTIONS + int ret = +#endif + bdecode(buf.first, buf.first + buf.second, e, ec); TORRENT_ASSERT(ret == 0); #ifndef BOOST_NO_EXCEPTIONS diff --git a/src/session_impl.cpp b/src/session_impl.cpp index 1f1fb834c..9129ceafe 100644 --- a/src/session_impl.cpp +++ b/src/session_impl.cpp @@ -740,35 +740,35 @@ namespace aux { return proxy_settings(m_settings); } - void session_impl::load_state(lazy_entry const* e) + void session_impl::load_state(bdecode_node const* e) { TORRENT_ASSERT(is_single_thread()); - lazy_entry const* settings; - if (e->type() != lazy_entry::dict_t) return; + bdecode_node settings; + if (e->type() != bdecode_node::dict_t) return; #ifndef TORRENT_DISABLE_DHT // load from the old settings names settings = e->dict_find_dict("dht"); if (settings) { - lazy_entry const* val; - val = settings->dict_find_int("max_peers_reply"); - if (val) m_dht_settings.max_peers_reply = val->int_value(); - val = settings->dict_find_int("search_branching"); - if (val) m_dht_settings.search_branching = val->int_value(); - val = settings->dict_find_int("max_fail_count"); - if (val) m_dht_settings.max_fail_count = val->int_value(); - val = settings->dict_find_int("max_torrents"); - if (val) m_dht_settings.max_torrents = val->int_value(); - val = settings->dict_find_int("max_dht_items"); - if (val) m_dht_settings.max_dht_items = val->int_value(); - val = settings->dict_find_int("max_torrent_search_reply"); - if (val) m_dht_settings.max_torrent_search_reply = val->int_value(); - val = settings->dict_find_int("restrict_routing_ips"); - if (val) m_dht_settings.restrict_routing_ips = val->int_value(); - val = settings->dict_find_int("extended_routing_table"); - if (val) m_dht_settings.extended_routing_table = val->int_value(); + bdecode_node val; + val = settings.dict_find_int("max_peers_reply"); + if (val) m_dht_settings.max_peers_reply = val.int_value(); + val = settings.dict_find_int("search_branching"); + if (val) m_dht_settings.search_branching = val.int_value(); + val = settings.dict_find_int("max_fail_count"); + if (val) m_dht_settings.max_fail_count = val.int_value(); + val = settings.dict_find_int("max_torrents"); + if (val) m_dht_settings.max_torrents = val.int_value(); + val = settings.dict_find_int("max_dht_items"); + if (val) m_dht_settings.max_dht_items = val.int_value(); + val = settings.dict_find_int("max_torrent_search_reply"); + if (val) m_dht_settings.max_torrent_search_reply = val.int_value(); + val = settings.dict_find_int("restrict_routing_ips"); + if (val) m_dht_settings.restrict_routing_ips = val.int_value(); + val = settings.dict_find_int("extended_routing_table"); + if (val) m_dht_settings.extended_routing_table = val.int_value(); } #endif @@ -776,35 +776,35 @@ namespace aux { settings = e->dict_find_dict("proxy"); if (settings) { - lazy_entry const* val; - val = settings->dict_find_int("port"); - if (val) m_settings.set_int(settings_pack::proxy_port, val->int_value()); - val = settings->dict_find_int("type"); - if (val) m_settings.set_int(settings_pack::proxy_type, val->int_value()); - val = settings->dict_find_int("proxy_hostnames"); - if (val) m_settings.set_bool(settings_pack::proxy_hostnames, val->int_value()); - val = settings->dict_find_int("proxy_peer_connections"); - if (val) m_settings.set_bool(settings_pack::proxy_peer_connections, val->int_value()); - val = settings->dict_find_string("hostname"); - if (val) m_settings.set_str(settings_pack::proxy_hostname, val->string_value()); - val = settings->dict_find_string("password"); - if (val) m_settings.set_str(settings_pack::proxy_password, val->string_value()); - val = settings->dict_find_string("username"); - if (val) m_settings.set_str(settings_pack::proxy_username, val->string_value()); + bdecode_node val; + val = settings.dict_find_int("port"); + if (val) m_settings.set_int(settings_pack::proxy_port, val.int_value()); + val = settings.dict_find_int("type"); + if (val) m_settings.set_int(settings_pack::proxy_type, val.int_value()); + val = settings.dict_find_int("proxy_hostnames"); + if (val) m_settings.set_bool(settings_pack::proxy_hostnames, val.int_value()); + val = settings.dict_find_int("proxy_peer_connections"); + if (val) m_settings.set_bool(settings_pack::proxy_peer_connections, val.int_value()); + val = settings.dict_find_string("hostname"); + if (val) m_settings.set_str(settings_pack::proxy_hostname, val.string_value()); + val = settings.dict_find_string("password"); + if (val) m_settings.set_str(settings_pack::proxy_password, val.string_value()); + val = settings.dict_find_string("username"); + if (val) m_settings.set_str(settings_pack::proxy_username, val.string_value()); } settings = e->dict_find_dict("encryption"); if (settings) { - lazy_entry const* val; - val = settings->dict_find_int("prefer_rc4"); - if (val) m_settings.set_bool(settings_pack::prefer_rc4, val->int_value()); - val = settings->dict_find_int("out_enc_policy"); - if (val) m_settings.set_int(settings_pack::out_enc_policy, val->int_value()); - val = settings->dict_find_int("in_enc_policy"); - if (val) m_settings.set_int(settings_pack::in_enc_policy, val->int_value()); - val = settings->dict_find_int("allowed_enc_level"); - if (val) m_settings.set_int(settings_pack::allowed_enc_level, val->int_value()); + bdecode_node val; + val = settings.dict_find_int("prefer_rc4"); + if (val) m_settings.set_bool(settings_pack::prefer_rc4, val.int_value()); + val = settings.dict_find_int("out_enc_policy"); + if (val) m_settings.set_int(settings_pack::out_enc_policy, val.int_value()); + val = settings.dict_find_int("in_enc_policy"); + if (val) m_settings.set_int(settings_pack::in_enc_policy, val.int_value()); + val = settings.dict_find_int("allowed_enc_level"); + if (val) m_settings.set_int(settings_pack::allowed_enc_level, val.int_value()); } #endif @@ -824,19 +824,19 @@ namespace aux { settings = e->dict_find_dict("dht state"); if (settings) { - m_dht_state = *settings; + m_dht_state = settings; } #endif settings = e->dict_find_list("feeds"); if (settings) { - m_feeds.reserve(settings->list_size()); - for (int i = 0; i < settings->list_size(); ++i) + m_feeds.reserve(settings.list_size()); + for (int i = 0; i < settings.list_size(); ++i) { - if (settings->list_at(i)->type() != lazy_entry::dict_t) continue; + if (settings.list_at(i).type() != bdecode_node::dict_t) continue; boost::shared_ptr f(new_feed(*this, feed_settings())); - f->load_state(*settings->list_at(i)); + f->load_state(settings.list_at(i)); f->update_feed(); m_feeds.push_back(f); } @@ -4542,14 +4542,14 @@ retry: { int pos; error_code ec; - lazy_entry tmp; - lazy_entry const* info = 0; + bdecode_node tmp; + bdecode_node info; #if defined TORRENT_LOGGING session_log("adding magnet link with resume data"); #endif - if (lazy_bdecode(¶ms.resume_data[0], ¶ms.resume_data[0] + if (bdecode(¶ms.resume_data[0], ¶ms.resume_data[0] + params.resume_data.size(), tmp, ec, &pos) == 0 - && tmp.type() == lazy_entry::dict_t + && tmp.type() == bdecode_node::dict_t && (info = tmp.dict_find_dict("info"))) { #if defined TORRENT_LOGGING @@ -4558,7 +4558,7 @@ retry: // verify the info-hash of the metadata stored in the resume file matches // the torrent we're loading - std::pair buf = info->data_section(); + std::pair buf = info.data_section(); sha1_hash resume_ih = hasher(buf.first, buf.second).final(); // if url is set, the info_hash is not actually the info-hash of the @@ -4573,7 +4573,7 @@ retry: #endif params.ti = boost::make_shared(resume_ih); - if (params.ti->parse_info_section(*info, ec, 0)) + if (params.ti->parse_info_section(info, ec, 0)) { #if defined TORRENT_LOGGING session_log("successfully loaded metadata from resume file"); diff --git a/src/settings_pack.cpp b/src/settings_pack.cpp index 058ccb538..f32069384 100644 --- a/src/settings_pack.cpp +++ b/src/settings_pack.cpp @@ -386,27 +386,27 @@ namespace libtorrent return ""; } - settings_pack* load_pack_from_dict(lazy_entry const* settings) + settings_pack* load_pack_from_dict(bdecode_node const& settings) { settings_pack* pack = new settings_pack; - for (int i = 0; i < settings->dict_size(); ++i) + for (int i = 0; i < settings.dict_size(); ++i) { std::string key; - lazy_entry const* val; - boost::tie(key, val) = settings->dict_at(i); - switch (val->type()) + bdecode_node val; + boost::tie(key, val) = settings.dict_at(i); + switch (val.type()) { - case lazy_entry::dict_t: - case lazy_entry::list_t: + case bdecode_node::dict_t: + case bdecode_node::list_t: continue; - case lazy_entry::int_t: + case bdecode_node::int_t: { bool found = false; for (int k = 0; k < sizeof(int_settings)/sizeof(int_settings[0]); ++k) { if (key != int_settings[k].name) continue; - pack->set_int(settings_pack::int_type_base + k, val->int_value()); + pack->set_int(settings_pack::int_type_base + k, val.int_value()); found = true; break; } @@ -414,20 +414,20 @@ namespace libtorrent for (int k = 0; k < sizeof(bool_settings)/sizeof(bool_settings[0]); ++k) { if (key != bool_settings[k].name) continue; - pack->set_bool(settings_pack::bool_type_base + k, val->int_value()); + pack->set_bool(settings_pack::bool_type_base + k, val.int_value()); break; } } break; - case lazy_entry::string_t: + case bdecode_node::string_t: for (int k = 0; k < sizeof(str_settings)/sizeof(str_settings[0]); ++k) { if (key != str_settings[k].name) continue; - pack->set_str(settings_pack::string_type_base + k, val->string_value()); + pack->set_str(settings_pack::string_type_base + k, val.string_value()); break; } break; - case lazy_entry::none_t: + case bdecode_node::none_t: break; } } diff --git a/src/storage.cpp b/src/storage.cpp index cd8d9df4f..73a19851d 100644 --- a/src/storage.cpp +++ b/src/storage.cpp @@ -712,47 +712,47 @@ namespace libtorrent return int((data_start + files().piece_length() - 1) / files().piece_length()); } - bool default_storage::verify_resume_data(lazy_entry const& rd, storage_error& ec) + bool default_storage::verify_resume_data(bdecode_node const& rd, storage_error& ec) { // TODO: make this more generic to not just work if files have been // renamed, but also if they have been merged into a single file for instance // maybe use the same format as .torrent files and reuse some code from torrent_info - lazy_entry const* mapped_files = rd.dict_find_list("mapped_files"); - if (mapped_files && mapped_files->list_size() == m_files.num_files()) + bdecode_node mapped_files = rd.dict_find_list("mapped_files"); + if (mapped_files && mapped_files.list_size() == m_files.num_files()) { m_mapped_files.reset(new file_storage(m_files)); for (int i = 0; i < m_files.num_files(); ++i) { - std::string new_filename = mapped_files->list_string_value_at(i); + std::string new_filename = mapped_files.list_string_value_at(i); if (new_filename.empty()) continue; m_mapped_files->rename_file(i, new_filename); } } - lazy_entry const* file_priority = rd.dict_find_list("file_priority"); - if (file_priority && file_priority->list_size() + bdecode_node file_priority = rd.dict_find_list("file_priority"); + if (file_priority && file_priority.list_size() == files().num_files()) { - m_file_priority.resize(file_priority->list_size()); - for (int i = 0; i < file_priority->list_size(); ++i) - m_file_priority[i] = boost::uint8_t(file_priority->list_int_value_at(i, 1)); + m_file_priority.resize(file_priority.list_size()); + for (int i = 0; i < file_priority.list_size(); ++i) + m_file_priority[i] = boost::uint8_t(file_priority.list_int_value_at(i, 1)); } - lazy_entry const* file_sizes_ent = rd.dict_find_list("file sizes"); + bdecode_node file_sizes_ent = rd.dict_find_list("file sizes"); if (file_sizes_ent == 0) { ec.ec = errors::missing_file_sizes; return false; } - if (file_sizes_ent->list_size() == 0) + if (file_sizes_ent.list_size() == 0) { ec.ec = errors::no_files_in_resume_data; return false; } file_storage const& fs = files(); - if (file_sizes_ent->list_size() != fs.num_files()) + if (file_sizes_ent.list_size() != fs.num_files()) { ec.ec = errors::mismatching_number_of_files; ec.file = -1; @@ -761,27 +761,27 @@ namespace libtorrent } bool seed = false; - lazy_entry const* slots = rd.dict_find_list("slots"); + bdecode_node slots = rd.dict_find_list("slots"); if (slots) { - if (int(slots->list_size()) == m_files.num_pieces()) + if (int(slots.list_size()) == m_files.num_pieces()) { seed = true; - for (int i = 0; i < slots->list_size(); ++i) + for (int i = 0; i < slots.list_size(); ++i) { - if (slots->list_int_value_at(i, -1) >= 0) continue; + if (slots.list_int_value_at(i, -1) >= 0) continue; seed = false; break; } } } - else if (lazy_entry const* pieces = rd.dict_find_string("pieces")) + else if (bdecode_node pieces = rd.dict_find_string("pieces")) { - if (int(pieces->string_length()) == m_files.num_pieces()) + if (int(pieces.string_length()) == m_files.num_pieces()) { seed = true; - char const* p = pieces->string_ptr(); - for (int i = 0; i < pieces->string_length(); ++i) + char const* p = pieces.string_ptr(); + for (int i = 0; i < pieces.string_length(); ++i) { if ((p[i] & 1) == 1) continue; seed = false; @@ -795,14 +795,14 @@ namespace libtorrent return false; } - for (int i = 0; i < file_sizes_ent->list_size(); ++i) + for (int i = 0; i < file_sizes_ent.list_size(); ++i) { if (fs.pad_file_at(i)) continue; - lazy_entry const* e = file_sizes_ent->list_at(i); - if (e->type() != lazy_entry::list_t - || e->list_size() < 2 - || e->list_at(0)->type() != lazy_entry::int_t - || e->list_at(1)->type() != lazy_entry::int_t) + bdecode_node e = file_sizes_ent.list_at(i); + if (e.type() != bdecode_node::list_t + || e.list_size() < 2 + || e.list_at(0).type() != bdecode_node::int_t + || e.list_at(1).type() != bdecode_node::int_t) { ec.ec = errors::missing_file_sizes; ec.file = i; @@ -810,8 +810,8 @@ namespace libtorrent return false; } - boost::int64_t expected_size = e->list_int_value_at(0); - time_t expected_time = e->list_int_value_at(1); + boost::int64_t expected_size = e.list_int_value_at(0); + time_t expected_time = e.list_int_value_at(1); // if we're a seed, the expected size should match // the actual full size according to the torrent @@ -1472,14 +1472,14 @@ namespace libtorrent // isn't return false and the full check // will be run int piece_manager::check_fastresume( - lazy_entry const& rd, storage_error& ec) + bdecode_node const& rd, storage_error& ec) { TORRENT_ASSERT(m_files.piece_length() > 0); // if we don't have any resume data, return - if (rd.type() == lazy_entry::none_t) return check_no_fastresume(ec); + if (rd.type() == bdecode_node::none_t) return check_no_fastresume(ec); - if (rd.type() != lazy_entry::dict_t) + if (rd.type() != bdecode_node::dict_t) { ec.ec = errors::not_a_dictionary; return check_no_fastresume(ec); diff --git a/src/torrent.cpp b/src/torrent.cpp index b60b4de51..30f575e6f 100644 --- a/src/torrent.cpp +++ b/src/torrent.cpp @@ -763,8 +763,8 @@ namespace libtorrent { int pos; error_code ec; - if (lazy_bdecode(&m_resume_data->buf[0], &m_resume_data->buf[0] - + m_resume_data->buf.size(), m_resume_data->entry, ec, &pos) != 0) + if (bdecode(&m_resume_data->buf[0], &m_resume_data->buf[0] + + m_resume_data->buf.size(), m_resume_data->node, ec, &pos) != 0) { m_resume_data.reset(); #if defined TORRENT_LOGGING @@ -1745,13 +1745,16 @@ namespace libtorrent return; } - if (m_resume_data && m_resume_data->entry.type() == lazy_entry::dict_t) + if (m_resume_data && m_resume_data->node.type() == bdecode_node::dict_t) { int ev = 0; - if (m_resume_data->entry.dict_find_string_value("file-format") != "libtorrent resume file") + if (m_resume_data->node.dict_find_string_value("file-format") + != "libtorrent resume file") + { ev = errors::invalid_file_tag; + } - std::string info_hash = m_resume_data->entry.dict_find_string_value("info-hash"); + std::string info_hash = m_resume_data->node.dict_find_string_value("info-hash"); if (!ev && info_hash.empty()) ev = errors::missing_info_hash; @@ -1774,7 +1777,7 @@ namespace libtorrent } else { - read_resume_data(m_resume_data->entry); + read_resume_data(m_resume_data->node); } } @@ -1786,12 +1789,14 @@ namespace libtorrent if (!m_seed_mode && m_resume_data) { - lazy_entry const* piece_priority = m_resume_data->entry.dict_find_string("piece_priority"); - if (piece_priority && piece_priority->string_length() + bdecode_node piece_priority = m_resume_data->node + .dict_find_string("piece_priority"); + + if (piece_priority && piece_priority.string_length() == m_torrent_file->num_pieces()) { - char const* p = piece_priority->string_ptr(); - for (int i = 0; i < piece_priority->string_length(); ++i) + char const* p = piece_priority.string_ptr(); + for (int i = 0; i < piece_priority.string_length(); ++i) { int prio = p[i]; if (!has_picker() && prio == 1) continue; @@ -1924,7 +1929,7 @@ namespace libtorrent inc_refcount("check_fastresume"); m_ses.disk_thread().async_check_fastresume( - m_storage.get(), m_resume_data ? &m_resume_data->entry : NULL + m_storage.get(), m_resume_data ? &m_resume_data->node : NULL , boost::bind(&torrent::on_resume_data_checked , shared_from_this(), _1)); #if defined TORRENT_LOGGING @@ -2146,14 +2151,14 @@ namespace libtorrent state_updated(); - if (m_resume_data && m_resume_data->entry.type() == lazy_entry::dict_t) + if (m_resume_data && m_resume_data->node.type() == bdecode_node::dict_t) { using namespace libtorrent::detail; // for read_*_endpoint() - if (lazy_entry const* peers_entry = m_resume_data->entry.dict_find_string("peers")) + if (bdecode_node peers_entry = m_resume_data->node.dict_find_string("peers")) { - int num_peers = peers_entry->string_length() / (sizeof(address_v4::bytes_type) + 2); - char const* ptr = peers_entry->string_ptr(); + int num_peers = peers_entry.string_length() / (sizeof(address_v4::bytes_type) + 2); + char const* ptr = peers_entry.string_ptr(); for (int i = 0; i < num_peers; ++i) { add_peer(read_v4_endpoint(ptr) @@ -2162,10 +2167,11 @@ namespace libtorrent update_want_peers(); } - if (lazy_entry const* banned_peers_entry = m_resume_data->entry.dict_find_string("banned_peers")) + if (bdecode_node banned_peers_entry + = m_resume_data->node.dict_find_string("banned_peers")) { - int num_peers = banned_peers_entry->string_length() / (sizeof(address_v4::bytes_type) + 2); - char const* ptr = banned_peers_entry->string_ptr(); + int num_peers = banned_peers_entry.string_length() / (sizeof(address_v4::bytes_type) + 2); + char const* ptr = banned_peers_entry.string_ptr(); for (int i = 0; i < num_peers; ++i) { std::vector peers; @@ -2178,10 +2184,10 @@ namespace libtorrent } #if TORRENT_USE_IPV6 - if (lazy_entry const* peers6_entry = m_resume_data->entry.dict_find_string("peers6")) + if (bdecode_node peers6_entry = m_resume_data->node.dict_find_string("peers6")) { - int num_peers = peers6_entry->string_length() / (sizeof(address_v6::bytes_type) + 2); - char const* ptr = peers6_entry->string_ptr(); + int num_peers = peers6_entry.string_length() / (sizeof(address_v6::bytes_type) + 2); + char const* ptr = peers6_entry.string_ptr(); for (int i = 0; i < num_peers; ++i) { add_peer(read_v6_endpoint(ptr) @@ -2190,10 +2196,10 @@ namespace libtorrent update_want_peers(); } - if (lazy_entry const* banned_peers6_entry = m_resume_data->entry.dict_find_string("banned_peers6")) + if (bdecode_node banned_peers6_entry = m_resume_data->node.dict_find_string("banned_peers6")) { - int num_peers = banned_peers6_entry->string_length() / (sizeof(address_v6::bytes_type) + 2); - char const* ptr = banned_peers6_entry->string_ptr(); + int num_peers = banned_peers6_entry.string_length() / (sizeof(address_v6::bytes_type) + 2); + char const* ptr = banned_peers6_entry.string_ptr(); for (int i = 0; i < num_peers; ++i) { torrent_peer* p = add_peer(read_v6_endpoint(ptr) @@ -2205,14 +2211,14 @@ namespace libtorrent #endif // parse out "peers" from the resume data and add them to the peer list - if (lazy_entry const* peers_entry = m_resume_data->entry.dict_find_list("peers")) + if (bdecode_node peers_entry = m_resume_data->node.dict_find_list("peers")) { - for (int i = 0; i < peers_entry->list_size(); ++i) + for (int i = 0; i < peers_entry.list_size(); ++i) { - lazy_entry const* e = peers_entry->list_at(i); - if (e->type() != lazy_entry::dict_t) continue; - std::string ip = e->dict_find_string_value("ip"); - int port = e->dict_find_int_value("port"); + bdecode_node e = peers_entry.list_at(i); + if (e.type() != bdecode_node::dict_t) continue; + std::string ip = e.dict_find_string_value("ip"); + int port = e.dict_find_int_value("port"); if (ip.empty() || port == 0) continue; error_code ec; tcp::endpoint a(address::from_string(ip, ec), (unsigned short)port); @@ -2223,14 +2229,14 @@ namespace libtorrent } // parse out "banned_peers" and add them as banned - if (lazy_entry const* banned_peers_entry = m_resume_data->entry.dict_find_list("banned_peers")) + if (bdecode_node banned_peers_entry = m_resume_data->node.dict_find_list("banned_peers")) { - for (int i = 0; i < banned_peers_entry->list_size(); ++i) + for (int i = 0; i < banned_peers_entry.list_size(); ++i) { - lazy_entry const* e = banned_peers_entry->list_at(i); - if (e->type() != lazy_entry::dict_t) continue; - std::string ip = e->dict_find_string_value("ip"); - int port = e->dict_find_int_value("port"); + bdecode_node e = banned_peers_entry.list_at(i); + if (e.type() != bdecode_node::dict_t) continue; + std::string ip = e.dict_find_string_value("ip"); + int port = e.dict_find_int_value("port"); if (ip.empty() || port == 0) continue; error_code ec; tcp::endpoint a(address::from_string(ip, ec), (unsigned short)port); @@ -2276,15 +2282,15 @@ namespace libtorrent // there are either no files for this torrent // or the resume_data was accepted - if (!j->error && m_resume_data && m_resume_data->entry.type() == lazy_entry::dict_t) + if (!j->error && m_resume_data && m_resume_data->node.type() == bdecode_node::dict_t) { // parse have bitmask - lazy_entry const* pieces = m_resume_data->entry.dict_find("pieces"); - if (pieces && pieces->type() == lazy_entry::string_t - && int(pieces->string_length()) == m_torrent_file->num_pieces()) + bdecode_node pieces = m_resume_data->node.dict_find("pieces"); + if (pieces && pieces.type() == bdecode_node::string_t + && int(pieces.string_length()) == m_torrent_file->num_pieces()) { - char const* pieces_str = pieces->string_ptr(); - for (int i = 0, end(pieces->string_length()); i < end; ++i) + char const* pieces_str = pieces.string_ptr(); + for (int i = 0, end(pieces.string_length()); i < end; ++i) { if (pieces_str[i] & 1) { @@ -2299,12 +2305,12 @@ namespace libtorrent } else { - lazy_entry const* slots = m_resume_data->entry.dict_find("slots"); - if (slots && slots->type() == lazy_entry::list_t) + bdecode_node slots = m_resume_data->node.dict_find("slots"); + if (slots && slots.type() == bdecode_node::list_t) { - for (int i = 0; i < slots->list_size(); ++i) + for (int i = 0; i < slots.list_size(); ++i) { - int piece = slots->list_int_value_at(i, -1); + int piece = slots.list_int_value_at(i, -1); if (piece >= 0) { need_picker(); @@ -2321,13 +2327,14 @@ namespace libtorrent int num_blocks_per_piece = static_cast(torrent_file().piece_length()) / block_size(); - if (lazy_entry const* unfinished_ent = m_resume_data->entry.dict_find_list("unfinished")) + if (bdecode_node unfinished_ent + = m_resume_data->node.dict_find_list("unfinished")) { - for (int i = 0; i < unfinished_ent->list_size(); ++i) + for (int i = 0; i < unfinished_ent.list_size(); ++i) { - lazy_entry const* e = unfinished_ent->list_at(i); - if (e->type() != lazy_entry::dict_t) continue; - int piece = e->dict_find_int_value("piece", -1); + bdecode_node e = unfinished_ent.list_at(i); + if (e.type() != bdecode_node::dict_t) continue; + int piece = e.dict_find_int_value("piece", -1); if (piece < 0 || piece > torrent_file().num_pieces()) continue; if (has_picker() && m_picker->have_piece(piece)) @@ -2336,7 +2343,7 @@ namespace libtorrent update_gauge(); } - std::string bitmask = e->dict_find_string_value("bitmask"); + std::string bitmask = e.dict_find_string_value("bitmask"); if (bitmask.empty()) continue; need_picker(); @@ -6534,7 +6541,7 @@ namespace libtorrent } #endif - void torrent::read_resume_data(lazy_entry const& rd) + void torrent::read_resume_data(bdecode_node const& rd) { m_total_uploaded = rd.dict_find_int_value("total_uploaded"); m_total_downloaded = rd.dict_find_int_value("total_downloaded"); @@ -6627,12 +6634,12 @@ namespace libtorrent // The mapped_files needs to be read both in the network thread // and in the disk thread, since they both have their own mapped files structures // which are kept in sync - lazy_entry const* mapped_files = rd.dict_find_list("mapped_files"); - if (mapped_files && mapped_files->list_size() == m_torrent_file->num_files()) + bdecode_node mapped_files = rd.dict_find_list("mapped_files"); + if (mapped_files && mapped_files.list_size() == m_torrent_file->num_files()) { for (int i = 0; i < m_torrent_file->num_files(); ++i) { - std::string new_filename = mapped_files->list_string_value_at(i); + std::string new_filename = mapped_files.list_string_value_at(i); if (new_filename.empty()) continue; m_torrent_file->rename_file(i, new_filename); } @@ -6645,14 +6652,14 @@ namespace libtorrent if (!m_seed_mode && !m_override_resume_data) { - lazy_entry const* file_priority = rd.dict_find_list("file_priority"); - if (file_priority && file_priority->list_size() + bdecode_node file_priority = rd.dict_find_list("file_priority"); + if (file_priority && file_priority.list_size() == m_torrent_file->num_files()) { int num_files = m_torrent_file->num_files(); m_file_priority.resize(num_files); for (int i = 0; i < num_files; ++i) - m_file_priority[i] = file_priority->list_int_value_at(i, 1); + m_file_priority[i] = file_priority.list_int_value_at(i, 1); // unallocated slots are assumed to be priority 1, so cut off any // trailing ones int end_range = num_files - 1; @@ -6671,19 +6678,19 @@ namespace libtorrent update_piece_priorities(); } - lazy_entry const* trackers = rd.dict_find_list("trackers"); + bdecode_node trackers = rd.dict_find_list("trackers"); if (trackers) { if (!m_merge_resume_trackers) m_trackers.clear(); int tier = 0; - for (int i = 0; i < trackers->list_size(); ++i) + for (int i = 0; i < trackers.list_size(); ++i) { - lazy_entry const* tier_list = trackers->list_at(i); - if (tier_list == 0 || tier_list->type() != lazy_entry::list_t) + bdecode_node tier_list = trackers.list_at(i); + if (!tier_list || tier_list.type() != bdecode_node::list_t) continue; - for (int j = 0; j < tier_list->list_size(); ++j) + for (int j = 0; j < tier_list.list_size(); ++j) { - announce_entry e(tier_list->list_string_value_at(j)); + announce_entry e(tier_list.list_string_value_at(j)); if (std::find_if(m_trackers.begin(), m_trackers.end() , boost::bind(&announce_entry::url, _1) == e.url) != m_trackers.end()) continue; @@ -6700,24 +6707,24 @@ namespace libtorrent prioritize_udp_trackers(); } - lazy_entry const* url_list = rd.dict_find_list("url-list"); + bdecode_node url_list = rd.dict_find_list("url-list"); if (url_list) { - for (int i = 0; i < url_list->list_size(); ++i) + for (int i = 0; i < url_list.list_size(); ++i) { - std::string url = url_list->list_string_value_at(i); + std::string url = url_list.list_string_value_at(i); if (url.empty()) continue; if (m_torrent_file->num_files() > 1 && url[url.size()-1] != '/') url += '/'; add_web_seed(url, web_seed_entry::url_seed); } } - lazy_entry const* httpseeds = rd.dict_find_list("httpseeds"); + bdecode_node httpseeds = rd.dict_find_list("httpseeds"); if (httpseeds) { - for (int i = 0; i < httpseeds->list_size(); ++i) + for (int i = 0; i < httpseeds.list_size(); ++i) { - std::string url = httpseeds->list_string_value_at(i); + std::string url = httpseeds.list_string_value_at(i); if (url.empty()) continue; add_web_seed(url, web_seed_entry::http_seed); } @@ -6725,16 +6732,16 @@ namespace libtorrent if (m_torrent_file->is_merkle_torrent()) { - lazy_entry const* mt = rd.dict_find_string("merkle tree"); + bdecode_node mt = rd.dict_find_string("merkle tree"); if (mt) { std::vector tree; tree.resize(m_torrent_file->merkle_tree().size()); - std::memcpy(&tree[0], mt->string_ptr() - , (std::min)(mt->string_length(), int(tree.size()) * 20)); - if (mt->string_length() < int(tree.size()) * 20) - std::memset(&tree[0] + mt->string_length() / 20, 0 - , tree.size() - mt->string_length() / 20); + std::memcpy(&tree[0], mt.string_ptr() + , (std::min)(mt.string_length(), int(tree.size()) * 20)); + if (mt.string_length() < int(tree.size()) * 20) + std::memset(&tree[0] + mt.string_length() / 20, 0 + , tree.size() - mt.string_length() / 20); m_torrent_file->set_merkle_tree(tree); } else @@ -7425,9 +7432,9 @@ namespace libtorrent return false; } - lazy_entry metadata; + bdecode_node metadata; error_code ec; - int ret = lazy_bdecode(metadata_buf, metadata_buf + metadata_size, metadata, ec); + int ret = bdecode(metadata_buf, metadata_buf + metadata_size, metadata, ec); if (ret != 0 || !m_torrent_file->parse_info_section(metadata, ec, 0)) { update_gauge(); @@ -8416,8 +8423,8 @@ namespace libtorrent // this fires during disconnecting peers // if (is_paused()) TORRENT_ASSERT(num_peers() == 0 || m_graceful_pause_mode); - TORRENT_ASSERT(!m_resume_data || m_resume_data->entry.type() == lazy_entry::dict_t - || m_resume_data->entry.type() == lazy_entry::none_t); + TORRENT_ASSERT(!m_resume_data || m_resume_data->node.type() == bdecode_node::dict_t + || m_resume_data->node.type() == bdecode_node::none_t); int seeds = 0; int num_uploads = 0; diff --git a/src/torrent_info.cpp b/src/torrent_info.cpp index 18f4f9f48..ef8a486d4 100644 --- a/src/torrent_info.cpp +++ b/src/torrent_info.cpp @@ -54,6 +54,10 @@ POSSIBILITY OF SUCH DAMAGE. #include "libtorrent/add_torrent_params.hpp" #include "libtorrent/magnet_uri.hpp" +#ifndef TORRENT_NO_DEPRECATE +#include "libtorrent/lazy_entry.hpp" +#endif + #ifdef _MSC_VER #pragma warning(push, 1) #endif @@ -362,11 +366,11 @@ namespace libtorrent // "path" // root_dir is the name of the torrent, unless this is a single file // torrent, in which case it's empty. - bool extract_single_file(lazy_entry const& dict, file_storage& files + bool extract_single_file(bdecode_node const& dict, file_storage& files , std::string const& root_dir, ptrdiff_t info_ptr_diff, bool top_level , error_code& ec) { - if (dict.type() != lazy_entry::dict_t) return false; + if (dict.type() != bdecode_node::dict_t) return false; boost::int64_t file_size = dict.dict_find_int_value("length", -1); if (file_size < 0) { @@ -385,52 +389,52 @@ namespace libtorrent { // prefer the name.utf-8 because if it exists, it is more likely to be // correctly encoded - lazy_entry const* p = dict.dict_find_string("name.utf-8"); - if (p == 0) p = dict.dict_find_string("name"); - if (p == 0 || p->string_length() == 0) + bdecode_node p = dict.dict_find_string("name.utf-8"); + if (!p) p = dict.dict_find_string("name"); + if (!p || p.string_length() == 0) { ec = errors::torrent_missing_name; return false; } - filename = p->string_ptr() + info_ptr_diff; - filename_len = p->string_length(); - sanitize_append_path_element(path, p->string_ptr(), p->string_length()); + filename = p.string_ptr() + info_ptr_diff; + filename_len = p.string_length(); + sanitize_append_path_element(path, p.string_ptr(), p.string_length()); // if (path.empty()) path = to_hex(files.info_hash().to_string()); } else { - lazy_entry const* p = dict.dict_find_list("path.utf-8"); - if (p == 0) p = dict.dict_find_list("path"); - if (p == 0 || p->list_size() == 0) + bdecode_node p = dict.dict_find_list("path.utf-8"); + if (!p) p = dict.dict_find_list("path"); + if (!p || p.list_size() == 0) { ec = errors::torrent_missing_name; return false; } int preallocate = path.size(); - for (int i = 0, end(p->list_size()); i < end; ++i) + for (int i = 0, end(p.list_size()); i < end; ++i) { - lazy_entry const* e = p->list_at(i); - if (e->type() != lazy_entry::string_t) + bdecode_node e = p.list_at(i); + if (e.type() != bdecode_node::string_t) { ec = errors::torrent_missing_name; return false; } - preallocate += e->string_length() + 1; + preallocate += e.string_length() + 1; } path.reserve(preallocate); - for (int i = 0, end(p->list_size()); i < end; ++i) + for (int i = 0, end(p.list_size()); i < end; ++i) { - lazy_entry const* e = p->list_at(i); + bdecode_node e = p.list_at(i); if (i == end - 1) { - filename = e->string_ptr() + info_ptr_diff; - filename_len = e->string_length(); + filename = e.string_ptr() + info_ptr_diff; + filename_len = e.string_length(); } - sanitize_append_path_element(path, e->string_ptr(), e->string_length()); + sanitize_append_path_element(path, e.string_ptr(), e.string_length()); } } @@ -439,12 +443,12 @@ namespace libtorrent if (path.find("_____padding_file_") != std::string::npos) file_flags = file_storage::flag_pad_file; - lazy_entry const* attr = dict.dict_find_string("attr"); + bdecode_node attr = dict.dict_find_string("attr"); if (attr) { - for (int i = 0; i < attr->string_length(); ++i) + for (int i = 0; i < attr.string_length(); ++i) { - switch (attr->string_ptr()[i]) + switch (attr.string_ptr()[i]) { case 'l': file_flags |= file_storage::flag_symlink; file_size = 0; break; case 'x': file_flags |= file_storage::flag_executable; break; @@ -454,19 +458,19 @@ namespace libtorrent } } - lazy_entry const* fh = dict.dict_find_string("sha1"); + bdecode_node fh = dict.dict_find_string("sha1"); char const* filehash = NULL; - if (fh && fh->string_length() == 20) - filehash = fh->string_ptr() + info_ptr_diff; + if (fh && fh.string_length() == 20) + filehash = fh.string_ptr() + info_ptr_diff; std::string symlink_path; - lazy_entry const* s_p = dict.dict_find("symlink path"); - if (s_p != 0 && s_p->type() == lazy_entry::list_t + bdecode_node s_p = dict.dict_find("symlink path"); + if (s_p && s_p.type() == bdecode_node::list_t && (file_flags & file_storage::flag_symlink)) { - for (int i = 0, end(s_p->list_size()); i < end; ++i) + for (int i = 0, end(s_p.list_size()); i < end; ++i) { - std::string path_element = s_p->list_at(i)->string_value(); + std::string path_element = s_p.list_at(i).string_value(); symlink_path = combine_path(symlink_path, path_element); } } @@ -550,10 +554,10 @@ namespace libtorrent // root_dir is the name of the torrent, unless this is a single file // torrent, in which case it's empty. - bool extract_files(lazy_entry const& list, file_storage& target + bool extract_files(bdecode_node const& list, file_storage& target , std::string const& root_dir, ptrdiff_t info_ptr_diff, error_code& ec) { - if (list.type() != lazy_entry::list_t) + if (list.type() != bdecode_node::list_t) { ec = errors::torrent_file_parse_failed; return false; @@ -562,7 +566,7 @@ namespace libtorrent for (int i = 0, end(list.list_size()); i < end; ++i) { - if (!extract_single_file(*list.list_at(i), target, root_dir + if (!extract_single_file(list.list_at(i), target, root_dir , info_ptr_diff, false, ec)) return false; } @@ -691,7 +695,7 @@ namespace libtorrent // event, we need to let this announce through bool need_send_complete = is_seed && !complete_sent; - return now >= next_announce + return now > next_announce && (now >= min_announce || need_send_complete) && (fails < fail_limit || fail_limit == 0) && !updating; @@ -735,6 +739,7 @@ namespace libtorrent t.check_invariant(); #endif if (m_info_section_size == 0) return; + TORRENT_ASSERT(m_piece_hashes); error_code ec; m_info_section.reset(new char[m_info_section_size]); @@ -746,15 +751,12 @@ namespace libtorrent if (m_orig_files) const_cast(*m_orig_files).apply_pointer_offset(offset); -#if TORRENT_USE_ASSERTS || !defined BOOST_NO_EXCEPTIONS - int ret = -#endif - lazy_bdecode(m_info_section.get(), m_info_section.get() - + m_info_section_size, m_info_dict, ec); -#ifndef BOOST_NO_EXCEPTIONS - if (ret != 0) throw libtorrent_exception(ec); -#endif - TORRENT_ASSERT(ret == 0); + if (m_info_dict) + { + // make this decoded object point to our copy of the info section + // buffer + m_info_dict.switch_underlying_buffer(m_info_section.get()); + } m_piece_hashes += offset; TORRENT_ASSERT(m_piece_hashes >= m_info_section.get()); @@ -861,6 +863,50 @@ namespace libtorrent } #ifndef TORRENT_NO_DEPRECATE + torrent_info::torrent_info(lazy_entry const& torrent_file, error_code& ec + , int flags) + : m_piece_hashes(0) + , m_creation_date(0) + , m_merkle_first_leaf(0) + , m_info_section_size(0) + , m_multifile(false) + , m_private(false) + , m_i2p(false) + { + std::pair buf = torrent_file.data_section(); + bdecode_node e; + if (bdecode(buf.first, buf.first + buf.second, e, ec) != 0) + return; + parse_torrent_file(e, ec, 0); + } + + torrent_info::torrent_info(lazy_entry const& torrent_file, int flags) + : m_piece_hashes(0) + , m_creation_date(0) + , m_merkle_first_leaf(0) + , m_info_section_size(0) + , m_multifile(false) + , m_private(false) + , m_i2p(false) + { + std::pair buf = torrent_file.data_section(); + bdecode_node e; + error_code ec; + if (bdecode(buf.first, buf.first + buf.second, e, ec) != 0) + { +#ifndef BOOST_NO_EXCEPTIONS + throw invalid_torrent_file(ec); +#endif + return; + } +#ifndef BOOST_NO_EXCEPTIONS + if (!parse_torrent_file(e, ec, 0)) + throw invalid_torrent_file(ec); +#else + parse_torrent_file(e, ec, 0); +#endif + } + // standard constructor that parses a torrent file torrent_info::torrent_info(entry const& torrent_file) : m_piece_hashes(0) @@ -875,9 +921,9 @@ namespace libtorrent std::back_insert_iterator > out(tmp); bencode(out, torrent_file); - lazy_entry e; + bdecode_node e; error_code ec; - if (tmp.size() == 0 || lazy_bdecode(&tmp[0], &tmp[0] + tmp.size(), e, ec) != 0) + if (tmp.size() == 0 || bdecode(&tmp[0], &tmp[0] + tmp.size(), e, ec) != 0) { #ifndef BOOST_NO_EXCEPTIONS throw invalid_torrent_file(ec); @@ -895,7 +941,7 @@ namespace libtorrent #endif #ifndef BOOST_NO_EXCEPTIONS - torrent_info::torrent_info(lazy_entry const& torrent_file, int flags) + torrent_info::torrent_info(bdecode_node const& torrent_file, int flags) : m_piece_hashes(0) , m_creation_date(0) , m_merkle_first_leaf(0) @@ -921,8 +967,8 @@ namespace libtorrent , m_i2p(false) { error_code ec; - lazy_entry e; - if (lazy_bdecode(buffer, buffer + size, e, ec) != 0) + bdecode_node e; + if (bdecode(buffer, buffer + size, e, ec) != 0) throw invalid_torrent_file(ec); if (!parse_torrent_file(e, ec, flags)) @@ -945,8 +991,8 @@ namespace libtorrent int ret = load_file(filename, buf, ec); if (ret < 0) throw invalid_torrent_file(ec); - lazy_entry e; - if (buf.size() == 0 || lazy_bdecode(&buf[0], &buf[0] + buf.size(), e, ec) != 0) + bdecode_node e; + if (buf.size() == 0 || bdecode(&buf[0], &buf[0] + buf.size(), e, ec) != 0) throw invalid_torrent_file(ec); if (!parse_torrent_file(e, ec, flags)) @@ -973,8 +1019,8 @@ namespace libtorrent int ret = load_file(utf8, buf, ec); if (ret < 0) throw invalid_torrent_file(ec); - lazy_entry e; - if (buf.size() == 0 || lazy_bdecode(&buf[0], &buf[0] + buf.size(), e, ec) != 0) + bdecode_node e; + if (buf.size() == 0 || bdecode(&buf[0], &buf[0] + buf.size(), e, ec) != 0) throw invalid_torrent_file(ec); if (!parse_torrent_file(e, ec, flags)) @@ -993,7 +1039,7 @@ namespace libtorrent #endif // TORRENT_USE_WSTRING #endif - torrent_info::torrent_info(lazy_entry const& torrent_file, error_code& ec, int flags) + torrent_info::torrent_info(bdecode_node const& torrent_file, error_code& ec, int flags) : m_piece_hashes(0) , m_creation_date(0) , m_merkle_first_leaf(0) @@ -1016,8 +1062,8 @@ namespace libtorrent , m_private(false) , m_i2p(false) { - lazy_entry e; - if (lazy_bdecode(buffer, buffer + size, e, ec) != 0) + bdecode_node e; + if (bdecode(buffer, buffer + size, e, ec) != 0) return; parse_torrent_file(e, ec, flags); @@ -1037,8 +1083,8 @@ namespace libtorrent int ret = load_file(filename, buf, ec); if (ret < 0) return; - lazy_entry e; - if (buf.size() == 0 || lazy_bdecode(&buf[0], &buf[0] + buf.size(), e, ec) != 0) + bdecode_node e; + if (buf.size() == 0 || bdecode(&buf[0], &buf[0] + buf.size(), e, ec) != 0) return; parse_torrent_file(e, ec, flags); @@ -1062,8 +1108,8 @@ namespace libtorrent int ret = load_file(utf8, buf, ec); if (ret < 0) return; - lazy_entry e; - if (buf.size() == 0 || lazy_bdecode(&buf[0], &buf[0] + buf.size(), e, ec) != 0) + bdecode_node e; + if (buf.size() == 0 || bdecode(&buf[0], &buf[0] + buf.size(), e, ec) != 0) return; parse_torrent_file(e, ec, flags); @@ -1092,8 +1138,8 @@ namespace libtorrent void torrent_info::load(char const* buffer, int size, error_code& ec) { - lazy_entry e; - if (lazy_bdecode(buffer, buffer + size, e, ec) != 0) + bdecode_node e; + if (bdecode(buffer, buffer + size, e, ec) != 0) return; if (!parse_torrent_file(e, ec, 0)) @@ -1166,20 +1212,21 @@ namespace libtorrent std::string torrent_info::ssl_cert() const { // this is parsed lazily - if (m_info_dict.type() == lazy_entry::none_t) + if (!m_info_dict) { error_code ec; - lazy_bdecode(m_info_section.get(), m_info_section.get() + bdecode(m_info_section.get(), m_info_section.get() + m_info_section_size, m_info_dict, ec); if (ec) return ""; } - if (m_info_dict.type() != lazy_entry::dict_t) return ""; + if (m_info_dict.type() != bdecode_node::dict_t) return ""; return m_info_dict.dict_find_string_value("ssl-cert"); } - bool torrent_info::parse_info_section(lazy_entry const& info, error_code& ec, int flags) + bool torrent_info::parse_info_section(bdecode_node const& info + , error_code& ec, int flags) { - if (info.type() != lazy_entry::dict_t) + if (info.type() != bdecode_node::dict_t) { ec = errors::torrent_info_no_dict; return false; @@ -1214,22 +1261,23 @@ namespace libtorrent files.set_piece_length(piece_length); // extract file name (or the directory name if it's a multifile libtorrent) - lazy_entry const* name_ent = info.dict_find_string("name.utf-8"); - if (name_ent == 0) name_ent = info.dict_find_string("name"); - if (name_ent == 0) + bdecode_node name_ent = info.dict_find_string("name.utf-8"); + if (!name_ent) name_ent = info.dict_find_string("name"); + if (!name_ent) { ec = errors::torrent_missing_name; return false; } std::string name; - sanitize_append_path_element(name, name_ent->string_ptr(), name_ent->string_length()); + sanitize_append_path_element(name, name_ent.string_ptr() + , name_ent.string_length()); if (name.empty()) name = to_hex(m_info_hash.to_string()); // extract file list - lazy_entry const* i = info.dict_find_list("files"); - if (i == 0) + bdecode_node i = info.dict_find_list("files"); + if (!i) { // if there's no list of files, there has to be a length // field. @@ -1240,7 +1288,7 @@ namespace libtorrent } else { - if (!extract_files(*i, files, name, info_ptr_diff, ec)) + if (!extract_files(i, files, name, info_ptr_diff, ec)) return false; m_multifile = true; } @@ -1253,9 +1301,9 @@ namespace libtorrent files.set_num_pieces(int((files.total_size() + files.piece_length() - 1) / files.piece_length())); - lazy_entry const* pieces = info.dict_find_string("pieces"); - lazy_entry const* root_hash = info.dict_find_string("root hash"); - if (pieces == 0 && root_hash == 0) + bdecode_node pieces = info.dict_find_string("pieces"); + bdecode_node root_hash = info.dict_find_string("root hash"); + if (!pieces && !root_hash) { ec = errors::torrent_missing_pieces; return false; @@ -1263,20 +1311,20 @@ namespace libtorrent if (pieces) { - if (pieces->string_length() != files.num_pieces() * 20) + if (pieces.string_length() != files.num_pieces() * 20) { ec = errors::torrent_invalid_hashes; return false; } - m_piece_hashes = pieces->string_ptr() + info_ptr_diff; + m_piece_hashes = pieces.string_ptr() + info_ptr_diff; TORRENT_ASSERT(m_piece_hashes >= m_info_section.get()); TORRENT_ASSERT(m_piece_hashes < m_info_section.get() + m_info_section_size); } else { TORRENT_ASSERT(root_hash); - if (root_hash->string_length() != 20) + if (root_hash.string_length() != 20) { ec = errors::torrent_invalid_hashes; return false; @@ -1286,7 +1334,7 @@ namespace libtorrent m_merkle_first_leaf = num_nodes - num_leafs; m_merkle_tree.resize(num_nodes); std::memset(&m_merkle_tree[0], 0, num_nodes * 20); - m_merkle_tree[0].assign(root_hash->string_ptr()); + m_merkle_tree[0].assign(root_hash.string_ptr()); } m_private = info.dict_find_int_value("private", 0); @@ -1396,21 +1444,22 @@ namespace libtorrent } #endif - bool torrent_info::parse_torrent_file(lazy_entry const& torrent_file, error_code& ec, int flags) + bool torrent_info::parse_torrent_file(bdecode_node const& torrent_file + , error_code& ec, int flags) { - if (torrent_file.type() != lazy_entry::dict_t) + if (torrent_file.type() != bdecode_node::dict_t) { ec = errors::torrent_is_no_dict; return false; } - lazy_entry const* info = torrent_file.dict_find_dict("info"); + bdecode_node info = torrent_file.dict_find_dict("info"); if (info == 0) { - lazy_entry const* link = torrent_file.dict_find_string("magnet-uri"); + bdecode_node link = torrent_file.dict_find_string("magnet-uri"); if (link) { - std::string uri = link->string_value(); + std::string uri = link.string_value(); add_torrent_params p; parse_magnet_uri(uri, p, ec); @@ -1427,21 +1476,21 @@ namespace libtorrent ec = errors::torrent_missing_info; return false; } - if (!parse_info_section(*info, ec, flags)) return false; + if (!parse_info_section(info, ec, flags)) return false; resolve_duplicate_filenames(); // extract the url of the tracker - lazy_entry const* i = torrent_file.dict_find_list("announce-list"); + bdecode_node i = torrent_file.dict_find_list("announce-list"); if (i) { - m_urls.reserve(i->list_size()); - for (int j = 0, end(i->list_size()); j < end; ++j) + m_urls.reserve(i.list_size()); + for (int j = 0, end(i.list_size()); j < end; ++j) { - lazy_entry const* tier = i->list_at(j); - if (tier->type() != lazy_entry::list_t) continue; - for (int k = 0, end(tier->list_size()); k < end; ++k) + bdecode_node tier = i.list_at(j); + if (tier.type() != bdecode_node::list_t) continue; + for (int k = 0, end(tier.list_size()); k < end; ++k) { - announce_entry e(tier->list_string_value_at(k)); + announce_entry e(tier.list_string_value_at(k)); e.trim(); if (e.url.empty()) continue; e.tier = j; @@ -1486,20 +1535,20 @@ namespace libtorrent if (!e.url.empty()) m_urls.push_back(e); } - lazy_entry const* nodes = torrent_file.dict_find_list("nodes"); + bdecode_node nodes = torrent_file.dict_find_list("nodes"); if (nodes) { - for (int i = 0, end(nodes->list_size()); i < end; ++i) + for (int i = 0, end(nodes.list_size()); i < end; ++i) { - 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) + bdecode_node n = nodes.list_at(i); + if (n.type() != bdecode_node::list_t + || n.list_size() < 2 + || n.list_at(0).type() != bdecode_node::string_t + || n.list_at(1).type() != bdecode_node::int_t) continue; m_nodes.push_back(std::make_pair( - n->list_at(0)->string_value() - , int(n->list_at(1)->int_value()))); + n.list_at(0).string_value() + , int(n.list_at(1).int_value()))); } } @@ -1511,24 +1560,25 @@ namespace libtorrent } // if there are any url-seeds, extract them - lazy_entry const* url_seeds = torrent_file.dict_find("url-list"); - if (url_seeds && url_seeds->type() == lazy_entry::string_t && url_seeds->string_length() > 0) + bdecode_node url_seeds = torrent_file.dict_find("url-list"); + if (url_seeds && url_seeds.type() == bdecode_node::string_t + && url_seeds.string_length() > 0) { - web_seed_entry ent(maybe_url_encode(url_seeds->string_value()) + web_seed_entry ent(maybe_url_encode(url_seeds.string_value()) , web_seed_entry::url_seed); if (m_multifile && ent.url[ent.url.size()-1] != '/') ent.url += '/'; m_web_seeds.push_back(ent); } - else if (url_seeds && url_seeds->type() == lazy_entry::list_t) + else if (url_seeds && url_seeds.type() == bdecode_node::list_t) { // only add a URL once std::set unique; - for (int i = 0, end(url_seeds->list_size()); i < end; ++i) + for (int i = 0, end(url_seeds.list_size()); i < end; ++i) { - lazy_entry const* url = url_seeds->list_at(i); - if (url->type() != lazy_entry::string_t) continue; - if (url->string_length() == 0) continue; - web_seed_entry ent(maybe_url_encode(url->string_value()) + bdecode_node url = url_seeds.list_at(i); + if (url.type() != bdecode_node::string_t) continue; + if (url.string_length() == 0) continue; + web_seed_entry ent(maybe_url_encode(url.string_value()) , web_seed_entry::url_seed); if (m_multifile && ent.url[ent.url.size()-1] != '/') ent.url += '/'; if (unique.count(ent.url)) continue; @@ -1538,21 +1588,22 @@ namespace libtorrent } // if there are any http-seeds, extract them - lazy_entry const* http_seeds = torrent_file.dict_find("httpseeds"); - if (http_seeds && http_seeds->type() == lazy_entry::string_t && http_seeds->string_length() > 0) + bdecode_node http_seeds = torrent_file.dict_find("httpseeds"); + if (http_seeds && http_seeds.type() == bdecode_node::string_t + && http_seeds.string_length() > 0) { - m_web_seeds.push_back(web_seed_entry(maybe_url_encode(http_seeds->string_value()) + m_web_seeds.push_back(web_seed_entry(maybe_url_encode(http_seeds.string_value()) , web_seed_entry::http_seed)); } - else if (http_seeds && http_seeds->type() == lazy_entry::list_t) + else if (http_seeds && http_seeds.type() == bdecode_node::list_t) { // only add a URL once std::set unique; - for (int i = 0, end(http_seeds->list_size()); i < end; ++i) + for (int i = 0, end(http_seeds.list_size()); i < end; ++i) { - lazy_entry const* url = http_seeds->list_at(i); - if (url->type() != lazy_entry::string_t || url->string_length() == 0) continue; - std::string u = maybe_url_encode(url->string_value()); + bdecode_node url = http_seeds.list_at(i); + if (url.type() != bdecode_node::string_t || url.string_length() == 0) continue; + std::string u = maybe_url_encode(url.string_value()); if (unique.count(u)) continue; unique.insert(u); m_web_seeds.push_back(web_seed_entry(u, web_seed_entry::http_seed)); @@ -1616,6 +1667,18 @@ namespace libtorrent , filter_web_seed_type(web_seed_entry::http_seed)).urls; } + bool torrent_info::parse_info_section(lazy_entry const& le, error_code& ec + , int flags) + { + if (le.type() == lazy_entry::none_t) return false; + std::pair buf = le.data_section(); + bdecode_node e; + if (bdecode(buf.first, buf.first + buf.second, e, ec) != 0) + return false; + + return parse_info_section(e, ec, flags); + } + #endif // TORRENT_NO_DEPRECATE void torrent_info::add_url_seed(std::string const& url diff --git a/src/ut_metadata.cpp b/src/ut_metadata.cpp index adf7198cc..b0aea8672 100644 --- a/src/ut_metadata.cpp +++ b/src/ut_metadata.cpp @@ -234,14 +234,14 @@ namespace libtorrent { namespace } // called when the extension handshake from the other end is received - virtual bool on_extension_handshake(lazy_entry const& h) + virtual bool on_extension_handshake(bdecode_node const& h) { m_message_index = 0; - if (h.type() != lazy_entry::dict_t) return false; - lazy_entry const* messages = h.dict_find_dict("m"); + if (h.type() != bdecode_node::dict_t) return false; + bdecode_node messages = h.dict_find_dict("m"); if (!messages) return false; - int index = messages->dict_find_int_value("ut_metadata", -1); + int index = messages.dict_find_int_value("ut_metadata", -1); if (index == -1) return false; m_message_index = index; diff --git a/src/ut_pex.cpp b/src/ut_pex.cpp index 05115dd21..59ee42151 100644 --- a/src/ut_pex.cpp +++ b/src/ut_pex.cpp @@ -260,14 +260,14 @@ namespace libtorrent { namespace messages[extension_name] = extension_index; } - virtual bool on_extension_handshake(lazy_entry const& h) + virtual bool on_extension_handshake(bdecode_node const& h) { m_message_index = 0; - if (h.type() != lazy_entry::dict_t) return false; - lazy_entry const* messages = h.dict_find("m"); - if (!messages || messages->type() != lazy_entry::dict_t) return false; + if (h.type() != bdecode_node::dict_t) return false; + bdecode_node messages = h.dict_find_dict("m"); + if (!messages) return false; - int index = int(messages->dict_find_int_value(extension_name, -1)); + int index = int(messages.dict_find_int_value(extension_name, -1)); if (index == -1) return false; m_message_index = index; return true; @@ -300,26 +300,26 @@ namespace libtorrent { namespace m_last_pex[i] = m_last_pex[i+1]; m_last_pex[num_pex_timers-1] = now; - lazy_entry pex_msg; + bdecode_node pex_msg; error_code ec; - int ret = lazy_bdecode(body.begin, body.end, pex_msg, ec); - if (ret != 0 || pex_msg.type() != lazy_entry::dict_t) + int ret = bdecode(body.begin, body.end, pex_msg, ec); + if (ret != 0 || pex_msg.type() != bdecode_node::dict_t) { m_pc.disconnect(errors::invalid_pex_message, op_bittorrent, 2); return true; } - lazy_entry const* p = pex_msg.dict_find_string("dropped"); + bdecode_node p = pex_msg.dict_find_string("dropped"); #ifdef TORRENT_LOGGING int num_dropped = 0; int num_added = 0; - if (p) num_dropped += p->string_length()/6; + if (p) num_dropped += p.string_length()/6; #endif if (p) { - int num_peers = p->string_length() / 6; - char const* in = p->string_ptr(); + int num_peers = p.string_length() / 6; + char const* in = p.string_ptr(); for (int i = 0; i < num_peers; ++i) { @@ -331,18 +331,16 @@ namespace libtorrent { namespace } p = pex_msg.dict_find_string("added"); - lazy_entry const* pf = pex_msg.dict_find_string("added.f"); + bdecode_node pf = pex_msg.dict_find_string("added.f"); #ifdef TORRENT_LOGGING - if (p) num_added += p->string_length() / 6; + if (p) num_added += p.string_length() / 6; #endif - if (p != 0 - && pf != 0 - && pf->string_length() == p->string_length() / 6) + if (p && pf && pf.string_length() == p.string_length() / 6) { - int num_peers = pf->string_length(); - char const* in = p->string_ptr(); - char const* fin = pf->string_ptr(); + int num_peers = pf.string_length(); + char const* in = p.string_ptr(); + char const* fin = pf.string_ptr(); for (int i = 0; i < num_peers; ++i) { @@ -366,14 +364,14 @@ namespace libtorrent { namespace #if TORRENT_USE_IPV6 - lazy_entry const* p6 = pex_msg.dict_find("dropped6"); + bdecode_node p6 = pex_msg.dict_find("dropped6"); #ifdef TORRENT_LOGGING - if (p6) num_dropped += p6->string_length() / 18; + if (p6) num_dropped += p6.string_length() / 18; #endif - if (p6 != 0 && p6->type() == lazy_entry::string_t) + if (p6 != 0 && p6.type() == bdecode_node::string_t) { - int num_peers = p6->string_length() / 18; - char const* in = p6->string_ptr(); + int num_peers = p6.string_length() / 18; + char const* in = p6.string_ptr(); for (int i = 0; i < num_peers; ++i) { @@ -386,18 +384,18 @@ namespace libtorrent { namespace p6 = pex_msg.dict_find("added6"); #ifdef TORRENT_LOGGING - if (p6) num_added += p6->string_length() / 18; + if (p6) num_added += p6.string_length() / 18; #endif - lazy_entry const* p6f = pex_msg.dict_find("added6.f"); + bdecode_node p6f = pex_msg.dict_find("added6.f"); if (p6 != 0 && p6f != 0 - && p6->type() == lazy_entry::string_t - && p6f->type() == lazy_entry::string_t - && p6f->string_length() == p6->string_length() / 18) + && p6.type() == bdecode_node::string_t + && p6f.type() == bdecode_node::string_t + && p6f.string_length() == p6.string_length() / 18) { - int num_peers = p6f->string_length(); - char const* in = p6->string_ptr(); - char const* fin = p6f->string_ptr(); + int num_peers = p6f.string_length(); + char const* in = p6.string_ptr(); + char const* fin = p6f.string_ptr(); for (int i = 0; i < num_peers; ++i) { @@ -500,21 +498,21 @@ namespace libtorrent { namespace m_pc.stats_counters().inc_stats_counter(counters::num_outgoing_pex); #ifdef TORRENT_LOGGING - lazy_entry m; + bdecode_node m; error_code ec; - int ret = lazy_bdecode(&pex_msg[0], &pex_msg[0] + pex_msg.size(), m, ec); + int ret = bdecode(&pex_msg[0], &pex_msg[0] + pex_msg.size(), m, ec); TORRENT_ASSERT(ret == 0); TORRENT_ASSERT(!ec); int num_dropped = 0; int num_added = 0; - lazy_entry const* e = m.dict_find_string("added"); - if (e) num_added += e->string_length() / 6; + bdecode_node e = m.dict_find_string("added"); + if (e) num_added += e.string_length() / 6; e = m.dict_find_string("dropped"); - if (e) num_dropped += e->string_length() / 6; + if (e) num_dropped += e.string_length() / 6; e = m.dict_find_string("added6"); - if (e) num_added += e->string_length() / 18; + if (e) num_added += e.string_length() / 18; e = m.dict_find_string("dropped6"); - if (e) num_dropped += e->string_length() / 18; + if (e) num_dropped += e.string_length() / 18; m_pc.peer_log("==> PEX_DIFF [ dropped: %d added: %d msg_size: %d ]" , num_dropped, num_added, int(pex_msg.size())); #endif diff --git a/test/Jamfile b/test/Jamfile index 1e2c188f9..62458f211 100644 --- a/test/Jamfile +++ b/test/Jamfile @@ -9,8 +9,12 @@ exe test_natpmp : test_natpmp.cpp /torrent//torrent exe enum_if : enum_if.cpp /torrent//torrent : multi on full ; +exe bdecode_benchmark : test_bdecode_performance.cpp /torrent//torrent + : release ; + explicit test_natpmp ; explicit enum_if ; +explicit bdecode_benchmark ; rule link_test ( properties * ) { @@ -117,6 +121,7 @@ test-suite libtorrent : [ run test_buffer.cpp ] [ run test_piece_picker.cpp ] [ run test_bencoding.cpp ] + [ run test_bdecode.cpp ] [ run test_fast_extension.cpp ] [ run test_primitives.cpp ] [ run test_http_parser.cpp ] @@ -149,7 +154,6 @@ test-suite libtorrent : [ run test_web_seed_http_pw.cpp ] [ run test_web_seed_chunked.cpp ] [ run test_web_seed_ban.cpp ] - [ run test_bdecode_performance.cpp ] [ run test_pe_crypto.cpp ] [ run test_dos_blocker.cpp ] diff --git a/test/setup_transfer.cpp b/test/setup_transfer.cpp index 1da7d61ee..c0718d0c1 100644 --- a/test/setup_transfer.cpp +++ b/test/setup_transfer.cpp @@ -602,7 +602,6 @@ void create_random_files(std::string const& path, const int file_sizes[], int nu boost::shared_ptr create_torrent(std::ostream* file, int piece_size , int num_pieces, bool add_tracker, std::string ssl_certificate) { - char const* tracker_url = "http://non-existent-name.com/announce"; // excercise the path when encountering invalid urls char const* invalid_tracker_url = "http:"; char const* invalid_tracker_protocol = "foo://non/existent-name.com/announce"; @@ -613,7 +612,6 @@ boost::shared_ptr create_torrent(std::ostream* file, int piece_siz libtorrent::create_torrent t(fs, piece_size); if (add_tracker) { - t.add_tracker(tracker_url); t.add_tracker(invalid_tracker_url); t.add_tracker(invalid_tracker_protocol); } diff --git a/test/test_bdecode.cpp b/test/test_bdecode.cpp new file mode 100644 index 000000000..d38e572db --- /dev/null +++ b/test/test_bdecode.cpp @@ -0,0 +1,1169 @@ +/* + +Copyright (c) 2015, 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 "test.hpp" +#include "libtorrent/bdecode.hpp" + +using namespace libtorrent; + +int test_main() +{ + // test integer + { + char b[] = "i12453e"; + bdecode_node e; + error_code ec; + int ret = bdecode(b, b + sizeof(b)-1, e, ec); + TEST_CHECK(ret == 0); + printf("%s\n", print_entry(e).c_str()); + std::pair section = e.data_section(); + TEST_CHECK(std::memcmp(b, section.first, section.second) == 0); + TEST_CHECK(section.second == sizeof(b) - 1); + TEST_CHECK(e.type() == bdecode_node::int_t); + TEST_CHECK(e.int_value() == 12453); + } + + // test string + { + char b[] = "26:abcdefghijklmnopqrstuvwxyz"; + bdecode_node e; + error_code ec; + int ret = bdecode(b, b + sizeof(b)-1, e, ec); + TEST_CHECK(ret == 0); + printf("%s\n", print_entry(e).c_str()); + std::pair section = e.data_section(); + TEST_CHECK(std::memcmp(b, section.first, section.second) == 0); + TEST_CHECK(section.second == sizeof(b) - 1); + TEST_CHECK(e.type() == bdecode_node::string_t); + TEST_CHECK(e.string_value() == std::string("abcdefghijklmnopqrstuvwxyz")); + TEST_CHECK(e.string_length() == 26); + } + + // test list + { + char b[] = "li12453e3:aaae"; + bdecode_node e; + error_code ec; + int ret = bdecode(b, b + sizeof(b)-1, e, ec); + TEST_CHECK(ret == 0); + printf("%s\n", print_entry(e).c_str()); + std::pair section = e.data_section(); + TEST_CHECK(std::memcmp(b, section.first, section.second) == 0); + TEST_CHECK(section.second == sizeof(b) - 1); + TEST_CHECK(e.type() == bdecode_node::list_t); + TEST_CHECK(e.list_size() == 2); + TEST_CHECK(e.list_at(0).type() == bdecode_node::int_t); + TEST_CHECK(e.list_at(1).type() == bdecode_node::string_t); + TEST_CHECK(e.list_at(0).int_value() == 12453); + TEST_CHECK(e.list_at(1).string_value() == std::string("aaa")); + TEST_CHECK(e.list_at(1).string_length() == 3); + section = e.list_at(1).data_section(); + TEST_CHECK(std::memcmp("3:aaa", section.first, section.second) == 0); + TEST_CHECK(section.second == 5); + } + + // test dict + { + char b[] = "d1:ai12453e1:b3:aaa1:c3:bbb1:X10:0123456789e"; + bdecode_node e; + error_code ec; + int ret = bdecode(b, b + sizeof(b)-1, e, ec); + TEST_EQUAL(ret, 0); + printf("%s\n", print_entry(e).c_str()); + std::pair section = e.data_section(); + TEST_CHECK(std::memcmp(b, section.first, section.second) == 0); + TEST_CHECK(section.second == sizeof(b) - 1); + TEST_CHECK(e.type() == bdecode_node::dict_t); + TEST_CHECK(e.dict_size() == 4); + TEST_CHECK(e.dict_find("a").type() == bdecode_node::int_t); + TEST_CHECK(e.dict_find("a").int_value() == 12453); + TEST_CHECK(e.dict_find("b").type() == bdecode_node::string_t); + TEST_CHECK(e.dict_find("b").string_value() == std::string("aaa")); + TEST_CHECK(e.dict_find("b").string_length() == 3); + TEST_CHECK(e.dict_find("c").type() == bdecode_node::string_t); + TEST_CHECK(e.dict_find("c").string_value() == std::string("bbb")); + TEST_CHECK(e.dict_find("c").string_length() == 3); + TEST_CHECK(e.dict_find_string_value("X") == "0123456789"); + } + + // test dictionary with a key without a value + { + char b[] = "d1:ai1e1:be"; + bdecode_node e; + error_code ec; + int pos; + int ret = bdecode(b, b + sizeof(b)-1, e, ec, &pos); + TEST_EQUAL(ret, -1); + TEST_EQUAL(pos, 10); + TEST_EQUAL(ec, error_code(bdecode_errors::expected_value)); + printf("%s\n", print_entry(e).c_str()); + } + + // test dictionary with a key that's not a string + { + char b[] = "di5e1:ae"; + bdecode_node e; + error_code ec; + int pos; + int ret = bdecode(b, b + sizeof(b)-1, e, ec, &pos); + TEST_EQUAL(ret, -1); + TEST_EQUAL(pos, 1); + TEST_EQUAL(ec, error_code(bdecode_errors::expected_digit)); + printf("%s\n", print_entry(e).c_str()); + } + + // dictionary key with \0 + { + char b[] = "d3:a\0bi1ee"; + bdecode_node e; + error_code ec; + int ret = bdecode(b, b + sizeof(b)-1, e, ec); + TEST_CHECK(ret == 0); + TEST_CHECK(e.dict_size() == 1); + bdecode_node d = e.dict_find(std::string("a\0b", 3)); + TEST_EQUAL(d.type(), bdecode_node::int_t); + TEST_EQUAL(d.int_value(), 1); + } + + // premature e + { + char b[] = "e"; + bdecode_node e; + error_code ec; + int ret = bdecode(b, b + sizeof(b)-1, e, ec); + TEST_EQUAL(ret, -1); + TEST_EQUAL(ec, error_code(bdecode_errors::unexpected_eof)); + printf("%s\n", print_entry(e).c_str()); + } + + // test strings with negative length-prefix + { + char b[] = "-10:foobar"; + bdecode_node e; + error_code ec; + int pos; + int ret = bdecode(b, b + sizeof(b)-1, e, ec, &pos); + TEST_EQUAL(ret, -1); + TEST_EQUAL(pos, 0); + TEST_EQUAL(ec, error_code(bdecode_errors::expected_value)); + printf("%s\n", print_entry(e).c_str()); + } + + // test strings with overflow length-prefix + { + char b[] = "18446744073709551615:foobar"; + bdecode_node e; + error_code ec; + int pos; + int ret = bdecode(b, b + sizeof(b)-1, e, ec, &pos); + TEST_EQUAL(ret, -1); + TEST_EQUAL(pos, 19); + TEST_EQUAL(ec, error_code(bdecode_errors::overflow)); + printf("%s\n", print_entry(e).c_str()); + } + + // test strings with almost overflow (more than 8 digits) + { + char b[] = "99999999:foobar"; + bdecode_node e; + error_code ec; + int pos; + int ret = bdecode(b, b + sizeof(b)-1, e, ec, &pos); + TEST_EQUAL(ret, -1); + TEST_EQUAL(pos, 8); + TEST_EQUAL(ec, error_code(bdecode_errors::unexpected_eof)); + printf("%s\n", print_entry(e).c_str()); + } + + // test strings with overflow (more than 8 digits) + { + char b[] = "199999999:foobar"; + bdecode_node e; + error_code ec; + int pos; + // pretend that we have a large buffer like that + int ret = bdecode(b, b + 999999999, e, ec, &pos); + TEST_EQUAL(ret, -1); + TEST_EQUAL(pos, 0); + TEST_EQUAL(ec, error_code(bdecode_errors::limit_exceeded)); + printf("%s\n", print_entry(e).c_str()); + } + + // test integer without any digits + { + char b[] = "ie"; + bdecode_node e; + error_code ec; + int pos; + int ret = bdecode(b, b + sizeof(b)-1, e, ec, &pos); + TEST_EQUAL(ret, -1); + TEST_EQUAL(pos, 1); + TEST_EQUAL(ec, error_code(bdecode_errors::expected_digit)); + printf("%s\n", print_entry(e).c_str()); + } + + // test integer with just a minus + { + char b[] = "i-e"; + bdecode_node e; + error_code ec; + int pos; + int ret = bdecode(b, b + sizeof(b)-1, e, ec, &pos); + TEST_EQUAL(ret, -1); + TEST_EQUAL(pos, 2); + TEST_EQUAL(ec, error_code(bdecode_errors::expected_digit)); + printf("%s\n", print_entry(e).c_str()); + } + + + // test integer with a minus inserted in it + { + char b[] = "i35412-5633e"; + bdecode_node e; + error_code ec; + int pos; + int ret = bdecode(b, b + sizeof(b)-1, e, ec, &pos); + TEST_EQUAL(ret, -1); + TEST_EQUAL(pos, 6); + TEST_EQUAL(ec, error_code(bdecode_errors::expected_digit)); + printf("%s\n", print_entry(e).c_str()); + } + + + // test integers that don't fit in 64 bits + { + char b[] = "i18446744073709551615e"; + bdecode_node e; + error_code ec; + int ret = bdecode(b, b + sizeof(b)-1, e, ec); + TEST_EQUAL(ret, 0); + printf("%s\n", print_entry(e).c_str()); + // the lazy aspect makes this overflow when asking for + // the value. turning it to zero. + TEST_EQUAL(e.int_value(), 0); + } + + // test integers with more than 20 digits (overflow on parsing) + { + char b[] = "i184467440737095516154e"; + bdecode_node e; + error_code ec; + int pos; + int ret = bdecode(b, b + sizeof(b)-1, e, ec, &pos); + TEST_EQUAL(ret, -1); + TEST_EQUAL(pos, 22); + TEST_EQUAL(ec, error_code(bdecode_errors::overflow)); + printf("%s\n", print_entry(e).c_str()); + } + + // test truncated negative integer + { + char b[] = "i-"; + bdecode_node e; + error_code ec; + int pos; + int ret = bdecode(b, b + sizeof(b)-1, e, ec, &pos); + TEST_EQUAL(ret, -1); + TEST_EQUAL(pos, 2); + TEST_EQUAL(ec, error_code(bdecode_errors::unexpected_eof)); + printf("%s\n", print_entry(e).c_str()); + } + + // test truncated negative integer + { + char b[] = "i-e"; + bdecode_node e; + error_code ec; + int pos; + int ret = bdecode(b, b + sizeof(b)-1, e, ec, &pos); + TEST_EQUAL(ret, -1); + TEST_EQUAL(pos, 2); + TEST_EQUAL(ec, error_code(bdecode_errors::expected_digit)); + printf("%s\n", print_entry(e).c_str()); + } + + // bdecode_error + { + error_code ec(bdecode_errors::overflow); + TEST_EQUAL(ec.message(), "integer overflow"); + TEST_EQUAL(ec.category().name(), std::string("bdecode error")); + ec.assign(5434, get_bdecode_category()); + TEST_EQUAL(ec.message(), "Unknown error"); + } + + // test integers that just exactly fit in 64 bits + { + char b[] = "i9223372036854775807e"; + bdecode_node e; + error_code ec; + int ret = bdecode(b, b + sizeof(b)-1, e, ec); + TEST_CHECK(ret == 0); + printf("%s\n", print_entry(e).c_str()); + TEST_CHECK(e.int_value() == 9223372036854775807LL); + } + + // test integers that just exactly fit in 64 bits + { + char b[] = "i-9223372036854775807e"; + bdecode_node e; + error_code ec; + int ret = bdecode(b, b + sizeof(b)-1, e, ec); + TEST_CHECK(ret == 0); + printf("%s\n", print_entry(e).c_str()); + TEST_CHECK(e.int_value() == -9223372036854775807LL); + } + + // test integers that have invalid digits + { + char b[] = "i92337203t854775807e"; + bdecode_node e; + error_code ec; + int pos = 0; + int ret = bdecode(b, b + sizeof(b)-1, e, ec, &pos); + TEST_EQUAL(ret, -1); + TEST_EQUAL(pos, 9); + TEST_EQUAL(ec, error_code(bdecode_errors::expected_digit)); + printf("%s\n", print_entry(e).c_str()); + } + + // test invalid encoding + { + unsigned char buf[] = + { 0x64 , 0x31 , 0x3a , 0x61 , 0x64 , 0x32 , 0x3a , 0x69 + , 0x64 , 0x32 , 0x30 , 0x3a , 0x2a , 0x21 , 0x19 , 0x89 + , 0x9f , 0xcd , 0x5f , 0xc9 , 0xbc , 0x80 , 0xc1 , 0x76 + , 0xfe , 0xe0 , 0xc6 , 0x84 , 0x2d , 0xf6 , 0xfc , 0xb8 + , 0x39 , 0x3a , 0x69 , 0x6e , 0x66 , 0x6f , 0x5f , 0x68 + , 0x61 , 0xae , 0x68 , 0x32 , 0x30 , 0x3a , 0x14 , 0x78 + , 0xd5 , 0xb0 , 0xdc , 0xf6 , 0x82 , 0x42 , 0x32 , 0xa0 + , 0xd6 , 0x88 , 0xeb , 0x48 , 0x57 , 0x01 , 0x89 , 0x40 + , 0x4e , 0xbc , 0x65 , 0x31 , 0x3a , 0x71 , 0x39 , 0x3a + , 0x67 , 0x65 , 0x74 , 0x5f , 0x70 , 0x65 , 0x65 , 0x72 + , 0x78 , 0xff , 0x3a , 0x74 , 0x38 , 0x3a , 0xaa , 0xd4 + , 0xa1 , 0x88 , 0x7a , 0x8d , 0xc3 , 0xd6 , 0x31 , 0x3a + , 0x79 , 0x31 , 0xae , 0x71 , 0x65 , 0}; + + printf("%s\n", buf); + bdecode_node e; + error_code ec; + int ret = bdecode((char*)buf, (char*)buf + sizeof(buf), e, ec); + TEST_CHECK(ret == -1); + } + + // test the depth limit + { + char b[2048]; + for (int i = 0; i < 1024; ++i) + b[i]= 'l'; + + for (int i = 1024; i < 2048; ++i) + b[i]= 'e'; + + // 1024 levels nested lists + + bdecode_node e; + error_code ec; + int ret = bdecode(b, b + sizeof(b), e, ec, NULL, 100); + TEST_CHECK(ret != 0); + TEST_EQUAL(ec, error_code(bdecode_errors::depth_exceeded + , get_bdecode_category())); + } + + // test the item limit + { + char b[10240]; + b[0] = 'l'; + int i = 1; + for (i = 1; i < 10239; i += 2) + memcpy(&b[i], "0:", 2); + b[i] = 'e'; + + bdecode_node e; + error_code ec; + int ret = bdecode(b, b + i + 1, e, ec, NULL, 1000, 1000); + TEST_CHECK(ret != 0); + TEST_EQUAL(ec, error_code(bdecode_errors::limit_exceeded + , get_bdecode_category())); + } + + // test unexpected EOF + { + char b[] = "l2:.."; // expected terminating 'e' + + bdecode_node e; + error_code ec; + int pos; + int ret = bdecode(b, b + sizeof(b)-1, e, ec, &pos); + TEST_EQUAL(ret, -1); + TEST_EQUAL(pos, 5); + TEST_EQUAL(ec, error_code(bdecode_errors::unexpected_eof)); + printf("%s\n", print_entry(e).c_str()); + } + + // test unexpected EOF (really expected terminator) + { + char b[] = "l2:..0"; // expected terminating 'e' instead of '0' + + bdecode_node e; + error_code ec; + int pos; + int ret = bdecode(b, b + sizeof(b)-1, e, ec, &pos); + TEST_EQUAL(ret, -1); + TEST_EQUAL(pos, 6); + TEST_EQUAL(ec, error_code(bdecode_errors::expected_colon)); + printf("%s\n", print_entry(e).c_str()); + } + + // test expected string + { + char b[] = "di2ei0ee"; + // expected string (dict keys must be strings) + + bdecode_node e; + error_code ec; + int pos; + int ret = bdecode(b, b + sizeof(b)-1, e, ec, &pos); + TEST_EQUAL(ret, -1); + TEST_EQUAL(pos, 1); + TEST_EQUAL(ec, error_code(bdecode_errors::expected_digit)); + printf("%s\n", print_entry(e).c_str()); + } + + // test unexpected EOF while parsing dict key + { + char b[] = "d1000:..e"; + + bdecode_node e; + error_code ec; + int pos; + int ret = bdecode(b, b + sizeof(b)-1, e, ec, &pos); + TEST_EQUAL(ret, -1); + TEST_EQUAL(pos, 5); + TEST_EQUAL(ec, error_code(bdecode_errors::unexpected_eof)); + printf("%s\n", print_entry(e).c_str()); + } + + // test unexpected EOF while parsing dict key + { + char b[] = "d1000:"; + + bdecode_node e; + error_code ec; + int pos; + int ret = bdecode(b, b + sizeof(b)-1, e, ec, &pos); + TEST_EQUAL(ret, -1); + TEST_EQUAL(pos, 5); + TEST_EQUAL(ec, error_code(bdecode_errors::unexpected_eof)); + printf("%s\n", print_entry(e).c_str()); + } + + // test expected string while parsing dict key + { + char b[] = "df00:"; + + bdecode_node e; + error_code ec; + int pos; + int ret = bdecode(b, b + sizeof(b)-1, e, ec, &pos); + TEST_EQUAL(ret, -1); + TEST_EQUAL(pos, 1); + TEST_EQUAL(ec, error_code(bdecode_errors::expected_digit)); + printf("%s\n", print_entry(e).c_str()); + } + + // test unexpected EOF while parsing int + { + char b[] = "i"; + + bdecode_node e; + error_code ec; + int pos; + int ret = bdecode(b, b + sizeof(b)-1, e, ec, &pos); + TEST_EQUAL(ret, -1); + TEST_EQUAL(pos, 1); + TEST_EQUAL(ec, error_code(bdecode_errors::unexpected_eof)); + printf("%s\n", print_entry(e).c_str()); + } + + // test unexpected EOF while parsing int + { + char b[] = "i10"; + + bdecode_node e; + error_code ec; + int pos; + int ret = bdecode(b, b + sizeof(b)-1, e, ec, &pos); + TEST_EQUAL(ret, -1); + TEST_EQUAL(pos, 3); + TEST_EQUAL(ec, error_code(bdecode_errors::unexpected_eof)); + printf("%s\n", print_entry(e).c_str()); + } + + + // test expected colon + { + char b[] = "d1000"; + + bdecode_node e; + error_code ec; + int pos; + int ret = bdecode(b, b + sizeof(b)-1, e, ec, &pos); + TEST_EQUAL(ret, -1); + TEST_EQUAL(pos, 5); + TEST_EQUAL(ec, error_code(bdecode_errors::expected_colon)); + printf("%s\n", print_entry(e).c_str()); + } + + // test empty string + { + char b[] = ""; + + bdecode_node e; + error_code ec; + int ret = bdecode(b, b + sizeof(b)-1, e, ec, NULL); + TEST_EQUAL(ret, 0); + printf("%s\n", print_entry(e).c_str()); + } + + // test partial string + { + char b[] = "100:.."; + + bdecode_node e; + error_code ec; + int pos; + int ret = bdecode(b, b + sizeof(b)-1, e, ec, &pos); + TEST_EQUAL(ret, -1); + TEST_EQUAL(pos, 3); + TEST_EQUAL(ec, error_code(bdecode_errors::unexpected_eof)); + printf("%s\n", print_entry(e).c_str()); + } + + { + std::string buf; + buf += "l"; + for (int i = 0; i < 1000; ++i) + { + char tmp[20]; + snprintf(tmp, sizeof(tmp), "i%de", i); + buf += tmp; + } + buf += "e"; + + bdecode_node e; + error_code ec; + int ret = bdecode((char*)&buf[0], (char*)&buf[0] + buf.size(), e, ec); + TEST_EQUAL(ret, 0); + TEST_EQUAL(e.type(), bdecode_node::list_t); + TEST_EQUAL(e.list_size(), 1000); + for (int i = 0; i < 1000; ++i) + { + TEST_EQUAL(e.list_int_value_at(i), i); + } + } + + { + std::string buf; + buf += "d"; + for (int i = 0; i < 1000; ++i) + { + char tmp[30]; + snprintf(tmp, sizeof(tmp), "4:%04di%de", i, i); + buf += tmp; + } + buf += "e"; + + printf("%s\n", buf.c_str()); + bdecode_node e; + error_code ec; + int ret = bdecode((char*)&buf[0], (char*)&buf[0] + buf.size(), e, ec); + TEST_EQUAL(ret, 0); + TEST_EQUAL(e.type(), bdecode_node::dict_t); + TEST_EQUAL(e.dict_size(), 1000); + for (int i = 0; i < 1000; ++i) + { + char tmp[30]; + snprintf(tmp, sizeof(tmp), "%04d", i); + TEST_EQUAL(e.dict_find_int_value(tmp), i); + } + } + + // test dict_at + { + char b[] = "d3:fooi1e3:bari2ee"; + + bdecode_node e; + error_code ec; + int ret = bdecode(b, b + sizeof(b)-1, e, ec); + TEST_EQUAL(ret, 0); + + TEST_EQUAL(e.type(), bdecode_node::dict_t); + TEST_EQUAL(e.dict_size(), 2); + TEST_EQUAL(e.dict_at(0).first, "foo"); + TEST_EQUAL(e.dict_at(0).second.type(), bdecode_node::int_t); + TEST_EQUAL(e.dict_at(0).second.int_value(), 1); + TEST_EQUAL(e.dict_at(1).first, "bar"); + TEST_EQUAL(e.dict_at(1).second.type(), bdecode_node::int_t); + TEST_EQUAL(e.dict_at(1).second.int_value(), 2); + } + + // test string_ptr + { + char b[] = "l3:fooe"; + + bdecode_node e; + error_code ec; + int ret = bdecode(b, b + sizeof(b)-1, e, ec); + TEST_EQUAL(ret, 0); + + TEST_EQUAL(e.type(), bdecode_node::list_t); + TEST_EQUAL(e.list_size(), 1); + TEST_EQUAL(e.list_at(0).type(), bdecode_node::string_t); + TEST_EQUAL(e.list_at(0).string_ptr(), b + 3); + TEST_EQUAL(e.list_at(0).string_length(), 3); + } + + // test exceeding buffer size limit + { + char b[] = "l3:fooe"; + + bdecode_node e; + error_code ec; + int ret = bdecode(b, b + 0x3fffffff, e, ec); + TEST_EQUAL(ret, -1); + TEST_EQUAL(ec, error_code(bdecode_errors::limit_exceeded)); + printf("%s\n", print_entry(e).c_str()); + } + + // test parse_int + { + char b[] = "1234567890e"; + boost::int64_t val = 0; + bdecode_errors::error_code_enum ec; + char const* e = parse_int(b, b + sizeof(b)-1, 'e', val, ec); + TEST_EQUAL(val, 1234567890); + TEST_EQUAL(e, b + sizeof(b) - 2); + } + + // test invalid digit + { + char b[] = "0o"; + boost::int64_t val = 0; + bdecode_errors::error_code_enum ec; + char const* e = parse_int(b, b + sizeof(b)-1, 'e', val, ec); + TEST_EQUAL(ec, bdecode_errors::expected_digit); + TEST_EQUAL(e, b + 1); + } + + // test parse_int overflow + { + char b[] = "9223372036854775808:"; + boost::int64_t val = 0; + bdecode_errors::error_code_enum ec; + char const* e = parse_int(b, b + sizeof(b)-1, ':', val, ec); + TEST_EQUAL(ec, bdecode_errors::overflow); + TEST_EQUAL(e, b + 18); + } + + { + char b[] = "928"; + boost::int64_t val = 0; + bdecode_errors::error_code_enum ec; + char const* e = parse_int(b, b + sizeof(b)-1, ':', val, ec); + TEST_EQUAL(ec, bdecode_errors::expected_colon); + TEST_EQUAL(e, b + 3); + } + + // test dict_find_* functions + { + // a: int + // b: string + // c: list + // d: dict + char b[] = "d1:ai1e1:b3:foo1:cli1ei2ee1:dd1:xi1eee"; + bdecode_node e; + error_code ec; + int ret = bdecode(b, b + sizeof(b)-1, e, ec); + TEST_EQUAL(ret, 0); + printf("%s\n", print_entry(e).c_str()); + + TEST_EQUAL(e.type(), bdecode_node::dict_t); + + // dict_find_int* + + TEST_EQUAL(e.dict_find_int_value("a"), 1); + TEST_EQUAL(e.dict_find_int("a").type(), bdecode_node::int_t); + TEST_EQUAL(e.dict_find_int_value("b", -10), -10); + TEST_EQUAL(e.dict_find_int_value("x", -10), -10); + TEST_EQUAL(e.dict_find_int("b").type(), bdecode_node::none_t); + TEST_EQUAL(e.dict_find_int("x").type(), bdecode_node::none_t); + + // dict_find_string* + + TEST_EQUAL(e.dict_find_string_value("b"), "foo"); + TEST_EQUAL(e.dict_find_string("b").type(), bdecode_node::string_t); + TEST_EQUAL(e.dict_find_string_value("c", "blah"), "blah"); + TEST_EQUAL(e.dict_find_string_value("x", "blah"), "blah"); + TEST_EQUAL(e.dict_find_string("c").type(), bdecode_node::none_t); + TEST_EQUAL(e.dict_find_string("x").type(), bdecode_node::none_t); + + // dict_find_list + + TEST_CHECK(e.dict_find_list("c")); + TEST_EQUAL(e.dict_find_list("c").list_size(), 2); + TEST_EQUAL(e.dict_find_list("c").list_int_value_at(0), 1); + TEST_EQUAL(e.dict_find_list("c").list_int_value_at(1), 2); + TEST_CHECK(!e.dict_find_list("d")); + + // dict_find_dict + + TEST_CHECK(e.dict_find_dict("d")); + TEST_EQUAL(e.dict_find_dict("d").dict_find_int_value("x"), 1); + TEST_EQUAL(e.dict_find_dict("d").dict_find_int_value("y", -10), -10); + TEST_CHECK(!e.dict_find_dict("c")); + + // variants taking std::string + TEST_EQUAL(e.dict_find_dict(std::string("d")).dict_find_int_value("x"), 1); + TEST_CHECK(!e.dict_find_dict(std::string("c"))); + TEST_CHECK(!e.dict_find_dict(std::string("x"))); + + TEST_EQUAL(e.dict_size(), 4); + TEST_EQUAL(e.dict_size(), 4); + + // dict_at + + TEST_EQUAL(e.dict_at(0).first, "a"); + TEST_EQUAL(e.dict_at(0).second.int_value(), 1); + TEST_EQUAL(e.dict_at(1).first, "b"); + TEST_EQUAL(e.dict_at(1).second.string_value(), "foo"); + TEST_EQUAL(e.dict_at(2).first, "c"); + TEST_EQUAL(e.dict_at(2).second.type(), bdecode_node::list_t); + TEST_EQUAL(e.dict_at(3).first, "d"); + TEST_EQUAL(e.dict_at(3).second.type(), bdecode_node::dict_t); + } + + // test list_*_at functions + { + // int + // string + // list + // dict + char b[] = "li1e3:fooli1ei2eed1:xi1eee"; + bdecode_node e; + error_code ec; + int ret = bdecode(b, b + sizeof(b)-1, e, ec); + TEST_EQUAL(ret, 0); + printf("%s\n", print_entry(e).c_str()); + + TEST_EQUAL(e.type(), bdecode_node::list_t); + + TEST_EQUAL(e.list_int_value_at(0), 1); + // make sure default values work + TEST_EQUAL(e.list_int_value_at(1, -10), -10); + + TEST_EQUAL(e.list_string_value_at(1), "foo"); + // make sure default values work + TEST_EQUAL(e.list_string_value_at(2, "blah"), "blah"); + + TEST_EQUAL(e.list_at(2).type(), bdecode_node::list_t); + TEST_EQUAL(e.list_at(2).list_size(), 2); + TEST_EQUAL(e.list_at(2).list_int_value_at(0), 1); + TEST_EQUAL(e.list_at(2).list_int_value_at(1), 2); + + TEST_EQUAL(e.list_at(3).type(), bdecode_node::dict_t); + TEST_EQUAL(e.list_at(3).dict_size(), 1); + TEST_EQUAL(e.list_at(3).dict_find_int_value("x"), 1); + TEST_EQUAL(e.list_at(3).dict_find_int_value("y", -10), -10); + + TEST_EQUAL(e.list_size(), 4); + TEST_EQUAL(e.list_size(), 4); + } + + // test list_at in reverse order + { + // int + // string + // list + // dict + char b[] = "li1e3:fooli1ei2eed1:xi1eee"; + bdecode_node e; + error_code ec; + int ret = bdecode(b, b + sizeof(b)-1, e, ec); + TEST_EQUAL(ret, 0); + printf("%s\n", print_entry(e).c_str()); + + TEST_EQUAL(e.type(), bdecode_node::list_t); + + TEST_EQUAL(e.list_at(3).type(), bdecode_node::dict_t); + TEST_EQUAL(e.list_at(2).type(), bdecode_node::list_t); + TEST_EQUAL(e.list_string_value_at(1), "foo"); + TEST_EQUAL(e.list_int_value_at(0), 1); + + TEST_EQUAL(e.list_size(), 4); + TEST_EQUAL(e.list_size(), 4); + } + + + // test dict_find_* functions + { + // a: int + // b: string + // c: list + // d: dict + char b[] = "d1:ai1e1:b3:foo1:cli1ei2ee1:dd1:xi1eee"; + bdecode_node e; + error_code ec; + int ret = bdecode(b, b + sizeof(b)-1, e, ec); + TEST_EQUAL(ret, 0); + printf("%s\n", print_entry(e).c_str()); + + TEST_EQUAL(e.type(), bdecode_node::dict_t); + + // try finding the last item in a dict (to skip all the other ones) + TEST_EQUAL(e.dict_find("d").type(), bdecode_node::dict_t); + TEST_EQUAL(e.dict_find(std::string("d")).type(), bdecode_node::dict_t); + } + + // print_entry + + { + char b[] = "li1e3:fooli1ei2eed1:xi1eee"; + bdecode_node e; + error_code ec; + int ret = bdecode(b, b + sizeof(b)-1, e, ec); + TEST_EQUAL(ret, 0); + printf("%s\n", print_entry(e).c_str()); + + TEST_EQUAL(print_entry(e), "[ 1, 'foo', [ 1, 2 ], { 'x': 1 } ]"); + } + + { + char b[] = "d1:ai1e1:b3:foo1:cli1ei2ee1:dd1:xi1eee"; + bdecode_node e; + error_code ec; + int ret = bdecode(b, b + sizeof(b)-1, e, ec); + TEST_EQUAL(ret, 0); + printf("%s\n", print_entry(e).c_str()); + + TEST_EQUAL(print_entry(e), "{ 'a': 1, 'b': 'foo', 'c': [ 1, 2 ], 'd': { 'x': 1 } }"); + } + + // test swap() + { + char b1[] = "d1:ai1e1:b3:foo1:cli1ei2ee1:dd1:xi1eee"; + char b2[] = "i1e"; + + bdecode_node e1; + bdecode_node e2; + + error_code ec; + + int ret = bdecode(b1, b1 + sizeof(b1)-1, e1, ec); + TEST_EQUAL(ret, 0); + ret = bdecode(b2, b2 + sizeof(b2)-1, e2, ec); + TEST_EQUAL(ret, 0); + + std::string str1 = print_entry(e1); + std::string str2 = print_entry(e2); + TEST_EQUAL(e1.type(), bdecode_node::dict_t); + TEST_EQUAL(e2.type(), bdecode_node::int_t); + printf("%s\n", print_entry(e1).c_str()); + + e1.swap(e2); + + TEST_EQUAL(e1.type(), bdecode_node::int_t); + TEST_EQUAL(e2.type(), bdecode_node::dict_t); + TEST_EQUAL(print_entry(e1), str2); + TEST_EQUAL(print_entry(e2), str1); + printf("%s\n", print_entry(e1).c_str()); + + e1.swap(e2); + + TEST_EQUAL(e1.type(), bdecode_node::dict_t); + TEST_EQUAL(e2.type(), bdecode_node::int_t); + TEST_EQUAL(print_entry(e1), str1); + TEST_EQUAL(print_entry(e2), str2); + printf("%s\n", print_entry(e1).c_str()); + } + + // test swap() (one node is the root of the other node) + { + char b1[] = "d1:ai1e1:b3:foo1:cli1ei2ee1:dd1:xi1eee"; + + bdecode_node e1; + bdecode_node e2; + + error_code ec; + + int ret = bdecode(b1, b1 + sizeof(b1)-1, e1, ec); + TEST_EQUAL(ret, 0); + + e2 = e1.dict_find("c").list_at(0); + + std::string str1 = print_entry(e1); + std::string str2 = print_entry(e2); + TEST_EQUAL(e1.type(), bdecode_node::dict_t); + TEST_EQUAL(e2.type(), bdecode_node::int_t); + printf("%s\n", print_entry(e1).c_str()); + + e1.swap(e2); + + TEST_EQUAL(e1.type(), bdecode_node::int_t); + TEST_EQUAL(e2.type(), bdecode_node::dict_t); + TEST_EQUAL(print_entry(e1), str2); + TEST_EQUAL(print_entry(e2), str1); + printf("%s\n", print_entry(e1).c_str()); + + // swap back + e1.swap(e2); + + TEST_EQUAL(e1.type(), bdecode_node::dict_t); + TEST_EQUAL(e2.type(), bdecode_node::int_t); + TEST_EQUAL(print_entry(e1), str1); + TEST_EQUAL(print_entry(e2), str2); + printf("%s\n", print_entry(e1).c_str()); + } + + // test swap() (neither is a root and they don't share a root) + { + char b1[] = "d1:ai1e1:b3:foo1:cli1ei2ee1:dd1:xi1eee"; + char b2[] = "li1e3:fooli1ei2eed1:xi1eee"; + + bdecode_node e1_root; + bdecode_node e2_root; + + error_code ec; + + int ret = bdecode(b1, b1 + sizeof(b1)-1, e1_root, ec); + TEST_EQUAL(ret, 0); + ret = bdecode(b2, b2 + sizeof(b2)-1, e2_root, ec); + TEST_EQUAL(ret, 0); + + bdecode_node e1 = e1_root.dict_find("c").list_at(0); + bdecode_node e2 = e2_root.list_at(1); + + std::string str1 = print_entry(e1); + std::string str2 = print_entry(e2); + TEST_EQUAL(e1.type(), bdecode_node::int_t); + TEST_EQUAL(e2.type(), bdecode_node::string_t); + + e1.swap(e2); + + TEST_EQUAL(e1.type(), bdecode_node::string_t); + TEST_EQUAL(e2.type(), bdecode_node::int_t); + TEST_EQUAL(print_entry(e1), str2); + TEST_EQUAL(print_entry(e2), str1); + + // swap back + e1.swap(e2); + + TEST_EQUAL(e1.type(), bdecode_node::int_t); + TEST_EQUAL(e2.type(), bdecode_node::string_t); + TEST_EQUAL(print_entry(e1), str1); + TEST_EQUAL(print_entry(e2), str2); + } + + // test swap() (one is a root and they don't share a root) + { + char b1[] = "d1:ai1e1:b3:foo1:cli1ei2ee1:dd1:xi1eee"; + char b2[] = "li1e3:fooli1ei2eed1:xi1eee"; + + bdecode_node e1_root; + bdecode_node e2; + + error_code ec; + + int ret = bdecode(b1, b1 + sizeof(b1)-1, e1_root, ec); + TEST_EQUAL(ret, 0); + ret = bdecode(b2, b2 + sizeof(b2)-1, e2, ec); + TEST_EQUAL(ret, 0); + + bdecode_node e1 = e1_root.dict_find("d"); + + std::string str1 = print_entry(e1); + std::string str2 = print_entry(e2); + TEST_EQUAL(e1.type(), bdecode_node::dict_t); + TEST_EQUAL(e2.type(), bdecode_node::list_t); + + e1.swap(e2); + + TEST_EQUAL(e1.type(), bdecode_node::list_t); + TEST_EQUAL(e2.type(), bdecode_node::dict_t); + TEST_EQUAL(print_entry(e1), str2); + TEST_EQUAL(print_entry(e2), str1); + + // swap back + e1.swap(e2); + + TEST_EQUAL(e1.type(), bdecode_node::dict_t); + TEST_EQUAL(e2.type(), bdecode_node::list_t); + TEST_EQUAL(print_entry(e1), str1); + TEST_EQUAL(print_entry(e2), str2); + } + + // make sure it's safe to reuse bdecode_nodes after clear() is called + { + char b1[] = "d1:ai1e1:b3:foo1:cli1ei2ee1:dd1:xi1eee"; + char b2[] = "li1ei2ee"; + + bdecode_node e; + error_code ec; + int ret = bdecode(b1, b1 + sizeof(b1)-1, e, ec); + printf("%s\n", print_entry(e).c_str()); + TEST_EQUAL(ret, 0); + TEST_EQUAL(e.type(), bdecode_node::dict_t); + TEST_EQUAL(e.dict_size(), 4); + TEST_EQUAL(e.dict_at(1).first, "b"); + + ret = bdecode(b2, b2 + sizeof(b2)-1, e, ec); + printf("%s\n", print_entry(e).c_str()); + TEST_EQUAL(ret, 0); + TEST_EQUAL(e.type(), bdecode_node::list_t); + TEST_EQUAL(e.list_size(), 2); + TEST_EQUAL(e.list_int_value_at(1), 2); + } + + // assignment/copy of root nodes + { + char b1[] = "d1:ai1e1:b3:foo1:cli1ei2ee1:dd1:xi1eee"; + + bdecode_node e1; + error_code ec; + int ret = bdecode(b1, b1 + sizeof(b1)-1, e1, ec); + TEST_EQUAL(ret, 0); + TEST_EQUAL(e1.type(), bdecode_node::dict_t); + printf("%s\n", print_entry(e1).c_str()); + + bdecode_node e2(e1); + bdecode_node e3; + e3 = e1; + + e1.clear(); + + TEST_EQUAL(e2.type(), bdecode_node::dict_t); + TEST_EQUAL(e2.dict_size(), 4); + TEST_EQUAL(e2.dict_at(1).first, "b"); + + TEST_EQUAL(e3.type(), bdecode_node::dict_t); + TEST_EQUAL(e3.dict_size(), 4); + TEST_EQUAL(e3.dict_at(1).first, "b"); + } + + // non-owning references + { + char b1[] = "d1:ai1e1:b3:foo1:cli1ei2ee1:dd1:xi1eee"; + + bdecode_node e1; + error_code ec; + int ret = bdecode(b1, b1 + sizeof(b1)-1, e1, ec); + + TEST_EQUAL(ret, 0); + TEST_EQUAL(e1.type(), bdecode_node::dict_t); + printf("%s\n", print_entry(e1).c_str()); + + bdecode_node e2 = e1.non_owning(); + + TEST_EQUAL(e2.type(), bdecode_node::dict_t); + + e1.clear(); + + // e2 is invalid now + } + + // test that a partial parse can be still be printed up to the + // point where it faild + { + char b[] = "d1:ai1e1:b3:foo1:cli1ei2ee1:dd1:xi1-eee"; + + bdecode_node e; + error_code ec; + int pos; + int ret = bdecode(b, b + sizeof(b)-1, e, ec, &pos); + TEST_EQUAL(ret, -1); + TEST_EQUAL(pos, 35); + TEST_EQUAL(e.type(), bdecode_node::dict_t); + + printf("%s\n", print_entry(e).c_str()); + + TEST_EQUAL(print_entry(e), "{ 'a': 1, 'b': 'foo', 'c': [ 1, 2 ], 'd': { 'x': {} } }"); + } + { + char b[] = "d1:ai1e1:b3:foo1:cli1ei2ee1:d-d1:xi1eee"; + + bdecode_node e; + error_code ec; + int pos; + int ret = bdecode(b, b + sizeof(b)-1, e, ec, &pos); + TEST_EQUAL(ret, -1); + TEST_EQUAL(pos, 29); + TEST_EQUAL(e.type(), bdecode_node::dict_t); + + printf("%s\n", print_entry(e).c_str()); + + TEST_EQUAL(print_entry(e), "{ 'a': 1, 'b': 'foo', 'c': [ 1, 2 ], 'd': {} }"); + } + { + char b[] = "d1:ai1e1:b3:foo1:cli1ei2ee-1:dd1:xi1eee"; + + bdecode_node e; + error_code ec; + int pos; + int ret = bdecode(b, b + sizeof(b)-1, e, ec, &pos); + TEST_EQUAL(ret, -1); + TEST_EQUAL(pos, 26); + TEST_EQUAL(e.type(), bdecode_node::dict_t); + + printf("%s\n", print_entry(e).c_str()); + + TEST_EQUAL(print_entry(e), "{ 'a': 1, 'b': 'foo', 'c': [ 1, 2 ] }"); + } + { + char b[] = "d1:ai1e1:b3:foo1:cli1e-i2ee1:dd1:xi1eee"; + + bdecode_node e; + error_code ec; + int pos; + int ret = bdecode(b, b + sizeof(b)-1, e, ec, &pos); + TEST_EQUAL(ret, -1); + TEST_EQUAL(pos, 22); + TEST_EQUAL(e.type(), bdecode_node::dict_t); + + printf("%s\n", print_entry(e).c_str()); + + TEST_EQUAL(print_entry(e), "{ 'a': 1, 'b': 'foo', 'c': [ 1 ] }"); + } + + // TODO: test switch_underlying_buffer + + return 0; +} + diff --git a/test/test_bdecode_performance.cpp b/test/test_bdecode_performance.cpp index 1d18042ab..a15f61889 100644 --- a/test/test_bdecode_performance.cpp +++ b/test/test_bdecode_performance.cpp @@ -31,6 +31,9 @@ POSSIBILITY OF SUCH DAMAGE. */ #include "libtorrent/lazy_entry.hpp" +#include "libtorrent/bdecode.hpp" +#include "libtorrent/bencode.hpp" +#include "libtorrent/sha1_hash.hpp" #include #include @@ -39,22 +42,143 @@ POSSIBILITY OF SUCH DAMAGE. using namespace libtorrent; -int test_main() +int load_file(std::string const& filename, std::vector& v + , libtorrent::error_code& ec, int limit = 8000000) { - using namespace libtorrent; - - time_point start(clock_type::now()); - - for (int i = 0; i < 100000; ++i) + ec.clear(); + FILE* f = fopen(filename.c_str(), "rb"); + if (f == NULL) { - char b[] = "d1:ai12453e1:b3:aaa1:c3:bbbe"; - lazy_entry e; - error_code ec; - lazy_bdecode(b, b + sizeof(b)-1, e, ec); + ec.assign(errno, boost::system::generic_category()); + return -1; + } + + int r = fseek(f, 0, SEEK_END); + if (r != 0) + { + ec.assign(errno, boost::system::generic_category()); + fclose(f); + return -1; + } + long s = ftell(f); + if (s < 0) + { + ec.assign(errno, boost::system::generic_category()); + fclose(f); + return -1; + } + + if (s > limit) + { + fclose(f); + return -2; + } + + r = fseek(f, 0, SEEK_SET); + if (r != 0) + { + ec.assign(errno, boost::system::generic_category()); + fclose(f); + return -1; + } + + v.resize(s); + if (s == 0) + { + fclose(f); + return 0; + } + + r = fread(&v[0], 1, v.size(), f); + if (r < 0) + { + ec.assign(errno, boost::system::generic_category()); + fclose(f); + return -1; + } + + fclose(f); + + if (r != s) return -3; + + return 0; +} + +int main(int argc, char* argv[]) +{ + using namespace libtorrent; + + if (argc != 2) + { + fputs("usage: bdecode_benchmark torrent-file\n", stderr); + return 1; + } + + std::vector buf; + error_code ec; + int ret = load_file(argv[1], buf, ec, 40 * 1000000); + if (ret == -1) + { + fprintf(stderr, "file too big, aborting\n"); + return 1; + } + + if (ret != 0) + { + fprintf(stderr, "failed to load file: %s\n", ec.message().c_str()); + return 1; + } + + { + time_point start(clock_type::now()); + entry e; + for (int i = 0; i < 1000000; ++i) + { + int len; + e = bdecode(&buf[0], &buf[0] + buf.size(), len); +// entry& info = e["info"]; + } + ptime stop(time_now_hires()); + + fprintf(stderr, "(slow) bdecode done in %5d ns per message\n" + , int(total_microseconds(stop - start) / 1000)); + } + + // =============================================== + + { + ptime start(time_now_hires()); + lazy_entry e; + for (int i = 0; i < 1000000; ++i) + { + error_code ec; + lazy_bdecode(&buf[0], &buf[0] + buf.size(), e, ec); +// lazy_entry* info = e.dict_find("info"); + } + time_point stop(clock_type::now()); + + fprintf(stderr, "lazy_bdecode done in %5d ns per message\n" + , int(total_microseconds(stop - start) / 1000)); + } + + // =============================================== + + { + ptime start(time_now_hires()); + bdecode_node e; + e.reserve(100); + for (int i = 0; i < 1000000; ++i) + { + error_code ec; + bdecode(&buf[0], &buf[0] + buf.size(), e, ec); +// bdecode_node info = e.dict_find("info"); + } + ptime stop(time_now_hires()); + + fprintf(stderr, "bdecode done in %5d ns per message\n" + , int(total_microseconds(stop - start) / 1000)); } - time_point stop(clock_type::now()); - std::cout << "done in " << total_milliseconds(stop - start) / 100. << " seconds per million message" << std::endl; return 0; } diff --git a/test/test_bencoding.cpp b/test/test_bencoding.cpp index f15b3d0e6..cfabb3ccb 100644 --- a/test/test_bencoding.cpp +++ b/test/test_bencoding.cpp @@ -31,11 +31,14 @@ POSSIBILITY OF SUCH DAMAGE. */ #include "libtorrent/bencode.hpp" -#include "libtorrent/lazy_entry.hpp" #include #include #include +#ifndef TORRENT_NO_DEPRECATE +#include "libtorrent/lazy_entry.hpp" +#endif + #include "test.hpp" using namespace libtorrent; @@ -57,8 +60,6 @@ entry decode(std::string const& str) int test_main() { - using namespace libtorrent; - // ** strings ** { entry e("spam"); @@ -104,6 +105,7 @@ int test_main() TEST_CHECK(decode(encode(e)) == e); } +#ifndef TORRENT_NO_DEPRECATE { char b[] = "i12453e"; lazy_entry e; @@ -347,7 +349,7 @@ int test_main() int ret = lazy_bdecode(b, b + sizeof(b)-1, e, ec, NULL); TEST_CHECK(ret != 0); printf("%s\n", print_entry(e).c_str()); - TEST_EQUAL(ec, error_code(bdecode_errors::expected_string + TEST_EQUAL(ec, error_code(bdecode_errors::expected_digit , get_bdecode_category())); } @@ -386,7 +388,7 @@ int test_main() int ret = lazy_bdecode(b, b + sizeof(b)-1, e, ec, NULL); TEST_CHECK(ret != 0); printf("%s\n", print_entry(e).c_str()); - TEST_EQUAL(ec, error_code(bdecode_errors::expected_string + TEST_EQUAL(ec, error_code(bdecode_errors::expected_digit , get_bdecode_category())); } @@ -564,7 +566,7 @@ int test_main() boost::int64_t val = 0; bdecode_errors::error_code_enum ec; char const* e = parse_int(b, b + sizeof(b)-1, 'e', val, ec); - TEST_EQUAL(ec, bdecode_errors::expected_string); + TEST_EQUAL(ec, bdecode_errors::expected_digit); TEST_EQUAL(e, b + 1); } @@ -583,6 +585,7 @@ int test_main() char const* e = parse_int(b, b + sizeof(b)-1, ':', val, ec); TEST_CHECK(ec == bdecode_errors::expected_colon); } +#endif // TORRENT_NO_DEPRECATE return 0; } diff --git a/test/test_block_cache.cpp b/test/test_block_cache.cpp index be0009331..f4885e7cd 100644 --- a/test/test_block_cache.cpp +++ b/test/test_block_cache.cpp @@ -72,12 +72,16 @@ struct test_storage_impl : storage_interface } virtual bool has_any_file(storage_error& ec) { return false; } - virtual void set_file_priority(std::vector const& prio, storage_error& ec) {} - virtual int move_storage(std::string const& save_path, int flags, storage_error& ec) { return 0; } - virtual bool verify_resume_data(lazy_entry const& rd, storage_error& ec) { return true; } + virtual void set_file_priority(std::vector const& prio + , storage_error& ec) {} + virtual int move_storage(std::string const& save_path, int flags, storage_error& ec) + { return 0; } + virtual bool verify_resume_data(bdecode_node const& rd, storage_error& ec) + { return true; } virtual void write_resume_data(entry& rd, storage_error& ec) const {} virtual void release_files(storage_error& ec) {} - virtual void rename_file(int index, std::string const& new_filenamem, storage_error& ec) {} + virtual void rename_file(int index, std::string const& new_filenamem + , storage_error& ec) {} virtual void delete_files(storage_error& ec) {} virtual void finalize_file(int, storage_error&) {} }; diff --git a/test/test_dht.cpp b/test/test_dht.cpp index 34da1c334..98ead05d8 100644 --- a/test/test_dht.cpp +++ b/test/test_dht.cpp @@ -127,17 +127,17 @@ find_packet(udp::endpoint ep) , boost::bind(&std::pair::first, _1) == ep); } -void lazy_from_entry(entry const& e, lazy_entry& l) +void lazy_from_entry(entry const& e, bdecode_node& l) { error_code ec; static char inbuf[1500]; int len = bencode(inbuf, e); - int ret = lazy_bdecode(inbuf, inbuf + len, l, ec); + int ret = bdecode(inbuf, inbuf + len, l, ec); TEST_CHECK(ret == 0); } void send_dht_request(node_impl& node, char const* msg, udp::endpoint const& ep - , lazy_entry* reply, char const* t = "10", char const* info_hash = 0 + , bdecode_node* reply, char const* t = "10", char const* info_hash = 0 , char const* name = 0, std::string const token = std::string(), int port = 0 , char const* target = 0, entry const* value = 0 , bool scrape = false, bool seed = false @@ -179,10 +179,10 @@ void send_dht_request(node_impl& node, char const* msg, udp::endpoint const& ep VALGRIND_CHECK_MEM_IS_DEFINED(msg_buf, size); #endif - lazy_entry decoded; + bdecode_node decoded; error_code ec; - lazy_bdecode(msg_buf, msg_buf + size, decoded, ec); - if (ec) fprintf(stderr, "lazy_bdecode failed: %s\n", ec.message().c_str()); + bdecode(msg_buf, msg_buf + size, decoded, ec); + if (ec) fprintf(stderr, "bdecode failed: %s\n", ec.message().c_str()); dht::msg m(decoded, ep); node.incoming(m); @@ -222,7 +222,7 @@ void write_peers(entry::dictionary_type& r, std::set const& peers } } -void send_dht_response(node_impl& node, lazy_entry const& request, udp::endpoint const& ep +void send_dht_response(node_impl& node, bdecode_node const& request, udp::endpoint const& ep , nodes_t const& nodes = nodes_t() , std::string const token = std::string(), int port = 0 , std::set const& peers = std::set() @@ -256,10 +256,10 @@ void send_dht_response(node_impl& node, lazy_entry const& request, udp::endpoint VALGRIND_CHECK_MEM_IS_DEFINED(msg_buf, size); #endif - lazy_entry decoded; + bdecode_node decoded; error_code ec; - lazy_bdecode(msg_buf, msg_buf + size, decoded, ec); - if (ec) fprintf(stderr, "lazy_bdecode failed: %s\n", ec.message().c_str()); + bdecode(msg_buf, msg_buf + size, decoded, ec); + if (ec) fprintf(stderr, "bdecode failed: %s\n", ec.message().c_str()); dht::msg m(decoded, ep); node.incoming(m); @@ -295,28 +295,29 @@ void announce_immutable_items(node_impl& node, udp::endpoint const* eps for (int j = 0; j < num_items; ++j) { if ((i % items[j].num_peers) == 0) continue; - lazy_entry response; + bdecode_node response; send_dht_request(node, "get", eps[i], &response, "10", 0 , 0, no, 0, (char const*)&items[j].target[0]); key_desc_t desc[] = { - { "r", lazy_entry::dict_t, 0, key_desc_t::parse_children }, - { "id", lazy_entry::string_t, 20, 0}, - { "token", lazy_entry::string_t, 0, 0}, - { "ip", lazy_entry::string_t, 0, key_desc_t::optional | key_desc_t::last_child}, - { "y", lazy_entry::string_t, 1, 0}, + { "r", bdecode_node::dict_t, 0, key_desc_t::parse_children }, + { "id", bdecode_node::string_t, 20, 0}, + { "token", bdecode_node::string_t, 0, 0}, + { "ip", bdecode_node::string_t, 0, key_desc_t::optional | key_desc_t::last_child}, + { "y", bdecode_node::string_t, 1, 0}, }; - lazy_entry const* parsed[6]; + bdecode_node parsed[6]; char error_string[200]; // fprintf(stderr, "msg: %s\n", print_entry(response).c_str()); - int ret = verify_message(&response, desc, parsed, 5, error_string, sizeof(error_string)); + int ret = verify_message(response, desc, parsed, 5, error_string + , sizeof(error_string)); if (ret) { - TEST_EQUAL(parsed[4]->string_value(), "r"); - token = parsed[2]->string_value(); + TEST_EQUAL(parsed[4].string_value(), "r"); + token = parsed[2].string_value(); // fprintf(stderr, "got token: %s\n", token.c_str()); } else @@ -329,7 +330,7 @@ void announce_immutable_items(node_impl& node, udp::endpoint const* eps if (parsed[3]) { address_v4::bytes_type b; - memcpy(&b[0], parsed[3]->string_ptr(), b.size()); + memcpy(&b[0], parsed[3].string_ptr(), b.size()); address_v4 addr(b); TEST_EQUAL(addr, eps[i].address()); } @@ -339,16 +340,17 @@ void announce_immutable_items(node_impl& node, udp::endpoint const* eps key_desc_t desc2[] = { - { "y", lazy_entry::string_t, 1, 0 } + { "y", bdecode_node::string_t, 1, 0 } }; - ret = verify_message(&response, desc2, parsed, 1, error_string, sizeof(error_string)); + ret = verify_message(response, desc2, parsed, 1, error_string + , sizeof(error_string)); if (ret) { - if (parsed[0]->string_value() != "r") + if (parsed[0].string_value() != "r") fprintf(stderr, "msg: %s\n", print_entry(response).c_str()); - TEST_EQUAL(parsed[0]->string_value(), "r"); + TEST_EQUAL(parsed[0].string_value(), "r"); } else { @@ -362,22 +364,23 @@ void announce_immutable_items(node_impl& node, udp::endpoint const* eps std::set items_num; for (int j = 0; j < num_items; ++j) { - lazy_entry response; + bdecode_node response; send_dht_request(node, "get", eps[j], &response, "10", 0 , 0, no, 0, (char const*)&items[j].target[0]); key_desc_t desc[] = { - { "r", lazy_entry::dict_t, 0, key_desc_t::parse_children }, - { "v", lazy_entry::dict_t, 0, 0}, - { "id", lazy_entry::string_t, 20, key_desc_t::last_child}, - { "y", lazy_entry::string_t, 1, 0}, + { "r", bdecode_node::dict_t, 0, key_desc_t::parse_children }, + { "v", bdecode_node::dict_t, 0, 0}, + { "id", bdecode_node::string_t, 20, key_desc_t::last_child}, + { "y", bdecode_node::string_t, 1, 0}, }; - lazy_entry const* parsed[4]; + bdecode_node parsed[4]; char error_string[200]; - int ret = verify_message(&response, desc, parsed, 4, error_string, sizeof(error_string)); + int ret = verify_message(response, desc, parsed, 4, error_string + , sizeof(error_string)); if (ret) { items_num.insert(items_num.begin(), j); @@ -447,8 +450,8 @@ int test_main() dht::node_impl node(&ad, &s, sett, node_id(0), ext, 0, cnt); // DHT should be running on port 48199 now - lazy_entry response; - lazy_entry const* parsed[11]; + bdecode_node response; + bdecode_node parsed[11]; char error_string[200]; bool ret; @@ -457,19 +460,20 @@ int test_main() send_dht_request(node, "ping", source, &response, "10"); dht::key_desc_t pong_desc[] = { - {"y", lazy_entry::string_t, 1, 0}, - {"t", lazy_entry::string_t, 2, 0}, - {"r", lazy_entry::dict_t, 0, key_desc_t::parse_children}, - {"id", lazy_entry::string_t, 20, key_desc_t::last_child}, + {"y", bdecode_node::string_t, 1, 0}, + {"t", bdecode_node::string_t, 2, 0}, + {"r", bdecode_node::dict_t, 0, key_desc_t::parse_children}, + {"id", bdecode_node::string_t, 20, key_desc_t::last_child}, }; fprintf(stderr, "msg: %s\n", print_entry(response).c_str()); - ret = dht::verify_message(&response, pong_desc, parsed, 4, error_string, sizeof(error_string)); + ret = dht::verify_message(response, pong_desc, parsed, 4, error_string + , sizeof(error_string)); TEST_CHECK(ret); if (ret) { - TEST_CHECK(parsed[0]->string_value() == "r"); - TEST_CHECK(parsed[1]->string_value() == "10"); + TEST_CHECK(parsed[0].string_value() == "r"); + TEST_CHECK(parsed[1].string_value() == "10"); } else { @@ -481,20 +485,21 @@ int test_main() send_dht_request(node, "find_node", source, &response, "10"); dht::key_desc_t err_desc[] = { - {"y", lazy_entry::string_t, 1, 0}, - {"e", lazy_entry::list_t, 2, 0} + {"y", bdecode_node::string_t, 1, 0}, + {"e", bdecode_node::list_t, 2, 0} }; fprintf(stderr, "msg: %s\n", print_entry(response).c_str()); - ret = dht::verify_message(&response, err_desc, parsed, 2, error_string, sizeof(error_string)); + ret = dht::verify_message(response, err_desc, parsed, 2, error_string + , sizeof(error_string)); TEST_CHECK(ret); if (ret) { - TEST_CHECK(parsed[0]->string_value() == "e"); - if (parsed[1]->list_at(0)->type() == lazy_entry::int_t - && parsed[1]->list_at(1)->type() == lazy_entry::string_t) + TEST_CHECK(parsed[0].string_value() == "e"); + if (parsed[1].list_at(0).type() == bdecode_node::int_t + && parsed[1].list_at(1).type() == bdecode_node::string_t) { - TEST_CHECK(parsed[1]->list_at(1)->string_value() == "missing 'target' key"); + TEST_CHECK(parsed[1].list_at(1).string_value() == "missing 'target' key"); } else { @@ -511,20 +516,21 @@ int test_main() send_dht_request(node, "get_peers", source, &response, "10", "01010101010101010101"); dht::key_desc_t peer1_desc[] = { - {"y", lazy_entry::string_t, 1, 0}, - {"r", lazy_entry::dict_t, 0, key_desc_t::parse_children}, - {"token", lazy_entry::string_t, 0, 0}, - {"id", lazy_entry::string_t, 20, key_desc_t::last_child}, + {"y", bdecode_node::string_t, 1, 0}, + {"r", bdecode_node::dict_t, 0, key_desc_t::parse_children}, + {"token", bdecode_node::string_t, 0, 0}, + {"id", bdecode_node::string_t, 20, key_desc_t::last_child}, }; std::string token; fprintf(stderr, "msg: %s\n", print_entry(response).c_str()); - ret = dht::verify_message(&response, peer1_desc, parsed, 4, error_string, sizeof(error_string)); + ret = dht::verify_message(response, peer1_desc, parsed, 4, error_string + , sizeof(error_string)); TEST_CHECK(ret); if (ret) { - TEST_CHECK(parsed[0]->string_value() == "r"); - token = parsed[2]->string_value(); + TEST_CHECK(parsed[0].string_value() == "r"); + token = parsed[2].string_value(); // fprintf(stderr, "got token: %s\n", token.c_str()); } else @@ -538,17 +544,18 @@ int test_main() send_dht_request(node, "announce_peer", source, &response, "10", "01010101010101010101", "test", token, 8080); dht::key_desc_t ann_desc[] = { - {"y", lazy_entry::string_t, 1, 0}, - {"r", lazy_entry::dict_t, 0, key_desc_t::parse_children}, - {"id", lazy_entry::string_t, 20, key_desc_t::last_child}, + {"y", bdecode_node::string_t, 1, 0}, + {"r", bdecode_node::dict_t, 0, key_desc_t::parse_children}, + {"id", bdecode_node::string_t, 20, key_desc_t::last_child}, }; fprintf(stderr, "msg: %s\n", print_entry(response).c_str()); - ret = dht::verify_message(&response, ann_desc, parsed, 3, error_string, sizeof(error_string)); + ret = dht::verify_message(response, ann_desc, parsed, 3, error_string + , sizeof(error_string)); TEST_CHECK(ret); if (ret) { - TEST_CHECK(parsed[0]->string_value() == "r"); + TEST_CHECK(parsed[0].string_value() == "r"); } else { @@ -561,12 +568,13 @@ int test_main() { source = udp::endpoint(rand_v4(), 6000); send_dht_request(node, "get_peers", source, &response, "10", "01010101010101010101"); - ret = dht::verify_message(&response, peer1_desc, parsed, 4, error_string, sizeof(error_string)); + ret = dht::verify_message(response, peer1_desc, parsed, 4, error_string + , sizeof(error_string)); if (ret) { - TEST_CHECK(parsed[0]->string_value() == "r"); - token = parsed[2]->string_value(); + TEST_CHECK(parsed[0].string_value() == "r"); + token = parsed[2].string_value(); // fprintf(stderr, "got token: %s\n", token.c_str()); } else @@ -586,25 +594,26 @@ int test_main() , 0, no, 0, 0, 0, true); dht::key_desc_t peer2_desc[] = { - {"y", lazy_entry::string_t, 1, 0}, - {"r", lazy_entry::dict_t, 0, key_desc_t::parse_children}, - {"BFpe", lazy_entry::string_t, 256, 0}, - {"BFsd", lazy_entry::string_t, 256, 0}, - {"id", lazy_entry::string_t, 20, key_desc_t::last_child}, + {"y", bdecode_node::string_t, 1, 0}, + {"r", bdecode_node::dict_t, 0, key_desc_t::parse_children}, + {"BFpe", bdecode_node::string_t, 256, 0}, + {"BFsd", bdecode_node::string_t, 256, 0}, + {"id", bdecode_node::string_t, 20, key_desc_t::last_child}, }; fprintf(stderr, "msg: %s\n", print_entry(response).c_str()); - ret = dht::verify_message(&response, peer2_desc, parsed, 5, error_string, sizeof(error_string)); + ret = dht::verify_message(response, peer2_desc, parsed, 5, error_string + , sizeof(error_string)); TEST_CHECK(ret); if (ret) { - TEST_CHECK(parsed[0]->string_value() == "r"); - TEST_EQUAL(parsed[1]->dict_find_string_value("n"), "test"); + TEST_CHECK(parsed[0].string_value() == "r"); + TEST_EQUAL(parsed[1].dict_find_string_value("n"), "test"); bloom_filter<256> downloaders; bloom_filter<256> seeds; - downloaders.from_string(parsed[2]->string_ptr()); - seeds.from_string(parsed[3]->string_ptr()); + downloaders.from_string(parsed[2].string_ptr()); + seeds.from_string(parsed[3].string_ptr()); fprintf(stderr, "seeds: %f\n", seeds.size()); fprintf(stderr, "downloaders: %f\n", downloaders.size()); @@ -644,17 +653,18 @@ int test_main() , 0, "0101010101010101010101010101010101010101", 0, false, false, std::string(), std::string(), -1, 0, &nid); dht::key_desc_t nodes_desc[] = { - {"y", lazy_entry::string_t, 1, 0}, - {"r", lazy_entry::dict_t, 0, key_desc_t::parse_children}, - {"id", lazy_entry::string_t, 20, key_desc_t::last_child}, + {"y", bdecode_node::string_t, 1, 0}, + {"r", bdecode_node::dict_t, 0, key_desc_t::parse_children}, + {"id", bdecode_node::string_t, 20, key_desc_t::last_child}, }; fprintf(stderr, "msg: %s\n", print_entry(response).c_str()); - ret = dht::verify_message(&response, nodes_desc, parsed, 3, error_string, sizeof(error_string)); + ret = dht::verify_message(response, nodes_desc, parsed, 3, error_string + , sizeof(error_string)); TEST_CHECK(ret); if (ret) { - TEST_CHECK(parsed[0]->string_value() == "r"); + TEST_CHECK(parsed[0].string_value() == "r"); } else { @@ -668,15 +678,16 @@ int test_main() send_dht_request(node, "find_node", source, &response, "10", 0, 0, std::string() , 0, "0101010101010101010101010101010101010101", 0, false, false, std::string(), std::string(), -1, 0, &nid); - ret = dht::verify_message(&response, err_desc, parsed, 2, error_string, sizeof(error_string)); + ret = dht::verify_message(response, err_desc, parsed, 2, error_string + , sizeof(error_string)); TEST_CHECK(ret); if (ret) { - TEST_CHECK(parsed[0]->string_value() == "e"); - if (parsed[1]->list_at(0)->type() == lazy_entry::int_t - && parsed[1]->list_at(1)->type() == lazy_entry::string_t) + TEST_CHECK(parsed[0].string_value() == "e"); + if (parsed[1].list_at(0).type() == bdecode_node::int_t + && parsed[1].list_at(1).type() == bdecode_node::string_t) { - TEST_CHECK(parsed[1]->list_at(1)->string_value() == "invalid node ID"); + TEST_CHECK(parsed[1].list_at(1).string_value() == "invalid node ID"); } else { @@ -761,13 +772,13 @@ int test_main() key_desc_t desc2[] = { - { "y", lazy_entry::string_t, 1, 0 } + { "y", bdecode_node::string_t, 1, 0 } }; key_desc_t desc_error[] = { - { "e", lazy_entry::list_t, 2, 0 }, - { "y", lazy_entry::string_t, 1, 0}, + { "e", bdecode_node::list_t, 2, 0 }, + { "y", bdecode_node::string_t, 1, 0}, }; // ==== get / put mutable items === @@ -814,18 +825,19 @@ int test_main() key_desc_t desc[] = { - { "r", lazy_entry::dict_t, 0, key_desc_t::parse_children }, - { "id", lazy_entry::string_t, 20, 0}, - { "token", lazy_entry::string_t, 0, 0}, - { "ip", lazy_entry::string_t, 0, key_desc_t::optional | key_desc_t::last_child}, - { "y", lazy_entry::string_t, 1, 0}, + { "r", bdecode_node::dict_t, 0, key_desc_t::parse_children }, + { "id", bdecode_node::string_t, 20, 0}, + { "token", bdecode_node::string_t, 0, 0}, + { "ip", bdecode_node::string_t, 0, key_desc_t::optional | key_desc_t::last_child}, + { "y", bdecode_node::string_t, 1, 0}, }; - ret = verify_message(&response, desc, parsed, 5, error_string, sizeof(error_string)); + ret = verify_message(response, desc, parsed, 5, error_string + , sizeof(error_string)); if (ret) { - TEST_EQUAL(parsed[4]->string_value(), "r"); - token = parsed[2]->string_value(); + TEST_EQUAL(parsed[4].string_value(), "r"); + token = parsed[2].string_value(); fprintf(stderr, "get response: %s\n" , print_entry(response).c_str()); fprintf(stderr, "got token: %s\n", to_hex(token).c_str()); @@ -850,12 +862,13 @@ int test_main() , std::string(public_key, item_pk_len) , std::string(signature, item_sig_len), seq, -1, NULL, salt.first); - ret = verify_message(&response, desc2, parsed, 1, error_string, sizeof(error_string)); + ret = verify_message(response, desc2, parsed, 1, error_string + , sizeof(error_string)); if (ret) { fprintf(stderr, "put response: %s\n" , print_entry(response).c_str()); - TEST_EQUAL(parsed[0]->string_value(), "r"); + TEST_EQUAL(parsed[0].string_value(), "r"); } else { @@ -873,16 +886,17 @@ int test_main() key_desc_t desc3[] = { - { "r", lazy_entry::dict_t, 0, key_desc_t::parse_children }, - { "id", lazy_entry::string_t, 20, 0}, - { "v", lazy_entry::none_t, 0, 0}, - { "seq", lazy_entry::int_t, 0, 0}, - { "sig", lazy_entry::string_t, 0, 0}, - { "ip", lazy_entry::string_t, 0, key_desc_t::optional | key_desc_t::last_child}, - { "y", lazy_entry::string_t, 1, 0}, + { "r", bdecode_node::dict_t, 0, key_desc_t::parse_children }, + { "id", bdecode_node::string_t, 20, 0}, + { "v", bdecode_node::none_t, 0, 0}, + { "seq", bdecode_node::int_t, 0, 0}, + { "sig", bdecode_node::string_t, 0, 0}, + { "ip", bdecode_node::string_t, 0, key_desc_t::optional | key_desc_t::last_child}, + { "y", bdecode_node::string_t, 1, 0}, }; - ret = verify_message(&response, desc3, parsed, 7, error_string, sizeof(error_string)); + ret = verify_message(response, desc3, parsed, 7, error_string + , sizeof(error_string)); if (ret == 0) { fprintf(stderr, "msg: %s\n", print_entry(response).c_str()); @@ -897,10 +911,10 @@ int test_main() char value[1020]; char* ptr = value; int value_len = bencode(ptr, items[0].ent); - TEST_EQUAL(value_len, parsed[2]->data_section().second); - TEST_CHECK(memcmp(parsed[2]->data_section().first, value, value_len) == 0); + TEST_EQUAL(value_len, parsed[2].data_section().second); + TEST_CHECK(memcmp(parsed[2].data_section().first, value, value_len) == 0); - TEST_EQUAL(seq, parsed[3]->int_value()); + TEST_EQUAL(seq, parsed[3].int_value()); } // also test that invalid signatures fail! @@ -923,13 +937,14 @@ int test_main() , std::string(public_key, item_pk_len) , std::string(signature, item_sig_len), seq, -1, NULL, salt.first); - ret = verify_message(&response, desc_error, parsed, 2, error_string, sizeof(error_string)); + ret = verify_message(response, desc_error, parsed, 2, error_string + , sizeof(error_string)); if (ret) { fprintf(stderr, "put response: %s\n", print_entry(response).c_str()); - TEST_EQUAL(parsed[1]->string_value(), "e"); + TEST_EQUAL(parsed[1].string_value(), "e"); // 206 is the code for invalid signature - TEST_EQUAL(parsed[0]->list_int_value_at(0), 206); + TEST_EQUAL(parsed[0].list_int_value_at(0), 206); } else { @@ -945,10 +960,10 @@ int test_main() , 0, false, false, std::string(), std::string(), seq-1); { - lazy_entry const* r = response.dict_find_dict("r"); - TEST_CHECK(r->dict_find("v")); - TEST_CHECK(r->dict_find("k")); - TEST_CHECK(r->dict_find("sig")); + bdecode_node r = response.dict_find_dict("r"); + TEST_CHECK(r.dict_find("v")); + TEST_CHECK(r.dict_find("k")); + TEST_CHECK(r.dict_find("sig")); } send_dht_request(node, "get", source, &response, "10", 0 @@ -956,10 +971,10 @@ int test_main() , 0, false, false, std::string(), std::string(), seq); { - lazy_entry const* r = response.dict_find_dict("r"); - TEST_CHECK(!r->dict_find("v")); - TEST_CHECK(!r->dict_find("k")); - TEST_CHECK(!r->dict_find("sig")); + bdecode_node r = response.dict_find_dict("r"); + TEST_CHECK(!r.dict_find("v")); + TEST_CHECK(!r.dict_find("k")); + TEST_CHECK(!r.dict_find("sig")); } // === test CAS put === @@ -987,12 +1002,13 @@ int test_main() , std::string(signature, item_sig_len), seq , cas, NULL, salt.first); - ret = verify_message(&response, desc2, parsed, 1, error_string, sizeof(error_string)); + ret = verify_message(response, desc2, parsed, 1, error_string + , sizeof(error_string)); if (ret) { fprintf(stderr, "put response: %s\n" , print_entry(response).c_str()); - TEST_EQUAL(parsed[0]->string_value(), "r"); + TEST_EQUAL(parsed[0].string_value(), "r"); } else { @@ -1012,14 +1028,15 @@ int test_main() , std::string(signature, item_sig_len), seq , cas, NULL, salt.first); - ret = verify_message(&response, desc_error, parsed, 2, error_string, sizeof(error_string)); + ret = verify_message(response, desc_error, parsed, 2, error_string + , sizeof(error_string)); if (ret) { fprintf(stderr, "put response: %s\n" , print_entry(response).c_str()); - TEST_EQUAL(parsed[1]->string_value(), "e"); + TEST_EQUAL(parsed[1].string_value(), "e"); // 301 is the error code for CAS hash mismatch - TEST_EQUAL(parsed[0]->list_int_value_at(0), 301); + TEST_EQUAL(parsed[0].list_int_value_at(0), 301); } else { @@ -1077,94 +1094,99 @@ int test_main() // test verify_message const static key_desc_t msg_desc[] = { - {"A", lazy_entry::string_t, 4, 0}, - {"B", lazy_entry::dict_t, 0, key_desc_t::optional | key_desc_t::parse_children}, - {"B1", lazy_entry::string_t, 0, 0}, - {"B2", lazy_entry::string_t, 0, key_desc_t::last_child}, - {"C", lazy_entry::dict_t, 0, key_desc_t::optional | key_desc_t::parse_children}, - {"C1", lazy_entry::string_t, 0, 0}, - {"C2", lazy_entry::string_t, 0, key_desc_t::last_child}, + {"A", bdecode_node::string_t, 4, 0}, + {"B", bdecode_node::dict_t, 0, key_desc_t::optional | key_desc_t::parse_children}, + {"B1", bdecode_node::string_t, 0, 0}, + {"B2", bdecode_node::string_t, 0, key_desc_t::last_child}, + {"C", bdecode_node::dict_t, 0, key_desc_t::optional | key_desc_t::parse_children}, + {"C1", bdecode_node::string_t, 0, 0}, + {"C2", bdecode_node::string_t, 0, key_desc_t::last_child}, }; - lazy_entry const* msg_keys[7]; + bdecode_node msg_keys[7]; - lazy_entry ent; + bdecode_node ent; error_code ec; char const test_msg[] = "d1:A4:test1:Bd2:B15:test22:B25:test3ee"; - lazy_bdecode(test_msg, test_msg + sizeof(test_msg)-1, ent, ec); + bdecode(test_msg, test_msg + sizeof(test_msg)-1, ent, ec); fprintf(stderr, "%s\n", print_entry(ent).c_str()); - ret = verify_message(&ent, msg_desc, msg_keys, 7, error_string, sizeof(error_string)); + ret = verify_message(ent, msg_desc, msg_keys, 7, error_string + , sizeof(error_string)); TEST_CHECK(ret); TEST_CHECK(msg_keys[0]); - if (msg_keys[0]) TEST_EQUAL(msg_keys[0]->string_value(), "test"); + if (msg_keys[0]) TEST_EQUAL(msg_keys[0].string_value(), "test"); TEST_CHECK(msg_keys[1]); TEST_CHECK(msg_keys[2]); - if (msg_keys[2]) TEST_EQUAL(msg_keys[2]->string_value(), "test2"); + if (msg_keys[2]) TEST_EQUAL(msg_keys[2].string_value(), "test2"); TEST_CHECK(msg_keys[3]); - if (msg_keys[3]) TEST_EQUAL(msg_keys[3]->string_value(), "test3"); - TEST_CHECK(msg_keys[4] == 0); - TEST_CHECK(msg_keys[5] == 0); - TEST_CHECK(msg_keys[6] == 0); + if (msg_keys[3]) TEST_EQUAL(msg_keys[3].string_value(), "test3"); + TEST_CHECK(!msg_keys[4]); + TEST_CHECK(!msg_keys[5]); + TEST_CHECK(!msg_keys[6]); char const test_msg2[] = "d1:A4:test1:Cd2:C15:test22:C25:test3ee"; - lazy_bdecode(test_msg2, test_msg2 + sizeof(test_msg2)-1, ent, ec); + bdecode(test_msg2, test_msg2 + sizeof(test_msg2)-1, ent, ec); fprintf(stderr, "%s\n", print_entry(ent).c_str()); - ret = verify_message(&ent, msg_desc, msg_keys, 7, error_string, sizeof(error_string)); + ret = verify_message(ent, msg_desc, msg_keys, 7, error_string + , sizeof(error_string)); TEST_CHECK(ret); TEST_CHECK(msg_keys[0]); - if (msg_keys[0]) TEST_EQUAL(msg_keys[0]->string_value(), "test"); - TEST_CHECK(msg_keys[1] == 0); - TEST_CHECK(msg_keys[2] == 0); - TEST_CHECK(msg_keys[3] == 0); + if (msg_keys[0]) TEST_EQUAL(msg_keys[0].string_value(), "test"); + TEST_CHECK(!msg_keys[1]); + TEST_CHECK(!msg_keys[2]); + TEST_CHECK(!msg_keys[3]); TEST_CHECK(msg_keys[4]); TEST_CHECK(msg_keys[5]); - if (msg_keys[5]) TEST_EQUAL(msg_keys[5]->string_value(), "test2"); + if (msg_keys[5]) TEST_EQUAL(msg_keys[5].string_value(), "test2"); TEST_CHECK(msg_keys[6]); - if (msg_keys[6]) TEST_EQUAL(msg_keys[6]->string_value(), "test3"); + if (msg_keys[6]) TEST_EQUAL(msg_keys[6].string_value(), "test3"); char const test_msg3[] = "d1:Cd2:C15:test22:C25:test3ee"; - lazy_bdecode(test_msg3, test_msg3 + sizeof(test_msg3)-1, ent, ec); + bdecode(test_msg3, test_msg3 + sizeof(test_msg3)-1, ent, ec); fprintf(stderr, "%s\n", print_entry(ent).c_str()); - ret = verify_message(&ent, msg_desc, msg_keys, 7, error_string, sizeof(error_string)); + ret = verify_message(ent, msg_desc, msg_keys, 7, error_string + , sizeof(error_string)); TEST_CHECK(!ret); fprintf(stderr, "%s\n", error_string); TEST_EQUAL(error_string, std::string("missing 'A' key")); char const test_msg4[] = "d1:A6:foobare"; - lazy_bdecode(test_msg4, test_msg4 + sizeof(test_msg4)-1, ent, ec); + bdecode(test_msg4, test_msg4 + sizeof(test_msg4)-1, ent, ec); fprintf(stderr, "%s\n", print_entry(ent).c_str()); - ret = verify_message(&ent, msg_desc, msg_keys, 7, error_string, sizeof(error_string)); + ret = verify_message(ent, msg_desc, msg_keys, 7, error_string + , sizeof(error_string)); TEST_CHECK(!ret); fprintf(stderr, "%s\n", error_string); TEST_EQUAL(error_string, std::string("invalid value for 'A'")); char const test_msg5[] = "d1:A4:test1:Cd2:C15:test2ee"; - lazy_bdecode(test_msg5, test_msg5 + sizeof(test_msg5)-1, ent, ec); + bdecode(test_msg5, test_msg5 + sizeof(test_msg5)-1, ent, ec); fprintf(stderr, "%s\n", print_entry(ent).c_str()); - ret = verify_message(&ent, msg_desc, msg_keys, 7, error_string, sizeof(error_string)); + ret = verify_message(ent, msg_desc, msg_keys, 7, error_string + , sizeof(error_string)); TEST_CHECK(!ret); fprintf(stderr, "%s\n", error_string); TEST_EQUAL(error_string, std::string("missing 'C2' key")); // test empty strings [ { "":1 }, "" ] char const test_msg6[] = "ld0:i1ee0:e"; - lazy_bdecode(test_msg6, test_msg6 + sizeof(test_msg6)-1, ent, ec); + bdecode(test_msg6, test_msg6 + sizeof(test_msg6)-1, ent, ec); fprintf(stderr, "%s\n", print_entry(ent).c_str()); - TEST_CHECK(ent.type() == lazy_entry::list_t); - if (ent.type() == lazy_entry::list_t) + TEST_CHECK(ent.type() == bdecode_node::list_t); + if (ent.type() == bdecode_node::list_t) { TEST_CHECK(ent.list_size() == 2); if (ent.list_size() == 2) { - TEST_CHECK(ent.list_at(0)->dict_find_int_value("") == 1); - TEST_CHECK(ent.list_at(1)->string_value() == ""); + TEST_CHECK(ent.list_at(0).dict_find_int_value("") == 1); + TEST_CHECK(ent.list_at(1).string_value() == ""); } } @@ -1410,31 +1432,31 @@ int test_main() // test traversal algorithms dht::key_desc_t find_node_desc[] = { - {"y", lazy_entry::string_t, 1, 0}, - {"t", lazy_entry::string_t, 2, 0}, - {"q", lazy_entry::string_t, 9, 0}, - {"a", lazy_entry::dict_t, 0, key_desc_t::parse_children}, - {"id", lazy_entry::string_t, 20, 0}, - {"target", lazy_entry::string_t, 20, key_desc_t::optional}, - {"info_hash", lazy_entry::string_t, 20, key_desc_t::optional | key_desc_t::last_child}, + {"y", bdecode_node::string_t, 1, 0}, + {"t", bdecode_node::string_t, 2, 0}, + {"q", bdecode_node::string_t, 9, 0}, + {"a", bdecode_node::dict_t, 0, key_desc_t::parse_children}, + {"id", bdecode_node::string_t, 20, 0}, + {"target", bdecode_node::string_t, 20, key_desc_t::optional}, + {"info_hash", bdecode_node::string_t, 20, key_desc_t::optional | key_desc_t::last_child}, }; dht::key_desc_t get_peers_desc[] = { - {"y", lazy_entry::string_t, 1, 0}, - {"t", lazy_entry::string_t, 2, 0}, - {"q", lazy_entry::string_t, 9, 0}, - {"a", lazy_entry::dict_t, 0, key_desc_t::parse_children}, - {"id", lazy_entry::string_t, 20, 0}, - {"info_hash", lazy_entry::string_t, 20, key_desc_t::last_child}, + {"y", bdecode_node::string_t, 1, 0}, + {"t", bdecode_node::string_t, 2, 0}, + {"q", bdecode_node::string_t, 9, 0}, + {"a", bdecode_node::dict_t, 0, key_desc_t::parse_children}, + {"id", bdecode_node::string_t, 20, 0}, + {"info_hash", bdecode_node::string_t, 20, key_desc_t::last_child}, }; dht::key_desc_t get_item_desc[] = { - {"y", lazy_entry::string_t, 1, 0}, - {"t", lazy_entry::string_t, 2, 0}, - {"q", lazy_entry::string_t, 3, 0}, - {"a", lazy_entry::dict_t, 0, key_desc_t::parse_children}, - {"id", lazy_entry::string_t, 20, 0}, - {"target", lazy_entry::string_t, 20, key_desc_t::last_child}, + {"y", bdecode_node::string_t, 1, 0}, + {"t", bdecode_node::string_t, 2, 0}, + {"q", bdecode_node::string_t, 3, 0}, + {"a", bdecode_node::dict_t, 0, key_desc_t::parse_children}, + {"id", bdecode_node::string_t, 20, 0}, + {"target", bdecode_node::string_t, 20, key_desc_t::last_child}, }; // bootstrap @@ -1454,16 +1476,17 @@ int test_main() TEST_EQUAL(g_sent_packets.front().first, initial_node); lazy_from_entry(g_sent_packets.front().second, response); - ret = verify_message(&response, find_node_desc, parsed, 7, error_string, sizeof(error_string)); + ret = verify_message(response, find_node_desc, parsed, 7, error_string + , sizeof(error_string)); if (ret) { - TEST_EQUAL(parsed[0]->string_value(), "q"); - TEST_CHECK(parsed[2]->string_value() == "find_node" - || parsed[2]->string_value() == "get_peers"); + TEST_EQUAL(parsed[0].string_value(), "q"); + TEST_CHECK(parsed[2].string_value() == "find_node" + || parsed[2].string_value() == "get_peers"); - if (parsed[0]->string_value() != "q" - || (parsed[2]->string_value() != "find_node" - && parsed[2]->string_value() != "get_peers")) break; + if (parsed[0].string_value() != "q" + || (parsed[2].string_value() != "find_node" + && parsed[2].string_value() != "get_peers")) break; } else { @@ -1483,14 +1506,15 @@ int test_main() TEST_EQUAL(g_sent_packets.front().first, found_node); lazy_from_entry(g_sent_packets.front().second, response); - ret = verify_message(&response, find_node_desc, parsed, 7, error_string, sizeof(error_string)); + ret = verify_message(response, find_node_desc, parsed, 7, error_string + , sizeof(error_string)); if (ret) { - TEST_EQUAL(parsed[0]->string_value(), "q"); - TEST_CHECK(parsed[2]->string_value() == "find_node" - || parsed[2]->string_value() == "get_peers"); - if (parsed[0]->string_value() != "q" || (parsed[2]->string_value() != "find_node" - && parsed[2]->string_value() == "get_peers")) break; + TEST_EQUAL(parsed[0].string_value(), "q"); + TEST_CHECK(parsed[2].string_value() == "find_node" + || parsed[2].string_value() == "get_peers"); + if (parsed[0].string_value() != "q" || (parsed[2].string_value() != "find_node" + && parsed[2].string_value() == "get_peers")) break; } else { @@ -1524,13 +1548,14 @@ int test_main() TEST_EQUAL(g_sent_packets.front().first, initial_node); lazy_from_entry(g_sent_packets.front().second, response); - ret = verify_message(&response, get_peers_desc, parsed, 6, error_string, sizeof(error_string)); + ret = verify_message(response, get_peers_desc, parsed, 6, error_string + , sizeof(error_string)); if (ret) { - TEST_EQUAL(parsed[0]->string_value(), "q"); - TEST_EQUAL(parsed[2]->string_value(), "get_peers"); - TEST_EQUAL(parsed[5]->string_value(), target.to_string()); - if (parsed[0]->string_value() != "q" || parsed[2]->string_value() != "get_peers") break; + TEST_EQUAL(parsed[0].string_value(), "q"); + TEST_EQUAL(parsed[2].string_value(), "get_peers"); + TEST_EQUAL(parsed[5].string_value(), target.to_string()); + if (parsed[0].string_value() != "q" || parsed[2].string_value() != "get_peers") break; } else { @@ -1556,13 +1581,14 @@ int test_main() TEST_EQUAL(g_sent_packets.front().first, next_node); lazy_from_entry(g_sent_packets.front().second, response); - ret = verify_message(&response, get_peers_desc, parsed, 6, error_string, sizeof(error_string)); + ret = verify_message(response, get_peers_desc, parsed, 6, error_string + , sizeof(error_string)); if (ret) { - TEST_EQUAL(parsed[0]->string_value(), "q"); - TEST_EQUAL(parsed[2]->string_value(), "get_peers"); - TEST_EQUAL(parsed[5]->string_value(), target.to_string()); - if (parsed[0]->string_value() != "q" || parsed[2]->string_value() != "get_peers") break; + TEST_EQUAL(parsed[0].string_value(), "q"); + TEST_EQUAL(parsed[2].string_value(), "get_peers"); + TEST_EQUAL(parsed[5].string_value(), target.to_string()); + if (parsed[0].string_value() != "q" || parsed[2].string_value() != "get_peers") break; } else { @@ -1615,13 +1641,14 @@ int test_main() TEST_EQUAL(g_sent_packets.front().first, initial_node); lazy_from_entry(g_sent_packets.front().second, response); - ret = verify_message(&response, get_item_desc, parsed, 6, error_string, sizeof(error_string)); + ret = verify_message(response, get_item_desc, parsed, 6, error_string + , sizeof(error_string)); if (ret) { - TEST_EQUAL(parsed[0]->string_value(), "q"); - TEST_EQUAL(parsed[2]->string_value(), "get"); - TEST_EQUAL(parsed[5]->string_value(), items[0].target.to_string()); - if (parsed[0]->string_value() != "q" || parsed[2]->string_value() != "get") break; + TEST_EQUAL(parsed[0].string_value(), "q"); + TEST_EQUAL(parsed[2].string_value(), "get"); + TEST_EQUAL(parsed[5].string_value(), items[0].target.to_string()); + if (parsed[0].string_value() != "q" || parsed[2].string_value() != "get") break; } else { @@ -1661,13 +1688,14 @@ int test_main() TEST_EQUAL(g_sent_packets.front().first, initial_node); lazy_from_entry(g_sent_packets.front().second, response); - ret = verify_message(&response, get_item_desc, parsed, 6, error_string, sizeof(error_string)); + ret = verify_message(response, get_item_desc, parsed, 6, error_string + , sizeof(error_string)); if (ret) { - TEST_EQUAL(parsed[0]->string_value(), "q"); - TEST_EQUAL(parsed[2]->string_value(), "get"); - TEST_EQUAL(parsed[5]->string_value(), target.to_string()); - if (parsed[0]->string_value() != "q" || parsed[2]->string_value() != "get") break; + TEST_EQUAL(parsed[0].string_value(), "q"); + TEST_EQUAL(parsed[2].string_value(), "get"); + TEST_EQUAL(parsed[5].string_value(), target.to_string()); + if (parsed[0].string_value() != "q" || parsed[2].string_value() != "get") break; } else { @@ -1696,27 +1724,27 @@ int test_main() } while (false); dht::key_desc_t put_immutable_item_desc[] = { - {"y", lazy_entry::string_t, 1, 0}, - {"t", lazy_entry::string_t, 2, 0}, - {"q", lazy_entry::string_t, 3, 0}, - {"a", lazy_entry::dict_t, 0, key_desc_t::parse_children}, - {"id", lazy_entry::string_t, 20, 0}, - {"token", lazy_entry::string_t, 2, 0}, - {"v", lazy_entry::none_t, 0, key_desc_t::last_child}, + {"y", bdecode_node::string_t, 1, 0}, + {"t", bdecode_node::string_t, 2, 0}, + {"q", bdecode_node::string_t, 3, 0}, + {"a", bdecode_node::dict_t, 0, key_desc_t::parse_children}, + {"id", bdecode_node::string_t, 20, 0}, + {"token", bdecode_node::string_t, 2, 0}, + {"v", bdecode_node::none_t, 0, key_desc_t::last_child}, }; dht::key_desc_t put_mutable_item_desc[] = { - {"y", lazy_entry::string_t, 1, 0}, - {"t", lazy_entry::string_t, 2, 0}, - {"q", lazy_entry::string_t, 3, 0}, - {"a", lazy_entry::dict_t, 0, key_desc_t::parse_children}, - {"id", lazy_entry::string_t, 20, 0}, - {"cas", lazy_entry::string_t, 20, key_desc_t::optional}, - {"k", lazy_entry::string_t, item_pk_len, 0}, - {"seq", lazy_entry::int_t, 0, 0}, - {"sig", lazy_entry::string_t, item_sig_len, 0}, - {"token", lazy_entry::string_t, 2, 0}, - {"v", lazy_entry::none_t, 0, key_desc_t::last_child}, + {"y", bdecode_node::string_t, 1, 0}, + {"t", bdecode_node::string_t, 2, 0}, + {"q", bdecode_node::string_t, 3, 0}, + {"a", bdecode_node::dict_t, 0, key_desc_t::parse_children}, + {"id", bdecode_node::string_t, 20, 0}, + {"cas", bdecode_node::string_t, 20, key_desc_t::optional}, + {"k", bdecode_node::string_t, item_pk_len, 0}, + {"seq", bdecode_node::int_t, 0, 0}, + {"sig", bdecode_node::string_t, item_sig_len, 0}, + {"token", bdecode_node::string_t, 2, 0}, + {"v", bdecode_node::none_t, 0, key_desc_t::last_child}, }; // immutable put @@ -1745,7 +1773,8 @@ int test_main() if (packet == g_sent_packets.end()) continue; lazy_from_entry(packet->second, response); - ret = verify_message(&response, get_item_desc, parsed, 6, error_string, sizeof(error_string)); + ret = verify_message(response, get_item_desc, parsed, 6, error_string + , sizeof(error_string)); if (!ret) { fprintf(stderr, " invalid get request: %s\n", print_entry(response).c_str()); @@ -1772,18 +1801,19 @@ int test_main() if (packet == g_sent_packets.end()) continue; lazy_from_entry(packet->second, response); - ret = verify_message(&response, put_immutable_item_desc, parsed, 7, error_string, sizeof(error_string)); + ret = verify_message(response, put_immutable_item_desc, parsed, 7 + , error_string, sizeof(error_string)); if (ret) { - TEST_EQUAL(parsed[0]->string_value(), "q"); - TEST_EQUAL(parsed[2]->string_value(), "put"); - std::pair v = parsed[6]->data_section(); + TEST_EQUAL(parsed[0].string_value(), "q"); + TEST_EQUAL(parsed[2].string_value(), "put"); + std::pair v = parsed[6].data_section(); TEST_EQUAL(v.second, itemv.second); TEST_CHECK(memcmp(v.first, itemv.first, itemv.second) == 0); char t[10]; snprintf(t, sizeof(t), "%02d", i); - TEST_EQUAL(parsed[5]->string_value(), t); - if (parsed[0]->string_value() != "q" || parsed[2]->string_value() != "put") continue; + TEST_EQUAL(parsed[5].string_value(), t); + if (parsed[0].string_value() != "q" || parsed[2].string_value() != "put") continue; } else { @@ -1827,7 +1857,8 @@ int test_main() if (packet == g_sent_packets.end()) continue; lazy_from_entry(packet->second, response); - ret = verify_message(&response, get_item_desc, parsed, 6, error_string, sizeof(error_string)); + ret = verify_message(response, get_item_desc, parsed, 6 + , error_string, sizeof(error_string)); if (!ret) { fprintf(stderr, " invalid mutable put request: %s\n", print_entry(response).c_str()); @@ -1854,21 +1885,22 @@ int test_main() if (packet == g_sent_packets.end()) continue; lazy_from_entry(packet->second, response); - ret = verify_message(&response, put_mutable_item_desc, parsed, 11, error_string, sizeof(error_string)); + ret = verify_message(response, put_mutable_item_desc, parsed, 11 + , error_string, sizeof(error_string)); if (ret) { - TEST_EQUAL(parsed[0]->string_value(), "q"); - TEST_EQUAL(parsed[2]->string_value(), "put"); - TEST_EQUAL(parsed[6]->string_value(), std::string(public_key, item_pk_len)); - TEST_EQUAL(parsed[7]->int_value(), seq); - TEST_EQUAL(parsed[8]->string_value(), sig); - std::pair v = parsed[10]->data_section(); + TEST_EQUAL(parsed[0].string_value(), "q"); + TEST_EQUAL(parsed[2].string_value(), "put"); + TEST_EQUAL(parsed[6].string_value(), std::string(public_key, item_pk_len)); + TEST_EQUAL(parsed[7].int_value(), seq); + TEST_EQUAL(parsed[8].string_value(), sig); + std::pair v = parsed[10].data_section(); TEST_EQUAL(v.second, itemv.second); TEST_CHECK(memcmp(v.first, itemv.first, itemv.second) == 0); char t[10]; snprintf(t, sizeof(t), "%02d", i); - TEST_EQUAL(parsed[9]->string_value(), t); - if (parsed[0]->string_value() != "q" || parsed[2]->string_value() != "put") continue; + TEST_EQUAL(parsed[9].string_value(), t); + if (parsed[0].string_value() != "q" || parsed[2].string_value() != "put") continue; } else { diff --git a/test/test_fast_extension.cpp b/test/test_fast_extension.cpp index 8b5dd09a1..3bd01f7bd 100644 --- a/test/test_fast_extension.cpp +++ b/test/test_fast_extension.cpp @@ -37,7 +37,7 @@ POSSIBILITY OF SUCH DAMAGE. #include "libtorrent/alloca.hpp" #include "libtorrent/time.hpp" #include "libtorrent/peer_info.hpp" -#include "libtorrent/lazy_entry.hpp" +#include "libtorrent/bdecode.hpp" #include #include #include @@ -476,20 +476,26 @@ void test_dont_have() int ext_msg = recv_buffer[1]; if (ext_msg != 0) continue; - lazy_entry e; + bdecode_node e; error_code ec; - int ret = lazy_bdecode(recv_buffer + 2, recv_buffer + len, e, ec); + int pos = 0; + int ret = bdecode(recv_buffer + 2, recv_buffer + len, e, ec, &pos); + if (ret != 0) + { + fprintf(stderr, "failed to parse extension handshake: %s at pos %d\n" + , ec.message().c_str(), pos); + } TEST_EQUAL(ret, 0); printf("extension handshake: %s\n", print_entry(e).c_str()); - lazy_entry const* m = e.dict_find_dict("m"); + bdecode_node m = e.dict_find_dict("m"); TEST_CHECK(m); if (!m) return; - lazy_entry const* dont_have = m->dict_find_int("lt_donthave"); + bdecode_node dont_have = m.dict_find_int("lt_donthave"); TEST_CHECK(dont_have); if (!dont_have) return; - lt_dont_have = dont_have->int_value(); + lt_dont_have = dont_have.int_value(); } char* ptr = recv_buffer; diff --git a/test/test_magnet.cpp b/test/test_magnet.cpp index 1464f1a39..c6d1801d3 100644 --- a/test/test_magnet.cpp +++ b/test/test_magnet.cpp @@ -169,8 +169,8 @@ int test_main() std::vector buf; bencode(std::back_inserter(buf), session_state); - lazy_entry session_state2; - int ret = lazy_bdecode(&buf[0], &buf[0] + buf.size(), session_state2, ec); + bdecode_node session_state2; + int ret = bdecode(&buf[0], &buf[0] + buf.size(), session_state2, ec); TEST_CHECK(ret == 0); fprintf(stderr, "session_state\n%s\n", print_entry(session_state2).c_str()); @@ -204,7 +204,8 @@ int test_main() #endif // make sure settings that haven't been changed from their defaults are not saved - TEST_CHECK(session_state2.dict_find("settings")->dict_find("optimistic_disk_retry") == 0); + TEST_CHECK(session_state2.dict_find("settings") + .dict_find("optimistic_disk_retry") == 0); s->load_state(session_state2); diff --git a/test/test_socket_io.cpp b/test/test_socket_io.cpp index b96c1ccf9..ed5543d9c 100644 --- a/test/test_socket_io.cpp +++ b/test/test_socket_io.cpp @@ -86,12 +86,12 @@ int test_main() #endif char const eplist[] = "l6:\x10\x05\x80\x01\x05\x39" "18:\x10\0\0\0\0\0\0\0\0\0\0\0\0\0\xff\xff\x05\x39" "e"; - lazy_entry e; + bdecode_node e; error_code ec; - lazy_bdecode(eplist, eplist + sizeof(eplist)-1, e, ec); + bdecode(eplist, eplist + sizeof(eplist)-1, e, ec); TEST_CHECK(!ec); std::vector list; - read_endpoint_list(&e, list); + read_endpoint_list(e, list); #if TORRENT_USE_IPV6 TEST_EQUAL(list.size(), 2); diff --git a/test/test_storage.cpp b/test/test_storage.cpp index 30042e69f..e7f78c07d 100644 --- a/test/test_storage.cpp +++ b/test/test_storage.cpp @@ -459,7 +459,7 @@ void test_check_files(std::string const& test_path libtorrent::mutex lock; bool done = false; - lazy_entry frd; + bdecode_node frd; io.async_check_fastresume(pm.get(), &frd, boost::bind(&on_check_resume_data, _1, &done)); io.submit_jobs(); ios.reset(); diff --git a/tools/dht_put.cpp b/tools/dht_put.cpp index 2b278671c..16ae2a5a2 100644 --- a/tools/dht_put.cpp +++ b/tools/dht_put.cpp @@ -177,9 +177,9 @@ int main(int argc, char* argv[]) state.resize(size); fread(&state[0], 1, state.size(), f); - lazy_entry e; + bdecode_node e; error_code ec; - lazy_bdecode(&state[0], &state[0] + state.size(), e, ec); + bdecode(&state[0], &state[0] + state.size(), e, ec); if (ec) fprintf(stderr, "failed to parse .dht file: (%d) %s\n" , ec.value(), ec.message().c_str()); diff --git a/tools/fuzz_torrent.cpp b/tools/fuzz_torrent.cpp index c1f39c6d4..ec4371b28 100644 --- a/tools/fuzz_torrent.cpp +++ b/tools/fuzz_torrent.cpp @@ -34,11 +34,11 @@ POSSIBILITY OF SUCH DAMAGE. #include #include #include -#include "libtorrent/lazy_entry.hpp" +#include "libtorrent/bdecode.hpp" #include "libtorrent/torrent_info.hpp" #include "libtorrent/error_code.hpp" -using libtorrent::lazy_entry; +using libtorrent::bdecode_node; using boost::random::mt19937; using boost::random::uniform_int_distribution; @@ -233,52 +233,52 @@ void render_arbitrary_item(std::string& out) } } -void render_variant(std::string& out, lazy_entry const& e) +void render_variant(std::string& out, bdecode_node const& e) { switch (e.type()) { - case lazy_entry::dict_t: + case bdecode_node::dict_t: print_dict(out); for (int i = 0; i < e.dict_size(); ++i) { - std::pair item = e.dict_at(i); + std::pair item = e.dict_at(i); const bool duplicate = g_seed == 1; const bool skipped = g_seed == 2; g_seed -= 2; if (duplicate) { print_string(out, item.first); - render_variant(out, *item.second); + render_variant(out, item.second); } if (!skipped) { print_string(out, item.first); - render_variant(out, *item.second); + render_variant(out, item.second); } render_arbitrary_item(out); } print_terminate(out); break; - case lazy_entry::list_t: + case bdecode_node::list_t: print_list(out); for (int i = 0; i < e.list_size(); ++i) { const bool duplicate = g_seed == 1; const bool skipped = g_seed == 2; g_seed -= 2; - if (duplicate) render_variant(out, *e.list_at(i)); + if (duplicate) render_variant(out, e.list_at(i)); render_arbitrary_item(out); - if (!skipped) render_variant(out, *e.list_at(i)); + if (!skipped) render_variant(out, e.list_at(i)); } print_terminate(out); break; - case lazy_entry::int_t: + case bdecode_node::int_t: print_int(out, e.int_value()); break; - case lazy_entry::string_t: + case bdecode_node::string_t: print_string(out, e.string_value()); break; default: @@ -371,8 +371,8 @@ int main(int argc, char const* argv[]) continue; } - lazy_entry e; - if (buf.size() == 0 || lazy_bdecode(&buf[0], &buf[0] + buf.size(), e, ec) != 0) + bdecode_node e; + if (buf.size() == 0 || bdecode(&buf[0], &buf[0] + buf.size(), e, ec) != 0) { fprintf(stderr, "ERROR parsing file: %s\n%s\n" , *argv, ec.message().c_str()); diff --git a/tools/test_coverage.sh b/tools/test_coverage.sh index 0cfa55e29..95f7928f5 100755 --- a/tools/test_coverage.sh +++ b/tools/test_coverage.sh @@ -3,10 +3,15 @@ OBJECT_PATH=bin/gcc-4.8/debug/asserts-off/boost-source/debug-iterators-on/export-extra-on/invariant-checks-off/link-static/logging-on/test-coverage-on/threading-multi/src function run_test { + set +e rm $OBJECT_PATH/*.gcda + set -e cd test + set +e rm -rf bin + set -e + bjam asserts=off invariant-checks=off link=static boost=source test-coverage=on picker-debugging=off -j4 $1 cd .. @@ -20,11 +25,16 @@ function run_test { # force rebuilding and rerunning the unit tests cd test +set +e rm -rf bin +set -e cd .. +set +e mkdir test-coverage +set -e +run_test test_bdecode "*/bdecode.*" run_test test_piece_picker "*/piece_picker.*" run_test test_torrent_info "*/torrent_info.*" run_test test_part_file "*/part_file.*" @@ -40,5 +50,3 @@ run_test test_sliding_average "*/sliding_average.*" run_test test_string "*/escape_string.*" run_test test_utf8 "*/ConvertUTF.*" - -