deprecate slow bdecode() function

This commit is contained in:
arvidn 2018-11-18 12:59:52 +01:00 committed by Arvid Norberg
parent 0d8a5a8a44
commit 9ae4aedeb0
4 changed files with 36 additions and 67 deletions

View File

@ -5,6 +5,7 @@
#include "boost_python.hpp"
#include <libtorrent/identify_client.hpp>
#include <libtorrent/bencode.hpp>
#include <libtorrent/bdecode.hpp>
#include "bytes.hpp"
using namespace boost::python;
@ -74,7 +75,7 @@ object client_fingerprint_(peer_id const& id)
entry bdecode_(bytes const& data)
{
return bdecode(data.arr.begin(), data.arr.end());
return bdecode(data.arr);
}
bytes bencode_(entry const& e)

View File

@ -38,35 +38,19 @@ POSSIBILITY OF SUCH DAMAGE.
// Bencoding is a common representation in bittorrent used for for dictionary,
// list, int and string hierarchies. It's used to encode .torrent files and
// some messages in the network protocol. libtorrent also uses it to store
// settings, resume data and other state between sessions.
// settings, resume data and other session state.
//
// Strings in bencoded structures are not necessarily representing text.
// Strings in bencoded structures do not necessarily represent text.
// Strings are raw byte buffers of a certain length. If a string is meant to be
// interpreted as text, it is required to be UTF-8 encoded. See `BEP 3`_.
//
// There are two mechanisms to *decode* bencoded buffers in libtorrent.
// The function for decoding bencoded data bdecode(), returning a bdecode_node.
// This function builds a tree that points back into the original buffer. The
// returned bdecode_node will not be valid once the buffer it was parsed out of
// is discarded.
//
// The most flexible one is `bdecode() bencode()`_, which returns a structure
// represented by entry. Once a buffer has been decoded with this function, it
// can be discarded. The entry does not contain any references back to it. This
// means that bdecode() copies all the data out of the buffer and into its own
// hierarchy. This makes this function expensive, which might matter if you're
// parsing large amounts of data.
//
// Another consideration is that `bdecode() bencode()`_ is a recursive parser.
// For this reason, in order to avoid DoS attacks by triggering a stack
// overflow, there is a recursion limit. This limit is a sanity check to make
// sure it doesn't run the risk of busting the stack.
//
// The second mechanism is the decode function for bdecode_node. This function
// builds a tree that points back into the original buffer. The returned
// bdecode_node will not be valid once the buffer it was parsed out of is
// discarded.
//
// Not only is this function more efficient because of less memory allocation
// and data copy, the parser is also not recursive, which means it probably
// performs a little bit better and can have a higher recursion limit on the
// structures it's parsing.
// It's possible to construct an entry from a bdecode_node, if a structure needs
// to be altered and re-encoded.
#include <string>
#include <iterator> // for distance
@ -206,7 +190,7 @@ namespace detail {
}
return ret;
}
#if TORRENT_ABI_VERSION == 1
template<class InIt>
void bdecode_recursive(InIt& in, InIt end, entry& ret, bool& err, int depth)
{
@ -364,56 +348,36 @@ namespace detail {
#endif
}
}
#endif // TORRENT_ABI_VERSION
}
// These functions will encode data to bencoded or decode bencoded data.
//
// If possible, ``bdecode()`` producing a bdecode_node should be preferred
// over this function.
// This function will encode data to bencoded form.
//
// 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
// the program and given to ``bencode()`` to encode it into the ``OutIt``
// iterator.
//
// The ``OutIt`` and ``InIt`` are iterators
// (InputIterator_ and OutputIterator_ respectively). They
// are templates and are usually instantiated as ostream_iterator_,
// back_insert_iterator_ or istream_iterator_. These
// functions will assume that the iterator refers to a character
// (``char``). So, if you want to encode entry ``e`` into a buffer
// in memory, you can do it like this::
// ``OutIt`` is an OutputIterator_. It's a template and usually
// instantiated as ostream_iterator_ or back_insert_iterator_. This
// function assumes the value_type of the iterator is a ``char``.
// In order to encode entry ``e`` into a buffer, do::
//
// std::vector<char> buffer;
// bencode(std::back_inserter(buf), e);
//
// .. _InputIterator: http://www.sgi.com/tech/stl/InputIterator.html
// .. _OutputIterator: http://www.sgi.com/tech/stl/OutputIterator.html
// .. _ostream_iterator: http://www.sgi.com/tech/stl/ostream_iterator.html
// .. _back_insert_iterator: http://www.sgi.com/tech/stl/back_insert_iterator.html
// .. _istream_iterator: http://www.sgi.com/tech/stl/istream_iterator.html
//
// If you want to decode a torrent file from a buffer in memory, you can do it like this::
//
// std::vector<char> buffer;
// // ...
// entry e = bdecode(buf.begin(), buf.end());
//
// Or, if you have a raw char buffer::
//
// const char* buf;
// // ...
// entry e = bdecode(buf, buf + data_size);
//
// Now we just need to know how to retrieve information from the entry.
//
// If ``bdecode()`` encounters invalid encoded data in the range given to it
// it will return a default constructed ``entry`` object.
// .. _OutputIterator: https://en.cppreference.com/w/cpp/named_req/OutputIterator
// .. _ostream_iterator: https://en.cppreference.com/w/cpp/iterator/ostream_iterator
// .. _back_insert_iterator: https://en.cppreference.com/w/cpp/iterator/back_insert_iterator
template<class OutIt> int bencode(OutIt out, const entry& e)
{
return detail::bencode_recursive(out, e);
}
template<class InIt> entry bdecode(InIt start, InIt end)
#if TORRENT_ABI_VERSION == 1
template<class InIt>
TORRENT_DEPRECATED
entry bdecode(InIt start, InIt end)
{
entry e;
bool err = false;
@ -422,7 +386,9 @@ namespace detail {
if (err) return entry();
return e;
}
template<class InIt> entry bdecode(InIt start, InIt end
template<class InIt>
TORRENT_DEPRECATED
entry bdecode(InIt start, InIt end
, typename std::iterator_traits<InIt>::difference_type& len)
{
entry e;
@ -434,6 +400,7 @@ namespace detail {
if (err) return entry();
return e;
}
#endif
}
#endif // TORRENT_BENCODE_HPP_INCLUDED

View File

@ -162,10 +162,10 @@ void item::assign(entry v)
void item::assign(entry v, span<char const> salt
, sequence_number const seq, public_key const& pk, secret_key const& sk)
{
char buffer[1000];
int bsize = bencode(buffer, v);
std::array<char, 1000> buffer;
int const bsize = bencode(buffer.begin(), v);
TORRENT_ASSERT(bsize <= 1000);
m_sig = sign_mutable_item({buffer, bsize}
m_sig = sign_mutable_item(span<char const>(buffer).first(bsize)
, salt, seq, pk, sk);
m_salt.assign(salt.data(), static_cast<std::size_t>(salt.size()));
m_pk = pk;

View File

@ -37,6 +37,7 @@ POSSIBILITY OF SUCH DAMAGE.
#include "libtorrent/error_code.hpp"
#include "libtorrent/socket.hpp"
#include "libtorrent/aux_/time.hpp"
#include "libtorrent/bdecode.hpp"
#include "dht_server.hpp"
#include "test_utils.hpp"
@ -114,7 +115,7 @@ struct dht_server
void thread_fun()
{
char buffer[2000];
std::array<char, 2000> buffer;
for (;;)
{
@ -123,7 +124,7 @@ struct dht_server
size_t bytes_transferred;
bool done = false;
m_socket.async_receive_from(
boost::asio::buffer(buffer, sizeof(buffer)), from, 0
boost::asio::buffer(buffer.data(), buffer.size()), from, 0
, std::bind(&incoming_packet, _1, _2, &bytes_transferred, &ec, &done));
while (!done)
{
@ -142,7 +143,7 @@ struct dht_server
try
{
entry msg = bdecode(buffer, buffer + bytes_transferred);
entry msg = bdecode(span<char const>(buffer).first(int(bytes_transferred)));
#if TORRENT_USE_IOSTREAM
std::cout << msg << std::endl;