landed the bdecode branch in master. lazy_bdecode/lazy_entry is now being replaced by bdecode/bdecode_node

This commit is contained in:
Arvid Norberg 2015-03-12 05:20:12 +00:00
parent c1dc982f4f
commit 6c1df7eb55
72 changed files with 4039 additions and 1144 deletions

View File

@ -13,6 +13,7 @@ set(sources
bandwidth_limit bandwidth_limit
bandwidth_manager bandwidth_manager
bandwidth_queue_entry bandwidth_queue_entry
bdecode
block_cache block_cache
bloom_filter bloom_filter
chained_buffer chained_buffer

View File

@ -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 * deprecate time functions, expose typedefs of boost::chrono in the libtorrent
namespace instead namespace instead
* deprecate file_base feature in file_storage/torrent_info * deprecate file_base feature in file_storage/torrent_info

View File

@ -529,6 +529,7 @@ SOURCES =
bandwidth_limit bandwidth_limit
bandwidth_manager bandwidth_manager
bandwidth_queue_entry bandwidth_queue_entry
bdecode
block_cache block_cache
bloom_filter bloom_filter
chained_buffer chained_buffer

View File

@ -32,7 +32,7 @@ POSSIBILITY OF SUCH DAMAGE.
#include <boost/python.hpp> #include <boost/python.hpp>
#include <libtorrent/error_code.hpp> #include <libtorrent/error_code.hpp>
#include <libtorrent/lazy_entry.hpp> #include <libtorrent/bdecode.hpp>
#include <libtorrent/upnp.hpp> #include <libtorrent/upnp.hpp>
#include <libtorrent/socks5_stream.hpp> #include <libtorrent/socks5_stream.hpp>

View File

@ -12,7 +12,7 @@
#include <libtorrent/disk_io_thread.hpp> #include <libtorrent/disk_io_thread.hpp>
#include <libtorrent/aux_/session_settings.hpp> #include <libtorrent/aux_/session_settings.hpp>
#include <libtorrent/extensions.hpp> #include <libtorrent/extensions.hpp>
#include <libtorrent/lazy_entry.hpp> #include <libtorrent/bdecode.hpp>
#include <libtorrent/bencode.hpp> #include <libtorrent/bencode.hpp>
#include <libtorrent/aux_/session_impl.hpp> // for settings_map() #include <libtorrent/aux_/session_impl.hpp> // for settings_map()
@ -486,9 +486,9 @@ namespace
std::vector<char> buf; std::vector<char> buf;
bencode(std::back_inserter(buf), st); bencode(std::back_inserter(buf), st);
lazy_entry e; bdecode_node e;
error_code ec; 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); TORRENT_ASSERT(!ec);
ses.load_state(e); ses.load_state(e);
} }

View File

@ -82,6 +82,7 @@ category_mapping = {
'alert_types.hpp': 'Alerts', 'alert_types.hpp': 'Alerts',
'bencode.hpp': 'Bencoding', 'bencode.hpp': 'Bencoding',
'lazy_entry.hpp': 'Bencoding', 'lazy_entry.hpp': 'Bencoding',
'bdecode.hpp': 'Bdecoding',
'entry.hpp': 'Bencoding', 'entry.hpp': 'Bencoding',
'time.hpp': 'Time', 'time.hpp': 'Time',
'escape_string.hpp': 'String', 'escape_string.hpp': 'String',

View File

@ -85,8 +85,8 @@ $(REFERENCE_TARGETS:=.rst):gen_reference_doc.py ../include/libtorrent/*.hpp ../i
rst2pdf $? -o $@ --stylesheets stylesheet rst2pdf $? -o $@ --stylesheets stylesheet
%.html:%.rst %.html:%.rst
rst2html-2.6.py --template=template.txt --stylesheet-path=style.css --link-stylesheet --no-toc-backlinks $? > $@ rst2html-3.4.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=template2.txt --stylesheet-path=style.css --link-stylesheet --no-toc-backlinks $? > $(WEB_PATH)/$@
%.png:%.dot %.png:%.dot
dot -Tpng $? >$@ dot -Tpng $? >$@

View File

@ -64,7 +64,7 @@ POSSIBILITY OF SUCH DAMAGE.
#include "libtorrent/magnet_uri.hpp" #include "libtorrent/magnet_uri.hpp"
#include "libtorrent/bitfield.hpp" #include "libtorrent/bitfield.hpp"
#include "libtorrent/peer_info.hpp" #include "libtorrent/peer_info.hpp"
#include "libtorrent/lazy_entry.hpp" #include "libtorrent/bdecode.hpp"
#include "libtorrent/add_torrent_params.hpp" #include "libtorrent/add_torrent_params.hpp"
#include "libtorrent/time.hpp" #include "libtorrent/time.hpp"
#include "libtorrent/create_torrent.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 (seed_mode) p.flags |= add_torrent_params::flag_seed_mode;
if (disable_storage) p.storage = disabled_storage_constructor; if (disable_storage) p.storage = disabled_storage_constructor;
if (share_mode) p.flags |= add_torrent_params::flag_share_mode; 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" std::string filename = path_append(save_path, path_append(".resume"
, leaf_path(torrent) + ".resume")); , leaf_path(torrent) + ".resume"));
@ -1324,8 +1323,8 @@ int main(int argc, char* argv[])
error_code ec; error_code ec;
if (load_file(".ses_state", in, ec) == 0) if (load_file(".ses_state", in, ec) == 0)
{ {
lazy_entry e; bdecode_node e;
if (lazy_bdecode(&in[0], &in[0] + in.size(), e, ec) == 0) if (bdecode(&in[0], &in[0] + in.size(), e, ec) == 0)
ses.load_state(e); ses.load_state(e);
} }

View File

@ -33,10 +33,11 @@ POSSIBILITY OF SUCH DAMAGE.
#include "libtorrent/entry.hpp" #include "libtorrent/entry.hpp"
#include "libtorrent/bencode.hpp" #include "libtorrent/bencode.hpp"
#include "libtorrent/torrent_info.hpp" #include "libtorrent/torrent_info.hpp"
#include "libtorrent/lazy_entry.hpp" #include "libtorrent/bdecode.hpp"
#include "libtorrent/magnet_uri.hpp" #include "libtorrent/magnet_uri.hpp"
int load_file(std::string const& filename, std::vector<char>& v, libtorrent::error_code& ec, int limit = 8000000) int load_file(std::string const& filename, std::vector<char>& v
, libtorrent::error_code& ec, int limit = 8000000)
{ {
ec.clear(); ec.clear();
FILE* f = fopen(filename.c_str(), "rb"); 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()); fprintf(stderr, "failed to load file: %s\n", ec.message().c_str());
return 1; return 1;
} }
lazy_entry e; bdecode_node e;
int pos = -1; int pos = -1;
printf("decoding. recursion limit: %d total item count limit: %d\n" printf("decoding. recursion limit: %d total item count limit: %d\n"
, depth_limit, item_limit); , 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); , depth_limit, item_limit);
printf("\n\n----- raw info -----\n\n%s\n", print_entry(e).c_str()); printf("\n\n----- raw info -----\n\n%s\n", print_entry(e).c_str());

View File

@ -179,8 +179,8 @@ int main(int argc, char* argv[])
error_code ec; error_code ec;
if (load_file(".ses_state", in, ec) == 0) if (load_file(".ses_state", in, ec) == 0)
{ {
lazy_entry e; bdecode_node e;
if (lazy_bdecode(&in[0], &in[0] + in.size(), e, ec) == 0) if (bdecode(&in[0], &in[0] + in.size(), e, ec) == 0)
ses.load_state(e); ses.load_state(e);
} }

View File

@ -16,6 +16,7 @@ nobase_include_HEADERS = \
bandwidth_socket.hpp \ bandwidth_socket.hpp \
bandwidth_queue_entry.hpp \ bandwidth_queue_entry.hpp \
bencode.hpp \ bencode.hpp \
bdecode.hpp \
bitfield.hpp \ bitfield.hpp \
block_cache.hpp \ block_cache.hpp \
bloom_filter.hpp \ bloom_filter.hpp \

View File

@ -492,7 +492,7 @@ namespace libtorrent
void announce_lsd(sha1_hash const& ih, int port, bool broadcast = false); void announce_lsd(sha1_hash const& ih, int port, bool broadcast = false);
void save_state(entry* e, boost::uint32_t flags) const; 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; bool has_connection(peer_connection* p) const;
void insert_peer(boost::shared_ptr<peer_connection> const& c); void insert_peer(boost::shared_ptr<peer_connection> const& c);

View File

@ -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 <boost/cstdint.hpp>
#include <boost/system/error_code.hpp>
#include <vector>
#include <string>
#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<libtorrent::bdecode_errors::error_code_enum>
{ static const bool value = true; };
template<> struct is_error_condition_enum<libtorrent::bdecode_errors::error_code_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<char const*, int> 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<std::string, bdecode_node> 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<detail::bdecode_token> 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

View File

@ -51,7 +51,7 @@ POSSIBILITY OF SUCH DAMAGE.
// //
// There are two mechanims to *decode* bencoded buffers in libtorrent. // 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, // represented by entry. When a buffer is decoded with this function,
// it can be discarded. The entry does not contain any references back // it can be discarded. The entry does not contain any references back
// to it. This means that bdecode() actually copies all the data out // 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 // function potentially expensive, if you're parsing large amounts
// of data. // 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 // For this reason, in order to avoid DoS attacks by triggering
// a stack overflow, there is a recursion limit. This limit is // a stack overflow, there is a recursion limit. This limit is
// a sanity check to make sure it doesn't run the risk of // a sanity check to make sure it doesn't run the risk of
// busting the stack. // busting the stack.
// //
// The second mechanism is lazy_bdecode(), which returns a // The second mechanism is bdecode(), which returns a
// bencoded structure represented by lazy_entry. This function // bencoded structure represented by bdecode_node. This function
// builds a tree that points back into the original buffer. // 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. // it was parsed out of is discarded.
// //
// Not only is this function more efficient because of less // 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 // 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 // and it can be used to retrieve information, an entry_ can also be build by

View File

@ -43,6 +43,7 @@ POSSIBILITY OF SUCH DAMAGE.
namespace libtorrent namespace libtorrent
{ {
// internal
inline void cpuid(unsigned int info[4], int type) inline void cpuid(unsigned int info[4], int type)
{ {
#if TORRENT_HAS_SSE && defined _MSC_VER #if TORRENT_HAS_SSE && defined _MSC_VER

View File

@ -36,7 +36,7 @@ POSSIBILITY OF SUCH DAMAGE.
#include <boost/function/function1.hpp> #include <boost/function/function1.hpp>
#include <boost/shared_ptr.hpp> #include <boost/shared_ptr.hpp>
#include "libtorrent/lazy_entry.hpp" #include "libtorrent/bdecode.hpp"
#include <string> #include <string>
@ -66,7 +66,7 @@ namespace libtorrent
, boost::function<void(disk_io_job const*)> const& handler , boost::function<void(disk_io_job const*)> const& handler
= boost::function<void(disk_io_job const*)>()) = 0; = boost::function<void(disk_io_job const*)>()) = 0;
virtual void async_check_fastresume(piece_manager* storage virtual void async_check_fastresume(piece_manager* storage
, lazy_entry const* resume_data , bdecode_node const* resume_data
, boost::function<void(disk_io_job const*)> const& handler) = 0; , boost::function<void(disk_io_job const*)> const& handler) = 0;
#ifndef TORRENT_NO_DEPRECATE #ifndef TORRENT_NO_DEPRECATE
virtual void async_finalize_file(piece_manager*, int file virtual void async_finalize_file(piece_manager*, int file

View File

@ -307,7 +307,7 @@ namespace libtorrent
void async_delete_files(piece_manager* storage void async_delete_files(piece_manager* storage
, boost::function<void(disk_io_job const*)> const& handler); , boost::function<void(disk_io_job const*)> const& handler);
void async_check_fastresume(piece_manager* storage void async_check_fastresume(piece_manager* storage
, lazy_entry const* resume_data , bdecode_node const* resume_data
, boost::function<void(disk_io_job const*)> const& handler); , boost::function<void(disk_io_job const*)> const& handler);
void async_save_resume_data(piece_manager* storage void async_save_resume_data(piece_manager* storage
, boost::function<void(disk_io_job const*)> const& handler); , boost::function<void(disk_io_job const*)> const& handler);

View File

@ -76,7 +76,10 @@ POSSIBILITY OF SUCH DAMAGE.
namespace libtorrent namespace libtorrent
{ {
#ifndef TORRENT_NO_DEPRECATE
struct lazy_entry; struct lazy_entry;
#endif
struct bdecode_node;
// thrown by any accessor function of entry if the accessor // thrown by any accessor function of entry if the accessor
// function requires a type different than the actual type // 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 // copies the structure of the right hand side into this
// entry. // entry.
#ifndef TORRENT_NO_DEPRECATE
void operator=(lazy_entry const&); void operator=(lazy_entry const&);
#endif
void operator=(bdecode_node const&);
void operator=(entry const&); void operator=(entry const&);
void operator=(dictionary_type const&); void operator=(dictionary_type const&);
void operator=(string_type const&); void operator=(string_type const&);

View File

@ -191,7 +191,7 @@ namespace libtorrent
struct peer_request; struct peer_request;
class peer_connection; class peer_connection;
class entry; class entry;
struct lazy_entry; struct bdecode_node;
struct disk_buffer_holder; struct disk_buffer_holder;
struct bitfield; struct bitfield;
class alert; class alert;
@ -248,7 +248,7 @@ namespace libtorrent
virtual void save_state(entry&) const {} virtual void save_state(entry&) const {}
// called when loading settings state // 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 // 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 // supported by this peer. It will result in this peer_plugin
// being removed from the peer_connection and destructed. // being removed from the peer_connection and destructed.
// this is not called for web seeds // 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 // returning true from any of the message handlers
// indicates that the plugin has handeled the message. // indicates that the plugin has handeled the message.

View File

@ -56,7 +56,6 @@ POSSIBILITY OF SUCH DAMAGE.
namespace libtorrent namespace libtorrent
{ {
namespace aux { struct session_impl; } namespace aux { struct session_impl; }
struct lazy_entry;
struct counters; struct counters;
#ifndef TORRENT_NO_DEPRECATE #ifndef TORRENT_NO_DEPRECATE
struct session_status; struct session_status;
@ -139,6 +138,11 @@ namespace libtorrent { namespace dht
virtual bool send_packet(libtorrent::entry& e, udp::endpoint const& addr virtual bool send_packet(libtorrent::entry& e, udp::endpoint const& addr
, int send_flags); , 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; counters& m_counters;
node_impl m_dht; node_impl m_dht;
rate_limited_udp_socket& m_sock; rate_limited_udp_socket& m_sock;

View File

@ -45,7 +45,7 @@ class get_item : public find_data
public: public:
typedef boost::function<bool(item&)> data_callback; typedef boost::function<bool(item&)> data_callback;
void got_data(lazy_entry const* v, void got_data(bdecode_node const& v,
char const* pk, char const* pk,
boost::uint64_t seq, boost::uint64_t seq,
char const* sig); char const* sig);

View File

@ -34,7 +34,7 @@ POSSIBILITY OF SUCH DAMAGE.
#define LIBTORRENT_ITEM_HPP #define LIBTORRENT_ITEM_HPP
#include <libtorrent/sha1_hash.hpp> #include <libtorrent/sha1_hash.hpp>
#include <libtorrent/lazy_entry.hpp> #include <libtorrent/bdecode.hpp>
#include <libtorrent/entry.hpp> #include <libtorrent/entry.hpp>
#include <vector> #include <vector>
#include <exception> #include <exception>
@ -91,7 +91,7 @@ public:
item(entry const& v item(entry const& v
, std::pair<char const*, int> salt , std::pair<char const*, int> salt
, boost::uint64_t seq, char const* pk, char const* sk); , 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) void assign(entry const& v)
{ {
@ -100,12 +100,12 @@ public:
} }
void assign(entry const& v, std::pair<char const*, int> salt void assign(entry const& v, std::pair<char const*, int> salt
, boost::uint64_t seq, char const* pk, char const* sk); , 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<char const*, int>(static_cast<char const*>(NULL) assign(v, std::pair<char const*, int>(static_cast<char const*>(NULL)
, 0), 0, NULL, NULL); , 0), 0, NULL, NULL);
} }
bool assign(lazy_entry const* v, std::pair<char const*, int> salt bool assign(bdecode_node const& v, std::pair<char const*, int> salt
, boost::uint64_t seq, char const* pk, char const* sig); , boost::uint64_t seq, char const* pk, char const* sig);
void assign(entry const& v, std::string salt, boost::uint64_t seq void assign(entry const& v, std::string salt, boost::uint64_t seq
, char const* pk, char const* sig); , char const* pk, char const* sig);

View File

@ -51,9 +51,9 @@ typedef std::vector<tcp::endpoint> peers_t;
struct msg 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 // the message
lazy_entry const& message; bdecode_node const& message;
// the address of the process sending or receiving // the address of the process sending or receiving
// the message. // the message.

View File

@ -99,8 +99,8 @@ struct key_desc_t
}; };
}; };
bool TORRENT_EXTRA_EXPORT verify_message(lazy_entry const* msg, key_desc_t const desc[] bool TORRENT_EXTRA_EXPORT verify_message(bdecode_node const& msg, key_desc_t const desc[]
, lazy_entry const* ret[], int size , char* error, int error_size); , bdecode_node ret[], int size , char* error, int error_size);
// this is the entry for every peer // this is the entry for every peer
// the timestamp is there to make it possible // the timestamp is there to make it possible

View File

@ -33,6 +33,8 @@ POSSIBILITY OF SUCH DAMAGE.
#ifndef TORRENT_LAZY_ENTRY_HPP_INCLUDED #ifndef TORRENT_LAZY_ENTRY_HPP_INCLUDED
#define TORRENT_LAZY_ENTRY_HPP_INCLUDED #define TORRENT_LAZY_ENTRY_HPP_INCLUDED
#ifndef TORRENT_NO_DEPRECATE
#include <utility> #include <utility>
#include <vector> #include <vector>
#include <string> #include <string>
@ -41,6 +43,7 @@ POSSIBILITY OF SUCH DAMAGE.
#include "libtorrent/config.hpp" #include "libtorrent/config.hpp"
#include "libtorrent/assert.hpp" #include "libtorrent/assert.hpp"
#include "libtorrent/error_code.hpp" #include "libtorrent/error_code.hpp"
#include "libtorrent/bdecode.hpp" // for error codes
namespace libtorrent namespace libtorrent
{ {
@ -50,9 +53,8 @@ namespace libtorrent
// //
// .. _bencoded: http://wiki.theory.org/index.php/BitTorrentSpecification // .. _bencoded: http://wiki.theory.org/index.php/BitTorrentSpecification
// //
// Whenever possible, ``lazy_bdecode()`` should be preferred over ``bdecode()``. // The lazy bdecoder and lazy_entry has been deprecated in favour of
// It is more efficient and more secure. It supports having constraints on the // bdecode_node and its corresponding bdecode() function.
// amount of memory is consumed by the parser.
// //
// *lazy* refers to the fact that it doesn't copy any actual data out of the // *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 // 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, // 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, // which will be set to the byte offset into the buffer where an error occurred,
// in case the function fails. // in case the function fails.
TORRENT_DEPRECATED_PREFIX
TORRENT_EXPORT int lazy_bdecode(char const* start, char const* end TORRENT_EXPORT int lazy_bdecode(char const* start, char const* end
, lazy_entry& ret, error_code& ec, int* error_pos = 0 , 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 #ifndef TORRENT_NO_DEPRECATE
// for backwards compatibility, does not report error code // for backwards compatibility, does not report error code
@ -392,63 +395,21 @@ namespace libtorrent
lazy_entry val; 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. // that's returned.
TORRENT_DEPRECATED_PREFIX
TORRENT_EXPORT std::string print_entry(lazy_entry const& e TORRENT_EXPORT std::string print_entry(lazy_entry const& e
, bool single_line = false, int indent = 0); , bool single_line = false, int indent = 0) TORRENT_DEPRECATED;
// 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);
}
// defined in bdecode.cpp
TORRENT_DEPRECATED_PREFIX
TORRENT_EXTRA_EXPORT char const* parse_int(char const* start TORRENT_EXTRA_EXPORT char const* parse_int(char const* start
, char const* end, char delimiter, boost::int64_t& val , 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 #endif // TORRENT_NO_DEPRECATE
namespace boost { namespace system {
template<> struct is_error_code_enum<libtorrent::bdecode_errors::error_code_enum>
{ static const bool value = true; };
template<> struct is_error_condition_enum<libtorrent::bdecode_errors::error_code_enum>
{ static const bool value = true; };
} }
#endif
#endif #endif

View File

@ -229,7 +229,7 @@ namespace libtorrent
int next_update(time_t now) const; 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; void save_state(entry& rd) const;
// private: // private:

View File

@ -311,14 +311,14 @@ namespace libtorrent
// to the ``entry`` that's passed in, which needs to either not be // to the ``entry`` that's passed in, which needs to either not be
// initialized, or initialized as a dictionary. // initialized, or initialized as a dictionary.
// //
// ``load_state`` expects a lazy_entry which can be built from a bencoded // ``load_state`` expects a bdecode_node which can be built from a bencoded
// buffer with lazy_bdecode(). // buffer with bdecode().
// //
// The ``flags`` arguments passed in to ``save_state`` can be used to // 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 // 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 // is saved (except for the individual torrents). see save_state_flags_t
void save_state(entry& e, boost::uint32_t flags = 0xffffffff) const; 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:: // .. note::
// these calls are potentially expensive and won't scale well with // 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; void load_state(entry const& ses_state) TORRENT_DEPRECATED;
TORRENT_DEPRECATED_PREFIX TORRENT_DEPRECATED_PREFIX
entry state() const TORRENT_DEPRECATED; 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 #endif // TORRENT_NO_DEPRECATE
// Sets a filter that will be used to reject and accept incoming as well // Sets a filter that will be used to reject and accept incoming as well

View File

@ -51,9 +51,9 @@ namespace libtorrent
namespace aux { struct session_impl; struct session_settings; } namespace aux { struct session_impl; struct session_settings; }
struct settings_pack; 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 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); TORRENT_EXTRA_EXPORT void apply_pack(settings_pack const* pack, aux::session_settings& sett, aux::session_impl* ses = 0);

View File

@ -37,7 +37,7 @@ POSSIBILITY OF SUCH DAMAGE.
#include "libtorrent/address.hpp" #include "libtorrent/address.hpp"
#include "libtorrent/io.hpp" #include "libtorrent/io.hpp"
#include "libtorrent/error_code.hpp" #include "libtorrent/error_code.hpp"
#include "libtorrent/lazy_entry.hpp" #include "libtorrent/bdecode.hpp"
#include "libtorrent/bencode.hpp" #include "libtorrent/bencode.hpp"
#include "libtorrent/peer_id.hpp" // for sha1_hash #include "libtorrent/peer_id.hpp" // for sha1_hash
#include <string> #include <string>
@ -123,20 +123,21 @@ namespace libtorrent
#endif #endif
template <class EndpointType> template <class EndpointType>
void read_endpoint_list(libtorrent::lazy_entry const* n, std::vector<EndpointType>& epl) void read_endpoint_list(libtorrent::bdecode_node const& n
, std::vector<EndpointType>& epl)
{ {
using namespace libtorrent; using namespace libtorrent;
if (n->type() != lazy_entry::list_t) return; if (n.type() != bdecode_node::list_t) return;
for (int i = 0; i < n->list_size(); ++i) for (int i = 0; i < n.list_size(); ++i)
{ {
lazy_entry const* e = n->list_at(i); bdecode_node e = n.list_at(i);
if (e->type() != lazy_entry::string_t) return; if (e.type() != bdecode_node::string_t) return;
if (e->string_length() < 6) continue; if (e.string_length() < 6) continue;
char const* in = e->string_ptr(); char const* in = e.string_ptr();
if (e->string_length() == 6) if (e.string_length() == 6)
epl.push_back(read_v4_endpoint<EndpointType>(in)); epl.push_back(read_v4_endpoint<EndpointType>(in));
#if TORRENT_USE_IPV6 #if TORRENT_USE_IPV6
else if (e->string_length() == 18) else if (e.string_length() == 18)
epl.push_back(read_v6_endpoint<EndpointType>(in)); epl.push_back(read_v6_endpoint<EndpointType>(in));
#endif #endif
} }

View File

@ -66,7 +66,7 @@ POSSIBILITY OF SUCH DAMAGE.
#include "libtorrent/file_pool.hpp" // pool_file_status #include "libtorrent/file_pool.hpp" // pool_file_status
#include "libtorrent/part_file.hpp" #include "libtorrent/part_file.hpp"
#include "libtorrent/stat_cache.hpp" #include "libtorrent/stat_cache.hpp"
#include "libtorrent/lazy_entry.hpp" #include "libtorrent/bdecode.hpp"
#include "libtorrent/bitfield.hpp" #include "libtorrent/bitfield.hpp"
#include "libtorrent/performance_counters.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) // virtual bool rename_file(int file, std::string const& new_name)
// { assert(false); return false; } // { assert(false); return false; }
// virtual bool move_storage(std::string const& save_path) { 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 bool write_resume_data(entry& rd) const { return false; }
// virtual boost::int64_t physical_offset(int slot, int offset) // virtual boost::int64_t physical_offset(int slot, int offset)
// { return slot * m_files.piece_length() + 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 // 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 // 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. // 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 // This function should fill in resume data, the current state of the
// storage, in ``rd``. The default storage adds file timestamps and // storage, in ``rd``. The default storage adds file timestamps and
@ -423,7 +423,7 @@ namespace libtorrent
void initialize(storage_error& ec); void initialize(storage_error& ec);
int move_storage(std::string const& save_path, int flags, storage_error& ec); int move_storage(std::string const& save_path, int flags, storage_error& ec);
int sparse_end(int start) const; 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; void write_resume_data(entry& rd, storage_error& ec) const;
bool tick(); bool tick();
@ -519,7 +519,7 @@ namespace libtorrent
int writev(file::iovec_t const* bufs, int num_bufs, int piece int writev(file::iovec_t const* bufs, int num_bufs, int piece
, int offset, int flags, storage_error& ec); , 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 {} void write_resume_data(entry&, storage_error&) const {}
int m_piece_size; int m_piece_size;
@ -541,7 +541,7 @@ namespace libtorrent
, storage_error&) {} , storage_error&) {}
virtual int move_storage(std::string const& /* save_path */ virtual int move_storage(std::string const& /* save_path */
, int /* flags */, storage_error&) { return 0; } , 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; } { return false; }
virtual void write_resume_data(entry&, storage_error&) const {} virtual void write_resume_data(entry&, storage_error&) const {}
virtual void release_files(storage_error&) {} virtual void release_files(storage_error&) {}
@ -674,7 +674,7 @@ namespace libtorrent
// the error message indicates that the fast resume data was rejected // the error message indicates that the fast resume data was rejected
// if 'fatal_disk_error' is returned, the error message indicates what // if 'fatal_disk_error' is returned, the error message indicates what
// when wrong in the disk access // 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 // helper functions for check_fastresume
int check_no_fastresume(storage_error& error); int check_no_fastresume(storage_error& error);

View File

@ -116,7 +116,7 @@ namespace libtorrent
struct resume_data_t struct resume_data_t
{ {
std::vector<char> buf; std::vector<char> buf;
lazy_entry entry; bdecode_node node;
}; };
struct time_critical_piece struct time_critical_piece
@ -1019,7 +1019,7 @@ namespace libtorrent
torrent_handle get_handle(); torrent_handle get_handle();
void write_resume_data(entry& rd) const; 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); } void seen_complete() { m_last_seen_complete = time(0); }
int time_since_complete() const { return int(time(0) - m_last_seen_complete); } int time_since_complete() const { return int(time(0) - m_last_seen_complete); }

View File

@ -49,7 +49,7 @@ POSSIBILITY OF SUCH DAMAGE.
#include "libtorrent/config.hpp" #include "libtorrent/config.hpp"
#include "libtorrent/entry.hpp" #include "libtorrent/entry.hpp"
#include "libtorrent/lazy_entry.hpp" #include "libtorrent/bdecode.hpp"
#include "libtorrent/peer_id.hpp" #include "libtorrent/peer_id.hpp"
#include "libtorrent/time.hpp" #include "libtorrent/time.hpp"
#include "libtorrent/assert.hpp" #include "libtorrent/assert.hpp"
@ -280,10 +280,10 @@ namespace libtorrent
// metadata will be created by libtorrent as soon as it has been // metadata will be created by libtorrent as soon as it has been
// downloaded from the swarm. // 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 // object from the information found in the given torrent_file. The
// lazy_entry represents a tree node in an bencoded file. To load an // bdecode_node represents a tree node in an bencoded file. To load an
// ordinary .torrent file into a lazy_entry, use lazy_bdecode(). // ordinary .torrent file into a bdecode_node, use bdecode().
// //
// The version that takes a buffer pointer and a size will decode it as a // 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. // .torrent file and initialize the torrent_info object for you.
@ -306,7 +306,7 @@ namespace libtorrent
// //
// The ``flags`` argument is currently unused. // The ``flags`` argument is currently unused.
#ifndef BOOST_NO_EXCEPTIONS #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(char const* buffer, int size, int flags = 0);
torrent_info(std::string const& filename, int flags = 0); torrent_info(std::string const& filename, int flags = 0);
#ifndef TORRENT_NO_DEPRECATE #ifndef TORRENT_NO_DEPRECATE
@ -317,18 +317,24 @@ namespace libtorrent
torrent_info(std::wstring const& filename, int flags = 0) TORRENT_DEPRECATED; torrent_info(std::wstring const& filename, int flags = 0) TORRENT_DEPRECATED;
#endif // TORRENT_USE_WSTRING #endif // TORRENT_USE_WSTRING
#endif // TORRENT_NO_DEPRECATE #endif // TORRENT_NO_DEPRECATE
#endif #endif // BOOST_NO_EXCEPTIONS
torrent_info(torrent_info const& t); torrent_info(torrent_info const& t);
torrent_info(sha1_hash const& info_hash, int flags = 0); 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(char const* buffer, int size, error_code& ec, int flags = 0);
torrent_info(std::string const& filename, error_code& ec, int flags = 0); torrent_info(std::string const& filename, error_code& ec, int flags = 0);
#ifndef TORRENT_NO_DEPRECATE #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 #if TORRENT_USE_WSTRING
// all wstring APIs are deprecated since 0.16.11 instead, use the wchar // all wstring APIs are deprecated since 0.16.11 instead, use the wchar
// -> utf8 conversion functions and pass in utf8 strings // -> utf8 conversion functions and pass in utf8 strings
TORRENT_DEPRECATED_PREFIX 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_USE_WSTRING
#endif // TORRENT_NO_DEPRECATE #endif // TORRENT_NO_DEPRECATE
@ -413,6 +419,11 @@ namespace libtorrent
std::vector<std::string> url_seeds() const TORRENT_DEPRECATED; std::vector<std::string> url_seeds() const TORRENT_DEPRECATED;
TORRENT_DEPRECATED_PREFIX TORRENT_DEPRECATED_PREFIX
std::vector<std::string> http_seeds() const TORRENT_DEPRECATED; std::vector<std::string> 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 #endif // TORRENT_NO_DEPRECATE
// ``web_seeds()`` returns all url seeds and http seeds in the torrent. // ``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. // populates the torrent_info by providing just the info-dict buffer.
// This is used when loading a torrent from a magnet link for instance, // 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 // parsed info-dictionary. ``ec`` returns an error code if something
// fails (typically if the info dictionary is malformed). ``flags`` are // fails (typically if the info dictionary is malformed). ``flags`` are
// currently unused. // 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 // 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. It can be used to access extension values put in the
// .torrent file. If the specified key cannot be found, it returns NULL. // .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; 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); + m_info_section_size, m_info_dict, ec);
if (ec) return NULL; if (ec) return bdecode_node();
} }
return m_info_dict.dict_find(key); return m_info_dict.dict_find(key);
} }
@ -670,7 +681,7 @@ namespace libtorrent
// __ http://bittorrent.org/beps/bep_0030.html // __ http://bittorrent.org/beps/bep_0030.html
bool is_merkle_torrent() const { return !m_merkle_tree.empty(); } 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 // if we're logging member offsets, we need access to them
private: private:
@ -726,7 +737,7 @@ namespace libtorrent
// the info section parsed. points into m_info_section // the info section parsed. points into m_info_section
// parsed lazily // parsed lazily
mutable lazy_entry m_info_dict; mutable bdecode_node m_info_dict;
// if a creation date is found in the torrent file // if a creation date is found in the torrent file
// this will be set to that, otherwise it'll be // this will be set to that, otherwise it'll be

View File

@ -43,6 +43,7 @@ libtorrent_rasterbar_la_SOURCES = \
bandwidth_limit.cpp \ bandwidth_limit.cpp \
bandwidth_manager.cpp \ bandwidth_manager.cpp \
bandwidth_queue_entry.cpp \ bandwidth_queue_entry.cpp \
bdecode.cpp \
bloom_filter.cpp \ bloom_filter.cpp \
broadcast_socket.cpp \ broadcast_socket.cpp \
block_cache.cpp \ block_cache.cpp \

1081
src/bdecode.cpp Normal file

File diff suppressed because it is too large Load Diff

View File

@ -1263,9 +1263,9 @@ namespace libtorrent
#ifdef TORRENT_LOGGING #ifdef TORRENT_LOGGING
peer_log("<== HASHPIECE [ piece: %d list: %d ]", p.piece, list_size); peer_log("<== HASHPIECE [ piece: %d list: %d ]", p.piece, list_size);
#endif #endif
lazy_entry hash_list; bdecode_node hash_list;
error_code ec; 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) , hash_list, ec) != 0)
{ {
disconnect(errors::invalid_hash_piece, op_bittorrent, 2); disconnect(errors::invalid_hash_piece, op_bittorrent, 2);
@ -1274,7 +1274,7 @@ namespace libtorrent
// the list has this format: // the list has this format:
// [ [node-index, hash], [node-index, hash], ... ] // [ [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); disconnect(errors::invalid_hash_list, op_bittorrent, 2);
return; return;
@ -1283,15 +1283,15 @@ namespace libtorrent
std::map<int, sha1_hash> nodes; std::map<int, sha1_hash> nodes;
for (int i = 0; i < hash_list.list_size(); ++i) for (int i = 0; i < hash_list.list_size(); ++i)
{ {
lazy_entry const* e = hash_list.list_at(i); bdecode_node e = hash_list.list_at(i);
if (e->type() != lazy_entry::list_t if (e.type() != bdecode_node::list_t
|| e->list_size() != 2 || e.list_size() != 2
|| e->list_at(0)->type() != lazy_entry::int_t || e.list_at(0).type() != bdecode_node::int_t
|| e->list_at(1)->type() != lazy_entry::string_t || e.list_at(1).type() != bdecode_node::string_t
|| e->list_at(1)->string_length() != 20) continue; || e.list_at(1).string_length() != 20) continue;
nodes.insert(std::make_pair(int(e->list_int_value_at(0)) nodes.insert(std::make_pair(int(e.list_int_value_at(0))
, sha1_hash(e->list_at(1)->string_ptr()))); , sha1_hash(e.list_at(1).string_ptr())));
} }
if (!nodes.empty() && !t->add_merkle_nodes(nodes, p.piece)) 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(); buffer::const_interval recv_buffer = m_recv_buffer.get();
lazy_entry root; bdecode_node root;
error_code ec; error_code ec;
int pos; int pos;
int ret = lazy_bdecode(recv_buffer.begin + 2, recv_buffer.end, root, ec, &pos); int ret = bdecode(recv_buffer.begin + 2, recv_buffer.end, root, ec, &pos);
if (ret != 0 || ec || root.type() != lazy_entry::dict_t) if (ret != 0 || ec || root.type() != bdecode_node::dict_t)
{ {
#ifdef TORRENT_LOGGING #ifdef TORRENT_LOGGING
peer_log("*** invalid extended handshake: %s pos: %d" peer_log("*** invalid extended handshake: %s pos: %d"
@ -1813,11 +1813,11 @@ namespace libtorrent
if (is_disconnecting()) return; if (is_disconnecting()) return;
// upload_only // 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_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_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_dont_have_id = boost::uint8_t(m.dict_find_int_value("lt_donthave", 0));
} }
// there is supposed to be a remote listen port // there is supposed to be a remote listen port

View File

@ -1902,7 +1902,7 @@ namespace libtorrent
} }
void disk_io_thread::async_check_fastresume(piece_manager* storage void disk_io_thread::async_check_fastresume(piece_manager* storage
, lazy_entry const* resume_data , bdecode_node const* resume_data
, boost::function<void(disk_io_job const*)> const& handler) , boost::function<void(disk_io_job const*)> const& handler)
{ {
#ifdef TORRENT_DEBUG #ifdef TORRENT_DEBUG
@ -2603,8 +2603,8 @@ namespace libtorrent
// if this assert fails, something's wrong with the fence logic // if this assert fails, something's wrong with the fence logic
TORRENT_ASSERT(j->storage->num_outstanding_jobs() == 1); TORRENT_ASSERT(j->storage->num_outstanding_jobs() == 1);
lazy_entry const* rd = (lazy_entry const*)j->buffer; bdecode_node const* rd = (bdecode_node const*)j->buffer;
lazy_entry tmp; bdecode_node tmp;
if (rd == NULL) rd = &tmp; if (rd == NULL) rd = &tmp;
return j->storage->check_fastresume(*rd, j->error); return j->storage->check_fastresume(*rd, j->error);

View File

@ -38,7 +38,10 @@ POSSIBILITY OF SUCH DAMAGE.
#include "libtorrent/entry.hpp" #include "libtorrent/entry.hpp"
#include "libtorrent/config.hpp" #include "libtorrent/config.hpp"
#include "libtorrent/escape_string.hpp" #include "libtorrent/escape_string.hpp"
#ifndef TORRENT_NO_DEPRECATE
#include "libtorrent/lazy_entry.hpp" #include "libtorrent/lazy_entry.hpp"
#endif
#include "libtorrent/bdecode.hpp"
#include "libtorrent/escape_string.hpp" #include "libtorrent/escape_string.hpp"
#if defined(_MSC_VER) #if defined(_MSC_VER)
@ -314,6 +317,44 @@ namespace libtorrent
m_type = int_t; 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<std::string, bdecode_node> 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 // convert a lazy_entry into an old skool entry
void entry::operator=(lazy_entry const& e) void entry::operator=(lazy_entry const& e)
{ {
@ -350,6 +391,7 @@ namespace libtorrent
break; break;
} }
} }
#endif
void entry::operator=(dictionary_type const& v) void entry::operator=(dictionary_type const& v)
{ {

View File

@ -377,18 +377,18 @@ namespace libtorrent
close(); 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) // 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()); ec.assign(errors::invalid_peer_dict, get_libtorrent_category());
return false; return false;
} }
lazy_entry const* i = info.dict_find_string("peer id"); bdecode_node i = info.dict_find_string("peer id");
if (i != 0 && i->string_length() == 20) 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 else
{ {
@ -403,7 +403,7 @@ namespace libtorrent
ec.assign(errors::invalid_tracker_response, get_libtorrent_category()); ec.assign(errors::invalid_tracker_response, get_libtorrent_category());
return false; return false;
} }
ret.hostname = i->string_value(); ret.hostname = i.string_value();
// extract port // extract port
i = info.dict_find_int("port"); i = info.dict_find_int("port");
@ -412,7 +412,7 @@ namespace libtorrent
ec.assign(errors::invalid_tracker_response, get_libtorrent_category()); ec.assign(errors::invalid_tracker_response, get_libtorrent_category());
return false; return false;
} }
ret.port = (unsigned short)i->int_value(); ret.port = (unsigned short)i.int_value();
return true; return true;
} }
@ -422,12 +422,12 @@ namespace libtorrent
{ {
tracker_response resp; tracker_response resp;
lazy_entry e; bdecode_node e;
int res = lazy_bdecode(data, data + size, e, ec); int res = bdecode(data, data + size, e, ec);
if (ec) return resp; 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()); ec.assign(errors::invalid_tracker_response, get_libtorrent_category());
return resp; return resp;
@ -441,45 +441,45 @@ namespace libtorrent
resp.interval = interval; resp.interval = interval;
resp.min_interval = min_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) if (tracker_id)
resp.trackerid = tracker_id->string_value(); resp.trackerid = tracker_id.string_value();
// parse the response // parse the response
lazy_entry const* failure = e.dict_find_string("failure reason"); bdecode_node failure = e.dict_find_string("failure reason");
if (failure) if (failure)
{ {
resp.failure_reason = failure->string_value(); resp.failure_reason = failure.string_value();
ec.assign(errors::tracker_failure, get_libtorrent_category()); ec.assign(errors::tracker_failure, get_libtorrent_category());
return resp; return resp;
} }
lazy_entry const* warning = e.dict_find_string("warning message"); bdecode_node warning = e.dict_find_string("warning message");
if (warning) if (warning)
resp.warning_message = warning->string_value(); resp.warning_message = warning.string_value();
if (scrape_request) if (scrape_request)
{ {
lazy_entry const* files = e.dict_find_dict("files"); bdecode_node files = e.dict_find_dict("files");
if (files == 0) if (!files)
{ {
ec.assign(errors::invalid_files_entry, get_libtorrent_category()); ec.assign(errors::invalid_files_entry, get_libtorrent_category());
return resp; return resp;
} }
lazy_entry const* scrape_data = files->dict_find_dict( bdecode_node scrape_data = files.dict_find_dict(
scrape_ih.to_string()); scrape_ih.to_string());
if (scrape_data == 0) if (!scrape_data)
{ {
ec.assign(errors::invalid_hash_entry, get_libtorrent_category()); ec.assign(errors::invalid_hash_entry, get_libtorrent_category());
return resp; return resp;
} }
resp.complete = int(scrape_data->dict_find_int_value("complete", -1)); resp.complete = int(scrape_data.dict_find_int_value("complete", -1));
resp.incomplete = int(scrape_data->dict_find_int_value("incomplete", -1)); resp.incomplete = int(scrape_data.dict_find_int_value("incomplete", -1));
resp.downloaded = int(scrape_data->dict_find_int_value("downloaded", -1)); resp.downloaded = int(scrape_data.dict_find_int_value("downloaded", -1));
resp.downloaders = int(scrape_data->dict_find_int_value("downloaders", -1)); resp.downloaders = int(scrape_data.dict_find_int_value("downloaders", -1));
return resp; return resp;
} }
@ -489,11 +489,11 @@ namespace libtorrent
resp.incomplete = int(e.dict_find_int_value("incomplete", -1)); resp.incomplete = int(e.dict_find_int_value("incomplete", -1));
resp.downloaded = int(e.dict_find_int_value("downloaded", -1)); resp.downloaded = int(e.dict_find_int_value("downloaded", -1));
lazy_entry const* peers_ent = e.dict_find("peers"); bdecode_node peers_ent = e.dict_find("peers");
if (peers_ent && peers_ent->type() == lazy_entry::string_t) if (peers_ent && peers_ent.type() == bdecode_node::string_t)
{ {
char const* peers = peers_ent->string_ptr(); char const* peers = peers_ent.string_ptr();
int len = peers_ent->string_length(); int len = peers_ent.string_length();
resp.peers4.reserve(len / 6); resp.peers4.reserve(len / 6);
for (int i = 0; i < len; i += 6) for (int i = 0; i < len; i += 6)
{ {
@ -506,15 +506,15 @@ namespace libtorrent
resp.peers4.push_back(p); 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); resp.peers.reserve(len);
error_code parse_error; error_code parse_error;
for (int i = 0; i < len; ++i) for (int i = 0; i < len; ++i)
{ {
peer_entry p; 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; continue;
resp.peers.push_back(p); resp.peers.push_back(p);
} }
@ -528,15 +528,15 @@ namespace libtorrent
} }
else else
{ {
peers_ent = 0; peers_ent.clear();
} }
#if TORRENT_USE_IPV6 #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) if (ipv6_peers)
{ {
char const* peers = ipv6_peers->string_ptr(); char const* peers = ipv6_peers.string_ptr();
int len = ipv6_peers->string_length(); int len = ipv6_peers.string_length();
resp.peers6.reserve(len / 18); resp.peers6.reserve(len / 18);
for (int i = 0; i < len; i += 18) for (int i = 0; i < len; i += 18)
{ {
@ -550,10 +550,10 @@ namespace libtorrent
} }
else else
{ {
ipv6_peers = 0; ipv6_peers.clear();
} }
#else #else
lazy_entry const* ipv6_peers = 0; bdecode_node ipv6_peers = 0;
#endif #endif
/* /*
// if we didn't receive any peers. We don't care if we're stopping anyway // if we didn't receive any peers. We don't care if we're stopping anyway
@ -564,14 +564,14 @@ namespace libtorrent
return resp; 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) if (ip_ent)
{ {
char const* p = ip_ent->string_ptr(); char const* p = ip_ent.string_ptr();
if (ip_ent->string_length() == int(address_v4::bytes_type().size())) if (ip_ent.string_length() == int(address_v4::bytes_type().size()))
resp.external_ip = detail::read_v4_address(p); resp.external_ip = detail::read_v4_address(p);
#if TORRENT_USE_IPV6 #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); resp.external_ip = detail::read_v6_address(p);
#endif #endif
} }

View File

@ -72,9 +72,9 @@ namespace libtorrent { namespace dht
void incoming_error(entry& e, char const* msg); void incoming_error(entry& e, char const* msg);
#ifdef TORRENT_DHT_VERBOSE_LOGGING #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"; if (!ver) return "generic";
std::string const& client = ver->string_value(); std::string const& client = ver->string_value();
if (client.size() < 2) if (client.size() < 2)
@ -116,12 +116,12 @@ namespace libtorrent { namespace dht
TORRENT_DEFINE_LOG(dht_tracker) TORRENT_DEFINE_LOG(dht_tracker)
#endif #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)(); if (!e || e.type() != bdecode_node::dict_t) return (node_id::min)();
lazy_entry const* nid = e->dict_find_string("node-id"); bdecode_node nid = e.dict_find_string("node-id");
if (nid == 0 || nid->string_length() != 20) return (node_id::min)(); if (!nid || nid.string_length() != 20) return (node_id::min)();
return node_id(node_id(nid->string_ptr())); return node_id(node_id(nid.string_ptr()));
} }
node_id extract_node_id(entry const* e) 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 // class that puts the networking and the kademlia node in a single
// unit and connecting them together. // 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) , dht_settings const& settings, counters& cnt, entry const* state)
: m_counters(cnt) : m_counters(cnt)
, m_dht(&ses, this, settings, extract_node_id(state) , m_dht(&ses, this, settings, extract_node_id(state)
@ -391,10 +392,9 @@ namespace libtorrent { namespace dht
TORRENT_ASSERT(size > 0); TORRENT_ASSERT(size > 0);
lazy_entry e;
int pos; int pos;
error_code err; 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) if (ret != 0)
{ {
#ifdef TORRENT_DHT_VERBOSE_LOGGING #ifdef TORRENT_DHT_VERBOSE_LOGGING
@ -404,9 +404,7 @@ namespace libtorrent { namespace dht
return false; return false;
} }
libtorrent::dht::msg m(e, ep); if (m_msg.type() != bdecode_node::dict_t)
if (e.type() != lazy_entry::dict_t)
{ {
#ifdef TORRENT_DHT_VERBOSE_LOGGING #ifdef TORRENT_DHT_VERBOSE_LOGGING
TORRENT_LOG(dht_tracker) << "<== " << ep << " ERROR: not a dictionary: " TORRENT_LOG(dht_tracker) << "<== " << ep << " ERROR: not a dictionary: "
@ -420,6 +418,7 @@ namespace libtorrent { namespace dht
return false; return false;
} }
libtorrent::dht::msg m(m_msg, ep);
m_dht.incoming(m); m_dht.incoming(m);
return true; return true;
} }
@ -503,8 +502,8 @@ namespace libtorrent { namespace dht
#ifdef TORRENT_DHT_VERBOSE_LOGGING #ifdef TORRENT_DHT_VERBOSE_LOGGING
std::stringstream log_line; std::stringstream log_line;
lazy_entry print; bdecode_node print;
int ret = lazy_bdecode(&m_send_buf[0], &m_send_buf[0] + m_send_buf.size(), print, ec); int ret = bdecode(&m_send_buf[0], &m_send_buf[0] + m_send_buf.size(), print, ec);
TORRENT_ASSERT(ret == 0); TORRENT_ASSERT(ret == 0);
log_line << print_entry(print, true); log_line << print_entry(print, true);
#endif #endif

View File

@ -54,7 +54,7 @@ using detail::read_v6_endpoint;
void find_data_observer::reply(msg const& m) 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) if (!r)
{ {
#ifdef TORRENT_DHT_VERBOSE_LOGGING #ifdef TORRENT_DHT_VERBOSE_LOGGING
@ -63,19 +63,19 @@ void find_data_observer::reply(msg const& m)
return; return;
} }
lazy_entry const* id = r->dict_find_string("id"); bdecode_node id = r.dict_find_string("id");
if (!id || id->string_length() != 20) if (!id || id.string_length() != 20)
{ {
#ifdef TORRENT_DHT_VERBOSE_LOGGING #ifdef TORRENT_DHT_VERBOSE_LOGGING
TORRENT_LOG(traversal) << "[" << m_algorithm.get() << "] invalid id in response"; TORRENT_LOG(traversal) << "[" << m_algorithm.get() << "] invalid id in response";
#endif #endif
return; return;
} }
lazy_entry const* token = r->dict_find_string("token"); bdecode_node token = r.dict_find_string("token");
if (token) if (token)
{ {
static_cast<find_data*>(m_algorithm.get())->got_write_token( static_cast<find_data*>(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); traversal_observer::reply(m);

View File

@ -42,7 +42,7 @@ POSSIBILITY OF SUCH DAMAGE.
namespace libtorrent { namespace dht 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, char const* pk,
boost::uint64_t seq, boost::uint64_t seq,
char const* sig) char const* sig)
@ -55,7 +55,7 @@ void get_item::got_data(lazy_entry const* v,
if (pk) if (pk)
incoming_target = item_target_id(salt, pk); incoming_target = item_target_id(salt, pk);
else else
incoming_target = item_target_id(v->data_section()); incoming_target = item_target_id(v.data_section());
if (incoming_target != m_target) return; if (incoming_target != m_target) return;
@ -248,7 +248,7 @@ void get_item_observer::reply(msg const& m)
char const* sig = NULL; char const* sig = NULL;
boost::uint64_t seq = 0; 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) if (!r)
{ {
#ifdef TORRENT_DHT_VERBOSE_LOGGING #ifdef TORRENT_DHT_VERBOSE_LOGGING
@ -257,21 +257,21 @@ void get_item_observer::reply(msg const& m)
return; return;
} }
lazy_entry const* k = r->dict_find_string("k"); bdecode_node k = r.dict_find_string("k");
if (k && k->string_length() == item_pk_len) if (k && k.string_length() == item_pk_len)
pk = k->string_ptr(); pk = k.string_ptr();
lazy_entry const* s = r->dict_find_string("sig"); bdecode_node s = r.dict_find_string("sig");
if (s && s->string_length() == item_sig_len) if (s && s.string_length() == item_sig_len)
sig = s->string_ptr(); sig = s.string_ptr();
lazy_entry const* q = r->dict_find_int("seq"); bdecode_node q = r.dict_find_int("seq");
if (q) if (q)
seq = q->int_value(); seq = q.int_value();
else if (pk && sig) else if (pk && sig)
return; return;
lazy_entry const* v = r->dict_find("v"); bdecode_node v = r.dict_find("v");
if (v) if (v)
{ {
static_cast<get_item*>(m_algorithm.get())->got_data(v, pk, seq, sig); static_cast<get_item*>(m_algorithm.get())->got_data(v, pk, seq, sig);

View File

@ -47,7 +47,7 @@ using detail::read_v6_endpoint;
void get_peers_observer::reply(msg const& m) 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) if (!r)
{ {
#ifdef TORRENT_DHT_VERBOSE_LOGGING #ifdef TORRENT_DHT_VERBOSE_LOGGING
@ -57,27 +57,27 @@ void get_peers_observer::reply(msg const& m)
} }
// look for peers // look for peers
lazy_entry const* n = r->dict_find_list("values"); bdecode_node n = r.dict_find_list("values");
if (n) if (n)
{ {
std::vector<tcp::endpoint> peer_list; std::vector<tcp::endpoint> 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 // assume it's mainline format
char const* peers = n->list_at(0)->string_ptr(); char const* peers = n.list_at(0).string_ptr();
char const* end = peers + n->list_at(0)->string_length(); char const* end = peers + n.list_at(0).string_length();
#ifdef TORRENT_DHT_VERBOSE_LOGGING #ifdef TORRENT_DHT_VERBOSE_LOGGING
lazy_entry const* id = r->dict_find_string("id"); bdecode_node id = r.dict_find_string("id");
if (id && id->string_length() == 20) if (id && id.string_length() == 20)
{ {
TORRENT_LOG(traversal) TORRENT_LOG(traversal)
<< "[" << m_algorithm.get() << "] PEERS" << "[" << m_algorithm.get() << "] PEERS"
<< " invoke-count: " << m_algorithm->invoke_count() << " invoke-count: " << m_algorithm.invoke_count()
<< " branch-factor: " << m_algorithm->branch_factor() << " branch-factor: " << m_algorithm.branch_factor()
<< " addr: " << m.addr << " 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())) << " distance: " << distance_exp(m_algorithm.target(), node_id(id.string_ptr()))
<< " p: " << ((end - peers) / 6); << " p: " << ((end - peers) / 6);
} }
#endif #endif
@ -89,17 +89,17 @@ void get_peers_observer::reply(msg const& m)
// assume it's uTorrent/libtorrent format // assume it's uTorrent/libtorrent format
read_endpoint_list<tcp::endpoint>(n, peer_list); read_endpoint_list<tcp::endpoint>(n, peer_list);
#ifdef TORRENT_DHT_VERBOSE_LOGGING #ifdef TORRENT_DHT_VERBOSE_LOGGING
lazy_entry const* id = r->dict_find_string("id"); bdecode_node id = r.dict_find_string("id");
if (id && id->string_length() == 20) if (id && id.string_length() == 20)
{ {
TORRENT_LOG(traversal) TORRENT_LOG(traversal)
<< "[" << m_algorithm.get() << "] PEERS" << "[" << m_algorithm.get() << "] PEERS"
<< " invoke-count: " << m_algorithm->invoke_count() << " invoke-count: " << m_algorithm->invoke_count()
<< " branch-factor: " << m_algorithm->branch_factor() << " branch-factor: " << m_algorithm->branch_factor()
<< " addr: " << m.addr << " 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())) << " distance: " << distance_exp(m_algorithm->target(), node_id(id->string_ptr()))
<< " p: " << n->list_size(); << " p: " << n.list_size();
} }
#endif #endif
} }
@ -295,7 +295,7 @@ void obfuscated_get_peers::done()
void obfuscated_get_peers_observer::reply(msg const& m) 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) if (!r)
{ {
#ifdef TORRENT_DHT_VERBOSE_LOGGING #ifdef TORRENT_DHT_VERBOSE_LOGGING
@ -305,8 +305,8 @@ void obfuscated_get_peers_observer::reply(msg const& m)
return; return;
} }
lazy_entry const* id = r->dict_find_string("id"); bdecode_node id = r.dict_find_string("id");
if (!id || id->string_length() != 20) if (!id || id.string_length() != 20)
{ {
#ifdef TORRENT_DHT_VERBOSE_LOGGING #ifdef TORRENT_DHT_VERBOSE_LOGGING
TORRENT_LOG(traversal) << "[" << m_algorithm.get() TORRENT_LOG(traversal) << "[" << m_algorithm.get()

View File

@ -36,7 +36,7 @@ POSSIBILITY OF SUCH DAMAGE.
#include <libtorrent/ed25519.hpp> #include <libtorrent/ed25519.hpp>
#ifdef TORRENT_DEBUG #ifdef TORRENT_DEBUG
#include "libtorrent/lazy_entry.hpp" #include "libtorrent/bdecode.hpp"
#endif #endif
#ifdef TORRENT_USE_VALGRIND #ifdef TORRENT_USE_VALGRIND
@ -54,9 +54,9 @@ namespace
{ {
// v must be valid bencoding! // v must be valid bencoding!
#ifdef TORRENT_DEBUG #ifdef TORRENT_DEBUG
lazy_entry e; bdecode_node e;
error_code ec; 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 #endif
char* ptr = out; char* ptr = out;
@ -185,14 +185,14 @@ void item::assign(entry const& v, std::pair<char const*, int> salt
m_mutable = false; m_mutable = false;
} }
bool item::assign(lazy_entry const* v bool item::assign(bdecode_node const& v
, std::pair<char const*, int> salt , std::pair<char const*, int> salt
, boost::uint64_t seq, char const* pk, char const* sig) , 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 (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; return false;
memcpy(m_pk.c_array(), pk, item_pk_len); memcpy(m_pk.c_array(), pk, item_pk_len);
memcpy(m_sig.c_array(), sig, item_sig_len); memcpy(m_sig.c_array(), sig, item_sig_len);
@ -206,7 +206,7 @@ bool item::assign(lazy_entry const* v
else else
m_mutable = false; m_mutable = false;
m_value = *v; m_value = v;
return true; return true;
} }

View File

@ -221,44 +221,44 @@ void node_impl::unreachable(udp::endpoint const& ep)
void node_impl::incoming(msg const& m) void node_impl::incoming(msg const& m)
{ {
// is this a reply? // is this a reply?
lazy_entry const* y_ent = m.message.dict_find_string("y"); bdecode_node y_ent = m.message.dict_find_string("y");
if (!y_ent || y_ent->string_length() == 0) if (!y_ent || y_ent.string_length() == 0)
{ {
// don't respond to this obviously broken messages. We don't // don't respond to this obviously broken messages. We don't
// want to open up a magnification opportunity // want to open up a magnification opportunity
// entry e; // entry e;
// incoming_error(e, "missing 'y' entry"); // incoming_error(e, "missing 'y' entry");
// m_sock->send_packet(e, m.addr, 0); // m_sock.send_packet(e, m.addr, 0);
return; 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 // 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) if (r)
ext_ip = r->dict_find_string("ip"); ext_ip = r.dict_find_string("ip");
} }
#if TORRENT_USE_IPV6 #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! // this node claims we use the wrong node-ID!
address_v6::bytes_type b; address_v6::bytes_type b;
memcpy(&b[0], ext_ip->string_ptr(), 16); memcpy(&b[0], ext_ip.string_ptr(), 16);
if (m_observer) if (m_observer)
m_observer->set_external_address(address_v6(b) m_observer->set_external_address(address_v6(b)
, m.addr.address()); , m.addr.address());
} else } else
#endif #endif
if (ext_ip && ext_ip->string_length() >= 4) if (ext_ip && ext_ip.string_length() >= 4)
{ {
address_v4::bytes_type b; address_v4::bytes_type b;
memcpy(&b[0], ext_ip->string_ptr(), 4); memcpy(&b[0], ext_ip.string_ptr(), 4);
if (m_observer) if (m_observer)
m_observer->set_external_address(address_v4(b) m_observer->set_external_address(address_v4(b)
, m.addr.address()); , m.addr.address());
@ -283,10 +283,10 @@ void node_impl::incoming(msg const& m)
case 'e': case 'e':
{ {
#ifdef TORRENT_DHT_VERBOSE_LOGGING #ifdef TORRENT_DHT_VERBOSE_LOGGING
lazy_entry const* err = m.message.dict_find_list("e"); bdecode_node err = m.message.dict_find_list("e");
if (err && err->list_size() >= 2) 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 #endif
node_id id; node_id id;
@ -419,7 +419,7 @@ struct ping_observer : observer
{ {
flags |= flag_done; flags |= flag_done;
lazy_entry const* r = m.message.dict_find_dict("r"); bdecode_node r = m.message.dict_find_dict("r");
if (!r) if (!r)
{ {
#ifdef TORRENT_DHT_VERBOSE_LOGGING #ifdef TORRENT_DHT_VERBOSE_LOGGING
@ -430,11 +430,11 @@ struct ping_observer : observer
} }
// look for nodes // look for nodes
lazy_entry const* n = r->dict_find_string("nodes"); bdecode_node n = r.dict_find_string("nodes");
if (n) if (n)
{ {
char const* nodes = n->string_ptr(); char const* nodes = n.string_ptr();
char const* end = nodes + n->string_length(); char const* end = nodes + n.string_length();
while (end - nodes >= 26) while (end - nodes >= 26)
{ {
@ -674,18 +674,23 @@ using detail::write_nodes_entry;
// verifies that a message has all the required // verifies that a message has all the required
// entries and returns them in ret // entries and returns them in ret
bool verify_message(lazy_entry const* msg, key_desc_t const desc[], lazy_entry const* ret[] bool verify_message(bdecode_node const& message, key_desc_t const desc[]
, int size , char* error, int error_size) , 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 // 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 // when parsing child nodes, this is the stack
// of lazy_entry pointers to return to // of bdecode_nodes to return to
lazy_entry const* stack[5]; bdecode_node stack[5];
int stack_ptr = -1; 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"); snprintf(error, error_size, "not a dictionary");
return false; 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()); // 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 // 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) if (ret[i] == 0 && (k.flags & key_desc_t::optional) == 0)
{ {
// the key was not found, and it's not an optional key // 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 if (k.size > 0
&& ret[i] && ret[i]
&& k.type == lazy_entry::string_t) && k.type == bdecode_node::string_t)
{ {
bool invalid = false; bool invalid = false;
if (k.flags & key_desc_t::size_divisible) 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 else
invalid = ret[i]->string_length() != k.size; invalid = ret[i].string_length() != k.size;
if (invalid) if (invalid)
{ {
// the string was not of the required size // the string was not of the required size
ret[i] = 0; ret[i].clear();
if ((k.flags & key_desc_t::optional) == 0) if ((k.flags & key_desc_t::optional) == 0)
{ {
snprintf(error, error_size, "invalid value for '%s'", k.name); 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) 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]) 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"); e["t"] = m.message.dict_find_string_value("t");
key_desc_t top_desc[] = { key_desc_t top_desc[] = {
{"q", lazy_entry::string_t, 0, 0}, {"q", bdecode_node::string_t, 0, 0},
{"ro", lazy_entry::int_t, 0, key_desc_t::optional}, {"ro", bdecode_node::int_t, 0, key_desc_t::optional},
{"a", lazy_entry::dict_t, 0, key_desc_t::parse_children}, {"a", bdecode_node::dict_t, 0, key_desc_t::parse_children},
{"id", lazy_entry::string_t, 20, key_desc_t::last_child}, {"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]; 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); incoming_error(e, error_string);
return; return;
@ -821,11 +828,12 @@ void node_impl::incoming_request(msg const& m, entry& e)
e["ip"] = endpoint_to_bytes(m.addr); 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]; bdecode_node arg_ent = top_level[2];
bool read_only = top_level[1] && top_level[1]->int_value() != 0; bool read_only = top_level[1] && top_level[1].int_value() != 0;
node_id id(top_level[3]->string_ptr()); node_id id(top_level[3].string_ptr());
// if this nodes ID doesn't match its IP, tell it what // if this nodes ID doesn't match its IP, tell it what
// its IP is with an error // 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 // mirror back the other node's external port
reply["p"] = m.addr.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); m_counters.inc_stats_counter(counters::dht_ping_in);
// we already have 't' and 'id' in the response // we already have 't' and 'id' in the response
// no more left to add // 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[] = { key_desc_t msg_desc[] = {
{"info_hash", lazy_entry::string_t, 20, 0}, {"info_hash", bdecode_node::string_t, 20, 0},
{"noseed", lazy_entry::int_t, 0, key_desc_t::optional}, {"noseed", bdecode_node::int_t, 0, key_desc_t::optional},
{"scrape", lazy_entry::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 if (!verify_message(arg_ent, msg_desc, msg_keys, 3, error_string
, sizeof(error_string))) , sizeof(error_string)))
{ {
@ -868,11 +876,11 @@ void node_impl::incoming_request(msg const& m, entry& e)
return; 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); 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; nodes_t n;
// always return nodes as well as peers // always return nodes as well as peers
m_table.find_node(info_hash, n, 0); 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 noseed = false;
bool scrape = false; bool scrape = false;
if (msg_keys[1] && msg_keys[1]->int_value() != 0) noseed = 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; if (msg_keys[2] && msg_keys[2].int_value() != 0) scrape = true;
lookup_peers(info_hash, reply, noseed, scrape); lookup_peers(info_hash, reply, noseed, scrape);
#ifdef TORRENT_DHT_VERBOSE_LOGGING #ifdef TORRENT_DHT_VERBOSE_LOGGING
if (reply.find_key("values")) if (reply.find_key("values"))
@ -890,13 +898,13 @@ void node_impl::incoming_request(msg const& m, entry& e)
} }
#endif #endif
} }
else if (strcmp(query, "find_node") == 0) else if (query_len == 9 && memcmp(query, "find_node", 9) == 0)
{ {
key_desc_t msg_desc[] = { 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))) if (!verify_message(arg_ent, msg_desc, msg_keys, 1, error_string, sizeof(error_string)))
{ {
incoming_error(e, 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); 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 // TODO: 2 find_node should write directly to the response entry
nodes_t n; nodes_t n;
m_table.find_node(target, n, 0); m_table.find_node(target, n, 0);
write_nodes_entry(reply, n); 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[] = { key_desc_t msg_desc[] = {
{"info_hash", lazy_entry::string_t, 20, 0}, {"info_hash", bdecode_node::string_t, 20, 0},
{"port", lazy_entry::int_t, 0, 0}, {"port", bdecode_node::int_t, 0, 0},
{"token", lazy_entry::string_t, 0, 0}, {"token", bdecode_node::string_t, 0, 0},
{"n", lazy_entry::string_t, 0, key_desc_t::optional}, {"n", bdecode_node::string_t, 0, key_desc_t::optional},
{"seed", lazy_entry::int_t, 0, key_desc_t::optional}, {"seed", bdecode_node::int_t, 0, key_desc_t::optional},
{"implied_port", lazy_entry::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))) if (!verify_message(arg_ent, msg_desc, msg_keys, 6, error_string, sizeof(error_string)))
{ {
m_counters.inc_stats_counter(counters::dht_invalid_announce); m_counters.inc_stats_counter(counters::dht_invalid_announce);
@ -930,11 +938,11 @@ void node_impl::incoming_request(msg const& m, entry& e)
return; 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 // is the announcer asking to ignore the explicit
// listen port and instead use the source port of the packet? // 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(); port = m.addr.port();
if (port < 0 || port >= 65536) if (port < 0 || port >= 65536)
@ -944,7 +952,7 @@ void node_impl::incoming_request(msg const& m, entry& e)
return; return;
} }
sha1_hash info_hash(msg_keys[0]->string_ptr()); sha1_hash info_hash(msg_keys[0].string_ptr());
if (m_post_alert) 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 (!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); m_counters.inc_stats_counter(counters::dht_invalid_announce);
incoming_error(e, "invalid token"); incoming_error(e, "invalid token");
@ -1001,7 +1009,7 @@ void node_impl::incoming_request(msg const& m, entry& e)
// for this torrent. Store it. // for this torrent. Store it.
if (msg_keys[3] && v->name.empty()) 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); if (name.size() > 50) name.resize(50);
v->name = name; v->name = name;
} }
@ -1009,28 +1017,28 @@ void node_impl::incoming_request(msg const& m, entry& e)
peer_entry peer; peer_entry peer;
peer.addr = tcp::endpoint(m.addr.address(), port); peer.addr = tcp::endpoint(m.addr.address(), port);
peer.added = aux::time_now(); 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<peer_entry>::iterator i = v->peers.find(peer); std::set<peer_entry>::iterator i = v->peers.find(peer);
if (i != v->peers.end()) v->peers.erase(i++); if (i != v->peers.end()) v->peers.erase(i++);
v->peers.insert(i, peer); 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 // the first 2 entries are for both mutable and
// immutable puts // immutable puts
const static key_desc_t msg_desc[] = { const static key_desc_t msg_desc[] = {
{"token", lazy_entry::string_t, 0, 0}, {"token", bdecode_node::string_t, 0, 0},
{"v", lazy_entry::none_t, 0, 0}, {"v", bdecode_node::none_t, 0, 0},
{"seq", lazy_entry::int_t, 0, key_desc_t::optional}, {"seq", bdecode_node::int_t, 0, key_desc_t::optional},
// public key // public key
{"k", lazy_entry::string_t, item_pk_len, key_desc_t::optional}, {"k", bdecode_node::string_t, item_pk_len, key_desc_t::optional},
{"sig", lazy_entry::string_t, item_sig_len, key_desc_t::optional}, {"sig", bdecode_node::string_t, item_sig_len, key_desc_t::optional},
{"cas", lazy_entry::int_t, 0, key_desc_t::optional}, {"cas", bdecode_node::int_t, 0, key_desc_t::optional},
{"salt", lazy_entry::string_t, 0, key_desc_t::optional}, {"salt", bdecode_node::string_t, 0, key_desc_t::optional},
}; };
// attempt to parse the message // 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))) if (!verify_message(arg_ent, msg_desc, msg_keys, 7, error_string, sizeof(error_string)))
{ {
m_counters.inc_stats_counter(counters::dht_invalid_put); 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) // public key (only set if it's a mutable put)
char const* pk = NULL; 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) // signature (only set if it's a mutable put)
char const* sig = NULL; 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 // pointer and length to the whole entry
std::pair<char const*, int> buf = msg_keys[1]->data_section(); std::pair<char const*, int> buf = msg_keys[1].data_section();
if (buf.second > 1000 || buf.second <= 0) if (buf.second > 1000 || buf.second <= 0)
{ {
m_counters.inc_stats_counter(counters::dht_invalid_put); 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<char const*, int> salt(static_cast<char const*>(NULL), 0); std::pair<char const*, int> salt(static_cast<char const*>(NULL), 0);
if (msg_keys[6]) if (msg_keys[6])
salt = std::pair<char const*, int>( salt = std::pair<char const*, int>(
msg_keys[6]->string_ptr(), msg_keys[6]->string_length()); msg_keys[6].string_ptr(), msg_keys[6].string_length());
if (salt.second > 64) if (salt.second > 64)
{ {
m_counters.inc_stats_counter(counters::dht_invalid_put); 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 // verify the write-token. tokens are only valid to write to
// specific target hashes. it must match the one we got a "get" for // 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); m_counters.inc_stats_counter(counters::dht_invalid_put);
incoming_error(e, "invalid token"); 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 // mutable put, we must verify the signature
#ifdef TORRENT_USE_VALGRIND #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); VALGRIND_CHECK_MEM_IS_DEFINED(pk, item_pk_len);
#endif #endif
// msg_keys[4] is the signature, msg_keys[3] is the public key // msg_keys[4] is the signature, msg_keys[3] is the public key
if (!verify_mutable_item(buf, salt 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); m_counters.inc_stats_counter(counters::dht_invalid_put);
incoming_error(e, "invalid signature", 206); 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; dht_mutable_item to_add;
to_add.value = (char*)malloc(buf.second); to_add.value = (char*)malloc(buf.second);
to_add.size = 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 = NULL;
to_add.salt_size = 0; to_add.salt_size = 0;
if (salt.second > 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.salt, salt.first, salt.second);
} }
memcpy(to_add.sig, sig, sizeof(to_add.sig)); 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.value, buf.first, buf.second);
memcpy(&to_add.key, pk, sizeof(to_add.key)); 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 // number matches the expected value before replacing it
// this is critical for avoiding race conditions when multiple // this is critical for avoiding race conditions when multiple
// writers are accessing the same slot // 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); m_counters.inc_stats_counter(counters::dht_invalid_put);
incoming_error(e, "CAS mismatch", 301); incoming_error(e, "CAS mismatch", 301);
return; 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); m_counters.inc_stats_counter(counters::dht_invalid_put);
incoming_error(e, "old sequence number", 302); incoming_error(e, "old sequence number", 302);
return; 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) 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->value = (char*)malloc(buf.second);
item->size = buf.second; item->size = buf.second;
} }
item->seq = msg_keys[2]->int_value(); item->seq = msg_keys[2].int_value();
memcpy(item->sig, msg_keys[4]->string_ptr(), sizeof(item->sig)); memcpy(item->sig, msg_keys[4].string_ptr(), sizeof(item->sig));
TORRENT_ASSERT(sizeof(item->sig) == msg_keys[4]->string_length()); TORRENT_ASSERT(sizeof(item->sig) == msg_keys[4].string_length());
memcpy(item->value, buf.first, buf.second); memcpy(item->value, buf.first, buf.second);
} }
} }
@ -1242,17 +1250,17 @@ void node_impl::incoming_request(msg const& m, entry& e)
++f->num_announcers; ++f->num_announcers;
} }
} }
else if (strcmp(query, "get") == 0) else if (query_len == 3 && memcmp(query, "get", 3) == 0)
{ {
key_desc_t msg_desc[] = { key_desc_t msg_desc[] = {
{"seq", lazy_entry::int_t, 0, key_desc_t::optional}, {"seq", bdecode_node::int_t, 0, key_desc_t::optional},
{"target", lazy_entry::string_t, 20, 0}, {"target", bdecode_node::string_t, 20, 0},
}; };
// k is not used for now // k is not used for now
// attempt to parse the message // 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 if (!verify_message(arg_ent, msg_desc, msg_keys, 2, error_string
, sizeof(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); 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" // fprintf(stderr, "%s GET target: %s\n"
// , msg_keys[1] ? "mutable":"immutable" // , msg_keys[1] ? "mutable":"immutable"
// , to_hex(target.to_string()).c_str()); // , 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; nodes_t n;
// always return nodes as well as peers // 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; dht_mutable_item const& f = i->second;
reply["seq"] = f.seq; 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["v"] = bdecode(f.value, f.value + f.size);
reply["sig"] = std::string(f.sig, f.sig + sizeof(f.sig)); 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 // if we don't recognize the message but there's a
// 'target' or 'info_hash' in the arguments, treat it // 'target' or 'info_hash' in the arguments, treat it
// as find_node to be future compatible // as find_node to be future compatible
lazy_entry const* target_ent = arg_ent->dict_find_string("target"); bdecode_node target_ent = arg_ent.dict_find_string("target");
if (target_ent == 0 || target_ent->string_length() != 20) if (!target_ent || target_ent.string_length() != 20)
{ {
target_ent = arg_ent->dict_find_string("info_hash"); target_ent = arg_ent.dict_find_string("info_hash");
if (target_ent == 0 || target_ent->string_length() != 20) if (!target_ent || target_ent.string_length() != 20)
{ {
incoming_error(e, "unknown message"); incoming_error(e, "unknown message");
return; return;
} }
} }
sha1_hash target(target_ent->string_ptr()); sha1_hash target(target_ent.string_ptr());
nodes_t n; nodes_t n;
// always return nodes as well as peers // always return nodes as well as peers
m_table.find_node(target, n, 0); m_table.find_node(target, n, 0);

View File

@ -324,13 +324,13 @@ bool rpc_manager::incoming(msg const& m, node_id* id, libtorrent::dht_settings c
<< std::endl; << std::endl;
#endif #endif
lazy_entry const* ret_ent = m.message.dict_find_dict("r"); bdecode_node ret_ent = m.message.dict_find_dict("r");
if (ret_ent == 0) if (!ret_ent)
{ {
// it may be an error // it may be an error
ret_ent = m.message.dict_find("e"); ret_ent = m.message.dict_find("e");
o->timeout(); o->timeout();
if (ret_ent == NULL) if (!ret_ent)
{ {
entry e; entry e;
incoming_error(e, "missing 'r' key"); 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; return false;
} }
lazy_entry const* node_id_ent = ret_ent->dict_find_string("id"); bdecode_node node_id_ent = ret_ent.dict_find_string("id");
if (node_id_ent == 0 || node_id_ent->string_length() != 20) if (!node_id_ent || node_id_ent.string_length() != 20)
{ {
o->timeout(); o->timeout();
entry e; entry e;
@ -349,7 +349,7 @@ bool rpc_manager::incoming(msg const& m, node_id* id, libtorrent::dht_settings c
return false; 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())) if (settings.enforce_node_id && !verify_id(nid, m.addr.address()))
{ {
o->timeout(); o->timeout();

View File

@ -521,7 +521,7 @@ void traversal_algorithm::status(dht_lookup& l)
void traversal_observer::reply(msg const& m) 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) if (!r)
{ {
#ifdef TORRENT_DHT_VERBOSE_LOGGING #ifdef TORRENT_DHT_VERBOSE_LOGGING
@ -532,20 +532,20 @@ void traversal_observer::reply(msg const& m)
} }
#ifdef TORRENT_DHT_VERBOSE_LOGGING #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() << "] " TORRENT_LOG(traversal) << "[" << m_algorithm.get() << "] "
"RESPONSE id: " << to_hex(nid->string_value()) "RESPONSE id: " << to_hex(nid.string_value())
<< " invoke-count: " << m_algorithm->invoke_count() << " invoke-count: " << m_algorithm.invoke_count()
<< " addr: " << m.addr << " addr: " << m.addr
<< " type: " << m_algorithm->name() << " type: " << m_algorithm.name()
; ;
#endif #endif
// look for nodes // look for nodes
lazy_entry const* n = r->dict_find_string("nodes"); bdecode_node n = r.dict_find_string("nodes");
if (n) if (n)
{ {
char const* nodes = n->string_ptr(); char const* nodes = n.string_ptr();
char const* end = nodes + n->string_length(); char const* end = nodes + n.string_length();
while (end - nodes >= 26) while (end - nodes >= 26)
{ {
@ -556,8 +556,8 @@ void traversal_observer::reply(msg const& m)
} }
} }
lazy_entry const* id = r->dict_find_string("id"); bdecode_node id = r.dict_find_string("id");
if (!id || id->string_length() != 20) if (!id || id.string_length() != 20)
{ {
#ifdef TORRENT_DHT_VERBOSE_LOGGING #ifdef TORRENT_DHT_VERBOSE_LOGGING
TORRENT_LOG(traversal) << "[" << m_algorithm.get() << "] invalid id in response"; 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 // 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. // 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() void traversal_algorithm::abort()

View File

@ -30,8 +30,11 @@ POSSIBILITY OF SUCH DAMAGE.
*/ */
#ifndef TORRENT_NO_DEPRECATE
#include "libtorrent/config.hpp" #include "libtorrent/config.hpp"
#include "libtorrent/lazy_entry.hpp" #include "libtorrent/lazy_entry.hpp"
#include "libtorrent/bdecode.hpp" // for error codes
#include <cstring> #include <cstring>
#include <limits> // for numeric_limits #include <limits> // for numeric_limits
@ -70,40 +73,6 @@ namespace libtorrent
namespace { bool numeric(char c) { return c >= '0' && c <= '9'; } } 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<boost::int64_t>::max)() / 10)
{
ec = bdecode_errors::overflow;
return start;
}
val *= 10;
int digit = *start - '0';
if (val > (std::numeric_limits<boost::int64_t>::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) char const* find_char(char const* start, char const* end, char delimiter)
{ {
while (start < end && *start != delimiter) ++start; while (start < end && *start != delimiter) ++start;
@ -153,7 +122,7 @@ namespace libtorrent
stack.pop_back(); stack.pop_back();
continue; 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'; boost::int64_t len = t - '0';
bdecode_errors::error_code_enum e = bdecode_errors::no_error; bdecode_errors::error_code_enum e = bdecode_errors::no_error;
start = parse_int(start, end, ':', len, e); start = parse_int(start, end, ':', len, e);
@ -382,7 +351,8 @@ namespace libtorrent
return e; 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); lazy_entry const* e = dict_find(name);
if (e == 0 || e->type() != lazy_entry::int_t) return default_val; if (e == 0 || e->type() != lazy_entry::int_t) return default_val;
@ -672,50 +642,7 @@ namespace libtorrent
} }
return ret; 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

View File

@ -167,14 +167,14 @@ namespace libtorrent { namespace
} }
// called when the extension handshake from the other end is received // 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; m_message_index = 0;
if (h.type() != lazy_entry::dict_t) return false; if (h.type() != bdecode_node::dict_t) return false;
lazy_entry const* messages = h.dict_find("m"); bdecode_node messages = h.dict_find("m");
if (!messages || messages->type() != lazy_entry::dict_t) return false; 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; if (index == -1) return false;
m_message_index = index; m_message_index = index;
@ -196,16 +196,16 @@ namespace libtorrent { namespace
if (m_message_index == 0) return false; if (m_message_index == 0) return false;
if (!m_pc.packet_finished()) return true; if (!m_pc.packet_finished()) return true;
lazy_entry msg; bdecode_node msg;
error_code ec; error_code ec;
int ret = lazy_bdecode(body.begin, body.end, msg, ec); int ret = bdecode(body.begin, body.end, msg, ec);
if (ret != 0 || msg.type() != lazy_entry::dict_t) if (ret != 0 || msg.type() != bdecode_node::dict_t)
{ {
m_pc.disconnect(errors::invalid_lt_tracker_message, op_bittorrent, 2); m_pc.disconnect(errors::invalid_lt_tracker_message, op_bittorrent, 2);
return true; return true;
} }
lazy_entry const* added = msg.dict_find_list("added"); bdecode_node added = msg.dict_find_list("added");
// invalid tex message // invalid tex message
if (added == 0) if (added == 0)
@ -231,9 +231,9 @@ namespace libtorrent { namespace
"added: "; "added: ";
#endif #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; if (e.url.empty()) continue;
// ignore urls with binary data in them // ignore urls with binary data in them

View File

@ -277,14 +277,14 @@ namespace libtorrent { namespace
} }
// called when the extension handshake from the other end is received // 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; m_message_index = 0;
if (h.type() != lazy_entry::dict_t) return false; if (h.type() != bdecode_node::dict_t) return false;
lazy_entry const* messages = h.dict_find("m"); bdecode_node messages = h.dict_find("m");
if (!messages || messages->type() != lazy_entry::dict_t) return false; 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; if (index == -1) return false;
m_message_index = index; m_message_index = index;
return true; return true;

View File

@ -398,31 +398,31 @@ void feed::on_feed(error_code const& ec
m_ses.update_rss_feeds(); 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_title = rd.dict_find_string_value("m_title");
m_description = rd.dict_find_string_value("m_description"); m_description = rd.dict_find_string_value("m_description");
m_last_attempt = rd.dict_find_int_value("m_last_attempt"); m_last_attempt = rd.dict_find_int_value("m_last_attempt");
m_last_update = rd.dict_find_int_value("m_last_update"); 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) if (e)
{ {
m_items.reserve(e->list_size()); m_items.reserve(e.list_size());
for (int i = 0; i < e->list_size(); ++i) for (int i = 0; i < e.list_size(); ++i)
{ {
lazy_entry const* entry = e->list_at(i); bdecode_node entry = e.list_at(i);
if (entry->type() != lazy_entry::dict_t) continue; if (entry.type() != bdecode_node::dict_t) continue;
m_items.push_back(feed_item()); m_items.push_back(feed_item());
feed_item& item = m_items.back(); feed_item& item = m_items.back();
item.url = entry->dict_find_string_value("url"); item.url = entry.dict_find_string_value("url");
item.uuid = entry->dict_find_string_value("uuid"); item.uuid = entry.dict_find_string_value("uuid");
item.title = entry->dict_find_string_value("title"); item.title = entry.dict_find_string_value("title");
item.description = entry->dict_find_string_value("description"); item.description = entry.dict_find_string_value("description");
item.comment = entry->dict_find_string_value("comment"); item.comment = entry.dict_find_string_value("comment");
item.category = entry->dict_find_string_value("category"); item.category = entry.dict_find_string_value("category");
item.size = entry->dict_find_int_value("size"); item.size = entry.dict_find_int_value("size");
// don't load duplicates // don't load duplicates
if (m_urls.find(item.url) != m_urls.end()) 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"); e = rd.dict_find_dict("add_params");
if (e) if (e)
{ {
m_settings.add_args.save_path = e->dict_find_string_value("save_path"); 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.flags = e.dict_find_int_value("flags");
} }
e = rd.dict_find_list("history"); e = rd.dict_find_list("history");
if (e) 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 if (item.list_size() != 2
|| item->list_at(0)->type() != lazy_entry::string_t || item.list_at(0).type() != bdecode_node::string_t
|| item->list_at(1)->type() != lazy_entry::int_t) || item.list_at(1).type() != bdecode_node::int_t)
continue; continue;
m_added.insert(std::pair<std::string, time_t>( m_added.insert(std::pair<std::string, time_t>(
item->list_at(0)->string_value() item.list_at(0).string_value()
, item->list_at(1)->int_value())); , item.list_at(1).int_value()));
} }
} }
} }

View File

@ -433,7 +433,7 @@ namespace libtorrent
TORRENT_SYNC_CALL2(save_state, &e, flags); 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 // this needs to be synchronized since the lifespan
// of e is tied to the caller // of e is tied to the caller
@ -494,12 +494,30 @@ namespace libtorrent
if (ses_state.type() == entry::undefined_t) return; if (ses_state.type() == entry::undefined_t) return;
std::vector<char> buf; std::vector<char> buf;
bencode(std::back_inserter(buf), ses_state); bencode(std::back_inserter(buf), ses_state);
lazy_entry e; bdecode_node e;
error_code ec; error_code ec;
#if defined TORRENT_DEBUG || TORRENT_RELEASE_ASSERTS || !defined BOOST_NO_EXCEPTIONS #if defined TORRENT_DEBUG || TORRENT_RELEASE_ASSERTS || !defined BOOST_NO_EXCEPTIONS
int ret = int ret =
#endif #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<char const*, int> 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); TORRENT_ASSERT(ret == 0);
#ifndef BOOST_NO_EXCEPTIONS #ifndef BOOST_NO_EXCEPTIONS

View File

@ -740,35 +740,35 @@ namespace aux {
return proxy_settings(m_settings); 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()); TORRENT_ASSERT(is_single_thread());
lazy_entry const* settings; bdecode_node settings;
if (e->type() != lazy_entry::dict_t) return; if (e->type() != bdecode_node::dict_t) return;
#ifndef TORRENT_DISABLE_DHT #ifndef TORRENT_DISABLE_DHT
// load from the old settings names // load from the old settings names
settings = e->dict_find_dict("dht"); settings = e->dict_find_dict("dht");
if (settings) if (settings)
{ {
lazy_entry const* val; bdecode_node val;
val = settings->dict_find_int("max_peers_reply"); val = settings.dict_find_int("max_peers_reply");
if (val) m_dht_settings.max_peers_reply = val->int_value(); if (val) m_dht_settings.max_peers_reply = val.int_value();
val = settings->dict_find_int("search_branching"); val = settings.dict_find_int("search_branching");
if (val) m_dht_settings.search_branching = val->int_value(); if (val) m_dht_settings.search_branching = val.int_value();
val = settings->dict_find_int("max_fail_count"); val = settings.dict_find_int("max_fail_count");
if (val) m_dht_settings.max_fail_count = val->int_value(); if (val) m_dht_settings.max_fail_count = val.int_value();
val = settings->dict_find_int("max_torrents"); val = settings.dict_find_int("max_torrents");
if (val) m_dht_settings.max_torrents = val->int_value(); if (val) m_dht_settings.max_torrents = val.int_value();
val = settings->dict_find_int("max_dht_items"); val = settings.dict_find_int("max_dht_items");
if (val) m_dht_settings.max_dht_items = val->int_value(); if (val) m_dht_settings.max_dht_items = val.int_value();
val = settings->dict_find_int("max_torrent_search_reply"); val = settings.dict_find_int("max_torrent_search_reply");
if (val) m_dht_settings.max_torrent_search_reply = val->int_value(); if (val) m_dht_settings.max_torrent_search_reply = val.int_value();
val = settings->dict_find_int("restrict_routing_ips"); val = settings.dict_find_int("restrict_routing_ips");
if (val) m_dht_settings.restrict_routing_ips = val->int_value(); if (val) m_dht_settings.restrict_routing_ips = val.int_value();
val = settings->dict_find_int("extended_routing_table"); val = settings.dict_find_int("extended_routing_table");
if (val) m_dht_settings.extended_routing_table = val->int_value(); if (val) m_dht_settings.extended_routing_table = val.int_value();
} }
#endif #endif
@ -776,35 +776,35 @@ namespace aux {
settings = e->dict_find_dict("proxy"); settings = e->dict_find_dict("proxy");
if (settings) if (settings)
{ {
lazy_entry const* val; bdecode_node val;
val = settings->dict_find_int("port"); val = settings.dict_find_int("port");
if (val) m_settings.set_int(settings_pack::proxy_port, val->int_value()); if (val) m_settings.set_int(settings_pack::proxy_port, val.int_value());
val = settings->dict_find_int("type"); val = settings.dict_find_int("type");
if (val) m_settings.set_int(settings_pack::proxy_type, val->int_value()); if (val) m_settings.set_int(settings_pack::proxy_type, val.int_value());
val = settings->dict_find_int("proxy_hostnames"); val = settings.dict_find_int("proxy_hostnames");
if (val) m_settings.set_bool(settings_pack::proxy_hostnames, val->int_value()); if (val) m_settings.set_bool(settings_pack::proxy_hostnames, val.int_value());
val = settings->dict_find_int("proxy_peer_connections"); val = settings.dict_find_int("proxy_peer_connections");
if (val) m_settings.set_bool(settings_pack::proxy_peer_connections, val->int_value()); if (val) m_settings.set_bool(settings_pack::proxy_peer_connections, val.int_value());
val = settings->dict_find_string("hostname"); val = settings.dict_find_string("hostname");
if (val) m_settings.set_str(settings_pack::proxy_hostname, val->string_value()); if (val) m_settings.set_str(settings_pack::proxy_hostname, val.string_value());
val = settings->dict_find_string("password"); val = settings.dict_find_string("password");
if (val) m_settings.set_str(settings_pack::proxy_password, val->string_value()); if (val) m_settings.set_str(settings_pack::proxy_password, val.string_value());
val = settings->dict_find_string("username"); val = settings.dict_find_string("username");
if (val) m_settings.set_str(settings_pack::proxy_username, val->string_value()); if (val) m_settings.set_str(settings_pack::proxy_username, val.string_value());
} }
settings = e->dict_find_dict("encryption"); settings = e->dict_find_dict("encryption");
if (settings) if (settings)
{ {
lazy_entry const* val; bdecode_node val;
val = settings->dict_find_int("prefer_rc4"); val = settings.dict_find_int("prefer_rc4");
if (val) m_settings.set_bool(settings_pack::prefer_rc4, val->int_value()); if (val) m_settings.set_bool(settings_pack::prefer_rc4, val.int_value());
val = settings->dict_find_int("out_enc_policy"); val = settings.dict_find_int("out_enc_policy");
if (val) m_settings.set_int(settings_pack::out_enc_policy, val->int_value()); if (val) m_settings.set_int(settings_pack::out_enc_policy, val.int_value());
val = settings->dict_find_int("in_enc_policy"); val = settings.dict_find_int("in_enc_policy");
if (val) m_settings.set_int(settings_pack::in_enc_policy, val->int_value()); if (val) m_settings.set_int(settings_pack::in_enc_policy, val.int_value());
val = settings->dict_find_int("allowed_enc_level"); val = settings.dict_find_int("allowed_enc_level");
if (val) m_settings.set_int(settings_pack::allowed_enc_level, val->int_value()); if (val) m_settings.set_int(settings_pack::allowed_enc_level, val.int_value());
} }
#endif #endif
@ -824,19 +824,19 @@ namespace aux {
settings = e->dict_find_dict("dht state"); settings = e->dict_find_dict("dht state");
if (settings) if (settings)
{ {
m_dht_state = *settings; m_dht_state = settings;
} }
#endif #endif
settings = e->dict_find_list("feeds"); settings = e->dict_find_list("feeds");
if (settings) if (settings)
{ {
m_feeds.reserve(settings->list_size()); m_feeds.reserve(settings.list_size());
for (int i = 0; i < settings->list_size(); ++i) 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<feed> f(new_feed(*this, feed_settings())); boost::shared_ptr<feed> f(new_feed(*this, feed_settings()));
f->load_state(*settings->list_at(i)); f->load_state(settings.list_at(i));
f->update_feed(); f->update_feed();
m_feeds.push_back(f); m_feeds.push_back(f);
} }
@ -4542,14 +4542,14 @@ retry:
{ {
int pos; int pos;
error_code ec; error_code ec;
lazy_entry tmp; bdecode_node tmp;
lazy_entry const* info = 0; bdecode_node info;
#if defined TORRENT_LOGGING #if defined TORRENT_LOGGING
session_log("adding magnet link with resume data"); session_log("adding magnet link with resume data");
#endif #endif
if (lazy_bdecode(&params.resume_data[0], &params.resume_data[0] if (bdecode(&params.resume_data[0], &params.resume_data[0]
+ params.resume_data.size(), tmp, ec, &pos) == 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"))) && (info = tmp.dict_find_dict("info")))
{ {
#if defined TORRENT_LOGGING #if defined TORRENT_LOGGING
@ -4558,7 +4558,7 @@ retry:
// verify the info-hash of the metadata stored in the resume file matches // verify the info-hash of the metadata stored in the resume file matches
// the torrent we're loading // the torrent we're loading
std::pair<char const*, int> buf = info->data_section(); std::pair<char const*, int> buf = info.data_section();
sha1_hash resume_ih = hasher(buf.first, buf.second).final(); 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 // if url is set, the info_hash is not actually the info-hash of the
@ -4573,7 +4573,7 @@ retry:
#endif #endif
params.ti = boost::make_shared<torrent_info>(resume_ih); params.ti = boost::make_shared<torrent_info>(resume_ih);
if (params.ti->parse_info_section(*info, ec, 0)) if (params.ti->parse_info_section(info, ec, 0))
{ {
#if defined TORRENT_LOGGING #if defined TORRENT_LOGGING
session_log("successfully loaded metadata from resume file"); session_log("successfully loaded metadata from resume file");

View File

@ -386,27 +386,27 @@ namespace libtorrent
return ""; 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; 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; std::string key;
lazy_entry const* val; bdecode_node val;
boost::tie(key, val) = settings->dict_at(i); boost::tie(key, val) = settings.dict_at(i);
switch (val->type()) switch (val.type())
{ {
case lazy_entry::dict_t: case bdecode_node::dict_t:
case lazy_entry::list_t: case bdecode_node::list_t:
continue; continue;
case lazy_entry::int_t: case bdecode_node::int_t:
{ {
bool found = false; bool found = false;
for (int k = 0; k < sizeof(int_settings)/sizeof(int_settings[0]); ++k) for (int k = 0; k < sizeof(int_settings)/sizeof(int_settings[0]); ++k)
{ {
if (key != int_settings[k].name) continue; 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; found = true;
break; break;
} }
@ -414,20 +414,20 @@ namespace libtorrent
for (int k = 0; k < sizeof(bool_settings)/sizeof(bool_settings[0]); ++k) for (int k = 0; k < sizeof(bool_settings)/sizeof(bool_settings[0]); ++k)
{ {
if (key != bool_settings[k].name) continue; 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;
} }
} }
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) for (int k = 0; k < sizeof(str_settings)/sizeof(str_settings[0]); ++k)
{ {
if (key != str_settings[k].name) continue; 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;
} }
break; break;
case lazy_entry::none_t: case bdecode_node::none_t:
break; break;
} }
} }

View File

@ -712,47 +712,47 @@ namespace libtorrent
return int((data_start + files().piece_length() - 1) / files().piece_length()); 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 // 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 // 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 // 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"); bdecode_node mapped_files = rd.dict_find_list("mapped_files");
if (mapped_files && mapped_files->list_size() == m_files.num_files()) if (mapped_files && mapped_files.list_size() == m_files.num_files())
{ {
m_mapped_files.reset(new file_storage(m_files)); m_mapped_files.reset(new file_storage(m_files));
for (int i = 0; i < m_files.num_files(); ++i) 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; if (new_filename.empty()) continue;
m_mapped_files->rename_file(i, new_filename); m_mapped_files->rename_file(i, new_filename);
} }
} }
lazy_entry const* file_priority = rd.dict_find_list("file_priority"); bdecode_node file_priority = rd.dict_find_list("file_priority");
if (file_priority && file_priority->list_size() if (file_priority && file_priority.list_size()
== files().num_files()) == files().num_files())
{ {
m_file_priority.resize(file_priority->list_size()); m_file_priority.resize(file_priority.list_size());
for (int i = 0; i < file_priority->list_size(); ++i) 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[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) if (file_sizes_ent == 0)
{ {
ec.ec = errors::missing_file_sizes; ec.ec = errors::missing_file_sizes;
return false; return false;
} }
if (file_sizes_ent->list_size() == 0) if (file_sizes_ent.list_size() == 0)
{ {
ec.ec = errors::no_files_in_resume_data; ec.ec = errors::no_files_in_resume_data;
return false; return false;
} }
file_storage const& fs = files(); 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.ec = errors::mismatching_number_of_files;
ec.file = -1; ec.file = -1;
@ -761,27 +761,27 @@ namespace libtorrent
} }
bool seed = false; bool seed = false;
lazy_entry const* slots = rd.dict_find_list("slots"); bdecode_node slots = rd.dict_find_list("slots");
if (slots) if (slots)
{ {
if (int(slots->list_size()) == m_files.num_pieces()) if (int(slots.list_size()) == m_files.num_pieces())
{ {
seed = true; 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; seed = false;
break; 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; seed = true;
char const* p = pieces->string_ptr(); char const* p = pieces.string_ptr();
for (int i = 0; i < pieces->string_length(); ++i) for (int i = 0; i < pieces.string_length(); ++i)
{ {
if ((p[i] & 1) == 1) continue; if ((p[i] & 1) == 1) continue;
seed = false; seed = false;
@ -795,14 +795,14 @@ namespace libtorrent
return false; 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; if (fs.pad_file_at(i)) continue;
lazy_entry const* e = file_sizes_ent->list_at(i); bdecode_node e = file_sizes_ent.list_at(i);
if (e->type() != lazy_entry::list_t if (e.type() != bdecode_node::list_t
|| e->list_size() < 2 || e.list_size() < 2
|| e->list_at(0)->type() != lazy_entry::int_t || e.list_at(0).type() != bdecode_node::int_t
|| e->list_at(1)->type() != lazy_entry::int_t) || e.list_at(1).type() != bdecode_node::int_t)
{ {
ec.ec = errors::missing_file_sizes; ec.ec = errors::missing_file_sizes;
ec.file = i; ec.file = i;
@ -810,8 +810,8 @@ namespace libtorrent
return false; return false;
} }
boost::int64_t expected_size = e->list_int_value_at(0); boost::int64_t expected_size = e.list_int_value_at(0);
time_t expected_time = e->list_int_value_at(1); time_t expected_time = e.list_int_value_at(1);
// if we're a seed, the expected size should match // if we're a seed, the expected size should match
// the actual full size according to the torrent // the actual full size according to the torrent
@ -1472,14 +1472,14 @@ namespace libtorrent
// isn't return false and the full check // isn't return false and the full check
// will be run // will be run
int piece_manager::check_fastresume( 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); TORRENT_ASSERT(m_files.piece_length() > 0);
// if we don't have any resume data, return // 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; ec.ec = errors::not_a_dictionary;
return check_no_fastresume(ec); return check_no_fastresume(ec);

View File

@ -763,8 +763,8 @@ namespace libtorrent
{ {
int pos; int pos;
error_code ec; error_code ec;
if (lazy_bdecode(&m_resume_data->buf[0], &m_resume_data->buf[0] if (bdecode(&m_resume_data->buf[0], &m_resume_data->buf[0]
+ m_resume_data->buf.size(), m_resume_data->entry, ec, &pos) != 0) + m_resume_data->buf.size(), m_resume_data->node, ec, &pos) != 0)
{ {
m_resume_data.reset(); m_resume_data.reset();
#if defined TORRENT_LOGGING #if defined TORRENT_LOGGING
@ -1745,13 +1745,16 @@ namespace libtorrent
return; 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; 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; 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()) if (!ev && info_hash.empty())
ev = errors::missing_info_hash; ev = errors::missing_info_hash;
@ -1774,7 +1777,7 @@ namespace libtorrent
} }
else 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) if (!m_seed_mode && m_resume_data)
{ {
lazy_entry const* piece_priority = m_resume_data->entry.dict_find_string("piece_priority"); bdecode_node piece_priority = m_resume_data->node
if (piece_priority && piece_priority->string_length() .dict_find_string("piece_priority");
if (piece_priority && piece_priority.string_length()
== m_torrent_file->num_pieces()) == m_torrent_file->num_pieces())
{ {
char const* p = piece_priority->string_ptr(); char const* p = piece_priority.string_ptr();
for (int i = 0; i < piece_priority->string_length(); ++i) for (int i = 0; i < piece_priority.string_length(); ++i)
{ {
int prio = p[i]; int prio = p[i];
if (!has_picker() && prio == 1) continue; if (!has_picker() && prio == 1) continue;
@ -1924,7 +1929,7 @@ namespace libtorrent
inc_refcount("check_fastresume"); inc_refcount("check_fastresume");
m_ses.disk_thread().async_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 , boost::bind(&torrent::on_resume_data_checked
, shared_from_this(), _1)); , shared_from_this(), _1));
#if defined TORRENT_LOGGING #if defined TORRENT_LOGGING
@ -2146,14 +2151,14 @@ namespace libtorrent
state_updated(); 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() 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); int num_peers = peers_entry.string_length() / (sizeof(address_v4::bytes_type) + 2);
char const* ptr = peers_entry->string_ptr(); char const* ptr = peers_entry.string_ptr();
for (int i = 0; i < num_peers; ++i) for (int i = 0; i < num_peers; ++i)
{ {
add_peer(read_v4_endpoint<tcp::endpoint>(ptr) add_peer(read_v4_endpoint<tcp::endpoint>(ptr)
@ -2162,10 +2167,11 @@ namespace libtorrent
update_want_peers(); 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); int num_peers = banned_peers_entry.string_length() / (sizeof(address_v4::bytes_type) + 2);
char const* ptr = banned_peers_entry->string_ptr(); char const* ptr = banned_peers_entry.string_ptr();
for (int i = 0; i < num_peers; ++i) for (int i = 0; i < num_peers; ++i)
{ {
std::vector<torrent_peer*> peers; std::vector<torrent_peer*> peers;
@ -2178,10 +2184,10 @@ namespace libtorrent
} }
#if TORRENT_USE_IPV6 #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); int num_peers = peers6_entry.string_length() / (sizeof(address_v6::bytes_type) + 2);
char const* ptr = peers6_entry->string_ptr(); char const* ptr = peers6_entry.string_ptr();
for (int i = 0; i < num_peers; ++i) for (int i = 0; i < num_peers; ++i)
{ {
add_peer(read_v6_endpoint<tcp::endpoint>(ptr) add_peer(read_v6_endpoint<tcp::endpoint>(ptr)
@ -2190,10 +2196,10 @@ namespace libtorrent
update_want_peers(); 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); int num_peers = banned_peers6_entry.string_length() / (sizeof(address_v6::bytes_type) + 2);
char const* ptr = banned_peers6_entry->string_ptr(); char const* ptr = banned_peers6_entry.string_ptr();
for (int i = 0; i < num_peers; ++i) for (int i = 0; i < num_peers; ++i)
{ {
torrent_peer* p = add_peer(read_v6_endpoint<tcp::endpoint>(ptr) torrent_peer* p = add_peer(read_v6_endpoint<tcp::endpoint>(ptr)
@ -2205,14 +2211,14 @@ namespace libtorrent
#endif #endif
// parse out "peers" from the resume data and add them to the peer list // 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); bdecode_node e = peers_entry.list_at(i);
if (e->type() != lazy_entry::dict_t) continue; if (e.type() != bdecode_node::dict_t) continue;
std::string ip = e->dict_find_string_value("ip"); std::string ip = e.dict_find_string_value("ip");
int port = e->dict_find_int_value("port"); int port = e.dict_find_int_value("port");
if (ip.empty() || port == 0) continue; if (ip.empty() || port == 0) continue;
error_code ec; error_code ec;
tcp::endpoint a(address::from_string(ip, ec), (unsigned short)port); 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 // 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); bdecode_node e = banned_peers_entry.list_at(i);
if (e->type() != lazy_entry::dict_t) continue; if (e.type() != bdecode_node::dict_t) continue;
std::string ip = e->dict_find_string_value("ip"); std::string ip = e.dict_find_string_value("ip");
int port = e->dict_find_int_value("port"); int port = e.dict_find_int_value("port");
if (ip.empty() || port == 0) continue; if (ip.empty() || port == 0) continue;
error_code ec; error_code ec;
tcp::endpoint a(address::from_string(ip, ec), (unsigned short)port); 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 // there are either no files for this torrent
// or the resume_data was accepted // 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 // parse have bitmask
lazy_entry const* pieces = m_resume_data->entry.dict_find("pieces"); bdecode_node pieces = m_resume_data->node.dict_find("pieces");
if (pieces && pieces->type() == lazy_entry::string_t if (pieces && pieces.type() == bdecode_node::string_t
&& int(pieces->string_length()) == m_torrent_file->num_pieces()) && int(pieces.string_length()) == m_torrent_file->num_pieces())
{ {
char const* pieces_str = pieces->string_ptr(); char const* pieces_str = pieces.string_ptr();
for (int i = 0, end(pieces->string_length()); i < end; ++i) for (int i = 0, end(pieces.string_length()); i < end; ++i)
{ {
if (pieces_str[i] & 1) if (pieces_str[i] & 1)
{ {
@ -2299,12 +2305,12 @@ namespace libtorrent
} }
else else
{ {
lazy_entry const* slots = m_resume_data->entry.dict_find("slots"); bdecode_node slots = m_resume_data->node.dict_find("slots");
if (slots && slots->type() == lazy_entry::list_t) 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) if (piece >= 0)
{ {
need_picker(); need_picker();
@ -2321,13 +2327,14 @@ namespace libtorrent
int num_blocks_per_piece = int num_blocks_per_piece =
static_cast<int>(torrent_file().piece_length()) / block_size(); static_cast<int>(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); bdecode_node e = unfinished_ent.list_at(i);
if (e->type() != lazy_entry::dict_t) continue; if (e.type() != bdecode_node::dict_t) continue;
int piece = e->dict_find_int_value("piece", -1); int piece = e.dict_find_int_value("piece", -1);
if (piece < 0 || piece > torrent_file().num_pieces()) continue; if (piece < 0 || piece > torrent_file().num_pieces()) continue;
if (has_picker() && m_picker->have_piece(piece)) if (has_picker() && m_picker->have_piece(piece))
@ -2336,7 +2343,7 @@ namespace libtorrent
update_gauge(); update_gauge();
} }
std::string bitmask = e->dict_find_string_value("bitmask"); std::string bitmask = e.dict_find_string_value("bitmask");
if (bitmask.empty()) continue; if (bitmask.empty()) continue;
need_picker(); need_picker();
@ -6534,7 +6541,7 @@ namespace libtorrent
} }
#endif #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_uploaded = rd.dict_find_int_value("total_uploaded");
m_total_downloaded = rd.dict_find_int_value("total_downloaded"); 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 // 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 // and in the disk thread, since they both have their own mapped files structures
// which are kept in sync // which are kept in sync
lazy_entry const* mapped_files = rd.dict_find_list("mapped_files"); bdecode_node mapped_files = rd.dict_find_list("mapped_files");
if (mapped_files && mapped_files->list_size() == m_torrent_file->num_files()) if (mapped_files && mapped_files.list_size() == m_torrent_file->num_files())
{ {
for (int i = 0; i < m_torrent_file->num_files(); ++i) 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; if (new_filename.empty()) continue;
m_torrent_file->rename_file(i, new_filename); m_torrent_file->rename_file(i, new_filename);
} }
@ -6645,14 +6652,14 @@ namespace libtorrent
if (!m_seed_mode && !m_override_resume_data) if (!m_seed_mode && !m_override_resume_data)
{ {
lazy_entry const* file_priority = rd.dict_find_list("file_priority"); bdecode_node file_priority = rd.dict_find_list("file_priority");
if (file_priority && file_priority->list_size() if (file_priority && file_priority.list_size()
== m_torrent_file->num_files()) == m_torrent_file->num_files())
{ {
int num_files = m_torrent_file->num_files(); int num_files = m_torrent_file->num_files();
m_file_priority.resize(num_files); m_file_priority.resize(num_files);
for (int i = 0; i < num_files; ++i) 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 // unallocated slots are assumed to be priority 1, so cut off any
// trailing ones // trailing ones
int end_range = num_files - 1; int end_range = num_files - 1;
@ -6671,19 +6678,19 @@ namespace libtorrent
update_piece_priorities(); update_piece_priorities();
} }
lazy_entry const* trackers = rd.dict_find_list("trackers"); bdecode_node trackers = rd.dict_find_list("trackers");
if (trackers) if (trackers)
{ {
if (!m_merge_resume_trackers) m_trackers.clear(); if (!m_merge_resume_trackers) m_trackers.clear();
int tier = 0; 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); bdecode_node tier_list = trackers.list_at(i);
if (tier_list == 0 || tier_list->type() != lazy_entry::list_t) if (!tier_list || tier_list.type() != bdecode_node::list_t)
continue; 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() if (std::find_if(m_trackers.begin(), m_trackers.end()
, boost::bind(&announce_entry::url, _1) == e.url) != m_trackers.end()) , boost::bind(&announce_entry::url, _1) == e.url) != m_trackers.end())
continue; continue;
@ -6700,24 +6707,24 @@ namespace libtorrent
prioritize_udp_trackers(); 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) 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 (url.empty()) continue;
if (m_torrent_file->num_files() > 1 && url[url.size()-1] != '/') url += '/'; if (m_torrent_file->num_files() > 1 && url[url.size()-1] != '/') url += '/';
add_web_seed(url, web_seed_entry::url_seed); 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) 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; if (url.empty()) continue;
add_web_seed(url, web_seed_entry::http_seed); add_web_seed(url, web_seed_entry::http_seed);
} }
@ -6725,16 +6732,16 @@ namespace libtorrent
if (m_torrent_file->is_merkle_torrent()) 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) if (mt)
{ {
std::vector<sha1_hash> tree; std::vector<sha1_hash> tree;
tree.resize(m_torrent_file->merkle_tree().size()); tree.resize(m_torrent_file->merkle_tree().size());
std::memcpy(&tree[0], mt->string_ptr() std::memcpy(&tree[0], mt.string_ptr()
, (std::min)(mt->string_length(), int(tree.size()) * 20)); , (std::min)(mt.string_length(), int(tree.size()) * 20));
if (mt->string_length() < int(tree.size()) * 20) if (mt.string_length() < int(tree.size()) * 20)
std::memset(&tree[0] + mt->string_length() / 20, 0 std::memset(&tree[0] + mt.string_length() / 20, 0
, tree.size() - mt->string_length() / 20); , tree.size() - mt.string_length() / 20);
m_torrent_file->set_merkle_tree(tree); m_torrent_file->set_merkle_tree(tree);
} }
else else
@ -7425,9 +7432,9 @@ namespace libtorrent
return false; return false;
} }
lazy_entry metadata; bdecode_node metadata;
error_code ec; 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)) if (ret != 0 || !m_torrent_file->parse_info_section(metadata, ec, 0))
{ {
update_gauge(); update_gauge();
@ -8416,8 +8423,8 @@ namespace libtorrent
// this fires during disconnecting peers // this fires during disconnecting peers
// if (is_paused()) TORRENT_ASSERT(num_peers() == 0 || m_graceful_pause_mode); // 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 TORRENT_ASSERT(!m_resume_data || m_resume_data->node.type() == bdecode_node::dict_t
|| m_resume_data->entry.type() == lazy_entry::none_t); || m_resume_data->node.type() == bdecode_node::none_t);
int seeds = 0; int seeds = 0;
int num_uploads = 0; int num_uploads = 0;

View File

@ -54,6 +54,10 @@ POSSIBILITY OF SUCH DAMAGE.
#include "libtorrent/add_torrent_params.hpp" #include "libtorrent/add_torrent_params.hpp"
#include "libtorrent/magnet_uri.hpp" #include "libtorrent/magnet_uri.hpp"
#ifndef TORRENT_NO_DEPRECATE
#include "libtorrent/lazy_entry.hpp"
#endif
#ifdef _MSC_VER #ifdef _MSC_VER
#pragma warning(push, 1) #pragma warning(push, 1)
#endif #endif
@ -362,11 +366,11 @@ namespace libtorrent
// "path" // "path"
// root_dir is the name of the torrent, unless this is a single file // root_dir is the name of the torrent, unless this is a single file
// torrent, in which case it's empty. // 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 , std::string const& root_dir, ptrdiff_t info_ptr_diff, bool top_level
, error_code& ec) , 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); boost::int64_t file_size = dict.dict_find_int_value("length", -1);
if (file_size < 0) 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 // prefer the name.utf-8 because if it exists, it is more likely to be
// correctly encoded // correctly encoded
lazy_entry const* p = dict.dict_find_string("name.utf-8"); bdecode_node p = dict.dict_find_string("name.utf-8");
if (p == 0) p = dict.dict_find_string("name"); if (!p) p = dict.dict_find_string("name");
if (p == 0 || p->string_length() == 0) if (!p || p.string_length() == 0)
{ {
ec = errors::torrent_missing_name; ec = errors::torrent_missing_name;
return false; return false;
} }
filename = p->string_ptr() + info_ptr_diff; filename = p.string_ptr() + info_ptr_diff;
filename_len = p->string_length(); filename_len = p.string_length();
sanitize_append_path_element(path, p->string_ptr(), 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()); // if (path.empty()) path = to_hex(files.info_hash().to_string());
} }
else else
{ {
lazy_entry const* p = dict.dict_find_list("path.utf-8"); bdecode_node p = dict.dict_find_list("path.utf-8");
if (p == 0) p = dict.dict_find_list("path"); if (!p) p = dict.dict_find_list("path");
if (p == 0 || p->list_size() == 0) if (!p || p.list_size() == 0)
{ {
ec = errors::torrent_missing_name; ec = errors::torrent_missing_name;
return false; return false;
} }
int preallocate = path.size(); 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); bdecode_node e = p.list_at(i);
if (e->type() != lazy_entry::string_t) if (e.type() != bdecode_node::string_t)
{ {
ec = errors::torrent_missing_name; ec = errors::torrent_missing_name;
return false; return false;
} }
preallocate += e->string_length() + 1; preallocate += e.string_length() + 1;
} }
path.reserve(preallocate); 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) if (i == end - 1)
{ {
filename = e->string_ptr() + info_ptr_diff; filename = e.string_ptr() + info_ptr_diff;
filename_len = e->string_length(); 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) if (path.find("_____padding_file_") != std::string::npos)
file_flags = file_storage::flag_pad_file; 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) 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 'l': file_flags |= file_storage::flag_symlink; file_size = 0; break;
case 'x': file_flags |= file_storage::flag_executable; 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; char const* filehash = NULL;
if (fh && fh->string_length() == 20) if (fh && fh.string_length() == 20)
filehash = fh->string_ptr() + info_ptr_diff; filehash = fh.string_ptr() + info_ptr_diff;
std::string symlink_path; std::string symlink_path;
lazy_entry const* s_p = dict.dict_find("symlink path"); bdecode_node s_p = dict.dict_find("symlink path");
if (s_p != 0 && s_p->type() == lazy_entry::list_t if (s_p && s_p.type() == bdecode_node::list_t
&& (file_flags & file_storage::flag_symlink)) && (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); 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 // root_dir is the name of the torrent, unless this is a single file
// torrent, in which case it's empty. // 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) , 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; ec = errors::torrent_file_parse_failed;
return false; return false;
@ -562,7 +566,7 @@ namespace libtorrent
for (int i = 0, end(list.list_size()); i < end; ++i) 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)) , info_ptr_diff, false, ec))
return false; return false;
} }
@ -691,7 +695,7 @@ namespace libtorrent
// event, we need to let this announce through // event, we need to let this announce through
bool need_send_complete = is_seed && !complete_sent; bool need_send_complete = is_seed && !complete_sent;
return now >= next_announce return now > next_announce
&& (now >= min_announce || need_send_complete) && (now >= min_announce || need_send_complete)
&& (fails < fail_limit || fail_limit == 0) && (fails < fail_limit || fail_limit == 0)
&& !updating; && !updating;
@ -735,6 +739,7 @@ namespace libtorrent
t.check_invariant(); t.check_invariant();
#endif #endif
if (m_info_section_size == 0) return; if (m_info_section_size == 0) return;
TORRENT_ASSERT(m_piece_hashes);
error_code ec; error_code ec;
m_info_section.reset(new char[m_info_section_size]); m_info_section.reset(new char[m_info_section_size]);
@ -746,15 +751,12 @@ namespace libtorrent
if (m_orig_files) if (m_orig_files)
const_cast<file_storage&>(*m_orig_files).apply_pointer_offset(offset); const_cast<file_storage&>(*m_orig_files).apply_pointer_offset(offset);
#if TORRENT_USE_ASSERTS || !defined BOOST_NO_EXCEPTIONS if (m_info_dict)
int ret = {
#endif // make this decoded object point to our copy of the info section
lazy_bdecode(m_info_section.get(), m_info_section.get() // buffer
+ m_info_section_size, m_info_dict, ec); m_info_dict.switch_underlying_buffer(m_info_section.get());
#ifndef BOOST_NO_EXCEPTIONS }
if (ret != 0) throw libtorrent_exception(ec);
#endif
TORRENT_ASSERT(ret == 0);
m_piece_hashes += offset; m_piece_hashes += offset;
TORRENT_ASSERT(m_piece_hashes >= m_info_section.get()); TORRENT_ASSERT(m_piece_hashes >= m_info_section.get());
@ -861,6 +863,50 @@ namespace libtorrent
} }
#ifndef TORRENT_NO_DEPRECATE #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<char const*, int> 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<char const*, int> 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 // standard constructor that parses a torrent file
torrent_info::torrent_info(entry const& torrent_file) torrent_info::torrent_info(entry const& torrent_file)
: m_piece_hashes(0) : m_piece_hashes(0)
@ -875,9 +921,9 @@ namespace libtorrent
std::back_insert_iterator<std::vector<char> > out(tmp); std::back_insert_iterator<std::vector<char> > out(tmp);
bencode(out, torrent_file); bencode(out, torrent_file);
lazy_entry e; bdecode_node e;
error_code ec; 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 #ifndef BOOST_NO_EXCEPTIONS
throw invalid_torrent_file(ec); throw invalid_torrent_file(ec);
@ -895,7 +941,7 @@ namespace libtorrent
#endif #endif
#ifndef BOOST_NO_EXCEPTIONS #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_piece_hashes(0)
, m_creation_date(0) , m_creation_date(0)
, m_merkle_first_leaf(0) , m_merkle_first_leaf(0)
@ -921,8 +967,8 @@ namespace libtorrent
, m_i2p(false) , m_i2p(false)
{ {
error_code ec; error_code ec;
lazy_entry e; bdecode_node e;
if (lazy_bdecode(buffer, buffer + size, e, ec) != 0) if (bdecode(buffer, buffer + size, e, ec) != 0)
throw invalid_torrent_file(ec); throw invalid_torrent_file(ec);
if (!parse_torrent_file(e, ec, flags)) if (!parse_torrent_file(e, ec, flags))
@ -945,8 +991,8 @@ namespace libtorrent
int ret = load_file(filename, buf, ec); int ret = load_file(filename, buf, ec);
if (ret < 0) throw invalid_torrent_file(ec); if (ret < 0) throw invalid_torrent_file(ec);
lazy_entry e; bdecode_node e;
if (buf.size() == 0 || lazy_bdecode(&buf[0], &buf[0] + buf.size(), e, ec) != 0) if (buf.size() == 0 || bdecode(&buf[0], &buf[0] + buf.size(), e, ec) != 0)
throw invalid_torrent_file(ec); throw invalid_torrent_file(ec);
if (!parse_torrent_file(e, ec, flags)) if (!parse_torrent_file(e, ec, flags))
@ -973,8 +1019,8 @@ namespace libtorrent
int ret = load_file(utf8, buf, ec); int ret = load_file(utf8, buf, ec);
if (ret < 0) throw invalid_torrent_file(ec); if (ret < 0) throw invalid_torrent_file(ec);
lazy_entry e; bdecode_node e;
if (buf.size() == 0 || lazy_bdecode(&buf[0], &buf[0] + buf.size(), e, ec) != 0) if (buf.size() == 0 || bdecode(&buf[0], &buf[0] + buf.size(), e, ec) != 0)
throw invalid_torrent_file(ec); throw invalid_torrent_file(ec);
if (!parse_torrent_file(e, ec, flags)) if (!parse_torrent_file(e, ec, flags))
@ -993,7 +1039,7 @@ namespace libtorrent
#endif // TORRENT_USE_WSTRING #endif // TORRENT_USE_WSTRING
#endif #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_piece_hashes(0)
, m_creation_date(0) , m_creation_date(0)
, m_merkle_first_leaf(0) , m_merkle_first_leaf(0)
@ -1016,8 +1062,8 @@ namespace libtorrent
, m_private(false) , m_private(false)
, m_i2p(false) , m_i2p(false)
{ {
lazy_entry e; bdecode_node e;
if (lazy_bdecode(buffer, buffer + size, e, ec) != 0) if (bdecode(buffer, buffer + size, e, ec) != 0)
return; return;
parse_torrent_file(e, ec, flags); parse_torrent_file(e, ec, flags);
@ -1037,8 +1083,8 @@ namespace libtorrent
int ret = load_file(filename, buf, ec); int ret = load_file(filename, buf, ec);
if (ret < 0) return; if (ret < 0) return;
lazy_entry e; bdecode_node e;
if (buf.size() == 0 || lazy_bdecode(&buf[0], &buf[0] + buf.size(), e, ec) != 0) if (buf.size() == 0 || bdecode(&buf[0], &buf[0] + buf.size(), e, ec) != 0)
return; return;
parse_torrent_file(e, ec, flags); parse_torrent_file(e, ec, flags);
@ -1062,8 +1108,8 @@ namespace libtorrent
int ret = load_file(utf8, buf, ec); int ret = load_file(utf8, buf, ec);
if (ret < 0) return; if (ret < 0) return;
lazy_entry e; bdecode_node e;
if (buf.size() == 0 || lazy_bdecode(&buf[0], &buf[0] + buf.size(), e, ec) != 0) if (buf.size() == 0 || bdecode(&buf[0], &buf[0] + buf.size(), e, ec) != 0)
return; return;
parse_torrent_file(e, ec, flags); parse_torrent_file(e, ec, flags);
@ -1092,8 +1138,8 @@ namespace libtorrent
void torrent_info::load(char const* buffer, int size, error_code& ec) void torrent_info::load(char const* buffer, int size, error_code& ec)
{ {
lazy_entry e; bdecode_node e;
if (lazy_bdecode(buffer, buffer + size, e, ec) != 0) if (bdecode(buffer, buffer + size, e, ec) != 0)
return; return;
if (!parse_torrent_file(e, ec, 0)) if (!parse_torrent_file(e, ec, 0))
@ -1166,20 +1212,21 @@ namespace libtorrent
std::string torrent_info::ssl_cert() const std::string torrent_info::ssl_cert() const
{ {
// this is parsed lazily // this is parsed lazily
if (m_info_dict.type() == lazy_entry::none_t) if (!m_info_dict)
{ {
error_code ec; 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); + m_info_section_size, m_info_dict, ec);
if (ec) return ""; 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"); 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; ec = errors::torrent_info_no_dict;
return false; return false;
@ -1214,22 +1261,23 @@ namespace libtorrent
files.set_piece_length(piece_length); files.set_piece_length(piece_length);
// extract file name (or the directory name if it's a multifile libtorrent) // 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"); bdecode_node name_ent = info.dict_find_string("name.utf-8");
if (name_ent == 0) name_ent = info.dict_find_string("name"); if (!name_ent) name_ent = info.dict_find_string("name");
if (name_ent == 0) if (!name_ent)
{ {
ec = errors::torrent_missing_name; ec = errors::torrent_missing_name;
return false; return false;
} }
std::string name; 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()); if (name.empty()) name = to_hex(m_info_hash.to_string());
// extract file list // extract file list
lazy_entry const* i = info.dict_find_list("files"); bdecode_node i = info.dict_find_list("files");
if (i == 0) if (!i)
{ {
// if there's no list of files, there has to be a length // if there's no list of files, there has to be a length
// field. // field.
@ -1240,7 +1288,7 @@ namespace libtorrent
} }
else else
{ {
if (!extract_files(*i, files, name, info_ptr_diff, ec)) if (!extract_files(i, files, name, info_ptr_diff, ec))
return false; return false;
m_multifile = true; m_multifile = true;
} }
@ -1253,9 +1301,9 @@ namespace libtorrent
files.set_num_pieces(int((files.total_size() + files.piece_length() - 1) files.set_num_pieces(int((files.total_size() + files.piece_length() - 1)
/ files.piece_length())); / files.piece_length()));
lazy_entry const* pieces = info.dict_find_string("pieces"); bdecode_node pieces = info.dict_find_string("pieces");
lazy_entry const* root_hash = info.dict_find_string("root hash"); bdecode_node root_hash = info.dict_find_string("root hash");
if (pieces == 0 && root_hash == 0) if (!pieces && !root_hash)
{ {
ec = errors::torrent_missing_pieces; ec = errors::torrent_missing_pieces;
return false; return false;
@ -1263,20 +1311,20 @@ namespace libtorrent
if (pieces) if (pieces)
{ {
if (pieces->string_length() != files.num_pieces() * 20) if (pieces.string_length() != files.num_pieces() * 20)
{ {
ec = errors::torrent_invalid_hashes; ec = errors::torrent_invalid_hashes;
return false; 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());
TORRENT_ASSERT(m_piece_hashes < m_info_section.get() + m_info_section_size); TORRENT_ASSERT(m_piece_hashes < m_info_section.get() + m_info_section_size);
} }
else else
{ {
TORRENT_ASSERT(root_hash); TORRENT_ASSERT(root_hash);
if (root_hash->string_length() != 20) if (root_hash.string_length() != 20)
{ {
ec = errors::torrent_invalid_hashes; ec = errors::torrent_invalid_hashes;
return false; return false;
@ -1286,7 +1334,7 @@ namespace libtorrent
m_merkle_first_leaf = num_nodes - num_leafs; m_merkle_first_leaf = num_nodes - num_leafs;
m_merkle_tree.resize(num_nodes); m_merkle_tree.resize(num_nodes);
std::memset(&m_merkle_tree[0], 0, num_nodes * 20); 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); m_private = info.dict_find_int_value("private", 0);
@ -1396,21 +1444,22 @@ namespace libtorrent
} }
#endif #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; ec = errors::torrent_is_no_dict;
return false; return false;
} }
lazy_entry const* info = torrent_file.dict_find_dict("info"); bdecode_node info = torrent_file.dict_find_dict("info");
if (info == 0) 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) if (link)
{ {
std::string uri = link->string_value(); std::string uri = link.string_value();
add_torrent_params p; add_torrent_params p;
parse_magnet_uri(uri, p, ec); parse_magnet_uri(uri, p, ec);
@ -1427,21 +1476,21 @@ namespace libtorrent
ec = errors::torrent_missing_info; ec = errors::torrent_missing_info;
return false; return false;
} }
if (!parse_info_section(*info, ec, flags)) return false; if (!parse_info_section(info, ec, flags)) return false;
resolve_duplicate_filenames(); resolve_duplicate_filenames();
// extract the url of the tracker // 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) if (i)
{ {
m_urls.reserve(i->list_size()); m_urls.reserve(i.list_size());
for (int j = 0, end(i->list_size()); j < end; ++j) for (int j = 0, end(i.list_size()); j < end; ++j)
{ {
lazy_entry const* tier = i->list_at(j); bdecode_node tier = i.list_at(j);
if (tier->type() != lazy_entry::list_t) continue; if (tier.type() != bdecode_node::list_t) continue;
for (int k = 0, end(tier->list_size()); k < end; ++k) 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(); e.trim();
if (e.url.empty()) continue; if (e.url.empty()) continue;
e.tier = j; e.tier = j;
@ -1486,20 +1535,20 @@ namespace libtorrent
if (!e.url.empty()) m_urls.push_back(e); 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) 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); bdecode_node n = nodes.list_at(i);
if (n->type() != lazy_entry::list_t if (n.type() != bdecode_node::list_t
|| n->list_size() < 2 || n.list_size() < 2
|| n->list_at(0)->type() != lazy_entry::string_t || n.list_at(0).type() != bdecode_node::string_t
|| n->list_at(1)->type() != lazy_entry::int_t) || n.list_at(1).type() != bdecode_node::int_t)
continue; continue;
m_nodes.push_back(std::make_pair( m_nodes.push_back(std::make_pair(
n->list_at(0)->string_value() n.list_at(0).string_value()
, int(n->list_at(1)->int_value()))); , int(n.list_at(1).int_value())));
} }
} }
@ -1511,24 +1560,25 @@ namespace libtorrent
} }
// if there are any url-seeds, extract them // if there are any url-seeds, extract them
lazy_entry const* url_seeds = torrent_file.dict_find("url-list"); bdecode_node url_seeds = torrent_file.dict_find("url-list");
if (url_seeds && url_seeds->type() == lazy_entry::string_t && url_seeds->string_length() > 0) 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); , web_seed_entry::url_seed);
if (m_multifile && ent.url[ent.url.size()-1] != '/') ent.url += '/'; if (m_multifile && ent.url[ent.url.size()-1] != '/') ent.url += '/';
m_web_seeds.push_back(ent); 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 // only add a URL once
std::set<std::string> unique; std::set<std::string> 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); bdecode_node url = url_seeds.list_at(i);
if (url->type() != lazy_entry::string_t) continue; if (url.type() != bdecode_node::string_t) continue;
if (url->string_length() == 0) continue; if (url.string_length() == 0) continue;
web_seed_entry ent(maybe_url_encode(url->string_value()) web_seed_entry ent(maybe_url_encode(url.string_value())
, web_seed_entry::url_seed); , web_seed_entry::url_seed);
if (m_multifile && ent.url[ent.url.size()-1] != '/') ent.url += '/'; if (m_multifile && ent.url[ent.url.size()-1] != '/') ent.url += '/';
if (unique.count(ent.url)) continue; if (unique.count(ent.url)) continue;
@ -1538,21 +1588,22 @@ namespace libtorrent
} }
// if there are any http-seeds, extract them // if there are any http-seeds, extract them
lazy_entry const* http_seeds = torrent_file.dict_find("httpseeds"); bdecode_node http_seeds = torrent_file.dict_find("httpseeds");
if (http_seeds && http_seeds->type() == lazy_entry::string_t && http_seeds->string_length() > 0) 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)); , 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 // only add a URL once
std::set<std::string> unique; std::set<std::string> 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); bdecode_node url = http_seeds.list_at(i);
if (url->type() != lazy_entry::string_t || url->string_length() == 0) continue; if (url.type() != bdecode_node::string_t || url.string_length() == 0) continue;
std::string u = maybe_url_encode(url->string_value()); std::string u = maybe_url_encode(url.string_value());
if (unique.count(u)) continue; if (unique.count(u)) continue;
unique.insert(u); unique.insert(u);
m_web_seeds.push_back(web_seed_entry(u, web_seed_entry::http_seed)); 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; , 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<char const*, int> 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 #endif // TORRENT_NO_DEPRECATE
void torrent_info::add_url_seed(std::string const& url void torrent_info::add_url_seed(std::string const& url

View File

@ -234,14 +234,14 @@ namespace libtorrent { namespace
} }
// called when the extension handshake from the other end is received // 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; m_message_index = 0;
if (h.type() != lazy_entry::dict_t) return false; if (h.type() != bdecode_node::dict_t) return false;
lazy_entry const* messages = h.dict_find_dict("m"); bdecode_node messages = h.dict_find_dict("m");
if (!messages) return false; 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; if (index == -1) return false;
m_message_index = index; m_message_index = index;

View File

@ -260,14 +260,14 @@ namespace libtorrent { namespace
messages[extension_name] = extension_index; 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; m_message_index = 0;
if (h.type() != lazy_entry::dict_t) return false; if (h.type() != bdecode_node::dict_t) return false;
lazy_entry const* messages = h.dict_find("m"); bdecode_node messages = h.dict_find_dict("m");
if (!messages || messages->type() != lazy_entry::dict_t) return false; 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; if (index == -1) return false;
m_message_index = index; m_message_index = index;
return true; return true;
@ -300,26 +300,26 @@ namespace libtorrent { namespace
m_last_pex[i] = m_last_pex[i+1]; m_last_pex[i] = m_last_pex[i+1];
m_last_pex[num_pex_timers-1] = now; m_last_pex[num_pex_timers-1] = now;
lazy_entry pex_msg; bdecode_node pex_msg;
error_code ec; error_code ec;
int ret = lazy_bdecode(body.begin, body.end, pex_msg, ec); int ret = bdecode(body.begin, body.end, pex_msg, ec);
if (ret != 0 || pex_msg.type() != lazy_entry::dict_t) if (ret != 0 || pex_msg.type() != bdecode_node::dict_t)
{ {
m_pc.disconnect(errors::invalid_pex_message, op_bittorrent, 2); m_pc.disconnect(errors::invalid_pex_message, op_bittorrent, 2);
return true; return true;
} }
lazy_entry const* p = pex_msg.dict_find_string("dropped"); bdecode_node p = pex_msg.dict_find_string("dropped");
#ifdef TORRENT_LOGGING #ifdef TORRENT_LOGGING
int num_dropped = 0; int num_dropped = 0;
int num_added = 0; int num_added = 0;
if (p) num_dropped += p->string_length()/6; if (p) num_dropped += p.string_length()/6;
#endif #endif
if (p) if (p)
{ {
int num_peers = p->string_length() / 6; int num_peers = p.string_length() / 6;
char const* in = p->string_ptr(); char const* in = p.string_ptr();
for (int i = 0; i < num_peers; ++i) for (int i = 0; i < num_peers; ++i)
{ {
@ -331,18 +331,16 @@ namespace libtorrent { namespace
} }
p = pex_msg.dict_find_string("added"); 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 #ifdef TORRENT_LOGGING
if (p) num_added += p->string_length() / 6; if (p) num_added += p.string_length() / 6;
#endif #endif
if (p != 0 if (p && pf && pf.string_length() == p.string_length() / 6)
&& pf != 0
&& pf->string_length() == p->string_length() / 6)
{ {
int num_peers = pf->string_length(); int num_peers = pf.string_length();
char const* in = p->string_ptr(); char const* in = p.string_ptr();
char const* fin = pf->string_ptr(); char const* fin = pf.string_ptr();
for (int i = 0; i < num_peers; ++i) for (int i = 0; i < num_peers; ++i)
{ {
@ -366,14 +364,14 @@ namespace libtorrent { namespace
#if TORRENT_USE_IPV6 #if TORRENT_USE_IPV6
lazy_entry const* p6 = pex_msg.dict_find("dropped6"); bdecode_node p6 = pex_msg.dict_find("dropped6");
#ifdef TORRENT_LOGGING #ifdef TORRENT_LOGGING
if (p6) num_dropped += p6->string_length() / 18; if (p6) num_dropped += p6.string_length() / 18;
#endif #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; int num_peers = p6.string_length() / 18;
char const* in = p6->string_ptr(); char const* in = p6.string_ptr();
for (int i = 0; i < num_peers; ++i) for (int i = 0; i < num_peers; ++i)
{ {
@ -386,18 +384,18 @@ namespace libtorrent { namespace
p6 = pex_msg.dict_find("added6"); p6 = pex_msg.dict_find("added6");
#ifdef TORRENT_LOGGING #ifdef TORRENT_LOGGING
if (p6) num_added += p6->string_length() / 18; if (p6) num_added += p6.string_length() / 18;
#endif #endif
lazy_entry const* p6f = pex_msg.dict_find("added6.f"); bdecode_node p6f = pex_msg.dict_find("added6.f");
if (p6 != 0 if (p6 != 0
&& p6f != 0 && p6f != 0
&& p6->type() == lazy_entry::string_t && p6.type() == bdecode_node::string_t
&& p6f->type() == lazy_entry::string_t && p6f.type() == bdecode_node::string_t
&& p6f->string_length() == p6->string_length() / 18) && p6f.string_length() == p6.string_length() / 18)
{ {
int num_peers = p6f->string_length(); int num_peers = p6f.string_length();
char const* in = p6->string_ptr(); char const* in = p6.string_ptr();
char const* fin = p6f->string_ptr(); char const* fin = p6f.string_ptr();
for (int i = 0; i < num_peers; ++i) 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); m_pc.stats_counters().inc_stats_counter(counters::num_outgoing_pex);
#ifdef TORRENT_LOGGING #ifdef TORRENT_LOGGING
lazy_entry m; bdecode_node m;
error_code ec; 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(ret == 0);
TORRENT_ASSERT(!ec); TORRENT_ASSERT(!ec);
int num_dropped = 0; int num_dropped = 0;
int num_added = 0; int num_added = 0;
lazy_entry const* e = m.dict_find_string("added"); bdecode_node e = m.dict_find_string("added");
if (e) num_added += e->string_length() / 6; if (e) num_added += e.string_length() / 6;
e = m.dict_find_string("dropped"); 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"); 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"); 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 ]" m_pc.peer_log("==> PEX_DIFF [ dropped: %d added: %d msg_size: %d ]"
, num_dropped, num_added, int(pex_msg.size())); , num_dropped, num_added, int(pex_msg.size()));
#endif #endif

View File

@ -9,8 +9,12 @@ exe test_natpmp : test_natpmp.cpp /torrent//torrent
exe enum_if : enum_if.cpp /torrent//torrent exe enum_if : enum_if.cpp /torrent//torrent
: <threading>multi <debug-iterators>on <invariant-checks>full ; : <threading>multi <debug-iterators>on <invariant-checks>full ;
exe bdecode_benchmark : test_bdecode_performance.cpp /torrent//torrent
: <variant>release ;
explicit test_natpmp ; explicit test_natpmp ;
explicit enum_if ; explicit enum_if ;
explicit bdecode_benchmark ;
rule link_test ( properties * ) rule link_test ( properties * )
{ {
@ -117,6 +121,7 @@ test-suite libtorrent :
[ run test_buffer.cpp ] [ run test_buffer.cpp ]
[ run test_piece_picker.cpp ] [ run test_piece_picker.cpp ]
[ run test_bencoding.cpp ] [ run test_bencoding.cpp ]
[ run test_bdecode.cpp ]
[ run test_fast_extension.cpp ] [ run test_fast_extension.cpp ]
[ run test_primitives.cpp ] [ run test_primitives.cpp ]
[ run test_http_parser.cpp ] [ run test_http_parser.cpp ]
@ -149,7 +154,6 @@ test-suite libtorrent :
[ run test_web_seed_http_pw.cpp ] [ run test_web_seed_http_pw.cpp ]
[ run test_web_seed_chunked.cpp ] [ run test_web_seed_chunked.cpp ]
[ run test_web_seed_ban.cpp ] [ run test_web_seed_ban.cpp ]
[ run test_bdecode_performance.cpp ]
[ run test_pe_crypto.cpp ] [ run test_pe_crypto.cpp ]
[ run test_dos_blocker.cpp ] [ run test_dos_blocker.cpp ]

View File

@ -602,7 +602,6 @@ void create_random_files(std::string const& path, const int file_sizes[], int nu
boost::shared_ptr<torrent_info> create_torrent(std::ostream* file, int piece_size boost::shared_ptr<torrent_info> create_torrent(std::ostream* file, int piece_size
, int num_pieces, bool add_tracker, std::string ssl_certificate) , 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 // excercise the path when encountering invalid urls
char const* invalid_tracker_url = "http:"; char const* invalid_tracker_url = "http:";
char const* invalid_tracker_protocol = "foo://non/existent-name.com/announce"; char const* invalid_tracker_protocol = "foo://non/existent-name.com/announce";
@ -613,7 +612,6 @@ boost::shared_ptr<torrent_info> create_torrent(std::ostream* file, int piece_siz
libtorrent::create_torrent t(fs, piece_size); libtorrent::create_torrent t(fs, piece_size);
if (add_tracker) if (add_tracker)
{ {
t.add_tracker(tracker_url);
t.add_tracker(invalid_tracker_url); t.add_tracker(invalid_tracker_url);
t.add_tracker(invalid_tracker_protocol); t.add_tracker(invalid_tracker_protocol);
} }

1169
test/test_bdecode.cpp Normal file

File diff suppressed because it is too large Load Diff

View File

@ -31,6 +31,9 @@ POSSIBILITY OF SUCH DAMAGE.
*/ */
#include "libtorrent/lazy_entry.hpp" #include "libtorrent/lazy_entry.hpp"
#include "libtorrent/bdecode.hpp"
#include "libtorrent/bencode.hpp"
#include "libtorrent/sha1_hash.hpp"
#include <boost/lexical_cast.hpp> #include <boost/lexical_cast.hpp>
#include <iostream> #include <iostream>
@ -39,22 +42,143 @@ POSSIBILITY OF SUCH DAMAGE.
using namespace libtorrent; using namespace libtorrent;
int test_main() int load_file(std::string const& filename, std::vector<char>& v
, libtorrent::error_code& ec, int limit = 8000000)
{ {
using namespace libtorrent; ec.clear();
FILE* f = fopen(filename.c_str(), "rb");
time_point start(clock_type::now()); if (f == NULL)
for (int i = 0; i < 100000; ++i)
{ {
char b[] = "d1:ai12453e1:b3:aaa1:c3:bbbe"; ec.assign(errno, boost::system::generic_category());
lazy_entry e; return -1;
error_code ec; }
lazy_bdecode(b, b + sizeof(b)-1, e, ec);
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<char> 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; return 0;
} }

View File

@ -31,11 +31,14 @@ POSSIBILITY OF SUCH DAMAGE.
*/ */
#include "libtorrent/bencode.hpp" #include "libtorrent/bencode.hpp"
#include "libtorrent/lazy_entry.hpp"
#include <boost/lexical_cast.hpp> #include <boost/lexical_cast.hpp>
#include <iostream> #include <iostream>
#include <cstring> #include <cstring>
#ifndef TORRENT_NO_DEPRECATE
#include "libtorrent/lazy_entry.hpp"
#endif
#include "test.hpp" #include "test.hpp"
using namespace libtorrent; using namespace libtorrent;
@ -57,8 +60,6 @@ entry decode(std::string const& str)
int test_main() int test_main()
{ {
using namespace libtorrent;
// ** strings ** // ** strings **
{ {
entry e("spam"); entry e("spam");
@ -104,6 +105,7 @@ int test_main()
TEST_CHECK(decode(encode(e)) == e); TEST_CHECK(decode(encode(e)) == e);
} }
#ifndef TORRENT_NO_DEPRECATE
{ {
char b[] = "i12453e"; char b[] = "i12453e";
lazy_entry e; lazy_entry e;
@ -347,7 +349,7 @@ int test_main()
int ret = lazy_bdecode(b, b + sizeof(b)-1, e, ec, NULL); int ret = lazy_bdecode(b, b + sizeof(b)-1, e, ec, NULL);
TEST_CHECK(ret != 0); TEST_CHECK(ret != 0);
printf("%s\n", print_entry(e).c_str()); 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())); , get_bdecode_category()));
} }
@ -386,7 +388,7 @@ int test_main()
int ret = lazy_bdecode(b, b + sizeof(b)-1, e, ec, NULL); int ret = lazy_bdecode(b, b + sizeof(b)-1, e, ec, NULL);
TEST_CHECK(ret != 0); TEST_CHECK(ret != 0);
printf("%s\n", print_entry(e).c_str()); 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())); , get_bdecode_category()));
} }
@ -564,7 +566,7 @@ int test_main()
boost::int64_t val = 0; boost::int64_t val = 0;
bdecode_errors::error_code_enum ec; bdecode_errors::error_code_enum ec;
char const* e = parse_int(b, b + sizeof(b)-1, 'e', val, 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); TEST_EQUAL(e, b + 1);
} }
@ -583,6 +585,7 @@ int test_main()
char const* e = parse_int(b, b + sizeof(b)-1, ':', val, ec); char const* e = parse_int(b, b + sizeof(b)-1, ':', val, ec);
TEST_CHECK(ec == bdecode_errors::expected_colon); TEST_CHECK(ec == bdecode_errors::expected_colon);
} }
#endif // TORRENT_NO_DEPRECATE
return 0; return 0;
} }

View File

@ -72,12 +72,16 @@ struct test_storage_impl : storage_interface
} }
virtual bool has_any_file(storage_error& ec) { return false; } virtual bool has_any_file(storage_error& ec) { return false; }
virtual void set_file_priority(std::vector<boost::uint8_t> const& prio, storage_error& ec) {} virtual void set_file_priority(std::vector<boost::uint8_t> const& prio
virtual int move_storage(std::string const& save_path, int flags, storage_error& ec) { return 0; } , storage_error& ec) {}
virtual bool verify_resume_data(lazy_entry const& rd, storage_error& ec) { return true; } 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 write_resume_data(entry& rd, storage_error& ec) const {}
virtual void release_files(storage_error& ec) {} 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 delete_files(storage_error& ec) {}
virtual void finalize_file(int, storage_error&) {} virtual void finalize_file(int, storage_error&) {}
}; };

View File

@ -127,17 +127,17 @@ find_packet(udp::endpoint ep)
, boost::bind(&std::pair<udp::endpoint, entry>::first, _1) == ep); , boost::bind(&std::pair<udp::endpoint, entry>::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; error_code ec;
static char inbuf[1500]; static char inbuf[1500];
int len = bencode(inbuf, e); 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); TEST_CHECK(ret == 0);
} }
void send_dht_request(node_impl& node, char const* msg, udp::endpoint const& ep 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* name = 0, std::string const token = std::string(), int port = 0
, char const* target = 0, entry const* value = 0 , char const* target = 0, entry const* value = 0
, bool scrape = false, bool seed = false , 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); VALGRIND_CHECK_MEM_IS_DEFINED(msg_buf, size);
#endif #endif
lazy_entry decoded; bdecode_node decoded;
error_code ec; error_code ec;
lazy_bdecode(msg_buf, msg_buf + size, decoded, ec); bdecode(msg_buf, msg_buf + size, decoded, ec);
if (ec) fprintf(stderr, "lazy_bdecode failed: %s\n", ec.message().c_str()); if (ec) fprintf(stderr, "bdecode failed: %s\n", ec.message().c_str());
dht::msg m(decoded, ep); dht::msg m(decoded, ep);
node.incoming(m); node.incoming(m);
@ -222,7 +222,7 @@ void write_peers(entry::dictionary_type& r, std::set<tcp::endpoint> 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() , nodes_t const& nodes = nodes_t()
, std::string const token = std::string(), int port = 0 , std::string const token = std::string(), int port = 0
, std::set<tcp::endpoint> const& peers = std::set<tcp::endpoint>() , std::set<tcp::endpoint> const& peers = std::set<tcp::endpoint>()
@ -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); VALGRIND_CHECK_MEM_IS_DEFINED(msg_buf, size);
#endif #endif
lazy_entry decoded; bdecode_node decoded;
error_code ec; error_code ec;
lazy_bdecode(msg_buf, msg_buf + size, decoded, ec); bdecode(msg_buf, msg_buf + size, decoded, ec);
if (ec) fprintf(stderr, "lazy_bdecode failed: %s\n", ec.message().c_str()); if (ec) fprintf(stderr, "bdecode failed: %s\n", ec.message().c_str());
dht::msg m(decoded, ep); dht::msg m(decoded, ep);
node.incoming(m); 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) for (int j = 0; j < num_items; ++j)
{ {
if ((i % items[j].num_peers) == 0) continue; if ((i % items[j].num_peers) == 0) continue;
lazy_entry response; bdecode_node response;
send_dht_request(node, "get", eps[i], &response, "10", 0 send_dht_request(node, "get", eps[i], &response, "10", 0
, 0, no, 0, (char const*)&items[j].target[0]); , 0, no, 0, (char const*)&items[j].target[0]);
key_desc_t desc[] = key_desc_t desc[] =
{ {
{ "r", lazy_entry::dict_t, 0, key_desc_t::parse_children }, { "r", bdecode_node::dict_t, 0, key_desc_t::parse_children },
{ "id", lazy_entry::string_t, 20, 0}, { "id", bdecode_node::string_t, 20, 0},
{ "token", lazy_entry::string_t, 0, 0}, { "token", bdecode_node::string_t, 0, 0},
{ "ip", lazy_entry::string_t, 0, key_desc_t::optional | key_desc_t::last_child}, { "ip", bdecode_node::string_t, 0, key_desc_t::optional | key_desc_t::last_child},
{ "y", lazy_entry::string_t, 1, 0}, { "y", bdecode_node::string_t, 1, 0},
}; };
lazy_entry const* parsed[6]; bdecode_node parsed[6];
char error_string[200]; char error_string[200];
// fprintf(stderr, "msg: %s\n", print_entry(response).c_str()); // 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) if (ret)
{ {
TEST_EQUAL(parsed[4]->string_value(), "r"); TEST_EQUAL(parsed[4].string_value(), "r");
token = parsed[2]->string_value(); token = parsed[2].string_value();
// fprintf(stderr, "got token: %s\n", token.c_str()); // fprintf(stderr, "got token: %s\n", token.c_str());
} }
else else
@ -329,7 +330,7 @@ void announce_immutable_items(node_impl& node, udp::endpoint const* eps
if (parsed[3]) if (parsed[3])
{ {
address_v4::bytes_type b; 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); address_v4 addr(b);
TEST_EQUAL(addr, eps[i].address()); 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[] = 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 (ret)
{ {
if (parsed[0]->string_value() != "r") if (parsed[0].string_value() != "r")
fprintf(stderr, "msg: %s\n", print_entry(response).c_str()); 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 else
{ {
@ -362,22 +364,23 @@ void announce_immutable_items(node_impl& node, udp::endpoint const* eps
std::set<int> items_num; std::set<int> items_num;
for (int j = 0; j < num_items; ++j) for (int j = 0; j < num_items; ++j)
{ {
lazy_entry response; bdecode_node response;
send_dht_request(node, "get", eps[j], &response, "10", 0 send_dht_request(node, "get", eps[j], &response, "10", 0
, 0, no, 0, (char const*)&items[j].target[0]); , 0, no, 0, (char const*)&items[j].target[0]);
key_desc_t desc[] = key_desc_t desc[] =
{ {
{ "r", lazy_entry::dict_t, 0, key_desc_t::parse_children }, { "r", bdecode_node::dict_t, 0, key_desc_t::parse_children },
{ "v", lazy_entry::dict_t, 0, 0}, { "v", bdecode_node::dict_t, 0, 0},
{ "id", lazy_entry::string_t, 20, key_desc_t::last_child}, { "id", bdecode_node::string_t, 20, key_desc_t::last_child},
{ "y", lazy_entry::string_t, 1, 0}, { "y", bdecode_node::string_t, 1, 0},
}; };
lazy_entry const* parsed[4]; bdecode_node parsed[4];
char error_string[200]; 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) if (ret)
{ {
items_num.insert(items_num.begin(), j); 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::node_impl node(&ad, &s, sett, node_id(0), ext, 0, cnt);
// DHT should be running on port 48199 now // DHT should be running on port 48199 now
lazy_entry response; bdecode_node response;
lazy_entry const* parsed[11]; bdecode_node parsed[11];
char error_string[200]; char error_string[200];
bool ret; bool ret;
@ -457,19 +460,20 @@ int test_main()
send_dht_request(node, "ping", source, &response, "10"); send_dht_request(node, "ping", source, &response, "10");
dht::key_desc_t pong_desc[] = { dht::key_desc_t pong_desc[] = {
{"y", lazy_entry::string_t, 1, 0}, {"y", bdecode_node::string_t, 1, 0},
{"t", lazy_entry::string_t, 2, 0}, {"t", bdecode_node::string_t, 2, 0},
{"r", lazy_entry::dict_t, 0, key_desc_t::parse_children}, {"r", bdecode_node::dict_t, 0, key_desc_t::parse_children},
{"id", lazy_entry::string_t, 20, key_desc_t::last_child}, {"id", bdecode_node::string_t, 20, key_desc_t::last_child},
}; };
fprintf(stderr, "msg: %s\n", print_entry(response).c_str()); 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); TEST_CHECK(ret);
if (ret) if (ret)
{ {
TEST_CHECK(parsed[0]->string_value() == "r"); TEST_CHECK(parsed[0].string_value() == "r");
TEST_CHECK(parsed[1]->string_value() == "10"); TEST_CHECK(parsed[1].string_value() == "10");
} }
else else
{ {
@ -481,20 +485,21 @@ int test_main()
send_dht_request(node, "find_node", source, &response, "10"); send_dht_request(node, "find_node", source, &response, "10");
dht::key_desc_t err_desc[] = { dht::key_desc_t err_desc[] = {
{"y", lazy_entry::string_t, 1, 0}, {"y", bdecode_node::string_t, 1, 0},
{"e", lazy_entry::list_t, 2, 0} {"e", bdecode_node::list_t, 2, 0}
}; };
fprintf(stderr, "msg: %s\n", print_entry(response).c_str()); 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); TEST_CHECK(ret);
if (ret) if (ret)
{ {
TEST_CHECK(parsed[0]->string_value() == "e"); TEST_CHECK(parsed[0].string_value() == "e");
if (parsed[1]->list_at(0)->type() == lazy_entry::int_t if (parsed[1].list_at(0).type() == bdecode_node::int_t
&& parsed[1]->list_at(1)->type() == lazy_entry::string_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 else
{ {
@ -511,20 +516,21 @@ int test_main()
send_dht_request(node, "get_peers", source, &response, "10", "01010101010101010101"); send_dht_request(node, "get_peers", source, &response, "10", "01010101010101010101");
dht::key_desc_t peer1_desc[] = { dht::key_desc_t peer1_desc[] = {
{"y", lazy_entry::string_t, 1, 0}, {"y", bdecode_node::string_t, 1, 0},
{"r", lazy_entry::dict_t, 0, key_desc_t::parse_children}, {"r", bdecode_node::dict_t, 0, key_desc_t::parse_children},
{"token", lazy_entry::string_t, 0, 0}, {"token", bdecode_node::string_t, 0, 0},
{"id", lazy_entry::string_t, 20, key_desc_t::last_child}, {"id", bdecode_node::string_t, 20, key_desc_t::last_child},
}; };
std::string token; std::string token;
fprintf(stderr, "msg: %s\n", print_entry(response).c_str()); 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); TEST_CHECK(ret);
if (ret) if (ret)
{ {
TEST_CHECK(parsed[0]->string_value() == "r"); TEST_CHECK(parsed[0].string_value() == "r");
token = parsed[2]->string_value(); token = parsed[2].string_value();
// fprintf(stderr, "got token: %s\n", token.c_str()); // fprintf(stderr, "got token: %s\n", token.c_str());
} }
else else
@ -538,17 +544,18 @@ int test_main()
send_dht_request(node, "announce_peer", source, &response, "10", "01010101010101010101", "test", token, 8080); send_dht_request(node, "announce_peer", source, &response, "10", "01010101010101010101", "test", token, 8080);
dht::key_desc_t ann_desc[] = { dht::key_desc_t ann_desc[] = {
{"y", lazy_entry::string_t, 1, 0}, {"y", bdecode_node::string_t, 1, 0},
{"r", lazy_entry::dict_t, 0, key_desc_t::parse_children}, {"r", bdecode_node::dict_t, 0, key_desc_t::parse_children},
{"id", lazy_entry::string_t, 20, key_desc_t::last_child}, {"id", bdecode_node::string_t, 20, key_desc_t::last_child},
}; };
fprintf(stderr, "msg: %s\n", print_entry(response).c_str()); 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); TEST_CHECK(ret);
if (ret) if (ret)
{ {
TEST_CHECK(parsed[0]->string_value() == "r"); TEST_CHECK(parsed[0].string_value() == "r");
} }
else else
{ {
@ -561,12 +568,13 @@ int test_main()
{ {
source = udp::endpoint(rand_v4(), 6000); source = udp::endpoint(rand_v4(), 6000);
send_dht_request(node, "get_peers", source, &response, "10", "01010101010101010101"); 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) if (ret)
{ {
TEST_CHECK(parsed[0]->string_value() == "r"); TEST_CHECK(parsed[0].string_value() == "r");
token = parsed[2]->string_value(); token = parsed[2].string_value();
// fprintf(stderr, "got token: %s\n", token.c_str()); // fprintf(stderr, "got token: %s\n", token.c_str());
} }
else else
@ -586,25 +594,26 @@ int test_main()
, 0, no, 0, 0, 0, true); , 0, no, 0, 0, 0, true);
dht::key_desc_t peer2_desc[] = { dht::key_desc_t peer2_desc[] = {
{"y", lazy_entry::string_t, 1, 0}, {"y", bdecode_node::string_t, 1, 0},
{"r", lazy_entry::dict_t, 0, key_desc_t::parse_children}, {"r", bdecode_node::dict_t, 0, key_desc_t::parse_children},
{"BFpe", lazy_entry::string_t, 256, 0}, {"BFpe", bdecode_node::string_t, 256, 0},
{"BFsd", lazy_entry::string_t, 256, 0}, {"BFsd", bdecode_node::string_t, 256, 0},
{"id", lazy_entry::string_t, 20, key_desc_t::last_child}, {"id", bdecode_node::string_t, 20, key_desc_t::last_child},
}; };
fprintf(stderr, "msg: %s\n", print_entry(response).c_str()); 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); TEST_CHECK(ret);
if (ret) if (ret)
{ {
TEST_CHECK(parsed[0]->string_value() == "r"); TEST_CHECK(parsed[0].string_value() == "r");
TEST_EQUAL(parsed[1]->dict_find_string_value("n"), "test"); TEST_EQUAL(parsed[1].dict_find_string_value("n"), "test");
bloom_filter<256> downloaders; bloom_filter<256> downloaders;
bloom_filter<256> seeds; bloom_filter<256> seeds;
downloaders.from_string(parsed[2]->string_ptr()); downloaders.from_string(parsed[2].string_ptr());
seeds.from_string(parsed[3]->string_ptr()); seeds.from_string(parsed[3].string_ptr());
fprintf(stderr, "seeds: %f\n", seeds.size()); fprintf(stderr, "seeds: %f\n", seeds.size());
fprintf(stderr, "downloaders: %f\n", downloaders.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); , 0, "0101010101010101010101010101010101010101", 0, false, false, std::string(), std::string(), -1, 0, &nid);
dht::key_desc_t nodes_desc[] = { dht::key_desc_t nodes_desc[] = {
{"y", lazy_entry::string_t, 1, 0}, {"y", bdecode_node::string_t, 1, 0},
{"r", lazy_entry::dict_t, 0, key_desc_t::parse_children}, {"r", bdecode_node::dict_t, 0, key_desc_t::parse_children},
{"id", lazy_entry::string_t, 20, key_desc_t::last_child}, {"id", bdecode_node::string_t, 20, key_desc_t::last_child},
}; };
fprintf(stderr, "msg: %s\n", print_entry(response).c_str()); 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); TEST_CHECK(ret);
if (ret) if (ret)
{ {
TEST_CHECK(parsed[0]->string_value() == "r"); TEST_CHECK(parsed[0].string_value() == "r");
} }
else else
{ {
@ -668,15 +678,16 @@ int test_main()
send_dht_request(node, "find_node", source, &response, "10", 0, 0, std::string() 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); , 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); TEST_CHECK(ret);
if (ret) if (ret)
{ {
TEST_CHECK(parsed[0]->string_value() == "e"); TEST_CHECK(parsed[0].string_value() == "e");
if (parsed[1]->list_at(0)->type() == lazy_entry::int_t if (parsed[1].list_at(0).type() == bdecode_node::int_t
&& parsed[1]->list_at(1)->type() == lazy_entry::string_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 else
{ {
@ -761,13 +772,13 @@ int test_main()
key_desc_t desc2[] = key_desc_t desc2[] =
{ {
{ "y", lazy_entry::string_t, 1, 0 } { "y", bdecode_node::string_t, 1, 0 }
}; };
key_desc_t desc_error[] = key_desc_t desc_error[] =
{ {
{ "e", lazy_entry::list_t, 2, 0 }, { "e", bdecode_node::list_t, 2, 0 },
{ "y", lazy_entry::string_t, 1, 0}, { "y", bdecode_node::string_t, 1, 0},
}; };
// ==== get / put mutable items === // ==== get / put mutable items ===
@ -814,18 +825,19 @@ int test_main()
key_desc_t desc[] = key_desc_t desc[] =
{ {
{ "r", lazy_entry::dict_t, 0, key_desc_t::parse_children }, { "r", bdecode_node::dict_t, 0, key_desc_t::parse_children },
{ "id", lazy_entry::string_t, 20, 0}, { "id", bdecode_node::string_t, 20, 0},
{ "token", lazy_entry::string_t, 0, 0}, { "token", bdecode_node::string_t, 0, 0},
{ "ip", lazy_entry::string_t, 0, key_desc_t::optional | key_desc_t::last_child}, { "ip", bdecode_node::string_t, 0, key_desc_t::optional | key_desc_t::last_child},
{ "y", lazy_entry::string_t, 1, 0}, { "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) if (ret)
{ {
TEST_EQUAL(parsed[4]->string_value(), "r"); TEST_EQUAL(parsed[4].string_value(), "r");
token = parsed[2]->string_value(); token = parsed[2].string_value();
fprintf(stderr, "get response: %s\n" fprintf(stderr, "get response: %s\n"
, print_entry(response).c_str()); , print_entry(response).c_str());
fprintf(stderr, "got token: %s\n", to_hex(token).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(public_key, item_pk_len)
, std::string(signature, item_sig_len), seq, -1, NULL, salt.first); , 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) if (ret)
{ {
fprintf(stderr, "put response: %s\n" fprintf(stderr, "put response: %s\n"
, print_entry(response).c_str()); , print_entry(response).c_str());
TEST_EQUAL(parsed[0]->string_value(), "r"); TEST_EQUAL(parsed[0].string_value(), "r");
} }
else else
{ {
@ -873,16 +886,17 @@ int test_main()
key_desc_t desc3[] = key_desc_t desc3[] =
{ {
{ "r", lazy_entry::dict_t, 0, key_desc_t::parse_children }, { "r", bdecode_node::dict_t, 0, key_desc_t::parse_children },
{ "id", lazy_entry::string_t, 20, 0}, { "id", bdecode_node::string_t, 20, 0},
{ "v", lazy_entry::none_t, 0, 0}, { "v", bdecode_node::none_t, 0, 0},
{ "seq", lazy_entry::int_t, 0, 0}, { "seq", bdecode_node::int_t, 0, 0},
{ "sig", lazy_entry::string_t, 0, 0}, { "sig", bdecode_node::string_t, 0, 0},
{ "ip", lazy_entry::string_t, 0, key_desc_t::optional | key_desc_t::last_child}, { "ip", bdecode_node::string_t, 0, key_desc_t::optional | key_desc_t::last_child},
{ "y", lazy_entry::string_t, 1, 0}, { "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) if (ret == 0)
{ {
fprintf(stderr, "msg: %s\n", print_entry(response).c_str()); fprintf(stderr, "msg: %s\n", print_entry(response).c_str());
@ -897,10 +911,10 @@ int test_main()
char value[1020]; char value[1020];
char* ptr = value; char* ptr = value;
int value_len = bencode(ptr, items[0].ent); int value_len = bencode(ptr, items[0].ent);
TEST_EQUAL(value_len, parsed[2]->data_section().second); TEST_EQUAL(value_len, parsed[2].data_section().second);
TEST_CHECK(memcmp(parsed[2]->data_section().first, value, value_len) == 0); 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! // also test that invalid signatures fail!
@ -923,13 +937,14 @@ int test_main()
, std::string(public_key, item_pk_len) , std::string(public_key, item_pk_len)
, std::string(signature, item_sig_len), seq, -1, NULL, salt.first); , 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) if (ret)
{ {
fprintf(stderr, "put response: %s\n", print_entry(response).c_str()); 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 // 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 else
{ {
@ -945,10 +960,10 @@ int test_main()
, 0, false, false, std::string(), std::string(), seq-1); , 0, false, false, std::string(), std::string(), seq-1);
{ {
lazy_entry const* r = response.dict_find_dict("r"); bdecode_node r = response.dict_find_dict("r");
TEST_CHECK(r->dict_find("v")); TEST_CHECK(r.dict_find("v"));
TEST_CHECK(r->dict_find("k")); TEST_CHECK(r.dict_find("k"));
TEST_CHECK(r->dict_find("sig")); TEST_CHECK(r.dict_find("sig"));
} }
send_dht_request(node, "get", source, &response, "10", 0 send_dht_request(node, "get", source, &response, "10", 0
@ -956,10 +971,10 @@ int test_main()
, 0, false, false, std::string(), std::string(), seq); , 0, false, false, std::string(), std::string(), seq);
{ {
lazy_entry const* r = response.dict_find_dict("r"); bdecode_node r = response.dict_find_dict("r");
TEST_CHECK(!r->dict_find("v")); TEST_CHECK(!r.dict_find("v"));
TEST_CHECK(!r->dict_find("k")); TEST_CHECK(!r.dict_find("k"));
TEST_CHECK(!r->dict_find("sig")); TEST_CHECK(!r.dict_find("sig"));
} }
// === test CAS put === // === test CAS put ===
@ -987,12 +1002,13 @@ int test_main()
, std::string(signature, item_sig_len), seq , std::string(signature, item_sig_len), seq
, cas, NULL, salt.first); , 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) if (ret)
{ {
fprintf(stderr, "put response: %s\n" fprintf(stderr, "put response: %s\n"
, print_entry(response).c_str()); , print_entry(response).c_str());
TEST_EQUAL(parsed[0]->string_value(), "r"); TEST_EQUAL(parsed[0].string_value(), "r");
} }
else else
{ {
@ -1012,14 +1028,15 @@ int test_main()
, std::string(signature, item_sig_len), seq , std::string(signature, item_sig_len), seq
, cas, NULL, salt.first); , 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) if (ret)
{ {
fprintf(stderr, "put response: %s\n" fprintf(stderr, "put response: %s\n"
, print_entry(response).c_str()); , 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 // 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 else
{ {
@ -1077,94 +1094,99 @@ int test_main()
// test verify_message // test verify_message
const static key_desc_t msg_desc[] = { const static key_desc_t msg_desc[] = {
{"A", lazy_entry::string_t, 4, 0}, {"A", bdecode_node::string_t, 4, 0},
{"B", lazy_entry::dict_t, 0, key_desc_t::optional | key_desc_t::parse_children}, {"B", bdecode_node::dict_t, 0, key_desc_t::optional | key_desc_t::parse_children},
{"B1", lazy_entry::string_t, 0, 0}, {"B1", bdecode_node::string_t, 0, 0},
{"B2", lazy_entry::string_t, 0, key_desc_t::last_child}, {"B2", bdecode_node::string_t, 0, key_desc_t::last_child},
{"C", lazy_entry::dict_t, 0, key_desc_t::optional | key_desc_t::parse_children}, {"C", bdecode_node::dict_t, 0, key_desc_t::optional | key_desc_t::parse_children},
{"C1", lazy_entry::string_t, 0, 0}, {"C1", bdecode_node::string_t, 0, 0},
{"C2", lazy_entry::string_t, 0, key_desc_t::last_child}, {"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; error_code ec;
char const test_msg[] = "d1:A4:test1:Bd2:B15:test22:B25:test3ee"; 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()); 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(ret);
TEST_CHECK(msg_keys[0]); 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[1]);
TEST_CHECK(msg_keys[2]); 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]); TEST_CHECK(msg_keys[3]);
if (msg_keys[3]) TEST_EQUAL(msg_keys[3]->string_value(), "test3"); if (msg_keys[3]) TEST_EQUAL(msg_keys[3].string_value(), "test3");
TEST_CHECK(msg_keys[4] == 0); TEST_CHECK(!msg_keys[4]);
TEST_CHECK(msg_keys[5] == 0); TEST_CHECK(!msg_keys[5]);
TEST_CHECK(msg_keys[6] == 0); TEST_CHECK(!msg_keys[6]);
char const test_msg2[] = "d1:A4:test1:Cd2:C15:test22:C25:test3ee"; 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()); 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(ret);
TEST_CHECK(msg_keys[0]); 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] == 0); TEST_CHECK(!msg_keys[1]);
TEST_CHECK(msg_keys[2] == 0); TEST_CHECK(!msg_keys[2]);
TEST_CHECK(msg_keys[3] == 0); TEST_CHECK(!msg_keys[3]);
TEST_CHECK(msg_keys[4]); TEST_CHECK(msg_keys[4]);
TEST_CHECK(msg_keys[5]); 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]); 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"; 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()); 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(!ret);
fprintf(stderr, "%s\n", error_string); fprintf(stderr, "%s\n", error_string);
TEST_EQUAL(error_string, std::string("missing 'A' key")); TEST_EQUAL(error_string, std::string("missing 'A' key"));
char const test_msg4[] = "d1:A6:foobare"; 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()); 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(!ret);
fprintf(stderr, "%s\n", error_string); fprintf(stderr, "%s\n", error_string);
TEST_EQUAL(error_string, std::string("invalid value for 'A'")); TEST_EQUAL(error_string, std::string("invalid value for 'A'"));
char const test_msg5[] = "d1:A4:test1:Cd2:C15:test2ee"; 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()); 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(!ret);
fprintf(stderr, "%s\n", error_string); fprintf(stderr, "%s\n", error_string);
TEST_EQUAL(error_string, std::string("missing 'C2' key")); TEST_EQUAL(error_string, std::string("missing 'C2' key"));
// test empty strings [ { "":1 }, "" ] // test empty strings [ { "":1 }, "" ]
char const test_msg6[] = "ld0:i1ee0:e"; 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()); fprintf(stderr, "%s\n", print_entry(ent).c_str());
TEST_CHECK(ent.type() == lazy_entry::list_t); TEST_CHECK(ent.type() == bdecode_node::list_t);
if (ent.type() == lazy_entry::list_t) if (ent.type() == bdecode_node::list_t)
{ {
TEST_CHECK(ent.list_size() == 2); TEST_CHECK(ent.list_size() == 2);
if (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(0).dict_find_int_value("") == 1);
TEST_CHECK(ent.list_at(1)->string_value() == ""); TEST_CHECK(ent.list_at(1).string_value() == "");
} }
} }
@ -1410,31 +1432,31 @@ int test_main()
// test traversal algorithms // test traversal algorithms
dht::key_desc_t find_node_desc[] = { dht::key_desc_t find_node_desc[] = {
{"y", lazy_entry::string_t, 1, 0}, {"y", bdecode_node::string_t, 1, 0},
{"t", lazy_entry::string_t, 2, 0}, {"t", bdecode_node::string_t, 2, 0},
{"q", lazy_entry::string_t, 9, 0}, {"q", bdecode_node::string_t, 9, 0},
{"a", lazy_entry::dict_t, 0, key_desc_t::parse_children}, {"a", bdecode_node::dict_t, 0, key_desc_t::parse_children},
{"id", lazy_entry::string_t, 20, 0}, {"id", bdecode_node::string_t, 20, 0},
{"target", lazy_entry::string_t, 20, key_desc_t::optional}, {"target", bdecode_node::string_t, 20, key_desc_t::optional},
{"info_hash", lazy_entry::string_t, 20, key_desc_t::optional | key_desc_t::last_child}, {"info_hash", bdecode_node::string_t, 20, key_desc_t::optional | key_desc_t::last_child},
}; };
dht::key_desc_t get_peers_desc[] = { dht::key_desc_t get_peers_desc[] = {
{"y", lazy_entry::string_t, 1, 0}, {"y", bdecode_node::string_t, 1, 0},
{"t", lazy_entry::string_t, 2, 0}, {"t", bdecode_node::string_t, 2, 0},
{"q", lazy_entry::string_t, 9, 0}, {"q", bdecode_node::string_t, 9, 0},
{"a", lazy_entry::dict_t, 0, key_desc_t::parse_children}, {"a", bdecode_node::dict_t, 0, key_desc_t::parse_children},
{"id", lazy_entry::string_t, 20, 0}, {"id", bdecode_node::string_t, 20, 0},
{"info_hash", lazy_entry::string_t, 20, key_desc_t::last_child}, {"info_hash", bdecode_node::string_t, 20, key_desc_t::last_child},
}; };
dht::key_desc_t get_item_desc[] = { dht::key_desc_t get_item_desc[] = {
{"y", lazy_entry::string_t, 1, 0}, {"y", bdecode_node::string_t, 1, 0},
{"t", lazy_entry::string_t, 2, 0}, {"t", bdecode_node::string_t, 2, 0},
{"q", lazy_entry::string_t, 3, 0}, {"q", bdecode_node::string_t, 3, 0},
{"a", lazy_entry::dict_t, 0, key_desc_t::parse_children}, {"a", bdecode_node::dict_t, 0, key_desc_t::parse_children},
{"id", lazy_entry::string_t, 20, 0}, {"id", bdecode_node::string_t, 20, 0},
{"target", lazy_entry::string_t, 20, key_desc_t::last_child}, {"target", bdecode_node::string_t, 20, key_desc_t::last_child},
}; };
// bootstrap // bootstrap
@ -1454,16 +1476,17 @@ int test_main()
TEST_EQUAL(g_sent_packets.front().first, initial_node); TEST_EQUAL(g_sent_packets.front().first, initial_node);
lazy_from_entry(g_sent_packets.front().second, response); 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) if (ret)
{ {
TEST_EQUAL(parsed[0]->string_value(), "q"); TEST_EQUAL(parsed[0].string_value(), "q");
TEST_CHECK(parsed[2]->string_value() == "find_node" TEST_CHECK(parsed[2].string_value() == "find_node"
|| parsed[2]->string_value() == "get_peers"); || parsed[2].string_value() == "get_peers");
if (parsed[0]->string_value() != "q" if (parsed[0].string_value() != "q"
|| (parsed[2]->string_value() != "find_node" || (parsed[2].string_value() != "find_node"
&& parsed[2]->string_value() != "get_peers")) break; && parsed[2].string_value() != "get_peers")) break;
} }
else else
{ {
@ -1483,14 +1506,15 @@ int test_main()
TEST_EQUAL(g_sent_packets.front().first, found_node); TEST_EQUAL(g_sent_packets.front().first, found_node);
lazy_from_entry(g_sent_packets.front().second, response); 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) if (ret)
{ {
TEST_EQUAL(parsed[0]->string_value(), "q"); TEST_EQUAL(parsed[0].string_value(), "q");
TEST_CHECK(parsed[2]->string_value() == "find_node" TEST_CHECK(parsed[2].string_value() == "find_node"
|| parsed[2]->string_value() == "get_peers"); || parsed[2].string_value() == "get_peers");
if (parsed[0]->string_value() != "q" || (parsed[2]->string_value() != "find_node" if (parsed[0].string_value() != "q" || (parsed[2].string_value() != "find_node"
&& parsed[2]->string_value() == "get_peers")) break; && parsed[2].string_value() == "get_peers")) break;
} }
else else
{ {
@ -1524,13 +1548,14 @@ int test_main()
TEST_EQUAL(g_sent_packets.front().first, initial_node); TEST_EQUAL(g_sent_packets.front().first, initial_node);
lazy_from_entry(g_sent_packets.front().second, response); 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) if (ret)
{ {
TEST_EQUAL(parsed[0]->string_value(), "q"); TEST_EQUAL(parsed[0].string_value(), "q");
TEST_EQUAL(parsed[2]->string_value(), "get_peers"); TEST_EQUAL(parsed[2].string_value(), "get_peers");
TEST_EQUAL(parsed[5]->string_value(), target.to_string()); TEST_EQUAL(parsed[5].string_value(), target.to_string());
if (parsed[0]->string_value() != "q" || parsed[2]->string_value() != "get_peers") break; if (parsed[0].string_value() != "q" || parsed[2].string_value() != "get_peers") break;
} }
else else
{ {
@ -1556,13 +1581,14 @@ int test_main()
TEST_EQUAL(g_sent_packets.front().first, next_node); TEST_EQUAL(g_sent_packets.front().first, next_node);
lazy_from_entry(g_sent_packets.front().second, response); 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) if (ret)
{ {
TEST_EQUAL(parsed[0]->string_value(), "q"); TEST_EQUAL(parsed[0].string_value(), "q");
TEST_EQUAL(parsed[2]->string_value(), "get_peers"); TEST_EQUAL(parsed[2].string_value(), "get_peers");
TEST_EQUAL(parsed[5]->string_value(), target.to_string()); TEST_EQUAL(parsed[5].string_value(), target.to_string());
if (parsed[0]->string_value() != "q" || parsed[2]->string_value() != "get_peers") break; if (parsed[0].string_value() != "q" || parsed[2].string_value() != "get_peers") break;
} }
else else
{ {
@ -1615,13 +1641,14 @@ int test_main()
TEST_EQUAL(g_sent_packets.front().first, initial_node); TEST_EQUAL(g_sent_packets.front().first, initial_node);
lazy_from_entry(g_sent_packets.front().second, response); 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) if (ret)
{ {
TEST_EQUAL(parsed[0]->string_value(), "q"); TEST_EQUAL(parsed[0].string_value(), "q");
TEST_EQUAL(parsed[2]->string_value(), "get"); TEST_EQUAL(parsed[2].string_value(), "get");
TEST_EQUAL(parsed[5]->string_value(), items[0].target.to_string()); TEST_EQUAL(parsed[5].string_value(), items[0].target.to_string());
if (parsed[0]->string_value() != "q" || parsed[2]->string_value() != "get") break; if (parsed[0].string_value() != "q" || parsed[2].string_value() != "get") break;
} }
else else
{ {
@ -1661,13 +1688,14 @@ int test_main()
TEST_EQUAL(g_sent_packets.front().first, initial_node); TEST_EQUAL(g_sent_packets.front().first, initial_node);
lazy_from_entry(g_sent_packets.front().second, response); 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) if (ret)
{ {
TEST_EQUAL(parsed[0]->string_value(), "q"); TEST_EQUAL(parsed[0].string_value(), "q");
TEST_EQUAL(parsed[2]->string_value(), "get"); TEST_EQUAL(parsed[2].string_value(), "get");
TEST_EQUAL(parsed[5]->string_value(), target.to_string()); TEST_EQUAL(parsed[5].string_value(), target.to_string());
if (parsed[0]->string_value() != "q" || parsed[2]->string_value() != "get") break; if (parsed[0].string_value() != "q" || parsed[2].string_value() != "get") break;
} }
else else
{ {
@ -1696,27 +1724,27 @@ int test_main()
} while (false); } while (false);
dht::key_desc_t put_immutable_item_desc[] = { dht::key_desc_t put_immutable_item_desc[] = {
{"y", lazy_entry::string_t, 1, 0}, {"y", bdecode_node::string_t, 1, 0},
{"t", lazy_entry::string_t, 2, 0}, {"t", bdecode_node::string_t, 2, 0},
{"q", lazy_entry::string_t, 3, 0}, {"q", bdecode_node::string_t, 3, 0},
{"a", lazy_entry::dict_t, 0, key_desc_t::parse_children}, {"a", bdecode_node::dict_t, 0, key_desc_t::parse_children},
{"id", lazy_entry::string_t, 20, 0}, {"id", bdecode_node::string_t, 20, 0},
{"token", lazy_entry::string_t, 2, 0}, {"token", bdecode_node::string_t, 2, 0},
{"v", lazy_entry::none_t, 0, key_desc_t::last_child}, {"v", bdecode_node::none_t, 0, key_desc_t::last_child},
}; };
dht::key_desc_t put_mutable_item_desc[] = { dht::key_desc_t put_mutable_item_desc[] = {
{"y", lazy_entry::string_t, 1, 0}, {"y", bdecode_node::string_t, 1, 0},
{"t", lazy_entry::string_t, 2, 0}, {"t", bdecode_node::string_t, 2, 0},
{"q", lazy_entry::string_t, 3, 0}, {"q", bdecode_node::string_t, 3, 0},
{"a", lazy_entry::dict_t, 0, key_desc_t::parse_children}, {"a", bdecode_node::dict_t, 0, key_desc_t::parse_children},
{"id", lazy_entry::string_t, 20, 0}, {"id", bdecode_node::string_t, 20, 0},
{"cas", lazy_entry::string_t, 20, key_desc_t::optional}, {"cas", bdecode_node::string_t, 20, key_desc_t::optional},
{"k", lazy_entry::string_t, item_pk_len, 0}, {"k", bdecode_node::string_t, item_pk_len, 0},
{"seq", lazy_entry::int_t, 0, 0}, {"seq", bdecode_node::int_t, 0, 0},
{"sig", lazy_entry::string_t, item_sig_len, 0}, {"sig", bdecode_node::string_t, item_sig_len, 0},
{"token", lazy_entry::string_t, 2, 0}, {"token", bdecode_node::string_t, 2, 0},
{"v", lazy_entry::none_t, 0, key_desc_t::last_child}, {"v", bdecode_node::none_t, 0, key_desc_t::last_child},
}; };
// immutable put // immutable put
@ -1745,7 +1773,8 @@ int test_main()
if (packet == g_sent_packets.end()) continue; if (packet == g_sent_packets.end()) continue;
lazy_from_entry(packet->second, response); 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) if (!ret)
{ {
fprintf(stderr, " invalid get request: %s\n", print_entry(response).c_str()); 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; if (packet == g_sent_packets.end()) continue;
lazy_from_entry(packet->second, response); 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) if (ret)
{ {
TEST_EQUAL(parsed[0]->string_value(), "q"); TEST_EQUAL(parsed[0].string_value(), "q");
TEST_EQUAL(parsed[2]->string_value(), "put"); TEST_EQUAL(parsed[2].string_value(), "put");
std::pair<const char*, int> v = parsed[6]->data_section(); std::pair<const char*, int> v = parsed[6].data_section();
TEST_EQUAL(v.second, itemv.second); TEST_EQUAL(v.second, itemv.second);
TEST_CHECK(memcmp(v.first, itemv.first, itemv.second) == 0); TEST_CHECK(memcmp(v.first, itemv.first, itemv.second) == 0);
char t[10]; char t[10];
snprintf(t, sizeof(t), "%02d", i); snprintf(t, sizeof(t), "%02d", i);
TEST_EQUAL(parsed[5]->string_value(), t); TEST_EQUAL(parsed[5].string_value(), t);
if (parsed[0]->string_value() != "q" || parsed[2]->string_value() != "put") continue; if (parsed[0].string_value() != "q" || parsed[2].string_value() != "put") continue;
} }
else else
{ {
@ -1827,7 +1857,8 @@ int test_main()
if (packet == g_sent_packets.end()) continue; if (packet == g_sent_packets.end()) continue;
lazy_from_entry(packet->second, response); 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) if (!ret)
{ {
fprintf(stderr, " invalid mutable put request: %s\n", print_entry(response).c_str()); 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; if (packet == g_sent_packets.end()) continue;
lazy_from_entry(packet->second, response); 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) if (ret)
{ {
TEST_EQUAL(parsed[0]->string_value(), "q"); TEST_EQUAL(parsed[0].string_value(), "q");
TEST_EQUAL(parsed[2]->string_value(), "put"); TEST_EQUAL(parsed[2].string_value(), "put");
TEST_EQUAL(parsed[6]->string_value(), std::string(public_key, item_pk_len)); TEST_EQUAL(parsed[6].string_value(), std::string(public_key, item_pk_len));
TEST_EQUAL(parsed[7]->int_value(), seq); TEST_EQUAL(parsed[7].int_value(), seq);
TEST_EQUAL(parsed[8]->string_value(), sig); TEST_EQUAL(parsed[8].string_value(), sig);
std::pair<const char*, int> v = parsed[10]->data_section(); std::pair<const char*, int> v = parsed[10].data_section();
TEST_EQUAL(v.second, itemv.second); TEST_EQUAL(v.second, itemv.second);
TEST_CHECK(memcmp(v.first, itemv.first, itemv.second) == 0); TEST_CHECK(memcmp(v.first, itemv.first, itemv.second) == 0);
char t[10]; char t[10];
snprintf(t, sizeof(t), "%02d", i); snprintf(t, sizeof(t), "%02d", i);
TEST_EQUAL(parsed[9]->string_value(), t); TEST_EQUAL(parsed[9].string_value(), t);
if (parsed[0]->string_value() != "q" || parsed[2]->string_value() != "put") continue; if (parsed[0].string_value() != "q" || parsed[2].string_value() != "put") continue;
} }
else else
{ {

View File

@ -37,7 +37,7 @@ POSSIBILITY OF SUCH DAMAGE.
#include "libtorrent/alloca.hpp" #include "libtorrent/alloca.hpp"
#include "libtorrent/time.hpp" #include "libtorrent/time.hpp"
#include "libtorrent/peer_info.hpp" #include "libtorrent/peer_info.hpp"
#include "libtorrent/lazy_entry.hpp" #include "libtorrent/bdecode.hpp"
#include <cstring> #include <cstring>
#include <boost/bind.hpp> #include <boost/bind.hpp>
#include <iostream> #include <iostream>
@ -476,20 +476,26 @@ void test_dont_have()
int ext_msg = recv_buffer[1]; int ext_msg = recv_buffer[1];
if (ext_msg != 0) continue; if (ext_msg != 0) continue;
lazy_entry e; bdecode_node e;
error_code ec; 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); TEST_EQUAL(ret, 0);
printf("extension handshake: %s\n", print_entry(e).c_str()); 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); TEST_CHECK(m);
if (!m) return; 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); TEST_CHECK(dont_have);
if (!dont_have) return; if (!dont_have) return;
lt_dont_have = dont_have->int_value(); lt_dont_have = dont_have.int_value();
} }
char* ptr = recv_buffer; char* ptr = recv_buffer;

View File

@ -169,8 +169,8 @@ int test_main()
std::vector<char> buf; std::vector<char> buf;
bencode(std::back_inserter(buf), session_state); bencode(std::back_inserter(buf), session_state);
lazy_entry session_state2; bdecode_node session_state2;
int ret = lazy_bdecode(&buf[0], &buf[0] + buf.size(), session_state2, ec); int ret = bdecode(&buf[0], &buf[0] + buf.size(), session_state2, ec);
TEST_CHECK(ret == 0); TEST_CHECK(ret == 0);
fprintf(stderr, "session_state\n%s\n", print_entry(session_state2).c_str()); fprintf(stderr, "session_state\n%s\n", print_entry(session_state2).c_str());
@ -204,7 +204,8 @@ int test_main()
#endif #endif
// make sure settings that haven't been changed from their defaults are not saved // 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); s->load_state(session_state2);

View File

@ -86,12 +86,12 @@ int test_main()
#endif #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"; 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; error_code ec;
lazy_bdecode(eplist, eplist + sizeof(eplist)-1, e, ec); bdecode(eplist, eplist + sizeof(eplist)-1, e, ec);
TEST_CHECK(!ec); TEST_CHECK(!ec);
std::vector<udp::endpoint> list; std::vector<udp::endpoint> list;
read_endpoint_list<udp::endpoint>(&e, list); read_endpoint_list<udp::endpoint>(e, list);
#if TORRENT_USE_IPV6 #if TORRENT_USE_IPV6
TEST_EQUAL(list.size(), 2); TEST_EQUAL(list.size(), 2);

View File

@ -459,7 +459,7 @@ void test_check_files(std::string const& test_path
libtorrent::mutex lock; libtorrent::mutex lock;
bool done = false; 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.async_check_fastresume(pm.get(), &frd, boost::bind(&on_check_resume_data, _1, &done));
io.submit_jobs(); io.submit_jobs();
ios.reset(); ios.reset();

View File

@ -177,9 +177,9 @@ int main(int argc, char* argv[])
state.resize(size); state.resize(size);
fread(&state[0], 1, state.size(), f); fread(&state[0], 1, state.size(), f);
lazy_entry e; bdecode_node e;
error_code ec; error_code ec;
lazy_bdecode(&state[0], &state[0] + state.size(), e, ec); bdecode(&state[0], &state[0] + state.size(), e, ec);
if (ec) if (ec)
fprintf(stderr, "failed to parse .dht file: (%d) %s\n" fprintf(stderr, "failed to parse .dht file: (%d) %s\n"
, ec.value(), ec.message().c_str()); , ec.value(), ec.message().c_str());

View File

@ -34,11 +34,11 @@ POSSIBILITY OF SUCH DAMAGE.
#include <boost/cstdint.hpp> #include <boost/cstdint.hpp>
#include <boost/random/mersenne_twister.hpp> #include <boost/random/mersenne_twister.hpp>
#include <boost/random/uniform_int_distribution.hpp> #include <boost/random/uniform_int_distribution.hpp>
#include "libtorrent/lazy_entry.hpp" #include "libtorrent/bdecode.hpp"
#include "libtorrent/torrent_info.hpp" #include "libtorrent/torrent_info.hpp"
#include "libtorrent/error_code.hpp" #include "libtorrent/error_code.hpp"
using libtorrent::lazy_entry; using libtorrent::bdecode_node;
using boost::random::mt19937; using boost::random::mt19937;
using boost::random::uniform_int_distribution; 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()) switch (e.type())
{ {
case lazy_entry::dict_t: case bdecode_node::dict_t:
print_dict(out); print_dict(out);
for (int i = 0; i < e.dict_size(); ++i) for (int i = 0; i < e.dict_size(); ++i)
{ {
std::pair<std::string, lazy_entry const*> item = e.dict_at(i); std::pair<std::string, bdecode_node> item = e.dict_at(i);
const bool duplicate = g_seed == 1; const bool duplicate = g_seed == 1;
const bool skipped = g_seed == 2; const bool skipped = g_seed == 2;
g_seed -= 2; g_seed -= 2;
if (duplicate) if (duplicate)
{ {
print_string(out, item.first); print_string(out, item.first);
render_variant(out, *item.second); render_variant(out, item.second);
} }
if (!skipped) if (!skipped)
{ {
print_string(out, item.first); print_string(out, item.first);
render_variant(out, *item.second); render_variant(out, item.second);
} }
render_arbitrary_item(out); render_arbitrary_item(out);
} }
print_terminate(out); print_terminate(out);
break; break;
case lazy_entry::list_t: case bdecode_node::list_t:
print_list(out); print_list(out);
for (int i = 0; i < e.list_size(); ++i) for (int i = 0; i < e.list_size(); ++i)
{ {
const bool duplicate = g_seed == 1; const bool duplicate = g_seed == 1;
const bool skipped = g_seed == 2; const bool skipped = g_seed == 2;
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); 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); print_terminate(out);
break; break;
case lazy_entry::int_t: case bdecode_node::int_t:
print_int(out, e.int_value()); print_int(out, e.int_value());
break; break;
case lazy_entry::string_t: case bdecode_node::string_t:
print_string(out, e.string_value()); print_string(out, e.string_value());
break; break;
default: default:
@ -371,8 +371,8 @@ int main(int argc, char const* argv[])
continue; continue;
} }
lazy_entry e; bdecode_node e;
if (buf.size() == 0 || lazy_bdecode(&buf[0], &buf[0] + buf.size(), e, ec) != 0) if (buf.size() == 0 || bdecode(&buf[0], &buf[0] + buf.size(), e, ec) != 0)
{ {
fprintf(stderr, "ERROR parsing file: %s\n%s\n" fprintf(stderr, "ERROR parsing file: %s\n%s\n"
, *argv, ec.message().c_str()); , *argv, ec.message().c_str());

View File

@ -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 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 { function run_test {
set +e
rm $OBJECT_PATH/*.gcda rm $OBJECT_PATH/*.gcda
set -e
cd test cd test
set +e
rm -rf bin rm -rf bin
set -e
bjam asserts=off invariant-checks=off link=static boost=source test-coverage=on picker-debugging=off -j4 $1 bjam asserts=off invariant-checks=off link=static boost=source test-coverage=on picker-debugging=off -j4 $1
cd .. cd ..
@ -20,11 +25,16 @@ function run_test {
# force rebuilding and rerunning the unit tests # force rebuilding and rerunning the unit tests
cd test cd test
set +e
rm -rf bin rm -rf bin
set -e
cd .. cd ..
set +e
mkdir test-coverage mkdir test-coverage
set -e
run_test test_bdecode "*/bdecode.*"
run_test test_piece_picker "*/piece_picker.*" run_test test_piece_picker "*/piece_picker.*"
run_test test_torrent_info "*/torrent_info.*" run_test test_torrent_info "*/torrent_info.*"
run_test test_part_file "*/part_file.*" 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_string "*/escape_string.*"
run_test test_utf8 "*/ConvertUTF.*" run_test test_utf8 "*/ConvertUTF.*"