From 9ae4aedeb00bd2abc1fcc4eb890722cf457e9a74 Mon Sep 17 00:00:00 2001 From: arvidn Date: Sun, 18 Nov 2018 12:59:52 +0100 Subject: [PATCH] deprecate slow bdecode() function --- bindings/python/src/utility.cpp | 3 +- include/libtorrent/bencode.hpp | 87 ++++++++++----------------------- src/kademlia/item.cpp | 6 +-- test/dht_server.cpp | 7 +-- 4 files changed, 36 insertions(+), 67 deletions(-) diff --git a/bindings/python/src/utility.cpp b/bindings/python/src/utility.cpp index 3f1ac4e6c..f5795e9ef 100644 --- a/bindings/python/src/utility.cpp +++ b/bindings/python/src/utility.cpp @@ -5,6 +5,7 @@ #include "boost_python.hpp" #include #include +#include #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) diff --git a/include/libtorrent/bencode.hpp b/include/libtorrent/bencode.hpp index 9c76b8442..7733d6855 100644 --- a/include/libtorrent/bencode.hpp +++ b/include/libtorrent/bencode.hpp @@ -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 #include // for distance @@ -206,7 +190,7 @@ namespace detail { } return ret; } - +#if TORRENT_ABI_VERSION == 1 template 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 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 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 int bencode(OutIt out, const entry& e) { return detail::bencode_recursive(out, e); } - template entry bdecode(InIt start, InIt end) + +#if TORRENT_ABI_VERSION == 1 + template + 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 entry bdecode(InIt start, InIt end + template + TORRENT_DEPRECATED + entry bdecode(InIt start, InIt end , typename std::iterator_traits::difference_type& len) { entry e; @@ -434,6 +400,7 @@ namespace detail { if (err) return entry(); return e; } +#endif } #endif // TORRENT_BENCODE_HPP_INCLUDED diff --git a/src/kademlia/item.cpp b/src/kademlia/item.cpp index 1d9687d3d..5489c37b7 100644 --- a/src/kademlia/item.cpp +++ b/src/kademlia/item.cpp @@ -162,10 +162,10 @@ void item::assign(entry v) void item::assign(entry v, span salt , sequence_number const seq, public_key const& pk, secret_key const& sk) { - char buffer[1000]; - int bsize = bencode(buffer, v); + std::array 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(buffer).first(bsize) , salt, seq, pk, sk); m_salt.assign(salt.data(), static_cast(salt.size())); m_pk = pk; diff --git a/test/dht_server.cpp b/test/dht_server.cpp index ec4166b55..83c5a3faa 100644 --- a/test/dht_server.cpp +++ b/test/dht_server.cpp @@ -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 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(buffer).first(int(bytes_transferred))); #if TORRENT_USE_IOSTREAM std::cout << msg << std::endl;